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
|
@@ -11,6 +11,7 @@ import { elementByPath } from "../studio-elements.js";
|
|
|
11
11
|
import { saveAutoColor } from "../auto-color.js";
|
|
12
12
|
import { trackFeature } from "../analytics.js";
|
|
13
13
|
import { GUIDE_LABELS, nextGuideMode } from "../shot-guides.js";
|
|
14
|
+
import GhostsMenuGroup from "./GhostsMenuGroup.jsx";
|
|
14
15
|
import "./viewport.css";
|
|
15
16
|
|
|
16
17
|
// G1: the single mode+tool pill. Keys 1-5 and W/E/R are bound in App's
|
|
@@ -40,7 +41,6 @@ const ICON = {
|
|
|
40
41
|
rotate: "M13.25 8A5.25 5.25 0 1 1 11.7 4.3 M13.25 2.5v2.75H10.5",
|
|
41
42
|
scale: "M2.5 8.5v4a1 1 0 0 0 1 1h4 M8.5 2.5h5v5 M13.5 2.5 7.5 8.5",
|
|
42
43
|
ik: "M2.5 13.5 6.5 9l3 2.2 4-7.7 M6.5 9h.01 M9.5 11.2h.01",
|
|
43
|
-
trail: "M2 12.5c3 0 3-9 6-9s3 9 6 9",
|
|
44
44
|
pin: "M8 14.5v-4 M5 2h6 M6.2 2v3.6L4.5 10.5h7L9.8 5.6V2",
|
|
45
45
|
blocks: "M2 3.5h7.5v3.5H2z M6.5 9h7.5v3.5H6.5z",
|
|
46
46
|
refine: "M10.5 2.5l3 3L6 13H3v-3z",
|
|
@@ -63,12 +63,10 @@ function RailIcon({ name, size = 16 }) {
|
|
|
63
63
|
|
|
64
64
|
// The gizmo's snap increments (TRANSLATE_SNAP / ROTATE_SNAP in
|
|
65
65
|
// src/scene-objects.js). They are fixed, so the value group names them.
|
|
66
|
-
const SNAP_MOVE = "5cm";
|
|
67
|
-
const SNAP_TURN = "5°";
|
|
66
|
+
const SNAP_MOVE = "5cm", SNAP_TURN = "5°";
|
|
68
67
|
|
|
69
68
|
// Editor lens range: shotsDomain.changeLens and the FOV slider take 14-90°.
|
|
70
|
-
const FOV_MIN = 14;
|
|
71
|
-
const FOV_MAX = 90;
|
|
69
|
+
const FOV_MIN = 14, FOV_MAX = 90;
|
|
72
70
|
|
|
73
71
|
// "+ Add › Character" stands the new body one metre along X per existing
|
|
74
72
|
// character, inside the same stage clamp the Content drag applies.
|
|
@@ -117,15 +115,14 @@ function MenuItem({ checked, role = "menuitemradio", className = "", children, .
|
|
|
117
115
|
export default function ViewportToolbar() {
|
|
118
116
|
const {
|
|
119
117
|
workflowMode, selectWorkflowMode, poseRefusal, gizmoMode, setGizmoMode, snapEnabled,
|
|
120
|
-
setSnapEnabled, preset, applyPreset, cameraPresetId,
|
|
118
|
+
setSnapEnabled, preset, applyPreset, cameraPresetId,
|
|
121
119
|
runStudioAction, shotAspectKey, fovDeg, shotsDomain, shot, shots, activeShot,
|
|
122
120
|
setNonce, workspaceLayout, viewMenuTriggerRef, viewMenuOpen,
|
|
123
121
|
setViewMenuOpen, viewLooksActive, gridView, setGridView, guideMode,
|
|
124
122
|
autoColor, setAutoColor, isCharacterSelection, partColoursChoice, embedMode,
|
|
125
123
|
agentCollapsed, addSceneObject, spawnCharacter, characters, flySpeed,
|
|
126
|
-
ikEditTool, setIkEditTool,
|
|
127
|
-
|
|
128
|
-
refineDisabledReason, previsMode, sculptView, requestSculptView,
|
|
124
|
+
ikEditTool, setIkEditTool, motion, setRangePinPartPick,
|
|
125
|
+
previsMode, sculptView, requestSculptView,
|
|
129
126
|
} = useStudioShell();
|
|
130
127
|
const menu = useOverlayMenu();
|
|
131
128
|
|
|
@@ -136,7 +133,6 @@ export default function ViewportToolbar() {
|
|
|
136
133
|
setAutoColor(next);
|
|
137
134
|
};
|
|
138
135
|
|
|
139
|
-
const refineReason = lineEditMode ? null : refineDisabledReason();
|
|
140
136
|
const tools = {
|
|
141
137
|
scene: [
|
|
142
138
|
{ key: "W", id: "move", name: ko("Move", "이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
|
|
@@ -145,11 +141,7 @@ export default function ViewportToolbar() {
|
|
|
145
141
|
],
|
|
146
142
|
pose: [
|
|
147
143
|
{ key: "W", id: "ik", name: ko("Pose fix (IK parts)", "포즈 수정 (IK 파츠)"), active: ikEditTool === "ik", pick: () => setIkEditTool("ik") },
|
|
148
|
-
|
|
149
|
-
key: "E", id: "trail", name: ko("Path fix (motion trail)", "경로 수정 (궤적선)"), active: ikEditTool === "trail",
|
|
150
|
-
refused: showTrails ? null : ko("Turn Trails on in Show to edit the motion path", "경로를 수정하려면 표시에서 궤적선을 켜세요"),
|
|
151
|
-
pick: () => setIkEditTool("trail"),
|
|
152
|
-
},
|
|
144
|
+
|
|
153
145
|
{
|
|
154
146
|
key: "R", id: "pin", name: ko("Pin (range pin)", "고정 (범위 고정)"), active: ikEditTool === "pin",
|
|
155
147
|
refused: motion ? null : ko("Pinning needs a motion take", "고정하려면 모션 테이크가 필요해요"),
|
|
@@ -160,16 +152,8 @@ export default function ViewportToolbar() {
|
|
|
160
152
|
{ key: "W", id: "move", name: ko("Move camera", "카메라 이동"), active: gizmoMode === "move", pick: () => setGizmoMode("move") },
|
|
161
153
|
{ key: "E", id: "rotate", name: ko("Rotate camera", "카메라 회전"), active: gizmoMode === "rotate", pick: () => setGizmoMode("rotate") },
|
|
162
154
|
],
|
|
163
|
-
motion
|
|
164
|
-
|
|
165
|
-
key: "W", id: "blocks", name: ko("Blocks (select and move prompt blocks)", "블록 (프롬프트 블록 선택·이동)"), active: !lineEditMode,
|
|
166
|
-
pick: () => { if (lineEditMode) exitLineEditMode(); },
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
key: "E", id: "refine", name: ko("Refine (edit the path line)", "다듬기 (경로선 편집)"), active: lineEditMode,
|
|
170
|
-
refused: refineReason, pick: () => { if (!lineEditMode) enterRefineMode(); },
|
|
171
|
-
},
|
|
172
|
-
],
|
|
155
|
+
// Motion is compiled by the agent (motion.compile); the department has no tools of its own.
|
|
156
|
+
motion: [],
|
|
173
157
|
// Sculpt mode's W/E/R swing the turntable camera to a reference view.
|
|
174
158
|
sculpt: [
|
|
175
159
|
{ key: "W", id: "front", name: ko("Front view", "정면 보기"), active: sculptView?.view === "front", pick: () => requestSculptView("front") },
|
|
@@ -200,33 +184,6 @@ export default function ViewportToolbar() {
|
|
|
200
184
|
<span className="vp-value-part"><RailIcon name="grid" size={14} />{SNAP_MOVE}</span>
|
|
201
185
|
<span className="vp-value-part"><RailIcon name="angle" size={14} />{SNAP_TURN}</span>
|
|
202
186
|
</button>
|
|
203
|
-
) : workflowMode === "pose" ? (
|
|
204
|
-
<div className="vp-menu-wrap" data-vp-menu="influence">
|
|
205
|
-
<button
|
|
206
|
-
type="button"
|
|
207
|
-
className="vp-value"
|
|
208
|
-
aria-haspopup="dialog"
|
|
209
|
-
aria-expanded={menu.open === "influence"}
|
|
210
|
-
title={ko("Influence range — how far an edit blends into nearby frames", "영향 범위 — 수정이 주변 프레임에 섞이는 길이")}
|
|
211
|
-
onClick={() => menu.toggle("influence")}
|
|
212
|
-
>
|
|
213
|
-
{trimNumber(trailFalloffS)}s
|
|
214
|
-
</button>
|
|
215
|
-
{menu.open === "influence" && (
|
|
216
|
-
<div className="vp-menu vp-slider-popover" role="dialog" aria-label={ko("Influence range", "영향 범위")}>
|
|
217
|
-
<input
|
|
218
|
-
type="range"
|
|
219
|
-
min={0.1}
|
|
220
|
-
max={2}
|
|
221
|
-
step={0.1}
|
|
222
|
-
value={trailFalloffS}
|
|
223
|
-
aria-label={ko("Influence range", "영향 범위")}
|
|
224
|
-
onChange={(event) => setTrailFalloffS(Number(event.target.value))}
|
|
225
|
-
/>
|
|
226
|
-
<output>{trimNumber(trailFalloffS)}s</output>
|
|
227
|
-
</div>
|
|
228
|
-
)}
|
|
229
|
-
</div>
|
|
230
187
|
) : workflowMode === "camera" ? (
|
|
231
188
|
<>
|
|
232
189
|
<div className="vp-menu-wrap" data-vp-menu="lens">
|
|
@@ -248,7 +205,6 @@ export default function ViewportToolbar() {
|
|
|
248
205
|
key={mm}
|
|
249
206
|
data-lens={mm}
|
|
250
207
|
checked={shot.focalMm === mm}
|
|
251
|
-
disabled={i2vMotionCameraLocked}
|
|
252
208
|
onClick={() => { shotsDomain.changeLens(fov); menu.close(); }}
|
|
253
209
|
>
|
|
254
210
|
{mm}mm
|
|
@@ -262,7 +218,6 @@ export default function ViewportToolbar() {
|
|
|
262
218
|
max={FOV_MAX}
|
|
263
219
|
step="1"
|
|
264
220
|
value={fovDeg}
|
|
265
|
-
disabled={i2vMotionCameraLocked}
|
|
266
221
|
onChange={(event) => shotsDomain.changeLens(Number(event.target.value))}
|
|
267
222
|
/>
|
|
268
223
|
<output>{Math.round(fovDeg)}°</output>
|
|
@@ -460,7 +415,6 @@ export default function ViewportToolbar() {
|
|
|
460
415
|
<select
|
|
461
416
|
aria-label={ko("Camera preset", "카메라 프리셋")}
|
|
462
417
|
value={cameraPresetId ?? ""}
|
|
463
|
-
disabled={i2vMotionCameraLocked}
|
|
464
418
|
onChange={(event) => {
|
|
465
419
|
const id = event.target.value;
|
|
466
420
|
if (!id) { runStudioAction("stage.setFilmback", { cameraPresetId: null }); return; }
|
|
@@ -577,21 +531,7 @@ export default function ViewportToolbar() {
|
|
|
577
531
|
{ko("Composition guides", "구도 가이드")}
|
|
578
532
|
<small>{ko(GUIDE_LABELS[guideMode].en, GUIDE_LABELS[guideMode].ko)}</small>
|
|
579
533
|
</button>
|
|
580
|
-
<
|
|
581
|
-
type="button"
|
|
582
|
-
role="menuitemcheckbox"
|
|
583
|
-
className={"view-menu-item trails-toggle" + (showTrails ? " active" : "")}
|
|
584
|
-
aria-checked={showTrails}
|
|
585
|
-
aria-pressed={showTrails}
|
|
586
|
-
title={ko("Motion trails while posing", "포즈 편집 중 궤적선")}
|
|
587
|
-
onClick={() => {
|
|
588
|
-
if (showTrails && ikEditTool === "trail") setIkEditTool("ik");
|
|
589
|
-
setShowTrails(!showTrails);
|
|
590
|
-
}}
|
|
591
|
-
>
|
|
592
|
-
<span className="view-menu-mark" aria-hidden="true">{showTrails ? "✓" : ""}</span>
|
|
593
|
-
{ko("Trails", "궤적선")}
|
|
594
|
-
</button>
|
|
534
|
+
<GhostsMenuGroup />
|
|
595
535
|
{/* Part colours repaint a BODY, so the section only exists
|
|
596
536
|
while a character is selected (R2). */}
|
|
597
537
|
{isCharacterSelection && (
|
|
@@ -23,7 +23,14 @@
|
|
|
23
23
|
border: 0;
|
|
24
24
|
background: none;
|
|
25
25
|
}
|
|
26
|
-
.app[data-shell="glass"] .studio-agent-inspector .agent-title {
|
|
26
|
+
.app[data-shell="glass"] .studio-agent-inspector .agent-title {
|
|
27
|
+
min-width: 0;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
color: var(--text-1);
|
|
30
|
+
font: 600 13px var(--sans);
|
|
31
|
+
white-space: nowrap;
|
|
32
|
+
text-overflow: ellipsis;
|
|
33
|
+
}
|
|
27
34
|
.app[data-shell="glass"] .studio-agent-inspector .agent-status-dot { display: none; }
|
|
28
35
|
.app[data-shell="glass"] .studio-agent-inspector .agent-icon-button {
|
|
29
36
|
display: grid;
|
|
@@ -227,7 +234,9 @@
|
|
|
227
234
|
font: 400 12.5px/1.5 var(--sans);
|
|
228
235
|
}
|
|
229
236
|
.app[data-shell="glass"] .studio-agent-inspector .agent-composer textarea::placeholder { color: var(--text-3); }
|
|
230
|
-
|
|
237
|
+
/* A narrow dock wraps the controls to a second row instead of crushing the
|
|
238
|
+
model name to its caret or pushing Send past the field's edge. */
|
|
239
|
+
.app[data-shell="glass"] .studio-agent-inspector .agent-composer-controls { flex-wrap: wrap; gap: 4px 2px; margin: 4px 0 0 -6px; }
|
|
231
240
|
.app[data-shell="glass"] .studio-agent-inspector .agent-attach-chip {
|
|
232
241
|
display: grid;
|
|
233
242
|
place-items: center;
|
|
@@ -248,9 +257,9 @@
|
|
|
248
257
|
.app[data-shell="glass"] .studio-agent-inspector .agent-model-select {
|
|
249
258
|
-webkit-appearance: none;
|
|
250
259
|
appearance: none;
|
|
251
|
-
flex:
|
|
252
|
-
min-width:
|
|
253
|
-
max-width:
|
|
260
|
+
flex: 1 1 96px;
|
|
261
|
+
min-width: 96px;
|
|
262
|
+
max-width: none;
|
|
254
263
|
height: 26px;
|
|
255
264
|
padding: 0 18px 0 8px;
|
|
256
265
|
border: 0;
|
|
@@ -262,7 +271,7 @@
|
|
|
262
271
|
cursor: pointer;
|
|
263
272
|
}
|
|
264
273
|
.app[data-shell="glass"] .studio-agent-inspector .agent-model-select:hover { background-color: var(--chip-fill); color: var(--text-1); }
|
|
265
|
-
.app[data-shell="glass"] .studio-agent-inspector .agent-effort-select { flex: none; max-width: none; }
|
|
274
|
+
.app[data-shell="glass"] .studio-agent-inspector .agent-effort-select { flex: none; min-width: 0; max-width: none; }
|
|
266
275
|
.app[data-shell="glass"] .studio-agent-inspector .agent-model-select optgroup,
|
|
267
276
|
.app[data-shell="glass"] .studio-agent-inspector .agent-model-select option { background: var(--surface-raised); color: var(--text-1); }
|
|
268
277
|
.app[data-shell="glass"] .studio-agent-inspector .agent-send {
|
|
@@ -293,4 +302,8 @@
|
|
|
293
302
|
|
|
294
303
|
/* Provider keys: the same quiet rows. */
|
|
295
304
|
.app[data-shell="glass"] .studio-agent-inspector .agent-keys { margin: 0 10px 8px; border: 0; border-radius: 12px; background: var(--card-fill); box-shadow: var(--card-ring); }
|
|
305
|
+
/* Connect a model takes the panel body while it is open: one scroll, and no
|
|
306
|
+
second "Connect a model" card showing through behind it. */
|
|
307
|
+
.app[data-shell="glass"] .studio-agent-inspector .agent-login { flex: 1 1 auto; min-height: 0; max-height: none; }
|
|
308
|
+
.app[data-shell="glass"] .studio-agent-inspector .agent-login ~ .agent-transcript { display: none; }
|
|
296
309
|
.app[data-shell="glass"] .studio-agent-inspector .agent-key-input { border: 0; border-radius: 8px; background: var(--field-fill); color: var(--text-1); }
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// The Details panel's selection header: the selected item's name and its
|
|
2
|
+
// "Kind · detail" type line.
|
|
3
|
+
import { ko } from "../locale.js";
|
|
4
|
+
import { sceneObjectNameDisplayKo, HIERARCHY_INSPECTOR_TITLES, CHARACTER_MODEL_LABELS } from "../app-stage.jsx";
|
|
5
|
+
import { CUTOUT_KIND, EMPTY_KIND, SCULPT_KIND } from "../scene-objects.js";
|
|
6
|
+
import { LIGHT_KIND } from "../object-look.js";
|
|
7
|
+
|
|
8
|
+
const characterIndexForRow = (rowId, characters) => rowId === "characterA" ? 0
|
|
9
|
+
: rowId === "characterB" ? 1
|
|
10
|
+
: characters.findIndex((entry) => `character:${entry.id}` === rowId);
|
|
11
|
+
const characterTitle = (index) => ko(`Character ${index + 1}`, `인물 ${index + 1}`);
|
|
12
|
+
|
|
13
|
+
/** The 2a selection header: the selected item's name and a "Kind · detail"
|
|
14
|
+
* type line. Null when nothing that owns settings is selected. */
|
|
15
|
+
export function detailsSelection({ selectedHierarchyId: id, selectedSceneObject, rigSelection, characters, shot, inspectorHasContent }) {
|
|
16
|
+
if (!inspectorHasContent) return null;
|
|
17
|
+
if (selectedSceneObject) {
|
|
18
|
+
const { renderer, light } = selectedSceneObject;
|
|
19
|
+
if (renderer === LIGHT_KIND) return { name: sceneObjectNameDisplayKo(selectedSceneObject.name), type: `${ko("Light", "조명")} · ${light?.type === "spot" ? ko("Spot", "스포트") : ko("Point", "점")}` };
|
|
20
|
+
const kind = renderer === CUTOUT_KIND ? ko("Cutout", "컷아웃") : renderer === EMPTY_KIND ? ko("Empty", "빈 오브젝트") : renderer === SCULPT_KIND ? ko("Sculpt", "조형") : ko("Mesh", "메시");
|
|
21
|
+
return { name: sceneObjectNameDisplayKo(selectedSceneObject.name), type: `${renderer === EMPTY_KIND ? ko("Node", "노드") : ko("Prop", "소품")} · ${kind}` };
|
|
22
|
+
}
|
|
23
|
+
if (rigSelection) {
|
|
24
|
+
const index = characterIndexForRow(rigSelection.rowId, characters);
|
|
25
|
+
const kind = rigSelection.token === "rig" ? ko("Rig", "리그") : ko("Bone", "본");
|
|
26
|
+
return { name: HIERARCHY_INSPECTOR_TITLES[rigSelection.token] ?? kind, type: index >= 0 ? `${kind} · ${characterTitle(index)}` : kind };
|
|
27
|
+
}
|
|
28
|
+
if (id === "camera") return { name: HIERARCHY_INSPECTOR_TITLES.camera, type: `${ko("Camera", "카메라")} · ${shot.focalMm}mm` };
|
|
29
|
+
if (id === "characterA" || id === "characterB" || id.startsWith("character:")) {
|
|
30
|
+
const index = characterIndexForRow(id, characters);
|
|
31
|
+
const model = CHARACTER_MODEL_LABELS[characters[index]?.model];
|
|
32
|
+
return { name: characterTitle(Math.max(index, 0)), type: model ? `${ko("Character", "인물")} · ${model}` : ko("Character", "인물") };
|
|
33
|
+
}
|
|
34
|
+
const types = {
|
|
35
|
+
shot: ko("Scene", "장면"),
|
|
36
|
+
light: ko("Light", "조명"),
|
|
37
|
+
characters: ko("Folder", "폴더"),
|
|
38
|
+
environment: ko("Environment", "환경"),
|
|
39
|
+
props: ko("Folder", "폴더"),
|
|
40
|
+
};
|
|
41
|
+
return { name: HIERARCHY_INSPECTOR_TITLES[id] ?? ko("Selection", "선택 항목"), type: types[id] ?? "" };
|
|
42
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* The View menu's Ghosts group (GhostsMenuGroup.jsx): two colour chips in the heading and
|
|
2
|
+
compact number steppers that keep the 24px menu rows. */
|
|
3
|
+
.ghosts-menu .view-menu-label { display: flex; align-items: center; gap: 4px; }
|
|
4
|
+
.ghosts-menu .ghost-swatch { display: inline-block; width: 8px; height: 8px; border-radius: 2px; opacity: 0.8; }
|
|
5
|
+
.ghosts-menu .ghost-swatch:first-of-type { margin-left: 4px; }
|
|
6
|
+
.ghosts-menu .view-menu-item.ghost-stepper { cursor: default; }
|
|
7
|
+
.ghosts-menu .ghost-stepper.disabled { opacity: 0.45; }
|
|
8
|
+
.ghosts-menu .ghost-stepper-label { flex: 1; }
|
|
9
|
+
.ghosts-menu .ghost-stepper button {
|
|
10
|
+
width: 18px;
|
|
11
|
+
height: 18px;
|
|
12
|
+
padding: 0;
|
|
13
|
+
border: 1px solid var(--row-divider, var(--line));
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
background: none;
|
|
16
|
+
color: inherit;
|
|
17
|
+
font: inherit;
|
|
18
|
+
line-height: 1;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
}
|
|
21
|
+
.ghosts-menu .ghost-stepper button:disabled { cursor: default; opacity: 0.5; }
|
|
22
|
+
.ghosts-menu .ghost-stepper-value { min-width: 16px; text-align: center; font-variant-numeric: tabular-nums; }
|
|
@@ -431,9 +431,9 @@
|
|
|
431
431
|
--tl-ruler-height: 24px;
|
|
432
432
|
--tl-track-row-height: 22px;
|
|
433
433
|
--tl-track-group-height: 66px;
|
|
434
|
-
/* The surface is exactly its rows (ruler +
|
|
434
|
+
/* The surface is exactly its rows (ruler + 1 lane + 2 lane groups), so it
|
|
435
435
|
never asks the body for more height than the dock gives it. */
|
|
436
|
-
--tl-surface-height: calc(var(--tl-ruler-height) + var(--tl-track-row-height)
|
|
436
|
+
--tl-surface-height: calc(var(--tl-ruler-height) + var(--tl-track-row-height) + var(--tl-track-group-height) * 2);
|
|
437
437
|
--tl-camera-bar-height: 28px;
|
|
438
438
|
--tl-track-tree-width: 170px;
|
|
439
439
|
--tl-clip-inset: 4px;
|
|
@@ -446,7 +446,8 @@
|
|
|
446
446
|
height: auto;
|
|
447
447
|
min-height: 48px;
|
|
448
448
|
gap: 12px;
|
|
449
|
-
|
|
449
|
+
/* The right inset keeps the pinned collapse toggle clear of the controls. */
|
|
450
|
+
padding: 0 52px 0 16px;
|
|
450
451
|
border: 0;
|
|
451
452
|
background: none;
|
|
452
453
|
}
|
|
@@ -500,6 +501,31 @@
|
|
|
500
501
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-seq-action:hover:not(:disabled),
|
|
501
502
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-head-group .tl-btn:hover:not(:disabled) { background: var(--chip-fill); color: var(--text-1); }
|
|
502
503
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-seq-action:disabled { opacity: .4; }
|
|
504
|
+
/* The take's segment speed sits in the same quiet chip grammar as its neighbours. */
|
|
505
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor {
|
|
506
|
+
min-width: 0;
|
|
507
|
+
height: 26px;
|
|
508
|
+
gap: 6px;
|
|
509
|
+
padding: 0 8px;
|
|
510
|
+
border: 0;
|
|
511
|
+
border-radius: 13px;
|
|
512
|
+
background: none;
|
|
513
|
+
color: var(--label);
|
|
514
|
+
font: 500 12px var(--sans);
|
|
515
|
+
}
|
|
516
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor > span { font-weight: 500; }
|
|
517
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor input[type="range"] { width: 72px; accent-color: var(--primary-fill, var(--select)); }
|
|
518
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor input[type="number"] {
|
|
519
|
+
width: 40px;
|
|
520
|
+
height: 22px;
|
|
521
|
+
padding: 0 4px;
|
|
522
|
+
border: 0;
|
|
523
|
+
border-radius: 6px;
|
|
524
|
+
background: var(--chip-fill);
|
|
525
|
+
color: var(--text-1);
|
|
526
|
+
font: 500 12px var(--sans);
|
|
527
|
+
}
|
|
528
|
+
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-motion-speed-editor small { color: var(--label); }
|
|
503
529
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-btn.wp.on { background: var(--seg-on); box-shadow: var(--seg-on-shadow); color: var(--seg-on-text); }
|
|
504
530
|
.app[data-shell="glass"]:not([data-embed-mode]) .v2-sequencer .tl-badge {
|
|
505
531
|
height: 22px;
|
|
@@ -381,6 +381,9 @@
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
.v2-preferences .v2-preferences__language {
|
|
384
|
+
display: inline-flex;
|
|
385
|
+
align-items: center;
|
|
386
|
+
justify-content: center;
|
|
384
387
|
height: var(--h-control, 28px);
|
|
385
388
|
padding: 0 var(--sp-2, 12px);
|
|
386
389
|
border: 0;
|
|
@@ -512,6 +515,8 @@
|
|
|
512
515
|
color: var(--text-3, #636369);
|
|
513
516
|
font-size: var(--prefs-secondary-size, 11px);
|
|
514
517
|
font-weight: 500;
|
|
518
|
+
letter-spacing: 0;
|
|
519
|
+
text-transform: none;
|
|
515
520
|
}
|
|
516
521
|
|
|
517
522
|
.v2-preferences .v2-preferences__help button {
|
|
@@ -519,7 +524,7 @@
|
|
|
519
524
|
padding: 0 var(--sp-2, 12px);
|
|
520
525
|
border: 0;
|
|
521
526
|
border-radius: var(--r-1, 4px);
|
|
522
|
-
background:
|
|
527
|
+
background: var(--field-fill, var(--surface-raised, #1e1e21));
|
|
523
528
|
color: var(--text-2, #9b9ba1);
|
|
524
529
|
font: inherit;
|
|
525
530
|
font-size: var(--prefs-secondary-size, 11px);
|
package/src/shot-authoring.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { createTiming, timingIsFlat } from "./speed-envelope.js";
|
|
8
8
|
import { createShot } from "./cuts.js";
|
|
9
|
+
import { railShotFields } from "./camera-block.js";
|
|
9
10
|
import { normalizeStableItems } from "./stable-items.js";
|
|
10
11
|
import { VIDEO_MODEL_PRESETS } from "./model-presets.js";
|
|
11
12
|
import { elementByPath } from "./studio-elements.js";
|
|
@@ -110,7 +111,7 @@ const FOLLOW_BOUNDS = {
|
|
|
110
111
|
height: [0.2, Number.POSITIVE_INFINITY],
|
|
111
112
|
response: [0.1, 3],
|
|
112
113
|
lead: [0, 1],
|
|
113
|
-
maxDollySpeed: [0.2,
|
|
114
|
+
maxDollySpeed: [0.2, 40],
|
|
114
115
|
pitchOffsetDeg: [-170, 170],
|
|
115
116
|
orbitOffsetDeg: [-180, 180],
|
|
116
117
|
};
|
|
@@ -299,6 +300,7 @@ function repairCamera(value) {
|
|
|
299
300
|
// The dolly's speed curve rides the rail the same way; the envelope
|
|
300
301
|
// module owns its repair (parse-don't-validate, flat heals to null).
|
|
301
302
|
dollyTiming: cameraRail ? repairDollyTiming(source.dollyTiming) : null,
|
|
303
|
+
...railShotFields(source, cameraRail),
|
|
302
304
|
};
|
|
303
305
|
}
|
|
304
306
|
|
|
@@ -310,12 +312,7 @@ function repairDollyTiming(value) {
|
|
|
310
312
|
function migratedCamera(followCam, cameraRail, railFollow = null) {
|
|
311
313
|
const rail = repairRail(cameraRail);
|
|
312
314
|
const enabled = followCam?.enabled === true;
|
|
313
|
-
return repairCamera({
|
|
314
|
-
mode: enabled ? (rail ? "rail" : "follow") : "keys",
|
|
315
|
-
followCam,
|
|
316
|
-
cameraRail: rail,
|
|
317
|
-
railFollow,
|
|
318
|
-
});
|
|
315
|
+
return repairCamera({ mode: enabled ? (rail ? "rail" : "follow") : "keys", followCam, cameraRail: rail, railFollow });
|
|
319
316
|
}
|
|
320
317
|
|
|
321
318
|
function repairShared(parsed, frameCount, ids) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Soft key shadows in the same pass. three r185's PCF filter takes five taps
|
|
2
|
+
// on a Vogel disk of shadow.radius texels, rotated per pixel by interleaved
|
|
3
|
+
// gradient noise; past a radius of about two texels those five taps show as a
|
|
4
|
+
// cross-hatched grain over every penumbra. A wider radius (stage.lighting
|
|
5
|
+
// shadowSoftness) therefore takes SOFT_SHADOW_TAPS taps instead, which keeps
|
|
6
|
+
// the same disk and noise rotation but averages the grain away. Radius 1 —
|
|
7
|
+
// every stage before the look was authorable — runs the original five-tap code
|
|
8
|
+
// unchanged, so studio frames stay pixel-identical.
|
|
9
|
+
//
|
|
10
|
+
// Evaluated against the alternatives: PCFSoftShadowMap is deprecated in r185
|
|
11
|
+
// (it falls back to PCF); VSMShadowMap blurs smoothly but loses contact shadows
|
|
12
|
+
// (a leg's shadow on a box beside it vanished), cannot shadow point lights, and
|
|
13
|
+
// is renderer-wide, so it would restyle the studio look too.
|
|
14
|
+
import { ShaderChunk } from "three";
|
|
15
|
+
|
|
16
|
+
const SOFT_SHADOW_TAPS = 16;
|
|
17
|
+
const tap = (index) => `texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( ${index}, 5, phi ) * radius, shadowCoord.z ) )`;
|
|
18
|
+
const FIVE_TAPS = `shadow = (\n${[0, 1, 2, 3, 4].map((index) => `\t\t\t\t\t${tap(index)}`).join(" +\n")}\n\t\t\t\t) * 0.2;`;
|
|
19
|
+
const SOFT_TAPS = `if ( shadowRadius <= 1.0 ) {
|
|
20
|
+
${FIVE_TAPS}
|
|
21
|
+
} else {
|
|
22
|
+
shadow = 0.0;
|
|
23
|
+
for ( int i = 0; i < ${SOFT_SHADOW_TAPS}; i ++ ) shadow += texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( i, ${SOFT_SHADOW_TAPS}, phi ) * radius, shadowCoord.z ) );
|
|
24
|
+
shadow /= ${SOFT_SHADOW_TAPS}.0;
|
|
25
|
+
}`;
|
|
26
|
+
|
|
27
|
+
/** Patch the directional/spot PCF filter once; answers whether the soft path is in. */
|
|
28
|
+
export function installSoftShadows(chunks = ShaderChunk) {
|
|
29
|
+
const source = chunks.shadowmap_pars_fragment;
|
|
30
|
+
if (source.includes(SOFT_TAPS)) return true;
|
|
31
|
+
// A three upgrade that rewrites the filter leaves the stock one in place.
|
|
32
|
+
if (!source.includes(FIVE_TAPS)) return false;
|
|
33
|
+
chunks.shadowmap_pars_fragment = source.replace(FIVE_TAPS, SOFT_TAPS);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
installSoftShadows();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { SCENE_ATTACH_BONES } from "./scene-objects.js";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { normalizeBoneName } from "./poses.js";
|
|
5
5
|
|
|
6
6
|
/** The rig rows that ARE an attach frame: `rig.<track id>`, the same camel
|
|
@@ -8,14 +8,14 @@ import { normalizeBoneName } from "./poses.js";
|
|
|
8
8
|
* rig.leftArm …) name a limb, not a frame, so they are deliberately absent. */
|
|
9
9
|
export const ATTACH_BONE_ROWS = new Map(SCENE_ATTACH_BONES.map((bone) => [`rig.${bone}`, bone]));
|
|
10
10
|
|
|
11
|
-
/** Attach track id -> the Mixamo bone carrying that frame on the shipped rigs.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
/** Attach track id -> the Mixamo bone carrying that frame on the shipped rigs. */
|
|
12
|
+
const MIXAMO_ATTACH_BONES = {
|
|
13
|
+
hips: "Hips", spine: "Spine", chest: "Spine1", neck: "Neck", head: "Head",
|
|
14
|
+
leftShoulder: "LeftArm", leftElbow: "LeftForeArm", leftHand: "LeftHand",
|
|
15
|
+
rightShoulder: "RightArm", rightElbow: "RightForeArm", rightHand: "RightHand",
|
|
16
|
+
leftKnee: "LeftLeg", leftFoot: "LeftFoot", rightKnee: "RightLeg", rightFoot: "RightFoot",
|
|
17
|
+
};
|
|
18
|
+
export const ATTACH_BONE_NAMES = Object.fromEntries(SCENE_ATTACH_BONES.map((bone) => [bone, MIXAMO_ATTACH_BONES[bone]]));
|
|
19
19
|
|
|
20
20
|
// One scratch set for the whole module: resolving a frame runs per attached
|
|
21
21
|
// prop per frame and must never allocate.
|
|
@@ -36,7 +36,7 @@ export const placeEuler = new THREE.Euler();
|
|
|
36
36
|
|
|
37
37
|
/** The bone a rig offers under `mixamoName`, by the project's matching rule
|
|
38
38
|
* (normalised names equal, or one a suffix of the other; first depth-first
|
|
39
|
-
* match wins — poses.js and
|
|
39
|
+
* match wins — poses.js and motion3/playback.js agree). Cached per rig: this is
|
|
40
40
|
* asked once per attached prop per rendered frame. */
|
|
41
41
|
export const attachBoneCache = new WeakMap();
|
|
42
42
|
export function attachBoneOf(rig, mixamoName) {
|
|
@@ -65,8 +65,8 @@ export function attachBoneOf(rig, mixamoName) {
|
|
|
65
65
|
* A carried prop takes the bone's place and facing; its size stays its own.
|
|
66
66
|
*
|
|
67
67
|
* `bone === null` is the character's animated ROOT: the hips' travel (during
|
|
68
|
-
* playback the
|
|
69
|
-
*
|
|
68
|
+
* playback the hips travel lives in the bones — see motion3/playback.js)
|
|
69
|
+
* carried at the character's own yaw, so a prop dropped on
|
|
70
70
|
* the character walks with the body instead of rolling with the hips.
|
|
71
71
|
*/
|
|
72
72
|
export function attachFrameMatrix(rig, bone, out = new THREE.Matrix4()) {
|
|
@@ -212,9 +212,7 @@ export function FollowCamRig({ enabled, frame, frameRef, scene, shot, camRef, lo
|
|
|
212
212
|
applied.current = null;
|
|
213
213
|
if (enabled) invalidate();
|
|
214
214
|
}, [scene, shot, enabled, invalidate]);
|
|
215
|
-
useEffect(() => {
|
|
216
|
-
if (enabled) invalidate();
|
|
217
|
-
}, [frame, enabled, invalidate]);
|
|
215
|
+
useEffect(() => { if (enabled) invalidate(); }, [frame, enabled, invalidate]);
|
|
218
216
|
useFrame(() => {
|
|
219
217
|
if (!enabled) return;
|
|
220
218
|
if (isInterrupted?.()) return; // the user is flying; yield until released
|
|
@@ -227,6 +225,8 @@ export function FollowCamRig({ enabled, frame, frameRef, scene, shot, camRef, lo
|
|
|
227
225
|
cam.position.set(sample.pos.x, sample.pos.y, sample.pos.z);
|
|
228
226
|
look.current.yaw = sample.yaw;
|
|
229
227
|
look.current.pitch = sample.pitch;
|
|
228
|
+
// A rail with a lens of its own carries it; otherwise this is the scene lens.
|
|
229
|
+
if (Math.abs(cam.fov - sample.fovDeg) > 1e-3) { cam.fov = sample.fovDeg; cam.updateProjectionMatrix(); }
|
|
230
230
|
invalidate();
|
|
231
231
|
});
|
|
232
232
|
return null;
|
package/src/stage-capture.jsx
CHANGED
|
@@ -25,7 +25,9 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
|
|
|
25
25
|
useEffect(() => {
|
|
26
26
|
// Each attempt owns its target independently of the live output size.
|
|
27
27
|
// Resizing the editor cannot dispose an in-flight export's resources.
|
|
28
|
-
|
|
28
|
+
// `camera` makes the camera of each render: a clone of the shot camera unless a caller
|
|
29
|
+
// (renderView) brings its own; the shot camera itself is never moved.
|
|
30
|
+
function createExportCapture({ width, height }, camera = () => camRef.current?.clone()) {
|
|
29
31
|
const target = new THREE.WebGLRenderTarget(width, height, {
|
|
30
32
|
colorSpace: THREE.SRGBColorSpace,
|
|
31
33
|
samples: 4,
|
|
@@ -35,9 +37,8 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
|
|
|
35
37
|
scene,
|
|
36
38
|
dispose: () => target.dispose(),
|
|
37
39
|
render() {
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
40
|
-
const cam = source.clone();
|
|
40
|
+
const cam = camera();
|
|
41
|
+
if (!cam) return null;
|
|
41
42
|
// the transform gizmo is UI: it never reaches an exported frame
|
|
42
43
|
cam.layers.disable(GIZMO_LAYER);
|
|
43
44
|
// QA hook: the layer mask the export camera actually renders
|
|
@@ -53,13 +54,27 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
|
|
|
53
54
|
// exported frame wants the opposite: the horizon IS the vanishing
|
|
54
55
|
// point, and without it the floor has no far edge to read depth
|
|
55
56
|
// against. Push the falloff back for this draw only, then restore
|
|
56
|
-
// it so the viewport is untouched.
|
|
57
|
+
// it so the viewport is untouched. Haze (stage.lighting.fog, set by
|
|
58
|
+
// StageAtmosphere) is part of the look, so it brings its own range.
|
|
57
59
|
const fog = scene.fog;
|
|
58
60
|
const fogNear = fog?.near;
|
|
59
61
|
const fogFar = fog?.far;
|
|
62
|
+
const look = scene.userData.stageCapture;
|
|
60
63
|
if (fog) {
|
|
61
|
-
fog.near = CAPTURE_FOG_NEAR;
|
|
62
|
-
fog.far = CAPTURE_FOG_FAR;
|
|
64
|
+
fog.near = look?.fog?.near ?? CAPTURE_FOG_NEAR;
|
|
65
|
+
fog.far = look?.fog?.far ?? CAPTURE_FOG_FAR;
|
|
66
|
+
}
|
|
67
|
+
// three tone-maps only the canvas, never a render target, so the
|
|
68
|
+
// viewport's exposure reaches an export as light: every light, and
|
|
69
|
+
// the environment light, is scaled by it for this draw and put back after.
|
|
70
|
+
const scaled = [], environmentIntensity = scene.environmentIntensity, backgroundIntensity = scene.backgroundIntensity, fogColor = fog?.color.clone();
|
|
71
|
+
if (look && look.exposure !== 1) scene.traverse((node) => { if (node.isLight) scaled.push([node, node.intensity]); });
|
|
72
|
+
for (const [light, intensity] of scaled) light.intensity = intensity * look.exposure;
|
|
73
|
+
if (look && look.exposure !== 1) scene.environmentIntensity = environmentIntensity * look.exposure;
|
|
74
|
+
// An HDR backdrop (stage.lighting.hdrBackground) is light too, and so is the horizon the deck fades into.
|
|
75
|
+
if (look?.backdrop && look.exposure !== 1) {
|
|
76
|
+
scene.backgroundIntensity = backgroundIntensity * look.exposure;
|
|
77
|
+
fog?.color.multiplyScalar(look.exposure);
|
|
63
78
|
}
|
|
64
79
|
try {
|
|
65
80
|
gl.setRenderTarget(target);
|
|
@@ -71,12 +86,31 @@ export function CaptureRig({ apiRef, camRef, width = CAPTURE_W, height = CAPTURE
|
|
|
71
86
|
fog.near = fogNear;
|
|
72
87
|
fog.far = fogFar;
|
|
73
88
|
}
|
|
89
|
+
for (const [light, intensity] of scaled) light.intensity = intensity;
|
|
90
|
+
scene.environmentIntensity = environmentIntensity;
|
|
91
|
+
scene.backgroundIntensity = backgroundIntensity;
|
|
92
|
+
if (fogColor) fog.color.copy(fogColor);
|
|
74
93
|
}
|
|
75
94
|
return buffer;
|
|
76
95
|
},
|
|
77
96
|
};
|
|
78
97
|
}
|
|
79
|
-
|
|
98
|
+
// verify_result's own views (src/motion3/views.js): one read-back, rows bottom-up, from a
|
|
99
|
+
// camera at eye with quaternion [x, y, z, w] and a vertical fov, on a target of its own size.
|
|
100
|
+
function renderView({ eye, quaternion, fovDeg, output }) {
|
|
101
|
+
const own = createExportCapture(output, () => {
|
|
102
|
+
const source = camRef.current;
|
|
103
|
+
if (!source) return null;
|
|
104
|
+
const cam = source.clone();
|
|
105
|
+
cam.clearViewOffset();
|
|
106
|
+
cam.position.set(...eye);
|
|
107
|
+
cam.quaternion.set(...quaternion);
|
|
108
|
+
cam.fov = fovDeg;
|
|
109
|
+
return cam;
|
|
110
|
+
});
|
|
111
|
+
try { return own.render(); } finally { own.dispose(); }
|
|
112
|
+
}
|
|
113
|
+
const api = { ...createExportCapture({ width, height }), createExportCapture, renderView };
|
|
80
114
|
apiRef.current = api;
|
|
81
115
|
if (width === MCP_CAPTURE_W && height === MCP_CAPTURE_H) {
|
|
82
116
|
window.__cozyclayMcpCaptureReady = true;
|