المصادقة
الـ 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?}
-- 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
كتالوج الأوامر (44)
scene
scene.reset
Remove all objects, lights, particles, animations and reset camera/effects to defaults.
{
"keepCamera": "bool (optional)"
}
{
"op": "scene.reset"
}
scene.config
Configure global scene settings.
{
"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)"
}
{
"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.
{
"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)"
}
{
"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.
{
"interval": "seconds (0 = off)",
"quality": "number",
"width": "px"
}
{
"op": "scene.autoSnapshot",
"interval": 2,
"quality": 0.6,
"width": 640
}
scene.setTime
Seek the master timeline to time t (seconds).
{
"t": "seconds"
}
{
"op": "scene.setTime",
"t": 3.5
}
scene.play
Start master timeline.
{}
{
"op": "scene.play"
}
scene.pause
Pause master timeline.
{}
{
"op": "scene.pause"
}
scene.timeline
Set timeline length/loop/speed. Animations use timeline time.
{
"duration": "seconds",
"loop": "bool",
"speed": "number (1 = realtime)"
}
{
"op": "scene.timeline",
"duration": 12,
"loop": false,
"speed": 1
}
environment
env.sky
Add a procedural sky dome with a sun. Presets tune colors and sun angle.
{
"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"
}
{
"op": "env.sky",
"preset": "sunset",
"stars": false
}
env.ground
Add a ground plane (optionally with grid / procedural terrain / reflective water).
{
"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)"
}
{
"op": "env.ground",
"type": "terrain",
"size": 300,
"color": "#3b4a2e",
"height": 14
}
objects
object.add
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).
{
"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"
}
{
"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.
{
"id": "string",
"duration": "seconds (optional tween)",
"easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
"...": "any object.add params"
}
{
"op": "object.update",
"id": "hero",
"position": [
3,
2,
-1
],
"material": {
"color": "#00ffcc"
},
"duration": 2,
"easing": "easeInOut"
}
object.remove
Remove object (and children).
{
"id": "string | array of ids | \"tag:<tag>\""
}
{
"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.
{
"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)"
}
{
"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.
{
"id": "string",
"target": "[x,y,z] number array | object id"
}
{
"op": "object.lookAt",
"id": "car1",
"target": "hero"
}
object.path
Move object along a smooth curve through points, over duration, optionally facing forward.
{
"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"
}
{
"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).
{
"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"
}
{
"op": "object.clone",
"id": "tree",
"count": 40,
"jitter": 40,
"prefix": "forest"
}
lights
light.add
Add a light. Types: ambient, hemisphere, directional (sun), point, spot, rect (area).
{
"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 }"
}
{
"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).
{
"id": "string",
"duration": "seconds",
"...": "light.add params"
}
{
"op": "light.update",
"id": "key",
"intensity": 0,
"duration": 1.5
}
light.remove
Remove light.
{
"id": "string"
}
{
"op": "light.remove",
"id": "key"
}
camera
camera.set
Set camera instantly (or tween with duration).
{
"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"
}
{
"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...).
{
"keyframes": "[{ t, position?, lookAt?, fov?, roll? }]",
"easing": "linear | easeIn | easeOut | easeInOut | easeInOutCubic | easeOutBack | easeOutElastic | easeInExpo | easeOutExpo",
"relative": "bool"
}
{
"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.
{
"target": "[x,y,z] number array | object id",
"radius": "number",
"height": "number",
"speed": "deg/sec",
"startAngle": "deg",
"enabled": "bool"
}
{
"op": "camera.orbit",
"target": "hero",
"radius": 12,
"height": 4,
"speed": 15
}
camera.follow
Follow an object with an offset and smoothing (chase cam).
{
"target": "object id",
"offset": "[x,y,z] number array",
"lerp": "0-1 smoothing",
"lookAhead": "number",
"enabled": "bool"
}
{
"op": "camera.follow",
"target": "car1",
"offset": [
0,
3,
-8
],
"lerp": 0.08
}
camera.shake
Handheld / impact camera shake.
{
"intensity": "number (0.05 subtle, 1 violent)",
"duration": "seconds (0 = continuous until intensity 0)",
"frequency": "number"
}
{
"op": "camera.shake",
"intensity": 0.4,
"duration": 1.2
}
camera.path
Fly camera along smooth spline through points.
{
"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"
}
{
"op": "camera.path",
"points": [
[
20,
5,
20
],
[
0,
8,
25
],
[
-20,
5,
20
],
[
-10,
3,
0
]
],
"lookAt": "hero",
"duration": 10
}
effects
fx.set
Post-processing look. All optional; duration tweens.
{
"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"
}
{
"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...).
{
"from": "0-1 opacity",
"to": "0-1",
"duration": "seconds",
"color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\""
}
{
"op": "fx.fade",
"from": 1,
"to": 0,
"duration": 2,
"color": "#000000"
}
fx.flash
Quick screen flash (explosion, lightning).
{
"color": "CSS color string, e.g. \"#ff8800\" or \"skyblue\"",
"duration": "seconds",
"intensity": "0-1"
}
{
"op": "fx.flash",
"color": "#ffffff",
"duration": 0.25
}
fx.slowmo
Timeline speed ramp (bullet-time). speed<1 slow, >1 fast.
{
"speed": "number",
"duration": "seconds to ramp",
"hold": "seconds to hold then return to 1"
}
{
"op": "fx.slowmo",
"speed": 0.2,
"duration": 0.5,
"hold": 2
}
particles
particles.add
GPU point particle system. Presets: fire, smoke, sparks, rain, snow, dust, stars, embers, magic, explosion, fog, confetti, fireflies.
{
"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)"
}
{
"op": "particles.add",
"id": "fire1",
"preset": "fire",
"position": [
0,
0,
0
],
"count": 800,
"size": 0.6
}
particles.update
Update particle system params.
{
"id": "string",
"...": "particles.add params"
}
{
"op": "particles.update",
"id": "fire1",
"emit": false
}
particles.remove
Remove particle system.
{
"id": "string"
}
{
"op": "particles.remove",
"id": "fire1"
}
overlay
title.show
Cinematic title card / subtitle overlay (2D). Supports Arabic and RTL.
{
"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"
}
{
"op": "title.show",
"text": "CHAPTER ONE",
"subtitle": "The Awakening",
"position": "center",
"duration": 4,
"style": "cinematic"
}
title.hide
Hide a title overlay.
{
"id": "string"
}
{
"op": "title.hide",
"id": "main"
}
hud.set
Engine HUD options (debug info for the human viewer; AI sees stats via /state anyway).
{
"stats": "bool",
"watermark": "string | null",
"safeArea": "bool"
}
{
"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.
{
"id": "string",
"url": "string",
"volume": "0-1",
"loop": "bool",
"fadeIn": "seconds",
"at": "timeline t"
}
{
"op": "audio.play",
"id": "music",
"url": "https://example.com/track.mp3",
"volume": 0.6,
"loop": true
}
audio.stop
Stop audio.
{
"id": "string",
"fadeOut": "seconds"
}
{
"op": "audio.stop",
"id": "music",
"fadeOut": 2
}
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.
{
"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)"
}
{
"op": "render.start",
"duration": 10,
"from": 0,
"fps": 30,
"width": 1280,
"height": 720
}
render.cancel
Cancel active recording.
{}
{
"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.
{
"steps": "[{ at, cmd }]",
"autoplay": "bool (start timeline)",
"resetTimeline": "bool"
}
{
"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).
{
"commands": "array of commands"
}
{
"op": "batch",
"commands": [
{
"op": "scene.reset"
},
{
"op": "env.sky",
"preset": "night",
"stars": true
}
]
}
engine
engine.reload
Reload the engine page (recover from errors).
{}
{
"op": "engine.reload"
}
engine.ping
Ask engine to immediately push a fresh state report.
{}
{
"op": "engine.ping"
}