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
@@ -1,48 +1,18 @@
1
- import { useEffect } from "react";
2
1
  import Foldout from "./Foldout.jsx";
3
- import { useStudioShell } from "../shell/studio-shell-context.js";
4
- import { useMotionCommands } from "../domains/motion.js";
5
2
  import { ko, isKo } from "../locale.js";
6
- import { HIERARCHY_INSPECTOR_TITLES, lineTrackLabel } from "../app-stage.jsx";
7
- import { PhysicsPanel } from "../ardy/physics-panel.jsx";
8
- import { Field } from "../ui.jsx";
9
- import { MotionReadiness } from "../motion-readiness-ui.jsx";
3
+ import { HIERARCHY_INSPECTOR_TITLES } from "../app-stage.jsx";
10
4
  import { RangePinPanel } from "../range-pin-panel.jsx";
11
- import { TRAIL_TRACKS } from "../motion-trail.js";
12
- import { PlatformFitPanel } from "../ardy/platform-fit-panel.jsx";
13
- import "../ardy/auto-fix-panel.css";
5
+
14
6
  import "./pose.css";
15
7
 
16
8
  export default function RigControlPanel({
17
9
  isRigSelection, rigSelection, ikChains, ikFocus, footSnap, ikMode, poseObjectOpacity = 0.2, setPoseObjectOpacity,
18
- collisionCleanupSupported, motion, autoPhysicsRunning, physicsProgress, physicsPreview,
19
- physicsShow, physicsOptions, tlFrame, changePhysicsOptions, runAutoPhysics, showPhysicsPreview,
20
- applyPhysicsPreview, cancelPhysicsPreview, setTlFrame, platformFitRunning, platformFitProgress,
21
- platformFitLast, platformFitApplied, ikEditTool, setIkEditTool, showTrails, setShowTrails,
22
- trailFalloffS, setTrailFalloffS, trailEdit, trailTrackFocus = null, selectTrailTrack, clearTrailTrackFocus, pendingIkEdit = null, applyPendingIkEdit, cancelPendingIkEdit, generationBusy, bridgeChecking, bridge,
23
- runTrailRegeneration, trailReadinessState, openMotionSetup, recheckMotionHealth,
10
+ motion, tlFrame, ikEditTool, setIkEditTool, pendingIkEdit = null, applyPendingIkEdit, cancelPendingIkEdit,
24
11
  rangePins = [], rangePinResiduals = new Map(), rangePinSelection = null, rangePinPartPick = null,
25
12
  rangePinPreview = null, objects = [], setRangePinSelection, setRangePinPartPick,
26
13
  previewRangePinDraft, applyRangePinDraft, deleteRangePin,
27
14
  }) {
28
- const { run } = useMotionCommands();
29
- const shell = useStudioShell();
30
- useEffect(() => {
31
- const preview = platformFitLast && !platformFitApplied && platformFitLast.candidate;
32
- const physics = physicsPreview && !preview;
33
- if (preview) {
34
- shell?.setStatusText?.(ko("Platform fit preview — review before applying", "발판 맞춤 미리보기 — 적용 전에 확인하세요"));
35
- const next = (platformFitLast.steps ?? []).map((step) => ({ start: step.start, end: step.end, kind: "body" }));
36
- shell?.setPreviewRanges?.((current) => JSON.stringify(current) === JSON.stringify(next) ? current : next);
37
- } else if (physics) {
38
- shell?.setStatusText?.(ko("Physics cleanup preview — review before applying", "물리 정리 미리보기 — 적용 전에 확인하세요"));
39
- const next = (physicsPreview.changedFrames ?? []).map((frame) => ({ start: frame, end: frame, kind: "body" }));
40
- shell?.setPreviewRanges?.((current) => JSON.stringify(current) === JSON.stringify(next) ? current : next);
41
- } else if (!platformFitRunning) {
42
- shell?.setStatusText?.(""); shell?.setPreviewRanges?.((current) => current.length ? [] : current);
43
- }
44
- }, [platformFitLast, platformFitApplied, platformFitRunning, physicsPreview, shell]);
45
- const activeTool = ikEditTool === "trail" ? "Path fix" : ikEditTool === "pin" ? "Pin" : "IK";
15
+ const activeTool = ikEditTool === "pin" ? "Pin" : "IK";
46
16
  return <Foldout hidden={!isRigSelection} title={ko("Pose", "포즈")}>
47
17
  <div className="pose-details" data-testid="pose-details">
48
18
  <section className="pose-section">
@@ -60,10 +30,9 @@ export default function RigControlPanel({
60
30
  <p className="inspector-hint">{rigSelection && rigSelection.token !== "rig" ? (isKo ? `${HIERARCHY_INSPECTOR_TITLES[rigSelection.token]}이 활성 제어 그룹입니다.` : `${HIERARCHY_INSPECTOR_TITLES[rigSelection.token]} is the active control group.`) : ko("Select a body group to pose it in the viewport.", "몸 그룹을 선택해 뷰포트에서 포즈를 잡으세요.")}</p>
61
31
  </section>
62
32
  {ikMode && <section className="pose-section" data-testid="pose-active-tool">
63
- <h4>{ko("Active tool", "활성 도구")} · {ko(activeTool, activeTool === "Path fix" ? "경로 수정" : activeTool === "Pin" ? "고정" : "IK")}</h4>
33
+ <h4>{ko("Active tool", "활성 도구")} · {ko(activeTool, activeTool === "Pin" ? "고정" : "IK")}</h4>
64
34
  <div className="pose-actions">
65
35
  <button type="button" className={"btn" + (ikEditTool === "ik" ? " primary" : "")} aria-pressed={ikEditTool === "ik"} onClick={() => setIkEditTool("ik")}>{ko("IK", "IK")}</button>
66
- <button type="button" className={"btn" + (ikEditTool === "trail" ? " primary" : "")} aria-pressed={ikEditTool === "trail"} disabled={!showTrails} onClick={() => setIkEditTool("trail")}>{ko("Path fix", "경로 수정")}</button>
67
36
  <button type="button" data-testid="range-pin-tool" className={"btn" + (ikEditTool === "pin" ? " primary" : "")} aria-pressed={ikEditTool === "pin"} disabled={!motion} onClick={() => { setIkEditTool("pin"); setRangePinPartPick?.(null); }}>{ko("Pin", "고정")}</button>
68
37
  </div>
69
38
  {pendingIkEdit && <div className="pose-section" data-testid="ik-pending-edit">
@@ -75,25 +44,8 @@ export default function RigControlPanel({
75
44
  </div>
76
45
  </div>}
77
46
  {ikEditTool === "pin" && <RangePinPanel active motion={motion} frame={tlFrame} frameCount={motion?.frames ?? 1} fps={motion?.fps ?? 24} pins={rangePins} residuals={rangePinResiduals} objects={objects} selectedPinId={rangePinSelection} partPick={rangePinPartPick} conflictFrames={rangePinPreview?.conflictFrames ?? []} overlapError={rangePinPreview?.overlapError ?? ""} onSelectPin={(id) => { setRangePinSelection?.(id); if (id) setIkEditTool("pin"); }} onApply={applyRangePinDraft} onCancel={() => { setRangePinSelection?.(null); setIkEditTool("ik"); }} onDelete={deleteRangePin} onPreviewTarget={previewRangePinDraft} />}
78
- {ikEditTool === "trail" && <>
79
- <button type="button" className="btn full" aria-pressed={showTrails} onClick={() => setShowTrails((value) => !value)}>{ko(`Trails ${showTrails ? "on" : "off"}`, `궤적선 ${showTrails ? "표시" : "숨김"}`)}</button>
80
- <label className="pose-row" data-testid="trail-selection"><span>{ko("Shown line", "표시 라인")}</span><select data-testid="trail-track-select" value={trailTrackFocus ?? ""} onChange={(event) => selectTrailTrack(event.target.value)}>
81
- <option value="" disabled>{ko("All lines", "모든 라인")}</option>
82
- {TRAIL_TRACKS.map((track) => <option key={track.id} value={track.id}>{lineTrackLabel(track.id)}</option>)}
83
- </select></label>
84
- {trailTrackFocus && <button type="button" className="btn full" data-testid="trail-show-all" onClick={clearTrailTrackFocus}>{ko("Show all lines", "모든 라인 보기")}</button>}
85
- <Field label={ko("Falloff", "영향 범위")}><div className="trail-falloff-row"><input type="range" min={0.1} max={2} step={0.1} value={trailFalloffS} onChange={(event) => setTrailFalloffS(Number(event.target.value))} /><span className="trail-falloff-value">{trailFalloffS.toFixed(1)}s</span></div></Field>
86
- <button type="button" className="btn primary full" disabled={!trailEdit || !motion?.url || generationBusy || bridgeChecking || bridge === null} onClick={runTrailRegeneration}>{ko("Regenerate", "재생성")}</button>
87
- <MotionReadiness state={trailReadinessState} checking={bridgeChecking} onSetup={() => openMotionSetup("trail")} onRetry={recheckMotionHealth} />
88
- </>}
89
47
  {ikEditTool === "ik" && <p className="inspector-hint">{ko("Grab a hand, foot, elbow or knee handle in the viewport.", "뷰포트에서 손·발·팔꿈치·무릎 핸들을 잡으세요.")}</p>}
90
48
  </section>}
91
- <section className="pose-section" data-testid="pose-auto-fix">
92
- <h4>{ko("Auto-fix", "자동 수정")}</h4>
93
- {collisionCleanupSupported && <div className="pose-actions"><button type="button" className="btn" disabled={!ikChains} onClick={() => run("motion.fixCollisions", { scope: "frame" })}>{ko("Body collisions · Frame", "신체 충돌 · 프레임")}</button><button type="button" className="btn" disabled={!ikChains || !motion} onClick={() => run("motion.fixCollisions", { scope: "clip" })}>{ko("Body collisions · Clip", "신체 충돌 · 클립")}</button></div>}
94
- <PlatformFitPanel ko={ko} disabled={!ikChains || !motion || autoPhysicsRunning} running={platformFitRunning} progress={platformFitProgress} last={platformFitLast} applied={platformFitApplied} onRun={() => run("motion.platformFit.run", { preview: true })} onApply={() => run("motion.platformFit.remove", { apply: true })} onCancel={() => run("motion.platformFit.remove")} onRemove={() => run("motion.platformFit.remove")} onFrame={setTlFrame} />
95
- <PhysicsPanel ko={ko} disabled={!ikChains || !motion} running={autoPhysicsRunning} progress={physicsProgress} preview={physicsPreview} show={physicsShow} options={physicsOptions} frame={tlFrame} frames={motion?.frames ?? 1} onOptions={changePhysicsOptions} onRun={runAutoPhysics} onShow={showPhysicsPreview} onApply={applyPhysicsPreview} onCancel={cancelPhysicsPreview} onFrame={setTlFrame} />
96
- </section>
97
49
  </div>
98
50
  </Foldout>;
99
51
  }
@@ -32,7 +32,10 @@ export default function SubjectBox({ label, onRemove, onPose, posing, color, onC
32
32
  title={isKo ? `${label} 포즈` : `Pose ${label}`}
33
33
  onClick={onPose}
34
34
  >
35
- ⌘
35
+ {/* The Pose mode figure, not a keyboard glyph. */}
36
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
37
+ <path d="M8 2.25a1.5 1.5 0 1 1 0 3 1.5 1.5 0 1 1 0-3z M5 7.25h6 M8 7.25v3.5 M6.25 13.75 8 10.75l1.75 3" />
38
+ </svg>
36
39
  </button>
37
40
  )}
38
41
  {onRemove && (
@@ -135,6 +135,20 @@
135
135
  line-height: var(--details-hint-line-height, 1.4);
136
136
  }
137
137
 
138
+ /* The follow-cam pointer is a plain hint here, not the dark theme's tinted box. */
139
+ .v2-details-section.v2-details-section .camera-editor-pointer {
140
+ padding: 0;
141
+ border: 0;
142
+ background: none;
143
+ }
144
+
145
+ /* Each camera readout number carries its name. */
146
+ .v2-details-section.v2-details-section .v2-details-readout small {
147
+ color: var(--text-3, #636369);
148
+ font-family: var(--sans);
149
+ font-size: 10px;
150
+ }
151
+
138
152
  .v2-details-section.v2-details-section .inspector-hint + .inspector-hint,
139
153
  .v2-details-section.v2-details-section .hint + .hint {
140
154
  margin-top: var(--details-gap, 4px);
@@ -4,7 +4,7 @@ import { Html, Line } from "@react-three/drei";
4
4
  import * as THREE from "three";
5
5
  import { POSE_BONES, normalizeBoneName, primeBindPose } from "./poses.js";
6
6
  import { poseThumbnail, warmThumbnailModels } from "./pose-thumbs.js";
7
- import { IK_TRACKS, MID_TRACKS, ikControlIsExposed } from "./ardy/ik.js";
7
+ import { IK_TRACKS, MID_TRACKS, ikControlIsExposed } from "./motion/ik.js";
8
8
  import { shouldRefreshIkExposure } from "./use-render-activity.js";
9
9
  import { POSER_LAYER } from "./dualview.jsx";
10
10
  import { ko, isKo } from "./locale.js";
@@ -1250,7 +1250,7 @@ export function warmPoseThumbnails() {
1250
1250
  warmThumbnailModels(["y-bot-tpose", "x-bot-tpose"]);
1251
1251
  }
1252
1252
 
1253
- export function PoseStudioPanel({ subject, model, poses, selectedId, onSelect, onApply, onReset, onSave, onDelete, onClose, closing, motionActive = false, ikCorrection = false, docked = false, onPhoto, photoState = "idle", photoError = "" }) {
1253
+ export function PoseStudioPanel({ subject, model, poses, selectedId, onSelect, onApply, onReset, onSave, onDelete, onClose, closing, motionActive = false, ikCorrection = false, docked = false }) {
1254
1254
  const poseLabelsKo = {
1255
1255
  "T-pose": ko("T-pose", "T 포즈"),
1256
1256
  Relaxed: ko("Relaxed", "편안한 자세"),
@@ -1333,8 +1333,8 @@ export function PoseStudioPanel({ subject, model, poses, selectedId, onSelect, o
1333
1333
  {poses.length === 0 && (
1334
1334
  <p className="studio-hint" data-pose-empty role="status">
1335
1335
  {ko(
1336
- "Your pose library is empty. Read a pose out of a photograph, or pose the character and save it — both stay here for every project.",
1337
- "포즈 라이브러리가 비어 있어요. 사진에서 자세를 읽어오거나 캐릭터 자세를 잡아 저장하면, 모든 프로젝트에서 계속 쓸 수 있어요.",
1336
+ "Your pose library is empty. Pose the character and save it — it stays here for every project.",
1337
+ "포즈 라이브러리가 비어 있어요. 캐릭터 자세를 잡아 저장하면, 모든 프로젝트에서 계속 쓸 수 있어요.",
1338
1338
  )}
1339
1339
  </p>
1340
1340
  )}
@@ -1345,14 +1345,9 @@ export function PoseStudioPanel({ subject, model, poses, selectedId, onSelect, o
1345
1345
  onSelect={selectPose}
1346
1346
  onDelete={onDelete}
1347
1347
  onSave={onSave}
1348
- onPhoto={onPhoto}
1349
- photoState={photoState}
1350
1348
  categoryOf={poseCategory}
1351
1349
  labelOf={displayPoseLabel}
1352
1350
  />
1353
- {photoError && (
1354
- <p className="studio-hint error" data-pose-photo-error role="status">{photoError}</p>
1355
- )}
1356
1351
  </div>
1357
1352
  );
1358
1353
  }
@@ -1372,8 +1367,6 @@ export function PoseTileGrid({
1372
1367
  onSelect,
1373
1368
  onDelete,
1374
1369
  onSave,
1375
- onPhoto,
1376
- photoState = "idle",
1377
1370
  categoryOf = () => "custom",
1378
1371
  labelOf = (pose) => pose.label,
1379
1372
  }) {
@@ -1411,22 +1404,6 @@ export function PoseTileGrid({
1411
1404
  <span className="add-text">{ko("Save pose", "포즈 저장")}</span>
1412
1405
  </button>
1413
1406
  )}
1414
- {onPhoto && (
1415
- <button
1416
- type="button"
1417
- className={"pose-tile add photo" + (photoState === "running" ? " busy" : "")}
1418
- data-pose-id="photo-pose"
1419
- data-photo-state={photoState}
1420
- disabled={photoState === "running"}
1421
- title={ko("Read the pose out of a reference photograph", "참조 사진에서 자세 읽어오기")}
1422
- onClick={onPhoto}
1423
- >
1424
- <span className="add-plus">{photoState === "running" ? "◌" : "◳"}</span>
1425
- <span className="add-text">
1426
- {photoState === "running" ? ko("Reading…", "읽는 중…") : ko("From photo", "사진에서")}
1427
- </span>
1428
- </button>
1429
- )}
1430
1407
  </div>
1431
1408
  );
1432
1409
  }
@@ -200,7 +200,8 @@ export default function ProjectBrowser({ currentName, onOpen, onOpenFile, onNew,
200
200
 
201
201
  const selectTemplate = (template) => {
202
202
  setSelectedTemplateId(template.id);
203
- setName((current) => current.trim() ? current : template.name);
203
+ // A name the previous card (or the open project) filled in follows the new card; a typed one stays.
204
+ setName((current) => !current.trim() || current.trim() === selectedTemplate?.name || current.trim() === currentName ? template.name : current);
204
205
  };
205
206
 
206
207
  const choosePrevisMode = (mode) => {
@@ -364,9 +365,7 @@ export default function ProjectBrowser({ currentName, onOpen, onOpenFile, onNew,
364
365
  </main>
365
366
 
366
367
  <aside className="v2-start-preview" data-testid="start-project-preview" aria-label={ko("Project preview", "프로젝트 미리보기")}>
367
- <div className={`v2-start-preview-art ${selectedTemplate?.kind || "blank"}`} aria-hidden="true">
368
- <span>{ko("template preview", "템플릿 미리보기")}</span>
369
- </div>
368
+ <div className={`v2-start-preview-art ${selectedTemplate?.kind || "blank"}`} aria-hidden="true" />
370
369
  <div className="v2-start-preview-copy">
371
370
  <strong>{selectedTemplate?.name}</strong>
372
371
  <span>{selectedTemplate?.description}</span>
@@ -2,16 +2,17 @@
2
2
  * Project resource manifest: everything a project points at, and whether the
3
3
  * bytes are here.
4
4
  *
5
- * A `.cclayproject` is only portable when every picture, motion clip, pose
6
- * and workflow output it names travels with it. This module answers "which
5
+ * A `.cclayproject` is only portable when every picture, mesh, pose and
6
+ * workflow output it names travels with it (a compiled take is its motion
7
+ * spec inside the scene document, so it always travels). This module answers "which
7
8
  * ones do, which ones live on a server, and which ones are gone" from the
8
9
  * documents already in memory. It is a runtime calculation: nothing here is
9
10
  * written to the file, and nothing here decodes or hashes bytes.
10
11
  *
11
12
  * Statuses:
12
- * embedded — the record is in `assets` / `motions` / `poseLibrary`, or the
13
- * workflow output is a data: URL that will be interned on save.
14
- * external — reachable by URL only (a bridge take, an http(s) output).
13
+ * embedded — the record is in `assets` / `poseLibrary`, or the workflow
14
+ * output is a data: URL that will be interned on save.
15
+ * external — reachable by URL only (an http(s) output).
15
16
  * missing — nothing to load. An image that the browser still holds in
16
17
  * IndexedDB is flagged `stored: true` so the integrator can
17
18
  * offer to embed it instead of reporting it lost.
@@ -20,6 +21,7 @@
20
21
  * library entry or a garbage id produce fewer items, never a throw.
21
22
  */
22
23
  import { isImageAssetId, isMeshAssetId } from "./scene-assets.js";
24
+ import { isHdrAssetId } from "./stage-hdr.js";
23
25
 
24
26
  /** Lineage fields on a scene object, in `assetUsageCounts` order: the card's
25
27
  * rendered picture, the photograph it was cut from, and the selection mask. */
@@ -111,9 +113,8 @@ function charactersOf(scene) {
111
113
 
112
114
  /**
113
115
  * One item per (kind, id). A second sighting of the same resource only adds
114
- * a ref — unless it resolves BETTER (a character that carries a url for a
115
- * motion another character names by id alone), in which case the status is
116
- * upgraded so the manifest is not order-dependent.
116
+ * a ref — unless it resolves BETTER, in which case the status is upgraded so
117
+ * the manifest is not order-dependent.
117
118
  */
118
119
  function collector(kind) {
119
120
  const items = new Map();
@@ -144,12 +145,7 @@ function resolveImage(id, assetsById, storedIds) {
144
145
  return { status: "missing", stored };
145
146
  }
146
147
 
147
- function resolveMotion(motionId, url, motionsById) {
148
- const record = motionId ? motionsById.get(motionId) : null;
149
- if (record) return { status: "embedded", stored: record.stored === true, bytes: byteSize(record.bytes) ?? byteSize(record.data) };
150
- if (url) return { status: "external", url };
151
- return { status: "missing" };
152
- }
148
+
153
149
 
154
150
  function defaultWorkflowOutputRefs() {
155
151
  return [];
@@ -168,20 +164,20 @@ export function resourceManifest(options) {
168
164
  scenesDocument,
169
165
  workflow,
170
166
  poseLibrary,
171
- assets,
172
- motions,
167
+ assets,
173
168
  storedAssetIds,
174
169
  workflowOutputRefs,
175
170
  } = plainObject(options) ? options : {};
176
171
 
177
172
  const assetsById = recordsById(assets, "id");
178
- const motionsById = recordsById(motions, "motionId");
173
+
179
174
  const storedIds = idSet(storedAssetIds);
180
175
  const scenes = scenesOf(scenesDocument);
181
176
 
182
177
  const images = collector("image");
183
178
  const meshes = collector("mesh");
184
- const motionItems = collector("motion");
179
+ const environments = collector("environment");
180
+
185
181
  const poses = collector("pose");
186
182
  const outputs = collector("workflow-output");
187
183
 
@@ -202,19 +198,10 @@ export function resourceManifest(options) {
202
198
  }
203
199
  }
204
200
 
205
- /* ---- motions: motionId (embedded) → url (external) → missing ---- */
201
+ /* ---- environments: a scene look's HDR file (stage.lighting.hdr) ---- */
206
202
  for (const scene of scenes) {
207
- const sceneId = nonEmptyString(scene?.id) ?? undefined;
208
- for (const character of charactersOf(scene)) {
209
- const ref = character?.motionRef;
210
- if (!plainObject(ref)) continue;
211
- const motionId = nonEmptyString(ref.motionId);
212
- const url = nonEmptyString(ref.url);
213
- const id = motionId ?? url;
214
- if (!id) continue;
215
- const characterId = nonEmptyString(character.id) ?? undefined;
216
- motionItems.note(id, resolveMotion(motionId, url, motionsById), { sceneId, characterId, field: "motionRef" });
217
- }
203
+ const id = scene?.stage?.lighting?.hdr;
204
+ if (isHdrAssetId(id)) environments.note(id, resolveImage(id, assetsById, storedIds), { sceneId: nonEmptyString(scene?.id) ?? undefined, field: "stage.lighting.hdr" });
218
205
  }
219
206
 
220
207
  /* ---- poses: the library is embedded; a character wearing one is a ref ---- */
@@ -276,7 +263,7 @@ export function resourceManifest(options) {
276
263
  }
277
264
  }
278
265
 
279
- const items = [...images.items.values(), ...meshes.items.values(), ...motionItems.items.values(), ...poses.items.values(), ...outputs.items.values()];
266
+ const items = [...images.items.values(), ...meshes.items.values(), ...environments.items.values(), ...poses.items.values(), ...outputs.items.values()];
280
267
  const totals = { embedded: 0, external: 0, missing: 0, bytes: 0 };
281
268
  for (const item of items) {
282
269
  totals[item.status] += 1;
package/src/project.js CHANGED
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * A project is ONE file (`.cclayproject`, JSON) holding the full authoring
5
5
  * state: the scene document (scenes + cast + animation layers), the
6
- * workspace layout, the custom pose library, the workflow graph, and the
7
- * embedded resources (images + motions) the scenes point at. Editor
6
+ * workspace layout, the custom pose library, the workflow graph, and the
7
+ * embedded resources (images and meshes) the scenes point at. A compiled
8
+ * take travels inside the scene document as its motion spec. Editor
8
9
  * preferences (theme, locale) deliberately stay OUT — they belong to the
9
10
  * operator, not the project.
10
11
  *
@@ -16,7 +17,7 @@
16
17
 
17
18
  import { SCENES_VERSION } from "./scenes.js";
18
19
  import { ASSET_MAX_SOURCE_BYTES, assetIdForBytes, isAssetId, isImageAssetId, isMeshAssetId, meshIdForBytes, normalizeAsset, referencedAssetIds } from "./scene-assets.js";
19
- import { ko } from "./locale.js";
20
+ import { ko } from "./locale.js"; import { hdrIdForBytes, isHdrAssetId } from "./stage-hdr.js";
20
21
 
21
22
  export const PROJECT_VERSION = 5;
22
23
  // A project is authored either as a storyboard (stills) or as animation
@@ -36,10 +37,8 @@ const IDB_KEY = "lastProjectHandle";
36
37
 
37
38
  // Embedded resources are bounded: the file is JSON, so every raw byte costs
38
39
  // 4/3 on disk and the whole file has to fit in one string on the way in.
39
- export const MOTION_MAX_BYTES = 192 * 1024 * 1024;
40
40
  export const PROJECT_MAX_RESOURCE_BYTES = 256 * 1024 * 1024;
41
- // A motion id is the SHA-256 of the raw NPZ bytes (see motion-resources.js).
42
- const MOTION_ID_PATTERN = /^[0-9a-f]{64}$/i;
41
+
43
42
 
44
43
  function plainRecord(value) {
45
44
  if (!value || typeof value !== "object") return false;
@@ -245,49 +244,12 @@ function workflowAssetIds(workflow) {
245
244
  return ids;
246
245
  }
247
246
 
248
- /** The optional motion fields carried verbatim; frames/fps come from the
249
- * encoder (motion-resources.js), never from decoding the NPZ here. */
250
- function motionDetails(record) {
251
- return {
252
- ...(Number.isInteger(record.frames) && record.frames >= 0 ? { frames: record.frames } : {}),
253
- ...(Number.isFinite(record.fps) && record.fps > 0 ? { fps: record.fps } : {}),
254
- ...(typeof record.name === "string" && record.name.trim() ? { name: record.name } : {}),
255
- ...(plainRecord(record.meta) ? { meta: jsonValue(record.meta) } : {}),
256
- };
257
- }
258
-
259
- function motionId(value) {
260
- return typeof value === "string" && MOTION_ID_PATTERN.test(value) ? value.toLowerCase() : null;
261
- }
262
-
263
- /**
264
- * Validate a motion record for embedding. Accepts the encoded shape
265
- * (`encoding: "base64"`, `data`) and raw `bytes` (ArrayBuffer or view); the
266
- * payload is encoded later, once the size budget is known to hold.
267
- */
268
- function embeddedMotion(record) {
269
- if (!record || typeof record !== "object") return null;
270
- const id = motionId(record.motionId);
271
- if (!id) return null;
272
- const raw = asArrayBuffer(record.bytes);
273
- if (raw) {
274
- if (!raw.byteLength) return null;
275
- if (raw.byteLength > MOTION_MAX_BYTES) throw resourcesTooLarge(raw.byteLength, MOTION_MAX_BYTES, `Motion ${id}`);
276
- return { motionId: id, bytes: raw.byteLength, raw, details: motionDetails(record) };
277
- }
278
- if (record.encoding !== "base64") return null;
279
- const shape = base64Shape(record.data, MOTION_MAX_BYTES);
280
- if (shape.code === "too-large") throw resourcesTooLarge((record.data.length / 4) * 3, MOTION_MAX_BYTES, `Motion ${id}`);
281
- if (shape.code || (record.bytes !== undefined && record.bytes !== shape.bytes)) return null;
282
- return { motionId: id, bytes: shape.bytes, data: record.data, details: motionDetails(record) };
283
- }
284
-
285
247
  /** Verify that an embedded record still belongs at its content-addressed id. */
286
248
  export async function verifyEmbeddedAsset(record, subtle) {
287
249
  const bytes = asArrayBuffer(record?.bytes);
288
250
  if (!bytes) return false;
289
251
  try {
290
- const expected = isMeshAssetId(record.id) ? await meshIdForBytes(bytes, subtle) : await assetIdForBytes(bytes, subtle);
252
+ const expected = isHdrAssetId(record.id) ? await hdrIdForBytes(bytes, subtle) : isMeshAssetId(record.id) ? await meshIdForBytes(bytes, subtle) : await assetIdForBytes(bytes, subtle);
291
253
  return expected === record.id;
292
254
  } catch {
293
255
  return false;
@@ -334,49 +296,12 @@ function readEmbeddedAssets(value, report) {
334
296
  return assets;
335
297
  }
336
298
 
337
- /** Motion records are returned in their encoded shape; decoding and hash
338
- * verification belong to motion-resources.js. */
339
- function readEmbeddedMotions(value, report) {
340
- const motions = [];
341
- if (!Array.isArray(value)) return motions;
342
- const seen = new Set();
343
- for (const entry of value) {
344
- const id = motionId(entry?.motionId);
345
- if (!id) {
346
- report("motion", typeof entry?.motionId === "string" ? entry.motionId : null, "bad-id");
347
- continue;
348
- }
349
- if (seen.has(id)) {
350
- report("motion", id, "duplicate");
351
- continue;
352
- }
353
- if (entry.encoding !== "base64") {
354
- report("motion", id, "bad-encoding");
355
- continue;
356
- }
357
- const shape = base64Shape(entry.data, MOTION_MAX_BYTES);
358
- if (shape.code) {
359
- report("motion", id, shape.code);
360
- continue;
361
- }
362
- if (entry.bytes !== shape.bytes) {
363
- report("motion", id, "length-mismatch");
364
- continue;
365
- }
366
- seen.add(id);
367
- motions.push({ motionId: id, encoding: "base64", data: entry.data, bytes: shape.bytes, ...motionDetails(entry) });
368
- }
369
- return motions;
370
- }
371
-
372
299
  /**
373
300
  * Build the v5 envelope. Images are embedded when a scene or workflow
374
- * assetRef references them; motions are embedded as given (deduped by
375
- * motionId, first record wins) because the caller already knows which ones
376
- * the project uses. Throws `resources-too-large` when one motion or the whole
301
+ * assetRef references them. Throws `resources-too-large` when the whole
377
302
  * manifest exceeds its budget.
378
303
  */
379
- export function createProjectDocument({ scenesDocument, workspaceLayout, customPoses, name, previsMode, assets, motions, savedAt, workflow }) {
304
+ export function createProjectDocument({ scenesDocument, workspaceLayout, customPoses, name, previsMode, assets, savedAt, workflow }) {
380
305
  const assetRecords = new Map();
381
306
  for (const record of Array.isArray(assets) ? assets : []) {
382
307
  const asset = embeddedAsset(record);
@@ -392,21 +317,7 @@ export function createProjectDocument({ scenesDocument, workspaceLayout, customP
392
317
  embeddedAssets.push(asset.record);
393
318
  resourceBytes += asset.bytes;
394
319
  }
395
- const motionRecords = new Map();
396
- for (const record of Array.isArray(motions) ? motions : []) {
397
- const motion = embeddedMotion(record);
398
- if (!motion || motionRecords.has(motion.motionId)) continue;
399
- motionRecords.set(motion.motionId, motion);
400
- resourceBytes += motion.bytes;
401
- }
402
- if (resourceBytes > PROJECT_MAX_RESOURCE_BYTES) throw resourcesTooLarge(resourceBytes, PROJECT_MAX_RESOURCE_BYTES, "Embedded resources");
403
- const embeddedMotions = [...motionRecords.values()].map(({ motionId: id, bytes, raw, data, details }) => ({
404
- motionId: id,
405
- encoding: "base64",
406
- data: data ?? bytesToBase64(raw),
407
- bytes,
408
- ...details,
409
- }));
320
+ if (resourceBytes > PROJECT_MAX_RESOURCE_BYTES) throw resourcesTooLarge(resourceBytes, PROJECT_MAX_RESOURCE_BYTES, "Embedded resources");
410
321
  return {
411
322
  app: "cozyclay",
412
323
  kind: "project",
@@ -418,7 +329,7 @@ export function createProjectDocument({ scenesDocument, workspaceLayout, customP
418
329
  workspace: workspaceLayout ?? null,
419
330
  poseLibrary: Array.isArray(customPoses) ? customPoses : [],
420
331
  workflow: normalizeWorkflowGraph(workflow),
421
- resources: { assets: embeddedAssets, motions: embeddedMotions },
332
+ resources: { assets: embeddedAssets },
422
333
  };
423
334
  }
424
335
 
@@ -445,8 +356,7 @@ export function buildAnimationProjectFromStoryboard(project) {
445
356
  customPoses: structuredClone(project?.customPoses ?? []),
446
357
  name: `${project?.name || "Untitled"} - ${ko("Animation", "애니메이션")}`,
447
358
  previsMode: "animation",
448
- assets: project?.assets ?? [],
449
- motions: project?.motions ?? [],
359
+ assets: project?.assets ?? [],
450
360
  workflow: structuredClone(project?.workflow ?? createWorkflowGraph()),
451
361
  savedAt: Date.now(),
452
362
  });
@@ -484,7 +394,7 @@ export function readProjectDocument(raw) {
484
394
  };
485
395
  const assetRecords = parsed.version >= 4 ? parsed.resources?.assets : parsed.version >= 2 ? parsed.assets : undefined;
486
396
  const assets = readEmbeddedAssets(assetRecords, report);
487
- const motions = parsed.version >= 4 ? readEmbeddedMotions(parsed.resources?.motions, report) : [];
397
+
488
398
  const workflow = normalizeWorkflowGraph(parsed.workflow);
489
399
  return {
490
400
  ok: true,
@@ -499,8 +409,7 @@ export function readProjectDocument(raw) {
499
409
  customPoses: Array.isArray(parsed.poseLibrary)
500
410
  ? parsed.poseLibrary.filter((p) => p && typeof p === "object" && typeof p.id === "string" && p.bones && typeof p.bones === "object")
501
411
  : [],
502
- assets,
503
- motions,
412
+ assets,
504
413
  workflow,
505
414
  },
506
415
  };