cutsceneplugin
A scene played from a cue file: camera shots, bars, a fade to black and lines of text, directing the rows it casts.
Putting it in a scene
List it after render3d and before chasecamera3d and ui. The scene's sim lists the cutscene and mark kinds from #plugins/cutscene/cutscene.sim.ts. cutscene is built from the ground's height, cutscene(height), where height(w, x, z) is the ground's height over a truth: pass terrain3d's server half, or () => 0 for a flat scene. The scene holds one cutscene actor, whose prefab is {}, and one mark actor for each named spot.
"plugins": ["loader", "scenemanager", "player", "terrain3d", "render3d", "cutscene", "chasecamera3d", "ui"],
"world": {
"loader": { "assets": { "intro": { "type": "json", "url": "/games/mygame/assets/intro.json", "preload": true } } },
"cutscene": {
"script": "intro",
"kinds": ["villager"],
"settle": 0.5,
"tremor": [[0.02, 31], [0.02, 37], [0.01, 43]],
"mods": { "play": "audio", "land": "terrain3d" }
},
"ui": {
"panels": {
"cutscene.top": { "anchor": "top", "size": [640, 60], "layer": 10 },
"cutscene.bottom": { "anchor": "bottom", "size": [640, 60], "layer": 10 },
"cutscene.veil": { "anchor": "center", "size": [640, 360], "layer": 11 },
"cutscene.line": { "anchor": "bottom", "at": [0, -70], "size": [600, 40], "layer": 12 }
},
"styles": {
"cutscene.bars": { "color": 0 },
"cutscene.veil": { "color": 0 },
"cutscene.line": { "fontSize": 16, "fill": "#ffffff" }
}
}
},
"prefabs": {
"cutscene": {},
"mark": { "name": "gate", "at": [12, 0, -4] }
}
The cue file is the loader json entry that script names:
{
"end": 12, "go": "arena", "arrive": [1],
"reach": 1.5, "stop": 0.3, "head": 1.6, "fov": 55, "pace": 1.4, "limit": 20,
"cast": { "elder": { "kind": "villager", "name": "Edda" } },
"cues": [
{ "at": 0, "do": "bars", "on": true, "over": 0.5 },
{ "at": 0, "do": "shot", "name": "wide", "pos": [0, 6, 20], "look": "elder", "over": 0 },
{ "at": 1, "do": "walk", "who": "elder", "to": "gate", "gear": "walk" },
{ "at": 1, "do": "wait", "who": "elder" },
{ "at": 1, "do": "say", "who": "elder", "text": "Follow me.", "for": 3 },
{ "at": 4, "do": "shot", "name": "close", "pos": [0, 0.2, 2.5], "look": "elder", "fov": 40, "over": 2, "follows": "elder", "frame": "body" }
]
}
Properties
The scene's numbers
Read from world.cutscene. A child scene inherits them from the manager scene.
| Setting | Meaning |
|---|---|
.script | The loader catalogue name of the cue file, a json entry with preload. |
.kinds | The kinds a cast member may be. |
.settle | Seconds of each quiet stretch that a skip still steps the cast through (see Start, skip and end). |
.tremor | [[weight, rate], [weight, rate], [weight, rate]]: the shake's weight and rate on x, y and z. The offset on an axis is amp·(1 − k)·weight·sin(rate·e), where k runs from 0 to 1 over the shake and e is the scene's elapsed seconds. |
.mods | { play, land } (see Mods). |
The cue file
Every number is required and is held to the range below. Lengths are metres and times are seconds.
| Key | Meaning |
|---|---|
end | Seconds on the cue clock at which the scene ends. 0 or more. |
go, arrive | Optional. The scene every seat's body goes to when the scene ends, and the arguments it arrives with: a list of numbers, strings, true, false and null. |
auto | Optional. True starts the scene on the cutscene row's first step. |
reach, stop | 0 or more. A walk to a cast member is done within reach of it, and a walk to a mark or a point within stop. |
head | Metres a cast member's head is above its feet, where a shot looks at it. |
fov | A shot's field of view in degrees, above 0 and below 180, when the shot gives none. |
pace | Metres a second a walk with no gear is walked at. Above 0. |
limit | Seconds after which a walk that gives no limit is done. Above 0. |
cast | Name to { kind, name }: the first row of that kind whose name is that name. No cast member may be named line. |
cues | A list of { at, do, ... }, at in seconds on the cue clock, 0 or more. |
Cues
A cue's fields depend on its do. A field ending in ? may be left out.
| do | Fields | What it does |
|---|---|---|
play | who, clip, holds, rate | Plays a whole-body clip on the member. holds is true or false, and rate is above 0. |
gesture | who, clip | Plays an upper-body clip. |
walk | who, to, gear, limit? | Walks the member to to. gear is the clip it walks with, at that clip's speed, or null to walk at pace. limit is above 0. |
face | who, to | Holds the member's facing toward to while it is not walking. Null lets go. It does not stop a walk. |
say | who, text, for, voice? | Shows the one line for for seconds, above 0. A new line replaces the last. voice is a sound cue raised from the speaker with it. |
wait | who | Holds the cue clock until that member's walk is done, or with "line" until the line has gone. |
shot | name, pos, look, fov?, over, follows?, frame? | A cut when over is 0, else a dolly of over seconds from the camera as it stands. With follows a cast member, pos is an offset [x, y, z] from its feet in the world's axes, or with frame: "body" in its own: z forward, x its left, y up, turned by its yaw. frame needs follows. The first shot in at order must have an over of 0. |
fade | to, over | Fades the veil to to, 0 clear to 1 black, over over seconds. |
bars | on, over | Brings the letterbox in (true) or out (false) over over seconds. |
shake | over, amp | Jitters the camera's position, decaying to nothing over over seconds. amp multiplies the scene's tremor. |
sound | cue, where? or who? | Sounds cue at where or from the member, through the play mod. Not both. |
music | name | Sets the row's music to name, or to null for "". |
prepare | where | Makes the land ready at where, ahead of a cut there (see Mods). |
Targets
A target (to, pos, look, where) is a cast name, a mark's name, or a point [x, z] or [x, up, z], up metres above the ground there. A cast name is looked for before a mark's. Every name must be a cast member or a mark. Everything stands on the scene's ground, and a point's height is the ground's as it is now, so ground raised under a mark or a shot raises it with it. A cast member is its feet for a walk, a face and a sound, and its head, head above its feet, for a shot's pos and look. A mark is { name, at }, at a point, and does nothing else.
Two clocks
The row's e is the elapsed time and always advances: shots, fades, bars, shakes and lines run on it, so a dolly keeps moving through a wait. The cue clock t advances unless a wait holds it, and a cue fires on the first step t reaches its at, in at order, cues with one at in the order written. A wait with nothing to wait for passes at once. So e − t is the time every wait so far has held. A walk is done within its reach or stop of its target, or limit seconds after it began. Fades and bars ramp in a straight line from where they stood to their target. A dolly eases with the smoothstep k²(3 − 2k), the position moving along a line, the facing turning the short way and the field of view blending.
Start, skip and end
The scene starts when a game rule calls the closed act start, or on the row's first step when the cue file's auto is true, or when the row's starts is true, on the first step every cast member's row is there. It does nothing while the scene runs or once it is done, so a scene plays once. On starting, each cast member is matched to its row, its direct is set to {} and the clocks go to 0. A cast member's row must come after the cutscene row.
The open act skip lets any seat skip the scene for every seat. On the next step the row plays the scene through to its end. It steps every step while a walk runs and settle seconds of steps of each quiet stretch (the steps after the last one a cue fired on, up to the next cue, the line going while a wait holds on it, or the end), and leaps the rest of the stretch without stepping the cast. A scene whose quiet stretches all fit in settle leaves the cast exactly where a played one would. A longer one leaves the cast as it stood settle seconds into each stretch. No sound or voice is raised while it plays through, and music is set as played.
At the end the row is done, the line, walks, faces and waits are cleared, and direct is null on the cast, so control returns. With go, every row of the kinds kinds names is sent go(go, ...arrive), after a skip too.
The row
The cutscene row carries only what changes. A rule can read it.
| Field | Meaning |
|---|---|
running, done, skip | Whether the scene is playing, has finished, or is to be played through. |
t, e | The cue clock and the elapsed time, in seconds. |
line | { who, text, until }, the line shown, until a value of e, or null. |
music | The name set by the last music cue, or null. |
prepare | The ground point [x, z] of the last prepare cue, or null. |
cast | Cast name to the id of its row. |
fired, wait, shot, fade, bars, shake, walks, faces | The playhead's state. fired is how many cues have fired, in at order. |
What a cast kind provides
A kind named in kinds carries a name and obeys direct in its tick. Its step reads no other cast member's fields, so the order the cast steps in changes nothing.
| Part | Meaning |
|---|---|
direct.walk | { to: [x, z], gear, stop, pace }. It seeks to with walker's seek, at the gear clip's speed, or at pace when gear is null. |
direct.face | [x, z], turned toward while not walking. |
direct.play, direct.gesture | { clip, holds, rate } and a clip. Each is started once and deleted, and deleted unplayed when its rig lacks the clip. |
While direct is set | The kind ignores its player's stick. direct is {} from the start and null at the end. |
Act advance(dt) | Runs exactly its own step. |
Act go(scene, ...arrive) | Moves the seat whose body it is through scenemanager, and does nothing on a row that is no seat's body. |
Methods
Acts
Of the cutscene row. A rule calls them with w.call.
start( )
Starts the scene. Closed, so only a game's rule calls it.
skip( )
Skips the scene for every seat while it runs. Open, so any seat may send it.
Rules
From #plugins/cutscene/cutscene.sim.ts.
longest( file ) : number
The most seconds of e a cue file can play: its end, plus at each wait the longest it can hold, a walk's limit or a line's for.
check( name, file )
Throws a sentence naming the file and the cue for a cue file the row cannot play.
placed( p, height ) : [x, y, z]
The world point of a point [x, z] or [x, up, z] on the ground whose height is height(x, z).
rooted( q, height ) : [x, up, z]
The point [x, up, z] of a world point q: the reverse of placed.
pose( d, rows, height ) : { pos, quat, fov } | undefined
Takes the cutscene row's data d and the rows as they stand. Gives the camera the row's shot draws, before any shake: a position, an orientation as a quaternion [x, y, z, w] and a field of view in degrees. Undefined with no shot, or while a member the shot names has no row.
view( to, cast, rows, height ) : { pos, quat, fov } | undefined
The camera of one shot held still: to is { pos, look, fov, head, follows?, frame? }, the fields of a shot cue with the cue file's head, and cast the row's cast names to ids, which stay on the row after the end. Undefined while a member it names has no row. A title's look carries the last shot on with it once the scene is done.
shaken( d, tremor ) : [x, y, z]
The shake's offset at the row's e, from the row's data d and the scene's tremor.
On the page
Through plugins.cutscene.
eye( ) : { pos, dir }
Where render3d's camera stands and its world −z direction. Call it after the first tick.
close( )
Gives the camera claim back, as the scene ending would.
The camera, the bars, the veil and the line
While the scene runs a shot, the page claims render3d's camera each frame and places it at the row's pose with the shake added, setting its field of view. It is the same on every seat and every frame the same rows are drawn: nothing eases and no clock of the page's is read, and a seat that arrives during a shot draws it from its first frame. It takes the camera from nobody. While another driver holds it, it places nothing and claims the camera again the first frame it is free. It places nothing on a frame whose rows lack a member the shot names. When the scene is done or skipped it gives the camera back the field of view it had when it took it. The scene needs render3d with a camera.
The bars, veil and line are drawn through ui while the scene runs, each only while it has something to show. A scene that shows none of them needs none of the panels, and no ui.
| Panel | What is drawn on it |
|---|---|
cutscene.top, cutscene.bottom | Each a bar the panel's width across and bars of its height, from the panel's top or bottom edge inward, filled in the style cutscene.bars. |
cutscene.veil | The panel filled in the style cutscene.veil at the fade's opacity. |
cutscene.line | who: text in the style cutscene.line, centred on the panel. |
Mods
Name them in world.cutscene.mods.
- audio
play: sounds asoundcue and asaycue'svoice, asplay(w, cue, at?, from?): the cue at the pointat, or from the rowfrom, or with neither at no place. A scene that names noplayplays no sound: its cues fire and nothing is heard. - terrain3d
land: the ground the page stands on, withheight(x, z), and optionallyprepare(x, z)andunprepare(). Apreparecue's point is handed to the land once, so it is made ready where the next cut lands, and let go when the scene stops. Withoutlandthe ground is flat at 0. The page places nothing while the land has no ground yet. A scene that names alandmust list its plugin.