# CINEMA-AI ENGINE — AI Control Guide (llms.txt) You are controlling a real-time 3D cinematic engine (Three.js/WebGL) that runs inside a phone browser. You have HANDS (commands) and EYES (state + frames). A human only opens the viewer URL; you do everything else. Base URL: https://cinema-ai-engine.pages.dev Auth (you): header X-Engine-Key: (or Authorization: Bearer ) ## Control loop 1. Create a scene: POST https://cinema-ai-engine.pages.dev/api/scenes {"name":"My Film","description":"..."} -> response.scene.viewerUrl (give this URL to the human to open on the phone) 2. Check engine online: GET https://cinema-ai-engine.pages.dev/api/scenes/{id}/state -> engineOnline: true 3. Send commands: POST https://cinema-ai-engine.pages.dev/api/scenes/{id}/commands body: [ {op..}, {op..} ] (add ?wait=10 to wait for execution) 4. Look: GET https://cinema-ai-engine.pages.dev/api/scenes/{id}/state (objects with onScreen coords, camera, fps, timeline) GET https://cinema-ai-engine.pages.dev/api/scenes/{id}/frames/latest (JPEG) or ?format=json (base64) 5. Iterate: adjust lights/camera/objects, snapshot again. 6. Final video: send {op:"render.start", duration: N, fps:30, width:1280, height:720} then poll GET https://cinema-ai-engine.pages.dev/api/scenes/{id}/renders -> renders[0].videoUrl 7. Optional built-in LLM director: POST https://cinema-ai-engine.pages.dev/api/scenes/{id}/director {"brief":"..."} — converts natural language to commands. ## Command envelope Each command is a JSON object with "op" plus params. Send an array to queue many. Use {op:"batch", commands:[...]} for atomic immediate execution and {op:"sequence", steps:[{at:sec, cmd:{...}}], autoplay:true, resetTimeline:true} for time-based shots. Coordinates: Y up, ground y=0, units ~ meters. Rotation in degrees. Colors as CSS strings. ## Performance limits (phone) particles total < 6000 · objects < 250 · shadows on ≤ 2 lights · pixelRatio ≤ 1.5 · keep textures small. ## Light intensity ranges (IMPORTANT — too high = white blown-out image) ambient/hemisphere 0.2-1.5 · directional (sun) 0.5-4 · point 1-15 · spot 2-25. Exposure 0.6-1.2. ## Cinematic recipe scene.reset -> scene.config (background/fog/toneMapping) -> env.sky + env.ground -> objects -> lights (key/fill/rim, castShadow on key) -> camera.set / camera.animate / camera.path -> fx.set (bloom, vignette, letterbox 2.39, colorGrade) -> title.show -> fx.fade in/out -> scene.timeline {duration} -> scene.play -> scene.snapshot -> render.start. ## State shape (GET /state) { engineOnline, state: { time, playing, timeline:{duration,loop,speed}, camera:{position,lookAt,fov}, objects:[{id,type,position,rotation,scale,visible,onScreen:{x,y,visible}}], lights:[...], particles:[...], fx:{...}, perf:{fps,drawCalls,triangles}, viewport:{w,h,dpr}, audioBlocked, recording }, lastFrame:{url} } ## Full command catalog ### scene.reset [scene] Remove all objects, lights, particles, animations and reset camera/effects to defaults. params: {"keepCamera":"bool (optional)"} example: {"op":"scene.reset"} ### scene.config [scene] 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 [scene] 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 (use 1-2 after titles/fades/camera tweens so transitions finish)"} example: {"op":"scene.snapshot","label":"check-lighting","quality":0.8,"delay":1} ### scene.autoSnapshot [scene] 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 [scene] Seek the master timeline to time t (seconds). params: {"t":"seconds"} example: {"op":"scene.setTime","t":3.5} ### scene.play [scene] Start master timeline. params: {} example: {"op":"scene.play"} ### scene.pause [scene] Pause master timeline. params: {} example: {"op":"scene.pause"} ### scene.timeline [scene] 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} ### env.sky [environment] 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 [environment] 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} ### object.add [objects] Add a 3D object. Types: box, sphere, cylinder, cone, torus, torusKnot, plane, capsule, icosahedron, octahedron, dodecahedron, ring, text (billboard text sprite), group (empty container), model (GLTF/GLB url), tree, rock, building, car, human (procedural low-poly props). 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","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 [objects] 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 [objects] Remove object (and children). params: {"id":"string | array of ids | \"tag:\""} example: {"op":"object.remove","id":"hero"} ### object.animate [objects] 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 [objects] 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 [objects] 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 [objects] 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"} ### light.add [lights] 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 (higher = brighter; >40 blows out)","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)","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 [lights] 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 [lights] Remove light. params: {"id":"string"} example: {"op":"light.remove","id":"key"} ### camera.set [camera] 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] 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 [camera] 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 [camera] 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 [camera] 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 [camera] 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} ### fx.set [effects] 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) }","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 [effects] 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 [effects] 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 [effects] 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} ### particles.add [particles] 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 [particles] Update particle system params. params: {"id":"string","...":"particles.add params"} example: {"op":"particles.update","id":"fire1","emit":false} ### particles.remove [particles] Remove particle system. params: {"id":"string"} example: {"op":"particles.remove","id":"fire1"} ### title.show [overlay] 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 [overlay] Hide a title overlay. params: {"id":"string"} example: {"op":"title.hide","id":"main"} ### hud.set [overlay] 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.play [audio] 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 [audio] Stop audio. params: {"id":"string","fadeOut":"seconds"} example: {"op":"audio.stop","id":"music","fadeOut":2} ### render.start [render] 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 [render] Cancel active recording. params: {} example: {"op":"render.cancel"} ### sequence [sequencing] Run a list of commands at scheduled timeline times (a full shot list in one call). Each step: { at: seconds, cmd: }. 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 [sequencing] 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}]} ### engine.reload [engine] Reload the engine page (recover from errors). params: {} example: {"op":"engine.reload"} ### engine.ping [engine] Ask engine to immediately push a fresh state report. params: {} example: {"op":"engine.ping"}