cozyclay 2.1.1 → 3.0.1
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 +88 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +43 -116
- package/bin/agent/agent-runner.mjs +14 -15
- 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/session-store.mjs +2 -2
- package/bin/agent/studio-context-budget.mjs +93 -0
- 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-BWCqdgWA.js +1 -0
- package/dist/assets/app-DfTCxaKk.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-BxKXh07s.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-DNO8kv_N.js} +1 -1
- package/dist/assets/{landing-ChUvB_zL.js → landing-yfZaJkWc.js} +1 -1
- package/dist/assets/scene-asset-sync-U3kS2rvK.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-D78eiKTa.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 +151 -2625
- package/src/agent-progress.js +80 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +12 -2
- 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 +10 -8
- 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 +214 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +55 -13
- 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 +53 -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 +47 -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 +60 -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 +79 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +113 -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 +197 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +177 -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 +144 -0
- package/src/motion3/compiler/validate-parts.js +118 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +74 -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 +177 -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 +204 -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/people.js +82 -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 +125 -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 +195 -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 +44 -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/people-checks.js +37 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +228 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +129 -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 +113 -0
- package/src/motion3/schema/types.js +149 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/settle.js +136 -0
- package/src/motion3/skills/basic.js +83 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/flip.js +200 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/impact.js +109 -0
- package/src/motion3/skills/index.js +85 -0
- package/src/motion3/skills/info.js +80 -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/qa-label.js +25 -0
- 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 +16 -14
- package/src/studio-agent-commands.js +19 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +47 -77
- package/src/studio-app-binding.js +27 -47
- 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 +15 -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 +109 -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 +9 -125
- 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
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
|
2
|
+
import { useThree } from "@react-three/fiber";
|
|
3
|
+
import * as THREE from "three";
|
|
4
|
+
import { stageLook } from "./stage-lighting.js";
|
|
5
|
+
import { ENV_HEIGHT, ENV_WIDTH, environmentPixels } from "./stage-environment.js";
|
|
6
|
+
import { installOcclusion } from "./stage-occlusion.js";
|
|
7
|
+
import { useHdrMap } from "./stage-hdr-map.js";
|
|
8
|
+
import { refreshHdrLibrary } from "./stage-hdr-library.js";
|
|
9
|
+
|
|
10
|
+
// Rows of the equirectangular gradient: v runs from straight down (0) through
|
|
11
|
+
// the horizon (0.5) to straight up (1).
|
|
12
|
+
const SKY_ROWS = 128;
|
|
13
|
+
const rgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
14
|
+
|
|
15
|
+
/** A sky that grades from `bottom` at the horizon (and below it) to `top`
|
|
16
|
+
* overhead, eased so most of the change happens in the lower 60 degrees a shot
|
|
17
|
+
* camera actually sees. Built once per look as an sRGB equirectangular texture;
|
|
18
|
+
* three draws it as the background in the same pass as the scene. */
|
|
19
|
+
function gradientSky(bottom, top) {
|
|
20
|
+
const [from, to] = [rgb(bottom), rgb(top)];
|
|
21
|
+
const data = new Uint8Array(SKY_ROWS * 4);
|
|
22
|
+
for (let row = 0; row < SKY_ROWS; row++) {
|
|
23
|
+
const elevation = ((row + 0.5) / SKY_ROWS - 0.5) * 180;
|
|
24
|
+
const t = elevation <= 0 ? 0 : 1 - (1 - Math.min(1, elevation / 60)) ** 2;
|
|
25
|
+
for (let channel = 0; channel < 3; channel++) data[row * 4 + channel] = Math.round(from[channel] + (to[channel] - from[channel]) * t);
|
|
26
|
+
data[row * 4 + 3] = 255;
|
|
27
|
+
}
|
|
28
|
+
const texture = new THREE.DataTexture(data, 1, SKY_ROWS);
|
|
29
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
30
|
+
texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
31
|
+
texture.magFilter = THREE.LinearFilter;
|
|
32
|
+
texture.minFilter = THREE.LinearFilter;
|
|
33
|
+
texture.needsUpdate = true;
|
|
34
|
+
return texture;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The look's environment map (stage-environment.js), prefiltered for image-based
|
|
38
|
+
* lighting. Half floats keep the glow around the key above 1 and filter
|
|
39
|
+
* everywhere WebGL2 runs. */
|
|
40
|
+
function environmentMap(gl, spec) {
|
|
41
|
+
const pixels = environmentPixels(spec), half = new Uint16Array(pixels.length);
|
|
42
|
+
for (let i = 0; i < pixels.length; i++) half[i] = THREE.DataUtils.toHalfFloat(pixels[i]);
|
|
43
|
+
const texture = new THREE.DataTexture(half, ENV_WIDTH, ENV_HEIGHT, THREE.RGBAFormat, THREE.HalfFloatType);
|
|
44
|
+
texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
45
|
+
texture.magFilter = THREE.LinearFilter;
|
|
46
|
+
texture.minFilter = THREE.LinearFilter;
|
|
47
|
+
texture.needsUpdate = true;
|
|
48
|
+
try { return prefiltered(gl, texture); } finally { texture.dispose(); }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** An equirectangular map prefiltered for image-based lighting (PMREM). */
|
|
52
|
+
function prefiltered(gl, texture) {
|
|
53
|
+
const generator = new THREE.PMREMGenerator(gl);
|
|
54
|
+
try { return generator.fromEquirectangular(texture); } finally { generator.dispose(); }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The stage's sky, fog and exposure (stage.lighting through stageLook), set on
|
|
59
|
+
* the one scene and renderer every path draws with: the viewport panes, the
|
|
60
|
+
* shot preview card, capture_frame, contact sheets and video export
|
|
61
|
+
* (stage-capture.jsx). Nothing here is a post-process; it is all the same pass.
|
|
62
|
+
*
|
|
63
|
+
* The open stage runs 500 m; without a falloff the whole deck reads at once and
|
|
64
|
+
* the horizon sits a kilometre away. The fog fades the floor INTO the sky colour,
|
|
65
|
+
* so past its far distance the deck simply ceases to exist with no horizon line,
|
|
66
|
+
* no clip edge and no tone break. Haze (stage.lighting.fog) pulls that fade in.
|
|
67
|
+
*
|
|
68
|
+
* Perspective cameras see the gradient sky when skyTop is set; orthographic ones
|
|
69
|
+
* (the plan) keep the flat horizon colour, since a box-mapped sky has no meaning
|
|
70
|
+
* looking straight down. A caller that swaps the background for a pass of its
|
|
71
|
+
* own (render-passes.js) is left alone.
|
|
72
|
+
*
|
|
73
|
+
* The environment light (scene.environment) and the ambient occlusion pass
|
|
74
|
+
* (stage-occlusion.js) are set here too, for the same paths. Both are off in the
|
|
75
|
+
* studio look, which therefore draws exactly what it drew before them. The map
|
|
76
|
+
* is rebuilt only when its colours or the key's direction change.
|
|
77
|
+
*
|
|
78
|
+
* An HDR environment (stage.lighting.hdr, stage-hdr-map.js) replaces that map
|
|
79
|
+
* once it has loaded: its prefiltered texture is the light (prefiltered again
|
|
80
|
+
* only when the map changes; rotation and intensity are uniforms), and with
|
|
81
|
+
* hdrBackground the map itself is the perspective backdrop, the deck fading
|
|
82
|
+
* into the map's horizon colour. Until a file loads, the look's own sky lights.
|
|
83
|
+
*/
|
|
84
|
+
export function StageAtmosphere({ lighting = null, keyLight, theme = "dark", grid = false }) {
|
|
85
|
+
// The scene and renderer are read inside the effects: they are three objects
|
|
86
|
+
// this component configures, not React state.
|
|
87
|
+
const get = useThree((state) => state.get), invalidate = useThree((state) => state.invalidate);
|
|
88
|
+
const look = stageLook({ lighting, keyLight, theme, grid });
|
|
89
|
+
const { sky, skyTop, exposure } = look, { near, far } = look.fog;
|
|
90
|
+
const hazeNear = look.captureFog?.near ?? null, hazeFar = look.captureFog?.far ?? null;
|
|
91
|
+
const envKey = look.env ? JSON.stringify(look.env) : null, { envIntensity, ao } = look;
|
|
92
|
+
const hdrMap = useHdrMap(look.hdr?.id ?? null), hdr = hdrMap ? look.hdr : null;
|
|
93
|
+
const backdrop = hdr?.background ? hdrMap : null, backdropIntensity = backdrop ? hdr.intensity : 1;
|
|
94
|
+
const hdrLight = hdr ? hdr.envIntensity : null, hdrTurn = hdr ? (hdr.rotation * Math.PI) / 180 : 0;
|
|
95
|
+
useEffect(() => { void refreshHdrLibrary(); }, []);
|
|
96
|
+
useLayoutEffect(() => {
|
|
97
|
+
const { scene } = get();
|
|
98
|
+
const flat = backdrop ? new THREE.Color().setRGB(...backdrop.horizon.map((value) => value * backdropIntensity), THREE.LinearSRGBColorSpace) : new THREE.Color(sky);
|
|
99
|
+
const gradient = skyTop ? gradientSky(sky, skyTop) : null, map = backdrop?.texture ?? null;
|
|
100
|
+
scene.background = flat;
|
|
101
|
+
scene.backgroundIntensity = backdropIntensity;
|
|
102
|
+
scene.fog = new THREE.Fog(flat, near, far);
|
|
103
|
+
scene.onBeforeRender = (_renderer, _scene, camera) => {
|
|
104
|
+
if (scene.background === flat || scene.background === gradient || (map && scene.background === map)) scene.background = camera.isPerspectiveCamera ? map ?? gradient ?? flat : flat;
|
|
105
|
+
};
|
|
106
|
+
invalidate();
|
|
107
|
+
return () => {
|
|
108
|
+
scene.onBeforeRender = () => {};
|
|
109
|
+
gradient?.dispose();
|
|
110
|
+
};
|
|
111
|
+
}, [get, invalidate, sky, skyTop, near, far, backdrop, backdropIntensity]);
|
|
112
|
+
useLayoutEffect(() => {
|
|
113
|
+
// The viewport applies exposure in tone mapping. Exports render into a
|
|
114
|
+
// target, which three never tone-maps, so CaptureRig reads it from here
|
|
115
|
+
// and scales the lights for its draw instead (same pass, same scene).
|
|
116
|
+
const { scene, gl } = get();
|
|
117
|
+
gl.toneMappingExposure = exposure;
|
|
118
|
+
// An HDR backdrop is light as well, so exports scale it (and the horizon the deck fades into) too.
|
|
119
|
+
scene.userData.stageCapture = { exposure, fog: hazeNear === null ? null : { near: hazeNear, far: hazeFar }, backdrop: Boolean(backdrop) };
|
|
120
|
+
invalidate();
|
|
121
|
+
}, [get, invalidate, exposure, hazeNear, hazeFar, backdrop]);
|
|
122
|
+
const hdrTexture = hdrMap?.texture ?? null, envSource = hdrTexture ? null : envKey;
|
|
123
|
+
useLayoutEffect(() => {
|
|
124
|
+
if (!hdrTexture && !envSource) return undefined;
|
|
125
|
+
const { scene, gl } = get();
|
|
126
|
+
const target = hdrTexture ? prefiltered(gl, hdrTexture) : environmentMap(gl, JSON.parse(envSource));
|
|
127
|
+
scene.environment = target.texture;
|
|
128
|
+
invalidate();
|
|
129
|
+
return () => {
|
|
130
|
+
if (scene.environment === target.texture) scene.environment = null;
|
|
131
|
+
target.dispose();
|
|
132
|
+
invalidate();
|
|
133
|
+
};
|
|
134
|
+
}, [get, invalidate, hdrTexture, envSource]);
|
|
135
|
+
useLayoutEffect(() => {
|
|
136
|
+
const { scene } = get();
|
|
137
|
+
scene.environmentIntensity = hdrLight ?? envIntensity;
|
|
138
|
+
// The light and the backdrop turn together: +90 deg carries +x to -z.
|
|
139
|
+
scene.environmentRotation.set(0, hdrTurn, 0);
|
|
140
|
+
scene.backgroundRotation.set(0, hdrTurn, 0);
|
|
141
|
+
invalidate();
|
|
142
|
+
}, [get, invalidate, envIntensity, hdrLight, hdrTurn]);
|
|
143
|
+
// The pass stays installed while ao > 0; the slider only changes its strength.
|
|
144
|
+
const occlusion = useRef({ strength: ao }), occluded = ao > 0;
|
|
145
|
+
useLayoutEffect(() => {
|
|
146
|
+
if (!occluded) return undefined;
|
|
147
|
+
const remove = installOcclusion(get().scene, occlusion.current);
|
|
148
|
+
invalidate();
|
|
149
|
+
return () => {
|
|
150
|
+
remove();
|
|
151
|
+
invalidate();
|
|
152
|
+
};
|
|
153
|
+
}, [get, invalidate, occluded]);
|
|
154
|
+
useLayoutEffect(() => {
|
|
155
|
+
occlusion.current.strength = ao;
|
|
156
|
+
invalidate();
|
|
157
|
+
}, [invalidate, ao]);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
@@ -59,19 +59,15 @@ export function nextCharacterId(list) {
|
|
|
59
59
|
}
|
|
60
60
|
return id;
|
|
61
61
|
}
|
|
62
|
-
export const DEMO_MOTION_URL = "/demo/walk-then-stop.npz";
|
|
63
|
-
export const DEMO_MOTION_PROMPT = "A person walks forward.";
|
|
64
62
|
// How long a deletion keeps offering its one-press Undo. Both toasts use the
|
|
65
63
|
// same window so the two deletion paths feel like one rule.
|
|
66
64
|
export const OBJECT_DELETE_UNDO_MS = 7000;
|
|
67
65
|
export const ASSET_DELETE_UNDO_MS = 7000;
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
export const CLAY = "#
|
|
71
|
-
export const CLAY_B = "#
|
|
72
|
-
|
|
73
|
-
// brighter, whiter clay to keep it readable against the set.
|
|
74
|
-
export const CLAY_X = "#d0d0d4";
|
|
66
|
+
// White clay: every figure starts white (the renderer still drops the value a
|
|
67
|
+
// little and shades the joint shells darker, so the body keeps its form).
|
|
68
|
+
export const CLAY = "#ffffff";
|
|
69
|
+
export const CLAY_B = "#ffffff";
|
|
70
|
+
export const CLAY_X = "#ffffff";
|
|
75
71
|
// Model/role default for a cast member; a user-picked entry.tint always wins
|
|
76
72
|
// over this at render time.
|
|
77
73
|
export const defaultCharacterTint = (entry, index) => (entry.model === "x-bot-tpose" ? CLAY_X : index === 0 ? CLAY : CLAY_B);
|
package/src/studio-actions.js
CHANGED
|
@@ -38,7 +38,7 @@ const castOverride = {
|
|
|
38
38
|
/** A world floor point in metres; y is the floor. */
|
|
39
39
|
const floorPoint = input({ x: { type: "number" }, z: { type: "number" } });
|
|
40
40
|
const waypointFrame = { ...frame, minimum: 1 };
|
|
41
|
-
/** The tracks an IK key stores (src/
|
|
41
|
+
/** The tracks an IK key stores (src/motion/ik.js IK_TRACKS and FK_TRACKS). A
|
|
42
42
|
* chain track keys its three bones (upper, lower, end); a joint track one. */
|
|
43
43
|
export const STUDIO_IK_CHAIN_TRACKS = freezeStudioData(["leftHand", "rightHand", "leftFoot", "rightFoot"]);
|
|
44
44
|
export const STUDIO_IK_JOINT_TRACKS = freezeStudioData(["hips", "spine", "chest", "neck", "head", "leftShoulder", "rightShoulder"]);
|
|
@@ -47,9 +47,9 @@ const perBone = items => ({ type: "array", items, minItems: 1, maxItems: 3 });
|
|
|
47
47
|
const quaternion = input({ x: num, y: num, z: num, w: num });
|
|
48
48
|
/** One track's key: the IK state's { q, p, baseQ, basePos, chainP,
|
|
49
49
|
* keepTranslations, blend, pin, correctionRange } with quaternions as {x,y,z,w} and positions
|
|
50
|
-
* as {x,y,z}; blend is the key's own correction range in frames (src/
|
|
50
|
+
* as {x,y,z}; blend is the key's own correction range in frames (src/motion/ik.js
|
|
51
51
|
* correctionWeight), absent for the editor's default range; pin is the id of
|
|
52
|
-
* the range pin that baked the key (src/
|
|
52
|
+
* the range pin that baked the key (src/motion/range-pin.js). correctionRange
|
|
53
53
|
* pairs the boundary keys of an explicitly selected interval. */
|
|
54
54
|
const ikTrackKey = input({}, { q: perBone(quaternion), p: StudioSchemas.Vec3, baseQ: perBone(quaternion), basePos: StudioSchemas.Vec3,
|
|
55
55
|
chainP: perBone(StudioSchemas.Vec3), keepTranslations: { type: "boolean" }, blend: { type: "integer", minimum: 1, maximum: 240 },
|
|
@@ -87,12 +87,10 @@ export const STUDIO_ACTIONS = freezeStudioData([
|
|
|
87
87
|
{ id: "shot.remove", label: "Delete shot", kind: "mutation", undoDomain: "shot", input: input(shotId),
|
|
88
88
|
description: "Delete a shot and leave its frames as free-camera time." },
|
|
89
89
|
{ id: "shot.setRange", label: "Set shot range", kind: "mutation", undoDomain: "shot", input: input({ ...shotId, range: StudioSchemas.FrameRange }),
|
|
90
|
-
description: "Move a shot's start and end to a half-open frame range. Edges are clamped to the timeline and refused where they would overlap another shot; the receipt's
|
|
90
|
+
description: "Move a shot's start and end to a half-open frame range, e.g. { shotId, range: { startFrame: 0, endFrameExclusive: 240 } } for frames 0-239. range: [0, 240] ([start, endExclusive]) and flat { shotId, startFrame: 0, endFrameExclusive: 240 } are taken as the same range. Edges are clamped to the timeline and refused where they would overlap another shot; the receipt's summary shows the range that landed (\"Set shot range: Shot 1 [0, 240).\")." },
|
|
91
91
|
{ id: "shot.reorder", label: "Move shot", kind: "mutation", undoDomain: "shot",
|
|
92
92
|
input: input(shotId, { startFrame: frame, index: stillIndex }),
|
|
93
93
|
description: "Move a shot; give exactly one of startFrame or index. With startFrame, a clip moves in time to start there, keeping its length and camera keys (a noop where it would overlap another shot), and a still moves to the place in the still order that frame falls in. With index (stills only), the still moves to that position among the stills (0 is first; past the end means last). Stills stay end to end from frame 0." },
|
|
94
|
-
{ id: "motion.generateAllBlocks", label: "Generate all blocks", kind: "job", generation: "motion", domain: "motion", background: true, input: input(),
|
|
95
|
-
description: "Generate the active character's motion from all of its prompt blocks, like the top-bar Generate Motion button when prompt blocks have text. It starts a job and returns status \"started\"; the take lands in the editor when the job finishes. Counts as the one motion generation of this message." },
|
|
96
94
|
{ id: "character.addWaypoint", label: "Add root waypoint", kind: "mutation", undoDomain: "cast", input: input({ ...characterId, position: floorPoint }, { frame: waypointFrame }),
|
|
97
95
|
description: `Pin a character's root path: at frame, the character's root stands at position (world x/z metres). Frame 0 is the character's own spot, so pins start at frame 1 and each frame holds one pin. Omit frame to pace the pin at a walk (1.4 m/s) from the previous one. ${WAYPOINT_RULES} Read paths with inspect_studio { scope: "motion" }.` },
|
|
98
96
|
{ id: "character.move", label: "Move character", kind: "mutation", undoDomain: "cast", input: input(characterId, { x: num, z: num, rot: num }),
|
|
@@ -110,10 +108,14 @@ export const STUDIO_ACTIONS = freezeStudioData([
|
|
|
110
108
|
{ id: "character.clearIkKeys", label: "Clear IK keys", kind: "mutation", undoDomain: "motion", input: input(characterId),
|
|
111
109
|
description: "Delete every IK key of the character, returning it to its take or pose without corrections." },
|
|
112
110
|
{ id: "shot.setCameraRail", label: "Set camera rail", kind: "mutation", undoDomain: "shot",
|
|
113
|
-
input: input({ ...shotId, points: { type: "array", items: floorPoint, minItems: 2, maxItems: 512 } }),
|
|
114
|
-
description: "Lay a shot's dolly rail through points (world floor x/z metres, in travel order) and put the shot's camera on it, like drawing the rail in the Top-View
|
|
111
|
+
input: input({ ...shotId, points: { type: "array", items: floorPoint, minItems: 2, maxItems: 512 } }, { height: { oneOf: [{ type: "number", minimum: 0.1, maximum: 30 }, { type: "array", items: input({ t: { type: "number", minimum: 0, maximum: 1 }, height: { type: "number", minimum: 0.1, maximum: 30 } }), minItems: 2, maxItems: 8 }] }, aim: { oneOf: [{ type: "array", items: idSchema, minItems: 1, maxItems: 4 }, input({ x: num, y: num, z: num }), { type: "null" }] }, aimHeight: { type: "number", minimum: 0, maximum: 30 }, focalMm: { oneOf: [{ type: "number", minimum: 10, maximum: 300 }, { type: "null" }] } }),
|
|
112
|
+
description: "Lay a shot's dolly rail through points (world floor x/z metres, in travel order) and put the shot's camera on it, like drawing the rail in the Top-View: the camera runs the rail at an even speed over the whole shot (or its authored rail-follow range), so a push-in, pull-out, orbit, track or crane is one call with 2-6 points (a line, or an arc through a few points; the rail is a smooth curve through them). height is the lens height in metres, one number or crane marks [{ t: 0..1 along the rail, height }] (default the follow height, 1.6). aim is what the camera holds: up to 4 character or object ids (their middle, frame by frame: a character's chest, an object's middle) or a world point { x, y, z }; without an aim it follows the scene's first character. aimHeight puts a cast aim at that world height instead of the chest, e.g. 0.9 to hold a whole standing body, 1.6 for faces. focalMm is the shot's lens (default the scene lens). It replaces any rail the shot had and keeps any height, aim or lens you leave out (null clears aim and lens), and it removes the camera keys the rail covers. Answers the rail's length, speed, height, aim and lens; check the framing with verify_result { targets, checks: [\"framing\"], range: the shot's frames } and a contact sheet. Read rails with inspect_studio { scope: \"shot\" }." },
|
|
115
113
|
{ id: "shot.clearCameraRail", label: "Delete camera rail", kind: "mutation", undoDomain: "shot", input: input(shotId),
|
|
116
114
|
description: "Delete a shot's camera rail; the shot's camera goes back to following its subject at the current distance." },
|
|
115
|
+
{ id: "shot.setCameraMode", label: "Set shot camera mode", kind: "mutation", undoDomain: "shot", input: input({ ...shotId, mode: { type: "string", enum: ["keys", "follow", "rail"] } }),
|
|
116
|
+
description: "Set how a shot's camera moves: keys plays the shot's camera keys (frame_shot frames them; one framing holds the whole shot), follow keeps the captured distance from the subject, rail rides the shot's rail (lay one first with shot.setCameraRail). Deleting a rail leaves follow; set keys to hold a framed camera instead." },
|
|
117
|
+
{ id: "shot.rename", label: "Rename shot", kind: "mutation", undoDomain: "shot", input: input({ ...shotId, name: { type: "string", maxLength: 240 } }),
|
|
118
|
+
description: "Rename a shot: its label on the timeline and in shot lists." },
|
|
117
119
|
{ id: "object.attach", label: "Attach to character", kind: "mutation", undoDomain: "objects",
|
|
118
120
|
input: input({ objectId: idSchema, ...characterId }, { bone: { type: "string", enum: STUDIO_ATTACH_BONES } }),
|
|
119
121
|
description: "Make a scene object ride a character, like dropping it on the character's Hierarchy row: on one bone (a cup in the right hand: bone \"rightHand\") or, with bone omitted, on the character's animated root so it travels with the body. The object keeps its place on screen: its position, rotation and scale are rewritten into the new frame (local to that bone while attached), and it leaves any group. Needs the character's rig on stage." },
|
|
@@ -125,6 +127,8 @@ export const STUDIO_ACTIONS = freezeStudioData([
|
|
|
125
127
|
description: "Show a composition guide over the shot frame: rule of thirds, golden ratio, center cross, safe areas, or off. Overlay only, never in exported pixels; a viewer setting that is never undone." },
|
|
126
128
|
{ id: "view.setInset", label: "Top-View inset", kind: "transient", input: input({ collapsed: { type: "boolean" } }),
|
|
127
129
|
description: "Fold (collapsed: true) or unfold the Top-View inset pane over the viewport. A viewer setting that is never undone." },
|
|
130
|
+
{ id: "view.setGhosts", label: "Ghosts", kind: "transient", input: input({ mode: { type: "string", enum: ["off", "step", "keys"] } }, { count: { type: "integer", minimum: 1, maximum: 6 }, step: { type: "integer", minimum: 1, maximum: 24 } }),
|
|
131
|
+
description: "Onion skin in the editor viewport, like the View menu's Ghosts: translucent poses of the active character's installed take, count (1-6, default 3) before the playhead in blue and as many after it in orange, fading with distance in time; props the take carries (a kit's bat) ghost with the body. mode step spaces them every step frames (1-24, default 4), keys puts them on the spec's key frames, off hides them; e.g. { mode: \"step\", count: 3, step: 4 }. An editor overlay: never in capture_frame, exports or contact sheets (verify_result ghosts: true draws them on a views sheet). A viewer setting: never saved or undone." },
|
|
128
132
|
{ id: "export.shotVideo", exposure: "confirm", confirmationReason: "Exporting writes a video file outside the Studio.", label: "Export video (mp4)", kind: "job", timeoutMs: 300_000, input: input({}, { ...shotId, scope: { type: "string", enum: ["timeline", "shot"], description: "timeline: the whole timeline, every shot back to back; shot: one shot (shotId, or the one under the playhead)." } }),
|
|
129
133
|
description: "Record a shot to an MP4 (camera move and character motion, no editor chrome), like the Export menu's Video (mp4), and ask the browser to download it. With shotId it records that shot's own range; without it, what the menu records: the whole take when there is motion, else the shot under the playhead (else the first shot), keyed from the current camera if it has no keys. Waits until the file is encoded (up to 5 minutes) and answers status \"completed\" with output.fileName and output.frameCount. One export at a time; not a motion generation." },
|
|
130
134
|
{ id: "scene.create", label: "New scene", kind: "document", input: input(),
|
|
@@ -151,9 +155,6 @@ export const STUDIO_ACTIONS = freezeStudioData([
|
|
|
151
155
|
description: "Prepare the Studio's Send-to-AI package for the shot under the playhead (else the current camera): the prompt for an external image or video model, written from the shot's camera, cast, poses, environment and style, plus reference frames rendered from the shot camera (its first and last camera key when it has keys). No AI service is called. mode \"image\" is a still, \"video\" a shot with its camera move; model is the image model the prompt is written for (image mode only). Each omitted choice keeps the Studio's current one; a given one becomes it. The Studio opens its result panel, where the user copies the prompt and downloads the frames; the frame images stay there and are not in the answer. Answers status \"completed\" with output.prompt, mode, modelLabel, shot (id, name, range), aspectRatio, cameraMode and referenceFrames (how many frames the panel shows). Changes nothing in the scene; not a motion generation." },
|
|
152
156
|
// The instruction leads the H3 prompt, which the motion API caps at 4000
|
|
153
157
|
// characters with its camera-lock text (about 225) appended.
|
|
154
|
-
{ id: "motion.generateFromVideo", exposure: "confirm", confirmationReason: "AI video motion uses a paid external generation.", label: "Generate motion (AI video)", kind: "job", generation: "motion", timeoutMs: 300_000,
|
|
155
|
-
input: input({ instruction: { type: "string", minLength: 1, maxLength: 3700 } }),
|
|
156
|
-
description: "Make the active character perform instruction through a hosted AI video model (Fal H3 Max Turbo, 480P), like the agent panel's Generate motion button. It sends the character's pose frame (pose A from the Fal card, else a fresh capture from the shot camera) with the instruction to the hosted model, and each run spends one of the account's daily AI video generations. Run it only when the user explicitly asked for AI-video motion; for ordinary motion use generate_motion or motion.generateAllBlocks. The capture needs the character's full body inside the shot frame and shaded part colours (view.setPartColours { mode: \"shaded\" }); a prompt the user hand-edited in the Fal card is sent instead of instruction. Waits for the clip (up to 5 minutes) and answers status \"completed\" with output.videoUrl, resolution, durationSeconds, ingested, frames, fps and dailyRemaining. The clip is ingested as Video capture footage and the timeline takes its length and frame rate; no take is installed until GVHMR extraction runs on it in the Video capture panel. Counts as the one motion generation of this message." },
|
|
157
158
|
]);
|
|
158
159
|
export const STUDIO_ACTION_IDS = freezeStudioData(STUDIO_ACTIONS.map(action => action.id));
|
|
159
160
|
|
|
@@ -216,14 +217,15 @@ export function createStudioActionRegistry({ readState } = {}) {
|
|
|
216
217
|
list(state = readState?.()) {
|
|
217
218
|
return [...entries.values()].map(entry => {
|
|
218
219
|
const verdict = availability(entry, state);
|
|
219
|
-
const row = { id: entry.id, label: entry.label, kind: entry.kind, description: entry.description, exposure: entry.exposure, ...(entry.agentHidden ? { agentHidden: true } : {}),
|
|
220
|
+
const row = { id: entry.id, label: entry.label, kind: entry.kind, description: entry.description, exposure: entry.exposure, ...(entry.agentHidden ? { agentHidden: true } : {}), ...(entry.readOnly ? { readOnly: true } : {}),
|
|
220
221
|
...(entry.timeoutMs === undefined ? {} : { timeoutMs: entry.timeoutMs }), ...(entry.generation ? { generation: entry.generation } : {}) };
|
|
221
222
|
return verdict === true ? { ...row, available: true, input: entry.input } : { ...row, available: false, reason: verdict };
|
|
222
223
|
});
|
|
223
224
|
},
|
|
224
225
|
prepare(id, args = {}) {
|
|
225
|
-
const entry = registry.get(id);
|
|
226
|
-
|
|
226
|
+
const entry = registry.get(id), given = args ?? {};
|
|
227
|
+
// normalizeArgs (optional) rewrites another spelling the action takes into its declared input first.
|
|
228
|
+
const validated = validateStudioSchema(entry.input, entry.normalizeArgs ? entry.normalizeArgs(given) : given, "INVALID_ARGUMENT", "$.args");
|
|
227
229
|
if (readState) {
|
|
228
230
|
const verdict = availability(entry, readState());
|
|
229
231
|
if (verdict !== true) fail("TARGET_NOT_READY", verdict);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Studio composites prepare private domain drafts; the App owns publication,
|
|
2
2
|
// history, gesture fences and semantic revision/telemetry. No UI callbacks here.
|
|
3
3
|
import { Euler, Vector3, Quaternion, PerspectiveCamera } from 'three';
|
|
4
|
-
import { createSceneObject, updateSceneObject, removeSceneObject, setSceneObjectParent, descendantsOf, isEffectivelyHidden, supportHeightForObject,
|
|
4
|
+
import { createSceneObject, updateSceneObject, removeSceneObject, setSceneObjectParent, descendantsOf, isEffectivelyHidden, supportHeightForObject, OBJECT_MENU_ENTRIES } from './scene-objects.js';
|
|
5
5
|
import { createCharacterEntry } from './scenes.js';
|
|
6
6
|
import { createShot, shotAtFrame } from './cuts.js';
|
|
7
7
|
import { captureFraming } from './camera-move.js';
|
|
@@ -12,6 +12,7 @@ import { clampWarning } from './receipt-findings.js';
|
|
|
12
12
|
import { occludersOf, primarySubjects, sideOfAxis } from './studio-geometry-facts.js';
|
|
13
13
|
import { StudioProtocolError, StudioSchemas, STUDIO_PATCH_KINDS, STUDIO_PATCH_DESCRIPTORS, validateStudioSchema, validateStudioIdentity, validateReceipt, freezeStudioData } from './studio-agent-protocol.js';
|
|
14
14
|
import { sampleContactSheetFrames } from './studio-contact-sheet.js';
|
|
15
|
+
import { supportGaps } from './studio-support-gap.js';
|
|
15
16
|
|
|
16
17
|
const DEG = Math.PI / 180, EPS = 1e-8, CHARACTER_SUPPORT_TOLERANCE = 5e-3;
|
|
17
18
|
const fail = (code, message) => { throw new StudioProtocolError(code, message); };
|
|
@@ -241,9 +242,8 @@ export function entityWorldBounds(entity, state, ports) {
|
|
|
241
242
|
} catch { return null; }
|
|
242
243
|
}
|
|
243
244
|
const overlapEvidence = overlaps => ({ coverage: 'same-frame-world-AABB-proxies', overlapIds: [...new Set(overlaps.map(o => o.id))].slice(0, 100), maximumFootprintOverlapM: Math.max(0, ...overlaps.map(o => o.depth)) });
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
export const placementChecks = (ids, state, ports) => overlapEvidence(overlapsOf(ids, state, ports));
|
|
245
|
+
// Placement evidence for entity ids: the AABB overlap an arrangement receipt reports, and each object's support gap (studio-support-gap.js).
|
|
246
|
+
export const placementChecks = (ids, state, ports) => ({ ...overlapEvidence(overlapsOf(ids, state, ports)), ...supportGaps(ids, state, ports.takes, entity => entityWorldBounds(entity, state, ports)) });
|
|
247
247
|
function avoid(entity, relation, state, ports) {
|
|
248
248
|
const blocked = overlapsFor(entity, state, ports);
|
|
249
249
|
if (!blocked.length) return entity;
|
|
@@ -369,7 +369,7 @@ const LEVELS = { ground: 0.3 / 1.8, low: 0.7 / 1.8, hip: 1.1 / 1.8, eye: 1.65 /
|
|
|
369
369
|
const ANGLES = { front: 0, 'front three-quarter': 40, profile: 90, 'rear three-quarter': 140, back: 180 };
|
|
370
370
|
/** Where subject bound points land through one camera: the evidence a
|
|
371
371
|
* frame_shot receipt reports, plus the screen box its details keep. */
|
|
372
|
-
function projectSubject(points, camera, fov, aspectRatio) {
|
|
372
|
+
export function projectSubject(points, camera, fov, aspectRatio) {
|
|
373
373
|
const direction = vector(camera.lookAt).sub(vector(camera.position));
|
|
374
374
|
const projection = new PerspectiveCamera(fov / DEG, aspectRatio, 0.01, 10000);
|
|
375
375
|
projection.position.copy(vector(camera.position)); projection.lookAt(vector(camera.lookAt)); projection.updateMatrixWorld(true);
|
|
@@ -436,9 +436,13 @@ export function frameDraft(command, state, ports) {
|
|
|
436
436
|
const created = !shot && !state.shotDocument.shots.length && !command.args.shotId;
|
|
437
437
|
if (created) shot = createShot('Shot 1', 0, state.frameCount - 1);
|
|
438
438
|
if (!shot) fail('AMBIGUOUS_TARGET', 'No shot owns this frame; select an existing shot explicitly.');
|
|
439
|
-
|
|
439
|
+
// The shot's camera keys are what the contact sheet and the export render, so
|
|
440
|
+
// every framing lands in them. Without keyAtFrame, a shot that holds one
|
|
441
|
+
// framing (a still, or a clip with at most one key) is reframed whole; a clip
|
|
442
|
+
// that already moves takes the framing as a key at the playhead.
|
|
440
443
|
const existingKey = shot.cameraKeys[0];
|
|
441
|
-
const
|
|
444
|
+
const hold = shot.kind === 'still' || (command.args.keyAtFrame === undefined && shot.cameraKeys.length <= 1);
|
|
445
|
+
const frame = hold ? (existingKey?.frame ?? shot.startFrame) : command.args.keyAtFrame ?? state.frame;
|
|
442
446
|
if (frame < shot.startFrame || frame > shot.endFrame || shot.endFrame >= state.frameCount) fail('INVALID_RANGE', 'Framing/key frame must be inside the shot range.');
|
|
443
447
|
const intent = command.args.framing.intent;
|
|
444
448
|
let camera = command.args.framing.exact;
|
|
@@ -457,19 +461,17 @@ export function frameDraft(command, state, ports) {
|
|
|
457
461
|
const direction = vector(camera.lookAt).sub(vector(camera.position));
|
|
458
462
|
if (direction.length() <= EPS) fail('INVALID_ARGUMENT', 'Camera position and aim must differ.');
|
|
459
463
|
const framing = captureFraming({ pos: camera.position, yaw: Math.atan2(-direction.x, -direction.z), pitch: Math.atan2(direction.y, Math.hypot(direction.x, direction.z)), fovDeg: fov / DEG });
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
if (still || command.args.keyAtFrame !== undefined) {
|
|
463
|
-
keyId = (still ? existingKey?.id : keys.find(k => k.frame === frame)?.id) ?? createStableItemId('camera-key');
|
|
464
|
-
keys = still ? [{ id: keyId, frame, framing }] : [...keys.filter(k => k.frame !== frame), { id: keyId, frame, framing }].sort((a, b) => a.frame - b.frame);
|
|
465
|
-
}
|
|
464
|
+
const keyId = (hold ? existingKey?.id : shot.cameraKeys.find(k => k.frame === frame)?.id) ?? createStableItemId('camera-key');
|
|
465
|
+
const keys = hold ? [{ id: keyId, frame, framing }] : [...shot.cameraKeys.filter(k => k.frame !== frame), { id: keyId, frame, framing }].sort((a, b) => a.frame - b.frame);
|
|
466
466
|
const nextShot = { ...shot, cameraKeys: keys, camera: { ...shot.camera, mode: 'keys' } };
|
|
467
467
|
const shots = created ? [nextShot] : state.shotDocument.shots.map(s => s.id === shot.id ? nextShot : s);
|
|
468
468
|
const { screenBounds, checks: projected } = projectSubject(points, camera, fov, state.filmback.aspectRatio), derivedSize = projected.derivedSize;
|
|
469
469
|
const sight = sightChecks([subject], [points], camera.position, state, ports), checks = { ...projected, ...sight.checks };
|
|
470
470
|
const resolvedCamera = { ...camera, sensorId: state.filmback.sensorId, slate: derivedSize };
|
|
471
|
-
|
|
472
|
-
|
|
471
|
+
// Not a manual override: the keys drive the live shot camera from here, so a
|
|
472
|
+
// later playhead move shows what the export renders at that frame.
|
|
473
|
+
const draft = { shotDocument: { ...state.shotDocument, shots }, camera: resolvedCamera, manual: false };
|
|
474
|
+
return { domain: 'shot', draft, affectedIds: [shot.id, keyId],
|
|
473
475
|
checks,
|
|
474
476
|
warnings: sight.occluders.slice(0, 5).map(item => ({ code: 'OCCLUDED', id: item.byObjectId })), details: { created, shotId: shot.id, keyId, frame, framing, screenBounds, subjectIds: [subject.id] } };
|
|
475
477
|
}
|
|
@@ -514,7 +516,8 @@ export function createStudioCommandJournal({ host, now = Date.now, isRetained =
|
|
|
514
516
|
};
|
|
515
517
|
}
|
|
516
518
|
export function studioObjectCatalogue() {
|
|
517
|
-
|
|
519
|
+
// Every creatable kind: the sized library, the Empty and the two practical lights (zero footprint).
|
|
520
|
+
return freezeStudioData({ objects: OBJECT_MENU_ENTRIES.map(({ kind, footprint, height, supportY }) => ({ kind, footprint: { ...footprint }, height, supportY: supportY ?? height })), imageRefs: [],
|
|
518
521
|
// The patchable vocabulary, so a caller reads the paths and their declared
|
|
519
522
|
// ranges instead of guessing them from a rejection.
|
|
520
523
|
patchable: Object.fromEntries(STUDIO_PATCH_KINDS.map(kind => [kind, STUDIO_PATCH_DESCRIPTORS.filter(descriptor => descriptor.path.startsWith(`${kind}.`))])) });
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { clone as cloneSkeleton } from 'three/examples/jsm/utils/SkeletonUtils.js';
|
|
5
5
|
import { StudioProtocolError, freezeStudioData } from './studio-agent-protocol.js';
|
|
6
|
-
import {
|
|
7
|
-
import { resolveIkRig, createIkState, ikEvaluate, findBone, hasBindPose } from './
|
|
8
|
-
import { PHYSICS_LIMITS, createSupportSampler, copyPhysicsKeys, supportIntervals, physicsMetrics } from './
|
|
9
|
-
import { createDynamicsSampler, supportDiagnostics } from './
|
|
10
|
-
import { computeCenterOfMass } from './
|
|
11
|
-
import { buildCollisionCapsules, detectPenetrations, supportsCollisionCleanup } from './
|
|
12
|
-
import { collisionBlockers, blockerSummary } from './
|
|
13
|
-
import { createGroundSampler } from './
|
|
6
|
+
import { applyTakeFrame } from './motion3/playback.js';
|
|
7
|
+
import { resolveIkRig, createIkState, ikEvaluate, findBone, hasBindPose } from './motion/ik.js';
|
|
8
|
+
import { PHYSICS_LIMITS, createSupportSampler, copyPhysicsKeys, supportIntervals, physicsMetrics } from './motion/physics-review.js';
|
|
9
|
+
import { createDynamicsSampler, supportDiagnostics } from './motion/physics-support.js';
|
|
10
|
+
import { computeCenterOfMass } from './motion/center-of-mass.js';
|
|
11
|
+
import { buildCollisionCapsules, detectPenetrations, supportsCollisionCleanup } from './motion/fix-collisions.js';
|
|
12
|
+
import { collisionBlockers, blockerSummary } from './motion/collision-blockers.js';
|
|
13
|
+
import { createGroundSampler } from './motion/ground.js';
|
|
14
14
|
import { OBJECT_LIBRARY } from './scene-objects.js';
|
|
15
15
|
import { objectTransformAt } from './object-path.js';
|
|
16
16
|
import { sampleAt } from './sample-at.js';
|
|
@@ -50,7 +50,7 @@ function disposeRig(value) {
|
|
|
50
50
|
}
|
|
51
51
|
function poseFrame(evaluator, motion, layer, frame) {
|
|
52
52
|
restore(evaluator.rest);
|
|
53
|
-
if (motion)
|
|
53
|
+
if (motion) applyTakeFrame(evaluator.rig, motion, sampleAt({ frameCount: motion.frames, motion }, null, frame).motionFrame);
|
|
54
54
|
if (layer) ikEvaluate(evaluator.chains, layer, frame, evaluator.fkJoints, motion ? BLEND : 0);
|
|
55
55
|
evaluator.parent.updateMatrixWorld(true);
|
|
56
56
|
}
|