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
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-frame half of practical lights and glow, kept free of React so the
|
|
3
|
+
* place pass can be exercised in Node: SceneObject calls `placeObjectLook`
|
|
4
|
+
* from its imperative place pass (and the recorder through it, for every
|
|
5
|
+
* frame it renders), and it writes the light's numbers and the glow for that
|
|
6
|
+
* frame only.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as THREE from "three";
|
|
10
|
+
import { LIGHT_INTENSITY_SCALE, flickerAt } from "./object-look.js";
|
|
11
|
+
import { trackLevel } from "./object-travel.js";
|
|
12
|
+
import { hasGlow, placeObjectGlow } from "./object-glow.js";
|
|
13
|
+
|
|
14
|
+
const DEG = Math.PI / 180;
|
|
15
|
+
/** A shadow camera's far plane when the light has no range of its own. */
|
|
16
|
+
export const SHADOW_FAR = 40;
|
|
17
|
+
|
|
18
|
+
const DOWN = new THREE.Vector3(0, -1, 0);
|
|
19
|
+
const scratchDir = new THREE.Vector3();
|
|
20
|
+
const scratchPos = new THREE.Vector3();
|
|
21
|
+
const scratchQuat = new THREE.Quaternion();
|
|
22
|
+
const scratchScale = new THREE.Vector3();
|
|
23
|
+
|
|
24
|
+
function childWith(group, key) {
|
|
25
|
+
for (const child of group.children) if (child.userData?.[key]) return child;
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Write the light's numbers for this frame. `gain` is level × flicker. */
|
|
30
|
+
function placeSceneLight(group, object, gain) {
|
|
31
|
+
const light = childWith(group, "sceneLight");
|
|
32
|
+
if (!light) return;
|
|
33
|
+
const { color, intensity, range, angle, softness, aim } = object.light;
|
|
34
|
+
light.color.set(color);
|
|
35
|
+
light.intensity = intensity * LIGHT_INTENSITY_SCALE * gain;
|
|
36
|
+
light.distance = range;
|
|
37
|
+
if (light.castShadow && light.isPointLight) {
|
|
38
|
+
const far = range > 0 ? range : SHADOW_FAR;
|
|
39
|
+
if (light.shadow.camera.far !== far) {
|
|
40
|
+
light.shadow.camera.far = far;
|
|
41
|
+
light.shadow.camera.updateProjectionMatrix();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!light.isSpotLight) return;
|
|
45
|
+
light.angle = angle * DEG;
|
|
46
|
+
light.penumbra = softness;
|
|
47
|
+
// The target is kept outside the scene graph, in world space: an aim point
|
|
48
|
+
// is a place in the set, and the record's own -Y is where it hangs pointing.
|
|
49
|
+
group.updateWorldMatrix(true, false);
|
|
50
|
+
group.matrixWorld.decompose(scratchPos, scratchQuat, scratchScale);
|
|
51
|
+
if (aim) scratchDir.set(aim.x - scratchPos.x, aim.y - scratchPos.y, aim.z - scratchPos.z);
|
|
52
|
+
else scratchDir.copy(DOWN).applyQuaternion(scratchQuat);
|
|
53
|
+
if (scratchDir.lengthSq() < 1e-10) scratchDir.copy(DOWN).applyQuaternion(scratchQuat);
|
|
54
|
+
scratchDir.normalize();
|
|
55
|
+
light.target.position.copy(scratchPos).add(scratchDir);
|
|
56
|
+
light.target.updateMatrixWorld();
|
|
57
|
+
const cone = childWith(group, "lightMarker")?.children.find((child) => child.userData?.lightCone);
|
|
58
|
+
if (cone) cone.quaternion.setFromUnitVectors(DOWN, scratchDir.applyQuaternion(scratchQuat.invert()));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The per-frame look of one record: its light (if it is one) and its glow (if
|
|
63
|
+
* it has one), from the take's level at `frame` and the light's flicker. Pure
|
|
64
|
+
* in the frame number, so any frame can be drawn in any order.
|
|
65
|
+
*/
|
|
66
|
+
export function placeObjectLook(group, object, frame, take) {
|
|
67
|
+
if (!object.light && !object.glow && !hasGlow(group)) return;
|
|
68
|
+
const level = trackLevel(object.id, frame, take);
|
|
69
|
+
const gain = level * (object.light ? flickerAt(object.id, frame, object.light.flicker, take?.fps) : 1);
|
|
70
|
+
if (object.light) placeSceneLight(group, object, gain);
|
|
71
|
+
placeObjectGlow(group, object, gain);
|
|
72
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Practical lights in the set: a point or spot light a record carries, and its
|
|
3
|
+
* editor-only marker.
|
|
4
|
+
*
|
|
5
|
+
* The light itself lives on the default layer, so the viewport, the shot
|
|
6
|
+
* preview, capture_frame, contact sheets and the video export all light the
|
|
7
|
+
* set with it. The marker (a bulb, plus the cone for a spot) is editor
|
|
8
|
+
* furniture on GIZMO_LAYER, exactly like an Empty's axes: drawn in the working
|
|
9
|
+
* views, dropped by every recorded camera, and picked through the same
|
|
10
|
+
* `emptyPick` volume so the user can select and move the light.
|
|
11
|
+
*
|
|
12
|
+
* Everything that changes with time (take level, flicker, a spot's aim while
|
|
13
|
+
* the record travels) is written by `placeObjectLook` (scene-light-place.js),
|
|
14
|
+
* which SceneObject calls from its imperative place pass. The recorder runs
|
|
15
|
+
* that pass for every frame it renders, so a scrub or an export never sees a
|
|
16
|
+
* stale light.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { useEffect, useMemo } from "react";
|
|
20
|
+
import { useThree } from "@react-three/fiber";
|
|
21
|
+
import * as THREE from "three";
|
|
22
|
+
import { GIZMO_LAYER } from "./dualview.jsx";
|
|
23
|
+
import { EMPTY_MARKER_SIZE } from "./scene-objects.js";
|
|
24
|
+
import { SHADOW_FAR } from "./scene-light-place.js";
|
|
25
|
+
|
|
26
|
+
const DEG = Math.PI / 180;
|
|
27
|
+
const BULB_RADIUS = 0.07;
|
|
28
|
+
/** Drawn length of a spot's cone outline, metres (the light reaches further). */
|
|
29
|
+
const CONE_LENGTH = 0.7;
|
|
30
|
+
|
|
31
|
+
function makeLight(type, shadow) {
|
|
32
|
+
const light = type === "spot" ? new THREE.SpotLight() : new THREE.PointLight();
|
|
33
|
+
// three.js hangs a spot 1 m up (DEFAULT_UP) by default; a practical sits on its record's pivot.
|
|
34
|
+
light.position.set(0, 0, 0);
|
|
35
|
+
light.decay = 2;
|
|
36
|
+
light.castShadow = shadow;
|
|
37
|
+
light.userData.sceneLight = true;
|
|
38
|
+
if (shadow) {
|
|
39
|
+
const size = type === "spot" ? 1024 : 512;
|
|
40
|
+
light.shadow.mapSize.set(size, size);
|
|
41
|
+
light.shadow.bias = -0.0004;
|
|
42
|
+
light.shadow.normalBias = 0.02;
|
|
43
|
+
// A lighter a hand-width from a face must still shadow the hand.
|
|
44
|
+
light.shadow.camera.near = 0.03;
|
|
45
|
+
light.shadow.camera.far = SHADOW_FAR;
|
|
46
|
+
light.shadow.camera.updateProjectionMatrix();
|
|
47
|
+
}
|
|
48
|
+
return light;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Line pairs of a circle of `radius` in the plane spanned by axes a and b. */
|
|
52
|
+
function circle(out, radius, a, b, y = 0, segments = 24) {
|
|
53
|
+
for (let i = 0; i < segments; i += 1) {
|
|
54
|
+
for (const k of [i, i + 1]) {
|
|
55
|
+
const t = (k / segments) * Math.PI * 2;
|
|
56
|
+
const p = [0, y, 0];
|
|
57
|
+
p[a] += Math.cos(t) * radius;
|
|
58
|
+
p[b] += Math.sin(t) * radius;
|
|
59
|
+
out.push(...p);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function lineGeometry(positions) {
|
|
66
|
+
const geometry = new THREE.BufferGeometry();
|
|
67
|
+
geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));
|
|
68
|
+
return geometry;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The bulb: three rings and a few short rays, so it reads as a light, not a ball. */
|
|
72
|
+
function bulbGeometry() {
|
|
73
|
+
const out = [];
|
|
74
|
+
circle(out, BULB_RADIUS, 0, 2);
|
|
75
|
+
circle(out, BULB_RADIUS, 0, 1);
|
|
76
|
+
circle(out, BULB_RADIUS, 1, 2);
|
|
77
|
+
for (let i = 0; i < 8; i += 1) {
|
|
78
|
+
const t = (i / 8) * Math.PI * 2;
|
|
79
|
+
out.push(Math.cos(t) * BULB_RADIUS * 1.3, 0, Math.sin(t) * BULB_RADIUS * 1.3, Math.cos(t) * BULB_RADIUS * 2, 0, Math.sin(t) * BULB_RADIUS * 2);
|
|
80
|
+
}
|
|
81
|
+
return lineGeometry(out);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** A spot's cone along local -Y: four edges and the rim at CONE_LENGTH. */
|
|
85
|
+
function coneGeometry(angleDeg) {
|
|
86
|
+
const radius = CONE_LENGTH * Math.tan(angleDeg * DEG);
|
|
87
|
+
const out = circle([], radius, 0, 2, -CONE_LENGTH, 32);
|
|
88
|
+
for (let i = 0; i < 4; i += 1) {
|
|
89
|
+
const t = (i / 4) * Math.PI * 2;
|
|
90
|
+
out.push(0, 0, 0, Math.cos(t) * radius, -CONE_LENGTH, Math.sin(t) * radius);
|
|
91
|
+
}
|
|
92
|
+
return lineGeometry(out);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const onGizmoLayer = (node) => {
|
|
96
|
+
if (node) node.layers.set(GIZMO_LAYER);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function LightMarker({ type, angle, color }) {
|
|
100
|
+
const bulb = useMemo(() => bulbGeometry(), []);
|
|
101
|
+
const cone = useMemo(() => (type === "spot" ? coneGeometry(angle) : null), [type, angle]);
|
|
102
|
+
useEffect(() => () => bulb.dispose(), [bulb]);
|
|
103
|
+
useEffect(() => () => cone?.dispose(), [cone]);
|
|
104
|
+
return (
|
|
105
|
+
<group userData={{ lightMarker: true }}>
|
|
106
|
+
<lineSegments ref={onGizmoLayer} geometry={bulb} renderOrder={997} frustumCulled={false}>
|
|
107
|
+
<lineBasicMaterial color={color} depthTest={false} depthWrite={false} transparent opacity={0.95} />
|
|
108
|
+
</lineSegments>
|
|
109
|
+
{cone && (
|
|
110
|
+
<group userData={{ lightCone: true }}>
|
|
111
|
+
<lineSegments ref={onGizmoLayer} geometry={cone} renderOrder={997} frustumCulled={false}>
|
|
112
|
+
<lineBasicMaterial color={color} depthTest={false} depthWrite={false} transparent opacity={0.55} />
|
|
113
|
+
</lineSegments>
|
|
114
|
+
</group>
|
|
115
|
+
)}
|
|
116
|
+
{/* Never drawn, still raycast: the object picker's gizmo-layer pass
|
|
117
|
+
finds it by `emptyPick` and selects the light's record. */}
|
|
118
|
+
<mesh ref={onGizmoLayer} visible={false} userData={{ emptyPick: true }}>
|
|
119
|
+
<sphereGeometry args={[EMPTY_MARKER_SIZE * 0.45, 12, 8]} />
|
|
120
|
+
<meshBasicMaterial />
|
|
121
|
+
</mesh>
|
|
122
|
+
</group>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** A light record's content: the three.js light and its marker. Rebuilt only
|
|
127
|
+
* when the type or the shadow switch changes (both change the shader). */
|
|
128
|
+
export function SceneLight({ object }) {
|
|
129
|
+
const { type, shadow, angle, color } = object.light;
|
|
130
|
+
const light = useMemo(() => makeLight(type, shadow), [type, shadow]);
|
|
131
|
+
useEffect(() => () => light.dispose(), [light]);
|
|
132
|
+
return (
|
|
133
|
+
<>
|
|
134
|
+
<primitive object={light} />
|
|
135
|
+
<LightMarker type={type} angle={angle} color={color} />
|
|
136
|
+
</>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Ask for a frame when the record's light or glow changes. Both are written by
|
|
141
|
+
* the place pass, which a demand frame loop runs only when something asks: an
|
|
142
|
+
* edit that changes no three.js prop would otherwise wait for the next orbit. */
|
|
143
|
+
export function useLookRefresh(object) {
|
|
144
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
invalidate();
|
|
147
|
+
}, [invalidate, object.light, object.glow]);
|
|
148
|
+
}
|
package/src/scene-objects.js
CHANGED
|
@@ -22,6 +22,13 @@ import { createObjectPath, translateObjectPath } from "./object-path.js";
|
|
|
22
22
|
import { elementByPath } from "./studio-elements.js";
|
|
23
23
|
import { MESH_DEFAULT_HEIGHT, MESH_HEIGHT_MIN } from "./scene-mesh.js";
|
|
24
24
|
import { normalizeSculptRecipe, sculptStandingBox } from "./sculpt-recipe.js";
|
|
25
|
+
import { GREY_BOX } from "./object-colors.js";
|
|
26
|
+
import { isEffectivelyHidden } from "./object-hidden.js";
|
|
27
|
+
import { objectSize } from "./object-size.js";
|
|
28
|
+
import { EFFECT_ENTRY, effectFields } from "./effects/effect-record.js";
|
|
29
|
+
import { LIGHT_KIND, LIGHT_MENU_ENTRIES, lightLibraryEntry, objectLookFields, objectLookPatch } from "./object-look.js";
|
|
30
|
+
export { OBJECT_COLORS, normalizeObjectColor, rememberObjectColor, readStoredObjectColors, writeStoredObjectColors } from "./object-colors.js";
|
|
31
|
+
export { isEffectivelyHidden };
|
|
25
32
|
|
|
26
33
|
export const DEFAULT_SCENE_OBJECTS = [];
|
|
27
34
|
/** The persistence contract (plan §8.1): the version lives in the key AND in
|
|
@@ -60,7 +67,6 @@ const snapTo = (value, step) => Number((step > 0 ? Math.round(value / step) * st
|
|
|
60
67
|
* else, and a tinted maquette reads as a finished prop. The hand-built set
|
|
61
68
|
* pieces keep their clay colours because they ARE the thing they depict.
|
|
62
69
|
*/
|
|
63
|
-
const GREY_BOX = "#c2c6c8";
|
|
64
70
|
export const OBJECT_LIBRARY = [
|
|
65
71
|
{ kind: "cube", label: "Cube", group: "Primitives", footprint: { width: 1, depth: 1 }, height: 1, color: GREY_BOX },
|
|
66
72
|
{ kind: "sphere", label: "Sphere", group: "Primitives", footprint: { width: 1, depth: 1 }, height: 1, color: GREY_BOX },
|
|
@@ -75,96 +81,6 @@ export const OBJECT_LIBRARY = [
|
|
|
75
81
|
{ kind: "small-plane", label: "Plane (aircraft)", group: "Set pieces", footprint: { width: 3.4, depth: 3.6 }, height: 1.4, color: "#7896a4" },
|
|
76
82
|
];
|
|
77
83
|
|
|
78
|
-
/** Blockout greys first, then the clay accents, then the blocking chromatics,
|
|
79
|
-
* for re-tinting from the inspector. The greys lead because a blockout starts
|
|
80
|
-
* grey; the saturated four exist so a shot can say "the red ball, the blue
|
|
81
|
-
* box" at a glance — the inspector had no way to say that at all (#88). They
|
|
82
|
-
* are muted off pure RGB so they still read as clay under the set's lighting.
|
|
83
|
-
* Any other colour is authored through the inspector's free colour input. */
|
|
84
|
-
export const OBJECT_COLORS = [
|
|
85
|
-
"#e2e5e6",
|
|
86
|
-
GREY_BOX,
|
|
87
|
-
"#9aa1a5",
|
|
88
|
-
"#767d81",
|
|
89
|
-
"#d9b18c",
|
|
90
|
-
"#8fae9b",
|
|
91
|
-
"#d94a4a",
|
|
92
|
-
"#4a7bd9",
|
|
93
|
-
"#e2c04a",
|
|
94
|
-
"#4fa86a",
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
/** How many hand-mixed colours the inspector remembers. Six is one palette
|
|
98
|
-
* row: enough to keep a scene's custom tints reachable, short enough that the
|
|
99
|
-
* popover never turns into a second, unruly palette. */
|
|
100
|
-
const RECENT_OBJECT_COLORS_MAX = 6;
|
|
101
|
-
/** Session memory of hand-mixed tints; versioned like every other key here. */
|
|
102
|
-
const RECENT_OBJECT_COLORS_KEY = "cozyclay.objectColors.recent";
|
|
103
|
-
|
|
104
|
-
const HEX_SHORT = /^#?([0-9a-f]{3})$/i;
|
|
105
|
-
const HEX_LONG = /^#?([0-9a-f]{6})$/i;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* What a colour input typed by a human means, or null if it means nothing.
|
|
109
|
-
*
|
|
110
|
-
* The hex field accepts what people actually type — `#f36`, `ff3366`, upper
|
|
111
|
-
* case, stray spaces — and folds it to the one form the record stores, so a
|
|
112
|
-
* colour typed by hand and the same colour picked from the native swatch are
|
|
113
|
-
* byte-identical (and therefore compare equal against the palette). Anything
|
|
114
|
-
* else returns null rather than throwing or guessing: a half-typed `#12` is a
|
|
115
|
-
* keystroke on the way somewhere, not an instruction to repaint the prop.
|
|
116
|
-
*/
|
|
117
|
-
export function normalizeObjectColor(value) {
|
|
118
|
-
if (typeof value !== "string") return null;
|
|
119
|
-
const text = value.trim();
|
|
120
|
-
const short = HEX_SHORT.exec(text);
|
|
121
|
-
if (short) return `#${short[1].toLowerCase().replace(/./g, (digit) => digit + digit)}`;
|
|
122
|
-
const long = HEX_LONG.exec(text);
|
|
123
|
-
return long ? `#${long[1].toLowerCase()}` : null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* The recent-colours list after mixing `hex`: newest first, no duplicates,
|
|
128
|
-
* capped, presets excluded.
|
|
129
|
-
*
|
|
130
|
-
* Pure so the list can be proved without a browser, and so a corrupt stored
|
|
131
|
-
* list is repaired on the way through instead of painting a swatch with junk.
|
|
132
|
-
* Presets are skipped because they are already one row up — remembering them
|
|
133
|
-
* would push the author's own colours off the end with colours they never
|
|
134
|
-
* mixed. Returns the SAME array when nothing changes, so a re-pick of an
|
|
135
|
-
* unchanged colour cannot trigger a storage write or a re-render.
|
|
136
|
-
*/
|
|
137
|
-
export function rememberObjectColor(list, hex) {
|
|
138
|
-
const clean = Array.isArray(list)
|
|
139
|
-
? list.map(normalizeObjectColor).filter((color, index, all) => color && all.indexOf(color) === index && !OBJECT_COLORS.includes(color))
|
|
140
|
-
: [];
|
|
141
|
-
const color = normalizeObjectColor(hex);
|
|
142
|
-
const next = color && !OBJECT_COLORS.includes(color) ? [color, ...clean.filter((entry) => entry !== color)] : clean;
|
|
143
|
-
const capped = next.slice(0, RECENT_OBJECT_COLORS_MAX);
|
|
144
|
-
const unchanged = Array.isArray(list) && capped.length === list.length && capped.every((entry, index) => entry === list[index]);
|
|
145
|
-
return unchanged ? list : capped;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Recent colours as last left by this browser; storage can be unavailable
|
|
149
|
-
* (private mode), and a corrupt body must not take the inspector down with
|
|
150
|
-
* it — either way the palette simply starts without a memory. */
|
|
151
|
-
export function readStoredObjectColors(storage) {
|
|
152
|
-
try {
|
|
153
|
-
const parsed = JSON.parse(storage?.getItem(RECENT_OBJECT_COLORS_KEY) ?? "[]");
|
|
154
|
-
return rememberObjectColor(Array.isArray(parsed) ? parsed : [], null);
|
|
155
|
-
} catch {
|
|
156
|
-
return [];
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function writeStoredObjectColors(storage, list) {
|
|
161
|
-
try {
|
|
162
|
-
storage?.setItem(RECENT_OBJECT_COLORS_KEY, JSON.stringify(list));
|
|
163
|
-
} catch {
|
|
164
|
-
// Storage can be unavailable (private mode); the colours simply stop persisting.
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
84
|
/**
|
|
169
85
|
* A cutout is a standee: an imported image standing on a card. Its size is NOT
|
|
170
86
|
* library data — the height is measured by the user and the width follows the
|
|
@@ -253,14 +169,16 @@ const EMPTY_ENTRY = {
|
|
|
253
169
|
color: "#ffffff",
|
|
254
170
|
};
|
|
255
171
|
|
|
256
|
-
/** True for a record that is only a node: no mesh, no collision, no surface.
|
|
172
|
+
/** True for a record that is only a node: no mesh, no collision, no surface.
|
|
173
|
+
* A practical light (object-look.js) is one too: it lights, it does not stand. */
|
|
257
174
|
export function isEmptyObject(object) {
|
|
258
|
-
return object?.renderer === EMPTY_KIND;
|
|
175
|
+
return object?.renderer === EMPTY_KIND || object?.renderer === LIGHT_KIND;
|
|
259
176
|
}
|
|
260
177
|
|
|
261
|
-
/** The catalogue grouped for the create menu: the library plus the empty,
|
|
262
|
-
*
|
|
263
|
-
|
|
178
|
+
/** The catalogue grouped for the create menu: the library plus the empty, the
|
|
179
|
+
* two practical lights and the effect emitter, which are creatable but have no
|
|
180
|
+
* footprint to satisfy the library's contract. */
|
|
181
|
+
export const OBJECT_MENU_ENTRIES = Object.freeze([EMPTY_ENTRY, ...OBJECT_LIBRARY, ...LIGHT_MENU_ENTRIES, EFFECT_ENTRY]);
|
|
264
182
|
|
|
265
183
|
/** Every kind that can exist in a scene: the catalogue you can create from,
|
|
266
184
|
* plus the kinds that arrive by import and so are deliberately absent from the
|
|
@@ -271,7 +189,8 @@ function objectLibraryEntry(kind) {
|
|
|
271
189
|
if (kind === MESH_KIND) return MESH_ENTRY;
|
|
272
190
|
if (kind === SCULPT_KIND) return SCULPT_ENTRY;
|
|
273
191
|
if (kind === EMPTY_KIND) return EMPTY_ENTRY;
|
|
274
|
-
|
|
192
|
+
if (kind === EFFECT_ENTRY.kind) return EFFECT_ENTRY;
|
|
193
|
+
return OBJECT_LIBRARY.find((entry) => entry.kind === kind) ?? lightLibraryEntry(kind);
|
|
275
194
|
}
|
|
276
195
|
|
|
277
196
|
/** Return the authored walkable surface for mocap contact staging. */
|
|
@@ -397,9 +316,10 @@ export function createSceneObject(kind, existing = [], placement = {}) {
|
|
|
397
316
|
return {
|
|
398
317
|
id,
|
|
399
318
|
name,
|
|
400
|
-
|
|
319
|
+
// A light kind (point-light, spot-light) is a preset of the one light renderer.
|
|
320
|
+
renderer: entry.renderer ?? kind,
|
|
401
321
|
x: TRANSFORM_LIMITS.x(Number(placement.x) || 0),
|
|
402
|
-
y: 0,
|
|
322
|
+
y: entry.placeY ?? 0,
|
|
403
323
|
z: TRANSFORM_LIMITS.z(Number(placement.z) || 0),
|
|
404
324
|
rot: TRANSFORM_LIMITS.rot(Number(placement.rot) || 0),
|
|
405
325
|
rotX: 0,
|
|
@@ -420,6 +340,8 @@ export function createSceneObject(kind, existing = [], placement = {}) {
|
|
|
420
340
|
footprint: { ...entry.footprint },
|
|
421
341
|
height: entry.height,
|
|
422
342
|
supportY: Number.isFinite(entry.supportY) ? entry.supportY : entry.height,
|
|
343
|
+
...objectLookFields({}, entry),
|
|
344
|
+
...effectFields({ renderer: kind }),
|
|
423
345
|
};
|
|
424
346
|
}
|
|
425
347
|
|
|
@@ -625,7 +547,8 @@ const TRANSFORM_LIMITS = {
|
|
|
625
547
|
/** The patch keys updateSceneObject reads for this object; any other key is
|
|
626
548
|
* silently ignored there, so callers that must not be silent check against this. */
|
|
627
549
|
export function objectPatchFields(object) {
|
|
628
|
-
const fields = [...Object.keys(TRANSFORM_LIMITS), "name", "color", "hidden", "opacity", "path"];
|
|
550
|
+
const fields = [...Object.keys(TRANSFORM_LIMITS), "name", "color", "hidden", "opacity", "path", "glow"];
|
|
551
|
+
if (object?.renderer === LIGHT_KIND) fields.push("light");
|
|
629
552
|
if (object?.renderer === CUTOUT_KIND) fields.push("assetId", "sourceAssetId", "matteAssetId", "matteScale", "height", "aspect", "width", "stretch");
|
|
630
553
|
if (object?.renderer === MESH_KIND) fields.push("clay", "assetId", "height");
|
|
631
554
|
if (object?.renderer === SCULPT_KIND) fields.push("recipe");
|
|
@@ -653,36 +576,6 @@ export function descendantsOf(objects, id) {
|
|
|
653
576
|
return out;
|
|
654
577
|
}
|
|
655
578
|
|
|
656
|
-
/** True when this record, a parent above it, or a character carrying any of
|
|
657
|
-
* those records is hidden. A cycle in parent links ends the walk. When the
|
|
658
|
-
* id is in `objects`, that stored record is what the walk reads, so a display
|
|
659
|
-
* copy cannot disagree with the authored flag. Nothing in the lists is changed. */
|
|
660
|
-
export function isEffectivelyHidden(entity, objects = [], characters = []) {
|
|
661
|
-
if (!entity || typeof entity !== "object") return false;
|
|
662
|
-
const byId = new Map();
|
|
663
|
-
for (const object of objects) {
|
|
664
|
-
if (object && typeof object.id === "string") byId.set(object.id, object);
|
|
665
|
-
}
|
|
666
|
-
const characterHidden = (id) => characters.some((item) => item && typeof item === "object" && item.id === id && item.hidden === true);
|
|
667
|
-
const seen = new Set();
|
|
668
|
-
let current = entity;
|
|
669
|
-
while (current && typeof current === "object") {
|
|
670
|
-
const id = typeof current.id === "string" ? current.id : null;
|
|
671
|
-
if (id) {
|
|
672
|
-
if (seen.has(id)) break;
|
|
673
|
-
seen.add(id);
|
|
674
|
-
if (byId.has(id)) current = byId.get(id);
|
|
675
|
-
}
|
|
676
|
-
if (current.hidden === true) return true;
|
|
677
|
-
const characterId = current.attach && typeof current.attach.characterId === "string" ? current.attach.characterId : null;
|
|
678
|
-
if (characterId && characterHidden(characterId)) return true;
|
|
679
|
-
const parentId = typeof current.parent === "string" ? current.parent : null;
|
|
680
|
-
if (!parentId) break;
|
|
681
|
-
current = byId.get(parentId) ?? null;
|
|
682
|
-
}
|
|
683
|
-
return false;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
579
|
/** Float dust (6e-17 where 0 belongs) is snapped away, and everything else is
|
|
687
580
|
* kept to 1e-9: fine enough that hundreds of small gizmo steps cannot drift a
|
|
688
581
|
* carried child visibly, coarse enough that stored values stay readable. */
|
|
@@ -963,6 +856,8 @@ export function updateSceneObject(objects, id, patch) {
|
|
|
963
856
|
Object.assign(update, sculptStandingBox(normalized.recipe));
|
|
964
857
|
}
|
|
965
858
|
}
|
|
859
|
+
// Light and glow merge over the record's own and are repaired (object-look.js).
|
|
860
|
+
Object.assign(update, objectLookPatch(object, patch));
|
|
966
861
|
if (!Object.keys(update).length) return object;
|
|
967
862
|
changed = true;
|
|
968
863
|
return { ...object, ...update };
|
|
@@ -1126,7 +1021,7 @@ export function normalizeSceneObject(record) {
|
|
|
1126
1021
|
return {
|
|
1127
1022
|
id: record.id,
|
|
1128
1023
|
name: typeof record.name === "string" && record.name ? record.name : entry.label,
|
|
1129
|
-
renderer: entry.kind,
|
|
1024
|
+
renderer: entry.renderer ?? entry.kind,
|
|
1130
1025
|
x: TRANSFORM_LIMITS.x(pick(record.x, 0)),
|
|
1131
1026
|
y: TRANSFORM_LIMITS.y(pick(record.y, 0)),
|
|
1132
1027
|
z: TRANSFORM_LIMITS.z(pick(record.z, 0)),
|
|
@@ -1191,6 +1086,10 @@ export function normalizeSceneObject(record) {
|
|
|
1191
1086
|
height: Math.max(MESH_HEIGHT_MIN, pick(record.height, entry.height)),
|
|
1192
1087
|
}
|
|
1193
1088
|
: { footprint: { ...entry.footprint }, height: entry.height, supportY: Number.isFinite(entry.supportY) ? entry.supportY : entry.height }),
|
|
1089
|
+
// A light's light, and a glow on any record (object-look.js).
|
|
1090
|
+
...objectLookFields(record, entry),
|
|
1091
|
+
// An effect record's emitter (src/effects/effect-record.js).
|
|
1092
|
+
...effectFields(record),
|
|
1194
1093
|
};
|
|
1195
1094
|
}
|
|
1196
1095
|
|
|
@@ -1315,14 +1214,7 @@ export function screenRotatePatch(start, viewAxis, deltaDeg, snap = ROTATE_SNAP)
|
|
|
1315
1214
|
};
|
|
1316
1215
|
}
|
|
1317
1216
|
|
|
1318
|
-
|
|
1319
|
-
export function objectSize(object) {
|
|
1320
|
-
return {
|
|
1321
|
-
width: (object.footprint?.width ?? 1) * (object.scaleX ?? 1),
|
|
1322
|
-
height: (object.height ?? 1) * (object.scaleY ?? 1),
|
|
1323
|
-
depth: (object.footprint?.depth ?? 1) * (object.scaleZ ?? 1),
|
|
1324
|
-
};
|
|
1325
|
-
}
|
|
1217
|
+
export { objectSize };
|
|
1326
1218
|
/** The tolerance that keeps an edge-abutting footprint from counting as
|
|
1327
1219
|
* overlap: a strict `<` against `max - EPS` makes a 0.5 - 0.5 touch false. */
|
|
1328
1220
|
const OVERLAP_EPS = 1e-4;
|