cozyclay 2.1.0 → 3.0.0

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 (583) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +12 -30
  3. package/bin/agent/agent-routes.mjs +40 -113
  4. package/bin/agent/agent-runner.mjs +9 -10
  5. package/bin/agent/cliproxy-provider.mjs +135 -0
  6. package/bin/agent/credential-store.mjs +30 -7
  7. package/bin/agent/pi-tools.mjs +4 -1
  8. package/bin/agent/provider-keys.mjs +32 -0
  9. package/bin/agent/provider-login.mjs +110 -0
  10. package/bin/agent/provider-routes.mjs +99 -0
  11. package/bin/agent/providers.mjs +19 -97
  12. package/bin/agent/script-tool.mjs +17 -4
  13. package/bin/agent/studio-motion-reference.mjs +23 -0
  14. package/bin/agent/studio-prompt.mjs +1 -1
  15. package/bin/agent/studio-rebase-text.mjs +32 -0
  16. package/bin/agent/studio-rebase.mjs +26 -39
  17. package/bin/agent/studio-tools.mjs +9 -28
  18. package/bin/agent/tool-arguments.mjs +49 -0
  19. package/bin/agent/turn-frames.mjs +66 -0
  20. package/bin/codex-auth.mjs +9 -2
  21. package/bin/cozyclay.mjs +10 -116
  22. package/bin/live/cli.mjs +22 -6
  23. package/bin/mcp-runtime.mjs +2 -12
  24. package/bin/package-signature.mjs +0 -4
  25. package/dist/app/index.html +7 -6
  26. package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
  27. package/dist/assets/analytics-C9sUnndd.js +1 -0
  28. package/dist/assets/app-CCh--1Hc.js +5087 -0
  29. package/dist/assets/app-f-fkV5uP.css +1 -0
  30. package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
  31. package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
  32. package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
  33. package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
  34. package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
  35. package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
  36. package/dist/assets/workflow-C4yKH1p4.js +179 -0
  37. package/dist/cozyclay-package.json +1 -1
  38. package/dist/index.html +3 -3
  39. package/dist/llms.txt +14 -0
  40. package/dist/sw.js +3 -6
  41. package/dist/workflow/index.html +5 -4
  42. package/mcp/LIVE-PROTOCOL.md +7 -47
  43. package/mcp/README.md +16 -26
  44. package/mcp/live-hub.mjs +6 -10
  45. package/mcp/package.json +1 -3
  46. package/mcp/tool-handlers.mjs +4 -168
  47. package/package.json +3 -22
  48. package/src/App.jsx +174 -2639
  49. package/src/agent-progress.js +79 -0
  50. package/src/agent-turn-mark.js +30 -0
  51. package/src/analytics.js +1 -19
  52. package/src/app-context.js +5 -0
  53. package/src/app-stage.jsx +2 -34
  54. package/src/asset-pane.jsx +6 -5
  55. package/src/camera-block.js +21 -0
  56. package/src/camera-direction.js +120 -0
  57. package/src/character-kind.js +3 -9
  58. package/src/command-bus.js +8 -6
  59. package/src/commands/cast.js +5 -34
  60. package/src/commands/elements/character.js +1 -1
  61. package/src/commands/elements/motion.js +1 -6
  62. package/src/commands/elements/object.js +6 -2
  63. package/src/commands/elements/shot.js +4 -1
  64. package/src/commands/elements.js +38 -14
  65. package/src/commands/index.js +3 -1
  66. package/src/commands/kits.js +37 -0
  67. package/src/commands/motion-timing.js +57 -0
  68. package/src/commands/motion.js +9 -152
  69. package/src/commands/motion3-compile.js +65 -0
  70. package/src/commands/motion3.js +207 -0
  71. package/src/commands/objects.js +6 -4
  72. package/src/commands/shot.js +49 -11
  73. package/src/commands/stage.js +14 -1
  74. package/src/commands/view.js +4 -1
  75. package/src/document-mirrors.js +42 -0
  76. package/src/document-store.js +4 -0
  77. package/src/domains/cast.js +19 -194
  78. package/src/domains/motion/motion-range-pin-rules.js +1 -1
  79. package/src/domains/motion/take-source.js +51 -0
  80. package/src/domains/motion.js +60 -1838
  81. package/src/domains/scenes.js +12 -55
  82. package/src/domains/shots.js +2 -2
  83. package/src/domains/stage.js +4 -2
  84. package/src/draft-ghost.js +46 -0
  85. package/src/draft-ghost.jsx +129 -0
  86. package/src/dualview.jsx +4 -3
  87. package/src/effects/EffectsLayer.jsx +112 -0
  88. package/src/effects/effect-meshes.js +232 -0
  89. package/src/effects/effect-record.js +103 -0
  90. package/src/effects/emitter.js +59 -0
  91. package/src/effects/simulate.js +261 -0
  92. package/src/effects/state.js +59 -0
  93. package/src/execution-telemetry.js +2 -3
  94. package/src/first-success-guide.jsx +5 -5
  95. package/src/ghost-set.js +257 -0
  96. package/src/held-object-edit.jsx +113 -0
  97. package/src/held-object-pose.js +175 -0
  98. package/src/hierarchy-model.js +1 -1
  99. package/src/hierarchy-panel.jsx +1 -1
  100. package/src/imported-mesh.jsx +103 -0
  101. package/src/kits/held.js +84 -0
  102. package/src/kits/index.js +70 -0
  103. package/src/kits/smoking.js +57 -0
  104. package/src/light-blockers.js +93 -0
  105. package/src/motion/beat-board-model.js +84 -0
  106. package/src/motion/beat-board.css +124 -0
  107. package/src/motion/beat-board.jsx +59 -0
  108. package/src/motion/center-of-mass.js +66 -0
  109. package/src/motion/fix-collisions.js +850 -0
  110. package/src/motion/physics-review.js +118 -0
  111. package/src/{ardy → motion}/physics-support.js +1 -76
  112. package/src/motion/rig-snapshot.js +22 -0
  113. package/src/motion/take-segments.jsx +140 -0
  114. package/src/{ardy → motion}/timeline-coordinates.js +0 -21
  115. package/src/{ardy → motion}/timeline.css +1 -2
  116. package/src/{ardy → motion}/timeline.jsx +48 -419
  117. package/src/motion/waypoints.js +76 -0
  118. package/src/motion3/beats.js +83 -0
  119. package/src/motion3/body.js +158 -0
  120. package/src/motion3/bones.js +47 -0
  121. package/src/motion3/carried.js +47 -0
  122. package/src/motion3/compile-job.js +75 -0
  123. package/src/motion3/compile-worker.js +10 -0
  124. package/src/motion3/compiler/anchors.js +105 -0
  125. package/src/motion3/compiler/arm-orient.js +128 -0
  126. package/src/motion3/compiler/channels.js +125 -0
  127. package/src/motion3/compiler/compile.js +205 -0
  128. package/src/motion3/compiler/gait-rhythm.js +97 -0
  129. package/src/motion3/compiler/grip.js +171 -0
  130. package/src/motion3/compiler/head-steady.js +48 -0
  131. package/src/motion3/compiler/hold.js +134 -0
  132. package/src/motion3/compiler/idle.js +113 -0
  133. package/src/motion3/compiler/limbs.js +170 -0
  134. package/src/motion3/compiler/math.js +72 -0
  135. package/src/motion3/compiler/pose.js +162 -0
  136. package/src/motion3/compiler/quat.js +49 -0
  137. package/src/motion3/compiler/skeleton.js +74 -0
  138. package/src/motion3/compiler/validate-common.js +32 -0
  139. package/src/motion3/compiler/validate-goals.js +118 -0
  140. package/src/motion3/compiler/validate-objects.js +143 -0
  141. package/src/motion3/compiler/validate-parts.js +116 -0
  142. package/src/motion3/compiler/validate.js +122 -0
  143. package/src/motion3/compiler/vocab.js +73 -0
  144. package/src/motion3/compiler/walk-pelvis.js +275 -0
  145. package/src/motion3/compiler/walk.js +207 -0
  146. package/src/motion3/compiler/wrist-clamp.js +32 -0
  147. package/src/motion3/delta.js +47 -0
  148. package/src/motion3/describe.js +174 -0
  149. package/src/motion3/docs.js +27 -0
  150. package/src/motion3/edit-carry.js +21 -0
  151. package/src/motion3/fix/ease.js +16 -0
  152. package/src/motion3/fix/ground.js +37 -0
  153. package/src/motion3/fix/index.js +52 -0
  154. package/src/motion3/fix/push.js +71 -0
  155. package/src/motion3/fix/reach.js +46 -0
  156. package/src/motion3/fix/retime.js +79 -0
  157. package/src/motion3/fix/self.js +211 -0
  158. package/src/motion3/fix/slide.js +70 -0
  159. package/src/motion3/fix/turn.js +51 -0
  160. package/src/motion3/follow.js +39 -0
  161. package/src/motion3/free-motion.js +173 -0
  162. package/src/motion3/grip-choice.js +130 -0
  163. package/src/motion3/hold-plan.js +157 -0
  164. package/src/motion3/json-patch.js +77 -0
  165. package/src/motion3/key-aim.js +105 -0
  166. package/src/motion3/key-edit.js +82 -0
  167. package/src/motion3/lenient.js +127 -0
  168. package/src/motion3/object-keys.js +236 -0
  169. package/src/motion3/object-pose.js +182 -0
  170. package/src/motion3/object-tracks.js +12 -0
  171. package/src/motion3/pipeline.js +102 -0
  172. package/src/motion3/playback.js +51 -0
  173. package/src/motion3/probes.js +91 -0
  174. package/src/motion3/qa/body-checks.js +34 -0
  175. package/src/motion3/qa/check-names.js +14 -0
  176. package/src/motion3/qa/checks.js +121 -0
  177. package/src/motion3/qa/contact-checks.js +51 -0
  178. package/src/motion3/qa/explain.js +80 -0
  179. package/src/motion3/qa/fmt.js +5 -0
  180. package/src/motion3/qa/foot-checks.js +72 -0
  181. package/src/motion3/qa/geometry.js +77 -0
  182. package/src/motion3/qa/goals.js +191 -0
  183. package/src/motion3/qa/ground.js +60 -0
  184. package/src/motion3/qa/hints-contact.js +179 -0
  185. package/src/motion3/qa/hints-goal.js +160 -0
  186. package/src/motion3/qa/hints-knee.js +24 -0
  187. package/src/motion3/qa/hints-motion.js +209 -0
  188. package/src/motion3/qa/hints-object.js +91 -0
  189. package/src/motion3/qa/index.js +42 -0
  190. package/src/motion3/qa/key-checks.js +82 -0
  191. package/src/motion3/qa/near.js +96 -0
  192. package/src/motion3/qa/object-checks.js +135 -0
  193. package/src/motion3/qa/patch.js +161 -0
  194. package/src/motion3/qa/severity.js +38 -0
  195. package/src/motion3/qa/spec-checks.js +65 -0
  196. package/src/motion3/qa/style.js +218 -0
  197. package/src/motion3/qa/wrist-checks.js +69 -0
  198. package/src/motion3/qa/wrist-obs.js +60 -0
  199. package/src/motion3/refs.js +120 -0
  200. package/src/motion3/repair-tune.js +121 -0
  201. package/src/motion3/repair.js +83 -0
  202. package/src/motion3/report.js +67 -0
  203. package/src/motion3/rigs/index.js +14 -0
  204. package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
  205. package/src/motion3/rigs/x-bot-tpose.json +1 -0
  206. package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
  207. package/src/motion3/rigs/y-bot-tpose.json +1 -0
  208. package/src/motion3/scene.js +60 -0
  209. package/src/motion3/schema/brief.js +89 -0
  210. package/src/motion3/schema/fields.js +44 -0
  211. package/src/motion3/schema/spec-examples.js +46 -0
  212. package/src/motion3/schema/topics.js +111 -0
  213. package/src/motion3/schema/types.js +147 -0
  214. package/src/motion3/search.js +117 -0
  215. package/src/motion3/second-hand.js +112 -0
  216. package/src/motion3/skills/basic.js +82 -0
  217. package/src/motion3/skills/book.js +76 -0
  218. package/src/motion3/skills/car.js +145 -0
  219. package/src/motion3/skills/frames-auto.js +29 -0
  220. package/src/motion3/skills/index.js +83 -0
  221. package/src/motion3/skills/info.js +65 -0
  222. package/src/motion3/skills/smoke-kit.js +109 -0
  223. package/src/motion3/skills/smoke.js +160 -0
  224. package/src/motion3/spec-store.js +59 -0
  225. package/src/motion3/take-edit.js +155 -0
  226. package/src/motion3/take.js +63 -0
  227. package/src/motion3/timeline.js +127 -0
  228. package/src/motion3/views.js +121 -0
  229. package/src/motion3/walk-plan.js +119 -0
  230. package/src/object-catalog.jsx +7 -1
  231. package/src/object-colors.js +98 -0
  232. package/src/object-gizmo-parts.js +115 -0
  233. package/src/object-gizmo.jsx +37 -122
  234. package/src/object-glow.js +139 -0
  235. package/src/object-hidden.js +33 -0
  236. package/src/object-look.js +196 -0
  237. package/src/object-size.js +10 -0
  238. package/src/object-travel.js +71 -6
  239. package/src/panels/CameraPanel.jsx +7 -7
  240. package/src/panels/HdrEnvironmentControls.jsx +59 -0
  241. package/src/panels/LightPanel.jsx +25 -4
  242. package/src/panels/ObjectLookPanel.jsx +88 -0
  243. package/src/panels/PoseImagePanel.jsx +1 -1
  244. package/src/panels/PosePanel.jsx +2 -17
  245. package/src/panels/RigControlPanel.jsx +5 -53
  246. package/src/panels/SubjectBox.jsx +4 -1
  247. package/src/panels/details.css +14 -0
  248. package/src/posestudio.jsx +4 -27
  249. package/src/project-browser.jsx +3 -4
  250. package/src/project-resources.js +18 -31
  251. package/src/project.js +13 -104
  252. package/src/props.jsx +25 -280
  253. package/src/rail-dot-drag.js +23 -0
  254. package/src/render-passes.js +10 -0
  255. package/src/resource-status.jsx +1 -0
  256. package/src/result-modal.jsx +4 -19
  257. package/src/room.jsx +20 -12
  258. package/src/scene-assets.js +8 -6
  259. package/src/scene-light-place.js +72 -0
  260. package/src/scene-lights.jsx +148 -0
  261. package/src/scene-objects.js +31 -139
  262. package/src/scenes.js +15 -105
  263. package/src/semantic-edit.js +2 -5
  264. package/src/set-pieces.jsx +183 -0
  265. package/src/settings-menu.jsx +3 -11
  266. package/src/shell/BottomDock.jsx +11 -53
  267. package/src/shell/CompositionGuideButton.jsx +20 -0
  268. package/src/shell/DetailsSlot.jsx +16 -200
  269. package/src/shell/GhostsMenuGroup.jsx +74 -0
  270. package/src/shell/LibrarySlot.jsx +1 -3
  271. package/src/shell/MenuBar.jsx +3 -3
  272. package/src/shell/PreferencesDialog.jsx +15 -264
  273. package/src/shell/PreferencesSlot.jsx +2 -8
  274. package/src/shell/ShotPreviewHeader.jsx +17 -0
  275. package/src/shell/TopBar.jsx +5 -83
  276. package/src/shell/ViewportToolbar.jsx +23 -93
  277. package/src/shell/agent-glass.css +19 -6
  278. package/src/shell/details-selection.js +42 -0
  279. package/src/shell/ghosts-menu.css +22 -0
  280. package/src/shell/glass-regions.css +29 -3
  281. package/src/shell/preferences.css +6 -1
  282. package/src/shell/viewport.css +12 -0
  283. package/src/shot-authoring.js +4 -7
  284. package/src/soft-shadows.js +37 -0
  285. package/src/stage-attach-frames.js +12 -12
  286. package/src/stage-canvas-rigs.jsx +3 -3
  287. package/src/stage-capture.jsx +42 -8
  288. package/src/stage-characters.jsx +22 -216
  289. package/src/stage-editor-gizmos.jsx +6 -6
  290. package/src/stage-environment.js +93 -0
  291. package/src/stage-hdr-builtins.js +107 -0
  292. package/src/stage-hdr-image.js +116 -0
  293. package/src/stage-hdr-library.js +70 -0
  294. package/src/stage-hdr-map.js +94 -0
  295. package/src/stage-hdr.js +130 -0
  296. package/src/stage-lighting.js +149 -0
  297. package/src/stage-occlusion.js +210 -0
  298. package/src/stage-sky.jsx +159 -0
  299. package/src/stage-startup-defaults.js +5 -9
  300. package/src/studio-actions.js +12 -14
  301. package/src/studio-agent-commands.js +46 -16
  302. package/src/studio-agent-motion.js +9 -9
  303. package/src/studio-agent-protocol.js +46 -73
  304. package/src/studio-app-binding.js +29 -45
  305. package/src/studio-asset-list.js +17 -0
  306. package/src/studio-contact-sheet.js +37 -5
  307. package/src/studio-elements.js +27 -7
  308. package/src/studio-entity-bounds.js +18 -0
  309. package/src/studio-error-codes.js +8 -0
  310. package/src/studio-export-framing.js +152 -0
  311. package/src/studio-lighting-check.js +103 -0
  312. package/src/studio-motion-visual.js +150 -0
  313. package/src/studio-schema-errors.js +80 -0
  314. package/src/studio-support-gap.js +74 -0
  315. package/src/styles.css +1 -19
  316. package/src/timeline-defaults.js +5 -0
  317. package/src/timeline-extent.js +8 -20
  318. package/src/tutorial-walk.js +17 -0
  319. package/src/ui-scrub.js +1 -1
  320. package/src/use-shot-camera-tracks.js +12 -0
  321. package/src/view-ghosts.js +97 -0
  322. package/src/view-ghosts.jsx +49 -0
  323. package/src/workflow/AgentPanel.jsx +47 -166
  324. package/src/workflow/AgentProgressCard.jsx +107 -0
  325. package/src/workflow/AgentReplyText.jsx +37 -0
  326. package/src/workflow/AgentTurnSteps.jsx +84 -0
  327. package/src/workflow/LoginPanel.jsx +140 -0
  328. package/src/workflow/WorkflowBuilder.jsx +7 -23
  329. package/src/workflow/agent-client.js +54 -51
  330. package/src/workflow/agent-panel.css +71 -1
  331. package/src/workflow/agent-progress-card.css +167 -0
  332. package/src/workflow/agent-progress-view.js +47 -0
  333. package/src/workflow/agent-turn-steps.css +113 -0
  334. package/src/workflow/agent-turn.js +191 -0
  335. package/src/workflow/login-client.js +34 -0
  336. package/src/workflow/motion-input.js +18 -31
  337. package/src/workflow/node-schema.js +1 -1
  338. package/src/workflow/reply-markdown.js +69 -0
  339. package/src/workflow/scene-asset-sync.js +8 -8
  340. package/tools/agent-session-stats.mjs +61 -0
  341. package/tools/dev-full.mjs +5 -56
  342. package/tools/eslint-baseline.json +12 -13
  343. package/tools/headless-studio.mjs +85 -0
  344. package/tools/knip-baseline.json +0 -179
  345. package/tools/loc-baseline.json +33 -83
  346. package/tools/motion3/extract-body.mjs +103 -0
  347. package/tools/motion3/extract-rig.mjs +85 -0
  348. package/tools/process-supervisor.mjs +0 -88
  349. package/tools/run-tests.mjs +9 -124
  350. package/bin/agent/motion-runtime.mjs +0 -76
  351. package/dist/ardy/cskel27-rest.json +0 -557
  352. package/dist/assets/analytics-B41FmPYI.js +0 -1
  353. package/dist/assets/app-Do-Og5Pu.css +0 -1
  354. package/dist/assets/app-DwP-tl2x.js +0 -4920
  355. package/dist/assets/config-Bx7pYsD9.js +0 -1
  356. package/dist/assets/config-DeoFTYzb.css +0 -1
  357. package/dist/assets/demo-Dt0qZfS7.js +0 -1
  358. package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
  359. package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
  360. package/dist/assets/ticket-jqMhqL88.js +0 -1
  361. package/dist/assets/workflow-Br-K7Srs.js +0 -179
  362. package/dist/demo/walk-then-stop.npz +0 -0
  363. package/mcp/ardy-prompts.mjs +0 -218
  364. package/src/ardy/auto-fix-panel.css +0 -108
  365. package/src/ardy/auto-physics.js +0 -1194
  366. package/src/ardy/client.js +0 -153
  367. package/src/ardy/convert.js +0 -313
  368. package/src/ardy/cskel27-neutral.js +0 -39
  369. package/src/ardy/cskel27.js +0 -77
  370. package/src/ardy/export.js +0 -165
  371. package/src/ardy/fix-collisions.js +0 -2257
  372. package/src/ardy/foot-lock.js +0 -230
  373. package/src/ardy/motion-calibration.js +0 -118
  374. package/src/ardy/motion-edit.js +0 -213
  375. package/src/ardy/motion-url.js +0 -55
  376. package/src/ardy/mp4-duration.js +0 -102
  377. package/src/ardy/npz.js +0 -595
  378. package/src/ardy/physics-panel.css +0 -21
  379. package/src/ardy/physics-panel.jsx +0 -89
  380. package/src/ardy/physics-refine.js +0 -111
  381. package/src/ardy/physics-review.js +0 -567
  382. package/src/ardy/physics-temporal.js +0 -54
  383. package/src/ardy/platform-fit-panel.css +0 -64
  384. package/src/ardy/platform-fit-panel.jsx +0 -41
  385. package/src/ardy/platform-fit.js +0 -326
  386. package/src/ardy/playback.js +0 -711
  387. package/src/ardy/pose-pin.js +0 -97
  388. package/src/ardy/prompt-clips.js +0 -30
  389. package/src/ardy/retime.js +0 -211
  390. package/src/ardy/root-drop.js +0 -369
  391. package/src/ardy/timeline-resize.js +0 -13
  392. package/src/ardy/to-cskel27.js +0 -225
  393. package/src/ardy/trim.js +0 -33
  394. package/src/ardy/waypoints.js +0 -369
  395. package/src/ardy-bridge-contract.js +0 -281
  396. package/src/domains/motion/motion-video-capture.js +0 -664
  397. package/src/i2v-motion-client.js +0 -77
  398. package/src/i2v-motion-studio.jsx +0 -180
  399. package/src/line-edit.js +0 -1348
  400. package/src/motion/generation.js +0 -105
  401. package/src/motion-readiness-ui.jsx +0 -67
  402. package/src/motion-readiness.js +0 -40
  403. package/src/motion-resources.js +0 -177
  404. package/src/motion-store.js +0 -65
  405. package/src/motion-trail.js +0 -601
  406. package/src/multimodel-ingest.js +0 -394
  407. package/src/panels/PromptBlocksPanel.jsx +0 -444
  408. package/src/panels/VideoCapturePanel.jsx +0 -181
  409. package/src/pose-extract/browser.js +0 -42
  410. package/src/pose-extract/detector.js +0 -100
  411. package/src/pose-extract/fit.js +0 -227
  412. package/src/pose-extract/image-frame.js +0 -51
  413. package/src/pose-extract/index.js +0 -58
  414. package/src/pose-extract/keyframes.js +0 -74
  415. package/src/pose-extract/landmarks.js +0 -162
  416. package/src/pose-extract/mirror.js +0 -153
  417. package/src/pose-extract/take.js +0 -131
  418. package/src/pose-extract/video-frames.js +0 -91
  419. package/src/take-recipe.js +0 -165
  420. package/src/trail-key-conflicts.js +0 -39
  421. package/src/trail-pick.js +0 -59
  422. package/src/use-i2v-capture-modal.js +0 -15
  423. package/tools/ardy/BRIDGE.md +0 -37
  424. package/tools/ardy/GVHMR-NPZ.md +0 -68
  425. package/tools/ardy/README.md +0 -124
  426. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  427. package/tools/ardy/artifacts.mjs +0 -34
  428. package/tools/ardy/bridge.mjs +0 -1732
  429. package/tools/ardy/bvh-cskel27.mjs +0 -1265
  430. package/tools/ardy/cclay_constrained_generate.py +0 -561
  431. package/tools/ardy/cclay_gvhmr_worker.py +0 -264
  432. package/tools/ardy/cclay_motion_edit.py +0 -510
  433. package/tools/ardy/cclay_sequence_generate.py +0 -705
  434. package/tools/ardy/cclay_worker.py +0 -304
  435. package/tools/ardy/dump-npz.py +0 -205
  436. package/tools/ardy/extract-rest.mjs +0 -299
  437. package/tools/ardy/extract.mjs +0 -507
  438. package/tools/ardy/footage.mjs +0 -467
  439. package/tools/ardy/gvhmr-floor.mjs +0 -102
  440. package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
  441. package/tools/ardy/gvhmr_fastpath.py +0 -168
  442. package/tools/ardy/gvhmr_trajectory.py +0 -240
  443. package/tools/ardy/merge-text-encoder.py +0 -160
  444. package/tools/ardy/mocap-metrics.mjs +0 -200
  445. package/tools/ardy/mocap-quality-gate.mjs +0 -110
  446. package/tools/ardy/motion-stabilize.mjs +0 -348
  447. package/tools/ardy/npz.mjs +0 -414
  448. package/tools/ardy/pose-to-npz.mjs +0 -106
  449. package/tools/ardy/prompt-limits.mjs +0 -5
  450. package/tools/ardy/run-edit-on-box.sh +0 -73
  451. package/tools/ardy/run-local.mjs +0 -233
  452. package/tools/ardy/run-on-box.sh +0 -593
  453. package/tools/ardy/run-sequence-on-box.sh +0 -177
  454. package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
  455. package/tools/ardy/runners/index.mjs +0 -18
  456. package/tools/ardy/runners/local.mjs +0 -455
  457. package/tools/ardy/runners/proc.mjs +0 -125
  458. package/tools/ardy/runners/remote.mjs +0 -252
  459. package/tools/ardy/setup-local.mjs +0 -189
  460. package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
  461. package/tools/ardy/setup-text-encoder.py +0 -306
  462. package/tools/ardy/smpl-cskel27.mjs +0 -178
  463. package/tools/ardy/visual-qa.mjs +0 -196
  464. package/tools/ardy/vq-car.mjs +0 -52
  465. package/tools/bench/EXP3.md +0 -61
  466. package/tools/bench/cclay_bench_extract_incam.py +0 -125
  467. package/tools/bench/cclay_bench_extract_obs.py +0 -204
  468. package/tools/bench/cclay_bench_runner.py +0 -42
  469. package/tools/bench/cube-contact.mjs +0 -162
  470. package/tools/bench/exp3.mjs +0 -152
  471. package/tools/bench/extract-bench-lib.mjs +0 -216
  472. package/tools/bench/extract-bench.mjs +0 -302
  473. package/tools/bench/fal-generate.mjs +0 -88
  474. package/tools/bench/fit/README.md +0 -189
  475. package/tools/bench/fit/camera.mjs +0 -59
  476. package/tools/bench/fit/contact.mjs +0 -419
  477. package/tools/bench/fit/footlock.mjs +0 -234
  478. package/tools/bench/fit/motion.mjs +0 -85
  479. package/tools/bench/fit/pin.mjs +0 -27
  480. package/tools/bench/fit/remote.mjs +0 -105
  481. package/tools/bench/fit-bench.mjs +0 -126
  482. package/tools/bench/fit-sanity.mjs +0 -45
  483. package/tools/bench/metrics.mjs +0 -313
  484. package/tools/bench/obs/depth.mjs +0 -258
  485. package/tools/bench/obs/extrinsics.mjs +0 -175
  486. package/tools/bench/obs/fit_mannequin_betas.py +0 -340
  487. package/tools/bench/obs/ground.mjs +0 -294
  488. package/tools/bench/obs/heading.mjs +0 -151
  489. package/tools/bench/obs/ladder.mjs +0 -555
  490. package/tools/bench/obs/mannequin-betas.json +0 -124
  491. package/tools/bench/obs/remote.mjs +0 -83
  492. package/tools/bench/obs/rest_joints.py +0 -52
  493. package/tools/bench/obs/ybot-targets.mjs +0 -49
  494. package/tools/bench/obs-bench.mjs +0 -520
  495. package/tools/bench/score.mjs +0 -343
  496. package/tools/bench/summarize.mjs +0 -86
  497. package/tools/demo-worker/README.md +0 -137
  498. package/tools/demo-worker/api-client.mjs +0 -233
  499. package/tools/demo-worker/generate.mjs +0 -301
  500. package/tools/demo-worker/index.mjs +0 -466
  501. package/tools/demo-worker/sign-core.mjs +0 -112
  502. package/tools/demo-worker/sign.mjs +0 -161
  503. package/tools/gt-render/browser.mjs +0 -159
  504. package/tools/gt-render/camera-math.mjs +0 -276
  505. package/tools/gt-render/page.mjs +0 -267
  506. package/tools/gt-render/render.mjs +0 -514
  507. package/tools/gt-render/scene-box.mjs +0 -31
  508. package/tools/gt-render/take-transform.mjs +0 -87
  509. package/tools/kimodo/compare-seam.mjs +0 -108
  510. package/tools/kimodo/constraints.mjs +0 -244
  511. package/tools/kimodo/edit.mjs +0 -259
  512. package/tools/kimodo/effector-constraints.mjs +0 -200
  513. package/tools/kimodo/generate.mjs +0 -646
  514. package/tools/kimodo/local-output.mjs +0 -265
  515. package/tools/kimodo/measure-pose.mjs +0 -65
  516. package/tools/kimodo/measure-preserve.mjs +0 -899
  517. package/tools/kimodo/measure-waypoints.mjs +0 -55
  518. package/tools/kimodo/mlx-generate.py +0 -111
  519. package/tools/kimodo/pose-constraints.mjs +0 -248
  520. package/tools/kimodo/preserve-mask.mjs +0 -543
  521. package/tools/kimodo/read-npz.mjs +0 -189
  522. package/tools/kimodo/run-edit-on-box.mjs +0 -155
  523. package/tools/kimodo/run-sequence-on-box.mjs +0 -178
  524. package/tools/kimodo/runner.mjs +0 -284
  525. package/tools/kimodo/seam-batch.mjs +0 -77
  526. package/tools/kimodo/setup-local.mjs +0 -30
  527. package/tools/kimodo/setup-on-box.sh +0 -339
  528. package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
  529. package/tools/morphgs/assets/gen_truth.py +0 -39
  530. package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
  531. package/tools/morphgs/assets/playback-check.mjs +0 -30
  532. package/tools/morphgs/demo-gate.sh +0 -26
  533. package/tools/morphgs/fbx2morphgs.mjs +0 -68
  534. package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
  535. package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
  536. package/tools/morphgs/setup-on-cluster.sh +0 -126
  537. package/tools/projflow/driver.py +0 -1069
  538. package/tools/projflow/generate.mjs +0 -805
  539. package/tools/projflow/hml22-to-cskel27.mjs +0 -735
  540. package/tools/projflow/line-edit-job.mjs +0 -547
  541. package/tools/projflow/replay.mjs +0 -452
  542. package/tools/projflow/runner.mjs +0 -269
  543. package/tools/projflow/service.mjs +0 -742
  544. package/tools/track/DESIGN.md +0 -513
  545. package/tools/track/backfill-provenance.mjs +0 -116
  546. package/tools/track/budget.mjs +0 -8
  547. package/tools/track/check-rig.mjs +0 -209
  548. package/tools/track/diagnostics.schema.json +0 -60
  549. package/tools/track/export-rig.mjs +0 -256
  550. package/tools/track/fallback.mjs +0 -7
  551. package/tools/track/fk-parity-fixture.mjs +0 -161
  552. package/tools/track/gate.mjs +0 -349
  553. package/tools/track/masks.mjs +0 -318
  554. package/tools/track/metrics.mjs +0 -201
  555. package/tools/track/publish-obs.mjs +0 -108
  556. package/tools/track/py/check_env.py +0 -61
  557. package/tools/track/py/eval_lr.py +0 -229
  558. package/tools/track/py/lr_viterbi.py +0 -294
  559. package/tools/track/py/masks.py +0 -405
  560. package/tools/track/py/objective.py +0 -382
  561. package/tools/track/py/rig.py +0 -508
  562. package/tools/track/py/scene.py +0 -326
  563. package/tools/track/py/test_joint_indices.py +0 -123
  564. package/tools/track/py/test_lr_viterbi.py +0 -195
  565. package/tools/track/py/test_masks.py +0 -229
  566. package/tools/track/py/test_rig.py +0 -288
  567. package/tools/track/py/test_scene.py +0 -354
  568. package/tools/track/py/test_track.py +0 -328
  569. package/tools/track/py/track.py +0 -411
  570. package/tools/track/remote.mjs +0 -140
  571. package/tools/track/rig-dump.mjs +0 -227
  572. package/tools/track/run-box-tests.mjs +0 -14
  573. package/tools/track/run-box.mjs +0 -168
  574. package/tools/track/setup-box.sh +0 -59
  575. package/tools/track/study-2d.mjs +0 -728
  576. /package/src/{ardy → motion}/collision-blockers.js +0 -0
  577. /package/src/{ardy → motion}/ground.js +0 -0
  578. /package/src/{ardy → motion}/ik-drag.js +0 -0
  579. /package/src/{ardy → motion}/ik-key-json.js +0 -0
  580. /package/src/{ardy → motion}/ik.js +0 -0
  581. /package/src/{ardy → motion}/physics-surface.js +0 -0
  582. /package/src/{ardy → motion}/playback-clock.js +0 -0
  583. /package/src/{ardy → motion}/range-pin.js +0 -0
@@ -0,0 +1,115 @@
1
+ import * as THREE from "three";
2
+ import { objectSize } from "./scene-objects.js";
3
+
4
+ // The ObjectGizmo's fixed parts: handle layout, sizes, colours and the two
5
+ // placement rules (where the gizmo stands, and which way its rings face).
6
+ export const AXES = [
7
+ { axis: "x", dir: new THREE.Vector3(1, 0, 0), color: "#ff5340" },
8
+ { axis: "y", dir: new THREE.Vector3(0, 1, 0), color: "#54e05c" },
9
+ { axis: "z", dir: new THREE.Vector3(0, 0, 1), color: "#3d8bff" },
10
+ ];
11
+ /** the same three directions, addressable by the record's axis key */
12
+ export const AXIS_VECTORS = { x: AXES[0].dir, y: AXES[1].dir, z: AXES[2].dir };
13
+ /** Move-tool plane handles. Unity colours each square after the axis it LOCKS,
14
+ * so the blue square (z locked) slides in xy. `normal` is the pinned axis. */
15
+ export const PLANES = [
16
+ { id: "xz", axes: ["x", "z"], normal: "y", color: "#54e05c" },
17
+ { id: "xy", axes: ["x", "y"], normal: "z", color: "#3d8bff" },
18
+ { id: "yz", axes: ["y", "z"], normal: "x", color: "#ff5340" },
19
+ ];
20
+ export const PLANE_OFFSET = 0.26; // where the square sits along each of its two axes
21
+ export const PLANE_SIZE = 0.2;
22
+ export const ARROW_LEN = 0.62;
23
+ export const SHAFT_R = 0.016;
24
+ export const TIP_R = 0.05;
25
+ export const TIP_LEN = 0.14;
26
+ export const RING_R = 0.52;
27
+ /**
28
+ * The axis rings are drawn as two half-tori instead of one full torus. A full
29
+ * ring is misleading: the half facing away from the camera is pixel-identical
30
+ * to the near half, so a drag started on the far side reads backwards.
31
+ * Depth-sorting the ring against the object would only help when the object
32
+ * is big enough to occlude the far half — the gizmo sits at the object's
33
+ * centre and the ring is only 0.52 m across, so for the small props a
34
+ * blocking tool is full of, the far half projects outside the silhouette and
35
+ * stays ambiguous. Fading it instead (FAR_HALF_ALPHA vs the near half's
36
+ * 0.95) is unambiguous at every object size and camera angle. Only the drawn
37
+ * halves fade — the pick proxy stays one full invisible torus per ring.
38
+ */
39
+ export const FAR_HALF_ALPHA = 0.28;
40
+ /** the outer screen-space ring: larger than the axis rings (RING_R) so it
41
+ * encloses them from every angle, and far enough out that its pick band
42
+ * [0.61, 0.75] clears the axis rings' [0.45, 0.59] — the two can never fight
43
+ * for a grab. (§3.3: "a larger circle enclosing the sphere, drawn flat to
44
+ * the viewer" — rotates about the view axis.) */
45
+ export const SCREEN_RING_R = 0.68;
46
+ /** Unity's yellow for the handle being dragged — and, after release, for the
47
+ * last-dragged one, until the selection or the tool changes (§3.1). */
48
+ export const ACTIVE_COLOR = "#ffd23d";
49
+ export const RING_TUBE = 0.022;
50
+ export const BOX_SIZE = 0.09; // scale-mode axis knobs
51
+ export const CENTRE_BOX = 0.11; // uniform-scale knob at the pivot
52
+ /** Pick proxies. A drawn 1.6 cm shaft is ~3 screen pixels — nothing anyone can
53
+ * reliably grab — so hit testing runs against invisible fat volumes around each
54
+ * arrow, ring and knob, the way every DCC gizmo does it. */
55
+ export const PICK_SHAFT_R = 0.09;
56
+ export const PICK_TUBE_R = 0.07;
57
+ export const PICK_CENTRE_R = 0.16;
58
+ /** metres of gizmo per metre of camera distance: keeps it a constant size on
59
+ * screen whether the object is at the lens or across the room */
60
+ export const SCREEN_SCALE = 0.16;
61
+
62
+ /** the object's own centre height, where the gizmo sits */
63
+ function gizmoHeight(object) {
64
+ return (object.y ?? 0) + Math.max(objectSize(object).height / 2, 0.25);
65
+ }
66
+
67
+ /** the handles-Map key a pick entry was registered under — the same
68
+ * expression __gizmoPick reports, so highlights and QA hooks agree on handle
69
+ * identity */
70
+ export function handleKey(entry) {
71
+ if (entry.corner) return `corner:${entry.corner.id}`;
72
+ return entry.axis ?? (entry.plane ? `plane:${entry.plane.id}` : "centre");
73
+ }
74
+
75
+ /**
76
+ * The four corners of a cutout card, in the card's own local space.
77
+ *
78
+ * A standee is a picture, and a picture is resized by its corners — grabbing
79
+ * one and pulling is the gesture everybody already has for "make this bigger",
80
+ * and unlike an axis knob it says which way is bigger without reading a label.
81
+ * `sx`/`sy` are which way each corner lies from the centre, so the drag can
82
+ * measure travel along the diagonal that corner actually points down.
83
+ */
84
+ export const CARD_CORNERS = [
85
+ { id: "tr", sx: 1, sy: 1 },
86
+ { id: "tl", sx: -1, sy: 1 },
87
+ { id: "br", sx: 1, sy: -1 },
88
+ { id: "bl", sx: -1, sy: -1 },
89
+ ];
90
+ export const CORNER_BOX = 0.085;
91
+ export const PICK_CORNER_R = 0.13;
92
+
93
+ /**
94
+ * Screen-space ring result: the object rotated `deltaDeg` about the world
95
+ * `viewAxis`, written back as all three Euler channels in one patch. The
96
+ * stored channels are Euler degrees per world axis, so the drag-start
97
+ * orientation is composed with the delta in quaternion space and decomposed
98
+ * again in the same order the renderer uses — exact for any start
99
+ * orientation, where a single-channel approximation would drift. Snap
100
+ * quantizes the accumulated delta to the same 5° grid the axis rings snap
101
+ * their start+delta to (start values are always on the grid themselves).
102
+ */
103
+
104
+ // Path authoring intersects presses with the set floor, exactly where a
105
+ // dropped pin will live.
106
+ export const GROUND = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
107
+ /** Where the gizmo stands: on the pose a take draws the object at (`held.pose`, held-object-edit.jsx), else at the authored centre. */
108
+ export function gizmoOrigin(object, held, out) {
109
+ return held?.pose ? out.fromArray(held.pose.centre) : out.set(object.x, gizmoHeight(object), object.z);
110
+ }
111
+
112
+ /** The rotation the handles take: the drawn object's own axes while a held-object drag edits it in rotate mode, else none (world axes). */
113
+ export function gizmoTurn(held, mode) {
114
+ return mode === "rotate" && held?.editable ? held.pose.quat : null;
115
+ }
@@ -3,15 +3,11 @@ import { useFrame, useThree } from "@react-three/fiber";
3
3
  import * as THREE from "three";
4
4
  import { GIZMO_LAYER, SHOT_ASPECT, fitAspect } from "./dualview.jsx";
5
5
  import { HANDLE_PROXY_FLAG, claimsPress } from "./gizmo-claim.js";
6
- import {
7
- CUTOUT_KIND,
8
- objectSize,
9
- rotatePatch,
10
- scalePatch,
11
- screenRotatePatch,
12
- translatePatch,
13
- wrapAngle,
14
- } from "./scene-objects.js";
6
+ import { CUTOUT_KIND, rotatePatch, scalePatch, screenRotatePatch, translatePatch, wrapAngle } from "./scene-objects.js";
7
+ import { dragTravel, dragTurn } from "./held-object-pose.js";
8
+ import { HeldTrail } from "./held-object-edit.jsx";
9
+ import { ACTIVE_COLOR, ARROW_LEN, AXES, AXIS_VECTORS, BOX_SIZE, CARD_CORNERS, CENTRE_BOX, CORNER_BOX, FAR_HALF_ALPHA, GROUND, PICK_CENTRE_R, PICK_CORNER_R, PICK_SHAFT_R, PICK_TUBE_R,
10
+ PLANES, PLANE_OFFSET, PLANE_SIZE, RING_R, RING_TUBE, SCREEN_RING_R, SCREEN_SCALE, SHAFT_R, TIP_LEN, TIP_R, gizmoOrigin, gizmoTurn, handleKey } from "./object-gizmo-parts.js";
15
11
 
16
12
  /**
17
13
  * The transform gizmo for the selected scene object — the thing every 3D tool
@@ -46,109 +42,8 @@ import {
46
42
  * space and decomposed back into the same channels (screenRotatePatch).
47
43
  */
48
44
 
49
- const AXES = [
50
- { axis: "x", dir: new THREE.Vector3(1, 0, 0), color: "#ff5340" },
51
- { axis: "y", dir: new THREE.Vector3(0, 1, 0), color: "#54e05c" },
52
- { axis: "z", dir: new THREE.Vector3(0, 0, 1), color: "#3d8bff" },
53
- ];
54
- /** the same three directions, addressable by the record's axis key */
55
- const AXIS_VECTORS = { x: AXES[0].dir, y: AXES[1].dir, z: AXES[2].dir };
56
- /** Move-tool plane handles. Unity colours each square after the axis it LOCKS,
57
- * so the blue square (z locked) slides in xy. `normal` is the pinned axis. */
58
- const PLANES = [
59
- { id: "xz", axes: ["x", "z"], normal: "y", color: "#54e05c" },
60
- { id: "xy", axes: ["x", "y"], normal: "z", color: "#3d8bff" },
61
- { id: "yz", axes: ["y", "z"], normal: "x", color: "#ff5340" },
62
- ];
63
- const PLANE_OFFSET = 0.26; // where the square sits along each of its two axes
64
- const PLANE_SIZE = 0.2;
65
- const ARROW_LEN = 0.62;
66
- const SHAFT_R = 0.016;
67
- const TIP_R = 0.05;
68
- const TIP_LEN = 0.14;
69
- const RING_R = 0.52;
70
- /**
71
- * The axis rings are drawn as two half-tori instead of one full torus. A full
72
- * ring is misleading: the half facing away from the camera is pixel-identical
73
- * to the near half, so a drag started on the far side reads backwards.
74
- * Depth-sorting the ring against the object would only help when the object
75
- * is big enough to occlude the far half — the gizmo sits at the object's
76
- * centre and the ring is only 0.52 m across, so for the small props a
77
- * blocking tool is full of, the far half projects outside the silhouette and
78
- * stays ambiguous. Fading it instead (FAR_HALF_ALPHA vs the near half's
79
- * 0.95) is unambiguous at every object size and camera angle. Only the drawn
80
- * halves fade — the pick proxy stays one full invisible torus per ring.
81
- */
82
- const FAR_HALF_ALPHA = 0.28;
83
- /** the outer screen-space ring: larger than the axis rings (RING_R) so it
84
- * encloses them from every angle, and far enough out that its pick band
85
- * [0.61, 0.75] clears the axis rings' [0.45, 0.59] — the two can never fight
86
- * for a grab. (§3.3: "a larger circle enclosing the sphere, drawn flat to
87
- * the viewer" — rotates about the view axis.) */
88
- const SCREEN_RING_R = 0.68;
89
- /** Unity's yellow for the handle being dragged — and, after release, for the
90
- * last-dragged one, until the selection or the tool changes (§3.1). */
91
- const ACTIVE_COLOR = "#ffd23d";
92
- const RING_TUBE = 0.022;
93
- const BOX_SIZE = 0.09; // scale-mode axis knobs
94
- const CENTRE_BOX = 0.11; // uniform-scale knob at the pivot
95
- /** Pick proxies. A drawn 1.6 cm shaft is ~3 screen pixels — nothing anyone can
96
- * reliably grab — so hit testing runs against invisible fat volumes around each
97
- * arrow, ring and knob, the way every DCC gizmo does it. */
98
- const PICK_SHAFT_R = 0.09;
99
- const PICK_TUBE_R = 0.07;
100
- const PICK_CENTRE_R = 0.16;
101
- /** metres of gizmo per metre of camera distance: keeps it a constant size on
102
- * screen whether the object is at the lens or across the room */
103
- const SCREEN_SCALE = 0.16;
104
-
105
- /** the object's own centre height, where the gizmo sits */
106
- function gizmoHeight(object) {
107
- return (object.y ?? 0) + Math.max(objectSize(object).height / 2, 0.25);
108
- }
109
-
110
- /** the handles-Map key a pick entry was registered under — the same
111
- * expression __gizmoPick reports, so highlights and QA hooks agree on handle
112
- * identity */
113
- function handleKey(entry) {
114
- if (entry.corner) return `corner:${entry.corner.id}`;
115
- return entry.axis ?? (entry.plane ? `plane:${entry.plane.id}` : "centre");
116
- }
117
-
118
- /**
119
- * The four corners of a cutout card, in the card's own local space.
120
- *
121
- * A standee is a picture, and a picture is resized by its corners — grabbing
122
- * one and pulling is the gesture everybody already has for "make this bigger",
123
- * and unlike an axis knob it says which way is bigger without reading a label.
124
- * `sx`/`sy` are which way each corner lies from the centre, so the drag can
125
- * measure travel along the diagonal that corner actually points down.
126
- */
127
- const CARD_CORNERS = [
128
- { id: "tr", sx: 1, sy: 1 },
129
- { id: "tl", sx: -1, sy: 1 },
130
- { id: "br", sx: 1, sy: -1 },
131
- { id: "bl", sx: -1, sy: -1 },
132
- ];
133
- const CORNER_BOX = 0.085;
134
- const PICK_CORNER_R = 0.13;
135
-
136
- /**
137
- * Screen-space ring result: the object rotated `deltaDeg` about the world
138
- * `viewAxis`, written back as all three Euler channels in one patch. The
139
- * stored channels are Euler degrees per world axis, so the drag-start
140
- * orientation is composed with the delta in quaternion space and decomposed
141
- * again in the same order the renderer uses — exact for any start
142
- * orientation, where a single-channel approximation would drift. Snap
143
- * quantizes the accumulated delta to the same 5° grid the axis rings snap
144
- * their start+delta to (start values are always on the grid themselves).
145
- */
146
-
147
- // Path authoring intersects presses with the set floor, exactly where a
148
- // dropped pin will live.
149
- const GROUND = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
150
45
 
151
- export default function ObjectGizmo({ object, objects = [], mode = "move", snap = true, enabled, pickOnly = false, paneRef, camRef, shotAspect = SHOT_ASPECT, onChange, onSelect, onGroundClick, onDragStart, onDragEnd, claimPointer }) {
46
+ export default function ObjectGizmo({ object, objects = [], mode = "move", snap = true, enabled, pickOnly = false, paneRef, camRef, shotAspect = SHOT_ASPECT, onChange, onSelect, onGroundClick, onDragStart, onDragEnd, claimPointer, held = null }) {
152
47
  const { gl, scene } = useThree();
153
48
  // shotAspect null = the camera fills the pane (the editor working view):
154
49
  // pointer mapping uses the pane rect itself instead of a letterboxed
@@ -174,7 +69,10 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
174
69
  const hoverRef = useRef(null); // last hovered key: pointer moves that keep it skip the re-render
175
70
  const dragRef = useRef(null);
176
71
  const stateRef = useRef(null);
177
- stateRef.current = { object, objects, mode, snap, onChange, onSelect, onGroundClick, onDragStart, onDragEnd, claimPointer };
72
+ // `held` (held-object-edit.jsx): the object is drawn by a compiled take. The
73
+ // gizmo stands on that drawn pose, and while a hand holds the object a move
74
+ // or rotate drag edits its motion through `held` instead of the record.
75
+ stateRef.current = { object, objects, mode, snap, onChange, onSelect, onGroundClick, onDragStart, onDragEnd, claimPointer, held };
178
76
  const tools = useMemo(
179
77
  () => ({
180
78
  raycaster: new THREE.Raycaster(),
@@ -347,6 +245,7 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
347
245
  // the moment the pointer crosses the ring's ±180° seam.
348
246
  drag.turned += wrapAngle(((angle - drag.lastAngle) * 180) / Math.PI);
349
247
  drag.lastAngle = angle;
248
+ if (drag.held) return void stateRef.current.held?.rotate(drag.dir, dragTurn(drag.turned, snapping ? 5 : 0));
350
249
  if (drag.axis === "screen") {
351
250
  // The screen ring spins about the view axis: compose the
352
251
  // delta onto the drag-start orientation in quaternion space
@@ -399,6 +298,7 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
399
298
  return;
400
299
  }
401
300
  tools.delta.subVectors(tools.hit, drag.hitStart);
301
+ if (drag.held) return void stateRef.current.held?.move(dragTravel(tools.delta, drag.planeAxes ? drag.planeAxes.map((axis) => AXIS_VECTORS[axis]) : [drag.dir], snapping ? 0.05 : 0));
402
302
  if (drag.planeAxes) {
403
303
  // Plane handle: two axes travel, the third is pinned. This is what
404
304
  // replaced body-dragging — the XZ square is how a set gets dressed.
@@ -438,7 +338,8 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
438
338
  const end = stateRef.current.onDragEnd;
439
339
  const token = drag.token;
440
340
  teardownDrag();
441
- if (token != null && end) end(token, { commit });
341
+ if (drag.held) stateRef.current.held?.end(commit);
342
+ else if (token != null && end) end(token, { commit });
442
343
  };
443
344
 
444
345
  /** pointerup and pointercancel both commit: the travel already applied
@@ -482,7 +383,8 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
482
383
  // (a jump of however far the car has driven). The pivot, and the yaw
483
384
  // the card's corners are seen at, are the shown ones.
484
385
  const live = stateRef.current.objects.find((entry) => entry.id === shown.id) ?? shown;
485
- tools.origin.set(shown.x, gizmoHeight(shown), shown.z);
386
+ const heldEdit = stateRef.current.held;
387
+ gizmoOrigin(shown, heldEdit, tools.origin);
486
388
  camera.getWorldDirection(tools.eye);
487
389
  let plane;
488
390
  let drag;
@@ -491,7 +393,9 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
491
393
  // pivot. The screen ring has no axis of its own: it spins
492
394
  // about the camera's own forward, so its plane is the
493
395
  // camera-facing plane through the pivot.
494
- const spinDir = axis === "screen" ? tools.eye : dir;
396
+ // A held object turns about its own axes (its rings are drawn turned too).
397
+ const turn = gizmoTurn(heldEdit, kind);
398
+ const spinDir = axis === "screen" ? tools.eye : turn ? dir.clone().applyQuaternion(new THREE.Quaternion(...turn)) : dir;
495
399
  plane = new THREE.Plane().setFromNormalAndCoplanarPoint(spinDir, tools.origin.clone());
496
400
  const hit = new THREE.Vector3();
497
401
  if (!tools.raycaster.ray.intersectPlane(plane, hit)) return false;
@@ -577,12 +481,14 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
577
481
  // (§6.1). The `cancel` handed over is teardown-only — the
578
482
  // coordinator owns the close, and a close attempted from inside it
579
483
  // is inert because the token is retired first (§5.2).
580
- const token = stateRef.current.onDragStart?.({
484
+ // A held-object drag edits the motion, not the record: no scene transaction.
485
+ const heldDrag = Boolean(heldEdit?.editable && (kind === "rotate" || (!heldEdit.hinge && (kind === "move" || kind === "plane"))) && heldEdit.begin());
486
+ const token = heldDrag ? undefined : stateRef.current.onDragStart?.({
581
487
  owner: "gizmo",
582
488
  cancel: teardownDrag,
583
489
  });
584
490
  const corner = kind === "corner" ? dir : null;
585
- dragRef.current = { ...drag, id: live.id, axis, plane, corner, start: { ...live }, token };
491
+ dragRef.current = { ...drag, id: live.id, axis, plane, corner, start: { ...live }, token, held: heldDrag };
586
492
  // the grabbed handle turns yellow now and stays yellow after
587
493
  // release, until the selection or the tool changes (§3.1)
588
494
  setActiveHandle(handleKey({ axis, plane, corner }));
@@ -593,7 +499,7 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
593
499
  // Only a real transaction gets the extra lifecycle edges: blur and
594
500
  // Escape would otherwise change mid-drag behaviour for callers that
595
501
  // pass no transaction props (the byte-for-byte fallback path).
596
- if (token != null) {
502
+ if (token != null || heldDrag) {
597
503
  window.addEventListener("blur", onBlur);
598
504
  window.addEventListener("keydown", onKeyDown, true);
599
505
  }
@@ -753,7 +659,7 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
753
659
  const camera = camRef?.current;
754
660
  if (!root || !camera || !object) return;
755
661
  camera.getWorldPosition(tools.camPos);
756
- tools.origin.set(object.x, gizmoHeight(object), object.z);
662
+ gizmoOrigin(object, held, tools.origin);
757
663
  root.scale.setScalar(Math.max(0.35, tools.camPos.distanceTo(tools.origin) * SCREEN_SCALE));
758
664
  if (mode !== "rotate") return;
759
665
  // The rotate rings are view-dependent, so their orientation is frame
@@ -764,6 +670,14 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
764
670
  camera.getWorldDirection(tools.eye);
765
671
  const screen = screenRingRef.current;
766
672
  if (screen) screen.quaternion.copy(camera.quaternion);
673
+ // Turned rings (a held object's own axes): the near/far split and the
674
+ // billboard are worked out in the gizmo's own frame.
675
+ const turn = gizmoTurn(held, mode);
676
+ if (turn) {
677
+ const unturn = new THREE.Quaternion(...turn).invert();
678
+ tools.eye.applyQuaternion(unturn);
679
+ screen?.quaternion.premultiply(unturn);
680
+ }
767
681
  for (const { axis, u, v } of ringBases) {
768
682
  const ring = ringGroupsRef.current[axis];
769
683
  if (!ring) continue;
@@ -855,8 +769,9 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
855
769
  const screenHovered = hoveredHandle === "screen";
856
770
  const centreActive = activeHandle === "centre";
857
771
  const centreHovered = hoveredHandle === "centre";
858
- return (
859
- <group ref={rootRef} position={[object.x, gizmoHeight(object), object.z]} renderOrder={999}>
772
+ return (<>
773
+ <HeldTrail trail={held?.trail ?? null} />
774
+ <group ref={rootRef} position={gizmoOrigin(object, held, new THREE.Vector3()).toArray()} quaternion={gizmoTurn(held, mode) ?? [0, 0, 0, 1]} renderOrder={999}>
860
775
  {AXES.map(({ axis, dir, color }) => {
861
776
  const quat = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
862
777
  // The handle under a drag — and, after release, the last one —
@@ -1033,5 +948,5 @@ export default function ObjectGizmo({ object, objects = [], mode = "move", snap
1033
948
  </>
1034
949
  )}
1035
950
  </group>
1036
- );
951
+ </>);
1037
952
  }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Glow: a record that gives off light of its own, drawn in one pass.
3
+ *
4
+ * There is no post-processing anywhere (the viewport, the shot preview,
5
+ * capture_frame, contact sheets and the video export all render the scene with
6
+ * one gl.render), so a bloom pass would have to be bolted onto every path.
7
+ * Instead a glow is two single-pass parts, both on the default layer:
8
+ * - an emissive colour on every material the record draws, which no stage
9
+ * light can darken, and
10
+ * - an additive, camera-facing halo sprite centred on the record, `halo` ×
11
+ * the record's radius. It writes no depth, casts no shadow and is never
12
+ * raycast, so it cannot occlude, shadow or be picked.
13
+ * Both scale with `gain` (the take's level, times a light's flicker).
14
+ * A glowing record is self-lit, so its meshes cast no shadow while it glows: a
15
+ * practical light placed inside a glowing bulb or flame lights the set instead
16
+ * of being shut in by the bulb's own faces (light-blockers.js).
17
+ *
18
+ * State is kept per group in a WeakMap, never in `userData` (React replaces a
19
+ * group's userData on every render). Removing the glow restores each
20
+ * material's own emissive and drops the halo.
21
+ */
22
+
23
+ import * as THREE from "three";
24
+
25
+ /** Halo brightness per unit of glow intensity. */
26
+ const HALO_GAIN = 0.2;
27
+ /** Radius used for a record with no size of its own (a light, an Empty), metres. */
28
+ const POINT_RADIUS = 0.02;
29
+ const noRaycast = () => {};
30
+ const glowStates = new WeakMap();
31
+
32
+ /** True while the group carries a glow that a later frame may have to remove. */
33
+ export function hasGlow(group) {
34
+ return glowStates.has(group);
35
+ }
36
+
37
+ let haloMap = null;
38
+ /** A white disc whose alpha is a bright core over a long soft tail. */
39
+ function haloTexture() {
40
+ if (haloMap) return haloMap;
41
+ const size = 64;
42
+ const data = new Uint8Array(size * size * 4);
43
+ for (let y = 0; y < size; y += 1) {
44
+ for (let x = 0; x < size; x += 1) {
45
+ const r = Math.hypot(x + 0.5 - size / 2, y + 0.5 - size / 2) / (size / 2);
46
+ const tail = r >= 1 ? 0 : (1 - r) ** 1.6;
47
+ const alpha = Math.min(1, 0.7 * Math.exp(-((r / 0.25) ** 2)) + 0.5 * tail);
48
+ data.set([255, 255, 255, Math.round(alpha * 255)], (y * size + x) * 4);
49
+ }
50
+ }
51
+ haloMap = new THREE.DataTexture(data, size, size);
52
+ haloMap.magFilter = THREE.LinearFilter;
53
+ haloMap.minFilter = THREE.LinearFilter;
54
+ haloMap.needsUpdate = true;
55
+ return haloMap;
56
+ }
57
+
58
+ function makeHalo() {
59
+ const material = new THREE.SpriteMaterial({ map: haloTexture(), blending: THREE.AdditiveBlending, transparent: true, depthWrite: false, fog: false });
60
+ const halo = new THREE.Sprite(material);
61
+ halo.userData.glowHalo = true;
62
+ // Beauty render only: the ink prepass and the depth/normal passes draw with
63
+ // an override material, which would turn the soft halo into a solid quad.
64
+ halo.userData.beautyOnly = true;
65
+ halo.raycast = noRaycast;
66
+ halo.castShadow = false;
67
+ halo.receiveShadow = false;
68
+ halo.renderOrder = 2;
69
+ return halo;
70
+ }
71
+
72
+ /** Each mesh the record draws on the default layer, and each of its lit
73
+ * materials (editor markers and the halo itself are left alone). */
74
+ function forEachGlowMesh(group, visitMesh, visitMaterial) {
75
+ group.traverse((node) => {
76
+ if (!node.isMesh || !node.layers.isEnabled(0)) return;
77
+ visitMesh(node);
78
+ for (const material of Array.isArray(node.material) ? node.material : [node.material]) {
79
+ if (material?.emissive?.isColor) visitMaterial(material);
80
+ }
81
+ });
82
+ }
83
+
84
+ function clearGlow(group, state) {
85
+ for (const [material, base] of state.bases) {
86
+ material.emissive.copy(base.emissive);
87
+ material.emissiveIntensity = base.intensity;
88
+ }
89
+ for (const mesh of state.shadowless) mesh.castShadow = true;
90
+ state.halo.removeFromParent();
91
+ state.halo.material.dispose();
92
+ glowStates.delete(group);
93
+ }
94
+
95
+ /** The record's centre (local) and its radius (world): half its largest
96
+ * extent, so a sphere's radius is exact; a record with no size (a light, an
97
+ * Empty) counts as POINT_RADIUS. Size comes from the record, the same numbers
98
+ * the selection cage and the plan use. */
99
+ function recordSphere(object, scale) {
100
+ const width = (object.footprint?.width ?? 0) * Math.abs(scale.x);
101
+ const height = (object.height ?? 0) * Math.abs(scale.y);
102
+ const depth = (object.footprint?.depth ?? 0) * Math.abs(scale.z);
103
+ const radius = Math.max(width, height, depth) / 2;
104
+ return { centreY: (object.height ?? 0) / 2, radius: radius > 0 ? radius : POINT_RADIUS };
105
+ }
106
+
107
+ /** Apply, update or remove the record's glow for this frame. */
108
+ export function placeObjectGlow(group, object, gain) {
109
+ const glow = object.glow;
110
+ let state = glowStates.get(group);
111
+ if (!glow) {
112
+ if (state) clearGlow(group, state);
113
+ return;
114
+ }
115
+ if (!state) {
116
+ state = { halo: makeHalo(), bases: new Map(), shadowless: new Set() };
117
+ glowStates.set(group, state);
118
+ }
119
+ if (state.halo.parent !== group) group.add(state.halo);
120
+ const strength = glow.intensity * gain;
121
+ forEachGlowMesh(group, (mesh) => {
122
+ // a mesh rebuilt while glowing (a new kind, a loaded file) casts again until this pass
123
+ if (!mesh.castShadow) return;
124
+ mesh.castShadow = false;
125
+ state.shadowless.add(mesh);
126
+ }, (material) => {
127
+ if (!state.bases.has(material)) state.bases.set(material, { emissive: material.emissive.clone(), intensity: material.emissiveIntensity });
128
+ material.emissive.set(glow.color);
129
+ material.emissiveIntensity = strength;
130
+ });
131
+ const { centreY, radius } = recordSphere(object, group.scale);
132
+ const size = 2 * radius * glow.halo * gain;
133
+ const halo = state.halo;
134
+ halo.visible = size > 0 && strength > 0;
135
+ halo.position.set(0, centreY, 0);
136
+ // The sprite inherits the record's scale; divide it out so the halo stays round.
137
+ halo.scale.set(size / (Math.abs(group.scale.x) || 1), size / (Math.abs(group.scale.y) || 1), 1);
138
+ halo.material.color.set(glow.color).multiplyScalar(HALO_GAIN * strength);
139
+ }
@@ -0,0 +1,33 @@
1
+ // Effective visibility of a scene record through its parents and its carrying
2
+ // character. Pure and dependency-free, so the renderers, the agent commands and
3
+ // the effects can share it; scene-objects.js re-exports it.
4
+
5
+ /** True when this record, a parent above it, or a character carrying any of
6
+ * those records is hidden. A cycle in parent links ends the walk. When the
7
+ * id is in `objects`, that stored record is what the walk reads, so a display
8
+ * copy cannot disagree with the authored flag. Nothing in the lists is changed. */
9
+ export function isEffectivelyHidden(entity, objects = [], characters = []) {
10
+ if (!entity || typeof entity !== "object") return false;
11
+ const byId = new Map();
12
+ for (const object of objects) {
13
+ if (object && typeof object.id === "string") byId.set(object.id, object);
14
+ }
15
+ const characterHidden = (id) => characters.some((item) => item && typeof item === "object" && item.id === id && item.hidden === true);
16
+ const seen = new Set();
17
+ let current = entity;
18
+ while (current && typeof current === "object") {
19
+ const id = typeof current.id === "string" ? current.id : null;
20
+ if (id) {
21
+ if (seen.has(id)) break;
22
+ seen.add(id);
23
+ if (byId.has(id)) current = byId.get(id);
24
+ }
25
+ if (current.hidden === true) return true;
26
+ const characterId = current.attach && typeof current.attach.characterId === "string" ? current.attach.characterId : null;
27
+ if (characterId && characterHidden(characterId)) return true;
28
+ const parentId = typeof current.parent === "string" ? current.parent : null;
29
+ if (!parentId) break;
30
+ current = byId.get(parentId) ?? null;
31
+ }
32
+ return false;
33
+ }