الرئيسية

توثيق API المحرك

كل ما يحتاجه الذكاء الاصطناعي ليتحكم في المحرك بالكامل. النسخة النصية: /llms.txt

المصادقة

الـ AI (المتحكم الكامل): أرسل الهيدر X-Engine-Key: <ENGINE_API_KEY> أو Authorization: Bearer ….

المحرك (المتصفح على الهاتف): يستخدم ?token=<viewerToken> الخاص بالمشهد فقط.

حلقة التحكم (Loop)

1. POST https://cinema-ai-engine.pages.dev/api/scenes                    -> {scene:{id, viewerToken, viewerUrl}}
2. (human) opens viewerUrl on phone -> engine online
3. POST /api/scenes/:id/commands  [ {op:...}, ... ]   (HANDS)
   optional ?wait=10 to block until executed
4. GET  /api/scenes/:id/state                         (EYES: structured)
5. GET  /api/scenes/:id/frames/latest                 (EYES: JPEG image)
   or  ?format=json for base64 data URL
6. POST /api/scenes/:id/director {brief:"..."}        (built-in LLM director)
7. GET  /api/scenes/:id/renders  -> videoUrl          (final video)

نقاط النهاية (Endpoints)

GET    /api/health
GET    /api/manifest                       command catalog (JSON)
GET    /llms.txt                           full AI guide (text)

POST   /api/scenes                         {name, description}
GET    /api/scenes
GET    /api/scenes/:id
PATCH  /api/scenes/:id
DELETE /api/scenes/:id

POST   /api/scenes/:id/commands            command | [commands] | {commands:[...]}   ?wait=sec
GET    /api/scenes/:id/commands            ?since=seq&status=pending|done|error
DELETE /api/scenes/:id/commands            cancel all pending

GET    /api/scenes/:id/state               engine state (objects, camera, fps, onScreen...)
GET    /api/scenes/:id/frames              list frames
GET    /api/scenes/:id/frames/latest       JPEG (or ?format=json)
GET    /api/scenes/:id/frames/:fid

GET    /api/scenes/:id/renders
GET    /api/scenes/:id/renders/:rid
GET    /api/scenes/:id/renders/:rid/video  WebM/MP4 bytes
DELETE /api/scenes/:id/renders/:rid

GET    /api/scenes/:id/events              engine log
POST   /api/scenes/:id/director            {brief, model?, dryRun?, useVision?}
GET    /api/presets                        ready-made films
POST   /api/scenes/:id/preset              {name, render?, fps?, width?, height?}
GET    /api/scenes/:id/export              film JSON
POST   /api/scenes/:id/import              {film}
POST   /api/scenes/:id/duplicate
GET    /api/stats
POST   /api/maintenance/cleanup
POST   /api/scenes/:id/checkpoints         {name?}  save film so far (rewind point)
GET    /api/scenes/:id/checkpoints
POST   /api/scenes/:id/checkpoints/:cid/restore   rewind (cancels pending, reset+replay)
DELETE /api/scenes/:id/checkpoints/:cid
GET    /api/macros · GET/PUT/DELETE /api/macros/:name   {description, params:{var:default}, commands:[... {{var}} ...]}
POST   /api/scenes/:id/macros/:name        {vars:{...}, snapshot?:bool}  run a macro
POST   /api/scenes/:id/auto?wait=15        {target?, shot?, look?, targetMean?}  auto-director pass (expose+snapshot+meter)
GET    /api/scenes/:id/state?view=summary|ids|diff   compact state views (save tokens)
POST   /api/scenes/:id/pair {ttl?}         6-digit pairing code + qrUrl (human opens /pair on the phone and types it)
GET    /api/qr?text=...                     QR code SVG
GET    /api/scenes/:id/stream?key=|token=  SSE live stream: events, acks, frames (EventSource)
POST   /api/scenes/:id/lock {owner, ttl?, force?} · GET · DELETE ?owner=   collaboration lock for several AIs
POST   /api/story/plan                     {prompt}  one sentence -> plan + screenplay (no LLM)
POST   /api/scenes/:id/story               {prompt, render?}  one sentence -> full film (runs + records + critiques)
POST   /api/scenes/:id/polish              {targetScore?, rounds?, target?}  critique->fix loop until score reached
GET    /api/films · POST /api/films · POST /api/scenes/:id/films (save current) · GET/DELETE /api/films/:fid · POST /api/scenes/:id/films/:fid/play
POST   /api/screenplay/compile             {text}  dry-run: screenplay text -> commands (no LLM)
POST   /api/scenes/:id/screenplay          {text, strict?, snapshot?}  compile + queue a whole film
GET    /api/screenplay/grammar · /api/screenplay/example
POST   /api/assets  (raw body+?name= | multipart file | json {url})  → /api/assets/:id   (GLB/images/audio on R2)
GET    /api/assets · DELETE /api/assets/:id
GET    /api/scenes/:id/devices             multi-viewer: which phone is PRIMARY
GET    /control/:id                        live control panel (human, needs key)

-- engine side (viewer token) --
POST   /api/engine/:id/sync                {since, state, acks, events} -> {commands}
POST   /api/engine/:id/frame               {data(base64), label, width, height, sceneTime}
POST   /api/engine/:id/render/begin
POST   /api/engine/:id/render/:rid/chunk?idx=n   (binary body)
POST   /api/engine/:id/render/:rid/complete
POST   /api/engine/:id/render/:rid/fail

كتالوج الأوامر (79)

scene

scene.reset

Remove all objects, lights, particles, animations and reset camera/effects to defaults.

Params
{
  "keepCamera": "bool (optional)"
}
Example
{
  "op": "scene.reset"
}
scene.config

Configure global scene settings.

Params
{
  "background": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" | \"transparent\"",
  "fog": "{ color, near, far } | { color, density } (exp2) | null",
  "exposure": "number (0.1-4) tone-mapping exposure",
  "toneMapping": "none | linear | reinhard | cineon | aces | agx | neutral",
  "shadows": "bool",
  "shadowMapSize": "512|1024|2048",
  "pixelRatio": "number 0.5-2 (lower = faster on phone)",
  "environment": "null | \"studio\" | \"sunset\" | \"night\" | \"dawn\" | \"warehouse\" | \"forest\" | \"city\" (procedural HDR-like env lighting)",
  "gravity": "number (for particles)"
}
Example
{
  "op": "scene.config",
  "background": "#05070f",
  "fog": {
    "color": "#05070f",
    "near": 20,
    "far": 120
  },
  "exposure": 1.1,
  "toneMapping": "aces",
  "environment": "night"
}
scene.snapshot

Capture the current frame (the AI's EYES). Uploads a JPEG to the server; read it via GET /api/scenes/:id/frames/latest.

Params
{
  "label": "string",
  "quality": "number 0.3-0.95",
  "width": "max width px (default 960)",
  "delay": "seconds to wait before capturing (1-2 after tweens/titles)"
}
Example
{
  "op": "scene.snapshot",
  "label": "check-lighting",
  "quality": 0.8,
  "delay": 1
}
scene.autoSnapshot

Automatically capture a frame every N seconds (0 disables). Lets the AI watch continuously.

Params
{
  "interval": "seconds (0 = off)",
  "quality": "number",
  "width": "px"
}
Example
{
  "op": "scene.autoSnapshot",
  "interval": 2,
  "quality": 0.6,
  "width": 640
}
scene.setTime

Seek the master timeline to time t (seconds).

Params
{
  "t": "seconds"
}
Example
{
  "op": "scene.setTime",
  "t": 3.5
}
scene.play

Start master timeline.

Params
{}
Example
{
  "op": "scene.play"
}
scene.pause

Pause master timeline.

Params
{}
Example
{
  "op": "scene.pause"
}
scene.timeline

Set timeline length/loop/speed. Animations use timeline time.

Params
{
  "duration": "seconds",
  "loop": "bool",
  "speed": "number (1 = realtime)"
}
Example
{
  "op": "scene.timeline",
  "duration": 12,
  "loop": false,
  "speed": 1
}
scene.inspect

AI EYES: one contact-sheet image of the scene/object from N angles (turnaround + top). Camera restored. Result -> GET frames/latest.

Params
{
  "target": "object id | [x,y,z]",
  "angles": "4|6|8",
  "radius": "distance",
  "height": "camera height offset",
  "width": "total px (default 1024)"
}
Example
{
  "op": "scene.inspect",
  "target": "hero",
  "angles": 6,
  "radius": 8
}
scene.storyboard

AI EYES: frames at several timeline times in one image (see the whole film). Timeline restored.

Params
{
  "times": "array of seconds (default 6 evenly spaced)",
  "width": "total px",
  "cols": "columns"
}
Example
{
  "op": "scene.storyboard",
  "times": [
    0,
    2,
    4,
    6,
    8,
    10
  ]
}
scene.measure

Bounding boxes, pairwise distances/overlaps and camera visibility (JSON, no image). Use to check collisions and framing.

Params
{
  "ids": "array of ids (default all)"
}
Example
{
  "op": "scene.measure",
  "ids": [
    "hero",
    "car"
  ]
}
scene.quality

Performance tier: low | medium | high | ultra.

Params
{
  "tier": "low | medium | high | ultra"
}
Example
{
  "op": "scene.quality",
  "tier": "medium"
}

environment

env.sky

Add a procedural sky dome with a sun. Presets tune colors and sun angle.

Params
{
  "preset": "day | sunset | night | dawn | space | overcast | alien",
  "sunPosition": "[x,y,z] number array (direction)",
  "turbidity": "number",
  "rayleigh": "number",
  "stars": "bool (add star field)",
  "starCount": "number"
}
Example
{
  "op": "env.sky",
  "preset": "sunset",
  "stars": false
}
env.ground

Add a ground plane (optionally with grid / procedural terrain / reflective water).

Params
{
  "type": "plane | grid | terrain | water | checker | none",
  "size": "number (default 200)",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "color2": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" (checker second color)",
  "height": "terrain max height",
  "roughness": "number",
  "metalness": "number",
  "reflective": "bool (mirror-like floor)"
}
Example
{
  "op": "env.ground",
  "type": "terrain",
  "size": 300,
  "color": "#3b4a2e",
  "height": 14
}
weather.set

One-call weather. type: rain | snow | lightning | wind | clear. Lightning = random flashes + thunder light. Wind sways trees.

Params
{
  "type": "rain | snow | lightning | wind | clear",
  "intensity": "0-1",
  "count": "particles override"
}
Example
{
  "op": "weather.set",
  "type": "rain",
  "intensity": 0.8
}

objects

object.add

Add a 3D object. Types: box, sphere, cylinder, cone, torus, torusKnot, plane, capsule, icosahedron, octahedron, dodecahedron, ring, text (billboard sprite), text3d (extruded 3D letters), group (empty container), model (GLTF/GLB url), tree, rock, building, car, human (procedural low-poly props; human supports walk:true), lamp (street lamp with light), crystal (glowing gem).

Params
{
  "id": "string unique id (auto if omitted)",
  "type": "see desc",
  "position": "[x,y,z] number array",
  "rotation": "[x,y,z] number array (degrees)",
  "scale": "[x,y,z] number array | number",
  "size": "[x,y,z] number array | number (geometry dimensions)",
  "segments": "number (geometry detail)",
  "material": "{ color, emissive, emissiveIntensity, metalness(0-1), roughness(0-1), opacity(0-1), transparent(bool), wireframe(bool), flatShading(bool), side(\"front\"|\"back\"|\"double\"), texture(url), envMapIntensity, type(\"standard\"|\"physical\"|\"basic\"|\"toon\"|\"normal\") , clearcoat, transmission, ior }",
  "castShadow": "bool",
  "receiveShadow": "bool",
  "parent": "id of parent object/group",
  "text": "string (type=text)",
  "fontSize": "number (type=text)",
  "url": "GLB/GLTF url (type=model)",
  "playClip": "animation clip name or \"*\" (type=model)",
  "visible": "bool",
  "spin": "{ axis:[x,y,z], speed: deg/sec } continuous rotation",
  "float": "{ amplitude, speed } bobbing motion",
  "walk": "bool (type=human) animate legs/arms while moving",
  "windowColor": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" (type=building)",
  "clothColor": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" (type=human)",
  "depth": "number (type=text3d extrusion)",
  "tag": "string label for grouping"
}
Example
{
  "op": "object.add",
  "id": "hero",
  "type": "sphere",
  "position": [
    0,
    1.5,
    0
  ],
  "size": 1.5,
  "material": {
    "color": "#ffcc00",
    "metalness": 0.8,
    "roughness": 0.2,
    "emissive": "#ff6600",
    "emissiveIntensity": 0.6
  },
  "castShadow": true
}
object.update

Update any property of an existing object (same params as object.add; partial). Use `duration` to tween the change.

Params
{
  "id": "string",
  "duration": "seconds (optional tween)",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
  "...": "any object.add params"
}
Example
{
  "op": "object.update",
  "id": "hero",
  "position": [
    3,
    2,
    -1
  ],
  "material": {
    "color": "#00ffcc"
  },
  "duration": 2,
  "easing": "easeInOut"
}
object.remove

Remove object (and children).

Params
{
  "id": "string | array of ids | \"tag:<tag>\""
}
Example
{
  "op": "object.remove",
  "id": "hero"
}
object.animate

Keyframe animation for an object on the master timeline. Each keyframe has time t and any of position/rotation/scale/opacity/color/emissiveIntensity.

Params
{
  "id": "string object id",
  "keyframes": "[{ t, position?, rotation?, scale?, opacity?, color?, emissiveIntensity? }]",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
  "loop": "bool | \"pingpong\"",
  "relative": "bool (t relative to now)"
}
Example
{
  "op": "object.animate",
  "id": "hero",
  "keyframes": [
    {
      "t": 0,
      "position": [
        0,
        1,
        0
      ],
      "scale": 1
    },
    {
      "t": 2,
      "position": [
        0,
        4,
        0
      ],
      "scale": 1.5
    },
    {
      "t": 4,
      "position": [
        5,
        1,
        -3
      ],
      "scale": 1
    }
  ],
  "easing": "easeInOutCubic"
}
object.lookAt

Rotate object to face a point or another object.

Params
{
  "id": "string",
  "target": "[x,y,z] number array | object id"
}
Example
{
  "op": "object.lookAt",
  "id": "car1",
  "target": "hero"
}
object.path

Move object along a smooth curve through points, over duration, optionally facing forward.

Params
{
  "id": "string",
  "points": "array of [x,y,z] number array",
  "duration": "seconds",
  "startAt": "timeline t (default now)",
  "loop": "bool",
  "faceForward": "bool",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
  "closed": "bool"
}
Example
{
  "op": "object.path",
  "id": "drone",
  "points": [
    [
      0,
      5,
      0
    ],
    [
      10,
      6,
      -5
    ],
    [
      0,
      8,
      -12
    ],
    [
      -10,
      5,
      -5
    ]
  ],
  "duration": 8,
  "loop": true,
  "faceForward": true,
  "closed": true
}
object.clone

Duplicate object N times with offsets (crowds, forests, cities).

Params
{
  "id": "source id",
  "count": "number",
  "offset": "[x,y,z] number array step",
  "jitter": "number random spread",
  "prefix": "id prefix",
  "grid": "[cols, rows] arrange in grid",
  "circle": "{ radius } arrange in circle"
}
Example
{
  "op": "object.clone",
  "id": "tree",
  "count": 40,
  "jitter": 40,
  "prefix": "forest"
}
object.drop

Gravity drop with bounce onto ground (y=0) or floor.

Params
{
  "id": "string | array",
  "height": "start height",
  "bounce": "0-1",
  "floor": "y"
}
Example
{
  "op": "object.drop",
  "id": "crate",
  "height": 8,
  "bounce": 0.4
}
object.explode

Break an object into flying fragments + flash + particles + shake, then remove it.

Params
{
  "id": "string",
  "force": "number",
  "fragments": "number (default 24)"
}
Example
{
  "op": "object.explode",
  "id": "crate",
  "force": 8
}
object.attach

Parent an object (or the camera with id "camera") to another object with an offset so it follows it.

Params
{
  "id": "object id | \"camera\"",
  "to": "target object id | null (detach)",
  "offset": "[x,y,z] number array"
}
Example
{
  "op": "object.attach",
  "id": "lamp1",
  "to": "car",
  "offset": [
    0,
    2,
    0
  ]
}
object.trail

Glowing motion trail behind a moving object.

Params
{
  "id": "string",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "length": "points (default 60)",
  "width": "number",
  "enabled": "bool"
}
Example
{
  "op": "object.trail",
  "id": "ship",
  "color": "#7df9ff",
  "length": 80
}
object.label

Floating text label above an object (billboard). Empty text removes it.

Params
{
  "id": "string",
  "text": "string",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "size": "number"
}
Example
{
  "op": "object.label",
  "id": "hero",
  "text": "HERO",
  "color": "#ffd700"
}

lights

light.add

Add a light. Types: ambient, hemisphere, directional (sun), point, spot, rect (area).

Params
{
  "id": "string",
  "type": "see desc",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "groundColor": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" (hemisphere)",
  "intensity": "number. Ranges: ambient/hemisphere 0.2-1.5, directional 0.5-4, point 1-15, spot 2-25 (>40 blows out to white)",
  "position": "[x,y,z] number array",
  "target": "[x,y,z] number array | object id (directional/spot)",
  "distance": "number",
  "decay": "number",
  "angle": "degrees (spot cone)",
  "penumbra": "0-1",
  "castShadow": "bool",
  "width": "rect width",
  "height": "rect height",
  "helper": "bool (debug gizmo)",
  "volumetric": "bool (spot only) visible light cone / god rays",
  "shadowSize": "directional shadow area half-size (default 30)",
  "flicker": "{ amount, speed } candle/fire flicker",
  "pulse": "{ min, max, speed }"
}
Example
{
  "op": "light.add",
  "id": "key",
  "type": "spot",
  "color": "#ffffff",
  "intensity": 10,
  "position": [
    5,
    8,
    5
  ],
  "target": "hero",
  "angle": 30,
  "penumbra": 0.4,
  "castShadow": true
}
light.update

Update light params (partial; `duration` tweens).

Params
{
  "id": "string",
  "duration": "seconds",
  "...": "light.add params"
}
Example
{
  "op": "light.update",
  "id": "key",
  "intensity": 0,
  "duration": 1.5
}
light.remove

Remove light.

Params
{
  "id": "string"
}
Example
{
  "op": "light.remove",
  "id": "key"
}

camera

camera.set

Set camera instantly (or tween with duration).

Params
{
  "position": "[x,y,z] number array",
  "lookAt": "[x,y,z] number array | object id",
  "fov": "degrees",
  "roll": "degrees",
  "near": "number",
  "far": "number",
  "duration": "seconds",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo"
}
Example
{
  "op": "camera.set",
  "position": [
    8,
    4,
    10
  ],
  "lookAt": "hero",
  "fov": 45,
  "duration": 2
}
camera.animate

Camera keyframes on the master timeline (dolly, crane, pan, zoom, push-in...).

Params
{
  "keyframes": "[{ t, position?, lookAt?, fov?, roll? }]",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
  "relative": "bool"
}
Example
{
  "op": "camera.animate",
  "keyframes": [
    {
      "t": 0,
      "position": [
        0,
        2,
        20
      ],
      "lookAt": [
        0,
        1,
        0
      ],
      "fov": 60
    },
    {
      "t": 5,
      "position": [
        4,
        3,
        6
      ],
      "lookAt": "hero",
      "fov": 35
    }
  ],
  "easing": "easeInOutCubic"
}
camera.orbit

Continuously orbit around a target. speed in deg/sec. Set speed 0 or enabled:false to stop.

Params
{
  "target": "[x,y,z] number array | object id",
  "radius": "number",
  "height": "number",
  "speed": "deg/sec",
  "startAngle": "deg",
  "enabled": "bool"
}
Example
{
  "op": "camera.orbit",
  "target": "hero",
  "radius": 12,
  "height": 4,
  "speed": 15
}
camera.follow

Follow an object with an offset and smoothing (chase cam).

Params
{
  "target": "object id",
  "offset": "[x,y,z] number array",
  "lerp": "0-1 smoothing",
  "lookAhead": "number",
  "enabled": "bool"
}
Example
{
  "op": "camera.follow",
  "target": "car1",
  "offset": [
    0,
    3,
    -8
  ],
  "lerp": 0.08
}
camera.shake

Handheld / impact camera shake.

Params
{
  "intensity": "number (0.05 subtle, 1 violent)",
  "duration": "seconds (0 = continuous until intensity 0)",
  "frequency": "number"
}
Example
{
  "op": "camera.shake",
  "intensity": 0.4,
  "duration": 1.2
}
camera.path

Fly camera along smooth spline through points.

Params
{
  "points": "array of [x,y,z] number array",
  "lookAt": "[x,y,z] number array | object id | \"forward\"",
  "duration": "seconds",
  "startAt": "t",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
  "loop": "bool"
}
Example
{
  "op": "camera.path",
  "points": [
    [
      20,
      5,
      20
    ],
    [
      0,
      8,
      25
    ],
    [
      -20,
      5,
      20
    ],
    [
      -10,
      3,
      0
    ]
  ],
  "lookAt": "hero",
  "duration": 10
}
camera.dolly

Move camera along its view axis (negative = push in). Optional fov for dolly-zoom (Vertigo).

Params
{
  "distance": "meters (+ back, - forward)",
  "duration": "seconds",
  "fov": "target fov",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo"
}
Example
{
  "op": "camera.dolly",
  "distance": -6,
  "duration": 4,
  "fov": 70
}
camera.preset

Classic framing relative to a target: wide, medium, closeup, lowAngle, highAngle, overShoulder, birdsEye, dutch.

Params
{
  "target": "object id",
  "shot": "see desc",
  "duration": "seconds tween",
  "side": "left | right"
}
Example
{
  "op": "camera.preset",
  "target": "hero",
  "shot": "lowAngle",
  "duration": 2
}
camera.frame

EXACT framing by geometry: put the target at a screen anchor (screenX/screenY 0-1, thirds = 0.333/0.667) filling a fraction of frame height, from a chosen azimuth/elevation. Use this to fix "subject too small / off thirds" precisely.

Params
{
  "target": "object id",
  "fill": "0.05-0.95 fraction of frame height (default 0.45)",
  "screenX": "0-1 (default 0.5)",
  "screenY": "0-1 (default 0.5)",
  "azimuth": "deg around target, 0 = front (default 35)",
  "elevation": "deg (default 12)",
  "fov": "deg",
  "roll": "deg",
  "headroom": "extra space above in radii",
  "duration": "seconds tween",
  "easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo"
}
Example
{
  "op": "camera.frame",
  "target": "hero",
  "fill": 0.5,
  "screenX": 0.667,
  "screenY": 0.4,
  "azimuth": 40,
  "elevation": 10,
  "duration": 1.5
}

effects

fx.set

Post-processing look. All optional; duration tweens.

Params
{
  "bloom": "{ enabled, strength(0-3), radius(0-1), threshold(0-1) }",
  "vignette": "{ enabled, darkness(0-2), offset(0-2) }",
  "grain": "{ enabled, amount(0-1) }",
  "chromatic": "{ enabled, amount(0-0.02) }",
  "colorGrade": "{ saturation, contrast, brightness, temperature(-1..1), tint(color), tintAmount }",
  "letterbox": "{ enabled, ratio (2.39 cinematic) }",
  "dof": "{ enabled, focus (distance m | object id), aperture (0.0005-0.05), maxblur (0.005-0.02) } depth of field",
  "pixelate": "{ enabled, size }",
  "scanlines": "{ enabled, amount }",
  "duration": "seconds"
}
Example
{
  "op": "fx.set",
  "bloom": {
    "enabled": true,
    "strength": 1.2,
    "threshold": 0.6
  },
  "vignette": {
    "enabled": true,
    "darkness": 1.1
  },
  "letterbox": {
    "enabled": true,
    "ratio": 2.39
  },
  "colorGrade": {
    "saturation": 1.1,
    "contrast": 1.1,
    "temperature": 0.2
  }
}
fx.fade

Fade screen from/to a color (fade in from black, fade out to white...).

Params
{
  "from": "0-1 opacity",
  "to": "0-1",
  "duration": "seconds",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\""
}
Example
{
  "op": "fx.fade",
  "from": 1,
  "to": 0,
  "duration": 2,
  "color": "#000000"
}
fx.flash

Quick screen flash (explosion, lightning).

Params
{
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "duration": "seconds",
  "intensity": "0-1"
}
Example
{
  "op": "fx.flash",
  "color": "#ffffff",
  "duration": 0.25
}
fx.slowmo

Timeline speed ramp (bullet-time). speed<1 slow, >1 fast.

Params
{
  "speed": "number",
  "duration": "seconds to ramp",
  "hold": "seconds to hold then return to 1"
}
Example
{
  "op": "fx.slowmo",
  "speed": 0.2,
  "duration": 0.5,
  "hold": 2
}
fx.look

Apply a complete color look in one call: teal_orange | noir | vintage | cyberpunk | dream | horror | documentary | none.

Params
{
  "name": "see desc",
  "duration": "seconds tween"
}
Example
{
  "op": "fx.look",
  "name": "teal_orange",
  "duration": 1
}
music.beatFx

Beat-synced effects: pulse a light, pump an object scale, flash, camera nudge on every N beats.

Params
{
  "light": "light id",
  "object": "object id",
  "flash": "bool",
  "shake": "intensity",
  "every": "beats (default 1)",
  "amount": "0-1 (default 0.35)",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "enabled": "false to stop"
}
Example
{
  "op": "music.beatFx",
  "light": "neonA",
  "object": "hero",
  "every": 2
}

particles

particles.add

GPU point particle system. Presets: fire, smoke, sparks, rain, snow, dust, stars, embers, magic, explosion, fog, confetti, fireflies.

Params
{
  "id": "string",
  "preset": "see desc",
  "position": "[x,y,z] number array",
  "count": "number (200-5000; keep low on phone)",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "color2": "CSS color string, e.g. \"#ff8800\" or \"skyblue\" (end color)",
  "size": "number",
  "speed": "number",
  "spread": "number | [x,y,z] number array",
  "lifetime": "seconds",
  "gravity": "number",
  "emit": "bool (false = burst once)",
  "parent": "object id (attach to object)",
  "area": "[x,y,z] number array (rain/snow volume)"
}
Example
{
  "op": "particles.add",
  "id": "fire1",
  "preset": "fire",
  "position": [
    0,
    0,
    0
  ],
  "count": 800,
  "size": 0.6
}
particles.update

Update particle system params.

Params
{
  "id": "string",
  "...": "particles.add params"
}
Example
{
  "op": "particles.update",
  "id": "fire1",
  "emit": false
}
particles.remove

Remove particle system.

Params
{
  "id": "string"
}
Example
{
  "op": "particles.remove",
  "id": "fire1"
}

overlay

title.show

Cinematic title card / subtitle overlay (2D). Supports Arabic and RTL.

Params
{
  "id": "string (default \"main\")",
  "text": "string",
  "subtitle": "string",
  "position": "center | top | bottom | lowerThird",
  "duration": "seconds (0 = until hidden)",
  "style": "cinematic | minimal | bold | typewriter | neon | subtitle",
  "color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
  "size": "number (vw units, default 6)",
  "font": "CSS font-family",
  "fadeIn": "seconds",
  "fadeOut": "seconds",
  "letterSpacing": "em",
  "align": "left | center | right",
  "rtl": "bool"
}
Example
{
  "op": "title.show",
  "text": "CHAPTER ONE",
  "subtitle": "The Awakening",
  "position": "center",
  "duration": 4,
  "style": "cinematic"
}
title.hide

Hide a title overlay.

Params
{
  "id": "string"
}
Example
{
  "op": "title.hide",
  "id": "main"
}
hud.set

Engine HUD options (debug info for the human viewer; AI sees stats via /state anyway).

Params
{
  "stats": "bool",
  "watermark": "string | null",
  "safeArea": "bool"
}
Example
{
  "op": "hud.set",
  "stats": false,
  "watermark": null
}

audio

audio.play

Play an audio URL (music/sfx). Mobile may require the viewer to tap once first; engine reports blocked state.

Params
{
  "id": "string",
  "url": "string",
  "volume": "0-1",
  "loop": "bool",
  "fadeIn": "seconds",
  "at": "timeline t"
}
Example
{
  "op": "audio.play",
  "id": "music",
  "url": "https://example.com/track.mp3",
  "volume": 0.6,
  "loop": true
}
audio.stop

Stop audio.

Params
{
  "id": "string",
  "fadeOut": "seconds"
}
Example
{
  "op": "audio.stop",
  "id": "music",
  "fadeOut": 2
}
speech.say

Text-to-speech narration in the phone browser (supports Arabic). Also shows optional subtitle. Requires the viewer to have tapped once (mobile autoplay).

Params
{
  "text": "string",
  "lang": "ar-EG | ar-SA | en-US | ...",
  "rate": "0.5-2",
  "pitch": "0-2",
  "volume": "0-1",
  "subtitle": "bool show text as subtitle",
  "voice": "voice name substring"
}
Example
{
  "op": "speech.say",
  "text": "في البداية كان الظلام",
  "lang": "ar-EG",
  "subtitle": true
}
speech.stop

Stop narration.

Params
{}
Example
{
  "op": "speech.stop"
}
music.play

Generative film score synthesized live in the browser (no files): chords, bass, arps, pads, drums matched to a mood. Recorded into the video. Moods: horror, melancholy, action, dream, romance, epic, commercial, documentary, cyberpunk, calm, neutral. Needs one tap on the phone (autoplay policy) — emits music_blocked event otherwise.

Params
{
  "mood": "see desc",
  "bpm": "override tempo",
  "scale": "minor|major|dorian|phrygian|pentMinor|lydian|wholeTone",
  "root": "MIDI note (default per mood)",
  "intensity": "0-1 (default 0.7)",
  "volume": "0-1 (default 0.5)",
  "drums": "bool",
  "arp": "bool",
  "fadeIn": "seconds",
  "seed": "number (reproducible)"
}
Example
{
  "op": "music.play",
  "mood": "epic",
  "intensity": 0.8
}
music.stop

Fade out and stop the score.

Params
{
  "fade": "seconds (default 1.5)"
}
Example
{
  "op": "music.stop",
  "fade": 2
}
music.set

Live adjust volume / intensity (e.g. build-up before a climax).

Params
{
  "volume": "0-1",
  "intensity": "0-1"
}
Example
{
  "op": "music.set",
  "intensity": 1
}

render

render.start

Record the canvas into a WebM/MP4 video for `duration` seconds and upload it. Timeline is rewound to `from` and played. Result at GET /api/scenes/:id/renders.

Params
{
  "renderId": "string (auto)",
  "duration": "seconds",
  "from": "timeline start t (default 0)",
  "fps": "24|30|60",
  "width": "px",
  "height": "px",
  "bitrate": "bits/sec (default 6e6)",
  "mime": "video/webm | video/mp4 (auto best)"
}
Example
{
  "op": "render.start",
  "duration": 10,
  "from": 0,
  "fps": 30,
  "width": 1280,
  "height": 720
}
render.cancel

Cancel active recording.

Params
{}
Example
{
  "op": "render.cancel"
}

sequencing

sequence

Run a list of commands at scheduled timeline times (a full shot list in one call). Each step: { at: seconds, cmd: <any command> }. Steps with no `at` run immediately.

Params
{
  "steps": "[{ at, cmd }]",
  "autoplay": "bool (start timeline)",
  "resetTimeline": "bool"
}
Example
{
  "op": "sequence",
  "resetTimeline": true,
  "autoplay": true,
  "steps": [
    {
      "at": 0,
      "cmd": {
        "op": "fx.fade",
        "from": 1,
        "to": 0,
        "duration": 2
      }
    },
    {
      "at": 1,
      "cmd": {
        "op": "title.show",
        "text": "GENESIS",
        "duration": 3
      }
    },
    {
      "at": 5,
      "cmd": {
        "op": "camera.shake",
        "intensity": 0.5,
        "duration": 1
      }
    },
    {
      "at": 6,
      "cmd": {
        "op": "fx.flash",
        "color": "#ffffff",
        "duration": 0.3
      }
    }
  ]
}
batch

Execute many commands immediately in order (one round-trip).

Params
{
  "commands": "array of commands"
}
Example
{
  "op": "batch",
  "commands": [
    {
      "op": "scene.reset"
    },
    {
      "op": "env.sky",
      "preset": "night",
      "stars": true
    }
  ]
}

editing

shot.save

Save the current camera (position/lookAt/fov/roll) as a named shot for later cuts.

Params
{
  "name": "string",
  "position": "[x,y,z] number array (optional override)",
  "lookAt": "[x,y,z] number array | id",
  "fov": "deg",
  "roll": "deg"
}
Example
{
  "op": "shot.save",
  "name": "wide"
}
shot.cut

Hard cut (or dissolve) to a saved shot. Use in sequence steps to edit like a film.

Params
{
  "name": "saved shot name",
  "dissolve": "seconds (0 = hard cut)",
  "color": "dissolve color (default black)"
}
Example
{
  "op": "shot.cut",
  "name": "closeup",
  "dissolve": 0.4
}
shot.list

List saved shots.

Params
{}
Example
{
  "op": "shot.list"
}

eyes

scene.exposure

LIGHT METER (no image). Returns mean luminance (0-1), clipped highlight/shadow ratios, 16-bin histogram, 3x3 zone brightness map, current exposure, a verdict (overexposed | underexposed | hot highlights | dark (moody) | ok) and suggestedExposureMultiplier. Measures the 3D render only (ignores fades/titles/letterbox). Call after lighting changes to avoid blown-out frames.

Params
{
  "target": "desired mean luminance (default 0.42)"
}
Example
{
  "op": "scene.exposure"
}
scene.autoExpose

Automatically adjust tone-mapping exposure so mean luminance approaches target. Returns from/to exposure and final verdict.

Params
{
  "target": "0.1-0.8 (default 0.42)",
  "iterations": "1-8 (default 4)",
  "delay": "seconds to wait first (let fades/tweens finish)",
  "minExposure": "default 0.3",
  "maxExposure": "default 2.2"
}
Example
{
  "op": "scene.autoExpose",
  "target": 0.4,
  "delay": 2
}
scene.find

Query objects in the scene. Filter by type, tag, id prefix / regex, distance to a point or object, on-screen visibility. Sorted by distance. Use to locate things before acting on them.

Params
{
  "type": "object type",
  "tag": "string",
  "prefix": "id prefix",
  "match": "regex on id",
  "near": "[x,y,z] number array | object id",
  "radius": "number (with near)",
  "onScreen": "bool",
  "sort": "distance | distanceToCamera",
  "limit": "default 50"
}
Example
{
  "op": "scene.find",
  "near": "hero",
  "radius": 5,
  "onScreen": true
}
scene.compare

A/B check: captures BEFORE, runs the inner commands, captures AFTER, uploads a side-by-side sheet and returns exposure of both plus per-command results.

Params
{
  "commands": "[command objects]",
  "delay": "seconds to wait before AFTER capture",
  "width": "sheet width px (default 900)",
  "label": "string"
}
Example
{
  "op": "scene.compare",
  "commands": [
    {
      "op": "fx.look",
      "name": "noir"
    }
  ],
  "label": "noir-test"
}
scene.timelapse

Capture N frames spaced by interval seconds while the scene keeps playing, into ONE sheet (see motion/animation over real time). Then GET /frames/latest.

Params
{
  "count": "2-16 (default 6)",
  "interval": "seconds (default 1)",
  "width": "px",
  "label": "string"
}
Example
{
  "op": "scene.timelapse",
  "count": 6,
  "interval": 0.5
}
scene.critique

FILM-SCHOOL SCORECARD (JSON, no image). Scores the current frame 0-100 (grade A-F): exposure, contrast, subject on-screen/size/rule-of-thirds/headroom, clutter, edge distraction. Returns issues[] and fixes[] = ready-to-send commands. Subject = param target or the object tagged "hero".

Params
{
  "target": "object id (optional)"
}
Example
{
  "op": "scene.critique",
  "target": "hero"
}
music.analyze

Live audio energy (low/mid/high, 0-1), bar, beatPhase, bpm — use to time cuts on the beat.

Params
{}
Example
{
  "op": "music.analyze"
}
scene.history

Motion memory: sampled world positions [t,x,y,z] of objects for the last N seconds (10 Hz), plus distance travelled, avgSpeed, moving flag. Use to verify that an animation/path really happened.

Params
{
  "id": "object id (default: all, max 20)",
  "seconds": "0.5-30 (default 10)",
  "maxSamples": "default 40"
}
Example
{
  "op": "scene.history",
  "id": "hero",
  "seconds": 5
}

engine

guardian.start

SELF-DIRECTING LOOP inside the engine: every N seconds it meters exposure (auto-fix), keeps the hero in frame (reframe when it leaves), and scores the frame. Runs without any API traffic. Emits "guardian" events. Stops on scene.reset.

Params
{
  "every": "seconds (default 3)",
  "target": "object id (default: tag hero)",
  "exposure": "bool (default true)",
  "keepInFrame": "bool (default true)",
  "targetMean": "default 0.38",
  "quiet": "bool: no events"
}
Example
{
  "op": "guardian.start",
  "every": 2,
  "target": "hero"
}
guardian.stop

Stop the self-directing loop.

Params
{}
Example
{
  "op": "guardian.stop"
}
guardian.status

Guardian status: runs, last score, recent actions.

Params
{}
Example
{
  "op": "guardian.status"
}
engine.selfTest

Device health report: GPU name, WebGL2, measured fps + tier (high/medium/low), counts (objects/lights/particles/triangles/drawCalls), memory, audioUnlocked, speechVoices, canRecord, recommendedBudget for this phone. Call once at the start to plan scene complexity.

Params
{
  "seconds": "fps sampling window (default 1.5)"
}
Example
{
  "op": "engine.selfTest"
}
engine.reload

Reload the engine page (recover from errors).

Params
{}
Example
{
  "op": "engine.reload"
}
engine.ping

Ask engine to immediately push a fresh state report.

Params
{}
Example
{
  "op": "engine.ping"
}