cozyclay 2.1.1 → 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.
- package/CHANGELOG.md +60 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +40 -113
- package/bin/agent/agent-runner.mjs +9 -10
- package/bin/agent/cliproxy-provider.mjs +135 -0
- package/bin/agent/credential-store.mjs +30 -7
- package/bin/agent/pi-tools.mjs +4 -1
- package/bin/agent/provider-keys.mjs +32 -0
- package/bin/agent/provider-login.mjs +110 -0
- package/bin/agent/provider-routes.mjs +99 -0
- package/bin/agent/providers.mjs +19 -97
- package/bin/agent/script-tool.mjs +17 -4
- package/bin/agent/studio-motion-reference.mjs +23 -0
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-rebase-text.mjs +32 -0
- package/bin/agent/studio-rebase.mjs +26 -39
- package/bin/agent/studio-tools.mjs +9 -28
- package/bin/agent/tool-arguments.mjs +49 -0
- package/bin/agent/turn-frames.mjs +66 -0
- package/bin/codex-auth.mjs +9 -2
- package/bin/cozyclay.mjs +10 -116
- package/bin/live/cli.mjs +3 -3
- package/bin/mcp-runtime.mjs +2 -12
- package/bin/package-signature.mjs +0 -4
- package/dist/app/index.html +7 -6
- package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
- package/dist/assets/analytics-C9sUnndd.js +1 -0
- package/dist/assets/app-CCh--1Hc.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
- package/dist/assets/{landing-ChUvB_zL.js → landing-DjHD8u7k.js} +1 -1
- package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-C4yKH1p4.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +3 -3
- package/dist/sw.js +3 -6
- package/dist/workflow/index.html +5 -4
- package/mcp/LIVE-PROTOCOL.md +7 -47
- package/mcp/README.md +16 -26
- package/mcp/live-hub.mjs +6 -10
- package/mcp/package.json +1 -3
- package/mcp/tool-handlers.mjs +4 -168
- package/package.json +3 -22
- package/src/App.jsx +150 -2624
- package/src/agent-progress.js +79 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +5 -0
- package/src/app-stage.jsx +2 -34
- package/src/asset-pane.jsx +6 -5
- package/src/camera-block.js +21 -0
- package/src/camera-direction.js +120 -0
- package/src/character-kind.js +3 -9
- package/src/command-bus.js +8 -6
- package/src/commands/cast.js +5 -34
- package/src/commands/elements/character.js +1 -1
- package/src/commands/elements/motion.js +1 -6
- package/src/commands/elements/object.js +6 -2
- package/src/commands/elements/shot.js +4 -1
- package/src/commands/elements.js +38 -14
- package/src/commands/index.js +3 -1
- package/src/commands/kits.js +37 -0
- package/src/commands/motion-timing.js +57 -0
- package/src/commands/motion.js +9 -152
- package/src/commands/motion3-compile.js +65 -0
- package/src/commands/motion3.js +207 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +49 -11
- package/src/commands/stage.js +14 -1
- package/src/commands/view.js +4 -1
- package/src/document-mirrors.js +42 -0
- package/src/document-store.js +4 -0
- package/src/domains/cast.js +19 -194
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion/take-source.js +51 -0
- package/src/domains/motion.js +60 -1838
- package/src/domains/scenes.js +12 -55
- package/src/domains/shots.js +2 -2
- package/src/domains/stage.js +4 -2
- package/src/draft-ghost.js +46 -0
- package/src/draft-ghost.jsx +129 -0
- package/src/dualview.jsx +4 -3
- package/src/effects/EffectsLayer.jsx +112 -0
- package/src/effects/effect-meshes.js +232 -0
- package/src/effects/effect-record.js +103 -0
- package/src/effects/emitter.js +59 -0
- package/src/effects/simulate.js +261 -0
- package/src/effects/state.js +59 -0
- package/src/execution-telemetry.js +2 -3
- package/src/first-success-guide.jsx +5 -5
- package/src/ghost-set.js +257 -0
- package/src/held-object-edit.jsx +113 -0
- package/src/held-object-pose.js +175 -0
- package/src/hierarchy-model.js +1 -1
- package/src/hierarchy-panel.jsx +1 -1
- package/src/imported-mesh.jsx +103 -0
- package/src/kits/held.js +84 -0
- package/src/kits/index.js +70 -0
- package/src/kits/smoking.js +57 -0
- package/src/light-blockers.js +93 -0
- package/src/motion/beat-board-model.js +84 -0
- package/src/motion/beat-board.css +124 -0
- package/src/motion/beat-board.jsx +59 -0
- package/src/motion/center-of-mass.js +66 -0
- package/src/motion/fix-collisions.js +850 -0
- package/src/motion/physics-review.js +118 -0
- package/src/{ardy → motion}/physics-support.js +1 -76
- package/src/motion/rig-snapshot.js +22 -0
- package/src/motion/take-segments.jsx +140 -0
- package/src/{ardy → motion}/timeline-coordinates.js +0 -21
- package/src/{ardy → motion}/timeline.css +1 -2
- package/src/{ardy → motion}/timeline.jsx +42 -413
- package/src/motion/waypoints.js +76 -0
- package/src/motion3/beats.js +83 -0
- package/src/motion3/body.js +158 -0
- package/src/motion3/bones.js +47 -0
- package/src/motion3/carried.js +47 -0
- package/src/motion3/compile-job.js +75 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +105 -0
- package/src/motion3/compiler/arm-orient.js +128 -0
- package/src/motion3/compiler/channels.js +125 -0
- package/src/motion3/compiler/compile.js +205 -0
- package/src/motion3/compiler/gait-rhythm.js +97 -0
- package/src/motion3/compiler/grip.js +171 -0
- package/src/motion3/compiler/head-steady.js +48 -0
- package/src/motion3/compiler/hold.js +134 -0
- package/src/motion3/compiler/idle.js +113 -0
- package/src/motion3/compiler/limbs.js +170 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +162 -0
- package/src/motion3/compiler/quat.js +49 -0
- package/src/motion3/compiler/skeleton.js +74 -0
- package/src/motion3/compiler/validate-common.js +32 -0
- package/src/motion3/compiler/validate-goals.js +118 -0
- package/src/motion3/compiler/validate-objects.js +143 -0
- package/src/motion3/compiler/validate-parts.js +116 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +73 -0
- package/src/motion3/compiler/walk-pelvis.js +275 -0
- package/src/motion3/compiler/walk.js +207 -0
- package/src/motion3/compiler/wrist-clamp.js +32 -0
- package/src/motion3/delta.js +47 -0
- package/src/motion3/describe.js +174 -0
- package/src/motion3/docs.js +27 -0
- package/src/motion3/edit-carry.js +21 -0
- package/src/motion3/fix/ease.js +16 -0
- package/src/motion3/fix/ground.js +37 -0
- package/src/motion3/fix/index.js +52 -0
- package/src/motion3/fix/push.js +71 -0
- package/src/motion3/fix/reach.js +46 -0
- package/src/motion3/fix/retime.js +79 -0
- package/src/motion3/fix/self.js +211 -0
- package/src/motion3/fix/slide.js +70 -0
- package/src/motion3/fix/turn.js +51 -0
- package/src/motion3/follow.js +39 -0
- package/src/motion3/free-motion.js +173 -0
- package/src/motion3/grip-choice.js +130 -0
- package/src/motion3/hold-plan.js +157 -0
- package/src/motion3/json-patch.js +77 -0
- package/src/motion3/key-aim.js +105 -0
- package/src/motion3/key-edit.js +82 -0
- package/src/motion3/lenient.js +127 -0
- package/src/motion3/object-keys.js +236 -0
- package/src/motion3/object-pose.js +182 -0
- package/src/motion3/object-tracks.js +12 -0
- package/src/motion3/pipeline.js +102 -0
- package/src/motion3/playback.js +51 -0
- package/src/motion3/probes.js +91 -0
- package/src/motion3/qa/body-checks.js +34 -0
- package/src/motion3/qa/check-names.js +14 -0
- package/src/motion3/qa/checks.js +121 -0
- package/src/motion3/qa/contact-checks.js +51 -0
- package/src/motion3/qa/explain.js +80 -0
- package/src/motion3/qa/fmt.js +5 -0
- package/src/motion3/qa/foot-checks.js +72 -0
- package/src/motion3/qa/geometry.js +77 -0
- package/src/motion3/qa/goals.js +191 -0
- package/src/motion3/qa/ground.js +60 -0
- package/src/motion3/qa/hints-contact.js +179 -0
- package/src/motion3/qa/hints-goal.js +160 -0
- package/src/motion3/qa/hints-knee.js +24 -0
- package/src/motion3/qa/hints-motion.js +209 -0
- package/src/motion3/qa/hints-object.js +91 -0
- package/src/motion3/qa/index.js +42 -0
- package/src/motion3/qa/key-checks.js +82 -0
- package/src/motion3/qa/near.js +96 -0
- package/src/motion3/qa/object-checks.js +135 -0
- package/src/motion3/qa/patch.js +161 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +218 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +120 -0
- package/src/motion3/repair-tune.js +121 -0
- package/src/motion3/repair.js +83 -0
- package/src/motion3/report.js +67 -0
- package/src/motion3/rigs/index.js +14 -0
- package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/x-bot-tpose.json +1 -0
- package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/y-bot-tpose.json +1 -0
- package/src/motion3/scene.js +60 -0
- package/src/motion3/schema/brief.js +89 -0
- package/src/motion3/schema/fields.js +44 -0
- package/src/motion3/schema/spec-examples.js +46 -0
- package/src/motion3/schema/topics.js +111 -0
- package/src/motion3/schema/types.js +147 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/skills/basic.js +82 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/index.js +83 -0
- package/src/motion3/skills/info.js +65 -0
- package/src/motion3/skills/smoke-kit.js +109 -0
- package/src/motion3/skills/smoke.js +160 -0
- package/src/motion3/spec-store.js +59 -0
- package/src/motion3/take-edit.js +155 -0
- package/src/motion3/take.js +63 -0
- package/src/motion3/timeline.js +127 -0
- package/src/motion3/views.js +121 -0
- package/src/motion3/walk-plan.js +119 -0
- package/src/object-catalog.jsx +7 -1
- package/src/object-colors.js +98 -0
- package/src/object-gizmo-parts.js +115 -0
- package/src/object-gizmo.jsx +37 -122
- package/src/object-glow.js +139 -0
- package/src/object-hidden.js +33 -0
- package/src/object-look.js +196 -0
- package/src/object-size.js +10 -0
- package/src/object-travel.js +71 -6
- package/src/panels/CameraPanel.jsx +7 -7
- package/src/panels/HdrEnvironmentControls.jsx +59 -0
- package/src/panels/LightPanel.jsx +25 -4
- package/src/panels/ObjectLookPanel.jsx +88 -0
- package/src/panels/PosePanel.jsx +2 -17
- package/src/panels/RigControlPanel.jsx +5 -53
- package/src/panels/SubjectBox.jsx +4 -1
- package/src/panels/details.css +14 -0
- package/src/posestudio.jsx +4 -27
- package/src/project-browser.jsx +3 -4
- package/src/project-resources.js +18 -31
- package/src/project.js +13 -104
- package/src/props.jsx +25 -280
- package/src/rail-dot-drag.js +23 -0
- package/src/render-passes.js +10 -0
- package/src/resource-status.jsx +1 -0
- package/src/result-modal.jsx +4 -19
- package/src/room.jsx +20 -12
- package/src/scene-assets.js +8 -6
- package/src/scene-light-place.js +72 -0
- package/src/scene-lights.jsx +148 -0
- package/src/scene-objects.js +31 -139
- package/src/scenes.js +15 -105
- package/src/semantic-edit.js +2 -5
- package/src/set-pieces.jsx +183 -0
- package/src/settings-menu.jsx +3 -11
- package/src/shell/BottomDock.jsx +9 -51
- package/src/shell/DetailsSlot.jsx +16 -200
- package/src/shell/GhostsMenuGroup.jsx +74 -0
- package/src/shell/LibrarySlot.jsx +1 -3
- package/src/shell/MenuBar.jsx +3 -3
- package/src/shell/PreferencesDialog.jsx +15 -264
- package/src/shell/PreferencesSlot.jsx +2 -8
- package/src/shell/TopBar.jsx +5 -84
- package/src/shell/ViewportToolbar.jsx +10 -70
- package/src/shell/agent-glass.css +19 -6
- package/src/shell/details-selection.js +42 -0
- package/src/shell/ghosts-menu.css +22 -0
- package/src/shell/glass-regions.css +29 -3
- package/src/shell/preferences.css +6 -1
- package/src/shot-authoring.js +4 -7
- package/src/soft-shadows.js +37 -0
- package/src/stage-attach-frames.js +12 -12
- package/src/stage-canvas-rigs.jsx +3 -3
- package/src/stage-capture.jsx +42 -8
- package/src/stage-characters.jsx +22 -216
- package/src/stage-editor-gizmos.jsx +6 -6
- package/src/stage-environment.js +93 -0
- package/src/stage-hdr-builtins.js +107 -0
- package/src/stage-hdr-image.js +116 -0
- package/src/stage-hdr-library.js +70 -0
- package/src/stage-hdr-map.js +94 -0
- package/src/stage-hdr.js +130 -0
- package/src/stage-lighting.js +149 -0
- package/src/stage-occlusion.js +210 -0
- package/src/stage-sky.jsx +159 -0
- package/src/stage-startup-defaults.js +5 -9
- package/src/studio-actions.js +12 -14
- package/src/studio-agent-commands.js +19 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +41 -71
- package/src/studio-app-binding.js +25 -45
- package/src/studio-asset-list.js +17 -0
- package/src/studio-contact-sheet.js +37 -5
- package/src/studio-elements.js +27 -7
- package/src/studio-entity-bounds.js +18 -0
- package/src/studio-error-codes.js +8 -0
- package/src/studio-export-framing.js +152 -0
- package/src/studio-lighting-check.js +103 -0
- package/src/studio-motion-visual.js +150 -0
- package/src/studio-schema-errors.js +80 -0
- package/src/studio-support-gap.js +74 -0
- package/src/styles.css +1 -19
- package/src/timeline-defaults.js +5 -0
- package/src/timeline-extent.js +8 -20
- package/src/tutorial-walk.js +17 -0
- package/src/ui-scrub.js +1 -1
- package/src/use-shot-camera-tracks.js +12 -0
- package/src/view-ghosts.js +97 -0
- package/src/view-ghosts.jsx +49 -0
- package/src/workflow/AgentPanel.jsx +47 -166
- package/src/workflow/AgentProgressCard.jsx +107 -0
- package/src/workflow/AgentReplyText.jsx +37 -0
- package/src/workflow/AgentTurnSteps.jsx +84 -0
- package/src/workflow/LoginPanel.jsx +140 -0
- package/src/workflow/WorkflowBuilder.jsx +7 -23
- package/src/workflow/agent-client.js +54 -51
- package/src/workflow/agent-panel.css +71 -1
- package/src/workflow/agent-progress-card.css +167 -0
- package/src/workflow/agent-progress-view.js +47 -0
- package/src/workflow/agent-turn-steps.css +113 -0
- package/src/workflow/agent-turn.js +191 -0
- package/src/workflow/login-client.js +34 -0
- package/src/workflow/motion-input.js +18 -31
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/reply-markdown.js +69 -0
- package/src/workflow/scene-asset-sync.js +8 -8
- package/tools/agent-session-stats.mjs +61 -0
- package/tools/dev-full.mjs +5 -56
- package/tools/eslint-baseline.json +12 -13
- package/tools/knip-baseline.json +0 -179
- package/tools/loc-baseline.json +31 -81
- package/tools/motion3/extract-body.mjs +103 -0
- package/tools/motion3/extract-rig.mjs +85 -0
- package/tools/process-supervisor.mjs +0 -88
- package/tools/run-tests.mjs +8 -124
- package/bin/agent/motion-runtime.mjs +0 -76
- package/dist/ardy/cskel27-rest.json +0 -557
- package/dist/assets/analytics-C9pMpW7s.js +0 -1
- package/dist/assets/app-B_2XB9rw.css +0 -1
- package/dist/assets/app-DAuvKPP8.js +0 -4920
- package/dist/assets/config-Bx7pYsD9.js +0 -1
- package/dist/assets/config-DeoFTYzb.css +0 -1
- package/dist/assets/demo-CvKuBgy5.js +0 -1
- package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
- package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
- package/dist/assets/ticket-BPk2Ni95.js +0 -1
- package/dist/assets/workflow-jJRBR94Z.js +0 -179
- package/dist/demo/walk-then-stop.npz +0 -0
- package/mcp/ardy-prompts.mjs +0 -218
- package/src/ardy/auto-fix-panel.css +0 -108
- package/src/ardy/auto-physics.js +0 -1194
- package/src/ardy/client.js +0 -153
- package/src/ardy/convert.js +0 -313
- package/src/ardy/cskel27-neutral.js +0 -39
- package/src/ardy/cskel27.js +0 -77
- package/src/ardy/export.js +0 -165
- package/src/ardy/fix-collisions.js +0 -2257
- package/src/ardy/foot-lock.js +0 -230
- package/src/ardy/motion-calibration.js +0 -118
- package/src/ardy/motion-edit.js +0 -213
- package/src/ardy/motion-url.js +0 -55
- package/src/ardy/mp4-duration.js +0 -102
- package/src/ardy/npz.js +0 -595
- package/src/ardy/physics-panel.css +0 -21
- package/src/ardy/physics-panel.jsx +0 -89
- package/src/ardy/physics-refine.js +0 -111
- package/src/ardy/physics-review.js +0 -567
- package/src/ardy/physics-temporal.js +0 -54
- package/src/ardy/platform-fit-panel.css +0 -64
- package/src/ardy/platform-fit-panel.jsx +0 -41
- package/src/ardy/platform-fit.js +0 -326
- package/src/ardy/playback.js +0 -711
- package/src/ardy/pose-pin.js +0 -97
- package/src/ardy/prompt-clips.js +0 -30
- package/src/ardy/retime.js +0 -211
- package/src/ardy/root-drop.js +0 -369
- package/src/ardy/timeline-resize.js +0 -13
- package/src/ardy/to-cskel27.js +0 -225
- package/src/ardy/trim.js +0 -33
- package/src/ardy/waypoints.js +0 -369
- package/src/ardy-bridge-contract.js +0 -281
- package/src/domains/motion/motion-video-capture.js +0 -664
- package/src/i2v-motion-client.js +0 -77
- package/src/i2v-motion-studio.jsx +0 -180
- package/src/line-edit.js +0 -1348
- package/src/motion/generation.js +0 -105
- package/src/motion-readiness-ui.jsx +0 -67
- package/src/motion-readiness.js +0 -40
- package/src/motion-resources.js +0 -177
- package/src/motion-store.js +0 -65
- package/src/motion-trail.js +0 -601
- package/src/multimodel-ingest.js +0 -394
- package/src/panels/PromptBlocksPanel.jsx +0 -444
- package/src/panels/VideoCapturePanel.jsx +0 -181
- package/src/pose-extract/browser.js +0 -42
- package/src/pose-extract/detector.js +0 -100
- package/src/pose-extract/fit.js +0 -227
- package/src/pose-extract/image-frame.js +0 -51
- package/src/pose-extract/index.js +0 -58
- package/src/pose-extract/keyframes.js +0 -74
- package/src/pose-extract/landmarks.js +0 -162
- package/src/pose-extract/mirror.js +0 -153
- package/src/pose-extract/take.js +0 -131
- package/src/pose-extract/video-frames.js +0 -91
- package/src/take-recipe.js +0 -165
- package/src/trail-key-conflicts.js +0 -39
- package/src/trail-pick.js +0 -59
- package/src/use-i2v-capture-modal.js +0 -15
- package/tools/ardy/BRIDGE.md +0 -37
- package/tools/ardy/GVHMR-NPZ.md +0 -68
- package/tools/ardy/README.md +0 -124
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/ardy/artifacts.mjs +0 -34
- package/tools/ardy/bridge.mjs +0 -1732
- package/tools/ardy/bvh-cskel27.mjs +0 -1265
- package/tools/ardy/cclay_constrained_generate.py +0 -561
- package/tools/ardy/cclay_gvhmr_worker.py +0 -264
- package/tools/ardy/cclay_motion_edit.py +0 -510
- package/tools/ardy/cclay_sequence_generate.py +0 -705
- package/tools/ardy/cclay_worker.py +0 -304
- package/tools/ardy/dump-npz.py +0 -205
- package/tools/ardy/extract-rest.mjs +0 -299
- package/tools/ardy/extract.mjs +0 -507
- package/tools/ardy/footage.mjs +0 -467
- package/tools/ardy/gvhmr-floor.mjs +0 -102
- package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
- package/tools/ardy/gvhmr_fastpath.py +0 -168
- package/tools/ardy/gvhmr_trajectory.py +0 -240
- package/tools/ardy/merge-text-encoder.py +0 -160
- package/tools/ardy/mocap-metrics.mjs +0 -200
- package/tools/ardy/mocap-quality-gate.mjs +0 -110
- package/tools/ardy/motion-stabilize.mjs +0 -348
- package/tools/ardy/npz.mjs +0 -414
- package/tools/ardy/pose-to-npz.mjs +0 -106
- package/tools/ardy/prompt-limits.mjs +0 -5
- package/tools/ardy/run-edit-on-box.sh +0 -73
- package/tools/ardy/run-local.mjs +0 -233
- package/tools/ardy/run-on-box.sh +0 -593
- package/tools/ardy/run-sequence-on-box.sh +0 -177
- package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
- package/tools/ardy/runners/index.mjs +0 -18
- package/tools/ardy/runners/local.mjs +0 -455
- package/tools/ardy/runners/proc.mjs +0 -125
- package/tools/ardy/runners/remote.mjs +0 -252
- package/tools/ardy/setup-local.mjs +0 -189
- package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
- package/tools/ardy/setup-text-encoder.py +0 -306
- package/tools/ardy/smpl-cskel27.mjs +0 -178
- package/tools/ardy/visual-qa.mjs +0 -196
- package/tools/ardy/vq-car.mjs +0 -52
- package/tools/bench/EXP3.md +0 -61
- package/tools/bench/cclay_bench_extract_incam.py +0 -125
- package/tools/bench/cclay_bench_extract_obs.py +0 -204
- package/tools/bench/cclay_bench_runner.py +0 -42
- package/tools/bench/cube-contact.mjs +0 -162
- package/tools/bench/exp3.mjs +0 -152
- package/tools/bench/extract-bench-lib.mjs +0 -216
- package/tools/bench/extract-bench.mjs +0 -302
- package/tools/bench/fal-generate.mjs +0 -88
- package/tools/bench/fit/README.md +0 -189
- package/tools/bench/fit/camera.mjs +0 -59
- package/tools/bench/fit/contact.mjs +0 -419
- package/tools/bench/fit/footlock.mjs +0 -234
- package/tools/bench/fit/motion.mjs +0 -85
- package/tools/bench/fit/pin.mjs +0 -27
- package/tools/bench/fit/remote.mjs +0 -105
- package/tools/bench/fit-bench.mjs +0 -126
- package/tools/bench/fit-sanity.mjs +0 -45
- package/tools/bench/metrics.mjs +0 -313
- package/tools/bench/obs/depth.mjs +0 -258
- package/tools/bench/obs/extrinsics.mjs +0 -175
- package/tools/bench/obs/fit_mannequin_betas.py +0 -340
- package/tools/bench/obs/ground.mjs +0 -294
- package/tools/bench/obs/heading.mjs +0 -151
- package/tools/bench/obs/ladder.mjs +0 -555
- package/tools/bench/obs/mannequin-betas.json +0 -124
- package/tools/bench/obs/remote.mjs +0 -83
- package/tools/bench/obs/rest_joints.py +0 -52
- package/tools/bench/obs/ybot-targets.mjs +0 -49
- package/tools/bench/obs-bench.mjs +0 -520
- package/tools/bench/score.mjs +0 -343
- package/tools/bench/summarize.mjs +0 -86
- package/tools/demo-worker/README.md +0 -137
- package/tools/demo-worker/api-client.mjs +0 -233
- package/tools/demo-worker/generate.mjs +0 -301
- package/tools/demo-worker/index.mjs +0 -466
- package/tools/demo-worker/sign-core.mjs +0 -112
- package/tools/demo-worker/sign.mjs +0 -161
- package/tools/gt-render/browser.mjs +0 -182
- package/tools/gt-render/camera-math.mjs +0 -276
- package/tools/gt-render/page.mjs +0 -267
- package/tools/gt-render/render.mjs +0 -514
- package/tools/gt-render/scene-box.mjs +0 -31
- package/tools/gt-render/take-transform.mjs +0 -87
- package/tools/kimodo/compare-seam.mjs +0 -108
- package/tools/kimodo/constraints.mjs +0 -244
- package/tools/kimodo/edit.mjs +0 -259
- package/tools/kimodo/effector-constraints.mjs +0 -200
- package/tools/kimodo/generate.mjs +0 -646
- package/tools/kimodo/local-output.mjs +0 -265
- package/tools/kimodo/measure-pose.mjs +0 -65
- package/tools/kimodo/measure-preserve.mjs +0 -899
- package/tools/kimodo/measure-waypoints.mjs +0 -55
- package/tools/kimodo/mlx-generate.py +0 -111
- package/tools/kimodo/pose-constraints.mjs +0 -248
- package/tools/kimodo/preserve-mask.mjs +0 -543
- package/tools/kimodo/read-npz.mjs +0 -189
- package/tools/kimodo/run-edit-on-box.mjs +0 -155
- package/tools/kimodo/run-sequence-on-box.mjs +0 -178
- package/tools/kimodo/runner.mjs +0 -284
- package/tools/kimodo/seam-batch.mjs +0 -77
- package/tools/kimodo/setup-local.mjs +0 -30
- package/tools/kimodo/setup-on-box.sh +0 -339
- package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
- package/tools/morphgs/assets/gen_truth.py +0 -39
- package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
- package/tools/morphgs/assets/playback-check.mjs +0 -30
- package/tools/morphgs/demo-gate.sh +0 -26
- package/tools/morphgs/fbx2morphgs.mjs +0 -68
- package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
- package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
- package/tools/morphgs/setup-on-cluster.sh +0 -126
- package/tools/projflow/driver.py +0 -1069
- package/tools/projflow/generate.mjs +0 -805
- package/tools/projflow/hml22-to-cskel27.mjs +0 -735
- package/tools/projflow/line-edit-job.mjs +0 -547
- package/tools/projflow/replay.mjs +0 -452
- package/tools/projflow/runner.mjs +0 -269
- package/tools/projflow/service.mjs +0 -742
- package/tools/track/DESIGN.md +0 -513
- package/tools/track/backfill-provenance.mjs +0 -116
- package/tools/track/budget.mjs +0 -8
- package/tools/track/check-rig.mjs +0 -209
- package/tools/track/diagnostics.schema.json +0 -60
- package/tools/track/export-rig.mjs +0 -256
- package/tools/track/fallback.mjs +0 -7
- package/tools/track/fk-parity-fixture.mjs +0 -161
- package/tools/track/gate.mjs +0 -349
- package/tools/track/masks.mjs +0 -318
- package/tools/track/metrics.mjs +0 -201
- package/tools/track/publish-obs.mjs +0 -108
- package/tools/track/py/check_env.py +0 -61
- package/tools/track/py/eval_lr.py +0 -229
- package/tools/track/py/lr_viterbi.py +0 -294
- package/tools/track/py/masks.py +0 -405
- package/tools/track/py/objective.py +0 -382
- package/tools/track/py/rig.py +0 -508
- package/tools/track/py/scene.py +0 -326
- package/tools/track/py/test_joint_indices.py +0 -123
- package/tools/track/py/test_lr_viterbi.py +0 -195
- package/tools/track/py/test_masks.py +0 -229
- package/tools/track/py/test_rig.py +0 -288
- package/tools/track/py/test_scene.py +0 -354
- package/tools/track/py/test_track.py +0 -328
- package/tools/track/py/track.py +0 -411
- package/tools/track/remote.mjs +0 -140
- package/tools/track/rig-dump.mjs +0 -227
- package/tools/track/run-box-tests.mjs +0 -14
- package/tools/track/run-box.mjs +0 -168
- package/tools/track/setup-box.sh +0 -59
- package/tools/track/study-2d.mjs +0 -728
- /package/src/{ardy → motion}/collision-blockers.js +0 -0
- /package/src/{ardy → motion}/ground.js +0 -0
- /package/src/{ardy → motion}/ik-drag.js +0 -0
- /package/src/{ardy → motion}/ik-key-json.js +0 -0
- /package/src/{ardy → motion}/ik.js +0 -0
- /package/src/{ardy → motion}/physics-surface.js +0 -0
- /package/src/{ardy → motion}/playback-clock.js +0 -0
- /package/src/{ardy → motion}/range-pin.js +0 -0
package/src/scenes.js
CHANGED
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
import { DEFAULT_SENSOR_FORMAT, SENSOR_FORMATS } from "./shot.js";
|
|
6
6
|
import { normalizeStableItems } from "./stable-items.js";
|
|
7
|
-
|
|
8
|
-
import { normalizeTrailEdits } from "./motion-trail.js";
|
|
7
|
+
|
|
9
8
|
import { elementByPath } from "./studio-elements.js";
|
|
10
9
|
import { wrapAngle } from "./scene-objects.js";
|
|
10
|
+
import { normalizeTakeSource } from "./domains/motion/take-source.js";
|
|
11
|
+
import { createKeyLight, normalizeLighting } from "./stage-lighting.js";
|
|
11
12
|
// The timeline clock lives in timeline-fps.js (three-free, so the agent
|
|
12
13
|
// sidecar can import it); re-exported here for every scene-side caller.
|
|
13
14
|
import { LEGACY_FRAME_FPS, TIMELINE_FRAME_FPS, toTimelineFrame } from "./timeline-fps.js";
|
|
14
15
|
|
|
15
16
|
const CHARACTER_POSITION_LIMITS = elementByPath("character.position");
|
|
16
17
|
const CHARACTER_SCALE_LIMITS = elementByPath("character.scale");
|
|
17
|
-
const KEY_LIGHT_LIMITS = Object.fromEntries(["x", "y", "z", "intensity", "warmth"].map((axis) => [axis, elementByPath(`stage.keyLight.${axis}`)]));
|
|
18
18
|
|
|
19
19
|
export const SCENES_VERSION = 5;
|
|
20
20
|
export const SCENES_STORAGE_KEY = "cozyclay.scenes.v5";
|
|
@@ -71,30 +71,8 @@ const DEFAULT_SCENE_STAGE = Object.freeze({
|
|
|
71
71
|
shotAspect: "16:9",
|
|
72
72
|
cameraPresetId: null,
|
|
73
73
|
sensorId: DEFAULT_SENSOR_FORMAT,
|
|
74
|
-
// The key light the user can grab: position of the sun puck, the rig's
|
|
75
|
-
// master brightness, and a warm/cool colour offset. Values mirror the
|
|
76
|
-
// tuned StageLights defaults, so a stage saved before the light was
|
|
77
|
-
// movable renders exactly as it did.
|
|
78
|
-
keyLight: Object.freeze({ x: 6, y: 9, z: 4, intensity: 1.12, warmth: 0.5 }),
|
|
79
74
|
});
|
|
80
75
|
|
|
81
|
-
/** Clamp a stored key light back into the stage's usable envelope. */
|
|
82
|
-
export function createKeyLight(value) {
|
|
83
|
-
const source = plainObject(value) ? value : {};
|
|
84
|
-
const fallback = DEFAULT_SCENE_STAGE.keyLight;
|
|
85
|
-
const finite = (entry, base, bounds) => (typeof entry === "number" && Number.isFinite(entry)
|
|
86
|
-
? Math.max(bounds.min, Math.min(bounds.max, entry))
|
|
87
|
-
: base);
|
|
88
|
-
return {
|
|
89
|
-
x: finite(source.x, fallback.x, KEY_LIGHT_LIMITS.x),
|
|
90
|
-
y: finite(source.y, fallback.y, KEY_LIGHT_LIMITS.y),
|
|
91
|
-
z: finite(source.z, fallback.z, KEY_LIGHT_LIMITS.z),
|
|
92
|
-
intensity: finite(source.intensity, fallback.intensity, KEY_LIGHT_LIMITS.intensity),
|
|
93
|
-
// 0 = cool daylight, 0.5 = the tuned warm default, 1 = sunset amber
|
|
94
|
-
warmth: finite(source.warmth, fallback.warmth, KEY_LIGHT_LIMITS.warmth),
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
76
|
let sceneSequence = 1;
|
|
99
77
|
|
|
100
78
|
const plainObject = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -135,28 +113,14 @@ export function normalizeReferenceImage(value) {
|
|
|
135
113
|
return typeof value === "string" && value.startsWith("data:image/") ? value : null;
|
|
136
114
|
}
|
|
137
115
|
|
|
138
|
-
/** Stature band for a cast member
|
|
139
|
-
*
|
|
140
|
-
* are a deliberate artistic ask, and a previs giant or child is legitimate. */
|
|
116
|
+
/** Stature band for a cast member: the gizmo's scale handles are a deliberate
|
|
117
|
+
* artistic ask, and a previs giant or child is legitimate. */
|
|
141
118
|
export const CHARACTER_SCALE_MIN = CHARACTER_SCALE_LIMITS.min;
|
|
142
119
|
export const CHARACTER_SCALE_MAX = CHARACTER_SCALE_LIMITS.max;
|
|
143
120
|
const clampScale = (value) => (Number.isFinite(value) && value > 0
|
|
144
121
|
? Math.max(CHARACTER_SCALE_LIMITS.min, Math.min(CHARACTER_SCALE_LIMITS.max, value))
|
|
145
122
|
: 1);
|
|
146
123
|
|
|
147
|
-
/** Where an extra extraction take's performer stands: the filmed offset from
|
|
148
|
-
* person 0, rotated into the ACTIVE character's facing. Pure geometry, so the
|
|
149
|
-
* placement can be proven without a renderer. */
|
|
150
|
-
export function takeAnchor(active, offsetX, offsetZ) {
|
|
151
|
-
const rad = (finiteOr(active?.rot, 0) * Math.PI) / 180;
|
|
152
|
-
const dx = finiteOr(offsetX, 0);
|
|
153
|
-
const dz = finiteOr(offsetZ, 0);
|
|
154
|
-
return {
|
|
155
|
-
x: finiteOr(active?.x, 0) + dx * Math.cos(rad) + dz * Math.sin(rad),
|
|
156
|
-
z: finiteOr(active?.z, 0) - dx * Math.sin(rad) + dz * Math.cos(rad),
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
124
|
/** One character entry in the stage envelope. `source` may be a v3 entry, a
|
|
161
125
|
* partial (spawn dialog), or null — every field falls back to a sane default
|
|
162
126
|
* and every object is freshly owned by the caller. */
|
|
@@ -190,25 +154,17 @@ export function createCharacterEntry(source = null, index = 0) {
|
|
|
190
154
|
// take's root travel was authored against it — see the render path.
|
|
191
155
|
scale: clampScale(s.scale),
|
|
192
156
|
subject: typeof s.subject === "string" ? s.subject : index === 0 ? DEFAULT_SUBJECT_ONE : DEFAULT_SUBJECT_TWO,
|
|
193
|
-
// The character's animation layer: its own root path
|
|
194
|
-
// schedule. The generated clip itself is heavy, so only a lightweight
|
|
195
|
-
// reference (bridge URL + generation params) is persisted — enough to
|
|
196
|
-
// re-fetch and decode it on the next session.
|
|
157
|
+
// The character's animation layer: its own root path.
|
|
197
158
|
layer: normalizeLayer(s.layer),
|
|
198
|
-
motionRef: normalizeMotionRef(s.motionRef),
|
|
199
159
|
// The Pose-mode / IK edits on this character's layer (encoded keys, range
|
|
200
160
|
// pins and their residuals). The motion domain owns them while the scene
|
|
201
161
|
// is open; this is what the saved scene carries so a reload keeps them.
|
|
202
162
|
ikEdits: normalizeIkEdits(s.ikEdits),
|
|
163
|
+
// A compiled take v3 saves its source; the motion layer compiles it again on load.
|
|
164
|
+
motionTake: normalizeTakeSource(s.motionTake),
|
|
203
165
|
};
|
|
204
166
|
}
|
|
205
167
|
|
|
206
|
-
const MOTION_ID_RE = /^[0-9a-f]{64}$/i;
|
|
207
|
-
|
|
208
|
-
// A motionRef names its take by content (motionId: SHA-256 of the npz, kept
|
|
209
|
-
// in the project's embedded motions) and/or by location (url: a bridge run,
|
|
210
|
-
// which is what pre-motionId documents carry). Either one alone is a valid
|
|
211
|
-
// ref; the restore path prefers the embedded bytes when both are present.
|
|
212
168
|
function normalizeIkEdits(value) {
|
|
213
169
|
if (!plainObject(value)) return null;
|
|
214
170
|
const rows = (list, valid) => (Array.isArray(list) ? list.filter(valid).map((entry) => cloneValue(entry)) : []);
|
|
@@ -218,40 +174,10 @@ function normalizeIkEdits(value) {
|
|
|
218
174
|
return keys.length || pins.length ? { keys, pins, pinResiduals } : null;
|
|
219
175
|
}
|
|
220
176
|
|
|
221
|
-
function normalizeMotionRef(ref) {
|
|
222
|
-
if (!plainObject(ref)) return null;
|
|
223
|
-
const motionId = typeof ref.motionId === "string" && MOTION_ID_RE.test(ref.motionId) ? ref.motionId.toLowerCase() : null;
|
|
224
|
-
const url = typeof ref.url === "string" && ref.url ? ref.url : null;
|
|
225
|
-
if (!motionId && !url) return null;
|
|
226
|
-
const normalized = {};
|
|
227
|
-
// Field order matters only for byte-stable serialization; a url-only ref
|
|
228
|
-
// keeps the exact legacy shape (url first, no motionId key).
|
|
229
|
-
if (motionId) normalized.motionId = motionId;
|
|
230
|
-
if (url) normalized.url = url;
|
|
231
|
-
Object.assign(normalized, {
|
|
232
|
-
prompt: typeof ref.prompt === "string" ? ref.prompt : "",
|
|
233
|
-
rotationDeg: Number.isFinite(ref.rotationDeg) ? ref.rotationDeg : 0,
|
|
234
|
-
anchorX: Number.isFinite(ref.anchorX) ? ref.anchorX : 0,
|
|
235
|
-
anchorZ: Number.isFinite(ref.anchorZ) ? ref.anchorZ : 0,
|
|
236
|
-
});
|
|
237
|
-
// Scene calibration is deliberately metadata on the lightweight motionRef,
|
|
238
|
-
// never an NPZ member. Keep it optional so old documents retain their exact
|
|
239
|
-
// shape, while preserving the calibration produced by the extraction/load
|
|
240
|
-
// boundary for a later scene reload. cloneValue also strips non-finite values
|
|
241
|
-
// and recursively owns the object, so a caller cannot mutate the saved stage.
|
|
242
|
-
if (plainObject(ref.calibration)) normalized.calibration = normalizeMotionCalibration(ref.calibration);
|
|
243
|
-
if (ref.trailEdits != null) normalized.trailEdits = normalizeTrailEdits(ref.trailEdits);
|
|
244
|
-
// An agent-installed take keeps the Studio take id its receipts name, so a
|
|
245
|
-
// reload still reports the same take. Optional, like calibration.
|
|
246
|
-
if (typeof ref.studioTakeId === "string" && ref.studioTakeId) normalized.studioTakeId = ref.studioTakeId;
|
|
247
|
-
return normalized;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
177
|
function normalizeLayer(layer) {
|
|
251
178
|
const source = plainObject(layer) ? layer : {};
|
|
252
179
|
return {
|
|
253
180
|
waypoints: normalizeStableItems(cloneValue(source.waypoints), "waypoint"),
|
|
254
|
-
promptClips: normalizeStableItems(cloneValue(source.promptClips), "prompt-clip"),
|
|
255
181
|
};
|
|
256
182
|
}
|
|
257
183
|
|
|
@@ -265,7 +191,6 @@ function normalizeStageLayers(stage) {
|
|
|
265
191
|
...character,
|
|
266
192
|
layer: {
|
|
267
193
|
waypoints: normalizeStableItems(cloneValue(character.layer?.waypoints), "waypoint", ids),
|
|
268
|
-
promptClips: normalizeStableItems(cloneValue(character.layer?.promptClips), "prompt-clip", ids),
|
|
269
194
|
},
|
|
270
195
|
}))
|
|
271
196
|
: source.characters,
|
|
@@ -273,16 +198,12 @@ function normalizeStageLayers(stage) {
|
|
|
273
198
|
}
|
|
274
199
|
|
|
275
200
|
export function createCharacterLayer() {
|
|
276
|
-
return { waypoints: []
|
|
201
|
+
return { waypoints: [] };
|
|
277
202
|
}
|
|
278
203
|
|
|
279
204
|
/** Retime one animation layer from the 20 fps authoring clock onto the 24 fps
|
|
280
|
-
* production clock. Frame numbers only: positions
|
|
281
|
-
*
|
|
282
|
-
* the gaps between prompt blocks survive it — the guards below re-establish
|
|
283
|
-
* both anyway, because a hand-edited body may never have had them. Prompt
|
|
284
|
-
* ranges are half-open [start, end), matching movePromptClipFrames: touching
|
|
285
|
-
* blocks are legal, overlapping ones are not. */
|
|
205
|
+
* production clock. Frame numbers only: positions and headings are untouched.
|
|
206
|
+
* The mapping is strictly increasing, so ascending order survives it. */
|
|
286
207
|
function migrateLayerFrames(layer) {
|
|
287
208
|
if (!plainObject(layer)) return layer;
|
|
288
209
|
const next = { ...cloneValue(layer) };
|
|
@@ -295,20 +216,6 @@ function migrateLayerFrames(layer) {
|
|
|
295
216
|
}
|
|
296
217
|
next.waypoints = [...byFrame.values()].sort((a, b) => a.frame - b.frame);
|
|
297
218
|
}
|
|
298
|
-
if (Array.isArray(layer.promptClips)) {
|
|
299
|
-
const ordered = layer.promptClips
|
|
300
|
-
.filter((clip) => plainObject(clip) && Number.isFinite(clip.startFrame) && Number.isFinite(clip.endFrame))
|
|
301
|
-
.sort((a, b) => a.startFrame - b.startFrame);
|
|
302
|
-
const clips = [];
|
|
303
|
-
let floor = 0;
|
|
304
|
-
for (const clip of ordered) {
|
|
305
|
-
const startFrame = Math.max(floor, toTimelineFrame(Math.round(clip.startFrame)));
|
|
306
|
-
const endFrame = Math.max(startFrame, toTimelineFrame(Math.round(clip.endFrame)));
|
|
307
|
-
clips.push({ ...cloneValue(clip), startFrame, endFrame });
|
|
308
|
-
floor = endFrame;
|
|
309
|
-
}
|
|
310
|
-
next.promptClips = clips;
|
|
311
|
-
}
|
|
312
219
|
return next;
|
|
313
220
|
}
|
|
314
221
|
|
|
@@ -337,7 +244,7 @@ function migrateLegacyCast(source) {
|
|
|
337
244
|
}
|
|
338
245
|
|
|
339
246
|
const STAGE_ENVELOPE_KEYS = new Set([
|
|
340
|
-
"characters", "hasCharSheet", "environmentImage", "environment", "style", "hasEnvSheet", "shotAspect", "cameraPresetId", "sensorId", "keyLight",
|
|
247
|
+
"characters", "hasCharSheet", "environmentImage", "environment", "style", "hasEnvSheet", "shotAspect", "cameraPresetId", "sensorId", "keyLight", "lighting",
|
|
341
248
|
"charA", "charB", "showB", "poseA", "poseB", "subject", "subject2",
|
|
342
249
|
]);
|
|
343
250
|
|
|
@@ -376,7 +283,10 @@ export function createSceneStage(stage = null) {
|
|
|
376
283
|
sensorId: Object.hasOwn(SENSOR_FORMATS, source.sensorId ?? source.sensorFormat)
|
|
377
284
|
? (source.sensorId ?? source.sensorFormat)
|
|
378
285
|
: DEFAULT_SCENE_STAGE.sensorId,
|
|
286
|
+
// The key light the user grabs (puck position, master brightness, warmth or
|
|
287
|
+
// colour) and the stage look; a stage saved before either renders as it did.
|
|
379
288
|
keyLight: createKeyLight(source.keyLight),
|
|
289
|
+
lighting: normalizeLighting(source.lighting),
|
|
380
290
|
};
|
|
381
291
|
}
|
|
382
292
|
|
package/src/semantic-edit.js
CHANGED
|
@@ -23,17 +23,14 @@ function equal(a, b) {
|
|
|
23
23
|
return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && equal(a[key], b[key]));
|
|
24
24
|
}
|
|
25
25
|
const poseValue = (pose) => ({ bones: pose?.bones ?? {}, rootY: pose?.rootY ?? 0 });
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
const keyValues = (keys = []) => keys.map(({ frame, framing }) => ({ frame, framing }));
|
|
28
28
|
const shotValue = (shot) => ({ ...shot, camera: createCameraBlock(shot.camera), cameraKeys: keyValues(shot.cameraKeys) });
|
|
29
29
|
|
|
30
30
|
export function semanticEditKind(domain, before, after) {
|
|
31
31
|
if (before === after) return null;
|
|
32
32
|
if (domain === "pose") return equal(before, after) ? null : "pose_edit";
|
|
33
|
-
|
|
34
|
-
if (equal(blockValues(before), blockValues(after))) return null;
|
|
35
|
-
return after.length > before.length ? "prompt_block_add" : "prompt_block_edit";
|
|
36
|
-
}
|
|
33
|
+
|
|
37
34
|
if (domain === "objects") {
|
|
38
35
|
const added = after.find((item) => !before.some((previous) => previous.id === item.id));
|
|
39
36
|
if (added) return added.renderer === "cutout" ? "cutout_insert" : "object_insert";
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-built set pieces: a car, a small plane and a chair, modelled from
|
|
3
|
+
* primitives in the same clay style as the room and the character tint.
|
|
4
|
+
* Dimensions are metres against real sizes so the 1.8 m figure keeps honest
|
|
5
|
+
* scale. Each takes `autoColor` (the viewport's auto-colour mode) and then
|
|
6
|
+
* tints its primary surfaces flat; glass, tyres and rims keep their own.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Blender's solid-view response for auto-colored surfaces. Workbench shades
|
|
10
|
+
// with a neutral studio rig, so the derived hue reaches the eye unmultiplied;
|
|
11
|
+
// under our warm key light a plain standard material turns every hue olive.
|
|
12
|
+
// Full roughness kills the specular sheen and a self-light of the same hue
|
|
13
|
+
// lifts the shadow side the way workbench's studio lighting does.
|
|
14
|
+
export function autoFlat(hex) {
|
|
15
|
+
return { color: hex, roughness: 1, metalness: 0, emissive: hex, emissiveIntensity: 0.4 };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const CLAY_CAR = "#d98770";
|
|
19
|
+
const CLAY_CAR_TOP = "#e49a84";
|
|
20
|
+
const CLAY_TIRE = "#41484c";
|
|
21
|
+
const CLAY_RIM = "#7c8588";
|
|
22
|
+
const CLAY_GLASS = "#55697a";
|
|
23
|
+
const CLAY_PLANE = "#7896a4";
|
|
24
|
+
const CLAY_PLANE_TRIM = "#e1a849";
|
|
25
|
+
const CLAY_CHAIR = "#b9855d";
|
|
26
|
+
const CLAY_CHAIR_LIGHT = "#cf9d72";
|
|
27
|
+
|
|
28
|
+
function Wheel({ position }) {
|
|
29
|
+
return (
|
|
30
|
+
<group position={position}>
|
|
31
|
+
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
32
|
+
<cylinderGeometry args={[0.33, 0.33, 0.24, 20]} />
|
|
33
|
+
<meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
|
|
34
|
+
</mesh>
|
|
35
|
+
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
36
|
+
<cylinderGeometry args={[0.17, 0.17, 0.26, 16]} />
|
|
37
|
+
<meshStandardMaterial color={CLAY_RIM} roughness={0.5} metalness={0.35} />
|
|
38
|
+
</mesh>
|
|
39
|
+
</group>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A generic 5-door-ish sedan silhouette, ~4.5 m long. Origin at the centre
|
|
44
|
+
* of the footprint, +Z forward.
|
|
45
|
+
*/
|
|
46
|
+
export function Car({ position = [0, 0, 0], rotY = 0, color = CLAY_CAR, topColor = CLAY_CAR_TOP, autoColor = undefined }) {
|
|
47
|
+
const bodyMaterial = autoColor
|
|
48
|
+
? { ...autoFlat(autoColor) }
|
|
49
|
+
: { color, roughness: 0.55, metalness: 0.25 };
|
|
50
|
+
const topMaterial = autoColor
|
|
51
|
+
? { ...autoFlat(autoColor) }
|
|
52
|
+
: { color: topColor, roughness: 0.5, metalness: 0.2 };
|
|
53
|
+
return (
|
|
54
|
+
<group position={position} rotation={[0, rotY, 0]}>
|
|
55
|
+
<mesh position={[0, 0.62, 0]}>
|
|
56
|
+
<boxGeometry args={[1.78, 0.62, 4.45]} />
|
|
57
|
+
<meshStandardMaterial {...bodyMaterial} />
|
|
58
|
+
</mesh>
|
|
59
|
+
<mesh position={[0, 1.12, -0.15]}>
|
|
60
|
+
<boxGeometry args={[1.58, 0.5, 2.2]} />
|
|
61
|
+
<meshStandardMaterial {...topMaterial} />
|
|
62
|
+
</mesh>
|
|
63
|
+
<mesh position={[0, 1.14, -0.15]}>
|
|
64
|
+
<boxGeometry args={[1.62, 0.3, 1.9]} />
|
|
65
|
+
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
66
|
+
</mesh>
|
|
67
|
+
<mesh position={[0, 1.05, 0.95]} rotation={[0.5, 0, 0]}>
|
|
68
|
+
<boxGeometry args={[1.56, 0.42, 0.08]} />
|
|
69
|
+
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
70
|
+
</mesh>
|
|
71
|
+
<mesh position={[0, 1.05, -1.25]} rotation={[-0.55, 0, 0]}>
|
|
72
|
+
<boxGeometry args={[1.56, 0.42, 0.08]} />
|
|
73
|
+
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
74
|
+
</mesh>
|
|
75
|
+
<Wheel position={[0.82, 0.33, 1.45]} />
|
|
76
|
+
<Wheel position={[-0.82, 0.33, 1.45]} />
|
|
77
|
+
<Wheel position={[0.82, 0.33, -1.45]} />
|
|
78
|
+
<Wheel position={[-0.82, 0.33, -1.45]} />
|
|
79
|
+
</group>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Compact single-engine propeller plane, ~3.4 m wingspan and +Z forward. */
|
|
84
|
+
export function SmallPlane({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
|
|
85
|
+
// Auto-color mode tints the PRIMARY surfaces only (fuselage, wings, trim);
|
|
86
|
+
// glass, tires and rims keep their materials so the silhouette still reads.
|
|
87
|
+
// Each mesh keeps its own hand-tuned roughness when the mode is off.
|
|
88
|
+
const mat = (color, roughness, metalness) =>
|
|
89
|
+
autoColor ? autoFlat(autoColor) : { color, roughness, metalness };
|
|
90
|
+
return (
|
|
91
|
+
<group position={position} rotation={[0, rotY, 0]}>
|
|
92
|
+
<mesh position={[0, 0.76, 0]} rotation={[Math.PI / 2, 0, 0]}>
|
|
93
|
+
<cylinderGeometry args={[0.23, 0.31, 2.75, 16]} />
|
|
94
|
+
<meshStandardMaterial {...mat(CLAY_PLANE, 0.58, 0.18)} />
|
|
95
|
+
</mesh>
|
|
96
|
+
<mesh position={[0, 0.76, 1.55]} rotation={[Math.PI / 2, 0, 0]}>
|
|
97
|
+
<coneGeometry args={[0.23, 0.55, 16]} />
|
|
98
|
+
<meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.52, 0.2)} />
|
|
99
|
+
</mesh>
|
|
100
|
+
|
|
101
|
+
<mesh position={[0, 0.73, 0.15]}>
|
|
102
|
+
<boxGeometry args={[3.4, 0.09, 0.58]} />
|
|
103
|
+
<meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.14)} />
|
|
104
|
+
</mesh>
|
|
105
|
+
<mesh position={[0, 0.84, -1.18]}>
|
|
106
|
+
<boxGeometry args={[1.45, 0.07, 0.38]} />
|
|
107
|
+
<meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.62, 0.12)} />
|
|
108
|
+
</mesh>
|
|
109
|
+
<mesh position={[0, 1.08, -1.2]} rotation={[0.22, 0, 0]}>
|
|
110
|
+
<boxGeometry args={[0.08, 0.62, 0.48]} />
|
|
111
|
+
<meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.12)} />
|
|
112
|
+
</mesh>
|
|
113
|
+
|
|
114
|
+
<mesh position={[0, 1.02, 0.42]} scale={[0.62, 0.46, 0.9]}>
|
|
115
|
+
<sphereGeometry args={[0.42, 16, 10, 0, Math.PI * 2, 0, Math.PI / 2]} />
|
|
116
|
+
<meshStandardMaterial color={CLAY_GLASS} roughness={0.16} metalness={0.55} />
|
|
117
|
+
</mesh>
|
|
118
|
+
|
|
119
|
+
<group position={[0, 0.76, 1.86]}>
|
|
120
|
+
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
|
121
|
+
<cylinderGeometry args={[0.11, 0.11, 0.2, 12]} />
|
|
122
|
+
<meshStandardMaterial color={CLAY_RIM} roughness={0.45} metalness={0.4} />
|
|
123
|
+
</mesh>
|
|
124
|
+
<mesh position={[0, 0, 0.12]} rotation={[0, 0, 0.28]}>
|
|
125
|
+
<boxGeometry args={[1.25, 0.08, 0.06]} />
|
|
126
|
+
<meshStandardMaterial color={CLAY_TIRE} roughness={0.8} />
|
|
127
|
+
</mesh>
|
|
128
|
+
</group>
|
|
129
|
+
|
|
130
|
+
{[-0.55, 0.55].map((x) => (
|
|
131
|
+
<group key={x} position={[x, 0.2, 0.15]}>
|
|
132
|
+
<mesh position={[0, 0.24, 0]} rotation={[0, 0, x < 0 ? -0.35 : 0.35]}>
|
|
133
|
+
<boxGeometry args={[0.045, 0.55, 0.045]} />
|
|
134
|
+
<meshStandardMaterial color={CLAY_RIM} roughness={0.65} metalness={0.3} />
|
|
135
|
+
</mesh>
|
|
136
|
+
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
137
|
+
<cylinderGeometry args={[0.16, 0.16, 0.09, 14]} />
|
|
138
|
+
<meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
|
|
139
|
+
</mesh>
|
|
140
|
+
</group>
|
|
141
|
+
))}
|
|
142
|
+
</group>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function Chair({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
|
|
147
|
+
// Auto-color mode tints seat/back and frame together; undefined keeps the
|
|
148
|
+
// hand-picked clay pair exactly as it ships.
|
|
149
|
+
const seat = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR_LIGHT, roughness: 0.86 };
|
|
150
|
+
const frame = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR, roughness: 0.9 };
|
|
151
|
+
const legPositions = [
|
|
152
|
+
[-0.24, 0.23, -0.22],
|
|
153
|
+
[0.24, 0.23, -0.22],
|
|
154
|
+
[-0.24, 0.23, 0.22],
|
|
155
|
+
[0.24, 0.23, 0.22],
|
|
156
|
+
];
|
|
157
|
+
return (
|
|
158
|
+
<group position={position} rotation={[0, rotY, 0]} scale={0.9}>
|
|
159
|
+
<mesh position={[0, 0.49, 0]} castShadow receiveShadow>
|
|
160
|
+
<boxGeometry args={[0.6, 0.12, 0.58]} />
|
|
161
|
+
<meshStandardMaterial {...seat} />
|
|
162
|
+
</mesh>
|
|
163
|
+
{legPositions.map((leg, index) => (
|
|
164
|
+
<mesh key={index} position={leg} castShadow receiveShadow>
|
|
165
|
+
<boxGeometry args={[0.09, 0.46, 0.09]} />
|
|
166
|
+
<meshStandardMaterial {...frame} />
|
|
167
|
+
</mesh>
|
|
168
|
+
))}
|
|
169
|
+
<mesh position={[-0.24, 0.92, -0.245]} castShadow receiveShadow>
|
|
170
|
+
<boxGeometry args={[0.09, 0.86, 0.09]} />
|
|
171
|
+
<meshStandardMaterial {...frame} />
|
|
172
|
+
</mesh>
|
|
173
|
+
<mesh position={[0.24, 0.92, -0.245]} castShadow receiveShadow>
|
|
174
|
+
<boxGeometry args={[0.09, 0.86, 0.09]} />
|
|
175
|
+
<meshStandardMaterial {...frame} />
|
|
176
|
+
</mesh>
|
|
177
|
+
<mesh position={[0, 1.08, -0.245]} castShadow receiveShadow>
|
|
178
|
+
<boxGeometry args={[0.52, 0.38, 0.1]} />
|
|
179
|
+
<meshStandardMaterial {...seat} />
|
|
180
|
+
</mesh>
|
|
181
|
+
</group>
|
|
182
|
+
);
|
|
183
|
+
}
|
package/src/settings-menu.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
2
2
|
import { ko, localeChosen } from "./locale.js";
|
|
3
3
|
import PreferencesDialog from "./shell/PreferencesDialog.jsx";
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ const LANGUAGES = [
|
|
|
14
14
|
{ id: "ko", label: "한국어", action: "한국어로 전환" },
|
|
15
15
|
];
|
|
16
16
|
|
|
17
|
-
export default function SettingsMenu(
|
|
17
|
+
export default function SettingsMenu() {
|
|
18
18
|
const [open, setOpen] = useState(false);
|
|
19
19
|
const triggerRef = useRef(null);
|
|
20
20
|
const close = useCallback(() => {
|
|
@@ -39,13 +39,6 @@ export default function SettingsMenu({ motionSetup, motionSetupReveal = 0 }) {
|
|
|
39
39
|
</>
|
|
40
40
|
);
|
|
41
41
|
|
|
42
|
-
// A contextual readiness action can reveal Preferences directly on the
|
|
43
|
-
// motion connection page without changing the topbar or adding a second
|
|
44
|
-
// settings surface.
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
if (motionSetupReveal) setOpen(true);
|
|
47
|
-
}, [motionSetupReveal]);
|
|
48
|
-
|
|
49
42
|
// First-run cue: the studio starts in English even on a Korean browser, so
|
|
50
43
|
// the only visible hint that Korean exists used to be the old locale button.
|
|
51
44
|
// Until a language is stored, a ko-* browser sees the trigger in Korean.
|
|
@@ -70,8 +63,7 @@ export default function SettingsMenu({ motionSetup, motionSetupReveal = 0 }) {
|
|
|
70
63
|
<PreferencesDialog
|
|
71
64
|
open={open}
|
|
72
65
|
onClose={close}
|
|
73
|
-
|
|
74
|
-
initialSection={motionSetupReveal ? "ARDY Connection" : "Appearance"}
|
|
66
|
+
initialSection="Appearance"
|
|
75
67
|
cameraTutorial={cameraTutorial}
|
|
76
68
|
/>
|
|
77
69
|
</div>
|
package/src/shell/BottomDock.jsx
CHANGED
|
@@ -5,9 +5,9 @@ import "./dock.css";
|
|
|
5
5
|
import LibrarySlot from "./LibrarySlot.jsx";
|
|
6
6
|
import BoardSlot from "./BoardSlot.jsx";
|
|
7
7
|
import { ko } from "../locale.js";
|
|
8
|
-
import Timeline from "../
|
|
8
|
+
import Timeline, { timelineTake } from "../motion/timeline.jsx";
|
|
9
9
|
import { DEFAULT_PLAYBACK_SPEED, SHOT_ASPECT_PRESETS, sceneObjectNameDisplayKo } from "../app-stage.jsx";
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
import { trackFeature } from "../analytics.js";
|
|
12
12
|
import { defaultRailRange } from "../camera-rail-schedule.js";
|
|
13
13
|
import { insertPathMark, pathMarks } from "../object-path.js";
|
|
@@ -74,9 +74,8 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
|
|
|
74
74
|
tlFrame, motion, waypointMode, craneSelectedIndex,
|
|
75
75
|
isCameraSelection, addActiveCranePoint, deleteSelectedCranePoint, setCraneSelectedIndex, tlFrameCount,
|
|
76
76
|
tlFps, characters, activeCharIndex, ghostLayers, pathSpeed,
|
|
77
|
-
tlPlaying, workflowMode, waypoints, pendingWaypointFrame,
|
|
78
|
-
|
|
79
|
-
resetMotionTrim, cutMotionAtPlayhead, changeMotionSegmentSpeed, removeMotionSegmentById, ikFrames,
|
|
77
|
+
tlPlaying, workflowMode, waypoints, pendingWaypointFrame,
|
|
78
|
+
stateBadge, ikMode, ikChains, ikFrames,
|
|
80
79
|
rangePins, rangePinSelection, ikEditTool, rangePinPreview, footSnap,
|
|
81
80
|
bodyContact, shots, shotAspectKey, activeShotIdx, railDraw,
|
|
82
81
|
pathDraw, pathTarget, setPathDraw, setRailDraw, setWorkspaceLayout,
|
|
@@ -85,13 +84,12 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
|
|
|
85
84
|
setBodyContact, setToast, setFootSnap, setTlFrame, advanceFrame,
|
|
86
85
|
stepFrame, cameraPreviewEndRef, manualCameraOverrideRef, setTlPlaying, toggleWaypointMode,
|
|
87
86
|
setWaypointMode, selectActiveCharacterInHierarchy, setActiveWaypointId, setPendingWaypointFrame, removeWaypoint,
|
|
88
|
-
queueRootWaypointFrame,
|
|
89
|
-
changePromptClip, resizePromptClip, movePromptClip, removePromptClip, setSelectedHierarchyId,
|
|
87
|
+
queueRootWaypointFrame, setSelectedHierarchyId,
|
|
90
88
|
selectWorkflowMode, addCameraKeyframe, moveCameraKeyframe, removeCameraKeyframe, syncActiveCameraFraming,
|
|
91
89
|
activeCamera, activeShotDuration, changeActiveCamera, cameraRail, previewCameraShot,
|
|
92
90
|
toggleCameraRailDraw, deleteCameraRail, selectTimelineShot, shotsDomain, runStudioAction,
|
|
93
|
-
clearMotion, subscribeToasts, exportStatus, exportPhaseLabel,
|
|
94
|
-
|
|
91
|
+
clearMotion, subscribeToasts, exportStatus, exportPhaseLabel,
|
|
92
|
+
pathPointIndex, setPathPointIndex,
|
|
95
93
|
} = useStudioShell();
|
|
96
94
|
const dockRef = useRef(null);
|
|
97
95
|
const [dockHeight, setDockHeight] = useState(readDockHeight);
|
|
@@ -160,20 +158,6 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
|
|
|
160
158
|
useEffect(() => subscribeToasts((toast) => logStore.push({ kind: "toast", text: toast.uiMessage })),
|
|
161
159
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
162
160
|
[]);
|
|
163
|
-
const generationWasRunning = useRef(false);
|
|
164
|
-
useEffect(() => {
|
|
165
|
-
if (ardyRunning && !generationWasRunning.current) logStore.push({ kind: "generation", text: ko("Motion generation started", "모션 생성을 시작했어요") });
|
|
166
|
-
generationWasRunning.current = ardyRunning;
|
|
167
|
-
}, [ardyRunning]);
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (ardyRunning && ardyStatus) logStore.push({ kind: "generation", key: "generation:status", text: ardyStatus });
|
|
170
|
-
}, [ardyRunning, ardyStatus]);
|
|
171
|
-
useEffect(() => {
|
|
172
|
-
if (!ardyOutcome) return;
|
|
173
|
-
logStore.push({ kind: "generation", text: ardyOutcome.ok
|
|
174
|
-
? ko("Motion generation finished", "모션 생성을 마쳤어요")
|
|
175
|
-
: ko(`Motion generation failed — ${ardyOutcome.message}`, `모션 생성 실패 — ${ardyOutcome.message}`) });
|
|
176
|
-
}, [ardyOutcome]);
|
|
177
161
|
const exportPhase = exportStatus?.phase, exportLabel = exportStatus?.label, exportMessage = exportStatus?.message;
|
|
178
162
|
const exportDone = exportStatus?.completedFrames, exportTotal = exportStatus?.frameCount;
|
|
179
163
|
useEffect(() => {
|
|
@@ -238,22 +222,10 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
|
|
|
238
222
|
waypointMode={waypointMode}
|
|
239
223
|
waypoints={waypoints}
|
|
240
224
|
pendingWaypointFrame={pendingWaypointFrame}
|
|
241
|
-
previsMode={previsMode}
|
|
242
|
-
promptClips={promptClips}
|
|
243
|
-
selectedPromptId={selectedPromptId}
|
|
244
225
|
badge={stateBadge}
|
|
245
226
|
ikMode={ikMode}
|
|
246
227
|
ikDisabled={!ikChains}
|
|
247
|
-
motion={motion
|
|
248
|
-
frames: motion.frames,
|
|
249
|
-
label: motion.prompt || ko("Loaded take", "불러온 테이크"),
|
|
250
|
-
segments: motionEditLayout(motion.editSegments ?? createMotionEdit(motion.frames)),
|
|
251
|
-
} : null}
|
|
252
|
-
onMotionTrim={applyMotionTrim}
|
|
253
|
-
onMotionTrimReset={resetMotionTrim}
|
|
254
|
-
onMotionCut={cutMotionAtPlayhead}
|
|
255
|
-
onMotionSpeedChange={changeMotionSegmentSpeed}
|
|
256
|
-
onMotionSegmentRemove={removeMotionSegmentById}
|
|
228
|
+
motion={timelineTake(motion, characters[activeCharIndex]?.id, runStudioAction)}
|
|
257
229
|
ikFrames={ikFrames}
|
|
258
230
|
rangePins={rangePins}
|
|
259
231
|
selectedPinId={rangePinSelection}
|
|
@@ -351,21 +323,7 @@ export default function BottomDock({ tab: requestedTab = "animation", onTabChang
|
|
|
351
323
|
}}
|
|
352
324
|
onMarkerRemove={removeWaypoint}
|
|
353
325
|
onRootKeyframeAdd={queueRootWaypointFrame}
|
|
354
|
-
|
|
355
|
-
addPromptClip(frame);
|
|
356
|
-
selectActiveCharacterInHierarchy();
|
|
357
|
-
revealPromptBlocks();
|
|
358
|
-
}}
|
|
359
|
-
onPromptSelect={(id) => {
|
|
360
|
-
setSelectedPromptId(id);
|
|
361
|
-
setArdyPrompt(promptClips.find((clip) => clip.id === id)?.text ?? "");
|
|
362
|
-
selectActiveCharacterInHierarchy();
|
|
363
|
-
revealPromptBlocks();
|
|
364
|
-
}}
|
|
365
|
-
onPromptChange={changePromptClip}
|
|
366
|
-
onPromptResize={resizePromptClip}
|
|
367
|
-
onPromptMove={movePromptClip}
|
|
368
|
-
onPromptRemove={removePromptClip}
|
|
326
|
+
|
|
369
327
|
onCameraMoveSelect={() => {
|
|
370
328
|
setSelectedHierarchyId("camera");
|
|
371
329
|
if (workflowMode !== "camera") selectWorkflowMode("camera");
|