cozyclay 1.0.0 → 1.2.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/README.md +59 -24
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/bin/cozyclay.mjs +105 -11
- package/dist/CNAME +1 -0
- package/dist/app/index.html +57 -0
- package/dist/assets/app-Cgpk2hwX.js +4803 -0
- package/dist/assets/app-DgZvaAE1.css +1 -0
- package/dist/favicon.ico +0 -0
- package/dist/icons/apple-touch-icon.png +0 -0
- package/dist/icons/icon-192.png +0 -0
- package/dist/icons/icon-32.png +0 -0
- package/dist/icons/icon-512.png +0 -0
- package/dist/icons/icon-maskable-512.png +0 -0
- package/dist/index.html +406 -5
- package/dist/manifest.webmanifest +42 -0
- package/dist/media/cozyclay-demo-poster.jpg +0 -0
- package/dist/media/cozyclay-logo.png +0 -0
- package/dist/robots.txt +4 -0
- package/dist/sitemap.xml +9 -0
- package/dist/sw.js +127 -0
- package/package.json +15 -3
- package/src/App.jsx +1393 -648
- package/src/ardy/client.js +5 -4
- package/src/ardy/mp4-duration.js +102 -0
- package/src/ardy/timeline-coordinates.js +11 -0
- package/src/ardy/timeline.jsx +528 -67
- package/src/ardy/waypoints.js +14 -9
- package/src/camera-block.js +60 -0
- package/src/camera-follow.js +49 -10
- package/src/camera-rail-schedule.js +176 -0
- package/src/controls.jsx +16 -2
- package/src/cuts.js +184 -0
- package/src/generation/client.js +56 -0
- package/src/generation/session.js +47 -0
- package/src/generation/shot-spec.js +40 -0
- package/src/generation/use-generation.js +55 -0
- package/src/hierarchy-model.js +9 -17
- package/src/hierarchy-panel.jsx +170 -23
- package/src/locale-toggle.jsx +18 -0
- package/src/locale.js +34 -0
- package/src/main.jsx +5 -0
- package/src/object-catalog.jsx +32 -3
- package/src/planview.jsx +174 -66
- package/src/pose-extract/browser.js +42 -0
- package/src/pose-extract/fit.js +194 -0
- package/src/pose-extract/index.js +53 -0
- package/src/pose-extract/keyframes.js +74 -0
- package/src/pose-extract/landmarks.js +162 -0
- package/src/poses.js +114 -0
- package/src/posestudio.jsx +75 -13
- package/src/pwa.js +42 -0
- package/src/result-modal.jsx +124 -0
- package/src/scenes.js +223 -0
- package/src/shot-authoring.js +204 -77
- package/src/shot.js +8 -4
- package/src/styles.css +839 -38
- package/src/ui.jsx +54 -5
- package/tools/ardy/BRIDGE.md +70 -4
- package/tools/ardy/README.md +55 -0
- package/tools/ardy/bridge.mjs +89 -389
- package/tools/ardy/cclay_constrained_generate.py +449 -0
- package/tools/ardy/cclay_motion_edit.py +74 -9
- package/tools/ardy/cclay_sequence_generate.py +68 -7
- package/tools/ardy/cclay_worker.py +304 -0
- package/tools/ardy/merge-text-encoder.py +160 -0
- package/tools/ardy/run-local.mjs +233 -0
- package/tools/ardy/runners/index.mjs +23 -0
- package/tools/ardy/runners/local.mjs +452 -0
- package/tools/ardy/runners/proc.mjs +125 -0
- package/tools/ardy/runners/remote.mjs +246 -0
- package/tools/ardy/setup-local.mjs +189 -0
- package/tools/ardy/setup-text-encoder-on-box.sh +93 -0
- package/tools/ardy/setup-text-encoder.py +296 -0
- package/tools/generation/README.md +29 -0
- package/tools/generation/bridge.mjs +149 -0
- package/tools/generation/job-store.mjs +51 -0
- package/tools/generation/providers/kling.mjs +76 -0
- package/tools/generation/providers/runway.mjs +101 -0
- package/tools/generation/providers/seedance.mjs +87 -0
- package/tools/generation/providers/shared.mjs +49 -0
- package/tools/generation/providers/veo.mjs +84 -0
- package/tools/metrics/archive-traffic.mjs +138 -0
- package/dist/assets/index-BW_S1YRy.js +0 -4395
- package/dist/assets/index-nRmmJgap.css +0 -1
- package/tools/ardy/__pycache__/cclay_sequence_generate.cpython-313.pyc +0 -0
- package/tools/ardy/out/gen-1786443326924-c6019e-generated.npz +0 -0
- package/tools/ardy/out/gen-1786443609325-0053db-generated.npz +0 -0
- package/tools/ardy/out/gen-1786443835628-749ed1-generated.npz +0 -0
- package/tools/ardy/out/gen-1786462605247-03cb19-generated.npz +0 -0
- package/tools/qa-browser.mjs +0 -84
- package/tools/qa-crop3.mjs +0 -22
- package/tools/qa-playview.mjs +0 -49
- package/tools/qa-screenshot.mjs +0 -24
- package/tools/qa-visual.mjs +0 -51
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "/app/",
|
|
3
|
+
"name": "Cozy Clay",
|
|
4
|
+
"short_name": "Cozy Clay",
|
|
5
|
+
"description": "Browser-based 3D staging studio: block a scene, pose characters, and author camera moves.",
|
|
6
|
+
"lang": "en",
|
|
7
|
+
"start_url": "/app/",
|
|
8
|
+
"scope": "/app/",
|
|
9
|
+
"display": "standalone",
|
|
10
|
+
"display_override": [
|
|
11
|
+
"standalone",
|
|
12
|
+
"minimal-ui"
|
|
13
|
+
],
|
|
14
|
+
"orientation": "landscape-primary",
|
|
15
|
+
"background_color": "#1e1e1e",
|
|
16
|
+
"theme_color": "#232323",
|
|
17
|
+
"categories": [
|
|
18
|
+
"graphics-design",
|
|
19
|
+
"photo",
|
|
20
|
+
"video"
|
|
21
|
+
],
|
|
22
|
+
"icons": [
|
|
23
|
+
{
|
|
24
|
+
"src": "./icons/icon-192.png",
|
|
25
|
+
"sizes": "192x192",
|
|
26
|
+
"type": "image/png",
|
|
27
|
+
"purpose": "any"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"src": "./icons/icon-512.png",
|
|
31
|
+
"sizes": "512x512",
|
|
32
|
+
"type": "image/png",
|
|
33
|
+
"purpose": "any"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"src": "./icons/icon-maskable-512.png",
|
|
37
|
+
"sizes": "512x512",
|
|
38
|
+
"type": "image/png",
|
|
39
|
+
"purpose": "maskable"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
Binary file
|
|
Binary file
|
package/dist/robots.txt
ADDED
package/dist/sitemap.xml
ADDED
package/dist/sw.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const CACHE_PREFIX = "cozyclay-pwa-";
|
|
2
|
+
// Bump on any change to what CORE_ASSETS resolves to. The icons are cached
|
|
3
|
+
// here, so a client on an older cache keeps serving the previous favicon from
|
|
4
|
+
// disk no matter what the server sends.
|
|
5
|
+
// v3: app shell moved from "/" to "/app/".
|
|
6
|
+
// v4: icons redrawn from the CozyClay mark.
|
|
7
|
+
// v5: tab icons cut to a circle so they stop reading as a sticker.
|
|
8
|
+
const CACHE_NAME = `${CACHE_PREFIX}v5`;
|
|
9
|
+
// The installable app is the studio, not the landing page.
|
|
10
|
+
const APP_SHELL = "/app/";
|
|
11
|
+
const CORE_ASSETS = [
|
|
12
|
+
APP_SHELL,
|
|
13
|
+
"/app/index.html",
|
|
14
|
+
"./manifest.webmanifest",
|
|
15
|
+
"./icons/icon-32.png",
|
|
16
|
+
"./icons/icon-192.png",
|
|
17
|
+
"./icons/icon-512.png",
|
|
18
|
+
"./icons/icon-maskable-512.png",
|
|
19
|
+
"./icons/apple-touch-icon.png",
|
|
20
|
+
"./favicon.ico",
|
|
21
|
+
"./fonts/inter-latin.woff2",
|
|
22
|
+
"./demo/walk-then-stop.npz",
|
|
23
|
+
"./models/x-bot-tpose.fbx",
|
|
24
|
+
"./models/y-bot-tpose.fbx",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
async function cacheResponse(cache, request, response) {
|
|
28
|
+
if (!response.ok || response.type === "opaque") {
|
|
29
|
+
throw new Error(`Required offline asset failed: ${request}`);
|
|
30
|
+
}
|
|
31
|
+
await cache.put(request, response.clone());
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function cacheBuiltAssets(cache) {
|
|
36
|
+
const response = await fetch(APP_SHELL, { cache: "reload" });
|
|
37
|
+
if (!response.ok) throw new Error("Required offline app shell failed");
|
|
38
|
+
await cache.put(APP_SHELL, response.clone());
|
|
39
|
+
const html = await response.text();
|
|
40
|
+
const assetUrls = [...html.matchAll(/(?:src|href)="([^"]+)"/g)]
|
|
41
|
+
.map((match) => new URL(match[1], self.location.href))
|
|
42
|
+
.filter((url) => url.origin === self.location.origin)
|
|
43
|
+
.map((url) => url.href);
|
|
44
|
+
await Promise.all(assetUrls.map(async (url) => {
|
|
45
|
+
const asset = await fetch(url, { cache: "reload" });
|
|
46
|
+
await cacheResponse(cache, url, asset);
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
self.addEventListener("install", (event) => {
|
|
51
|
+
event.waitUntil((async () => {
|
|
52
|
+
const cache = await caches.open(CACHE_NAME);
|
|
53
|
+
await Promise.all(CORE_ASSETS.map(async (url) => {
|
|
54
|
+
const response = await fetch(url, { cache: "reload" });
|
|
55
|
+
await cacheResponse(cache, url, response);
|
|
56
|
+
}));
|
|
57
|
+
await cacheBuiltAssets(cache);
|
|
58
|
+
})());
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
self.addEventListener("activate", (event) => {
|
|
62
|
+
event.waitUntil((async () => {
|
|
63
|
+
const names = await caches.keys();
|
|
64
|
+
await Promise.all(names
|
|
65
|
+
.filter((name) => name.startsWith(CACHE_PREFIX) && name !== CACHE_NAME)
|
|
66
|
+
.map((name) => caches.delete(name)));
|
|
67
|
+
await self.clients.claim();
|
|
68
|
+
})());
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
self.addEventListener("message", (event) => {
|
|
72
|
+
if (event.data?.type === "SKIP_WAITING") self.skipWaiting();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
self.addEventListener("fetch", (event) => {
|
|
76
|
+
const { request } = event;
|
|
77
|
+
if (request.method !== "GET") return;
|
|
78
|
+
const url = new URL(request.url);
|
|
79
|
+
if (url.origin !== self.location.origin || url.pathname.includes("/ardy/")) return;
|
|
80
|
+
if (request.headers.has("range")) {
|
|
81
|
+
event.respondWith((async () => {
|
|
82
|
+
try {
|
|
83
|
+
return await fetch(request);
|
|
84
|
+
} catch {
|
|
85
|
+
const cached = await caches.match(url.href);
|
|
86
|
+
if (!cached) return new Response(null, { status: 504 });
|
|
87
|
+
const bytes = await cached.arrayBuffer();
|
|
88
|
+
const range = request.headers.get("range")?.match(/bytes=(\d+)-(\d*)/);
|
|
89
|
+
if (!range) return cached;
|
|
90
|
+
const start = Number(range[1]);
|
|
91
|
+
const end = range[2] ? Number(range[2]) : bytes.byteLength - 1;
|
|
92
|
+
const chunk = bytes.slice(start, end + 1);
|
|
93
|
+
return new Response(chunk, {
|
|
94
|
+
status: 206,
|
|
95
|
+
headers: {
|
|
96
|
+
"accept-ranges": "bytes",
|
|
97
|
+
"content-length": String(chunk.byteLength),
|
|
98
|
+
"content-range": `bytes ${start}-${end}/${bytes.byteLength}`,
|
|
99
|
+
"content-type": cached.headers.get("content-type") || "application/octet-stream",
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
})());
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (request.mode === "navigate") {
|
|
108
|
+
event.respondWith((async () => {
|
|
109
|
+
const cache = await caches.open(CACHE_NAME);
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(request);
|
|
112
|
+
return cacheResponse(cache, request, response);
|
|
113
|
+
} catch {
|
|
114
|
+
return (await cache.match(request)) || (await cache.match(APP_SHELL)) || (await cache.match("/app/index.html"));
|
|
115
|
+
}
|
|
116
|
+
})());
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
event.respondWith((async () => {
|
|
121
|
+
const cached = await caches.match(request);
|
|
122
|
+
if (cached) return cached;
|
|
123
|
+
const cache = await caches.open(CACHE_NAME);
|
|
124
|
+
const response = await fetch(request);
|
|
125
|
+
return cacheResponse(cache, request, response);
|
|
126
|
+
})());
|
|
127
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozyclay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Browser-based 3D staging studio: block a scene, pose characters, author camera moves and cuts, and preview generated motion.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "node tools/dev-full.mjs --host 127.0.0.1 --port 5180",
|
|
@@ -10,22 +10,31 @@
|
|
|
10
10
|
"test:hierarchy": "node test/verify-hierarchy.mjs",
|
|
11
11
|
"test:history": "node test/verify-history.mjs",
|
|
12
12
|
"test:scene-objects": "node test/verify-scene-objects.mjs",
|
|
13
|
+
"test:scenes": "node test/verify-scenes.mjs",
|
|
13
14
|
"test:camera-move": "node test/verify-camera-move.mjs",
|
|
15
|
+
"test:cuts": "node test/verify-cuts.mjs",
|
|
14
16
|
"test:objects": "node tools/qa-browser.mjs -- node test/verify-object-gizmo.mjs",
|
|
15
17
|
"test:theme": "node test/verify-theme.mjs",
|
|
16
18
|
"test:appearance": "node test/verify-appearance.mjs",
|
|
17
19
|
"test:layout": "node test/verify-layout.mjs",
|
|
18
20
|
"test:timeline-camera": "node test/verify-timeline-camera.mjs",
|
|
21
|
+
"test:timeline-shots": "node test/verify-timeline-shots.mjs",
|
|
19
22
|
"preview": "vite preview",
|
|
20
23
|
"ardy:rest": "node tools/ardy/extract-rest.mjs",
|
|
21
24
|
"ardy:pose": "node tools/ardy/pose-to-npz.mjs",
|
|
22
25
|
"test:ardy": "for t in fk rest pose-shape fill npz compare-npz playback-skinning sequence-bridge; do node test/ardy/verify-$t.mjs || exit 1; done && node test/ardy/verify-browser-motion.mjs && node test/ik/verify-ik.mjs",
|
|
23
26
|
"bridge": "node tools/ardy/bridge.mjs",
|
|
27
|
+
"ardy:setup": "node tools/ardy/setup-local.mjs",
|
|
24
28
|
"dev:full": "node tools/dev-full.mjs --host 127.0.0.1 --port 5180",
|
|
25
29
|
"qa:browser": "node tools/qa-browser.mjs --",
|
|
26
30
|
"test:shot-authoring": "node test/verify-shot-authoring.mjs",
|
|
27
31
|
"test:camera-follow": "node test/verify-camera-follow.mjs",
|
|
28
|
-
"
|
|
32
|
+
"test:pose-extract": "node test/verify-pose-extract.mjs",
|
|
33
|
+
"test:pwa": "node test/verify-pwa.mjs",
|
|
34
|
+
"test:localization": "node test/verify-korean-ui.mjs",
|
|
35
|
+
"test:korean-ui": "node test/verify-korean-ui.mjs",
|
|
36
|
+
"prepack": "npm run build",
|
|
37
|
+
"metrics:traffic": "node tools/metrics/archive-traffic.mjs"
|
|
29
38
|
},
|
|
30
39
|
"license": "GPL-3.0-or-later",
|
|
31
40
|
"type": "module",
|
|
@@ -45,8 +54,11 @@
|
|
|
45
54
|
"files": [
|
|
46
55
|
"bin",
|
|
47
56
|
"dist",
|
|
57
|
+
"!dist/media/*.mp4",
|
|
48
58
|
"src",
|
|
49
59
|
"tools",
|
|
60
|
+
"!tools/ardy/out",
|
|
61
|
+
"!tools/qa-*.mjs",
|
|
50
62
|
"README.md",
|
|
51
63
|
"LICENSE",
|
|
52
64
|
"THIRD_PARTY_NOTICES.md"
|
|
@@ -70,7 +82,7 @@
|
|
|
70
82
|
"type": "git",
|
|
71
83
|
"url": "git+https://github.com/HaD0Yun/CozyClay.git"
|
|
72
84
|
},
|
|
73
|
-
"homepage": "https://
|
|
85
|
+
"homepage": "https://cozyclay.org/",
|
|
74
86
|
"bugs": {
|
|
75
87
|
"url": "https://github.com/HaD0Yun/CozyClay/issues"
|
|
76
88
|
},
|