cozyclay 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +40 -113
- package/bin/agent/agent-runner.mjs +9 -10
- package/bin/agent/cliproxy-provider.mjs +135 -0
- package/bin/agent/credential-store.mjs +30 -7
- package/bin/agent/pi-tools.mjs +4 -1
- package/bin/agent/provider-keys.mjs +32 -0
- package/bin/agent/provider-login.mjs +110 -0
- package/bin/agent/provider-routes.mjs +99 -0
- package/bin/agent/providers.mjs +19 -97
- package/bin/agent/script-tool.mjs +17 -4
- package/bin/agent/studio-motion-reference.mjs +23 -0
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-rebase-text.mjs +32 -0
- package/bin/agent/studio-rebase.mjs +26 -39
- package/bin/agent/studio-tools.mjs +9 -28
- package/bin/agent/tool-arguments.mjs +49 -0
- package/bin/agent/turn-frames.mjs +66 -0
- package/bin/codex-auth.mjs +9 -2
- package/bin/cozyclay.mjs +10 -116
- package/bin/live/cli.mjs +22 -6
- package/bin/mcp-runtime.mjs +2 -12
- package/bin/package-signature.mjs +0 -4
- package/dist/app/index.html +7 -6
- package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
- package/dist/assets/analytics-C9sUnndd.js +1 -0
- package/dist/assets/app-CCh--1Hc.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-BlT33CGf.js → first-shot-handoff-CC4xe4HM.js} +1 -1
- package/dist/assets/{landing-BSesrCpL.js → landing-DjHD8u7k.js} +1 -1
- package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-C4yKH1p4.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +3 -3
- package/dist/llms.txt +14 -0
- 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 +174 -2639
- package/src/agent-progress.js +79 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +5 -0
- package/src/app-stage.jsx +2 -34
- package/src/asset-pane.jsx +6 -5
- package/src/camera-block.js +21 -0
- package/src/camera-direction.js +120 -0
- package/src/character-kind.js +3 -9
- package/src/command-bus.js +8 -6
- package/src/commands/cast.js +5 -34
- package/src/commands/elements/character.js +1 -1
- package/src/commands/elements/motion.js +1 -6
- package/src/commands/elements/object.js +6 -2
- package/src/commands/elements/shot.js +4 -1
- package/src/commands/elements.js +38 -14
- package/src/commands/index.js +3 -1
- package/src/commands/kits.js +37 -0
- package/src/commands/motion-timing.js +57 -0
- package/src/commands/motion.js +9 -152
- package/src/commands/motion3-compile.js +65 -0
- package/src/commands/motion3.js +207 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +49 -11
- package/src/commands/stage.js +14 -1
- package/src/commands/view.js +4 -1
- package/src/document-mirrors.js +42 -0
- package/src/document-store.js +4 -0
- package/src/domains/cast.js +19 -194
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion/take-source.js +51 -0
- package/src/domains/motion.js +60 -1838
- package/src/domains/scenes.js +12 -55
- package/src/domains/shots.js +2 -2
- package/src/domains/stage.js +4 -2
- package/src/draft-ghost.js +46 -0
- package/src/draft-ghost.jsx +129 -0
- package/src/dualview.jsx +4 -3
- package/src/effects/EffectsLayer.jsx +112 -0
- package/src/effects/effect-meshes.js +232 -0
- package/src/effects/effect-record.js +103 -0
- package/src/effects/emitter.js +59 -0
- package/src/effects/simulate.js +261 -0
- package/src/effects/state.js +59 -0
- package/src/execution-telemetry.js +2 -3
- package/src/first-success-guide.jsx +5 -5
- package/src/ghost-set.js +257 -0
- package/src/held-object-edit.jsx +113 -0
- package/src/held-object-pose.js +175 -0
- package/src/hierarchy-model.js +1 -1
- package/src/hierarchy-panel.jsx +1 -1
- package/src/imported-mesh.jsx +103 -0
- package/src/kits/held.js +84 -0
- package/src/kits/index.js +70 -0
- package/src/kits/smoking.js +57 -0
- package/src/light-blockers.js +93 -0
- package/src/motion/beat-board-model.js +84 -0
- package/src/motion/beat-board.css +124 -0
- package/src/motion/beat-board.jsx +59 -0
- package/src/motion/center-of-mass.js +66 -0
- package/src/motion/fix-collisions.js +850 -0
- package/src/motion/physics-review.js +118 -0
- package/src/{ardy → motion}/physics-support.js +1 -76
- package/src/motion/rig-snapshot.js +22 -0
- package/src/motion/take-segments.jsx +140 -0
- package/src/{ardy → motion}/timeline-coordinates.js +0 -21
- package/src/{ardy → motion}/timeline.css +1 -2
- package/src/{ardy → motion}/timeline.jsx +48 -419
- package/src/motion/waypoints.js +76 -0
- package/src/motion3/beats.js +83 -0
- package/src/motion3/body.js +158 -0
- package/src/motion3/bones.js +47 -0
- package/src/motion3/carried.js +47 -0
- package/src/motion3/compile-job.js +75 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +105 -0
- package/src/motion3/compiler/arm-orient.js +128 -0
- package/src/motion3/compiler/channels.js +125 -0
- package/src/motion3/compiler/compile.js +205 -0
- package/src/motion3/compiler/gait-rhythm.js +97 -0
- package/src/motion3/compiler/grip.js +171 -0
- package/src/motion3/compiler/head-steady.js +48 -0
- package/src/motion3/compiler/hold.js +134 -0
- package/src/motion3/compiler/idle.js +113 -0
- package/src/motion3/compiler/limbs.js +170 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +162 -0
- package/src/motion3/compiler/quat.js +49 -0
- package/src/motion3/compiler/skeleton.js +74 -0
- package/src/motion3/compiler/validate-common.js +32 -0
- package/src/motion3/compiler/validate-goals.js +118 -0
- package/src/motion3/compiler/validate-objects.js +143 -0
- package/src/motion3/compiler/validate-parts.js +116 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +73 -0
- package/src/motion3/compiler/walk-pelvis.js +275 -0
- package/src/motion3/compiler/walk.js +207 -0
- package/src/motion3/compiler/wrist-clamp.js +32 -0
- package/src/motion3/delta.js +47 -0
- package/src/motion3/describe.js +174 -0
- package/src/motion3/docs.js +27 -0
- package/src/motion3/edit-carry.js +21 -0
- package/src/motion3/fix/ease.js +16 -0
- package/src/motion3/fix/ground.js +37 -0
- package/src/motion3/fix/index.js +52 -0
- package/src/motion3/fix/push.js +71 -0
- package/src/motion3/fix/reach.js +46 -0
- package/src/motion3/fix/retime.js +79 -0
- package/src/motion3/fix/self.js +211 -0
- package/src/motion3/fix/slide.js +70 -0
- package/src/motion3/fix/turn.js +51 -0
- package/src/motion3/follow.js +39 -0
- package/src/motion3/free-motion.js +173 -0
- package/src/motion3/grip-choice.js +130 -0
- package/src/motion3/hold-plan.js +157 -0
- package/src/motion3/json-patch.js +77 -0
- package/src/motion3/key-aim.js +105 -0
- package/src/motion3/key-edit.js +82 -0
- package/src/motion3/lenient.js +127 -0
- package/src/motion3/object-keys.js +236 -0
- package/src/motion3/object-pose.js +182 -0
- package/src/motion3/object-tracks.js +12 -0
- package/src/motion3/pipeline.js +102 -0
- package/src/motion3/playback.js +51 -0
- package/src/motion3/probes.js +91 -0
- package/src/motion3/qa/body-checks.js +34 -0
- package/src/motion3/qa/check-names.js +14 -0
- package/src/motion3/qa/checks.js +121 -0
- package/src/motion3/qa/contact-checks.js +51 -0
- package/src/motion3/qa/explain.js +80 -0
- package/src/motion3/qa/fmt.js +5 -0
- package/src/motion3/qa/foot-checks.js +72 -0
- package/src/motion3/qa/geometry.js +77 -0
- package/src/motion3/qa/goals.js +191 -0
- package/src/motion3/qa/ground.js +60 -0
- package/src/motion3/qa/hints-contact.js +179 -0
- package/src/motion3/qa/hints-goal.js +160 -0
- package/src/motion3/qa/hints-knee.js +24 -0
- package/src/motion3/qa/hints-motion.js +209 -0
- package/src/motion3/qa/hints-object.js +91 -0
- package/src/motion3/qa/index.js +42 -0
- package/src/motion3/qa/key-checks.js +82 -0
- package/src/motion3/qa/near.js +96 -0
- package/src/motion3/qa/object-checks.js +135 -0
- package/src/motion3/qa/patch.js +161 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +218 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +120 -0
- package/src/motion3/repair-tune.js +121 -0
- package/src/motion3/repair.js +83 -0
- package/src/motion3/report.js +67 -0
- package/src/motion3/rigs/index.js +14 -0
- package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/x-bot-tpose.json +1 -0
- package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/y-bot-tpose.json +1 -0
- package/src/motion3/scene.js +60 -0
- package/src/motion3/schema/brief.js +89 -0
- package/src/motion3/schema/fields.js +44 -0
- package/src/motion3/schema/spec-examples.js +46 -0
- package/src/motion3/schema/topics.js +111 -0
- package/src/motion3/schema/types.js +147 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/skills/basic.js +82 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/index.js +83 -0
- package/src/motion3/skills/info.js +65 -0
- package/src/motion3/skills/smoke-kit.js +109 -0
- package/src/motion3/skills/smoke.js +160 -0
- package/src/motion3/spec-store.js +59 -0
- package/src/motion3/take-edit.js +155 -0
- package/src/motion3/take.js +63 -0
- package/src/motion3/timeline.js +127 -0
- package/src/motion3/views.js +121 -0
- package/src/motion3/walk-plan.js +119 -0
- package/src/object-catalog.jsx +7 -1
- package/src/object-colors.js +98 -0
- package/src/object-gizmo-parts.js +115 -0
- package/src/object-gizmo.jsx +37 -122
- package/src/object-glow.js +139 -0
- package/src/object-hidden.js +33 -0
- package/src/object-look.js +196 -0
- package/src/object-size.js +10 -0
- package/src/object-travel.js +71 -6
- package/src/panels/CameraPanel.jsx +7 -7
- package/src/panels/HdrEnvironmentControls.jsx +59 -0
- package/src/panels/LightPanel.jsx +25 -4
- package/src/panels/ObjectLookPanel.jsx +88 -0
- package/src/panels/PoseImagePanel.jsx +1 -1
- package/src/panels/PosePanel.jsx +2 -17
- package/src/panels/RigControlPanel.jsx +5 -53
- package/src/panels/SubjectBox.jsx +4 -1
- package/src/panels/details.css +14 -0
- package/src/posestudio.jsx +4 -27
- package/src/project-browser.jsx +3 -4
- package/src/project-resources.js +18 -31
- package/src/project.js +13 -104
- package/src/props.jsx +25 -280
- package/src/rail-dot-drag.js +23 -0
- package/src/render-passes.js +10 -0
- package/src/resource-status.jsx +1 -0
- package/src/result-modal.jsx +4 -19
- package/src/room.jsx +20 -12
- package/src/scene-assets.js +8 -6
- package/src/scene-light-place.js +72 -0
- package/src/scene-lights.jsx +148 -0
- package/src/scene-objects.js +31 -139
- package/src/scenes.js +15 -105
- package/src/semantic-edit.js +2 -5
- package/src/set-pieces.jsx +183 -0
- package/src/settings-menu.jsx +3 -11
- package/src/shell/BottomDock.jsx +11 -53
- package/src/shell/CompositionGuideButton.jsx +20 -0
- 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/ShotPreviewHeader.jsx +17 -0
- package/src/shell/TopBar.jsx +5 -83
- package/src/shell/ViewportToolbar.jsx +23 -93
- 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/shell/viewport.css +12 -0
- package/src/shot-authoring.js +4 -7
- package/src/soft-shadows.js +37 -0
- package/src/stage-attach-frames.js +12 -12
- package/src/stage-canvas-rigs.jsx +3 -3
- package/src/stage-capture.jsx +42 -8
- package/src/stage-characters.jsx +22 -216
- package/src/stage-editor-gizmos.jsx +6 -6
- package/src/stage-environment.js +93 -0
- package/src/stage-hdr-builtins.js +107 -0
- package/src/stage-hdr-image.js +116 -0
- package/src/stage-hdr-library.js +70 -0
- package/src/stage-hdr-map.js +94 -0
- package/src/stage-hdr.js +130 -0
- package/src/stage-lighting.js +149 -0
- package/src/stage-occlusion.js +210 -0
- package/src/stage-sky.jsx +159 -0
- package/src/stage-startup-defaults.js +5 -9
- package/src/studio-actions.js +12 -14
- package/src/studio-agent-commands.js +46 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +46 -73
- package/src/studio-app-binding.js +29 -45
- package/src/studio-asset-list.js +17 -0
- package/src/studio-contact-sheet.js +37 -5
- package/src/studio-elements.js +27 -7
- package/src/studio-entity-bounds.js +18 -0
- package/src/studio-error-codes.js +8 -0
- package/src/studio-export-framing.js +152 -0
- package/src/studio-lighting-check.js +103 -0
- package/src/studio-motion-visual.js +150 -0
- package/src/studio-schema-errors.js +80 -0
- package/src/studio-support-gap.js +74 -0
- package/src/styles.css +1 -19
- package/src/timeline-defaults.js +5 -0
- package/src/timeline-extent.js +8 -20
- package/src/tutorial-walk.js +17 -0
- package/src/ui-scrub.js +1 -1
- package/src/use-shot-camera-tracks.js +12 -0
- package/src/view-ghosts.js +97 -0
- package/src/view-ghosts.jsx +49 -0
- package/src/workflow/AgentPanel.jsx +47 -166
- package/src/workflow/AgentProgressCard.jsx +107 -0
- package/src/workflow/AgentReplyText.jsx +37 -0
- package/src/workflow/AgentTurnSteps.jsx +84 -0
- package/src/workflow/LoginPanel.jsx +140 -0
- package/src/workflow/WorkflowBuilder.jsx +7 -23
- package/src/workflow/agent-client.js +54 -51
- package/src/workflow/agent-panel.css +71 -1
- package/src/workflow/agent-progress-card.css +167 -0
- package/src/workflow/agent-progress-view.js +47 -0
- package/src/workflow/agent-turn-steps.css +113 -0
- package/src/workflow/agent-turn.js +191 -0
- package/src/workflow/login-client.js +34 -0
- package/src/workflow/motion-input.js +18 -31
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/reply-markdown.js +69 -0
- package/src/workflow/scene-asset-sync.js +8 -8
- package/tools/agent-session-stats.mjs +61 -0
- package/tools/dev-full.mjs +5 -56
- package/tools/eslint-baseline.json +12 -13
- package/tools/headless-studio.mjs +85 -0
- package/tools/knip-baseline.json +0 -179
- package/tools/loc-baseline.json +33 -83
- 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 -124
- package/bin/agent/motion-runtime.mjs +0 -76
- package/dist/ardy/cskel27-rest.json +0 -557
- package/dist/assets/analytics-B41FmPYI.js +0 -1
- package/dist/assets/app-Do-Og5Pu.css +0 -1
- package/dist/assets/app-DwP-tl2x.js +0 -4920
- package/dist/assets/config-Bx7pYsD9.js +0 -1
- package/dist/assets/config-DeoFTYzb.css +0 -1
- package/dist/assets/demo-Dt0qZfS7.js +0 -1
- package/dist/assets/scene-asset-sync-BCWDJB1d.js +0 -19
- package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
- package/dist/assets/ticket-jqMhqL88.js +0 -1
- package/dist/assets/workflow-Br-K7Srs.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 -159
- package/tools/gt-render/camera-math.mjs +0 -276
- package/tools/gt-render/page.mjs +0 -267
- package/tools/gt-render/render.mjs +0 -514
- package/tools/gt-render/scene-box.mjs +0 -31
- package/tools/gt-render/take-transform.mjs +0 -87
- package/tools/kimodo/compare-seam.mjs +0 -108
- package/tools/kimodo/constraints.mjs +0 -244
- package/tools/kimodo/edit.mjs +0 -259
- package/tools/kimodo/effector-constraints.mjs +0 -200
- package/tools/kimodo/generate.mjs +0 -646
- package/tools/kimodo/local-output.mjs +0 -265
- package/tools/kimodo/measure-pose.mjs +0 -65
- package/tools/kimodo/measure-preserve.mjs +0 -899
- package/tools/kimodo/measure-waypoints.mjs +0 -55
- package/tools/kimodo/mlx-generate.py +0 -111
- package/tools/kimodo/pose-constraints.mjs +0 -248
- package/tools/kimodo/preserve-mask.mjs +0 -543
- package/tools/kimodo/read-npz.mjs +0 -189
- package/tools/kimodo/run-edit-on-box.mjs +0 -155
- package/tools/kimodo/run-sequence-on-box.mjs +0 -178
- package/tools/kimodo/runner.mjs +0 -284
- package/tools/kimodo/seam-batch.mjs +0 -77
- package/tools/kimodo/setup-local.mjs +0 -30
- package/tools/kimodo/setup-on-box.sh +0 -339
- package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
- package/tools/morphgs/assets/gen_truth.py +0 -39
- package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
- package/tools/morphgs/assets/playback-check.mjs +0 -30
- package/tools/morphgs/demo-gate.sh +0 -26
- package/tools/morphgs/fbx2morphgs.mjs +0 -68
- package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
- package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
- package/tools/morphgs/setup-on-cluster.sh +0 -126
- package/tools/projflow/driver.py +0 -1069
- package/tools/projflow/generate.mjs +0 -805
- package/tools/projflow/hml22-to-cskel27.mjs +0 -735
- package/tools/projflow/line-edit-job.mjs +0 -547
- package/tools/projflow/replay.mjs +0 -452
- package/tools/projflow/runner.mjs +0 -269
- package/tools/projflow/service.mjs +0 -742
- package/tools/track/DESIGN.md +0 -513
- package/tools/track/backfill-provenance.mjs +0 -116
- package/tools/track/budget.mjs +0 -8
- package/tools/track/check-rig.mjs +0 -209
- package/tools/track/diagnostics.schema.json +0 -60
- package/tools/track/export-rig.mjs +0 -256
- package/tools/track/fallback.mjs +0 -7
- package/tools/track/fk-parity-fixture.mjs +0 -161
- package/tools/track/gate.mjs +0 -349
- package/tools/track/masks.mjs +0 -318
- package/tools/track/metrics.mjs +0 -201
- package/tools/track/publish-obs.mjs +0 -108
- package/tools/track/py/check_env.py +0 -61
- package/tools/track/py/eval_lr.py +0 -229
- package/tools/track/py/lr_viterbi.py +0 -294
- package/tools/track/py/masks.py +0 -405
- package/tools/track/py/objective.py +0 -382
- package/tools/track/py/rig.py +0 -508
- package/tools/track/py/scene.py +0 -326
- package/tools/track/py/test_joint_indices.py +0 -123
- package/tools/track/py/test_lr_viterbi.py +0 -195
- package/tools/track/py/test_masks.py +0 -229
- package/tools/track/py/test_rig.py +0 -288
- package/tools/track/py/test_scene.py +0 -354
- package/tools/track/py/test_track.py +0 -328
- package/tools/track/py/track.py +0 -411
- package/tools/track/remote.mjs +0 -140
- package/tools/track/rig-dump.mjs +0 -227
- package/tools/track/run-box-tests.mjs +0 -14
- package/tools/track/run-box.mjs +0 -168
- package/tools/track/setup-box.sh +0 -59
- package/tools/track/study-2d.mjs +0 -728
- /package/src/{ardy → motion}/collision-blockers.js +0 -0
- /package/src/{ardy → motion}/ground.js +0 -0
- /package/src/{ardy → motion}/ik-drag.js +0 -0
- /package/src/{ardy → motion}/ik-key-json.js +0 -0
- /package/src/{ardy → motion}/ik.js +0 -0
- /package/src/{ardy → motion}/physics-surface.js +0 -0
- /package/src/{ardy → motion}/playback-clock.js +0 -0
- /package/src/{ardy → motion}/range-pin.js +0 -0
package/src/props.jsx
CHANGED
|
@@ -5,204 +5,28 @@
|
|
|
5
5
|
* world" (a car to lean on, to walk past, to frame behind glass) has nothing
|
|
6
6
|
* to work with. These props are built from primitives in the same clay style
|
|
7
7
|
* as the Room and the character tint, so the whole frame stays one
|
|
8
|
-
* consistent maquette.
|
|
9
|
-
*
|
|
8
|
+
* consistent maquette. The hand-built set pieces live in set-pieces.jsx;
|
|
9
|
+
* practical lights and glow in scene-lights.jsx and object-glow.js.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
13
13
|
import { useFrame } from "@react-three/fiber";
|
|
14
14
|
import { objectTransformAt } from "./object-path.js";
|
|
15
|
-
import { sceneObjectCarryMatrixAt, sceneObjectTravelMatrixAt, travelPose } from "./object-travel.js";
|
|
15
|
+
import { sceneObjectCarryMatrixAt, sceneObjectTravelMatrixAt, trackShown, travelPose } from "./object-travel.js";
|
|
16
16
|
import * as THREE from "three";
|
|
17
17
|
import { GIZMO_LAYER } from "./dualview.jsx";
|
|
18
18
|
import { CUTOUT_KIND, MESH_KIND, EMPTY_KIND, EMPTY_MARKER_SIZE, SCULPT_KIND } from "./scene-objects.js";
|
|
19
19
|
import { buildSculptGroup, disposeSculptGroup } from "./sculpt-geometry.js";
|
|
20
20
|
import { subscribeToAssetTexture } from "./scene-asset-cache.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
21
|
+
import { ImportedMesh } from "./imported-mesh.jsx";
|
|
22
|
+
import { EffectMarker, EffectsLayer } from "./effects/EffectsLayer.jsx";
|
|
23
|
+
import { EFFECT_KIND } from "./effects/effect-record.js";
|
|
23
24
|
import { applyPoseFade } from "./pose-fade.js";
|
|
24
25
|
import { coplanarDepthRanks } from "./coplanar-depth.js";
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const CLAY_RIM = "#7c8588";
|
|
30
|
-
const CLAY_GLASS = "#55697a";
|
|
31
|
-
const CLAY_PLANE = "#7896a4";
|
|
32
|
-
const CLAY_PLANE_TRIM = "#e1a849";
|
|
33
|
-
const CLAY_CHAIR = "#b9855d";
|
|
34
|
-
const CLAY_CHAIR_LIGHT = "#cf9d72";
|
|
35
|
-
|
|
36
|
-
function Wheel({ position }) {
|
|
37
|
-
return (
|
|
38
|
-
<group position={position}>
|
|
39
|
-
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
40
|
-
<cylinderGeometry args={[0.33, 0.33, 0.24, 20]} />
|
|
41
|
-
<meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
|
|
42
|
-
</mesh>
|
|
43
|
-
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
44
|
-
<cylinderGeometry args={[0.17, 0.17, 0.26, 16]} />
|
|
45
|
-
<meshStandardMaterial color={CLAY_RIM} roughness={0.5} metalness={0.35} />
|
|
46
|
-
</mesh>
|
|
47
|
-
</group>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* A generic 5-door-ish sedan silhouette, ~4.5 m long. Origin at the centre
|
|
52
|
-
* of the footprint, +Z forward.
|
|
53
|
-
*/
|
|
54
|
-
export function Car({ position = [0, 0, 0], rotY = 0, color = CLAY_CAR, topColor = CLAY_CAR_TOP, autoColor = undefined }) {
|
|
55
|
-
const bodyMaterial = autoColor
|
|
56
|
-
? { ...autoFlat(autoColor) }
|
|
57
|
-
: { color, roughness: 0.55, metalness: 0.25 };
|
|
58
|
-
const topMaterial = autoColor
|
|
59
|
-
? { ...autoFlat(autoColor) }
|
|
60
|
-
: { color: topColor, roughness: 0.5, metalness: 0.2 };
|
|
61
|
-
return (
|
|
62
|
-
<group position={position} rotation={[0, rotY, 0]}>
|
|
63
|
-
<mesh position={[0, 0.62, 0]}>
|
|
64
|
-
<boxGeometry args={[1.78, 0.62, 4.45]} />
|
|
65
|
-
<meshStandardMaterial {...bodyMaterial} />
|
|
66
|
-
</mesh>
|
|
67
|
-
<mesh position={[0, 1.12, -0.15]}>
|
|
68
|
-
<boxGeometry args={[1.58, 0.5, 2.2]} />
|
|
69
|
-
<meshStandardMaterial {...topMaterial} />
|
|
70
|
-
</mesh>
|
|
71
|
-
<mesh position={[0, 1.14, -0.15]}>
|
|
72
|
-
<boxGeometry args={[1.62, 0.3, 1.9]} />
|
|
73
|
-
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
74
|
-
</mesh>
|
|
75
|
-
<mesh position={[0, 1.05, 0.95]} rotation={[0.5, 0, 0]}>
|
|
76
|
-
<boxGeometry args={[1.56, 0.42, 0.08]} />
|
|
77
|
-
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
78
|
-
</mesh>
|
|
79
|
-
<mesh position={[0, 1.05, -1.25]} rotation={[-0.55, 0, 0]}>
|
|
80
|
-
<boxGeometry args={[1.56, 0.42, 0.08]} />
|
|
81
|
-
<meshStandardMaterial color={CLAY_GLASS} roughness={0.15} metalness={0.6} />
|
|
82
|
-
</mesh>
|
|
83
|
-
<Wheel position={[0.82, 0.33, 1.45]} />
|
|
84
|
-
<Wheel position={[-0.82, 0.33, 1.45]} />
|
|
85
|
-
<Wheel position={[0.82, 0.33, -1.45]} />
|
|
86
|
-
<Wheel position={[-0.82, 0.33, -1.45]} />
|
|
87
|
-
</group>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Compact single-engine propeller plane, ~3.4 m wingspan and +Z forward. */
|
|
92
|
-
export function SmallPlane({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
|
|
93
|
-
// Auto-color mode tints the PRIMARY surfaces only (fuselage, wings, trim);
|
|
94
|
-
// glass, tires and rims keep their materials so the silhouette still reads.
|
|
95
|
-
// Each mesh keeps its own hand-tuned roughness when the mode is off.
|
|
96
|
-
const mat = (color, roughness, metalness) =>
|
|
97
|
-
autoColor ? autoFlat(autoColor) : { color, roughness, metalness };
|
|
98
|
-
return (
|
|
99
|
-
<group position={position} rotation={[0, rotY, 0]}>
|
|
100
|
-
<mesh position={[0, 0.76, 0]} rotation={[Math.PI / 2, 0, 0]}>
|
|
101
|
-
<cylinderGeometry args={[0.23, 0.31, 2.75, 16]} />
|
|
102
|
-
<meshStandardMaterial {...mat(CLAY_PLANE, 0.58, 0.18)} />
|
|
103
|
-
</mesh>
|
|
104
|
-
<mesh position={[0, 0.76, 1.55]} rotation={[Math.PI / 2, 0, 0]}>
|
|
105
|
-
<coneGeometry args={[0.23, 0.55, 16]} />
|
|
106
|
-
<meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.52, 0.2)} />
|
|
107
|
-
</mesh>
|
|
108
|
-
|
|
109
|
-
<mesh position={[0, 0.73, 0.15]}>
|
|
110
|
-
<boxGeometry args={[3.4, 0.09, 0.58]} />
|
|
111
|
-
<meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.14)} />
|
|
112
|
-
</mesh>
|
|
113
|
-
<mesh position={[0, 0.84, -1.18]}>
|
|
114
|
-
<boxGeometry args={[1.45, 0.07, 0.38]} />
|
|
115
|
-
<meshStandardMaterial {...mat(CLAY_PLANE_TRIM, 0.62, 0.12)} />
|
|
116
|
-
</mesh>
|
|
117
|
-
<mesh position={[0, 1.08, -1.2]} rotation={[0.22, 0, 0]}>
|
|
118
|
-
<boxGeometry args={[0.08, 0.62, 0.48]} />
|
|
119
|
-
<meshStandardMaterial {...mat(CLAY_PLANE, 0.62, 0.12)} />
|
|
120
|
-
</mesh>
|
|
121
|
-
|
|
122
|
-
<mesh position={[0, 1.02, 0.42]} scale={[0.62, 0.46, 0.9]}>
|
|
123
|
-
<sphereGeometry args={[0.42, 16, 10, 0, Math.PI * 2, 0, Math.PI / 2]} />
|
|
124
|
-
<meshStandardMaterial color={CLAY_GLASS} roughness={0.16} metalness={0.55} />
|
|
125
|
-
</mesh>
|
|
126
|
-
|
|
127
|
-
<group position={[0, 0.76, 1.86]}>
|
|
128
|
-
<mesh rotation={[Math.PI / 2, 0, 0]}>
|
|
129
|
-
<cylinderGeometry args={[0.11, 0.11, 0.2, 12]} />
|
|
130
|
-
<meshStandardMaterial color={CLAY_RIM} roughness={0.45} metalness={0.4} />
|
|
131
|
-
</mesh>
|
|
132
|
-
<mesh position={[0, 0, 0.12]} rotation={[0, 0, 0.28]}>
|
|
133
|
-
<boxGeometry args={[1.25, 0.08, 0.06]} />
|
|
134
|
-
<meshStandardMaterial color={CLAY_TIRE} roughness={0.8} />
|
|
135
|
-
</mesh>
|
|
136
|
-
</group>
|
|
137
|
-
|
|
138
|
-
{[-0.55, 0.55].map((x) => (
|
|
139
|
-
<group key={x} position={[x, 0.2, 0.15]}>
|
|
140
|
-
<mesh position={[0, 0.24, 0]} rotation={[0, 0, x < 0 ? -0.35 : 0.35]}>
|
|
141
|
-
<boxGeometry args={[0.045, 0.55, 0.045]} />
|
|
142
|
-
<meshStandardMaterial color={CLAY_RIM} roughness={0.65} metalness={0.3} />
|
|
143
|
-
</mesh>
|
|
144
|
-
<mesh rotation={[0, 0, Math.PI / 2]}>
|
|
145
|
-
<cylinderGeometry args={[0.16, 0.16, 0.09, 14]} />
|
|
146
|
-
<meshStandardMaterial color={CLAY_TIRE} roughness={0.95} />
|
|
147
|
-
</mesh>
|
|
148
|
-
</group>
|
|
149
|
-
))}
|
|
150
|
-
</group>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function Chair({ position = [0, 0, 0], rotY = 0, autoColor = undefined }) {
|
|
155
|
-
// Auto-color mode tints seat/back and frame together; undefined keeps the
|
|
156
|
-
// hand-picked clay pair exactly as it ships.
|
|
157
|
-
const seat = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR_LIGHT, roughness: 0.86 };
|
|
158
|
-
const frame = autoColor ? autoFlat(autoColor) : { color: CLAY_CHAIR, roughness: 0.9 };
|
|
159
|
-
const legPositions = [
|
|
160
|
-
[-0.24, 0.23, -0.22],
|
|
161
|
-
[0.24, 0.23, -0.22],
|
|
162
|
-
[-0.24, 0.23, 0.22],
|
|
163
|
-
[0.24, 0.23, 0.22],
|
|
164
|
-
];
|
|
165
|
-
return (
|
|
166
|
-
<group position={position} rotation={[0, rotY, 0]} scale={0.9}>
|
|
167
|
-
<mesh position={[0, 0.49, 0]} castShadow receiveShadow>
|
|
168
|
-
<boxGeometry args={[0.6, 0.12, 0.58]} />
|
|
169
|
-
<meshStandardMaterial {...seat} />
|
|
170
|
-
</mesh>
|
|
171
|
-
{legPositions.map((leg, index) => (
|
|
172
|
-
<mesh key={index} position={leg} castShadow receiveShadow>
|
|
173
|
-
<boxGeometry args={[0.09, 0.46, 0.09]} />
|
|
174
|
-
<meshStandardMaterial {...frame} />
|
|
175
|
-
</mesh>
|
|
176
|
-
))}
|
|
177
|
-
<mesh position={[-0.24, 0.92, -0.245]} castShadow receiveShadow>
|
|
178
|
-
<boxGeometry args={[0.09, 0.86, 0.09]} />
|
|
179
|
-
<meshStandardMaterial {...frame} />
|
|
180
|
-
</mesh>
|
|
181
|
-
<mesh position={[0.24, 0.92, -0.245]} castShadow receiveShadow>
|
|
182
|
-
<boxGeometry args={[0.09, 0.86, 0.09]} />
|
|
183
|
-
<meshStandardMaterial {...frame} />
|
|
184
|
-
</mesh>
|
|
185
|
-
<mesh position={[0, 1.08, -0.245]} castShadow receiveShadow>
|
|
186
|
-
<boxGeometry args={[0.52, 0.38, 0.1]} />
|
|
187
|
-
<meshStandardMaterial {...seat} />
|
|
188
|
-
</mesh>
|
|
189
|
-
</group>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* The creatable primitives, Unity's 3D Object menu in clay. Each one is built
|
|
195
|
-
* with its base on the local floor (y = 0), so an object's `y` reads as height
|
|
196
|
-
* above the deck rather than "half of me is underground".
|
|
197
|
-
*/
|
|
198
|
-
// Blender's solid-view response for auto-colored surfaces. Workbench shades
|
|
199
|
-
// with a neutral studio rig, so the derived hue reaches the eye unmultiplied;
|
|
200
|
-
// under our warm key light a plain standard material turns every hue olive.
|
|
201
|
-
// Full roughness kills the specular sheen and a self-light of the same hue
|
|
202
|
-
// lifts the shadow side the way workbench's studio lighting does.
|
|
203
|
-
function autoFlat(hex) {
|
|
204
|
-
return { color: hex, roughness: 1, metalness: 0, emissive: hex, emissiveIntensity: 0.4 };
|
|
205
|
-
}
|
|
26
|
+
import { autoFlat, Car, Chair, SmallPlane } from "./set-pieces.jsx";
|
|
27
|
+
import { LIGHT_KIND, capPracticalShadows } from "./object-look.js";
|
|
28
|
+
import { SceneLight, useLookRefresh } from "./scene-lights.jsx";
|
|
29
|
+
import { placeObjectLook } from "./scene-light-place.js";
|
|
206
30
|
|
|
207
31
|
// Parts of an assembly can share a plane with an earlier part (hood top and
|
|
208
32
|
// grille top). The depth test can't order them and the winner flips as the
|
|
@@ -212,6 +36,11 @@ function depthRankProps(rank) {
|
|
|
212
36
|
return rank > 0 ? { polygonOffset: true, polygonOffsetFactor: -rank, polygonOffsetUnits: -rank } : null;
|
|
213
37
|
}
|
|
214
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The creatable primitives, Unity's 3D Object menu in clay. Each one is built
|
|
41
|
+
* with its base on the local floor (y = 0), so an object's `y` reads as height
|
|
42
|
+
* above the deck rather than "half of me is underground".
|
|
43
|
+
*/
|
|
215
44
|
function Primitive({ kind, color, autoColor, depthRank = 0 }) {
|
|
216
45
|
const side = kind === "plane" ? THREE.DoubleSide : THREE.FrontSide;
|
|
217
46
|
const material = autoColor ? (
|
|
@@ -284,97 +113,6 @@ function useAssetTexture(assetId) {
|
|
|
284
113
|
* missing): blockout grey, because that is exactly what it is again. */
|
|
285
114
|
const MISSING_CUTOUT = "#c2c6c8";
|
|
286
115
|
|
|
287
|
-
/** The parsed GLB for an `assetId`, or null while it loads (or forever, if
|
|
288
|
-
* the blob is gone). The cached graph is the FILE's own pivot and materials;
|
|
289
|
-
* each instance clones, then fits to the stored height. */
|
|
290
|
-
function useMeshScene(assetId) {
|
|
291
|
-
const [scene, setScene] = useState(null);
|
|
292
|
-
useEffect(() => {
|
|
293
|
-
setScene(null);
|
|
294
|
-
if (!assetId) return undefined;
|
|
295
|
-
return subscribeToMeshScene(assetId, setScene);
|
|
296
|
-
}, [assetId]);
|
|
297
|
-
return scene;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function disposeOwnedMaterials(root) {
|
|
301
|
-
if (!root) return;
|
|
302
|
-
root.traverse((node) => {
|
|
303
|
-
if (!node.isMesh || !(node.userData?.clayOwned || node.userData?.instanceOwned)) return;
|
|
304
|
-
const materials = Array.isArray(node.material) ? node.material : [node.material];
|
|
305
|
-
for (const material of materials) material?.dispose?.();
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Clone the cached graph, scale so its bbox height equals the stored
|
|
311
|
-
* `object.height`, and sit the underside on y = 0. The import heuristic
|
|
312
|
-
* already wrote that height — this pass must not re-guess it.
|
|
313
|
-
*
|
|
314
|
-
* Skinned graphs go through `cloneMeshGraph` so a Mixamo-as-statue keeps
|
|
315
|
-
* its bind pose. Clay replaces materials on THIS clone only, so a second
|
|
316
|
-
* instance of the same file can keep the textures from the disk. Every clone
|
|
317
|
-
* owns its materials, so auto-color tints and opacity fades never leak.
|
|
318
|
-
*/
|
|
319
|
-
function instantiateMesh(source, object) {
|
|
320
|
-
const root = cloneMeshGraph(source);
|
|
321
|
-
root.updateMatrixWorld(true);
|
|
322
|
-
const box = new THREE.Box3().setFromObject(root);
|
|
323
|
-
const size = box.getSize(new THREE.Vector3());
|
|
324
|
-
const targetHeight = Number(object.height);
|
|
325
|
-
if (Number.isFinite(targetHeight) && targetHeight > 0 && size.y > 1e-8) {
|
|
326
|
-
root.scale.multiplyScalar(targetHeight / size.y);
|
|
327
|
-
root.updateMatrixWorld(true);
|
|
328
|
-
box.setFromObject(root);
|
|
329
|
-
}
|
|
330
|
-
if (Number.isFinite(box.min.y)) root.position.y -= box.min.y;
|
|
331
|
-
const clay = object.clay === true;
|
|
332
|
-
const clayColor = object.autoColor ?? object.color ?? "#c4b8a8";
|
|
333
|
-
root.traverse((node) => {
|
|
334
|
-
if (node.isLight || node.isCamera) {
|
|
335
|
-
node.visible = false;
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
if (!node.isMesh) return;
|
|
339
|
-
node.castShadow = true;
|
|
340
|
-
node.receiveShadow = true;
|
|
341
|
-
if (clay) {
|
|
342
|
-
const make = () => new THREE.MeshStandardMaterial({ color: clayColor, roughness: 0.9, metalness: 0 });
|
|
343
|
-
for (const material of Array.isArray(node.material) ? node.material : [node.material]) material?.dispose?.();
|
|
344
|
-
node.material = Array.isArray(node.material) ? node.material.map(() => make()) : make();
|
|
345
|
-
node.userData.clayOwned = true;
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
if (!object.autoColor || !node.material) return;
|
|
349
|
-
// cloneMeshGraph already gave this instance its own materials.
|
|
350
|
-
for (const material of Array.isArray(node.material) ? node.material : [node.material]) {
|
|
351
|
-
if (material.color) material.color.set(object.autoColor);
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
return root;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function ImportedMesh({ object }) {
|
|
358
|
-
const source = useMeshScene(object.assetId);
|
|
359
|
-
const root = useMemo(
|
|
360
|
-
() => (source ? instantiateMesh(source, object) : null),
|
|
361
|
-
[source, object.height, object.clay, object.autoColor, object.color],
|
|
362
|
-
);
|
|
363
|
-
useEffect(() => () => disposeOwnedMaterials(root), [root]);
|
|
364
|
-
if (!root) {
|
|
365
|
-
const width = object.footprint?.width ?? 1;
|
|
366
|
-
const depth = object.footprint?.depth ?? 1;
|
|
367
|
-
const height = object.height ?? 1;
|
|
368
|
-
return (
|
|
369
|
-
<mesh position={[0, height / 2, 0]} castShadow receiveShadow>
|
|
370
|
-
<boxGeometry args={[width, height, depth]} />
|
|
371
|
-
<meshStandardMaterial color={MISSING_CUTOUT} roughness={0.92} metalness={0} />
|
|
372
|
-
</mesh>
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
return <primitive object={root} />;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
116
|
/**
|
|
379
117
|
* A cutout: an imported picture standing on a card, the standee a blockout
|
|
380
118
|
* gets instead of a modelled prop.
|
|
@@ -499,6 +237,8 @@ function SceneObjectContent({ object, depthRank = 0 }) {
|
|
|
499
237
|
// override as a cube — file materials are cloned and tinted per instance.
|
|
500
238
|
const { renderer, color, autoColor } = object;
|
|
501
239
|
if (renderer === EMPTY_KIND) return <EmptyMarker />;
|
|
240
|
+
if (renderer === LIGHT_KIND) return <SceneLight object={object} />;
|
|
241
|
+
if (renderer === EFFECT_KIND) return <EffectMarker object={object} />;
|
|
502
242
|
if (renderer === CUTOUT_KIND) return <Cutout object={object} />;
|
|
503
243
|
if (renderer === MESH_KIND) return <ImportedMesh object={object} />;
|
|
504
244
|
if (renderer === SCULPT_KIND) return <Sculpt object={object} depthRank={depthRank} />;
|
|
@@ -517,7 +257,7 @@ function SceneObjectContent({ object, depthRank = 0 }) {
|
|
|
517
257
|
function SelectionBox({ object }) {
|
|
518
258
|
// An Empty has no extent, so its cage is the marker's own cube, centred on
|
|
519
259
|
// the origin (a prop's cage stands on it).
|
|
520
|
-
const empty = object.renderer === EMPTY_KIND;
|
|
260
|
+
const empty = object.renderer === EMPTY_KIND || object.renderer === LIGHT_KIND || object.renderer === EFFECT_KIND;
|
|
521
261
|
const height = empty ? EMPTY_MARKER_SIZE : Math.max(object.height ?? 1, 0.08);
|
|
522
262
|
const width = empty ? EMPTY_MARKER_SIZE : object.footprint?.width ?? 1;
|
|
523
263
|
const depth = empty ? EMPTY_MARKER_SIZE : object.footprint?.depth ?? 1;
|
|
@@ -575,7 +315,7 @@ function SceneObject({ object, selected, frameRef = null, take = null, attachFra
|
|
|
575
315
|
const travelled = frameRef && !attach && travelLookupRef?.current
|
|
576
316
|
? sceneObjectTravelMatrixAt(travelLookupRef.current, object.id, frame, take ?? {}, placeWorld)
|
|
577
317
|
: null;
|
|
578
|
-
if (travelled) {
|
|
318
|
+
if ((group.visible = trackShown(object.id, frame, take, travelLookupRef?.current)) && travelled) {
|
|
579
319
|
travelled.decompose(group.position, group.quaternion, group.scale);
|
|
580
320
|
} else if (attach || object.path) {
|
|
581
321
|
// The authored numbers first. While attached they are the prop's LOCAL
|
|
@@ -617,8 +357,11 @@ function SceneObject({ object, selected, frameRef = null, take = null, attachFra
|
|
|
617
357
|
(window.__cclayPropWorld ??= {})[object.id] = { x: group.position.x, y: group.position.y, z: group.position.z, quat: { x: group.quaternion.x, y: group.quaternion.y, z: group.quaternion.z, w: group.quaternion.w }, frame };
|
|
618
358
|
}
|
|
619
359
|
applyPoseFade(group, fadeOpacity, object.opacity ?? 1);
|
|
360
|
+
// A light's level, flicker and aim, and a glow, for this frame (scene-light-place.js).
|
|
361
|
+
placeObjectLook(group, object, frame, take);
|
|
620
362
|
};
|
|
621
363
|
useFrame(place);
|
|
364
|
+
useLookRefresh(object);
|
|
622
365
|
// Two things the App needs to reach imperatively, registered per prop: a
|
|
623
366
|
// placement pass for the recorder (which renders through gl.render() and so
|
|
624
367
|
// never runs the frame loop — see SetProps' syncRef), and the prop's live
|
|
@@ -684,7 +427,8 @@ export function SetProps({ objects = [], authoredObjects = null, selectedId = nu
|
|
|
684
427
|
if (worldRef) worldRef.current = (id, out) => registryRef.current.get(id)?.world(out) ?? null;
|
|
685
428
|
return (
|
|
686
429
|
<group>
|
|
687
|
-
{
|
|
430
|
+
{/* Lights past the practical shadow cap draw without one (object-look.js). */}
|
|
431
|
+
{capPracticalShadows(objects).map((object) => (
|
|
688
432
|
<SceneObject
|
|
689
433
|
key={object.id}
|
|
690
434
|
object={object}
|
|
@@ -698,6 +442,7 @@ export function SetProps({ objects = [], authoredObjects = null, selectedId = nu
|
|
|
698
442
|
depthRank={depthRanks.get(object.id) ?? 0}
|
|
699
443
|
/>
|
|
700
444
|
))}
|
|
445
|
+
<EffectsLayer objects={authoredObjects ?? objects} frameRef={frameRef} take={take} registryRef={registryRef} fadeOpacity={fadeOpacity} />
|
|
701
446
|
</group>
|
|
702
447
|
);
|
|
703
448
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// A free drag on a camera rail's dot in the 3D view (CraneHandles): the dot moves over the floor and the rail
|
|
2
|
+
// bends under it, with the weighted bump the X and Z arrows use (prepareRailBend), on both floor axes at once.
|
|
3
|
+
// The drag reads the floor plane, not a plane level with the dot: that one goes edge-on when the editor's eye
|
|
4
|
+
// is at crane height. The dot's height stays on the Y arrow.
|
|
5
|
+
import * as THREE from "three";
|
|
6
|
+
import { prepareRailBend, railPoint } from "./camera-follow.js";
|
|
7
|
+
|
|
8
|
+
const FLOOR = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The drag a free press on crane mark `index` starts, shaped like an arrow drag (axis "floor"), or null when it
|
|
12
|
+
* cannot bend the rail: Shift (a slide along the arc), no rail callback or control points, or a ray off the floor.
|
|
13
|
+
* s: CraneHandles' live state { rail, crane, controlPoints, onChangeRail }; ray: the press's ray.
|
|
14
|
+
*/
|
|
15
|
+
export function floorDragStart(s, index, ray, shiftKey) {
|
|
16
|
+
const point = s.crane?.points[index];
|
|
17
|
+
if (shiftKey || !point || !s.rail || !s.onChangeRail) return null;
|
|
18
|
+
const bend = prepareRailBend(s.controlPoints, railPoint(s.rail, point.t * s.rail.length), s.crane.points, index);
|
|
19
|
+
const hitStart = new THREE.Vector3();
|
|
20
|
+
if (!bend || !ray.intersectPlane(FLOOR, hitStart)) return null;
|
|
21
|
+
return { axis: "floor", index, dir: new THREE.Vector3(), plane: FLOOR, hitStart, startControls: bend.startControls, bendWeights: bend.weights,
|
|
22
|
+
t0: bend.t0, radius: bend.radius, recorded: false };
|
|
23
|
+
}
|
package/src/render-passes.js
CHANGED
|
@@ -105,6 +105,15 @@ export function renderPass(capture, scene, camera, kind, toDataUrl = null, optio
|
|
|
105
105
|
const previousMaterial = scene.overrideMaterial;
|
|
106
106
|
const previousBackground = scene.background;
|
|
107
107
|
let buffer = null;
|
|
108
|
+
// A glow halo (userData.beautyOnly) is light, not a surface: drawn with the
|
|
109
|
+
// pass material it would be a solid quad in the depth or normal plate.
|
|
110
|
+
const hidden = [];
|
|
111
|
+
scene.traverse?.((node) => {
|
|
112
|
+
if (node.userData?.beautyOnly && node.visible) {
|
|
113
|
+
hidden.push(node);
|
|
114
|
+
node.visible = false;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
108
117
|
try {
|
|
109
118
|
scene.overrideMaterial = material;
|
|
110
119
|
// Empty sky is infinitely far away, so on a depth plate it is black. The
|
|
@@ -118,6 +127,7 @@ export function renderPass(capture, scene, camera, kind, toDataUrl = null, optio
|
|
|
118
127
|
// threw.
|
|
119
128
|
scene.overrideMaterial = previousMaterial;
|
|
120
129
|
scene.background = previousBackground;
|
|
130
|
+
for (const node of hidden) node.visible = true;
|
|
121
131
|
material.dispose();
|
|
122
132
|
}
|
|
123
133
|
if (!buffer) return null;
|
package/src/resource-status.jsx
CHANGED
package/src/result-modal.jsx
CHANGED
|
@@ -2,8 +2,6 @@ import { ko, isKo } from "./locale.js";
|
|
|
2
2
|
|
|
3
3
|
export default function ResultModal({ result, copied, recordedVideoName, onClose, onCopy, onDownload, downloadDisabled = false, exportFeedback = null }) {
|
|
4
4
|
const isVideo = result.mode === "video";
|
|
5
|
-
const motionVideo = result.motion?.videoUrl ?? null;
|
|
6
|
-
const isI2vMotion = Boolean(motionVideo);
|
|
7
5
|
const modelLabel = result.modelLabel ?? (isVideo ? ko("your AI video tool", "AI 영상 도구") : ko("your selected image model", "선택한 이미지 모델"));
|
|
8
6
|
const hasFrame = Boolean(result.frame);
|
|
9
7
|
|
|
@@ -42,14 +40,12 @@ export default function ResultModal({ result, copied, recordedVideoName, onClose
|
|
|
42
40
|
<div className="modal-overlay" onClick={onClose}>
|
|
43
41
|
<div className="modal result-modal" role="dialog" aria-modal="true" aria-labelledby="result-title" onClick={(event) => event.stopPropagation()}>
|
|
44
42
|
<div className="modal-head">
|
|
45
|
-
<h3 id="result-title">{
|
|
43
|
+
<h3 id="result-title">{ko("Your shot is ready", "장면이 준비됐어요")}</h3>
|
|
46
44
|
<button type="button" className="x" onClick={onClose} aria-label={ko("Close the result", "결과 닫기")}>
|
|
47
45
|
✕
|
|
48
46
|
</button>
|
|
49
47
|
</div>
|
|
50
|
-
{
|
|
51
|
-
<video className="preview result-motion-video" src={motionVideo} controls playsInline preload="metadata" />
|
|
52
|
-
) : result.frameB ? (
|
|
48
|
+
{result.frameB ? (
|
|
53
49
|
<div className="move-frames">
|
|
54
50
|
<figure>
|
|
55
51
|
<img className="preview" src={result.frame} alt={ko("Camera move start frame", "카메라 움직임 시작 프레임")} />
|
|
@@ -69,13 +65,6 @@ export default function ResultModal({ result, copied, recordedVideoName, onClose
|
|
|
69
65
|
<small>{ko("Camera move made from timeline keyframes", "타임라인 키프레임으로 만든 카메라 움직임")}</small>
|
|
70
66
|
</div>
|
|
71
67
|
)}
|
|
72
|
-
{isI2vMotion && result.motion && <div className="result-motion-meta">
|
|
73
|
-
<span>{result.motion.resolution || "480P"}</span>
|
|
74
|
-
{result.motion.width && result.motion.height && <span>{result.motion.width}×{result.motion.height}</span>}
|
|
75
|
-
{result.motion.fps && <span>{result.motion.fps} fps</span>}
|
|
76
|
-
{result.motion.duration && <span>{result.motion.duration}s</span>}
|
|
77
|
-
{result.motion.cost != null && <span>${Number(result.motion.cost).toFixed(4)}</span>}
|
|
78
|
-
</div>}
|
|
79
68
|
<label className="modal-label">{ko("Prompt", "프롬프트")} {copied && <em>· {ko("copied", "복사됨")}</em>}</label>
|
|
80
69
|
<div className="promptbox">{result.prompt}</div>
|
|
81
70
|
<div className="modal-actions">
|
|
@@ -90,11 +79,7 @@ export default function ResultModal({ result, copied, recordedVideoName, onClose
|
|
|
90
79
|
</div>
|
|
91
80
|
|
|
92
81
|
{exportFeedback}
|
|
93
|
-
|
|
94
|
-
<span className="result-next-kicker">{ko("Next · CozyClay motion source", "다음 · CozyClay 모션 소스")}</span>
|
|
95
|
-
<h4 id="result-next-title">{ko("Use this video for mocap extraction", "이 영상을 모캡 추출에 사용하세요")}</h4>
|
|
96
|
-
<div className="result-next-intro"><p>{ko("The fixed-camera H3 Max Turbo video is attached to the extraction panel as a motion source. Run GVHMR there, then review the resulting take in the timeline.", "고정 카메라 H3 Max Turbo 영상이 추출 패널의 모션 소스로 연결됐어요. 거기서 GVHMR을 실행한 뒤 타임라인의 테이크를 확인하세요.")}</p></div>
|
|
97
|
-
</section> : <section className="result-next" aria-labelledby="result-next-title">
|
|
82
|
+
<section className="result-next" aria-labelledby="result-next-title">
|
|
98
83
|
<span className="result-next-kicker">{ko(`Next · ${modelLabel}`, `다음 · ${modelLabel}`)}</span>
|
|
99
84
|
<h4 id="result-next-title">{ko("Handing off to your AI", "AI에 넣는 순서")}</h4>
|
|
100
85
|
<div className="result-next-intro">{nextStep}</div>
|
|
@@ -121,7 +106,7 @@ export default function ResultModal({ result, copied, recordedVideoName, onClose
|
|
|
121
106
|
{ko("A video recorded with the recording feature: ", "녹화 기능으로 만든 ")}<code>{recordedVideoName}</code>{ko(" file. Use it separately from the reference frame in the prompt above.", " 파일이에요. 위의 프롬프트 참고 프레임과는 별도로 활용하세요.")}
|
|
122
107
|
</p>
|
|
123
108
|
)}
|
|
124
|
-
</section>
|
|
109
|
+
</section>
|
|
125
110
|
</div>
|
|
126
111
|
</div>
|
|
127
112
|
);
|
package/src/room.jsx
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { useEffect, useMemo } from "react";
|
|
2
2
|
import * as THREE from "three";
|
|
3
|
+
import { stageLook } from "./stage-lighting.js";
|
|
4
|
+
// Patches three's PCF filter before any material compiles (16 taps past radius 1).
|
|
5
|
+
import "./soft-shadows.js";
|
|
6
|
+
export { StageAtmosphere } from "./stage-sky.jsx";
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* The blocking set: an open stage floor.
|
|
@@ -128,25 +132,24 @@ export function keyLightColor(warmth = 0.5) {
|
|
|
128
132
|
* One neutral rig (Blender's workbench studio light idea): a white sky over
|
|
129
133
|
* a grey ground bounce. `neutral` is the grid view, where the deck is gone
|
|
130
134
|
* and the ambient is lifted so authored colours stay saturated without any
|
|
131
|
-
* pretend floor.
|
|
135
|
+
* pretend floor. `lighting` (stage.lighting) scales and tints the rig into a
|
|
136
|
+
* look — night, golden hour, a black stage — through stageLook(); its studio
|
|
137
|
+
* default renders the tuned rig unchanged.
|
|
132
138
|
*/
|
|
133
|
-
export function StageLights({ keyLight = { x: 6, y: 9, z: 4, intensity: 1.12, warmth: 0.5 }, neutral = false, light = false }) {
|
|
134
|
-
const
|
|
139
|
+
export function StageLights({ keyLight = { x: 6, y: 9, z: 4, intensity: 1.12, warmth: 0.5 }, lighting = null, neutral = false, light = false }) {
|
|
140
|
+
const look = stageLook({ lighting, keyLight, theme: light ? "light" : "dark", grid: neutral });
|
|
135
141
|
return (
|
|
136
142
|
<>
|
|
137
|
-
<hemisphereLight
|
|
138
|
-
args={neutral ? ["#ffffff", "#3a3d42", 0.9] : ["#ffffff", light ? "#d6d8de" : "#5a5d64", 0.9]}
|
|
139
|
-
intensity={0.9 * Math.min(1, 0.35 + 0.65 * dim)}
|
|
140
|
-
/>
|
|
143
|
+
<hemisphereLight args={[look.hemi.sky, look.hemi.ground, 0.9]} intensity={look.hemi.intensity} />
|
|
141
144
|
{/* The light stage is a bright room: more ambient, so the clay's shaded
|
|
142
145
|
side stays soft grey instead of going charcoal against white. */}
|
|
143
|
-
<ambientLight intensity={
|
|
146
|
+
<ambientLight intensity={look.ambient} />
|
|
144
147
|
{/* Only the key casts: one soft, unambiguous contact shadow reads as
|
|
145
148
|
ground contact, while three overlapping shadows read as noise. The
|
|
146
149
|
map covers the blocking area rather than the whole 500 m deck — a
|
|
147
150
|
stage-wide frustum would spend its resolution on empty floor. */}
|
|
148
151
|
<directionalLight
|
|
149
|
-
color={keyLightColor(keyLight.warmth)}
|
|
152
|
+
color={keyLight.color ?? keyLightColor(keyLight.warmth)}
|
|
150
153
|
position={[keyLight.x, keyLight.y, keyLight.z]}
|
|
151
154
|
intensity={keyLight.intensity}
|
|
152
155
|
castShadow
|
|
@@ -162,10 +165,15 @@ export function StageLights({ keyLight = { x: 6, y: 9, z: 4, intensity: 1.12, wa
|
|
|
162
165
|
// shadow there. 60 covers the clamp envelope with headroom.
|
|
163
166
|
shadow-camera-far={60}
|
|
164
167
|
shadow-bias={-0.0006}
|
|
165
|
-
shadow
|
|
168
|
+
// PCF spreads its noise-rotated taps over shadow.radius texels, so a
|
|
169
|
+
// larger radius is a wider penumbra in the same single pass
|
|
170
|
+
// (stage.lighting.shadowSoftness; soft-shadows.js says why not VSM).
|
|
171
|
+
// The normal offset grows with the radius.
|
|
172
|
+
shadow-normalBias={look.shadowNormalBias}
|
|
173
|
+
shadow-radius={look.shadowRadius}
|
|
166
174
|
/>
|
|
167
|
-
<directionalLight color="#eef2f4" position={[-6, 4, -4]} intensity={
|
|
168
|
-
<directionalLight color="#ffffff" position={[2, 3, 9]} intensity={
|
|
175
|
+
<directionalLight color="#eef2f4" position={[-6, 4, -4]} intensity={look.fill} />
|
|
176
|
+
<directionalLight color="#ffffff" position={[2, 3, 9]} intensity={look.rim} />
|
|
169
177
|
</>
|
|
170
178
|
);
|
|
171
179
|
}
|
package/src/scene-assets.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* Everything above the storage adapter is pure and testable in node; the
|
|
19
19
|
* adapter is the only part that needs a browser.
|
|
20
20
|
*/
|
|
21
|
+
import { isHdrAssetId, normalizeHdrAsset } from "./stage-hdr.js";
|
|
21
22
|
|
|
22
23
|
/** Content-addressed, so the same bytes always land on the same id. */
|
|
23
24
|
export const ASSET_ID_PREFIX = "img-";
|
|
@@ -85,7 +86,7 @@ export function isMeshAssetId(value) {
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
export function isAssetId(value) {
|
|
88
|
-
return isImageAssetId(value) || isMeshAssetId(value);
|
|
89
|
+
return isImageAssetId(value) || isMeshAssetId(value) || isHdrAssetId(value);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
async function sha256Hex(bytes, subtle) {
|
|
@@ -149,6 +150,8 @@ export function normalizeAsset(record) {
|
|
|
149
150
|
if (!record || typeof record !== "object" || Array.isArray(record)) return null;
|
|
150
151
|
const bytes = record.bytes instanceof ArrayBuffer ? record.bytes : null;
|
|
151
152
|
if (!bytes || !bytes.byteLength) return null;
|
|
153
|
+
// An `hdr-` id is an HDR environment file (stage-hdr.js), stored verbatim.
|
|
154
|
+
if (isHdrAssetId(record.id)) return normalizeHdrAsset(record, bytes);
|
|
152
155
|
// Prefix and MIME must agree: a mesh id with an image type (or the reverse)
|
|
153
156
|
// is a cross-wired record and cannot be drawn as either kind.
|
|
154
157
|
if (isMeshAssetId(record.id)) {
|
|
@@ -309,12 +312,11 @@ export async function importImageFile(file, {
|
|
|
309
312
|
*/
|
|
310
313
|
export function referencedAssetIds(scenes) {
|
|
311
314
|
const ids = new Set(assetUsageCounts(scenes).keys());
|
|
312
|
-
// A storyboard panel's stylized picture is held by its shot, not by an object
|
|
315
|
+
// A storyboard panel's stylized picture is held by its shot, not by an object;
|
|
316
|
+
// a scene's HDR environment file by its stage look (stage.lighting.hdr).
|
|
313
317
|
for (const scene of Array.isArray(scenes) ? scenes : []) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
if (isImageAssetId(shot?.stylizedAssetId)) ids.add(shot.stylizedAssetId);
|
|
317
|
-
}
|
|
318
|
+
for (const shot of Array.isArray(scene?.shotDocument?.shots) ? scene.shotDocument.shots : []) if (isImageAssetId(shot?.stylizedAssetId)) ids.add(shot.stylizedAssetId);
|
|
319
|
+
if (isHdrAssetId(scene?.stage?.lighting?.hdr)) ids.add(scene.stage.lighting.hdr);
|
|
318
320
|
}
|
|
319
321
|
return ids;
|
|
320
322
|
}
|