cozyclay 1.10.0 → 2.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 +137 -0
- package/bin/agent/agent-routes.mjs +74 -70
- package/bin/agent/agent-runner.mjs +10 -3
- package/bin/agent/motion-runtime.mjs +32 -260
- package/bin/agent/providers.mjs +46 -3
- package/bin/agent/session-store.mjs +41 -5
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-tools.mjs +48 -11
- package/bin/cozyclay.mjs +26 -8
- package/bin/live/cli.mjs +22 -3
- package/bin/mcp-runtime.mjs +35 -20
- package/bin/telemetry-state.mjs +5 -2
- package/bin/update-check.mjs +15 -0
- package/dist/app/index.html +6 -6
- package/dist/assets/analytics-MVZOEW8O.js +1 -0
- package/dist/assets/app-C1sdVbg4.css +1 -0
- package/dist/assets/app-CA55tcI3.js +4876 -0
- package/dist/assets/{demo-B-eg1CT8.js → demo-ByeYp-dY.js} +1 -1
- package/dist/assets/{first-shot-handoff-CGgnvNu8.js → first-shot-handoff-DgT28ZiV.js} +1 -1
- package/dist/assets/{landing-IbRp3FnQ.js → landing-BaXkpFip.js} +1 -1
- package/dist/assets/shot-prompt-CbqWcWYi.css +1 -0
- package/dist/assets/shot-prompt-Yrt99wZx.js +17 -0
- package/dist/assets/{ticket-BgIzOBOf.js → ticket-BcmsnHn5.js} +1 -1
- package/dist/assets/workflow-DRdwoDBT.css +1 -0
- package/dist/assets/workflow-dNPGY9xz.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/fonts/IBM-Plex-Sans-OFL.txt +92 -0
- package/dist/fonts/JetBrains-Mono-OFL.txt +93 -0
- package/dist/fonts/README.md +13 -9
- package/dist/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
- package/dist/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
- package/dist/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-400-latin.woff2 +0 -0
- package/dist/fonts/jetbrains-mono-500-latin.woff2 +0 -0
- package/dist/index.html +7 -7
- package/dist/privacy/index.html +13 -8
- package/dist/sitemap.xml +6 -6
- package/dist/workflow/index.html +5 -5
- package/mcp/live-hub.mjs +35 -93
- package/mcp/mesh-file.mjs +48 -0
- package/mcp/server.mjs +6 -77
- package/mcp/tool-handlers.mjs +219 -376
- package/package.json +2 -1
- package/src/App.jsx +1249 -9076
- package/src/analytics.js +393 -9
- package/src/app-context.js +211 -0
- package/src/app-stage.jsx +25 -24
- package/src/ardy/auto-fix-panel.css +108 -0
- package/src/ardy/fix-collisions.js +10 -66
- package/src/ardy/ik-drag.js +101 -0
- package/src/ardy/ik-key-json.js +43 -0
- package/src/ardy/ik.js +97 -67
- package/src/ardy/physics-panel.css +2 -0
- package/src/ardy/physics-panel.jsx +17 -5
- package/src/ardy/platform-fit-panel.css +64 -0
- package/src/ardy/platform-fit-panel.jsx +40 -0
- package/src/ardy/platform-fit.js +326 -0
- package/src/ardy/playback.js +166 -20
- package/src/ardy/range-pin.js +299 -0
- package/src/ardy/timeline-coordinates.js +26 -0
- package/src/ardy/timeline.css +1199 -0
- package/src/ardy/timeline.jsx +149 -41
- package/src/ardy/waypoints.js +2 -2
- package/src/asset-pane.css +462 -0
- package/src/asset-pane.jsx +461 -232
- package/src/command-bus.js +349 -0
- package/src/commands/ai.js +31 -0
- package/src/commands/cast.js +140 -0
- package/src/commands/elements/character.js +13 -0
- package/src/commands/elements/motion.js +14 -0
- package/src/commands/elements/object.js +22 -0
- package/src/commands/elements/scene.js +16 -0
- package/src/commands/elements/shot.js +9 -0
- package/src/commands/elements/stage.js +11 -0
- package/src/commands/elements.js +155 -0
- package/src/commands/export.js +20 -0
- package/src/commands/index.js +40 -0
- package/src/commands/motion.js +231 -0
- package/src/commands/objects.js +174 -0
- package/src/commands/project.js +53 -0
- package/src/commands/scene.js +81 -0
- package/src/commands/shared.js +19 -0
- package/src/commands/shot.js +103 -0
- package/src/commands/stage.js +17 -0
- package/src/commands/view.js +42 -0
- package/src/document-store.js +144 -0
- package/src/domains/cast.js +1007 -0
- package/src/domains/motion.js +3219 -0
- package/src/domains/objects.js +932 -0
- package/src/domains/scenes.js +817 -0
- package/src/domains/shots.js +404 -0
- package/src/domains/stage.js +93 -0
- package/src/dualview.jsx +113 -57
- package/src/facing-marks.js +3 -0
- package/src/first-success-guide.jsx +14 -14
- package/src/grid-view.js +18 -5
- package/src/hierarchy-panel.css +386 -0
- package/src/hierarchy-panel.jsx +88 -19
- package/src/{fal-motion-client.js → i2v-motion-client.js} +13 -13
- package/src/i2v-motion-studio.jsx +180 -0
- package/src/ik-camera.js +3 -0
- package/src/main.jsx +6 -0
- package/src/motion/generation.js +105 -0
- package/src/motion-readiness-ui.jsx +4 -4
- package/src/motion-readiness.js +11 -0
- package/src/motion-trail.js +366 -9
- package/src/object-gizmo.jsx +7 -1
- package/src/panels/CameraPanel.jsx +60 -0
- package/src/panels/CharacterTransformPanel.jsx +48 -0
- package/src/panels/EnvironmentPanel.jsx +40 -0
- package/src/panels/Foldout.jsx +32 -0
- package/src/panels/LightPanel.jsx +24 -0
- package/src/panels/ObjectTransformPanel.jsx +554 -0
- package/src/panels/PosePanel.jsx +97 -0
- package/src/panels/ProjectPanel.jsx +33 -0
- package/src/panels/PromptBlocksPanel.jsx +442 -0
- package/src/panels/PropsPanel.jsx +70 -0
- package/src/panels/ReferenceImageField.jsx +91 -0
- package/src/panels/RigControlPanel.jsx +78 -0
- package/src/panels/RigPanel.jsx +37 -0
- package/src/panels/SubjectBox.jsx +47 -0
- package/src/panels/SubjectsPanel.jsx +39 -0
- package/src/panels/VideoCapturePanel.jsx +180 -0
- package/src/panels/details.css +1171 -0
- package/src/panels/motion.css +197 -0
- package/src/panels/pose.css +39 -0
- package/src/planview.jsx +60 -31
- package/src/posestudio.jsx +59 -4
- package/src/project-browser.css +1073 -0
- package/src/project-browser.jsx +284 -123
- package/src/range-pin-object-transform.js +19 -0
- package/src/range-pin-panel.css +518 -0
- package/src/range-pin-panel.jsx +344 -0
- package/src/result-modal.jsx +5 -5
- package/src/room.jsx +79 -51
- package/src/scenes.js +5 -0
- package/src/semantic-edit.js +2 -0
- package/src/settings-menu.jsx +39 -105
- package/src/shell/BottomDock.jsx +450 -0
- package/src/shell/DetailsSlot.jsx +513 -0
- package/src/shell/LibrarySlot.jsx +86 -0
- package/src/shell/MenuBar.jsx +601 -0
- package/src/shell/OutlinerSlot.jsx +50 -0
- package/src/shell/PreferencesDialog.jsx +538 -0
- package/src/shell/PreferencesSlot.jsx +40 -0
- package/src/shell/StatusBar.jsx +125 -0
- package/src/shell/StudioShell.jsx +92 -0
- package/src/shell/TopBar.jsx +129 -0
- package/src/shell/ViewportToolbar.jsx +656 -0
- package/src/shell/agent-glass.css +296 -0
- package/src/shell/dock.css +93 -0
- package/src/shell/glass-regions.css +985 -0
- package/src/shell/glass.css +687 -0
- package/src/shell/log-store.js +52 -0
- package/src/shell/mode.css +9 -0
- package/src/shell/preferences.css +651 -0
- package/src/shell/shell.css +282 -0
- package/src/shell/studio-shell-context.js +19 -0
- package/src/shell/topbar.css +435 -0
- package/src/shell/viewport.css +451 -0
- package/src/store/authored-intent.js +22 -0
- package/src/store/runtime-adapters.js +92 -0
- package/src/store/scene-stage.js +21 -0
- package/src/store/use-document-store.js +14 -0
- package/src/studio-actions.js +210 -0
- package/src/studio-agent-commands.js +38 -268
- package/src/studio-agent-context.js +38 -9
- package/src/studio-agent-motion.js +122 -378
- package/src/studio-agent-protocol.js +66 -30
- package/src/studio-app-binding.js +379 -0
- package/src/studio-contact-sheet.js +73 -0
- package/src/studio-elements.js +58 -51
- package/src/styles/themes.css +200 -0
- package/src/styles/tokens.css +69 -0
- package/src/styles.css +443 -1753
- package/src/theme.js +44 -0
- package/src/timeline-extent.js +16 -0
- package/src/trail-key-conflicts.js +39 -0
- package/src/trail-pick.js +59 -0
- package/src/ui.jsx +8 -8
- package/src/use-case-question.jsx +66 -0
- package/src/workflow/AgentPanel.jsx +82 -69
- package/src/workflow/agent-client.js +12 -2
- package/src/workflow/agent-panel.css +34 -32
- package/src/workflow/cozy-scene-node.css +2 -0
- package/src/workflow/workflow.css +2 -0
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/ardy/bridge.mjs +164 -146
- package/tools/ardy/visual-qa.mjs +5 -5
- package/tools/bench/EXP3.md +61 -0
- package/tools/bench/cclay_bench_extract_incam.py +125 -0
- package/tools/bench/cclay_bench_extract_obs.py +204 -0
- package/tools/bench/cclay_bench_runner.py +42 -0
- package/tools/bench/cube-contact.mjs +162 -0
- package/tools/bench/exp3.mjs +152 -0
- package/tools/bench/extract-bench-lib.mjs +216 -0
- package/tools/bench/extract-bench.mjs +302 -0
- package/tools/bench/fal-generate.mjs +88 -0
- package/tools/bench/fit/README.md +189 -0
- package/tools/bench/fit/camera.mjs +59 -0
- package/tools/bench/fit/contact.mjs +419 -0
- package/tools/bench/fit/footlock.mjs +234 -0
- package/tools/bench/fit/motion.mjs +85 -0
- package/tools/bench/fit/pin.mjs +27 -0
- package/tools/bench/fit/remote.mjs +105 -0
- package/tools/bench/fit-bench.mjs +126 -0
- package/tools/bench/fit-sanity.mjs +45 -0
- package/tools/bench/metrics.mjs +313 -0
- package/tools/bench/obs/depth.mjs +258 -0
- package/tools/bench/obs/extrinsics.mjs +175 -0
- package/tools/bench/obs/fit_mannequin_betas.py +340 -0
- package/tools/bench/obs/ground.mjs +294 -0
- package/tools/bench/obs/heading.mjs +151 -0
- package/tools/bench/obs/ladder.mjs +555 -0
- package/tools/bench/obs/mannequin-betas.json +124 -0
- package/tools/bench/obs/remote.mjs +83 -0
- package/tools/bench/obs/rest_joints.py +52 -0
- package/tools/bench/obs/ybot-targets.mjs +49 -0
- package/tools/bench/obs-bench.mjs +520 -0
- package/tools/bench/score.mjs +343 -0
- package/tools/bench/summarize.mjs +86 -0
- package/tools/dev/pages/privacy.html +13 -8
- package/tools/gt-render/browser.mjs +159 -0
- package/tools/gt-render/camera-math.mjs +276 -0
- package/tools/gt-render/page.mjs +267 -0
- package/tools/gt-render/render.mjs +514 -0
- package/tools/gt-render/scene-box.mjs +31 -0
- package/tools/gt-render/take-transform.mjs +87 -0
- package/tools/qa/css-rule-usage.mjs +283 -0
- package/tools/qa/studio-control-count.mjs +70 -32
- package/tools/run-tests.mjs +58 -3
- package/tools/track/DESIGN.md +513 -0
- package/tools/track/backfill-provenance.mjs +116 -0
- package/tools/track/budget.mjs +8 -0
- package/tools/track/check-rig.mjs +209 -0
- package/tools/track/diagnostics.schema.json +60 -0
- package/tools/track/export-rig.mjs +256 -0
- package/tools/track/fallback.mjs +7 -0
- package/tools/track/fk-parity-fixture.mjs +161 -0
- package/tools/track/gate.mjs +349 -0
- package/tools/track/masks.mjs +318 -0
- package/tools/track/metrics.mjs +201 -0
- package/tools/track/publish-obs.mjs +108 -0
- package/tools/track/py/check_env.py +61 -0
- package/tools/track/py/eval_lr.py +229 -0
- package/tools/track/py/lr_viterbi.py +294 -0
- package/tools/track/py/masks.py +405 -0
- package/tools/track/py/objective.py +382 -0
- package/tools/track/py/rig.py +508 -0
- package/tools/track/py/scene.py +326 -0
- package/tools/track/py/test_joint_indices.py +123 -0
- package/tools/track/py/test_lr_viterbi.py +195 -0
- package/tools/track/py/test_masks.py +229 -0
- package/tools/track/py/test_rig.py +288 -0
- package/tools/track/py/test_scene.py +354 -0
- package/tools/track/py/test_track.py +328 -0
- package/tools/track/py/track.py +411 -0
- package/tools/track/remote.mjs +140 -0
- package/tools/track/rig-dump.mjs +227 -0
- package/tools/track/run-box-tests.mjs +14 -0
- package/tools/track/run-box.mjs +168 -0
- package/tools/track/setup-box.sh +59 -0
- package/tools/track/study-2d.mjs +728 -0
- package/dist/assets/analytics-B1hnH66c.js +0 -1
- package/dist/assets/app-Cu1cexZR.css +0 -1
- package/dist/assets/app-Dxdh8kds.js +0 -4861
- package/dist/assets/shot-prompt-C_g2BHVc.css +0 -1
- package/dist/assets/shot-prompt-HVJRP4Gr.js +0 -17
- package/dist/assets/workflow-CJd-PDtV.js +0 -179
- package/dist/assets/workflow-DsudxKHF.css +0 -1
- package/src/fal-motion-studio.jsx +0 -180
- package/src/scene-history.js +0 -129
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
.v2-outliner {
|
|
2
|
+
min-height: 0;
|
|
3
|
+
max-height: none;
|
|
4
|
+
flex: 1 1 auto;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
background: var(--surface-panel, #151517);
|
|
8
|
+
border: 0;
|
|
9
|
+
color: var(--text-1, #e4e4e7);
|
|
10
|
+
font-family: var(--sans, 'IBM Plex Sans');
|
|
11
|
+
font-size: var(--outliner-ui-size, 12px);
|
|
12
|
+
line-height: 1.2;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.v2-outliner .hierarchy-heading {
|
|
17
|
+
height: var(--outliner-header-height, 36px);
|
|
18
|
+
min-height: var(--outliner-header-height, 36px);
|
|
19
|
+
padding: 0 var(--sp-2, 12px);
|
|
20
|
+
border-bottom: var(--outliner-border-width, 1px) solid var(--row-divider, #1d1d20);
|
|
21
|
+
background: var(--surface-panel, #151517);
|
|
22
|
+
color: var(--text-1, #e4e4e7);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.v2-outliner .hierarchy-heading strong {
|
|
26
|
+
margin: 0;
|
|
27
|
+
color: var(--text-1, #e4e4e7);
|
|
28
|
+
font-size: var(--outliner-title-size, 12px);
|
|
29
|
+
font-weight: 500;
|
|
30
|
+
letter-spacing: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.v2-outliner .hierarchy-kicker,
|
|
34
|
+
.v2-outliner .hierarchy-frame-status {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.v2-outliner .v2-outliner-count {
|
|
39
|
+
color: var(--text-3, #636369);
|
|
40
|
+
font-family: var(--mono, 'JetBrains Mono');
|
|
41
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
42
|
+
font-weight: 400;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.v2-outliner .v2-outliner-search-wrap {
|
|
46
|
+
position: relative;
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
height: var(--h-control, 28px);
|
|
50
|
+
min-height: var(--h-control, 28px);
|
|
51
|
+
margin: 0 var(--sp-2, 12px) var(--sp-1, 8px);
|
|
52
|
+
border-radius: var(--r-1, 4px);
|
|
53
|
+
background: var(--field, #0f0f11);
|
|
54
|
+
color: var(--text-3, #636369);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.v2-outliner .v2-outliner-search-icon {
|
|
58
|
+
position: absolute;
|
|
59
|
+
left: var(--sp-1, 8px);
|
|
60
|
+
color: var(--text-3, #636369);
|
|
61
|
+
font-size: var(--outliner-search-icon-size, 14px);
|
|
62
|
+
line-height: 1;
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.v2-outliner .v2-outliner-search {
|
|
67
|
+
width: 100%;
|
|
68
|
+
height: var(--h-control, 28px);
|
|
69
|
+
min-height: var(--h-control, 28px);
|
|
70
|
+
padding: 0 var(--sp-1, 8px) 0 var(--sp-3, 16px);
|
|
71
|
+
border: 0;
|
|
72
|
+
border-radius: var(--r-1, 4px);
|
|
73
|
+
outline: 0;
|
|
74
|
+
background: none;
|
|
75
|
+
color: var(--text-1, #e4e4e7);
|
|
76
|
+
font: inherit;
|
|
77
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.v2-outliner .v2-outliner-search::placeholder {
|
|
81
|
+
color: var(--text-3, #636369);
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.v2-outliner .v2-outliner-search:focus-visible {
|
|
86
|
+
outline: var(--outliner-border-width, 1px) solid var(--select, #e8a33d);
|
|
87
|
+
outline-offset: calc(var(--outliner-border-width, 1px) * -1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.v2-outliner .hierarchy-tree {
|
|
91
|
+
flex: 1 1 auto;
|
|
92
|
+
min-height: 0;
|
|
93
|
+
padding: 0 var(--sp-1, 8px) var(--sp-1, 8px);
|
|
94
|
+
overflow: auto;
|
|
95
|
+
background: var(--surface-panel, #151517);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.v2-outliner .hierarchy-row-wrap {
|
|
99
|
+
position: relative;
|
|
100
|
+
height: var(--h-row, 24px);
|
|
101
|
+
min-height: var(--h-row, 24px);
|
|
102
|
+
margin-left: calc(var(--hierarchy-depth, 0) * var(--outliner-indent, 14px));
|
|
103
|
+
padding-right: 0;
|
|
104
|
+
border-radius: var(--r-1, 4px);
|
|
105
|
+
background: none;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.v2-outliner .hierarchy-row-wrap:hover {
|
|
109
|
+
background: var(--surface-raised, #1e1e21);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.v2-outliner .hierarchy-row-wrap.selected {
|
|
113
|
+
background: var(--select-tint, rgba(232,163,61,.14));
|
|
114
|
+
box-shadow: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.v2-outliner .hierarchy-row-wrap[data-own-hidden="true"] {
|
|
118
|
+
opacity: .52;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.v2-outliner .hierarchy-row-wrap:before {
|
|
122
|
+
display: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.v2-outliner .hierarchy-toggle,
|
|
126
|
+
.v2-outliner .hierarchy-fold-space {
|
|
127
|
+
flex: 0 0 var(--outliner-chevron-slot, 12px);
|
|
128
|
+
width: var(--outliner-chevron-slot, 12px);
|
|
129
|
+
height: var(--h-row, 24px);
|
|
130
|
+
padding: 0;
|
|
131
|
+
border: 0;
|
|
132
|
+
background: none;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.v2-outliner .hierarchy-toggle {
|
|
136
|
+
display: grid;
|
|
137
|
+
place-items: center;
|
|
138
|
+
color: var(--text-3, #636369);
|
|
139
|
+
font-size: var(--outliner-chevron-size, 8px);
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
line-height: 1;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.v2-outliner .hierarchy-toggle:hover,
|
|
146
|
+
.v2-outliner .hierarchy-toggle:focus-visible {
|
|
147
|
+
color: var(--text-1, #e4e4e7);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.v2-outliner .hierarchy-toggle.placeholder,
|
|
151
|
+
.v2-outliner .hierarchy-fold-space {
|
|
152
|
+
pointer-events: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.v2-outliner .hierarchy-row {
|
|
156
|
+
width: 100%;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
height: var(--h-row, 24px);
|
|
159
|
+
padding: 0 var(--sp-1, 8px) 0 0;
|
|
160
|
+
border: 0;
|
|
161
|
+
background: none;
|
|
162
|
+
color: var(--text-row, #c9c9ce);
|
|
163
|
+
font: inherit;
|
|
164
|
+
font-size: var(--outliner-ui-size, 12px);
|
|
165
|
+
font-weight: 400;
|
|
166
|
+
text-align: left;
|
|
167
|
+
cursor: default;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.v2-outliner .hierarchy-row:not(.icon-only) {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: var(--sp-1, 8px);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.v2-outliner .hierarchy-row.icon-only {
|
|
177
|
+
flex: 0 0 auto;
|
|
178
|
+
display: inline-flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
gap: var(--sp-1, 8px);
|
|
181
|
+
width: auto;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.v2-outliner .v2-outliner-chip {
|
|
185
|
+
flex: 0 0 var(--outliner-chip-size, 6px);
|
|
186
|
+
width: var(--outliner-chip-size, 6px);
|
|
187
|
+
height: var(--outliner-chip-size, 6px);
|
|
188
|
+
border-radius: var(--outliner-chip-radius, 2px);
|
|
189
|
+
background: var(--chip-folder, #8a7a55);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.v2-outliner .v2-outliner-chip.folder { background: var(--chip-folder, #8a7a55); }
|
|
193
|
+
.v2-outliner .v2-outliner-chip.mesh { background: var(--chip-mesh, #7e8b99); }
|
|
194
|
+
.v2-outliner .v2-outliner-chip.cast { background: var(--chip-cast, #5fb584); }
|
|
195
|
+
.v2-outliner .v2-outliner-chip.cam { background: var(--camera, #a78bfa); }
|
|
196
|
+
.v2-outliner .v2-outliner-chip.light { background: var(--chip-light, #d9b84a); }
|
|
197
|
+
|
|
198
|
+
.v2-outliner .hierarchy-label {
|
|
199
|
+
flex: 1 1 auto;
|
|
200
|
+
min-width: 0;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
color: var(--text-row, #c9c9ce);
|
|
203
|
+
font-size: var(--outliner-ui-size, 12px);
|
|
204
|
+
font-weight: 400;
|
|
205
|
+
text-overflow: ellipsis;
|
|
206
|
+
white-space: nowrap;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.v2-outliner .hierarchy-row-wrap.selected .hierarchy-label {
|
|
210
|
+
color: var(--text-1, #e4e4e7);
|
|
211
|
+
font-weight: 500;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.v2-outliner .v2-outliner-type {
|
|
215
|
+
flex: 0 0 auto;
|
|
216
|
+
margin-left: auto;
|
|
217
|
+
color: var(--text-off, #4f4f55);
|
|
218
|
+
font-size: var(--outliner-type-size, 10.5px);
|
|
219
|
+
font-weight: 400;
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.v2-outliner .hierarchy-status,
|
|
224
|
+
.v2-outliner .hierarchy-badge {
|
|
225
|
+
display: none;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.v2-outliner .hierarchy-eye {
|
|
229
|
+
flex: 0 0 var(--outliner-eye-closed-width, 0px);
|
|
230
|
+
width: var(--outliner-eye-closed-width, 0px);
|
|
231
|
+
height: var(--h-row, 24px);
|
|
232
|
+
padding: 0;
|
|
233
|
+
border: 0;
|
|
234
|
+
background: none;
|
|
235
|
+
color: var(--text-2, #9b9ba1);
|
|
236
|
+
opacity: 0;
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.v2-outliner .hierarchy-eye:focus-visible {
|
|
241
|
+
flex-basis: var(--outliner-eye-width, 24px);
|
|
242
|
+
width: var(--outliner-eye-width, 24px);
|
|
243
|
+
opacity: 1;
|
|
244
|
+
outline: var(--outliner-border-width, 1px) solid var(--select, #e8a33d);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.v2-outliner .hierarchy-row-wrap[data-drop="over"] {
|
|
248
|
+
border: var(--outliner-border-width, 1px) dashed var(--select, #e8a33d);
|
|
249
|
+
background: var(--select-tint, rgba(232,163,61,.14));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.v2-outliner .hierarchy-row-wrap[data-drop="target"] {
|
|
253
|
+
border: var(--outliner-border-width, 1px) solid var(--row-divider, #1d1d20);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill {
|
|
257
|
+
flex: 1 1 auto;
|
|
258
|
+
min-width: 0;
|
|
259
|
+
max-width: none;
|
|
260
|
+
height: var(--h-row, 24px);
|
|
261
|
+
margin: 0 var(--sp-1, 8px) 0 var(--sp-1, 8px);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .dropdown,
|
|
265
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .trigger {
|
|
266
|
+
width: 100%;
|
|
267
|
+
min-width: 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .trigger {
|
|
271
|
+
height: var(--h-row, 24px);
|
|
272
|
+
gap: var(--outliner-trigger-gap, 6px);
|
|
273
|
+
padding: 0 var(--sp-1, 8px);
|
|
274
|
+
border: 0;
|
|
275
|
+
border-radius: var(--r-1, 4px);
|
|
276
|
+
background: var(--surface-active, #26262a);
|
|
277
|
+
color: var(--text-row, #c9c9ce);
|
|
278
|
+
font: inherit;
|
|
279
|
+
font-size: var(--outliner-ui-size, 12px);
|
|
280
|
+
text-align: left;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .trigger:hover,
|
|
284
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .dropdown.open .trigger {
|
|
285
|
+
background: var(--surface-raised, #1e1e21);
|
|
286
|
+
color: var(--text-1, #e4e4e7);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.v2-outliner .hierarchy-row-wrap .hierarchy-scene-pill .dd-caret {
|
|
290
|
+
flex: 0 0 var(--outliner-chevron-slot, 12px);
|
|
291
|
+
width: var(--outliner-chevron-slot, 12px);
|
|
292
|
+
height: var(--outliner-chevron-slot, 12px);
|
|
293
|
+
color: var(--text-3, #636369);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.v2-outliner .hierarchy-scene-hint {
|
|
297
|
+
flex: none;
|
|
298
|
+
margin: 0;
|
|
299
|
+
padding: 0 var(--sp-2, 12px) var(--sp-1, 8px);
|
|
300
|
+
color: var(--text-2, #9b9ba1);
|
|
301
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.v2-outliner .v2-outliner-empty {
|
|
305
|
+
min-height: var(--h-row, 24px);
|
|
306
|
+
padding: var(--sp-1, 8px);
|
|
307
|
+
color: var(--text-3, #636369);
|
|
308
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.v2-outliner .hierarchy-rename-input {
|
|
312
|
+
flex: 1 1 auto;
|
|
313
|
+
min-width: 0;
|
|
314
|
+
height: var(--h-control, 28px);
|
|
315
|
+
padding: 0 var(--sp-1, 8px);
|
|
316
|
+
border: 0;
|
|
317
|
+
border-radius: var(--r-1, 4px);
|
|
318
|
+
background: var(--field, #0f0f11);
|
|
319
|
+
color: var(--text-1, #e4e4e7);
|
|
320
|
+
font: inherit;
|
|
321
|
+
font-size: var(--outliner-ui-size, 12px);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.v2-outliner .hierarchy-rename-input:focus-visible {
|
|
325
|
+
outline: var(--outliner-border-width, 1px) solid var(--select, #e8a33d);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.v2-outliner .hierarchy-context-menu {
|
|
329
|
+
min-width: var(--outliner-menu-width, 220px);
|
|
330
|
+
padding: var(--outliner-menu-padding, 4px);
|
|
331
|
+
border: var(--outliner-border-width, 1px) solid var(--row-divider, #1d1d20);
|
|
332
|
+
border-radius: var(--r-2, 6px);
|
|
333
|
+
background: var(--surface-raised, #1e1e21);
|
|
334
|
+
box-shadow: 0 var(--sp-1, 8px) var(--sp-3, 16px) var(--overlay, rgba(12,12,13,.78));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.v2-outliner .hierarchy-context-item {
|
|
338
|
+
min-height: var(--h-control, 28px);
|
|
339
|
+
padding: 0 var(--sp-1, 8px);
|
|
340
|
+
border: 0;
|
|
341
|
+
border-radius: var(--r-1, 4px);
|
|
342
|
+
background: none;
|
|
343
|
+
color: var(--text-row, #c9c9ce);
|
|
344
|
+
font: inherit;
|
|
345
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
346
|
+
text-align: left;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.v2-outliner .hierarchy-context-item:hover,
|
|
350
|
+
.v2-outliner .hierarchy-context-item:focus-visible {
|
|
351
|
+
background: var(--surface-active, #26262a);
|
|
352
|
+
color: var(--text-1, #e4e4e7);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.v2-outliner .hierarchy-context-item.danger {
|
|
356
|
+
color: var(--danger, #e5484d);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.v2-outliner .add-object-item {
|
|
360
|
+
min-height: var(--h-control, 28px);
|
|
361
|
+
padding: 0 var(--sp-1, 8px);
|
|
362
|
+
border: 0;
|
|
363
|
+
border-radius: var(--r-1, 4px);
|
|
364
|
+
background: none;
|
|
365
|
+
color: var(--text-row, #c9c9ce);
|
|
366
|
+
font: inherit;
|
|
367
|
+
font-size: var(--outliner-secondary-size, 11px);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.v2-outliner .add-object-item:hover,
|
|
371
|
+
.v2-outliner .add-object-item:focus-visible {
|
|
372
|
+
background: var(--surface-active, #26262a);
|
|
373
|
+
color: var(--text-1, #e4e4e7);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.v2-outliner .add-object-heading {
|
|
377
|
+
padding: var(--sp-1, 8px) var(--sp-1, 8px) calc(var(--sp-1, 8px) / 2);
|
|
378
|
+
color: var(--text-3, #636369);
|
|
379
|
+
font-size: var(--outliner-type-size, 10.5px);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@media (max-width: 700px) {
|
|
383
|
+
.v2-outliner .v2-outliner-type {
|
|
384
|
+
display: none;
|
|
385
|
+
}
|
|
386
|
+
}
|
package/src/hierarchy-panel.jsx
CHANGED
|
@@ -2,8 +2,9 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|
|
2
2
|
import { ko, isKo } from "./locale.js";
|
|
3
3
|
import { buildHierarchyNodes } from "./hierarchy-model.js";
|
|
4
4
|
import { sceneObjectIdFromHierarchy } from "./scene-objects.js";
|
|
5
|
-
import
|
|
5
|
+
import { CatalogueEntries, displayObjectLabel } from "./object-catalog.jsx";
|
|
6
6
|
import { Dropdown } from "./ui.jsx";
|
|
7
|
+
import "./hierarchy-panel.css";
|
|
7
8
|
|
|
8
9
|
const HIERARCHY_LABELS_KO = {
|
|
9
10
|
"SCENE 01": "장면 01",
|
|
@@ -35,6 +36,8 @@ const HIERARCHY_LABELS_KO = {
|
|
|
35
36
|
Environment: "환경",
|
|
36
37
|
Props: "소품",
|
|
37
38
|
Light: "조명",
|
|
39
|
+
"Scene structure": "장면 구조",
|
|
40
|
+
"Scene hierarchy": "장면 계층",
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
const FALLBACK_SCENES = [{ id: "current-scene", name: "SCENE 01" }];
|
|
@@ -198,6 +201,57 @@ function displayHierarchyLabel(node) {
|
|
|
198
201
|
return isKo ? (HIERARCHY_LABELS_KO[node.label] ?? node.label) : node.label;
|
|
199
202
|
}
|
|
200
203
|
|
|
204
|
+
const OUTLINER_TYPES = {
|
|
205
|
+
folder: "Folder",
|
|
206
|
+
mesh: "Mesh",
|
|
207
|
+
cast: "Cast",
|
|
208
|
+
cam: "Cam",
|
|
209
|
+
light: "Light",
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
function outlinerTypeFor(node) {
|
|
213
|
+
const key = node.kind === "object"
|
|
214
|
+
? "mesh"
|
|
215
|
+
: node.kind === "character" || node.kind === "bone"
|
|
216
|
+
? "cast"
|
|
217
|
+
: node.kind === "camera"
|
|
218
|
+
? "cam"
|
|
219
|
+
: node.kind === "light"
|
|
220
|
+
? "light"
|
|
221
|
+
: "folder";
|
|
222
|
+
const label = key === "folder"
|
|
223
|
+
? ko(OUTLINER_TYPES[key], "폴더")
|
|
224
|
+
: key === "mesh"
|
|
225
|
+
? ko(OUTLINER_TYPES[key], "메시")
|
|
226
|
+
: key === "cast"
|
|
227
|
+
? ko(OUTLINER_TYPES[key], "캐스트")
|
|
228
|
+
: key === "cam"
|
|
229
|
+
? ko(OUTLINER_TYPES[key], "카메라")
|
|
230
|
+
: ko(OUTLINER_TYPES[key], "조명");
|
|
231
|
+
return { key, label };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function OutlinerChip({ type }) {
|
|
235
|
+
return <span className={`v2-outliner-chip ${type}`} aria-hidden="true" />;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function countHierarchyNodes(nodes) {
|
|
239
|
+
return nodes.reduce((count, node) => count + 1 + countHierarchyNodes(node.children ?? []), 0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function filterHierarchyNodes(nodes, query, showB) {
|
|
243
|
+
const normalized = query.trim().toLocaleLowerCase();
|
|
244
|
+
const filterNode = (node) => {
|
|
245
|
+
if (node.optional === "showB" && !showB) return null;
|
|
246
|
+
if (!normalized) return node;
|
|
247
|
+
const label = displayHierarchyLabel(node).toLocaleLowerCase();
|
|
248
|
+
const children = (node.children ?? []).map(filterNode).filter(Boolean);
|
|
249
|
+
if (!label.includes(normalized) && children.length === 0) return null;
|
|
250
|
+
return children.length ? { ...node, children } : { ...node, children: undefined };
|
|
251
|
+
};
|
|
252
|
+
return nodes.map(filterNode).filter(Boolean);
|
|
253
|
+
}
|
|
254
|
+
|
|
201
255
|
function indexParents(nodes, parent = null, parents = new Map()) {
|
|
202
256
|
for (const node of nodes) {
|
|
203
257
|
if (parent) parents.set(node.id, parent);
|
|
@@ -435,6 +489,7 @@ function TreeRow({
|
|
|
435
489
|
// only exists when the caller asked for reparenting.
|
|
436
490
|
const dropEvents = rowDrag || drop || null;
|
|
437
491
|
const label = displayHierarchyLabel(node);
|
|
492
|
+
const outlinerType = outlinerTypeFor(node);
|
|
438
493
|
const rowWrapRef = useRef(null);
|
|
439
494
|
const inputRef = useRef(null);
|
|
440
495
|
// A commit/cancel may race the blur that follows the input unmounting;
|
|
@@ -495,7 +550,7 @@ function TreeRow({
|
|
|
495
550
|
// blur commits (docs/unity-reference.md §9.7). A div, not the
|
|
496
551
|
// row button — an input inside a button is invalid HTML.
|
|
497
552
|
<div className={"hierarchy-row" + (touched ? " agent-touched" : "")}>
|
|
498
|
-
<
|
|
553
|
+
<OutlinerChip type={outlinerType.key} />
|
|
499
554
|
<input
|
|
500
555
|
ref={inputRef}
|
|
501
556
|
className="hierarchy-rename-input"
|
|
@@ -524,10 +579,11 @@ function TreeRow({
|
|
|
524
579
|
onClick={() => onSelect(node.id)}
|
|
525
580
|
onDoubleClick={onRenameStart ?? undefined}
|
|
526
581
|
>
|
|
527
|
-
<
|
|
582
|
+
<OutlinerChip type={outlinerType.key} />
|
|
528
583
|
{showLabel && <span className="hierarchy-label">{label}</span>}
|
|
529
584
|
{status && <span className="hierarchy-status">{status}</span>}
|
|
530
585
|
{badge !== null && badge !== undefined && badge !== 0 && <span className="hierarchy-badge">{badge}</span>}
|
|
586
|
+
<span className="v2-outliner-type">{outlinerType.label}</span>
|
|
531
587
|
</button>
|
|
532
588
|
)}
|
|
533
589
|
{(node.kind === "object" || node.kind === "character") && onToggleHidden && (
|
|
@@ -586,6 +642,7 @@ export default function HierarchyPanel({
|
|
|
586
642
|
onSceneDelete,
|
|
587
643
|
}) {
|
|
588
644
|
const [expanded, setExpanded] = useState(() => new Set(["shot", "characterA"]));
|
|
645
|
+
const [search, setSearch] = useState("");
|
|
589
646
|
const [contextMenu, setContextMenu] = useState(null);
|
|
590
647
|
// Row currently in in-place rename. The panel owns it: F2/Return and the
|
|
591
648
|
// row context menu are the only ways in, so app state stays out of it.
|
|
@@ -621,6 +678,14 @@ export default function HierarchyPanel({
|
|
|
621
678
|
}));
|
|
622
679
|
}, [activeSceneName, sceneObjects, characters]);
|
|
623
680
|
const parents = useMemo(() => indexParents(hierarchyNodes), [hierarchyNodes]);
|
|
681
|
+
const filteredHierarchyNodes = useMemo(
|
|
682
|
+
() => filterHierarchyNodes(hierarchyNodes, search, showB),
|
|
683
|
+
[hierarchyNodes, search, showB],
|
|
684
|
+
);
|
|
685
|
+
const outlinerCount = useMemo(
|
|
686
|
+
() => countHierarchyNodes(filteredHierarchyNodes),
|
|
687
|
+
[filteredHierarchyNodes],
|
|
688
|
+
);
|
|
624
689
|
|
|
625
690
|
useEffect(() => {
|
|
626
691
|
setExpanded((current) => {
|
|
@@ -795,9 +860,9 @@ export default function HierarchyPanel({
|
|
|
795
860
|
nodes.flatMap((node) => {
|
|
796
861
|
if (node.optional === "showB" && !showB) return [];
|
|
797
862
|
const sceneRoot = node.id === SCENE_ROOT_ID;
|
|
798
|
-
//
|
|
799
|
-
//
|
|
800
|
-
const open = sceneRoot || expanded.has(node.id);
|
|
863
|
+
// Search opens only the filtered branches. The stored expansion set is
|
|
864
|
+
// left untouched so clearing the query restores the author's tree.
|
|
865
|
+
const open = sceneRoot || expanded.has(node.id) || Boolean(search.trim());
|
|
801
866
|
const editing = editingId === node.id;
|
|
802
867
|
return [
|
|
803
868
|
<TreeRow
|
|
@@ -846,22 +911,26 @@ export default function HierarchyPanel({
|
|
|
846
911
|
});
|
|
847
912
|
|
|
848
913
|
return (
|
|
849
|
-
<section className="hierarchy-pane" aria-label={ko("
|
|
914
|
+
<section className="hierarchy-pane v2-outliner" aria-label={ko("Outliner", "아웃라이너")}>
|
|
850
915
|
<div className="hierarchy-heading">
|
|
851
|
-
<
|
|
852
|
-
|
|
853
|
-
<strong>{ko("Scene structure", "장면 구조")}</strong>
|
|
854
|
-
</div>
|
|
855
|
-
<span className="hierarchy-frame-status">{motionFrames ? (isKo ? `${motionFrames}프레임` : `${motionFrames} frames`) : ko("Blocking", "블로킹")}</span>
|
|
916
|
+
<strong>{ko("Outliner", "아웃라이너")}</strong>
|
|
917
|
+
<span className="v2-outliner-count" data-testid="outliner-count">{outlinerCount}</span>
|
|
856
918
|
</div>
|
|
857
|
-
|
|
858
|
-
<
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
919
|
+
<label className="v2-outliner-search-wrap">
|
|
920
|
+
<span className="v2-outliner-search-icon" aria-hidden="true">⌕</span>
|
|
921
|
+
<input
|
|
922
|
+
className="v2-outliner-search"
|
|
923
|
+
type="search"
|
|
924
|
+
value={search}
|
|
925
|
+
placeholder={ko("Search", "검색")}
|
|
926
|
+
aria-label={ko("Search Outliner", "아웃라이너 검색")}
|
|
927
|
+
onChange={(event) => setSearch(event.target.value)}
|
|
928
|
+
/>
|
|
929
|
+
</label>
|
|
863
930
|
<div className="hierarchy-tree" role="tree" ref={treeRef} onKeyDown={onTreeKeyDown} onContextMenu={openCreateMenu}>
|
|
864
|
-
{renderNodes(
|
|
931
|
+
{filteredHierarchyNodes.length > 0 ? renderNodes(filteredHierarchyNodes) : (
|
|
932
|
+
<div className="v2-outliner-empty" role="status">{ko("No matches", "일치하는 항목 없음")}</div>
|
|
933
|
+
)}
|
|
865
934
|
</div>
|
|
866
935
|
{sceneHint && (
|
|
867
936
|
<p className="hierarchy-scene-hint" role="status">{sceneHint}</p>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
// The durations the
|
|
1
|
+
export const I2V_MOTION_MODEL = "minimax/h3-max-turbo/image-to-video";
|
|
2
|
+
export const I2V_MOTION_RESOLUTION = "480P";
|
|
3
|
+
export const I2V_MOTION_MIN_DURATION = 5;
|
|
4
|
+
export const I2V_MOTION_MAX_DURATION = 15;
|
|
5
|
+
// The durations the AI motion card offers. 15 s (362 frames) is the measured upper
|
|
6
6
|
// end the H3 endpoint accepts and the extractor handles (#380 sit-to-bench).
|
|
7
|
-
export const
|
|
7
|
+
export const I2V_MOTION_DURATIONS = Object.freeze([5, 10, 15]);
|
|
8
8
|
// H3's 480P output is 832x480. The reference still is captured at exactly
|
|
9
9
|
// twice that canvas, and the Studio switches its viewport to the matching
|
|
10
10
|
// "fal 480P" ratio when A is captured, so the user composes the shot on the
|
|
11
11
|
// canvas the clip will have.
|
|
12
|
-
export const
|
|
13
|
-
export const
|
|
12
|
+
export const I2V_MOTION_STILL_OUTPUT = Object.freeze({ width: 1664, height: 960 });
|
|
13
|
+
export const I2V_MOTION_SHOT_ASPECT = "fal 480P";
|
|
14
14
|
|
|
15
15
|
export function motionApiOrigin(location = globalThis.location) {
|
|
16
16
|
const configured = globalThis.__COZYCLAY_MOTION_API__;
|
|
@@ -51,24 +51,24 @@ async function request(path, body, fetchImpl = fetch) {
|
|
|
51
51
|
return payload;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export function
|
|
54
|
+
export function submitMotionJob(input, fetchImpl = fetch) {
|
|
55
55
|
const kind = input?.kind === "interpolate" ? "interpolate" : "act";
|
|
56
56
|
const body = {
|
|
57
57
|
...(kind === "interpolate" ? { stillA: input.stillA, stillB: input.stillB } : { still: input.still }),
|
|
58
58
|
prompt: input.prompt,
|
|
59
|
-
duration: Number(input.duration ??
|
|
59
|
+
duration: Number(input.duration ?? I2V_MOTION_MIN_DURATION),
|
|
60
60
|
};
|
|
61
61
|
return request(`/v1/motion/${kind}`, body, fetchImpl);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export function
|
|
64
|
+
export function getMotionJob(id, fetchImpl = fetch) {
|
|
65
65
|
return request(`/v1/motion/jobs/${encodeURIComponent(id)}`, undefined, fetchImpl);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export async function
|
|
68
|
+
export async function waitForMotionJob(id, { intervalMs = 500, timeoutMs = 120_000, fetchImpl = fetch, onUpdate } = {}) {
|
|
69
69
|
const deadline = Date.now() + timeoutMs;
|
|
70
70
|
while (Date.now() < deadline) {
|
|
71
|
-
const payload = await
|
|
71
|
+
const payload = await getMotionJob(id, fetchImpl);
|
|
72
72
|
const job = payload?.job ?? null;
|
|
73
73
|
onUpdate?.(job, payload);
|
|
74
74
|
if (job?.status === "done" || job?.status === "failed") return payload;
|