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
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Snapshot GitHub traffic
|
|
3
|
+
* Snapshot GitHub traffic, stars, referrers, repo stats and npm downloads
|
|
4
|
+
* into JSONL ledgers on the `metrics` branch.
|
|
4
5
|
*
|
|
5
|
-
* GitHub's traffic API only keeps 14 days, so this
|
|
6
|
+
* GitHub's traffic API only keeps 14 days, so this runs daily
|
|
6
7
|
* (.github/workflows/metrics.yml) to build a permanent time series. Rows are
|
|
7
8
|
* deduped by date so overlapping 14-day windows never double-count.
|
|
8
9
|
*
|
|
10
|
+
* Files written to <output-dir>:
|
|
11
|
+
* traffic-daily.jsonl one row per UTC day: views, view_uniques, clones, clone_uniques
|
|
12
|
+
* stars-daily.jsonl one row per UTC day: new_stars, total (rebuilt from starred_at)
|
|
13
|
+
* referrers.jsonl one row per run date: 14-day top referrers and paths
|
|
14
|
+
* repo-stats.jsonl one row per run date: stars, forks, watchers, issues, npm weekly
|
|
15
|
+
*
|
|
9
16
|
* Usage: GITHUB_TOKEN=... node tools/metrics-snapshot.mjs <output-dir>
|
|
10
17
|
*/
|
|
11
18
|
import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
@@ -26,9 +33,9 @@ if (!token) {
|
|
|
26
33
|
process.exit(2);
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
async function github(path) {
|
|
36
|
+
async function github(path, accept = "application/vnd.github+json") {
|
|
30
37
|
const res = await fetch(`https://api.github.com/repos/${REPO}${path}`, {
|
|
31
|
-
headers: { authorization: `Bearer ${token}`, accept
|
|
38
|
+
headers: { authorization: `Bearer ${token}`, accept },
|
|
32
39
|
});
|
|
33
40
|
if (!res.ok) throw new Error(`GET ${path} -> ${res.status}`);
|
|
34
41
|
return res.json();
|
|
@@ -95,4 +102,35 @@ stats.set(today, {
|
|
|
95
102
|
});
|
|
96
103
|
const statsTotal = saveRows(statsFile, stats);
|
|
97
104
|
|
|
98
|
-
|
|
105
|
+
// 3) Stars per UTC day, rebuilt from every stargazer's starred_at. Someone who
|
|
106
|
+
// later unstars drops out of the history, so totals can trail repo.stargazers_count
|
|
107
|
+
// by a few. Rebuilt in full each run, so it never drifts.
|
|
108
|
+
const starDays = new Map();
|
|
109
|
+
for (let page = 1; page <= 400; page++) {
|
|
110
|
+
const batch = await github(`/stargazers?per_page=100&page=${page}`, "application/vnd.github.star+json");
|
|
111
|
+
if (!Array.isArray(batch) || batch.length === 0) break;
|
|
112
|
+
for (const s of batch) {
|
|
113
|
+
const day = String(s.starred_at).slice(0, 10);
|
|
114
|
+
starDays.set(day, (starDays.get(day) ?? 0) + 1);
|
|
115
|
+
}
|
|
116
|
+
if (batch.length < 100) break;
|
|
117
|
+
}
|
|
118
|
+
const starRows = new Map();
|
|
119
|
+
let running = 0;
|
|
120
|
+
for (const day of [...starDays.keys()].sort()) {
|
|
121
|
+
running += starDays.get(day);
|
|
122
|
+
starRows.set(day, { date: day, new_stars: starDays.get(day), total: running });
|
|
123
|
+
}
|
|
124
|
+
const starsTotal = saveRows(join(outDir, "stars-daily.jsonl"), starRows);
|
|
125
|
+
|
|
126
|
+
// 4) 14-day referrers and paths, one snapshot per run date.
|
|
127
|
+
const [referrers, paths] = await Promise.all([github("/traffic/popular/referrers"), github("/traffic/popular/paths")]);
|
|
128
|
+
const refFile = join(outDir, "referrers.jsonl");
|
|
129
|
+
const refs = loadRows(refFile);
|
|
130
|
+
refs.set(today, { date: today, referrers, paths });
|
|
131
|
+
const refTotal = saveRows(refFile, refs);
|
|
132
|
+
|
|
133
|
+
console.log(
|
|
134
|
+
`traffic-daily: +${added} new day(s), ${trafficTotal} total; repo-stats: ${statsTotal} snapshot(s); ` +
|
|
135
|
+
`stars-daily: ${starsTotal} day(s), ${running} stars; referrers: ${refTotal} snapshot(s)`,
|
|
136
|
+
);
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Render the start-screen template thumbnails from the real studio.
|
|
4
|
+
*
|
|
5
|
+
* npm run dev -- --port 5180 # any running dev server
|
|
6
|
+
* node tools/render-start-thumbs.mjs [--url http://127.0.0.1:5180/app/] [--out public/thumbs]
|
|
7
|
+
*
|
|
8
|
+
* For each template (Blank Stage plus every entry in STARTER_SCENES) and each
|
|
9
|
+
* theme, this opens the studio in a fresh headless Chrome profile, creates the
|
|
10
|
+
* project the way a user does (Blank Stage: the chooser's Create button; a
|
|
11
|
+
* starter: `?scene=<id>`), renders one offscreen frame through the studio's own
|
|
12
|
+
* capture path (`window.__cozyclay.captureFraming`), and writes
|
|
13
|
+
* `<out>/<template-id>-<theme>.webp` at 680x383 (2x the 340px preview).
|
|
14
|
+
* The chooser picks the file by id and theme and falls back to a plain tile
|
|
15
|
+
* when it is missing, so a new starter only needs this script re-run. A
|
|
16
|
+
* starter with no entry in FRAMINGS is shot through its own shot camera.
|
|
17
|
+
*
|
|
18
|
+
* Options: --url, --out, --cdp-port (default 9472), --only <template-id>.
|
|
19
|
+
* CHROME_PATH picks the browser; THUMBS_CHROME_FLAGS replaces the GPU flags
|
|
20
|
+
* (default: Metal on macOS, SwiftShader elsewhere).
|
|
21
|
+
*/
|
|
22
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { tmpdir } from "node:os";
|
|
24
|
+
import { join, resolve } from "node:path";
|
|
25
|
+
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { spawnOwned, terminateOwned } from "./process-supervisor.mjs";
|
|
27
|
+
import { STARTER_SCENES } from "../src/starter-scenes.js";
|
|
28
|
+
import { THEMES, THEME_KEY } from "../src/theme.js";
|
|
29
|
+
|
|
30
|
+
const ROOT = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
31
|
+
const WIDTH = 680;
|
|
32
|
+
const HEIGHT = 383;
|
|
33
|
+
const MAX_BYTES = 60 * 1024;
|
|
34
|
+
|
|
35
|
+
function arg(name, fallback) {
|
|
36
|
+
const argv = process.argv.slice(2);
|
|
37
|
+
const index = argv.indexOf(name);
|
|
38
|
+
return index >= 0 ? argv[index + 1] : fallback;
|
|
39
|
+
}
|
|
40
|
+
const appUrl = new URL(arg("--url", "http://127.0.0.1:5180/app/"));
|
|
41
|
+
const outDir = resolve(ROOT, arg("--out", "public/thumbs"));
|
|
42
|
+
const cdpPort = Number(arg("--cdp-port", 9472));
|
|
43
|
+
const only = arg("--only", null);
|
|
44
|
+
const chromePath = process.env.CHROME_PATH || "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
45
|
+
const gpuFlags = (process.env.THUMBS_CHROME_FLAGS
|
|
46
|
+
?? (process.platform === "darwin" ? "--use-angle=metal --ignore-gpu-blocklist" : "--use-angle=swiftshader --enable-unsafe-swiftshader"))
|
|
47
|
+
.split(/\s+/).filter(Boolean);
|
|
48
|
+
|
|
49
|
+
/** A studio framing ({ pos, yaw, pitch, fovDeg }) from an eye point and a target. */
|
|
50
|
+
function lookAt(eye, target, fovDeg) {
|
|
51
|
+
const [dx, dy, dz] = target.map((value, index) => value - eye[index]);
|
|
52
|
+
return { pos: { x: eye[0], y: eye[1], z: eye[2] }, yaw: Math.atan2(-dx, -dz), pitch: Math.atan2(dy, Math.hypot(dx, dz)), fovDeg };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Eye-level 3/4 view. Blank Stage: the default character on the floor grid.
|
|
56
|
+
const FRAMINGS = {
|
|
57
|
+
"blank-stage": lookAt([1.6, 1.55, 3.7], [0, 0.88, 0], 40),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const templates = [
|
|
61
|
+
{ id: "blank-stage", url: appUrl.href, create: true },
|
|
62
|
+
...STARTER_SCENES.map((scene) => ({ id: scene.id, url: `${appUrl.href}?scene=${encodeURIComponent(scene.id)}`, create: false })),
|
|
63
|
+
].filter((template) => !only || template.id === only);
|
|
64
|
+
|
|
65
|
+
const sleep = (ms) => new Promise((done) => setTimeout(done, ms));
|
|
66
|
+
|
|
67
|
+
async function connect() {
|
|
68
|
+
const deadline = Date.now() + 30000;
|
|
69
|
+
while (Date.now() < deadline) {
|
|
70
|
+
try {
|
|
71
|
+
const targets = await (await fetch(`http://127.0.0.1:${cdpPort}/json`)).json();
|
|
72
|
+
const page = targets.find((target) => target.type === "page" && target.webSocketDebuggerUrl);
|
|
73
|
+
if (page) {
|
|
74
|
+
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
75
|
+
await new Promise((done, fail) => { ws.onopen = done; ws.onerror = fail; });
|
|
76
|
+
return ws;
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// Chrome is still starting.
|
|
80
|
+
}
|
|
81
|
+
await sleep(150);
|
|
82
|
+
}
|
|
83
|
+
throw new Error("headless Chrome did not expose a page target");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function client(ws) {
|
|
87
|
+
let nextId = 1;
|
|
88
|
+
const pending = new Map();
|
|
89
|
+
ws.onmessage = (event) => {
|
|
90
|
+
const message = JSON.parse(event.data);
|
|
91
|
+
const entry = pending.get(message.id);
|
|
92
|
+
if (!entry) return;
|
|
93
|
+
pending.delete(message.id);
|
|
94
|
+
if (message.error) entry.reject(new Error(JSON.stringify(message.error)));
|
|
95
|
+
else entry.resolve(message.result);
|
|
96
|
+
};
|
|
97
|
+
const send = (method, params = {}) => new Promise((resolveSend, reject) => {
|
|
98
|
+
const id = nextId++;
|
|
99
|
+
pending.set(id, { resolve: resolveSend, reject });
|
|
100
|
+
ws.send(JSON.stringify({ id, method, params }));
|
|
101
|
+
});
|
|
102
|
+
const evaluate = async (expression) => {
|
|
103
|
+
const result = await send("Runtime.evaluate", { expression, awaitPromise: true, returnByValue: true });
|
|
104
|
+
if (result.exceptionDetails) throw new Error(result.exceptionDetails.exception?.description || "evaluate failed");
|
|
105
|
+
return result.result.value;
|
|
106
|
+
};
|
|
107
|
+
const waitFor = async (label, expression, timeoutMs = 30000) => {
|
|
108
|
+
const deadline = Date.now() + timeoutMs;
|
|
109
|
+
while (Date.now() < deadline) {
|
|
110
|
+
if (await evaluate(`(() => { try { return Boolean(${expression}); } catch { return false; } })()`)) return;
|
|
111
|
+
await sleep(200);
|
|
112
|
+
}
|
|
113
|
+
throw new Error(`timed out waiting for ${label}`);
|
|
114
|
+
};
|
|
115
|
+
return { send, evaluate, waitFor };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Runs in the page: render the framing at 2x, downscale, and encode WebP under the size cap.
|
|
119
|
+
const encodeInPage = (framing) => `(async () => {
|
|
120
|
+
const studio = window.__cozyclay;
|
|
121
|
+
const framing = ${JSON.stringify(framing)};
|
|
122
|
+
const output = { width: ${WIDTH * 2}, height: ${HEIGHT * 2} };
|
|
123
|
+
const png = framing ? studio.captureFraming(framing, output) : studio.capturePlate();
|
|
124
|
+
if (!png) throw new Error("studio capture returned nothing");
|
|
125
|
+
const image = new Image();
|
|
126
|
+
image.src = png;
|
|
127
|
+
await image.decode();
|
|
128
|
+
const canvas = document.createElement("canvas");
|
|
129
|
+
canvas.width = ${WIDTH};
|
|
130
|
+
canvas.height = ${HEIGHT};
|
|
131
|
+
const ctx = canvas.getContext("2d");
|
|
132
|
+
ctx.imageSmoothingQuality = "high";
|
|
133
|
+
const scale = Math.max(canvas.width / image.width, canvas.height / image.height);
|
|
134
|
+
const w = image.width * scale, h = image.height * scale;
|
|
135
|
+
ctx.drawImage(image, (canvas.width - w) / 2, (canvas.height - h) / 2, w, h);
|
|
136
|
+
for (let quality = 0.92; quality > 0.4; quality -= 0.06) {
|
|
137
|
+
const url = canvas.toDataURL("image/webp", quality);
|
|
138
|
+
if (url.length * 0.75 <= ${MAX_BYTES} || quality <= 0.46) return url;
|
|
139
|
+
}
|
|
140
|
+
})()`;
|
|
141
|
+
|
|
142
|
+
async function renderOne(template, theme) {
|
|
143
|
+
const profile = mkdtempSync(join(tmpdir(), "cozyclay-thumbs-"));
|
|
144
|
+
const chrome = spawnOwned(chromePath, [
|
|
145
|
+
"--headless=new", `--remote-debugging-port=${cdpPort}`, `--user-data-dir=${profile}`,
|
|
146
|
+
"--window-size=1440,900", "--no-first-run", "--no-default-browser-check", ...gpuFlags, "about:blank",
|
|
147
|
+
], { stdio: "ignore" });
|
|
148
|
+
try {
|
|
149
|
+
const cdp = client(await connect());
|
|
150
|
+
await cdp.send("Page.enable");
|
|
151
|
+
await cdp.send("Page.addScriptToEvaluateOnNewDocument", { source: `try { localStorage.setItem(${JSON.stringify(THEME_KEY)}, ${JSON.stringify(theme)}); } catch {}` });
|
|
152
|
+
await cdp.send("Page.navigate", { url: template.url });
|
|
153
|
+
if (template.create) {
|
|
154
|
+
await cdp.waitFor("the start screen", `document.querySelector('[data-template-id="${template.id}"]')`);
|
|
155
|
+
await cdp.evaluate(`document.querySelector('[data-template-id="${template.id}"]').click()`);
|
|
156
|
+
await sleep(200);
|
|
157
|
+
await cdp.evaluate("document.querySelector('.v2-start-project-form').requestSubmit()");
|
|
158
|
+
}
|
|
159
|
+
await cdp.waitFor("the studio", "window.__cozyclay?.charA && !document.querySelector('.v2-start-screen')");
|
|
160
|
+
await sleep(3000); // character model, textures and shadows settle
|
|
161
|
+
const dataUrl = await cdp.evaluate(encodeInPage(FRAMINGS[template.id] ?? null));
|
|
162
|
+
const bytes = Buffer.from(dataUrl.split(",")[1], "base64");
|
|
163
|
+
const file = join(outDir, `${template.id}-${theme}.webp`);
|
|
164
|
+
writeFileSync(file, bytes);
|
|
165
|
+
console.log(`${file.slice(ROOT.length + 1)} ${(bytes.length / 1024).toFixed(1)} KB`);
|
|
166
|
+
} finally {
|
|
167
|
+
await terminateOwned(chrome);
|
|
168
|
+
rmSync(profile, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
mkdirSync(outDir, { recursive: true });
|
|
173
|
+
for (const template of templates) {
|
|
174
|
+
for (const theme of THEMES) await renderOne(template, theme);
|
|
175
|
+
}
|
package/tools/run-tests.mjs
CHANGED
|
@@ -14,7 +14,7 @@ if (!process.env.COZYCLAY_AGENT_SESSIONS_DIR) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const NODE_FILES = [
|
|
17
|
-
"test/motion3/verify-motion3-core.mjs", "test/motion3/verify-motion3-idle.mjs", "test/motion3/verify-motion3-flip.mjs", "test/motion3/verify-motion3-timing.mjs", "test/motion3/verify-motion3-self.mjs", "test/motion3/verify-motion3-commands.mjs", "test/motion3/verify-motion3-exitcar.mjs", "test/motion3/verify-motion3-agentloop.mjs", "test/motion3/verify-motion3-search.mjs", "test/motion3/verify-motion3-skills.mjs", "test/motion3/verify-motion3-carried.mjs", "test/motion3/verify-motion3-people.mjs", "test/motion3/verify-motion3-hit.mjs", "test/motion3/verify-motion3-socket.mjs", "test/motion3/verify-motion3-reach-human.mjs", "test/motion3/verify-motion3-stance-grasp.mjs", "test/motion3/verify-motion3-grasp-friction.mjs", "test/motion3/verify-motion3-grasp-measure.mjs", "test/motion3/verify-motion3-contracts.mjs", "test/motion3/verify-motion3-describe.mjs", "test/motion3/verify-motion3-timeline.mjs", "test/motion3/verify-motion3-probes.mjs", "test/motion3/verify-motion3-grab.mjs", "test/motion3/verify-motion3-grab-blend.mjs", "test/motion3/verify-motion3-patch.mjs", "test/motion3/verify-motion3-repair.mjs", "test/motion3/verify-motion3-specstore.mjs", "test/motion3/verify-motion3-visual.mjs", "test/motion3/verify-motion3-goals.mjs", "test/motion3/verify-motion3-prompt.mjs", "test/motion3/verify-motion3-cup.mjs", "test/verify-proxy-figure.mjs", "test/verify-text-object.mjs",
|
|
17
|
+
"test/motion3/verify-motion3-core.mjs", "test/motion3/verify-playback-frame-store.mjs", "test/verify-playback-render-isolation.mjs", "test/motion3/verify-motion3-idle.mjs", "test/motion3/verify-motion3-flip.mjs", "test/motion3/verify-motion3-timing.mjs", "test/motion3/verify-motion3-self.mjs", "test/motion3/verify-motion3-commands.mjs", "test/motion3/verify-motion3-exitcar.mjs", "test/motion3/verify-motion3-agentloop.mjs", "test/motion3/verify-motion3-search.mjs", "test/motion3/verify-motion3-skills.mjs", "test/motion3/verify-motion3-carried.mjs", "test/motion3/verify-motion3-people.mjs", "test/motion3/verify-motion3-hit.mjs", "test/motion3/verify-motion3-socket.mjs", "test/motion3/verify-motion3-shapes.mjs", "test/motion3/verify-motion3-grasp-fields.mjs", "test/motion3/verify-motion3-finger-contact.mjs", "test/motion3/verify-motion3-grasp-qa.mjs", "test/motion3/verify-motion3-load.mjs", "test/motion3/verify-motion3-throw.mjs", "test/motion3/verify-motion3-catch.mjs", "test/motion3/verify-motion3-grasp-hints.mjs", "test/motion3/verify-motion3-reach-human.mjs", "test/motion3/verify-motion3-stance-grasp.mjs", "test/motion3/verify-motion3-grasp-friction.mjs", "test/motion3/verify-motion3-grasp-measure.mjs", "test/motion3/verify-motion3-contracts.mjs", "test/motion3/verify-motion3-describe.mjs", "test/motion3/verify-motion3-timeline.mjs", "test/motion3/verify-motion3-probes.mjs", "test/motion3/verify-motion3-grab.mjs", "test/motion3/verify-motion3-grab-blend.mjs", "test/motion3/verify-motion3-patch.mjs", "test/motion3/verify-motion3-repair.mjs", "test/motion3/verify-motion3-specstore.mjs", "test/motion3/verify-motion3-visual.mjs", "test/motion3/verify-motion3-goals.mjs", "test/motion3/verify-motion3-prompt.mjs", "test/motion3/verify-motion3-cup.mjs", "test/verify-proxy-figure.mjs", "test/verify-text-object.mjs",
|
|
18
18
|
"test/verify-proxy-figure-bounds.mjs",
|
|
19
19
|
"test/verify-character-capabilities.mjs",
|
|
20
20
|
"test/verify-root-path.mjs",
|
|
@@ -22,13 +22,12 @@ const NODE_FILES = [
|
|
|
22
22
|
"test/bus/verify-view-mode-pose.mjs",
|
|
23
23
|
"test/verify-studio-actions.mjs",
|
|
24
24
|
"test/ardy/verify-collision-blockers.mjs",
|
|
25
|
-
"test/verify-facing-marks.mjs",
|
|
26
25
|
"test/verify-pose-fade.mjs",
|
|
27
26
|
"test/verify-pose-gizmo.mjs",
|
|
28
27
|
"test/ardy/verify-key-runs.mjs",
|
|
29
28
|
"test/ardy/verify-playback-clock.mjs",
|
|
30
29
|
"test/ardy/verify-timeline-coordinates.mjs",
|
|
31
|
-
"test/verify-tokens.mjs",
|
|
30
|
+
"test/verify-tokens.mjs", "test/verify-lens-scrub.mjs",
|
|
32
31
|
"test/demo/verify-api-routes.mjs",
|
|
33
32
|
"test/ik/verify-collision-capsules.mjs",
|
|
34
33
|
"test/ik/verify-ground.mjs",
|
|
@@ -44,13 +43,13 @@ const NODE_FILES = [
|
|
|
44
43
|
"test/ik/verify-range-pin-ui.mjs",
|
|
45
44
|
"test/ik/verify-range-pin-object-transform.mjs",
|
|
46
45
|
"test/verify-ik-camera-performance.mjs",
|
|
47
|
-
"test/verify-ik-entry-camera.mjs",
|
|
46
|
+
"test/verify-ik-entry-camera.mjs", "test/verify-viewport-visible-rect.mjs",
|
|
48
47
|
"test/process/verify-lifecycle.mjs",
|
|
49
48
|
"test/process/verify-mcp-package-isolation.mjs",
|
|
50
49
|
"test/process/verify-package-telemetry.mjs",
|
|
51
50
|
"test/process/verify-agent-deps.mjs",
|
|
52
51
|
"test/verify-agent-image-references.mjs",
|
|
53
|
-
"test/verify-agent-panel.mjs", "test/verify-agent-turn-view.mjs", "test/verify-agent-reply-text.mjs",
|
|
52
|
+
"test/verify-agent-panel.mjs", "test/verify-agent-turn-view.mjs", "test/verify-agent-plan.mjs", "test/verify-agent-reply-text.mjs", "test/verify-agent-sculpt-sketch.mjs",
|
|
54
53
|
"test/verify-agent-host.mjs",
|
|
55
54
|
"test/verify-agent-routes.mjs",
|
|
56
55
|
"test/verify-studio-owner-restart.mjs",
|
|
@@ -65,7 +64,7 @@ const NODE_FILES = [
|
|
|
65
64
|
"test/verify-schema-to-typebox.mjs",
|
|
66
65
|
"test/verify-agent-sse-golden.mjs",
|
|
67
66
|
"test/verify-agent-context-budget.mjs", "test/verify-agent-context-trim.mjs",
|
|
68
|
-
"test/verify-agent-supervisor.mjs",
|
|
67
|
+
"test/verify-agent-supervisor.mjs", "test/verify-studio-tasks.mjs", "test/verify-task-board.mjs",
|
|
69
68
|
"test/verify-studio-agent-protocol.mjs",
|
|
70
69
|
"test/verify-studio-agent-sampled-framing.mjs",
|
|
71
70
|
"test/verify-studio-agent-tokens.mjs",
|
|
@@ -82,30 +81,27 @@ const NODE_FILES = [
|
|
|
82
81
|
"test/verify-auto-color.mjs",
|
|
83
82
|
"test/verify-coplanar-depth.mjs",
|
|
84
83
|
"test/verify-empty-object.mjs",
|
|
85
|
-
"test/verify-sculpt-recipe.mjs",
|
|
84
|
+
"test/verify-sculpt-recipe.mjs", "test/verify-sculpt-shapes.mjs", "test/verify-sculpt-loft-convex.mjs", "test/verify-sculpt-detail.mjs",
|
|
86
85
|
"test/verify-sculpt-object.mjs",
|
|
87
86
|
"test/verify-sculpt-compare.mjs",
|
|
88
87
|
"test/verify-sculpt-run.mjs",
|
|
89
88
|
"test/verify-sculpt-compare-command.mjs",
|
|
90
89
|
"test/verify-sculpt-panel.mjs",
|
|
91
90
|
"test/verify-sculpt-blueprint.mjs",
|
|
92
|
-
"test/verify-sculpt-mode.mjs",
|
|
91
|
+
"test/verify-sculpt-mode.mjs", "test/verify-sculpt-csg.mjs", "test/verify-material-presets.mjs",
|
|
93
92
|
"test/verify-route-owner.mjs",
|
|
94
93
|
"test/verify-part-colours.mjs",
|
|
95
94
|
"test/verify-asset-shelf.mjs",
|
|
96
95
|
"test/verify-blocking-depth.mjs",
|
|
97
96
|
"test/verify-render-passes-video.mjs",
|
|
98
|
-
"test/verify-burn-in.mjs",
|
|
99
97
|
"test/verify-camera-block.mjs", "test/verify-camera-direction.mjs",
|
|
100
98
|
"test/verify-camera-follow.mjs",
|
|
101
99
|
"test/verify-camera-move.mjs",
|
|
102
100
|
"test/verify-camera-rail-schedule.mjs",
|
|
103
101
|
"test/verify-camera-pointer-lock.mjs",
|
|
104
|
-
"test/verify-camera-tutorial.mjs",
|
|
105
|
-
"test/verify-first-shot-handoff.mjs",
|
|
106
102
|
"test/verify-codex-client.mjs",
|
|
107
103
|
"test/verify-cuts.mjs",
|
|
108
|
-
"test/verify-shot-guides.mjs",
|
|
104
|
+
"test/verify-shot-guides.mjs", "test/verify-shot-frame.mjs",
|
|
109
105
|
"test/verify-error-boundary.mjs",
|
|
110
106
|
"test/verify-g006-css.mjs",
|
|
111
107
|
"test/verify-gizmo-claim.mjs",
|
|
@@ -238,9 +234,6 @@ const BROWSER_FILES = [
|
|
|
238
234
|
"test/verify-static-shot-export-browser.mjs",
|
|
239
235
|
"test/qa-agent-view-toggle-browser.mjs",
|
|
240
236
|
"test/qa-agent-scenarios-browser.mjs",
|
|
241
|
-
"test/qa-camera-tutorial-browser.mjs",
|
|
242
|
-
"test/qa-first-shot-handoff-browser.mjs",
|
|
243
|
-
"test/qa-tutorial-analytics-browser.mjs",
|
|
244
237
|
"test/qa-camera-pointer-lock-browser.mjs",
|
|
245
238
|
"test/qa-first-edit-browser.mjs",
|
|
246
239
|
"test/qa-ia-tail-browser.mjs",
|
|
@@ -262,7 +255,7 @@ const BROWSER_FILES = [
|
|
|
262
255
|
// The inventory sweep only picks up `verify*.mjs`; a browser suite named for
|
|
263
256
|
// the QA runner it needs is listed here so it still shows up in the manifest
|
|
264
257
|
// (as an EXCLUDE with its reason) instead of going unmentioned.
|
|
265
|
-
const EXTRA_INVENTORY = ["test/ik/translation-step.mjs", "test/qa-scenes-v5-migration-browser.mjs", "test/qa-agent-scenarios-browser.mjs", "test/qa-execution-outcomes-browser.mjs", "test/qa-export-recovery-browser.mjs", "test/qa-agent-view-toggle-browser.mjs", "test/qa-camera-
|
|
258
|
+
const EXTRA_INVENTORY = ["test/ik/translation-step.mjs", "test/qa-scenes-v5-migration-browser.mjs", "test/qa-agent-scenarios-browser.mjs", "test/qa-execution-outcomes-browser.mjs", "test/qa-export-recovery-browser.mjs", "test/qa-agent-view-toggle-browser.mjs", "test/qa-camera-pointer-lock-browser.mjs", "test/qa-first-edit-browser.mjs", "test/qa-ia-tail-browser.mjs", "test/qa-keyframe-pack-browser.mjs", "test/qa-preview-browser.mjs", "test/qa-reference-slots-browser.mjs", "test/qa-scene-playback-browser.mjs", "test/qa-scene-switcher-browser.mjs", "test/qa-send-to-ai-browser.mjs", "test/qa-view-menu-browser.mjs", "test/qa-live-reconnect-browser.mjs", "test/qa-clipboard-paste-browser.mjs", "test/qa-rail-lean-browser.mjs", "test/qa-rail-reach-browser.mjs", "test/qa-rail-ring-browser.mjs", "test/qa-speed-graph-browser.mjs"];
|
|
266
259
|
|
|
267
260
|
EXTRA_INVENTORY.push("test/qa-proxy-figure-browser.mjs");
|
|
268
261
|
EXTRA_INVENTORY.push("test/qa-proxy-entry-browser.mjs");
|
|
@@ -275,7 +268,7 @@ function verificationFiles(directory) {
|
|
|
275
268
|
.flatMap((entry) => {
|
|
276
269
|
const path = join(directory, entry.name);
|
|
277
270
|
if (entry.isDirectory()) return entry.name === "node_modules" ? [] : verificationFiles(path);
|
|
278
|
-
return entry.isFile() && /^verify(-.*)?\.mjs$/.test(entry.name) ? [relative(".", path)] : [];
|
|
271
|
+
return entry.isFile() && /^verify(-.*)?\.mjs$/.test(entry.name) ? [relative(".", path).replaceAll("\\", "/")] : [];
|
|
279
272
|
})
|
|
280
273
|
.sort();
|
|
281
274
|
}
|
package/tools/sitemap.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { resolve } from "node:path";
|
|
|
8
8
|
|
|
9
9
|
const ORIGIN = "https://cozyclay.org";
|
|
10
10
|
const PAGES = [
|
|
11
|
-
{ path: "/", sources: ["index.html", "public/media"
|
|
11
|
+
{ path: "/", sources: ["index.html", "public/media"] },
|
|
12
12
|
{ path: "/greybox-to-video/", sources: ["greybox-to-video/index.html"] },
|
|
13
13
|
{ path: "/previs-software/", sources: ["previs-software/index.html"] },
|
|
14
14
|
{ path: "/seedance-camera-control/", sources: ["seedance-camera-control/index.html"] },
|