cozyclay 3.0.3 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/INSTALL_FOR_AGENTS.md +146 -0
- package/README.md +74 -192
- package/THIRD_PARTY_NOTICES.md +0 -21
- package/bin/agent/agent-routes.mjs +29 -62
- package/bin/agent/agent-runner.mjs +5 -3
- package/bin/agent/main-agent.mjs +70 -0
- package/bin/agent/main-prompt.mjs +17 -0
- package/bin/agent/plan-tool.mjs +114 -0
- package/bin/agent/script-tool.mjs +2 -0
- package/bin/agent/sculpt-sketch.mjs +190 -0
- package/bin/agent/session-store.mjs +4 -3
- package/bin/agent/sketch-code.mjs +151 -0
- package/bin/agent/sketch-sandbox.mjs +102 -0
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-task-routes.mjs +185 -0
- package/bin/agent/studio-tasks.mjs +156 -0
- package/bin/agent/studio-tools.mjs +3 -2
- package/bin/agent/studio-turn-transaction.mjs +76 -0
- package/bin/agent/turn-frames.mjs +4 -0
- package/bin/cozyclay.mjs +5 -7
- package/dist/app/index.html +7 -6
- package/dist/assets/TaskBoard-ngdqiu7u.js +1 -0
- package/dist/assets/app-BlwOpest.css +1 -0
- package/dist/assets/app-DmR7jBkz.js +5144 -0
- package/dist/assets/compile-worker-D0pKioa0.js +5 -0
- package/dist/assets/landing-y3EqDgSZ.js +1 -0
- package/dist/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
- package/dist/assets/motion3-compile-BB3_1-EB.js +1 -0
- package/dist/assets/scene-asset-sync-CBx7XRti.css +1 -0
- package/dist/assets/scene-asset-sync-Cgdtr1Yw.js +13 -0
- package/dist/assets/task-board-ErQvfoaz.js +14 -0
- package/dist/assets/workflow-zQM-EKW1.js +179 -0
- package/dist/assets/x-bot-tpose-body-BusyR3eg.json +1 -0
- package/dist/assets/y-bot-tpose-body-Dy1VKChZ.json +1 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/greybox-to-video/index.html +2 -3
- package/dist/index.html +7 -57
- package/dist/llms.txt +2 -1
- package/dist/previs-software/index.html +2 -2
- package/dist/privacy/index.html +3 -7
- package/dist/seedance-camera-control/index.html +2 -2
- package/dist/sitemap.xml +5 -5
- package/dist/sw.js +5 -1
- package/dist/thumbs/blank-stage-dark.webp +0 -0
- package/dist/thumbs/blank-stage-light.webp +0 -0
- package/dist/workflow/index.html +5 -4
- package/mcp/mesh-file.mjs +3 -1
- package/mcp/server.mjs +3 -0
- package/mcp/tool-handlers.mjs +2 -2
- package/package.json +5 -3
- package/src/App.jsx +51 -282
- package/src/analytics.js +3 -148
- package/src/app-stage.jsx +1 -1
- package/src/asset-pane.jsx +5 -10
- package/src/auto-flat.js +10 -0
- package/src/bus-tasks.js +11 -5
- package/src/command-bus.js +1 -1
- package/src/commands/elements.js +4 -3
- package/src/commands/motion3-compile.js +51 -27
- package/src/commands/motion3.js +3 -3
- package/src/commands/objects.js +1 -1
- package/src/commands/project.js +1 -1
- package/src/commands/shot.js +16 -4
- package/src/controls.jsx +0 -11
- package/src/cuts.js +11 -0
- package/src/domains/cast.js +3 -2
- package/src/domains/motion.js +3 -10
- package/src/domains/playback.js +32 -0
- package/src/domains/scenes.js +3 -22
- package/src/domains/shots.js +5 -5
- package/src/dualview.jsx +11 -15
- package/src/hierarchy-panel.css +18 -4
- package/src/hierarchy-panel.jsx +12 -11
- package/src/kits/held.js +3 -2
- package/src/light-blockers.js +2 -2
- package/src/main.jsx +5 -0
- package/src/material-look.js +189 -0
- package/src/material-presets.js +78 -0
- package/src/material-textures.js +157 -0
- package/src/motion/ground.js +5 -14
- package/src/motion/playback-frame-store.js +79 -0
- package/src/motion/playback-probe.js +16 -0
- package/src/motion/playback-subject.js +7 -0
- package/src/motion/timeline.css +43 -5
- package/src/motion/timeline.jsx +4 -3
- package/src/motion3/body.js +37 -5
- package/src/motion3/carried.js +11 -3
- package/src/motion3/compile-job.js +1 -1
- package/src/motion3/compiler/compile.js +7 -1
- package/src/motion3/compiler/finger-close.js +137 -0
- package/src/motion3/compiler/limbs.js +18 -3
- package/src/motion3/compiler/pose.js +6 -0
- package/src/motion3/compiler/validate-objects.js +17 -2
- package/src/motion3/compiler/validate-parts.js +2 -1
- package/src/motion3/compiler/vocab.js +4 -4
- package/src/motion3/describe.js +2 -2
- package/src/motion3/fix/index.js +5 -3
- package/src/motion3/flight.js +38 -0
- package/src/motion3/free-motion.js +10 -7
- package/src/motion3/load.js +125 -0
- package/src/motion3/mass.js +23 -0
- package/src/motion3/object-keys.js +11 -6
- package/src/motion3/object-pose.js +11 -3
- package/src/motion3/pipeline.js +3 -0
- package/src/motion3/qa/explain.js +3 -1
- package/src/motion3/qa/grasp-checks.js +123 -0
- package/src/motion3/qa/hints-grasp.js +71 -0
- package/src/motion3/qa/index.js +3 -1
- package/src/motion3/qa/object-checks.js +7 -2
- package/src/motion3/qa/patch.js +2 -1
- package/src/motion3/qa/spec-checks.js +10 -1
- package/src/motion3/schema/fields.js +3 -3
- package/src/motion3/schema/topics.js +9 -8
- package/src/motion3/schema/types.js +4 -1
- package/src/motion3/seat.js +84 -0
- package/src/motion3/settle.js +11 -6
- package/src/motion3/shapes.js +70 -0
- package/src/motion3/skills/catch.js +71 -0
- package/src/motion3/skills/index.js +10 -3
- package/src/motion3/skills/info.js +13 -0
- package/src/motion3/skills/throw.js +72 -0
- package/src/object-catalog.jsx +0 -4
- package/src/object-gizmo.jsx +2 -1
- package/src/object-look.js +9 -5
- package/src/object-path.js +1 -1
- package/src/panels/ProjectPanel.jsx +42 -21
- package/src/panels/details.css +15 -4
- package/src/popover.js +37 -0
- package/src/posestudio.jsx +15 -10
- package/src/primitive-look.js +38 -0
- package/src/project-browser-art.jsx +19 -0
- package/src/project-browser.css +74 -121
- package/src/project-browser.jsx +36 -60
- package/src/props.jsx +24 -35
- package/src/render-passes.js +7 -1
- package/src/retired-kinds.js +37 -0
- package/src/scene-objects.js +5 -9
- package/src/scenes.js +4 -5
- package/src/sculpt-colours.js +65 -0
- package/src/sculpt-compare.js +13 -50
- package/src/sculpt-csg.js +112 -0
- package/src/sculpt-curve.js +123 -0
- package/src/sculpt-cutters.js +43 -0
- package/src/sculpt-detail.js +207 -0
- package/src/sculpt-geometry-loft-convex.js +100 -0
- package/src/sculpt-geometry-shapes.js +250 -0
- package/src/sculpt-geometry.js +33 -15
- package/src/sculpt-loft-rings.js +225 -0
- package/src/sculpt-noise.js +65 -0
- package/src/sculpt-part-fields.js +27 -0
- package/src/sculpt-recipe-read.js +65 -0
- package/src/sculpt-recipe.js +33 -75
- package/src/sculpt-run.js +1 -1
- package/src/sculpt-scatter-items.js +183 -0
- package/src/sculpt-scatter-shape.js +57 -0
- package/src/sculpt-scatter.js +124 -0
- package/src/sculpt-shapes-curved.js +211 -0
- package/src/sculpt-shapes-loft-convex.js +218 -0
- package/src/sculpt-shapes.js +138 -0
- package/src/sculpt-sketch-state.js +76 -0
- package/src/sculpt-sketch.jsx +124 -0
- package/src/sculpt-surface-fields.js +65 -0
- package/src/settings-menu.jsx +1 -20
- package/src/shell/BottomDock.jsx +9 -9
- package/src/shell/MenuBar.jsx +1 -9
- package/src/shell/PreferencesDialog.jsx +3 -4
- package/src/shell/ViewportToolbar.jsx +3 -3
- package/src/shell/add-camera-shot.js +11 -0
- package/src/shell/glass-regions.css +3 -2
- package/src/shell/glass.css +0 -5
- package/src/shell/lens-scrub-math.js +51 -0
- package/src/shell/lens-scrub.css +73 -0
- package/src/shell/lens-scrub.jsx +98 -0
- package/src/shell/mode.css +6 -5
- package/src/shell/preferences.css +1 -32
- package/src/shell/shell.css +18 -1
- package/src/shell/studio-shell-context.js +5 -0
- package/src/shot-frame.js +26 -0
- package/src/stage-canvas-rigs.jsx +7 -8
- package/src/stage-characters.jsx +26 -0
- package/src/stage-gizmo.js +43 -0
- package/src/stage-labels-ko.js +0 -6
- package/src/stage-startup-defaults.js +3 -9
- package/src/starter-scenes.js +5 -11
- package/src/studio-agent-commands.js +2 -2
- package/src/studio-agent-protocol.js +2 -7
- package/src/studio-app-binding.js +1 -1
- package/src/studio-elements.js +6 -2
- package/src/styles/themes.css +13 -0
- package/src/styles.css +6 -674
- package/src/text/text-object.jsx +1 -1
- package/src/ui.jsx +8 -16
- package/src/use-embed-bridge.js +3 -6
- package/src/use-render-activity.js +3 -1
- package/src/view-ghosts.jsx +5 -3
- package/src/viewport-visible-rect.js +37 -0
- package/src/workflow/AgentPanel.jsx +79 -46
- package/src/workflow/AgentPlanCard.jsx +41 -0
- package/src/workflow/AgentProgressCard.jsx +1 -1
- package/src/workflow/TaskBoard.jsx +102 -0
- package/src/workflow/TaskInline.jsx +114 -0
- package/src/workflow/agent-client.js +25 -36
- package/src/workflow/agent-panel.css +14 -1
- package/src/workflow/agent-plan.css +93 -0
- package/src/workflow/agent-plan.js +59 -0
- package/src/workflow/attachment-image.js +10 -3
- package/src/workflow/attachment-video.js +91 -0
- package/src/workflow/task-board.css +98 -0
- package/src/workflow/task-board.js +169 -0
- package/tools/check-eslint.mjs +2 -1
- package/tools/check-knip.mjs +2 -1
- package/tools/dev/pages/greybox-to-video.html +2 -3
- package/tools/dev/pages/previs-software.html +2 -2
- package/tools/dev/pages/privacy.html +3 -7
- package/tools/dev/pages/seedance-camera-control.html +2 -2
- package/tools/dev-full.mjs +11 -2
- package/tools/eslint-baseline.json +6 -6
- package/tools/knip-baseline.json +0 -11
- package/tools/loc-baseline.json +30 -31
- package/tools/metrics-snapshot.mjs +43 -5
- package/tools/render-start-thumbs.mjs +175 -0
- package/tools/run-tests.mjs +10 -17
- package/tools/sitemap.mjs +1 -1
- package/dist/assets/analytics-BibyE5ar.js +0 -6
- package/dist/assets/app-DhRJ-PBz.js +0 -5088
- package/dist/assets/app-f-fkV5uP.css +0 -1
- package/dist/assets/compile-worker-DqiA4AaN.js +0 -5
- package/dist/assets/first-shot-handoff-Qx7SKl38.js +0 -1
- package/dist/assets/landing-DYg87MDY.js +0 -1
- package/dist/assets/scene-asset-sync-DBYQBR0T.js +0 -20
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +0 -1
- package/dist/assets/workflow-BSA22Ofr.js +0 -179
- package/dist/scenes/city-block.cclayproject +0 -1
- package/src/burn-in.js +0 -91
- package/src/camera-tutorial.jsx +0 -520
- package/src/facing-marks.js +0 -88
- package/src/first-shot-handoff.js +0 -44
- package/src/panels/motion.css +0 -197
- package/src/set-pieces.jsx +0 -183
- package/src/tutorial-analytics.js +0 -86
- package/src/tutorial-walk.js +0 -17
- package/src/use-camera-tutorial.js +0 -50
- package/src/use-semantic-state.js +0 -12
- package/tools/metrics/archive-traffic.mjs +0 -138
- package/tools/perf/ik-camera-drag.mjs +0 -138
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { placementAt } from "./root-path.js";
|
|
2
|
+
import { shotAtFrame } from "./cuts.js";
|
|
3
|
+
|
|
4
|
+
export function characterGizmoView({ selected, characters, activeCharacterId, activeCharacter, motion, shots, activeId, frame }) {
|
|
5
|
+
if (!selected) return null;
|
|
6
|
+
const entry = characters.find((item) => item.id === activeId);
|
|
7
|
+
if (!entry || entry.hidden) return null;
|
|
8
|
+
const hasTake = activeId === activeCharacterId ? Boolean(motion) : Boolean(activeCharacter.sessionMotion);
|
|
9
|
+
const placement = hasTake ? entry : placementAt(entry, frame, { shotAt: (at) => shotAtFrame(shots, at) });
|
|
10
|
+
return { position: [placement.x, entry.y ?? 0, placement.z], rot: placement.rot };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function characterGizmoObject(gizmoView, entry) {
|
|
14
|
+
if (!gizmoView) return null;
|
|
15
|
+
return {
|
|
16
|
+
id: "__character__",
|
|
17
|
+
x: gizmoView.position[0],
|
|
18
|
+
y: gizmoView.position[1],
|
|
19
|
+
z: gizmoView.position[2],
|
|
20
|
+
height: 1.15,
|
|
21
|
+
footprint: { width: 0.6, depth: 0.6 },
|
|
22
|
+
rotY: gizmoView.rot ?? entry?.rot ?? 0,
|
|
23
|
+
scaleX: entry?.scale ?? 1,
|
|
24
|
+
scaleY: entry?.scale ?? 1,
|
|
25
|
+
scaleZ: entry?.scale ?? 1,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function playbackSceneWithTrack(base, subjectTrack, followTrack) {
|
|
30
|
+
return { ...base, subjectTrack, cameraTrack: followTrack };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function followCameraActive(mode, track, frame, preview, ikMode, waypointMode, posing) {
|
|
34
|
+
return mode !== "keys" && Boolean(track?.[frame]) && (preview || (!ikMode && !waypointMode && !posing));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function updateShotMetrics({ position, visible, playing, setCameraPos, setSubjectVisible, cameraRef, visibleRef }) {
|
|
38
|
+
cameraRef.current = { x: position.x, y: position.y, z: position.z };
|
|
39
|
+
if (!playing) setCameraPos((prev) => Math.abs(prev.x - position.x) + Math.abs(prev.y - position.y) + Math.abs(prev.z - position.z) > 1e-4
|
|
40
|
+
? { x: position.x, y: position.y, z: position.z } : prev);
|
|
41
|
+
visibleRef.current = visible;
|
|
42
|
+
if (!playing) setSubjectVisible((prev) => (prev === visible ? prev : visible));
|
|
43
|
+
}
|
package/src/stage-labels-ko.js
CHANGED
|
@@ -119,9 +119,6 @@ export const SCENE_RENDERER_LABELS_KO = new Map([
|
|
|
119
119
|
["cylinder", ko("cylinder", "원기둥")],
|
|
120
120
|
["cone", ko("cone", "원뿔")],
|
|
121
121
|
["plane", ko("plane", "평면")],
|
|
122
|
-
["chair", ko("chair", "의자")],
|
|
123
|
-
["car", ko("car", "자동차")],
|
|
124
|
-
["aircraft", ko("aircraft", "비행기")],
|
|
125
122
|
[CUTOUT_KIND, ko("cutout", "컷아웃")],
|
|
126
123
|
[MESH_KIND, ko("Mesh", "모델")],
|
|
127
124
|
["sculpt", ko("Sculpt", "조형")],
|
|
@@ -134,9 +131,6 @@ export const SCENE_OBJECT_NAME_LABELS_KO = new Map([
|
|
|
134
131
|
["Cylinder", ko("Cylinder", "원기둥")],
|
|
135
132
|
["Cone", ko("Cone", "원뿔")],
|
|
136
133
|
["Plane", ko("Plane", "평면")],
|
|
137
|
-
["Chair", ko("Chair", "의자")],
|
|
138
|
-
["Car", ko("Car", "자동차")],
|
|
139
|
-
["Plane (aircraft)", ko("Plane (aircraft)", "비행기")],
|
|
140
134
|
["Mesh", ko("Mesh", "모델")],
|
|
141
135
|
["Model", ko("Model", "모델")],
|
|
142
136
|
]);
|
|
@@ -32,16 +32,10 @@ export const SHOT_ASPECT_PRESETS = Object.freeze({
|
|
|
32
32
|
"12:7": Object.freeze({ label: "12:7", aspect: SHOT_ASPECT_RATIOS["12:7"], width: 1536, height: 896, title: "12:7 video-inbetweener ratio" }),
|
|
33
33
|
"fal 480P": Object.freeze({ label: "fal 480P", aspect: SHOT_ASPECT_RATIOS["fal 480P"], width: 1664, height: 960, title: "Fal H3 480P canvas (832x480)" }),
|
|
34
34
|
});
|
|
35
|
-
// Pre-generated clip shipped with the build so a bridge-less session (a hosted
|
|
36
|
-
// static demo, or `npm run dev:ui`) still shows real generated motion.
|
|
37
|
-
// Root-absolute on purpose: the studio is served from "/app/" while these
|
|
38
|
-
// public files stay at the site root, so a page-relative path would resolve
|
|
39
|
-
// to "/app/models/..." and 404. Vite's base is "/" (own apex domain), so a
|
|
40
|
-
// leading slash is now the correct — and only — form that works from both
|
|
41
|
-
// the dev server and the built site.
|
|
42
35
|
// Per-character rig model: the stage entry's `model` is the FBX file stem in
|
|
43
|
-
// public/models
|
|
44
|
-
//
|
|
36
|
+
// public/models. Root-absolute on purpose: the studio is served from "/app/"
|
|
37
|
+
// while public files stay at the site root, so a page-relative path would
|
|
38
|
+
// resolve to "/app/models/..." and 404.
|
|
45
39
|
export const characterModelUrl = (model) => `/models/${model}.fbx`;
|
|
46
40
|
|
|
47
41
|
/** Shipped rig names as the operator says them, not as the files spell them. */
|
package/src/starter-scenes.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
// Starter scenes ship inside the build (public/scenes
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Starter scenes ship inside the build (public/scenes/<id>.cclayproject) and
|
|
2
|
+
// are referred to by id: `npx cozyclay --scene <id>`, `?scene=<id>` and the
|
|
3
|
+
// chooser's template cards. The build ships none today; an unknown id resolves
|
|
4
|
+
// to null, and the studio ignores it.
|
|
5
5
|
|
|
6
|
-
export const STARTER_SCENES = Object.freeze([
|
|
7
|
-
Object.freeze({
|
|
8
|
-
id: "city-block",
|
|
9
|
-
name: "City Block",
|
|
10
|
-
blurb: "The set from the cozyclay.org tutorial: an alley, parked cars, one character mid-walk.",
|
|
11
|
-
}),
|
|
12
|
-
]);
|
|
6
|
+
export const STARTER_SCENES = Object.freeze([]);
|
|
13
7
|
|
|
14
8
|
function starterSceneById(id) {
|
|
15
9
|
return STARTER_SCENES.find((scene) => scene.id === id) ?? null;
|
|
@@ -91,9 +91,9 @@ function basisAxis(spec, reference, state) {
|
|
|
91
91
|
}
|
|
92
92
|
function support(spec, state) {
|
|
93
93
|
const id = spec.onObject ?? (typeof spec.support === 'object' ? spec.support.objectId : null);
|
|
94
|
-
if (!id) return { y: state.floorY, label: 'floor' };
|
|
94
|
+
if (!id) return { y: state.floorY ?? 0, label: 'floor' }; // live app state carries no floorY; the 3.0 floor is flat at 0
|
|
95
95
|
const object = entityById(state, id);
|
|
96
|
-
if (!object.renderer || object.renderer === 'cutout' || ['sphere', 'capsule', 'cone', '
|
|
96
|
+
if (!object.renderer || object.renderer === 'cutout' || ['sphere', 'capsule', 'cone', 'empty', 'sculpt'].includes(object.renderer) || object.path || object.attach || Math.abs(object.rotX) > EPS || Math.abs(object.rotZ) > EPS || isEffectivelyHidden(object, state.objects, state.characters)) fail('TARGET_NOT_READY', 'Support must be a stationary solid upright surface.');
|
|
97
97
|
return { y: object.y + supportHeightForObject(object) * object.scaleY, label: `object:${id}`, object };
|
|
98
98
|
}
|
|
99
99
|
function facingYaw(spec, entity, state) {
|
|
@@ -8,7 +8,6 @@ import { wrongType, unknownField, missingField, arrayRefusal, duplicateItem, str
|
|
|
8
8
|
// both pull in three.js, which the agent sidecar must not load. The protocol test pins the lists to their owners.
|
|
9
9
|
const PREVIS_MODES = ["storyboard", "animation"], POSTURES = ["stand", "sit", "lie"];
|
|
10
10
|
|
|
11
|
-
export const STUDIO_PROTOCOL_VERSION = "studio-agent-v1";
|
|
12
11
|
// Sized for the compact index of up to 400 entities (~100 bytes each) beside
|
|
13
12
|
// 24 detailed rows; a small scene stays far below it.
|
|
14
13
|
export const STUDIO_CONTEXT_MAX_BYTES = 64 * 1024;
|
|
@@ -30,7 +29,6 @@ export const STUDIO_TOOLS = Object.freeze(Object.keys(STUDIO_TOOL_LABELS));
|
|
|
30
29
|
/** One patch target kind per authored commit domain: character→cast,
|
|
31
30
|
* object→objects, shot→shot, stage→stage. */
|
|
32
31
|
export const STUDIO_PATCH_KINDS = Object.freeze(["character", "object", "shot", "stage"]);
|
|
33
|
-
export const STUDIO_PATCH_DOMAINS = Object.freeze({ character: "cast", object: "objects", shot: "shot", stage: "stage" });
|
|
34
32
|
export { STUDIO_ERROR_CODES, refusalCode };
|
|
35
33
|
export const STUDIO_VARIANTS = freezeStudioData({
|
|
36
34
|
selectionKinds: ["scene", "object", "character", "rig", "camera"], modes: ["scene", "pose", "camera", "motion"], shotModes: ["keys", "follow", "rail"],
|
|
@@ -47,7 +45,6 @@ export class StudioProtocolError extends Error {
|
|
|
47
45
|
constructor(code, message, details = {}) { super(message); this.name = "StudioProtocolError"; this.code = code; this.details = details; }
|
|
48
46
|
toJSON() { return { code: this.code, message: this.message, ...(Object.keys(this.details).length ? { details: this.details } : {}) }; }
|
|
49
47
|
}
|
|
50
|
-
export const studioError = (code, message, details) => ({ ok: false, error: new StudioProtocolError(code, message, details).toJSON() });
|
|
51
48
|
export const utf8ByteLength = (text) => new TextEncoder().encode(text).byteLength;
|
|
52
49
|
export function freezeStudioData(value) {
|
|
53
50
|
if (value && typeof value === "object" && !Object.isFrozen(value)) { for (const child of Object.values(value)) freezeStudioData(child); Object.freeze(value); }
|
|
@@ -302,8 +299,7 @@ const receiptVariants = {
|
|
|
302
299
|
installed: object({ ...authoredReceipt, status: literal("installed"), jobId: id, artifactId: id, installed, verification }, {
|
|
303
300
|
// Who accepted an unverified take: the user's explicit button, or the
|
|
304
301
|
// runtime's advisory install policy. Exactly these two may admit one.
|
|
305
|
-
mutated: literal(true), explicitUnverifiedAcceptance: bool, acceptance: literal("advisory-policy"),
|
|
306
|
-
repairs: object({ autoPhysicsInvocations: integer(0, 1), fixCollisionsInvocations: integer(0, 1), remaining: integer(0, 2) }), ...batchDetails,
|
|
302
|
+
mutated: literal(true), explicitUnverifiedAcceptance: bool, acceptance: literal("advisory-policy"), ...batchDetails,
|
|
307
303
|
}),
|
|
308
304
|
undone: object({ ...authoredReceipt, status: literal("undone"), undoneReceiptId: id, restoredTargets: array(guardSchema, 100, 1) }, { mutated: literal(true), ...batchDetails }),
|
|
309
305
|
};
|
|
@@ -382,7 +378,6 @@ export function validateStudioSchema(schema, value, code = "INVALID_ARGUMENT", p
|
|
|
382
378
|
throw new Error("Unsupported internal Studio schema.");
|
|
383
379
|
}
|
|
384
380
|
export const validateStudioIdentity = value => validateStudioSchema(identity, value, "INVALID_IDENTITY");
|
|
385
|
-
export const validateFrameRange = value => freezeStudioData(validateStudioSchema(range, value, "INVALID_RANGE"));
|
|
386
381
|
|
|
387
382
|
export function mandatoryStudioTargetIds(context) {
|
|
388
383
|
return [...new Set([
|
|
@@ -544,6 +539,6 @@ export function validateReceipt(value) {
|
|
|
544
539
|
if (previous !== frameCount || r.installed.durationSeconds !== frameCount / 24 || r.verification.range.startFrame !== 0 || r.verification.range.endFrameExclusive !== frameCount || r.verification.evaluatedFrames > frameCount) fail("INVALID_RECEIPT", "Installed schedule and verification coverage disagree.");
|
|
545
540
|
if (r.verification.status === "verified" && r.verification.evaluatedFrames !== frameCount) fail("INVALID_RECEIPT", "Verified motion requires whole-clip coverage.");
|
|
546
541
|
if (r.verification.status === "unverified" && r.explicitUnverifiedAcceptance !== true && r.acceptance !== "advisory-policy") fail("INVALID_RECEIPT", "Unverified installation requires explicit user or advisory-policy acceptance.");
|
|
547
|
-
} else if (r.installed || r.verification || (r.jobId && !["started", "completed"].includes(r.status)) || r.artifactId || r.
|
|
542
|
+
} else if (r.installed || r.verification || (r.jobId && !["started", "completed"].includes(r.status)) || r.artifactId || r.explicitUnverifiedAcceptance !== undefined) fail("INVALID_RECEIPT", "Installation evidence is exclusive to installed receipts.");
|
|
548
543
|
return freezeStudioData(r);
|
|
549
544
|
}
|
|
@@ -228,7 +228,7 @@ export function createStudioAppBinding(ports) {
|
|
|
228
228
|
}
|
|
229
229
|
function runAction(request, args) {
|
|
230
230
|
const { name: _name, args: _args, ...options } = request;
|
|
231
|
-
const result = commandBus().run(args.action, args.args, { ...options, origin: "agent", turnId: request.turnId, confirmationToken: args.confirmationToken ?? request.confirmationToken });
|
|
231
|
+
const result = commandBus().run(args.action, args.args, { ...options, origin: "agent", turnId: request.turnId, taskId: request.taskId, confirmationToken: args.confirmationToken ?? request.confirmationToken });
|
|
232
232
|
const answer = receipt => receipt.nextHost ? { ...receipt, host: receipt.nextHost } : receipt;
|
|
233
233
|
return result?.then ? result.then(answer) : answer(result);
|
|
234
234
|
}
|
package/src/studio-elements.js
CHANGED
|
@@ -34,13 +34,17 @@ const entries = [
|
|
|
34
34
|
|
|
35
35
|
{ path: "character.sessionMotion", type: "array", persisted: false, undoDomain: "cast", normalizer: "createCharacterEntry", note: "dropped by createCharacterEntry" },
|
|
36
36
|
{ path: "character.ikKeys", type: "array", persisted: false, undoDomain: "cast", normalizer: "createCharacterEntry", actions: ["character.setIkKey", "character.removeIkKey", "character.clearIkKeys"], note: "dropped by createCharacterEntry; keys travel as JSON quaternions/positions" },
|
|
37
|
-
{ path: "object.renderer", type: "enum", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", enum: ["cube", "sphere", "capsule", "cylinder", "cone", "plane", "
|
|
37
|
+
{ path: "object.renderer", type: "enum", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", enum: ["cube", "sphere", "capsule", "cylinder", "cone", "plane", "empty", "light", "effect", "text"], note: "light is made from catalogue kind point-light or spot-light; effect (smoke, fire, rain, trail...) from kind effect; text (words, a sign, a logo) from kind text" },
|
|
38
38
|
{ path: "object.position", type: "vec3", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", min: { x: -240, y: 0, z: -240 }, max: { x: 240, y: 240, z: 240 }, note: "y is the object's base: y=0 rests on the floor; height/supportY rise from it" },
|
|
39
39
|
{ path: "object.rotation", type: "vec3", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", min: { x: -180, y: -180, z: -180 }, max: { x: 180, y: 180, z: 180 }, angle: true, note: "rot/rotX/rotZ degrees, wrapped at the upper bound" },
|
|
40
40
|
{ path: "object.scale", type: "vec3", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", min: { x: 0.01, y: 0.01, z: 0.01 }, max: { x: 100, y: 100, z: 100 } },
|
|
41
41
|
{ path: "object.name", type: "string", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject" },
|
|
42
42
|
{ path: "object.color", type: "color", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject" },
|
|
43
|
-
{ path: "object.opacity", type: "number", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", min: 0.05, max: 1, note: "1 is solid; lower is see-through, e.g. 0.
|
|
43
|
+
{ path: "object.opacity", type: "number", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", min: 0.05, max: 1, note: "1 is solid; lower is see-through, e.g. 0.4 for a ghost or water; for a glass object use object.material glass" },
|
|
44
|
+
// The preset names mirror material-presets.js MATERIAL_PRESETS / MATERIAL_FINISHES (test/verify-material-presets.mjs);
|
|
45
|
+
// sparse: a receipt lists them only on a record that has one.
|
|
46
|
+
{ path: "object.material", type: "enum", sparse: true, persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", enum: ["clay", "wood", "straw", "stone", "brick", "concrete", "metal", "glass", "ceramic", "plastic", "rubber", "fabric", "paper", "foliage"], note: "cube/sphere/capsule/cylinder/cone/plane only: surface preset with real texture and shine; color stays the tint and a grey (#c2c6c8) object takes the preset's own colour. clay is the default matte look; wood (planks, furniture), straw (thatch, hay, wicker), stone, brick (walls, chimneys), concrete (plaster, pavement), metal (reflects the stage), glass (clear, see-through; tint with color), ceramic (glazed), plastic, rubber (tyres), fabric (cloth, upholstery), paper, foliage (leaves, hedges)" },
|
|
47
|
+
{ path: "object.finish", type: "enum", sparse: true, persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", enum: ["matte", "satin", "gloss"], note: "with object.material: overrides the preset's shine, e.g. metal + gloss = chrome, glass + matte = frosted, wood + gloss = varnished" },
|
|
44
48
|
{ path: "object.parent", type: "id", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject" },
|
|
45
49
|
{ path: "object.attach", type: "id", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject", actions: ["object.attach", "object.detach"], note: "carried by a character's root or bone; channels convert so the prop stays put" },
|
|
46
50
|
{ path: "object.path", type: "array", persisted: true, undoDomain: "objects", normalizer: "normalizeSceneObject" },
|
package/src/styles/themes.css
CHANGED
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
--float-head: 48px;
|
|
14
14
|
--sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "IBM Plex Sans", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", system-ui, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
15
15
|
--mono: "SF Mono", ui-monospace, "JetBrains Mono", SFMono-Regular, Menlo, Consolas, monospace;
|
|
16
|
+
/* Shell popovers (project menu, dropdowns, Outliner context menu): one
|
|
17
|
+
solid surface and one layer above every panel and rail. They are
|
|
18
|
+
portaled to <body> and exclusive (src/popover.js), so the open one is
|
|
19
|
+
always on top. The top bar's menus use the same layer. */
|
|
20
|
+
--z-popover: 90;
|
|
21
|
+
--popover-surface: var(--surface-raised);
|
|
22
|
+
--popover-border: var(--row-divider);
|
|
23
|
+
--popover-radius: var(--r-2, 6px);
|
|
24
|
+
--popover-blur: none;
|
|
25
|
+
--popover-shadow: 0 8px 24px rgba(0,0,0,.45);
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
/* Dark: the v2 surfaces with a deep clay-orange accent and shaded panels. */
|
|
@@ -73,6 +83,9 @@
|
|
|
73
83
|
--surface-bar: #f4f4f6;
|
|
74
84
|
--surface-panel: #f7f7f9;
|
|
75
85
|
--surface-raised: #ffffff;
|
|
86
|
+
--popover-surface: rgba(255,255,255,.96);
|
|
87
|
+
--popover-blur: blur(24px) saturate(1.6);
|
|
88
|
+
--popover-shadow: 0 10px 30px rgba(30,32,40,.16), 0 1px 3px rgba(30,32,40,.08);
|
|
76
89
|
--surface-active: #e4e4e9;
|
|
77
90
|
--field: #ececf0;
|
|
78
91
|
--field-deep: #e6e6eb;
|