Kzeroko KTM2

Cinematic Scene Data

Define camera tracks, actor cues, world events and subtitles with the complete cinematic-scene JSON format.

Updated Sep 26, 2026 17 min read

A cinematic scene is a server-loaded timeline that combines camera motion, actor cues, world events and subtitles. Positions are relative to a supplied pivot, so the same scene can play at different locations without rewriting its coordinates.

Where the files live

Place scene JSON in data/<namespace>/cinematic_scenes/*.json, including subdirectories. By default its resource path becomes the scene ID; an explicit id overrides it. Higher-priority packs replace the same resource ID. Different files can collide on an explicit scene ID: the loader logs the collision but has already replaced the earlier entry, and resource iteration is not sorted.

Camera-only Gecko animations are separate client assets under assets/<namespace>/camera_animations/*.json. A scene’s gecko track references their animation registry ID, not the JSON filename. The native spline track needs no such asset.

Minimal example

This short fixed shot uses the same camera-node fields as the bundled isekaiexpansion:hidden_hud_subtitle_scene. Save it as data/example/cinematic_scenes/fixed_shot.json to define example:fixed_shot; its 40 ticks equal 2 seconds at 20 ticks per second.

{
  "schema": 1,
  "length_ticks": 40,
  "camera": {
    "track": {
      "nodes": [
        { "t": 0, "pos": [0, 1.7, 4], "rot": [0, 180, 0], "fov": 60 }
      ]
    }
  }
}

An empty object also parses, but supplies no camera pose. It still has default playback settings, so a successfully loaded file is not necessarily a useful shot.

Fields

Root and playback

FieldTypeDefaultMeaning and limits
schemainteger1Stored version; the loader does not reject another integer.
idstringFile resource IDOverrides the lookup ID. Must be a resource identifier.
length_ticksintegerduration, then 160Scene length in ticks, clamped to at least 1.
durationinteger160Legacy length alias; length_ticks wins, but this value is still parsed if present.
playbackobjectDefaults belowHUD, input, blend and fade settings.
pivotobjectDefaults belowMetadata only; runtime uses the transform supplied by the trigger or caller.
actorsobjectTriggering playerActor-key map; player is inserted if absent.
cameraobjectEmpty track/effectsContains track and effects.
actor_tracksobjectEmptyActor-key → cue array.
eventsarray<object>EmptyServer world events.
subtitlesarray<object>EmptyClient subtitle cues.
FieldTypeDefaultMeaning and limits
hide_hudbooleantrueHide the ordinary HUD; subtitles have their own overlay.
lock_inputbooleantrueLock cinematic input and close other client screens while playing.
lock_movementbooleantrueHold viewer movement except scripted local-player locomotion.
allow_esc_skipbooleanfalsePermit viewer skip votes; all current viewers must vote.
fade_in_ticksinteger10Entry fade duration in ticks; positive values delay local playback and advance its starting age.
fade_out_ticksinteger10Exit fade duration in ticks.
blend_in_ticksintegerfade_in_ticksWithin a playback object, defaults to its entry fade. Without that object the blend default is 8.
blend_out_ticksintegerfade_out_ticksWithin a playback object, defaults to its exit fade. Without that object the blend default is 8.
pivot.sourcestringtriggerBlank resets to trigger; stored, not used to choose the pivot.
pivot.spacestringlocal_yawBlank resets to local_yaw; does not enable an alternate world-space mode.

All scene times are ticks. Length is clamped, but cue times are not checked against it: entries after the end never run. Playback fade/blend values have no parser range check; client transport normalises negative values to 0. Omitting playback gives blend values of 8; supplying an empty object gives 10, because absent blend fields inherit the fade values.

Pivot coordinates and actors

The supplied transform uses +X right, +Y up and −Z forward in the scene’s reference pose. Local yaw 180 faces forward. Position offsets rotate by pivot yaw minus 180; local yaw becomes pivot yaw plus local yaw minus 180. All positions use blocks, and rotations use degrees. The pivot metadata does not select or move the actual transform.

FieldTypeDefaultMeaning and limits
<actor-key>objectNo custom actorsTrimmed, limited to 64 characters; letters, digits, underscore, hyphen, dot and colon survive. Other characters become collapsed underscores; empty becomes player.
selectorstringtriggering_player for player; nearest otherwisetriggering_player, nearest or nearest_type. Unknown value falls back to nearest.
entity_typestringAbsentOptional entity type ID; applies to nearest searches.
radiusnumber16Search-box half extent in blocks, at least 1 at resolution. The injected default player actor uses 0 and bypasses the search.
namestringAbsentExact displayed-name match for nearest searches.
uuidstringAbsentValid UUID; a found living entity takes precedence over nearest filters.

For triggering_player, the player wins before UUID and other filters. Otherwise a UUID-resolved living entity wins; if it cannot be found, nearest resolution continues. Both nearest selectors use the same axis-aligned search box and optional type/name filters, then choose the closest living, present candidate to the pivot. The box is not a spherical radius test. An explicit type filter excludes the triggering player from that search.

Actor keys that normalise to the same text overwrite earlier keys. A supplied player definition is retained; only an absent key gets the default triggering-player definition. Unresolved custom actors are omitted at playback start.

Camera tracks and nodes

The first table describes camera and its track; the second describes each track.nodes entry.

FieldTypeDefaultMeaning and limits
trackobjectEmpty splineCamera track inside camera.
effectsarray<object>EmptyTimed screen effects inside camera.
typestringgecko if animation exists; otherwise splinespline or gecko; unknown becomes spline.
interpolationstringcatmull_romcatmull_rom or linear; unknown becomes catmull_rom.
animationstringAbsentAnimation registry ID for a gecko track; missing/unresolved gives no camera pose.
nodesarray<object>EmptySpline keyframes sorted by time. Empty gives no pose; a single node is a fixed pose.
FieldTypeDefaultMeaning and limits
tintegertime, then 0Tick position; non-negative. Present t wins without reading time.
timeinteger0Alias used only when t is absent.
posarray<number>[0, 0, 0]Exactly 3 local block coordinates: x, y, z.
rotarray<number>[0, 180, 0]Exactly 3 degree values: pitch, yaw, roll. See the target/rotation caveat below.
fovnumberAbsentDegrees; no parser range clamp. Both ends absent preserves the underlying FOV; one supplied endpoint supplies that segment’s FOV.
look_attargetAbsentResolved target overrides pitch/yaw. An unresolved target leaves authored rotation.
easestringlinearSegment ending at this node uses this easing.

Native tracks interpolate position with the selected interpolation, pitch linearly, and yaw/roll by wrapped-angle interpolation. The destination node supplies easing. A destination look target takes precedence over the previous node’s target; the target is not blended between actors.

Scene transport rebuilds the camera JSON. When a node has look_at, it writes that target and omits rot; the client therefore reparses the default rotation. Do not rely on authored roll or an authored fallback rotation surviving a targeted node through normal server playback. Untargeted nodes retain their rotation.

Gecko tracks sample elapsed scene time at 20 ticks per second and clamp to the animation’s length. This path does not apply the camera-only API’s loop/hold selection. Missing animation data produces no pose.

Targets

look_at and face accept an object using the fields below, a 3-number local position array, or the string walk_target. Other strings produce no target; null also means no target.

FieldTypeDefaultMeaning and limits
actorstringAbsentActor-key target, based on its feet position before offset.
posarray<number>AbsentExactly 3 local coordinates if no actor/walk target is selected.
offsetarray<number>[0, 0, 0]Exactly 3 local offsets; rotate around the pivot before adding.
walk_targetbooleanfalsetrue selects the movement destination, ahead of actor or pos.
targetstringEmptywalk_target is the only special string value here.

Object priority is walk target, then actor, then position. Actor targets use feet, so add an upward offset to frame the face. walk_target is meaningful for an actor cue; a camera node has no movement cue to supply that destination and cannot resolve it. Target actor strings are not normalised by the direct data parser, while the editor and client transport normalise them; use the same already-normalised key everywhere.

Camera effects

FieldTypeDefaultMeaning and limits
t / timeinteger0Shared non-negative tick position and alias rules.
typestringshakeshake or distortion; unknown becomes shake.
durationinteger20Ticks, at least 1.
strengthnumber1Shake pixels clamp to 0–48; distortion strength clamps to 0–1. Values at or below 0.001 do not start an effect.
frequencynumber14Shake frequency clamps to 0.1–60; distortion forwards it to the shader.
dampingnumber2.2Shake decay exponent, clamped to 0.1–8; unused by distortion.
speednumber1Distortion shader time multiplier; unused by shake.

Shake instances combine up to their strength cap; a new distortion replaces the current distortion. These are client screen effects, not changes to actor position. A late viewer starts only the remaining portion of an already-started effect, rather than replaying its full duration.

Actor tracks

FieldTypeDefaultMeaning and limits
<actor-key>array<object>No trackNormalised like actor keys. A missing resolved actor skips the track.
t / timeinteger0Shared non-negative tick position and alias rules.
typestringposepose, move_path, teleport, emoji, npc_body_emote or animation; unknown becomes pose.
durationinteger0At least 0 ticks. Movement needs a positive duration; meaning for other cue types is listed below.
modestringwalk when absentgrounded, walk, sprint, teleport_interpolated or navigation. Unknown/blank becomes grounded, not walk.
posarray<number>AbsentExactly 3 local coordinates; pose without it keeps current position.
yawnumberAbsentLocal degrees; absent uses current yaw or movement/facing behaviour.
pointsarray<array<number>>EmptyPath points, each exactly 3 coordinates. Takes precedence over pos for path sampling.
facetargetAbsentFacing target; walk_target refers to this cue’s final path point or pos.
idstringAbsentEmoji, NPC emote or player/NPC animation ID, depending on type.
forcebooleantrueEmoji FORCE versus REPLACE policy; not a general movement-force switch.
speednumber1Walk/sprint nominal speed multiplier, clamped to 0.25–4; navigation uses at least 0.05.
easestringlinearUsed for interpolated movement, not gait-based walk/sprint speed.
Cue or modePlayback behaviour
pose / teleportDiscrete server position/yaw change. The default walk mode, and explicit grounded/sprint modes, fit the pose to nearby ground.
move_path with walk / sprintCollision-aware locomotion. Non-player actors move on the server; each player actor moves through its own client’s movement input.
move_path with navigationPath-aware actors request navigation to the endpoint; other actors use interpolated placement.
move_path with grounded / teleport_interpolatedServer interpolation along the authored path; grounded does not add collision-aware ground fitting to each interpolated step.
emojiPlay the named sticker for the authored positive duration, otherwise the emoji system’s default.
npc_body_emoteForce the named body emote on a supported NPC; not a general player animation.
animationNPC busy animation on the server; registered player animation on clients. For players, duration controls entry blend, clamped to 0–10 ticks, not clip length.

Walk/sprint needs a path with non-zero length. A single point, or pos alone, does not form a walk from the actor’s current position. Movement does not snap an off-path actor to its first point; use an explicit pose when that cut is intended.

Gait ruleValue
Nominal walk speed0.2160 blocks per tick
Nominal sprint speed0.2808 blocks per tick
Authored speed multiplier0.25–4
Accepted timing speed0.80–1.25 × the scaled nominal speed

Path length divided by duration determines the requested speed; outside that band it is clamped and the loader reports a timing warning. The correction does not extend the cue window or scene length. A blocked actor, off-path start or too-short duration can still leave the actor short of its destination.

Movement cues run from their start through start plus duration, inclusive, when duration is positive. Overlapping cues are not rejected or merged; avoid giving the same actor competing movement instructions. Missing actors and missing animation IDs skip their action rather than rejecting the scene.

World events

FieldTypeDefaultMeaning and limits
t / timeinteger0Shared non-negative tick position and alias rules.
typestringsoundsound, effek, particle, weather or time; unknown becomes sound.
idstringAbsentSound/Effek/particle resource ID; those event types do nothing without it.
posarray<number>PivotExactly 3 local coordinates for positioned events.
volumenumber1Sound volume, passed through.
pitchnumber1Sound pitch, passed through.
scalenumber1Effek scale.
durationinteger20At least 1 tick; used by weather, not to terminate sounds or Effek instances.
categorystringplayersSound category, case-insensitive; unknown/blank falls back to players.
weatherstringclear at executionrain, thunder or storm; all other values clear weather. Applies to the whole scene world.
time_of_dayinteger-1World time value; negative does nothing.
countinteger1Particle count, at least 1.
spreadarray<number>[0, 0, 0]Exactly 3 particle spread values in world axes; not pivot-rotated.
speednumber0Particle speed argument.
visible_to_allbooleantrueForwarded only to the Effek broadcast helper; not a general event audience filter.

Events are server-side and fire once when due. Sounds and particles use world broadcasting, and weather/time alter the world rather than just viewers’ presentation. Particle events support simple registered particle types without extra payload data; block/item-style particle parameters are not part of this format.

Subtitles and easing

FieldTypeDefaultMeaning and limits
t / timeinteger0Shared non-negative tick position and alias rules.
durationinteger40Visible duration in ticks, at least 1.
speakerstringAbsentOptional translation key or literal; blank hides the speaker line.
textstringRequiredTranslation key or literal text.
chars_per_secondnumber48Text reveal speed; non-positive shows the full line immediately.
colorinteger / string0 (inherit theme)Integer ARGB or hexadecimal string with optional #. At most 6 hex digits gets opaque alpha; longer values cast to a 32-bit integer.

Only one subtitle is active at a time; a new cue replaces it. Text and speaker strings are resolved as translation keys, with literal strings remaining usable. The subtitle overlay can render while the ordinary HUD is hidden. A late viewer resumes an unexpired cue partway through its reveal.

Easing names are linear, step, ease_in_quad, ease_out_quad, ease_in_out_quad, ease_in_sine, ease_out_sine, ease_in_out_sine, ease_in_cubic, ease_out_cubic, ease_in_out_cubic, ease_in_back and ease_out_back. Input is case-insensitive, trims whitespace and accepts hyphens/spaces as underscores; compact names such as easeInOutQuad are also recognised. Unknown names fall back to linear.

Validation

InputResult
Missing optional fieldUses the field-specific default above
Unknown fieldIgnored; it does not enable another event or execution mode
Wrong type for an optional object/array containerTreated as absent; this differs from a malformed item inside a valid array
Malformed array entry, invalid resource ID/UUID, missing subtitle text, vector with other than 3 elements, failed scalar conversionRejects that scene resource; other scenes continue
Unknown recognised-option valueFalls back to that option group’s default; it is not a load error
Unsupported schema integerStored; no version rejection or migration
Duplicate explicit scene IDLogs an error after replacing the previous loaded entry; no stable resource-order winner
Empty root objectAccepted with defaults
Invalid JSON textDoes not produce a valid scene
Failure during reloadThe newly collected map replaces the old map, including partial success; failed old scenes are not retained

The parser does not impose finite-number checks, maximum timeline length, maximum keyframe count or existence checks for every referenced asset. Use finite values and valid IDs; successful parsing does not establish that an actor, animation, sound or particle is available.

Normal scene-start transport sends a compressed authoring draft, limited to 262144 compressed bytes on receipt, and at most 64 actor bindings with keys up to 64 characters. This is a compressed-size bound, not a decompressed-memory limit. Client reconstruction rounds many vector, rotation and effect values to 3 decimal places, normalises target keys and discards unknown fields. Keep timelines within that transport budget and avoid depending on finer precision.

Reloading

/reload rebuilds the server scene catalogue and increments its revision, including reloads with errors. Starting a scene sends its current definition and resolved actor bindings; clients do not need the server data pack locally for native tracks. Gecko camera animations and other visual assets still belong in client resource packs.

Active server playbacks retain the scene object they started with. Reloading a definition changes later starts, not the existing timeline. Restart the scene to inspect changes, and reload client resources separately after editing camera animation assets.

Emoji data defines stickers used by emoji cues. NPC assets covers NPC animation resources, and Developer editor preferences explains the shared editor theme controls.