create-aura3d 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +9 -2
  4. package/dist/index.js.map +1 -1
  5. package/package.json +10 -2
  6. package/templates/animation-channel/package.json +1 -1
  7. package/templates/animation-channel/tests/screenshot.spec.ts +16 -0
  8. package/templates/animation-studio/dist/episodes/prompt-to-scene-proof/two-robots-fixing-a-car.document.json +680 -0
  9. package/templates/animation-studio/dist/episodes/scene/episode-3d.webm +0 -0
  10. package/templates/animation-studio/dist/episodes/scene/frames/action.png +0 -0
  11. package/templates/animation-studio/dist/episodes/scene/frames/dialogue.png +0 -0
  12. package/templates/animation-studio/dist/episodes/scene/frames/final.png +0 -0
  13. package/templates/animation-studio/dist/episodes/scene/frames/first.png +0 -0
  14. package/templates/animation-studio/dist/episodes/scene/frames/mouth-closed.png +0 -0
  15. package/templates/animation-studio/dist/episodes/scene/frames/mouth-open.png +0 -0
  16. package/templates/animation-studio/dist/episodes/scene/render-live-summary.json +4829 -682
  17. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/friend-1.png +0 -0
  18. package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/friend-2.png +0 -0
  19. package/templates/animation-studio/dist/scene/working.document.json +95 -16
  20. package/templates/animation-studio/index.html +12 -0
  21. package/templates/animation-studio/node_modules.publish-aside/.vite/deps/_metadata.json +8 -0
  22. package/templates/animation-studio/node_modules.publish-aside/.vite/deps/package.json +3 -0
  23. package/templates/animation-studio/package.json +1 -1
  24. package/templates/animation-studio/scripts/asset-motion-probe.ts +7 -1
  25. package/templates/animation-studio/scripts/render-live.ts +24 -0
  26. package/templates/animation-studio/src/director/prompt-to-scene.ts +73 -5
  27. package/templates/animation-studio/studio/dist/assets/index-C7f8tHfi.css +1 -0
  28. package/templates/animation-studio/studio/dist/assets/index-CLo3GXyN.js +43 -0
  29. package/templates/animation-studio/studio/dist/index.html +2 -2
  30. package/templates/animation-studio/studio/src/App.tsx +146 -78
  31. package/templates/animation-studio/studio/src/components/Console.tsx +8 -2
  32. package/templates/animation-studio/studio/src/components/Inspector.tsx +57 -1
  33. package/templates/animation-studio/studio/src/components/Stage.tsx +10 -5
  34. package/templates/animation-studio/studio/src/components/Timeline.tsx +49 -2
  35. package/templates/animation-studio/studio/src/state/mapDocument.ts +13 -2
  36. package/templates/animation-studio/studio/src/state/sceneTool.ts +20 -9
  37. package/templates/animation-studio/studio/src/state/types.ts +8 -0
  38. package/templates/animation-studio/tests/route-health.spec.ts +33 -0
  39. package/templates/animation-studio/tests/screenshot.spec.ts +30 -0
  40. package/templates/character-controller/package.json +1 -1
  41. package/templates/character-controller/src/main.ts +18 -1
  42. package/templates/cinematic-scene/package.json +1 -1
  43. package/templates/cinematic-scene/tests/screenshot.spec.ts +3 -1
  44. package/templates/episode-builder/package.json +1 -1
  45. package/templates/episode-builder/tests/screenshot.spec.ts +15 -0
  46. package/templates/fighting-game/package.json +1 -1
  47. package/templates/fighting-game/tests/screenshot.spec.ts +15 -0
  48. package/templates/mini-game/package.json +1 -1
  49. package/templates/product-viewer/package.json +1 -1
  50. package/templates/product-viewer/tests/screenshot.spec.ts +3 -1
  51. package/templates/prompt-animation-channel/package.json +1 -1
  52. package/templates/prompt-animation-channel/tests/screenshot.spec.ts +15 -0
  53. package/templates/three-compat-architecture-interior/index.html +16 -0
  54. package/templates/three-compat-architecture-interior/package.json +21 -0
  55. package/templates/three-compat-architecture-interior/playwright.config.ts +14 -0
  56. package/templates/three-compat-architecture-interior/src/main.ts +27 -0
  57. package/templates/three-compat-architecture-interior/tests/route-health.spec.ts +16 -0
  58. package/templates/three-compat-architecture-interior/tests/screenshot.spec.ts +15 -0
  59. package/templates/three-compat-architecture-interior/tsconfig.json +19 -0
  60. package/templates/three-compat-asset-inspector/index.html +16 -0
  61. package/templates/three-compat-asset-inspector/package.json +21 -0
  62. package/templates/three-compat-asset-inspector/playwright.config.ts +14 -0
  63. package/templates/three-compat-asset-inspector/src/main.ts +17 -0
  64. package/templates/three-compat-asset-inspector/tests/route-health.spec.ts +16 -0
  65. package/templates/three-compat-asset-inspector/tests/screenshot.spec.ts +15 -0
  66. package/templates/three-compat-asset-inspector/tsconfig.json +19 -0
  67. package/templates/three-compat-character-viewer/index.html +16 -0
  68. package/templates/three-compat-character-viewer/package.json +21 -0
  69. package/templates/three-compat-character-viewer/playwright.config.ts +14 -0
  70. package/templates/three-compat-character-viewer/src/main.ts +17 -0
  71. package/templates/three-compat-character-viewer/tests/route-health.spec.ts +16 -0
  72. package/templates/three-compat-character-viewer/tests/screenshot.spec.ts +15 -0
  73. package/templates/three-compat-character-viewer/tsconfig.json +19 -0
  74. package/templates/three-compat-custom-threejs-migration/index.html +16 -0
  75. package/templates/three-compat-custom-threejs-migration/package.json +21 -0
  76. package/templates/three-compat-custom-threejs-migration/playwright.config.ts +14 -0
  77. package/templates/three-compat-custom-threejs-migration/src/main.ts +16 -0
  78. package/templates/three-compat-custom-threejs-migration/tests/route-health.spec.ts +16 -0
  79. package/templates/three-compat-custom-threejs-migration/tests/screenshot.spec.ts +15 -0
  80. package/templates/three-compat-custom-threejs-migration/tsconfig.json +19 -0
  81. package/templates/three-compat-large-scene/index.html +16 -0
  82. package/templates/three-compat-large-scene/package.json +21 -0
  83. package/templates/three-compat-large-scene/playwright.config.ts +14 -0
  84. package/templates/three-compat-large-scene/src/main.ts +31 -0
  85. package/templates/three-compat-large-scene/tests/route-health.spec.ts +16 -0
  86. package/templates/three-compat-large-scene/tests/screenshot.spec.ts +15 -0
  87. package/templates/three-compat-large-scene/tsconfig.json +19 -0
  88. package/templates/three-compat-material-authoring/index.html +16 -0
  89. package/templates/three-compat-material-authoring/package.json +21 -0
  90. package/templates/three-compat-material-authoring/playwright.config.ts +14 -0
  91. package/templates/three-compat-material-authoring/src/main.ts +33 -0
  92. package/templates/three-compat-material-authoring/tests/route-health.spec.ts +16 -0
  93. package/templates/three-compat-material-authoring/tests/screenshot.spec.ts +15 -0
  94. package/templates/three-compat-material-authoring/tsconfig.json +19 -0
  95. package/templates/three-compat-postprocess-scene/index.html +16 -0
  96. package/templates/three-compat-postprocess-scene/package.json +21 -0
  97. package/templates/three-compat-postprocess-scene/playwright.config.ts +14 -0
  98. package/templates/three-compat-postprocess-scene/src/main.ts +17 -0
  99. package/templates/three-compat-postprocess-scene/tests/route-health.spec.ts +16 -0
  100. package/templates/three-compat-postprocess-scene/tests/screenshot.spec.ts +15 -0
  101. package/templates/three-compat-postprocess-scene/tsconfig.json +19 -0
  102. package/templates/three-compat-premium-product-viewer/index.html +16 -0
  103. package/templates/three-compat-premium-product-viewer/package.json +21 -0
  104. package/templates/three-compat-premium-product-viewer/playwright.config.ts +14 -0
  105. package/templates/three-compat-premium-product-viewer/src/main.ts +18 -0
  106. package/templates/three-compat-premium-product-viewer/tests/route-health.spec.ts +16 -0
  107. package/templates/three-compat-premium-product-viewer/tests/screenshot.spec.ts +15 -0
  108. package/templates/three-compat-premium-product-viewer/tsconfig.json +19 -0
  109. package/templates/animation-studio/studio/dist/assets/index-i8URxOOt.css +0 -1
  110. package/templates/animation-studio/studio/dist/assets/index-pC9hdZ-B.js +0 -11
@@ -1,10 +1,10 @@
1
1
  {
2
- "id": "scene-two-chefs-yelling-at-each-other-",
2
+ "id": "scene-two-friends-cooking-dinner-and-g",
3
3
  "duration": 24,
4
4
  "assets": {
5
5
  "characters": [
6
6
  {
7
- "id": "chefs",
7
+ "id": "friend-1",
8
8
  "url": "/aura-assets/cast-a.catalog.glb",
9
9
  "scale": 1.3,
10
10
  "defaultClip": "idle",
@@ -19,7 +19,27 @@
19
19
  "react"
20
20
  ],
21
21
  "mouthMorphIndex": 0,
22
- "attribution": "\"chefs\" — curated A-grade humanoid (humanoid-a)",
22
+ "attribution": "\"friend 1\" — curated A-grade humanoid (humanoid-a)",
23
+ "license": "CC0",
24
+ "fidelityGrade": "A"
25
+ },
26
+ {
27
+ "id": "friend-2",
28
+ "url": "/aura-assets/cast-b.catalog.glb",
29
+ "scale": 1.3,
30
+ "defaultClip": "idle",
31
+ "availableClips": [
32
+ "idle",
33
+ "talk",
34
+ "gesture",
35
+ "point",
36
+ "nod",
37
+ "walk",
38
+ "run",
39
+ "react"
40
+ ],
41
+ "mouthMorphIndex": 0,
42
+ "attribution": "\"friend 2\" — curated A-grade humanoid (humanoid-b)",
23
43
  "license": "CC0",
24
44
  "fidelityGrade": "A"
25
45
  }
@@ -481,7 +501,7 @@
481
501
  ],
482
502
  "blocking": [
483
503
  {
484
- "characterId": "chefs",
504
+ "characterId": "friend-1",
485
505
  "shots": [
486
506
  {
487
507
  "shotId": "shot-1",
@@ -499,11 +519,11 @@
499
519
  {
500
520
  "time": 2.88,
501
521
  "position": [
502
- 0,
522
+ -0.936,
503
523
  0,
504
524
  0
505
525
  ],
506
- "yaw": 0
526
+ "yaw": 1.5707963267948966
507
527
  }
508
528
  ]
509
529
  },
@@ -514,11 +534,70 @@
514
534
  {
515
535
  "time": 8,
516
536
  "position": [
537
+ -0.936,
538
+ 0,
539
+ 0
540
+ ],
541
+ "yaw": 1.5707963267948966
542
+ }
543
+ ]
544
+ },
545
+ {
546
+ "shotId": "shot-3",
547
+ "clip": "nod",
548
+ "waypoints": [
549
+ {
550
+ "time": 16,
551
+ "position": [
552
+ -0.936,
553
+ 0,
554
+ 0
555
+ ],
556
+ "yaw": 1.5707963267948966
557
+ }
558
+ ]
559
+ }
560
+ ]
561
+ },
562
+ {
563
+ "characterId": "friend-2",
564
+ "shots": [
565
+ {
566
+ "shotId": "shot-1",
567
+ "clip": "run",
568
+ "waypoints": [
569
+ {
570
+ "time": 0,
571
+ "position": [
572
+ 4.1,
517
573
  0,
574
+ 0
575
+ ],
576
+ "yaw": -1.5707963267948966
577
+ },
578
+ {
579
+ "time": 2.88,
580
+ "position": [
581
+ 0.936,
518
582
  0,
519
583
  0
520
584
  ],
521
- "yaw": 0
585
+ "yaw": -1.5707963267948966
586
+ }
587
+ ]
588
+ },
589
+ {
590
+ "shotId": "shot-2",
591
+ "clip": "walk",
592
+ "waypoints": [
593
+ {
594
+ "time": 8,
595
+ "position": [
596
+ 0.936,
597
+ 0,
598
+ 0
599
+ ],
600
+ "yaw": -1.5707963267948966
522
601
  }
523
602
  ]
524
603
  },
@@ -529,11 +608,11 @@
529
608
  {
530
609
  "time": 16,
531
610
  "position": [
532
- 0,
611
+ 0.936,
533
612
  0,
534
613
  0
535
614
  ],
536
- "yaw": 0
615
+ "yaw": -1.5707963267948966
537
616
  }
538
617
  ]
539
618
  }
@@ -549,42 +628,42 @@
549
628
  "lines": [
550
629
  {
551
630
  "lineId": "l0",
552
- "speakerId": "chefs",
553
- "text": "Hey, is the chefs ready?",
631
+ "speakerId": "friend-1",
632
+ "text": "Hey, is the friend ready?",
554
633
  "startTime": 0.2,
555
634
  "endTime": 2.668
556
635
  },
557
636
  {
558
637
  "lineId": "l1",
559
- "speakerId": "chefs",
638
+ "speakerId": "friend-2",
560
639
  "text": "Almost! Just give me a second.",
561
640
  "startTime": 2.918,
562
641
  "endTime": 5.9
563
642
  },
564
643
  {
565
644
  "lineId": "l2",
566
- "speakerId": "chefs",
645
+ "speakerId": "friend-1",
567
646
  "text": "That is great news.",
568
647
  "startTime": 6.15,
569
648
  "endTime": 8.005
570
649
  },
571
650
  {
572
651
  "lineId": "l3",
573
- "speakerId": "chefs",
652
+ "speakerId": "friend-2",
574
653
  "text": "I know, I can NOT wait to show you.",
575
654
  "startTime": 8.255,
576
655
  "endTime": 12.178
577
656
  },
578
657
  {
579
658
  "lineId": "l4",
580
- "speakerId": "chefs",
659
+ "speakerId": "friend-1",
581
660
  "text": "Come over and let us take a look.",
582
661
  "startTime": 12.428,
583
662
  "endTime": 15.737
584
663
  },
585
664
  {
586
665
  "lineId": "l5",
587
- "speakerId": "chefs",
666
+ "speakerId": "friend-2",
588
667
  "text": "Here it is, right in front of you.",
589
668
  "startTime": 15.987,
590
669
  "endTime": 19.546
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Aura3D Animation Studio</title>
7
+ </head>
8
+ <body style="margin:0;background:#0b0f1a;">
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/render-live-route.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,8 @@
1
+ {
2
+ "hash": "ffc76a4e",
3
+ "configHash": "a0e1cf88",
4
+ "lockfileHash": "014abcc5",
5
+ "browserHash": "7931f362",
6
+ "optimized": {},
7
+ "chunks": {}
8
+ }
@@ -19,7 +19,7 @@
19
19
  "@aura3d/animation": "1.3.2",
20
20
  "@aura3d/assets": "1.3.2",
21
21
  "@aura3d/core": "1.3.2",
22
- "@aura3d/engine": "1.3.2",
22
+ "@aura3d/engine": "1.3.3",
23
23
  "@aura3d/physics": "1.3.2",
24
24
  "react": "^18.3.1",
25
25
  "react-dom": "^18.3.1",
@@ -211,9 +211,15 @@ const VOCAB_KEYWORDS: Readonly<Record<StandardClipId, readonly string[]>> = {
211
211
  gesture: ["wave", "waving", "gesture", "greet", "hello", "clap"],
212
212
  point: ["point", "pointing", "aim", "indicate"],
213
213
  nod: ["nod", "nodding", "yes", "agree"],
214
+ wave: ["wave", "waving", "greet", "hello", "goodbye", "farewell"],
214
215
  walk: ["walk", "walking", "stride"],
215
216
  run: ["run", "running", "sprint", "jog"],
216
- react: ["react", "reaction", "surprised", "flinch", "recoil", "hit", "damage", "dodge"]
217
+ react: ["react", "reaction", "surprised", "flinch", "recoil", "hit", "damage", "dodge"],
218
+ sit: ["sit", "sitting", "seat", "seated"],
219
+ shrug: ["shrug", "shrugging", "dunno", "uncertain"],
220
+ cross_arms: ["cross", "arms", "armcross", "defiant", "impatient"],
221
+ salute: ["salute", "saluting", "respect", "military"],
222
+ shake_head: ["shake", "head", "no", "disagree", "deny"]
217
223
  };
218
224
 
219
225
  export interface ClipMotionScore {
@@ -59,6 +59,26 @@ const OUTPUT_DIR = resolve(TEMPLATE_ROOT, process.env.AURA_OUTPUT_DIR ?? "dist/e
59
59
  const FRAMES_DIR = resolve(OUTPUT_DIR, "frames");
60
60
  const VIDEO_PATH = resolve(OUTPUT_DIR, "episode-3d.webm");
61
61
 
62
+ // SSE render-progress contract (read by the studio dev server's /api/render-progress).
63
+ const PROGRESS_PATH = resolve(OUTPUT_DIR, "progress.json");
64
+ /**
65
+ * Atomic progress write: temp file + rename so the 200 ms SSE reader can never observe a
66
+ * partially written JSON (which it would surface as a bogus {label:"unknown", pct:0}).
67
+ * Guards total <= 0 so a zero-frame range can't produce Infinity/NaN pct.
68
+ */
69
+ function writeProgress(current: number, total: number, label: string): void {
70
+ try {
71
+ const pct = total <= 0 ? 100 : Math.round((current / total) * 100);
72
+ const tmp = `${PROGRESS_PATH}.tmp`;
73
+ writeFileSync(tmp, JSON.stringify({ current, total, label, pct, ts: Date.now() }));
74
+ renameSync(tmp, PROGRESS_PATH);
75
+ } catch {}
76
+ }
77
+ // FIRST action of the script: publish an initial 0% entry so the SSE reader never replays a
78
+ // previous render's final 100% (and the stale-file window shrinks to the tsx startup time).
79
+ mkdirSync(OUTPUT_DIR, { recursive: true });
80
+ writeProgress(0, 1, "starting");
81
+
62
82
  // M5 — RESOLUTION / OUTPUT TIERS via AURA_QUALITY:
63
83
  // preview (DEFAULT) = low-fi 480x270 @ 8fps, cheaper post — fast studio iteration.
64
84
  // final = 1080p (1920x1080) @ 24fps with the full post pass and no preview
@@ -507,6 +527,8 @@ async function main(): Promise<void> {
507
527
  `rendering frames ${FIRST_FRAME}..${LAST_FRAME} (${LAST_FRAME - FIRST_FRAME} frames) @ ${FRAME_RATE}fps` +
508
528
  `${PREVIEW_PARTS ? " [preview range]" : ` over ${EPISODE_DURATION}s`} ...`
509
529
  );
530
+ writeProgress(0, LAST_FRAME - FIRST_FRAME, "seeking");
531
+
510
532
  for (let i = FIRST_FRAME; i < LAST_FRAME; i += 1) {
511
533
  const t = i / FRAME_RATE;
512
534
  const result = await seekAndReadPixels(page, t, { burnCaption: false });
@@ -560,6 +582,7 @@ async function main(): Promise<void> {
560
582
  const basePng = await rawRgbaToPng(treated.pixels, WIDTH, HEIGHT);
561
583
  const png = await compositeCaptionPng(basePng, capText, WIDTH, HEIGHT);
562
584
  captured.push({ time: t, png });
585
+ writeProgress(i - FIRST_FRAME + 1, LAST_FRAME - FIRST_FRAME, "capturing");
563
586
 
564
587
  const fidelityId = fidelityFrameIndex.get(i);
565
588
  if (fidelityId) writeFileSync(resolve(FRAMES_DIR, `${fidelityId}.png`), png);
@@ -574,6 +597,7 @@ async function main(): Promise<void> {
574
597
  }
575
598
  }
576
599
 
600
+ writeProgress(LAST_FRAME - FIRST_FRAME, LAST_FRAME - FIRST_FRAME, "finishing");
577
601
  console.log("\n--- staged performance (per beat) ---");
578
602
  for (const beat of stagingByBeat.values()) {
579
603
  const m = beat.characters.find((c) => c.id === "miko");
@@ -137,14 +137,82 @@ export function parseCast(prompt: string): string[] {
137
137
  }
138
138
 
139
139
  /** Object nouns the prompt explicitly names (e.g. "car", "table") → extra registered props. */
140
+ const OBJECT_PROPS: Record<string, { kind: "prop"; defaultMesh: string }> = {
141
+ // furniture
142
+ table: { kind: "prop", defaultMesh: "table" },
143
+ chair: { kind: "prop", defaultMesh: "chair" },
144
+ desk: { kind: "prop", defaultMesh: "desk" },
145
+ bed: { kind: "prop", defaultMesh: "bed" },
146
+ sofa: { kind: "prop", defaultMesh: "sofa" },
147
+ bookshelf: { kind: "prop", defaultMesh: "bookshelf" },
148
+ cabinet: { kind: "prop", defaultMesh: "cabinet" },
149
+ stool: { kind: "prop", defaultMesh: "stool" },
150
+ bench: { kind: "prop", defaultMesh: "bench" },
151
+ wardrobe: { kind: "prop", defaultMesh: "wardrobe" },
152
+ // electronics
153
+ computer: { kind: "prop", defaultMesh: "computer" },
154
+ laptop: { kind: "prop", defaultMesh: "laptop" },
155
+ monitor: { kind: "prop", defaultMesh: "monitor" },
156
+ phone: { kind: "prop", defaultMesh: "phone" },
157
+ television: { kind: "prop", defaultMesh: "television" },
158
+ camera: { kind: "prop", defaultMesh: "camera" },
159
+ speaker: { kind: "prop", defaultMesh: "speaker" },
160
+ keyboard: { kind: "prop", defaultMesh: "keyboard" },
161
+ robot: { kind: "prop", defaultMesh: "robot" },
162
+ // vehicles
163
+ car: { kind: "prop", defaultMesh: "car" },
164
+ truck: { kind: "prop", defaultMesh: "truck" },
165
+ bike: { kind: "prop", defaultMesh: "bike" },
166
+ ship: { kind: "prop", defaultMesh: "ship" },
167
+ rocket: { kind: "prop", defaultMesh: "rocket" },
168
+ boat: { kind: "prop", defaultMesh: "boat" },
169
+ bus: { kind: "prop", defaultMesh: "bus" },
170
+ train: { kind: "prop", defaultMesh: "train" },
171
+ // nature
172
+ tree: { kind: "prop", defaultMesh: "tree" },
173
+ rock: { kind: "prop", defaultMesh: "rock" },
174
+ mushroom: { kind: "prop", defaultMesh: "mushroom" },
175
+ flower: { kind: "prop", defaultMesh: "flower" },
176
+ bush: { kind: "prop", defaultMesh: "bush" },
177
+ log: { kind: "prop", defaultMesh: "log" },
178
+ fern: { kind: "prop", defaultMesh: "fern" },
179
+ cactus: { kind: "prop", defaultMesh: "cactus" },
180
+ // tools
181
+ hammer: { kind: "prop", defaultMesh: "hammer" },
182
+ wrench: { kind: "prop", defaultMesh: "wrench" },
183
+ screwdriver: { kind: "prop", defaultMesh: "screwdriver" },
184
+ drill: { kind: "prop", defaultMesh: "drill" },
185
+ saw: { kind: "prop", defaultMesh: "saw" },
186
+ axe: { kind: "prop", defaultMesh: "axe" },
187
+ // containers
188
+ box: { kind: "prop", defaultMesh: "box" },
189
+ crate: { kind: "prop", defaultMesh: "crate" },
190
+ barrel: { kind: "prop", defaultMesh: "barrel" },
191
+ basket: { kind: "prop", defaultMesh: "basket" },
192
+ bucket: { kind: "prop", defaultMesh: "bucket" },
193
+ bottle: { kind: "prop", defaultMesh: "bottle" },
194
+ jar: { kind: "prop", defaultMesh: "jar" },
195
+ can: { kind: "prop", defaultMesh: "can" },
196
+ // decorations
197
+ lamp: { kind: "prop", defaultMesh: "lamp" },
198
+ picture: { kind: "prop", defaultMesh: "picture" },
199
+ vase: { kind: "prop", defaultMesh: "vase" },
200
+ statue: { kind: "prop", defaultMesh: "statue" },
201
+ sign: { kind: "prop", defaultMesh: "sign" },
202
+ trophy: { kind: "prop", defaultMesh: "trophy" },
203
+ mirror: { kind: "prop", defaultMesh: "mirror" },
204
+ candle: { kind: "prop", defaultMesh: "candle" },
205
+ // other
206
+ door: { kind: "prop", defaultMesh: "door" },
207
+ ball: { kind: "prop", defaultMesh: "ball" },
208
+ book: { kind: "prop", defaultMesh: "book" },
209
+ engine: { kind: "prop", defaultMesh: "engine" }
210
+ };
211
+
140
212
  export function parseObjectProps(prompt: string, castIds: readonly string[]): string[] {
141
213
  const castWords = new Set(castIds.flatMap((id) => id.split("-")));
142
- const OBJECTS = [
143
- "car", "table", "chair", "desk", "door", "box", "ball", "book", "lamp", "tree",
144
- "rock", "barrel", "crate", "engine", "computer", "robot", "ship", "rocket", "sign"
145
- ];
146
214
  const present = new Set(words(prompt));
147
- return OBJECTS.filter((o) => present.has(o) && !castWords.has(o));
215
+ return Object.keys(OBJECT_PROPS).filter((o) => present.has(o) && !castWords.has(o));
148
216
  }
149
217
 
150
218
  /** Infer the scene's dramatic intent from the prompt verbs. */
@@ -0,0 +1 @@
1
+ :root{--void:#06070b;--bg-0:#0a0c12;--bg-1:#0e111a;--bg-2:#131826;--bg-3:#1a2032;--bg-4:#222a40;--line:rgba(255,255,255,.065);--line-2:rgba(255,255,255,.11);--line-3:rgba(255,255,255,.18);--tx-hi:#eef1f8;--tx:#b9c1d2;--tx-dim:#737d93;--tx-faint:#4d556a;--acc:#7b7bff;--acc-2:#9a7bff;--acc-ink:#1a1840;--acc-glow:rgba(123,123,255,.45);--warm:#ff6f4d;--warm-glow:rgba(255,111,77,.4);--ok:#2dd4a7;--ok-ink:#0c2a23;--warn:#ffb020;--bad:#ff5c6a;--miko:#ff8a5b;--luma:#4fc2ff;--r-xs:5px;--r-sm:7px;--r:10px;--r-lg:14px;--r-xl:20px;--r-2xl:28px;--sh-1:0 1px 2px rgba(0,0,0,.4);--sh-2:0 6px 22px rgba(0,0,0,.45);--sh-pop:0 18px 50px -12px rgba(0,0,0,.75),0 0 0 1px var(--line-2);--sh-glow:0 0 0 1px rgba(123,123,255,.5),0 8px 30px -6px var(--acc-glow);--font:"Hanken Grotesk",system-ui,sans-serif;--disp:"Space Grotesk","Hanken Grotesk",sans-serif;--mono:"JetBrains Mono",ui-monospace,monospace;--top:54px;--rail:268px;--console:452px;--timeline:224px}*{box-sizing:border-box}html,body{height:100%}body{margin:0;background:var(--void);color:var(--tx);font-family:var(--font);font-size:13.5px;line-height:1.45;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden}#root{height:100vh}button{font-family:inherit;color:inherit;cursor:pointer;border:none;background:none}input,textarea{font-family:inherit}::selection{background:#7b7bff52}:focus{outline:none}*::-webkit-scrollbar{width:9px;height:9px}*::-webkit-scrollbar-thumb{background:#ffffff17;border-radius:20px;border:2px solid transparent;background-clip:padding-box}*::-webkit-scrollbar-thumb:hover{background:#ffffff2b;background-clip:padding-box}.app{height:100vh;display:grid;grid-template-rows:var(--top) auto 1fr;background:radial-gradient(1200px 600px at 16% -10%,rgba(123,123,255,.1),transparent 60%),radial-gradient(1000px 500px at 100% 110%,rgba(255,111,77,.06),transparent 55%),var(--bg-0)}.body{display:grid;grid-template-columns:var(--rail) 1fr var(--console);min-height:0;gap:0;padding:0 9px 9px}.col{min-width:0;min-height:0;display:flex;flex-direction:column}.center{padding:0 9px;gap:9px}.panel{background:linear-gradient(180deg,var(--bg-1),var(--bg-0));border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--sh-2),inset 0 1px #ffffff08;display:flex;flex-direction:column;min-height:0;overflow:hidden}.panel-h{height:42px;flex:0 0 auto;display:flex;align-items:center;gap:9px;padding:0 12px;border-bottom:1px solid var(--line)}.panel-h .ttl{font-family:var(--disp);font-weight:600;font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--tx-dim)}.panel-h .sp{flex:1}.hicon{width:26px;height:26px;display:grid;place-items:center;border-radius:var(--r-sm);color:var(--tx-dim);transition:.14s}.hicon:hover{background:var(--bg-3);color:var(--tx-hi)}.top{display:flex;align-items:center;gap:14px;padding:0 14px 0 16px;border-bottom:1px solid var(--line);position:relative;z-index:30}.brand{display:flex;align-items:center;gap:11px}.logo{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;background:linear-gradient(150deg,#8f7bff,#6b6bff 55%,#5a4fff);box-shadow:0 4px 14px -2px var(--acc-glow),inset 0 1px #fff6}.brand .wm{font-family:var(--disp);font-weight:700;font-size:14.5px;color:var(--tx-hi);letter-spacing:-.01em}.brand .wm b{color:#fff}.brand .ver{font-size:10px;font-family:var(--mono);color:var(--tx-faint);border:1px solid var(--line-2);padding:1px 5px;border-radius:5px;margin-left:2px}.crumb{display:flex;align-items:center;gap:8px;margin-left:6px;padding-left:16px;border-left:1px solid var(--line-2)}.crumb .proj{color:var(--tx-dim);font-size:12.5px}.crumb .sep{color:var(--tx-faint)}.crumb .scene{color:var(--tx-hi);font-weight:600;font-size:12.5px;display:flex;align-items:center;gap:7px;white-space:nowrap}.crumb .chev{color:var(--tx-faint)}.save{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--tx-dim);margin-left:4px}.save .dot{width:6px;height:6px;border-radius:50%;background:var(--ok);box-shadow:0 0 8px var(--ok)}.top .grow{flex:1}.seg{display:flex;background:var(--bg-2);border:1px solid var(--line);border-radius:9px;padding:3px;gap:2px}.seg button{padding:5px 11px;border-radius:6px;font-size:12px;font-weight:600;color:var(--tx-dim);display:flex;align-items:center;gap:6px;transition:.14s}.seg button.on{background:var(--bg-4);color:var(--tx-hi);box-shadow:var(--sh-1)}.seg button:hover:not(.on){color:var(--tx)}.avs{display:flex;align-items:center}.av{width:27px;height:27px;border-radius:50%;border:2px solid var(--bg-0);margin-left:-8px;display:grid;place-items:center;font-size:10.5px;font-weight:700;color:#fff}.av:first-child{margin-left:0}.btn{display:inline-flex;align-items:center;gap:7px;height:33px;padding:0 13px;border-radius:9px;font-size:12.5px;font-weight:600;color:var(--tx);background:var(--bg-2);border:1px solid var(--line-2);transition:.15s;white-space:nowrap}.btn:hover{background:var(--bg-3);color:var(--tx-hi);border-color:var(--line-3)}.btn.icon{padding:0;width:33px;justify-content:center}.btn-primary{color:#fff;background:linear-gradient(160deg,#8b7bff,#6b6bff);border:1px solid rgba(255,255,255,.16);box-shadow:0 4px 16px -3px var(--acc-glow),inset 0 1px #ffffff40}.btn-primary:hover{filter:brightness(1.08);color:#fff;border-color:#ffffff4d}.btn-warm{color:#fff;background:linear-gradient(160deg,#ff8a5b,#ff5f3d);border:1px solid rgba(255,255,255,.16);box-shadow:0 4px 16px -3px var(--warm-glow),inset 0 1px #ffffff40}.btn-warm:hover{filter:brightness(1.07);color:#fff}.btn-ghost{background:transparent;border-color:transparent}.btn-ghost:hover{background:var(--bg-2)}.ol-search{margin:10px 11px 4px;display:flex;align-items:center;gap:8px;height:32px;padding:0 10px;background:var(--bg-2);border:1px solid var(--line);border-radius:9px;color:var(--tx-faint)}.ol-search input{flex:1;background:none;border:none;color:var(--tx-hi);font-size:12.5px}.ol-search input::placeholder{color:var(--tx-faint)}.ol-search kbd{font-family:var(--mono);font-size:10px;color:var(--tx-faint);border:1px solid var(--line-2);border-radius:4px;padding:1px 5px}.ol-scroll{flex:1;overflow-y:auto;padding:6px 8px 14px}.ol-group{margin-top:6px}.ol-gh{display:flex;align-items:center;gap:7px;padding:6px 8px;color:var(--tx-dim);font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:7px}.ol-gh:hover{color:var(--tx)}.ol-gh .tw{transition:transform .18s;color:var(--tx-faint)}.ol-gh.closed .tw{transform:rotate(-90deg)}.ol-gh .cnt{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--tx-faint);font-weight:500;letter-spacing:0}.ol-gh .add{width:18px;height:18px;display:grid;place-items:center;border-radius:5px;color:var(--tx-faint)}.ol-gh .add:hover{background:var(--bg-3);color:var(--tx-hi)}.ol-item{display:flex;align-items:center;gap:9px;padding:6px 9px;border-radius:8px;cursor:pointer;color:var(--tx);font-size:12.5px;position:relative;transition:background .12s}.ol-item:hover{background:var(--bg-2)}.ol-item.sel{background:linear-gradient(90deg,#7b7bff2e,#7b7bff0f);box-shadow:inset 0 0 0 1px #7b7bff4d}.ol-item.sel:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:2.5px;border-radius:3px;background:var(--acc)}.ol-item .av{margin:0;width:22px;height:22px;border-radius:6px;border:none;font-size:9.5px;flex:0 0 auto}.ol-item .ic{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;background:var(--bg-3);color:var(--tx-dim);flex:0 0 auto}.ol-item .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ol-item.sel .nm{color:var(--tx-hi);font-weight:600}.ol-item .meta{font-family:var(--mono);font-size:10px;color:var(--tx-faint)}.ol-item .src-badge{font-family:var(--mono);font-size:9px;line-height:1;padding:2px 5px;border-radius:5px;text-transform:uppercase;letter-spacing:.04em;flex:0 0 auto;border:1px solid transparent}.ol-item .src-badge.src-fallback{color:#ffb020;background:#ffb0201f;border-color:#ffb0204d}.ol-item .src-badge.src-catalog{color:#4fc2ff;background:#4fc2ff1f;border-color:#4fc2ff4d}.ol-item .src-badge.src-uploaded{color:#2dd4a7;background:#2dd4a71f;border-color:#2dd4a74d}.ol-item .fid-badge{font-family:var(--mono);font-size:9px;line-height:1;padding:2px 5px;border-radius:5px;text-transform:uppercase;letter-spacing:.04em;flex:0 0 auto;border:1px solid transparent}.ol-item .fid-badge.fid-a{color:#2dd4a7;background:#2dd4a71f;border-color:#2dd4a759}.ol-item .fid-badge.fid-b{color:#4fc2ff;background:#4fc2ff1f;border-color:#4fc2ff59}.ol-item .fid-badge.fid-c,.ol-item .fid-badge.fid-previz{color:#ff8a5b;background:#ff8a5b24;border-color:#ff8a5b66}.scene-fidelity{display:flex;align-items:center;gap:8px;margin:6px 8px 10px;padding:7px 10px;border-radius:7px;border:1px solid transparent;font-size:11px}.scene-fidelity .fid-tier{font-family:var(--mono);font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;padding:2px 6px;border-radius:5px}.scene-fidelity .fid-note{color:var(--tx-faint)}.scene-fidelity.fid-a{border-color:#2dd4a74d;background:#2dd4a70f}.scene-fidelity.fid-a .fid-tier{color:#2dd4a7;background:#2dd4a724}.scene-fidelity.fid-b{border-color:#4fc2ff4d;background:#4fc2ff0f}.scene-fidelity.fid-b .fid-tier{color:#4fc2ff;background:#4fc2ff24}.scene-fidelity.fid-previz,.scene-fidelity.fid-c{border-color:#ff8a5b66;background:#ff8a5b14}.scene-fidelity.fid-previz .fid-tier,.scene-fidelity.fid-c .fid-tier{color:#ff8a5b;background:#ff8a5b29}.ol-item .vis{width:20px;height:20px;display:grid;place-items:center;color:var(--tx-faint);opacity:0;border-radius:4px}.ol-item:hover .vis{opacity:1}.ol-item .vis:hover{background:var(--bg-3);color:var(--tx-hi)}.ol-item .vis.off{opacity:1;color:var(--tx-faint)}.swatch{width:9px;height:9px;border-radius:3px;flex:0 0 auto}.caption{position:absolute;left:50%;bottom:16px;transform:translate(-50%);max-width:80%;display:flex;align-items:center;gap:12px;padding:10px 18px 12px;border-radius:14px;background:#07080d99;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,.11);box-shadow:0 14px 40px -12px #000000bf;animation:capIn .26s cubic-bezier(.2,.7,.3,1);z-index:6}.caption .who{flex:0 0 auto;font-family:var(--font);font-weight:800;font-size:11px;letter-spacing:.14em;text-transform:uppercase;padding:4px 9px;border-radius:7px;color:#fff;align-self:center}.caption .ctext{font-size:18.5px;font-weight:600;line-height:1.32;color:#fff;letter-spacing:.004em;text-wrap:balance;text-shadow:0 1px 12px rgba(0,0,0,.55)}.caption .bar{position:absolute;left:14px;right:14px;bottom:5px;height:2.5px;border-radius:3px;background:#ffffff24;overflow:hidden}.caption .bar i{display:block;height:100%;border-radius:3px}@keyframes capIn{0%{opacity:.001;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}.cc-off .caption{display:none}.caption-below{position:absolute;left:50%;bottom:82px;transform:translate(-50%);margin:0;max-width:90%;animation:capInBelow .26s cubic-bezier(.2,.7,.3,1);z-index:7}@keyframes capInBelow{0%{opacity:.001;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}.tp-pill.on{color:var(--acc);border-color:#7b7bff80;background:#7b7bff1f}.stage{position:relative;flex:1;min-height:0}.stage-canvas{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:13px;overflow:hidden;display:flex;align-items:center;justify-content:center;background:radial-gradient(820px 460px at 50% 34%,rgba(123,123,255,.08),transparent 66%),radial-gradient(720px 420px at 50% 122%,rgba(255,111,77,.05),transparent 60%),#06070c}.stage-env{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;opacity:.55;background-image:radial-gradient(rgba(255,255,255,.06) 1px,transparent 1.5px);background-size:25px 25px;-webkit-mask-image:radial-gradient(circle at 50% 44%,#000 26%,transparent 76%);mask-image:radial-gradient(circle at 50% 44%,#000 26%,transparent 76%)}.region-wrap{position:absolute;top:14px;right:18px;bottom:76px;left:18px;display:flex;align-items:center;justify-content:center;pointer-events:none}.render-region{position:relative;width:100%;aspect-ratio:16/9;max-height:100%;pointer-events:auto;border-radius:10px;box-shadow:0 44px 100px -34px #000000e6,0 0 0 1px #ffffff12,inset 0 1px #ffffff0d}.stage-frame{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:10px;overflow:hidden;background-size:cover;background-position:center;background-color:#070810;animation:frameIn .5s cubic-bezier(.2,.7,.3,1)}.stage-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;text-align:center;color:var(--tx-faint);padding:24px;max-width:340px}.stage-empty .ttl{font-size:14px;font-weight:600;color:var(--tx-hi);letter-spacing:.01em}.stage-empty .sub{font-size:12px;line-height:1.5;color:var(--tx-faint)}.stage-empty code{font-family:var(--mono);font-size:11px;color:var(--acc);background:#7b7bff1f;border:1px solid rgba(123,123,255,.25);padding:1px 6px;border-radius:5px}@keyframes frameIn{0%{transform:scale(1.015)}to{transform:none}}.stage-vig{position:absolute;top:0;right:0;bottom:0;left:0;box-shadow:inset 0 0 110px 16px #00000080;pointer-events:none;border-radius:10px}.tick{position:absolute;width:15px;height:15px;border:2px solid rgba(255,255,255,.5);pointer-events:none}.tick.tl{top:-5px;left:-5px;border-right:0;border-bottom:0;border-top-left-radius:6px}.tick.tr{top:-5px;right:-5px;border-left:0;border-bottom:0;border-top-right-radius:6px}.tick.bl{bottom:-5px;left:-5px;border-right:0;border-top:0;border-bottom-left-radius:6px}.tick.br{bottom:-5px;right:-5px;border-left:0;border-top:0;border-bottom-right-radius:6px}.stage-grain{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:10px;opacity:.05;pointer-events:none;mix-blend-mode:overlay;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}.hud{position:absolute;pointer-events:none;font-family:var(--mono);font-size:10.5px;letter-spacing:.04em}.hud.tl{top:14px;left:14px;display:flex;flex-direction:column;gap:7px;align-items:flex-start}.hud.tr{top:14px;right:14px;display:flex;flex-direction:column;gap:7px;align-items:flex-end}.hud-chip{display:inline-flex;align-items:center;gap:7px;padding:5px 9px;background:#08090e9e;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.1);border-radius:7px;color:var(--tx);pointer-events:auto;white-space:nowrap}.hud-chip .k{color:var(--tx-faint)}.hud-chip .v{color:var(--tx-hi);font-weight:600}.rec{width:7px;height:7px;border-radius:50%;background:var(--warm);box-shadow:0 0 9px var(--warm);animation:pulse 1.6s infinite}@keyframes pulse{50%{opacity:.35}}.live{color:var(--ok)}.live .d{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--ok);box-shadow:0 0 8px var(--ok);margin-right:6px;vertical-align:middle}.guides{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.guides .safe{position:absolute;border:1px dashed rgba(255,255,255,.18);border-radius:3px}.guides .action{top:5%;right:5%;bottom:5%;left:5%}.guides .title{top:10%;right:10%;bottom:10%;left:10%}.guides .cross{position:absolute;left:50%;top:50%;width:18px;height:18px;transform:translate(-50%,-50%)}.guides .cross:before,.guides .cross:after{content:"";position:absolute;background:#ffffff4d}.guides .cross:before{left:50%;top:0;width:1px;height:100%;transform:translate(-50%)}.guides .cross:after{top:50%;left:0;height:1px;width:100%;transform:translateY(-50%)}.transport{position:absolute;left:12px;right:12px;bottom:12px;display:flex;align-items:center;gap:12px;padding:9px 13px;border-radius:11px;background:#08090ea8;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,.09);box-shadow:0 8px 30px -8px #0009}.tp-btn{width:30px;height:30px;border-radius:8px;display:grid;place-items:center;color:var(--tx);transition:.13s}.tp-btn:hover{background:#ffffff14;color:var(--tx-hi)}.tp-play{width:36px;height:36px;background:var(--tx-hi);color:#0a0c12;border-radius:9px}.tp-play:hover{background:#fff;color:#0a0c12}.tp-time{font-family:var(--mono);font-size:11.5px;color:var(--tx);white-space:nowrap}.tp-time b{color:var(--tx-hi)}.tp-time .sl{color:var(--tx-faint)}.scrub{flex:1;height:30px;display:flex;align-items:center;cursor:pointer;position:relative}.scrub-rail{height:5px;width:100%;border-radius:4px;background:#ffffff1f;position:relative;overflow:visible}.scrub-buf{position:absolute;left:0;top:0;bottom:0;background:#ffffff1f;border-radius:4px}.scrub-fill{position:absolute;left:0;top:0;bottom:0;background:linear-gradient(90deg,var(--acc),#9a7bff);border-radius:4px}.scrub-marks{position:absolute;top:0;right:0;bottom:0;left:0}.scrub-mark{position:absolute;top:-3px;width:2px;height:11px;border-radius:2px;transform:translate(-1px)}.scrub-head{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;background:#fff;transform:translate(-50%,-50%);box-shadow:0 1px 5px #00000080,0 0 0 3px #7b7bff59}.tp-pill{font-family:var(--mono);font-size:10.5px;color:var(--tx-dim);padding:3px 8px;border:1px solid var(--line-2);border-radius:6px}.tp-pill:hover{color:var(--tx-hi);border-color:var(--line-3)}.tl{flex:0 0 var(--timeline);display:flex;flex-direction:column}.tl-h{height:38px;display:flex;align-items:center;gap:10px;padding:0 12px;border-bottom:1px solid var(--line)}.tl-h .ttl{font-family:var(--disp);font-weight:600;font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--tx-dim)}.tl-zoom{display:flex;align-items:center;gap:3px;margin-left:auto}.tl-body{flex:1;display:flex;min-height:0}.tl-labels{width:118px;flex:0 0 auto;border-right:1px solid var(--line);background:var(--bg-1)}.tl-lab{height:38px;display:flex;align-items:center;gap:8px;padding:0 12px;border-bottom:1px solid var(--line);font-size:11.5px;color:var(--tx-dim);font-weight:600}.tl-lab .dot{width:8px;height:8px;border-radius:3px}.tl-lab.ruler{height:24px;font-size:10px;color:var(--tx-faint);font-family:var(--mono)}.tl-tracks{flex:1;overflow-x:auto;overflow-y:hidden;position:relative}.tl-inner{position:relative;height:100%;min-width:100%}.tl-ruler{height:24px;border-bottom:1px solid var(--line);position:relative;background:var(--bg-1)}.tl-tick{position:absolute;top:0;bottom:0;border-left:1px solid var(--line)}.tl-tick span{position:absolute;top:5px;left:5px;font-family:var(--mono);font-size:9.5px;color:var(--tx-faint)}.tl-row{height:38px;border-bottom:1px solid var(--line);position:relative}.tl-row:nth-child(2n){background:#ffffff03}.clip{position:absolute;top:5px;bottom:5px;border-radius:7px;display:flex;align-items:center;gap:6px;padding:0 9px;font-size:11px;font-weight:600;color:var(--tx-hi);cursor:pointer;overflow:hidden;border:1px solid rgba(255,255,255,.13);box-shadow:var(--sh-1);transition:filter .12s,box-shadow .12s;white-space:nowrap}.clip:hover{filter:brightness(1.12)}.clip.sel{box-shadow:0 0 0 1.5px #fff,0 4px 14px -4px #0009;z-index:2}.clip .clab{overflow:hidden;text-overflow:ellipsis}.clip .gh{position:absolute;left:0;top:0;bottom:0;width:5px;background:#0000002e}.clip .gh.r{left:auto;right:0}.tl-playhead{position:absolute;top:0;bottom:0;width:2px;background:linear-gradient(180deg,#fff,var(--acc));z-index:5;pointer-events:none;box-shadow:0 0 10px #7b7bff99}.tl-playhead:before{content:"";position:absolute;top:-1px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:7px solid #fff}.console{--cpad:14px}.cns-h{height:50px;flex:0 0 auto;display:flex;align-items:center;gap:11px;padding:0 14px;border-bottom:1px solid var(--line);background:linear-gradient(180deg,rgba(123,123,255,.07),transparent)}.cns-orb{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;position:relative;background:radial-gradient(circle at 35% 30%,#a99bff,#6b6bff 70%);box-shadow:0 0 0 1px #ffffff1f,0 4px 16px -3px var(--acc-glow)}.cns-orb:after{content:"";position:absolute;top:-3px;right:-3px;bottom:-3px;left:-3px;border-radius:11px;border:1.5px solid rgba(123,123,255,.4);animation:ring 3s linear infinite}@keyframes ring{0%{transform:scale(.9);opacity:.7}to{transform:scale(1.25);opacity:0}}.cns-h .meta{flex:1;min-width:0}.cns-h .nm{font-family:var(--disp);font-weight:600;font-size:13.5px;color:var(--tx-hi);letter-spacing:.01em}.cns-h .sub{font-size:10.5px;color:var(--tx-dim);font-family:var(--mono);display:flex;align-items:center;gap:6px}.cns-h .sub .d{width:5px;height:5px;border-radius:50%;background:var(--ok);box-shadow:0 0 7px var(--ok)}.cns-scroll{flex:1;overflow-y:auto;padding:16px 14px 8px;display:flex;flex-direction:column;gap:14px}.turn{display:flex;flex-direction:column;gap:8px;opacity:1;animation:rise .35s cubic-bezier(.2,.7,.3,1)}@keyframes rise{0%{opacity:1;transform:translateY(9px)}to{transform:none}}.turn.you{align-items:flex-end}.bub{max-width:90%;padding:9px 13px;border-radius:13px;font-size:13px;line-height:1.5}.turn.you .bub{background:linear-gradient(160deg,#6b6bff,#5a4fe6);color:#fff;border-bottom-right-radius:5px;box-shadow:0 4px 16px -5px var(--acc-glow)}.turn.dir .lbl{display:flex;align-items:center;gap:7px;font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--tx-dim)}.turn.dir .lbl .mk{width:16px;height:16px;border-radius:5px;background:radial-gradient(circle at 35% 30%,#a99bff,#6b6bff);display:grid;place-items:center}.think{font-size:12.5px;color:var(--tx);line-height:1.55}.think .hl{color:var(--tx-hi);font-weight:600}.cmd{border:1px solid var(--line-2);border-radius:11px;overflow:hidden;background:var(--bg-1);box-shadow:var(--sh-1)}.cmd-top{display:flex;align-items:center;gap:9px;padding:9px 11px;font-family:var(--mono);font-size:12px;background:var(--bg-2)}.cmd-top .pr{color:var(--acc)}.cmd-top .verb{color:var(--tx-hi);font-weight:700}.cmd-top .args{color:var(--tx);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.cmd-top .flag{color:var(--luma)}.cmd-top .str{color:var(--ok)}.cmd-st{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;font-family:var(--font);font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:3px 8px;border-radius:6px}.st-run{background:#ffb02024;color:var(--warn)}.st-ok{background:#2dd4a724;color:var(--ok)}.st-bad{background:#ff5c6a24;color:var(--bad)}.spin{width:11px;height:11px;border-radius:50%;border:2px solid rgba(255,176,32,.3);border-top-color:var(--warn);animation:sp .7s linear infinite}@keyframes sp{to{transform:rotate(360deg)}}.cmd-body{padding:9px 11px;display:flex;flex-direction:column;gap:7px;border-top:1px solid var(--line)}.diff{display:flex;align-items:center;gap:8px;font-size:11.5px;font-family:var(--mono);line-height:1.5;min-height:17px}.diff .op{width:13px;text-align:center;font-weight:700;flex:0 0 auto}.diff .add{color:var(--ok)}.diff .mod{color:var(--warn)}.diff .del{color:var(--bad)}.diff .txt{color:var(--tx);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.diff .txt b{color:var(--tx-hi);font-weight:600}.cmd-foot{display:flex;align-items:center;gap:8px;padding:8px 11px;border-top:1px solid var(--line);font-size:11px;color:var(--tx-dim)}.cmd-foot .commit{margin-left:auto;display:flex;align-items:center;gap:5px;color:var(--ok);font-weight:600}.cmd-foot a{color:var(--tx-dim);cursor:pointer}.cmd-foot a:hover{color:var(--tx-hi)}.rcard{border:1px solid var(--line-2);border-radius:12px;overflow:hidden;background:var(--bg-1)}.rcard .thumb{aspect-ratio:16/9;background-size:cover;background-position:center;position:relative}.rcard .thumb .play{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center}.rcard .thumb .pb{width:42px;height:42px;border-radius:50%;background:#08090e8c;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:grid;place-items:center;border:1px solid rgba(255,255,255,.25);color:#fff}.rcard .thumb .badge{position:absolute;left:9px;top:9px;font-family:var(--mono);font-size:9.5px;padding:3px 7px;border-radius:6px;background:#08090e99;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.15);color:var(--tx-hi)}.rcard .rmeta{display:flex;align-items:center;gap:8px;padding:9px 11px;font-size:11.5px;color:var(--tx-dim)}.rcard .rmeta b{color:var(--tx-hi);font-weight:600}.prog{height:5px;border-radius:4px;background:var(--bg-3);overflow:hidden}.prog i{display:block;height:100%;background:linear-gradient(90deg,var(--warm),#ff9a6b);border-radius:4px;transition:width .25s;box-shadow:0 0 10px var(--warm-glow)}.composer{flex:0 0 auto;padding:10px var(--cpad) var(--cpad);border-top:1px solid var(--line);background:linear-gradient(180deg,transparent,rgba(0,0,0,.25))}.chips{display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;margin-bottom:9px;padding-bottom:2px;scrollbar-width:none}.chips::-webkit-scrollbar{display:none}.chip{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:11px;padding:5px 9px;border-radius:7px;background:var(--bg-2);border:1px solid var(--line);color:var(--tx-dim);transition:.13s;white-space:nowrap}.chip:hover{background:var(--bg-3);color:var(--tx-hi);border-color:var(--line-2)}.chip .pr{color:var(--acc)}.cbox{border:1px solid var(--line-2);border-radius:13px;background:var(--bg-2);overflow:visible;position:relative;transition:box-shadow .18s,border-color .18s}.cbox.focus{border-color:#7b7bff8c;box-shadow:var(--sh-glow)}.cmode{display:flex;align-items:center;gap:7px;padding:8px 10px 4px;flex-wrap:nowrap}.cmode .seg{padding:2px;flex:0 0 auto}.cmode .seg button{padding:3px 9px;font-size:11px}.cmode .hint{margin-left:auto;font-size:10px;color:var(--tx-faint);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:0 1 auto}.cinput{width:100%;background:none;border:none;color:var(--tx-hi);font-size:14px;padding:10px 12px 12px;resize:none;min-height:76px;max-height:200px;line-height:1.55}.cinput.mono{font-family:var(--mono);font-size:12.5px}.cinput::placeholder{color:var(--tx-faint)}.cbar{display:flex;align-items:center;gap:8px;padding:8px 10px 9px;border-top:1px solid var(--line)}.cbar .tool{width:28px;height:28px;border-radius:7px;display:grid;place-items:center;color:var(--tx-faint)}.cbar .tool:hover{background:var(--bg-3);color:var(--tx-hi)}.cbar .sp{flex:1}.send{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;background:linear-gradient(160deg,#8b7bff,#6b6bff);color:#fff;box-shadow:0 3px 12px -3px var(--acc-glow);transition:.14s}.send:hover{filter:brightness(1.1)}.send:disabled{opacity:.4;cursor:default;filter:none}.ac{position:absolute;left:0;right:0;bottom:calc(100% + 8px);background:var(--bg-2);border:1px solid var(--line-2);border-radius:12px;box-shadow:var(--sh-pop);overflow:hidden;z-index:40}.ac-h{padding:7px 12px;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx-faint);border-bottom:1px solid var(--line)}.ac-item{display:flex;align-items:center;gap:10px;padding:8px 12px;cursor:pointer;font-size:12.5px}.ac-item.on{background:var(--bg-3)}.ac-item .verb{font-family:var(--mono);color:var(--tx-hi);font-weight:600;min-width:90px}.ac-item .verb .fl{color:var(--luma)}.ac-item .desc{color:var(--tx-dim);font-size:11.5px}.ac-item kbd{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--tx-faint);border:1px solid var(--line-2);border-radius:4px;padding:1px 5px}.col.split{gap:9px}.insp{flex:0 0 312px}.insp-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:var(--tx-faint);font-size:12px;text-align:center;padding:24px}.insp-scroll{flex:1;overflow-y:auto}.insp-hero{position:relative;margin:11px 11px 4px;height:96px;border-radius:11px;overflow:hidden;border:1px solid var(--line-2);background-size:cover;background-position:center}.insp-hero .ov{position:absolute;top:0;right:0;bottom:0;left:0;background:linear-gradient(180deg,transparent 40%,rgba(7,8,13,.85))}.insp-hero .tag{position:absolute;left:9px;top:9px;font-family:var(--mono);font-size:9.5px;padding:3px 7px;border-radius:6px;background:#07080d99;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.13);color:var(--tx-hi)}.insp-hero .cap{position:absolute;left:11px;bottom:9px;right:11px}.insp-hero .cap .nm{font-family:var(--disp);font-weight:600;font-size:15px;color:#fff}.insp-hero .cap .sub{font-size:10.5px;color:var(--tx);font-family:var(--mono)}.insp-avatar{margin:14px auto 6px;width:62px;height:62px;border-radius:16px;display:grid;place-items:center;font-size:24px;font-weight:800;color:#fff;font-family:var(--disp);box-shadow:0 8px 22px -6px #0009,inset 0 1px #ffffff4d}.insp-name{text-align:center;font-family:var(--disp);font-weight:600;font-size:16px;color:var(--tx-hi)}.insp-sub{text-align:center;font-size:11.5px;color:var(--tx-dim);margin-bottom:6px}.prop-grid{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding:8px 11px}.prop-grid.one{grid-template-columns:1fr}.field{background:var(--bg-2);border:1px solid var(--line);border-radius:9px;padding:7px 10px;min-width:0}.field .fl{font-size:9.5px;text-transform:uppercase;letter-spacing:.1em;color:var(--tx-faint);margin-bottom:3px;display:flex;align-items:center;gap:5px}.field .fv{font-size:13px;color:var(--tx-hi);font-weight:600;display:flex;align-items:center;gap:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.field.act{cursor:pointer;transition:.13s}.field.act:hover{background:var(--bg-3);border-color:var(--line-2)}.field .chev{margin-left:auto;color:var(--tx-faint)}.field .mono{font-family:var(--mono);font-size:12px}.insp-sec{padding:4px 12px 2px;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx-dim);display:flex;align-items:center;gap:7px}.insp-sec .ln{flex:1;height:1px;background:var(--line)}.castrow{display:flex;gap:6px;flex-wrap:wrap;padding:6px 11px 10px}.castchip{display:inline-flex;align-items:center;gap:6px;padding:4px 9px 4px 5px;border-radius:20px;background:var(--bg-2);border:1px solid var(--line);font-size:11.5px;color:var(--tx-hi)}.castchip .d{width:16px;height:16px;border-radius:50%;display:grid;place-items:center;font-size:8.5px;font-weight:800;color:#fff}.range{padding:2px 11px 12px}.range .rr{height:5px;border-radius:4px;background:var(--bg-3);position:relative}.range .rr i{position:absolute;left:0;top:0;bottom:0;border-radius:4px;background:linear-gradient(90deg,var(--acc),#9a7bff)}.range .rr .k{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;background:#fff;transform:translate(-50%,-50%);box-shadow:0 1px 4px #00000080}.insp-note{margin:2px 11px 12px;padding:9px 11px;border-radius:9px;background:var(--bg-2);border:1px solid var(--line);border-left:2px solid var(--acc);font-size:12px;color:var(--tx);line-height:1.5}.beat-plan{display:flex;flex-direction:column;gap:7px;margin:2px 11px 12px}.beat-row{padding:8px 10px;border-radius:9px;background:var(--bg-2);border:1px solid var(--line);border-left:2px solid var(--acc)}.beat-line{font-size:12px;color:var(--tx-hi);line-height:1.45;margin-bottom:6px}.beat-intents{display:flex;flex-wrap:wrap;gap:5px}.beat-chip{font-family:var(--mono);font-size:10px;padding:2px 7px;border-radius:6px;border:1px solid var(--line);color:var(--tx);background:var(--bg-1)}.beat-chip.cam{color:#2dd4a7;border-color:#2dd4a74d;background:#2dd4a71a}.beat-chip.spk{color:var(--acc);border-color:#7b7bff4d;background:#7b7bff1a}.beat-chip.lst{color:#ff8a5b;border-color:#ff8a5b4d;background:#ff8a5b1a}.toast-wrap{position:fixed;bottom:20px;left:50%;transform:translate(-50%);z-index:80;display:flex;flex-direction:column;gap:8px;align-items:center}.toast{display:flex;align-items:center;gap:10px;padding:10px 15px;border-radius:11px;background:var(--bg-3);border:1px solid var(--line-2);box-shadow:var(--sh-pop);font-size:12.5px;color:var(--tx-hi);animation:rise .3s}.toast .i{width:18px;height:18px;display:grid;place-items:center}.render-ov{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:13px;background:#06070bc7;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px;z-index:20}.render-ov .ttl{font-family:var(--disp);font-size:15px;color:var(--tx-hi);font-weight:600}.render-ov .sub{font-family:var(--mono);font-size:11.5px;color:var(--tx-dim)}.render-ring{width:74px;height:74px;position:relative}.render-ring svg{transform:rotate(-90deg)}.render-pct{position:absolute;top:0;right:0;bottom:0;left:0;display:grid;place-items:center;font-family:var(--mono);font-size:15px;font-weight:600;color:var(--tx-hi)}.render-bar{width:280px}.fadein{animation:fade .5s}@keyframes fade{0%{opacity:0}}.cmdk-ov{position:fixed;top:0;right:0;bottom:0;left:0;z-index:100;background:#0405098c;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);display:flex;align-items:flex-start;justify-content:center;padding-top:11vh;animation:fade .15s}.cmdk{width:min(640px,92vw);background:linear-gradient(180deg,var(--bg-2),var(--bg-1));border:1px solid var(--line-2);border-radius:16px;box-shadow:var(--sh-pop);overflow:hidden;animation:popin .18s cubic-bezier(.2,.8,.3,1)}@keyframes popin{0%{opacity:.3;transform:translateY(-10px) scale(.985)}}.cmdk-in{display:flex;align-items:center;gap:12px;padding:15px 18px;border-bottom:1px solid var(--line)}.cmdk-in .si{color:var(--tx-dim)}.cmdk-in input{flex:1;background:none;border:none;color:var(--tx-hi);font-size:16px;font-family:var(--font)}.cmdk-in input::placeholder{color:var(--tx-faint)}.cmdk-in .esc{font-family:var(--mono);font-size:10px;color:var(--tx-faint);border:1px solid var(--line-2);border-radius:5px;padding:2px 7px}.cmdk-list{max-height:50vh;overflow-y:auto;padding:8px}.cmdk-grp{padding:9px 12px 5px;font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--tx-faint)}.cmdk-item{display:flex;align-items:center;gap:12px;padding:9px 12px;border-radius:9px;cursor:pointer}.cmdk-item.on{background:var(--bg-3)}.cmdk-item .ic{width:30px;height:30px;border-radius:8px;background:var(--bg-1);border:1px solid var(--line);display:grid;place-items:center;color:var(--tx-dim);flex:0 0 auto}.cmdk-item.on .ic{color:var(--acc);border-color:#7b7bff4d}.cmdk-item .av{width:30px;height:30px;border-radius:8px;display:grid;place-items:center;font-size:12px;font-weight:800;color:#fff;flex:0 0 auto}.cmdk-item .tx{min-width:0;flex:1}.cmdk-item .nm{font-size:13.5px;color:var(--tx-hi);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cmdk-item .ds{font-size:11.5px;color:var(--tx-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cmdk-item .ds.mono{font-family:var(--mono);font-size:11px}.cmdk-item .tag{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--tx-faint);border:1px solid var(--line-2);padding:2px 6px;border-radius:5px;flex:0 0 auto}.cmdk-item .ent{margin-left:auto;color:var(--acc);opacity:0;flex:0 0 auto}.cmdk-item.on .ent{opacity:1}.cmdk-empty{padding:34px;text-align:center;color:var(--tx-faint);font-size:13px}.cmdk-foot{display:flex;align-items:center;gap:16px;padding:9px 15px;border-top:1px solid var(--line);font-size:11px;color:var(--tx-faint)}.cmdk-foot span{display:flex;align-items:center;gap:6px}.cmdk-foot .kk{font-family:var(--mono);border:1px solid var(--line-2);border-radius:4px;padding:1px 5px;color:var(--tx-dim)}.empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:var(--tx-faint);text-align:center;padding:30px}.newscene-bar{display:flex;align-items:center;gap:10px;padding:9px 16px;background:linear-gradient(180deg,var(--bg-1),var(--bg-0));border-bottom:1px solid var(--line);position:relative;z-index:25}.newscene-spark{font-size:14px;filter:drop-shadow(0 0 6px var(--acc-glow))}.newscene-label{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--tx-faint);white-space:nowrap}.newscene-input{flex:1;height:34px;padding:0 13px;border-radius:9px;background:var(--bg-2);border:1px solid var(--line-2);color:var(--tx-hi);font-size:13px;outline:none;transition:.15s}.newscene-input::placeholder{color:var(--tx-faint)}.newscene-input:focus{border-color:#8b7bff;box-shadow:0 0 0 2px #7b7bff40}.newscene-input:disabled{opacity:.5}.newscene-btn{height:34px;padding:0 16px;border-radius:9px;font-size:12.5px;font-weight:700;color:#fff;white-space:nowrap;background:linear-gradient(160deg,#8b7bff,#6b6bff);box-shadow:0 3px 12px -3px var(--acc-glow);border:none;cursor:pointer;transition:.14s}.newscene-btn:hover{filter:brightness(1.1)}.newscene-btn:disabled{opacity:.45;cursor:default;filter:none}.newscene-status{flex:1;display:flex;align-items:center;gap:10px;font-size:13px;color:var(--tx-hi);font-weight:500}.newscene-spinner{width:15px;height:15px;border-radius:50%;border:2px solid var(--line-2);border-top-color:#8b7bff;animation:nsspin .7s linear infinite;flex:0 0 auto}@keyframes nsspin{to{transform:rotate(360deg)}}.newscene-btn.busy{opacity:1;cursor:default;animation:nspulse 1.1s ease-in-out infinite}@keyframes nspulse{0%,to{filter:brightness(1)}50%{filter:brightness(1.28)}}.newscene-div{width:1px;height:22px;background:var(--line-2);margin:0 2px;flex:0 0 auto}.newscene-continue{background:var(--bg-3);color:var(--tx-hi);box-shadow:none;border:1px solid var(--line-2)}.newscene-continue:hover:not(:disabled){background:var(--bg-4);filter:none}.cmd-list{margin:2px 0 6px;padding:6px;background:var(--bg-2);border:1px solid var(--line);border-radius:10px;max-height:208px;overflow-y:auto}.cmd-list-h{padding:5px 8px 7px;font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--tx-faint)}.cmd-list-item{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;padding:7px 9px;border-radius:7px;transition:.12s}.cmd-list-item:hover{background:var(--bg-3)}.cmd-list-item .verb{font-family:var(--mono);font-size:12px;color:var(--tx-hi);font-weight:600}.cmd-list-item .verb .fl{color:var(--luma);font-weight:500}.cmd-list-item .desc{font-size:11.5px;color:var(--tx-dim)}