cozyclay 2.0.2 → 2.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 +61 -0
- package/README.md +17 -2
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/bin/agent/agent-routes.mjs +211 -36
- package/bin/agent/agent-runner.mjs +98 -4
- package/bin/agent/codex-client.mjs +2 -1
- package/bin/agent/fal-contract.mjs +0 -17
- package/bin/agent/h3-preservation.mjs +6 -8
- package/bin/agent/provider-keys.mjs +1 -1
- package/bin/agent/providers.mjs +124 -3
- package/bin/agent/script-tool.mjs +74 -0
- package/bin/agent/session-store.mjs +5 -5
- package/bin/agent/studio-prompt.mjs +2 -1
- package/bin/agent/studio-rebase.mjs +314 -0
- package/bin/agent/studio-tools.mjs +21 -14
- package/bin/agent/supervisor.mjs +311 -0
- package/bin/agent/video-adapters.mjs +0 -7
- package/bin/codex-auth.mjs +4 -4
- package/bin/live/cli.mjs +23 -8
- package/bin/live/client.mjs +1 -1
- package/bin/live/studio.mjs +5 -2
- package/bin/mcp-runtime.mjs +2 -2
- package/bin/telemetry-state.mjs +3 -3
- package/dist/app/index.html +6 -6
- package/dist/assets/analytics-C9pMpW7s.js +1 -0
- package/dist/assets/app-B_2XB9rw.css +1 -0
- package/dist/assets/app-DAuvKPP8.js +4920 -0
- package/dist/assets/{demo-ByeYp-dY.js → demo-CvKuBgy5.js} +1 -1
- package/dist/assets/{first-shot-handoff-DgT28ZiV.js → first-shot-handoff-msLI71g1.js} +1 -1
- package/dist/assets/{landing-BaXkpFip.js → landing-ChUvB_zL.js} +1 -1
- package/dist/assets/scene-asset-sync-DKkpjKBV.js +19 -0
- package/dist/assets/{shot-prompt-CbqWcWYi.css → scene-asset-sync-DjJ_cJ2R.css} +1 -1
- package/dist/assets/{ticket-BcmsnHn5.js → ticket-BPk2Ni95.js} +1 -1
- package/dist/assets/workflow-jJRBR94Z.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +328 -222
- package/dist/llms.txt +14 -0
- package/dist/sitemap.xml +1 -1
- package/dist/workflow/index.html +4 -4
- package/mcp/LIVE-PROTOCOL.md +23 -2
- package/mcp/README.md +37 -2
- package/mcp/ardy-prompts.mjs +1 -1
- package/mcp/image-file.mjs +132 -0
- package/mcp/live-hub.mjs +2 -2
- package/mcp/package.json +1 -0
- package/mcp/runtime/package-lock.json +7 -0
- package/mcp/runtime/package.json +1 -0
- package/mcp/server.mjs +0 -6
- package/mcp/tool-handlers.mjs +289 -87
- package/package.json +11 -2
- package/src/App.jsx +813 -278
- package/src/agent-image-client.js +94 -0
- package/src/analytics.js +47 -3
- package/src/app-stage.jsx +129 -2745
- package/src/ardy/auto-physics.js +6 -16
- package/src/ardy/collision-blockers.js +3 -7
- package/src/ardy/fix-collisions.js +5 -35
- package/src/ardy/ik-drag.js +86 -5
- package/src/ardy/ik-key-json.js +3 -1
- package/src/ardy/ik.js +15 -13
- package/src/ardy/motion-calibration.js +1 -1
- package/src/ardy/npz.js +0 -8
- package/src/ardy/physics-panel.jsx +3 -2
- package/src/ardy/physics-review.js +3 -2
- package/src/ardy/physics-support.js +1 -1
- package/src/ardy/physics-surface.js +1 -1
- package/src/ardy/platform-fit-panel.jsx +2 -1
- package/src/ardy/playback.js +1 -5
- package/src/ardy/range-pin.js +2 -2
- package/src/ardy/root-drop.js +0 -1
- package/src/ardy/timeline.css +184 -6
- package/src/ardy/timeline.jsx +121 -36
- package/src/ardy/to-cskel27.js +0 -2
- package/src/ardy/waypoints.js +0 -3
- package/src/ardy-bridge-contract.js +281 -0
- package/src/asset-pane.jsx +19 -9
- package/src/auto-color.js +1 -1
- package/src/burn-in.js +1 -1
- package/src/camera-block.js +1 -1
- package/src/camera-follow.js +75 -32
- package/src/camera-move.js +0 -6
- package/src/camera-tutorial.jsx +6 -7
- package/src/character-kind.js +79 -0
- package/src/command-bus.js +76 -17
- package/src/commands/cast.js +31 -7
- package/src/commands/elements/object.js +1 -1
- package/src/commands/elements/shot.js +1 -1
- package/src/commands/elements.js +1 -1
- package/src/commands/export.js +3 -3
- package/src/commands/motion.js +2 -2
- package/src/commands/objects.js +105 -10
- package/src/commands/project.js +15 -2
- package/src/commands/sculpt-images.js +53 -0
- package/src/commands/shot.js +88 -10
- package/src/commands/view.js +10 -4
- package/src/coplanar-depth.js +216 -0
- package/src/cuts.js +7 -6
- package/src/domains/cast.js +60 -43
- package/src/domains/motion/motion-intent-codec.js +50 -0
- package/src/domains/motion/motion-range-pin-rules.js +23 -0
- package/src/domains/motion/motion-video-capture.js +664 -0
- package/src/domains/motion.js +253 -742
- package/src/domains/objects.js +106 -5
- package/src/domains/scenes.js +79 -28
- package/src/domains/shots.js +33 -7
- package/src/error-boundary.jsx +1 -1
- package/src/execution-telemetry.js +5 -5
- package/src/facing-marks.js +14 -1
- package/src/first-success-guide.jsx +35 -4
- package/src/gizmo-claim.js +3 -1
- package/src/grid-floor.jsx +1 -4
- package/src/hierarchy-model.js +48 -35
- package/src/hierarchy-panel.css +1 -0
- package/src/hierarchy-panel.jsx +54 -102
- package/src/history.js +0 -2
- package/src/i2v-motion-client.js +1 -4
- package/src/ime.js +6 -0
- package/src/keyframe-pack.js +15 -6
- package/src/line-edit.js +4 -4
- package/src/live-control.js +6 -6
- package/src/matte-editor.js +2 -8
- package/src/matte.js +0 -19
- package/src/mesh-graph-clone.js +16 -2
- package/src/mesh-sniff.js +0 -1
- package/src/monotone-cubic.js +40 -0
- package/src/motion-store.js +4 -4
- package/src/motion-trail.js +5 -11
- package/src/multimodel-ingest.js +1 -3
- package/src/object-catalog.jsx +7 -5
- package/src/object-gizmo.jsx +45 -31
- package/src/object-path.js +310 -67
- package/src/object-travel.js +224 -0
- package/src/otio.js +8 -3
- package/src/panels/CharacterTransformPanel.jsx +24 -6
- package/src/panels/ObjectTransformPanel.jsx +4 -3
- package/src/panels/PoseImagePanel.jsx +205 -0
- package/src/panels/PromptBlocksPanel.jsx +3 -1
- package/src/panels/ProxyFigurePanel.jsx +56 -0
- package/src/panels/ReferenceImageField.jsx +1 -1
- package/src/panels/RigControlPanel.jsx +24 -3
- package/src/panels/RigPanel.jsx +2 -1
- package/src/panels/SculptPanel.jsx +405 -0
- package/src/panels/SubjectBox.jsx +1 -1
- package/src/panels/SubjectsPanel.jsx +0 -2
- package/src/panels/VideoCapturePanel.jsx +2 -1
- package/src/panels/pose-image.css +42 -0
- package/src/panels/pose.css +3 -0
- package/src/panels/sculpt.css +162 -0
- package/src/plan-diagram.js +184 -0
- package/src/planview.jsx +127 -80
- package/src/playground.js +3 -5
- package/src/pose-fade.js +77 -0
- package/src/pose-gizmo.css +23 -0
- package/src/pose-gizmo.js +96 -0
- package/src/posestudio.jsx +134 -83
- package/src/project-browser.css +53 -0
- package/src/project-browser.jsx +49 -4
- package/src/project.js +55 -24
- package/src/props.jsx +177 -36
- package/src/proxy-figure.jsx +69 -0
- package/src/range-pin-panel.jsx +0 -1
- package/src/receipt-findings.js +20 -0
- package/src/render-passes.js +0 -1
- package/src/resource-status.jsx +1 -1
- package/src/root-path.js +48 -0
- package/src/route-owner.js +52 -0
- package/src/scene-asset-cache.js +1 -2
- package/src/scene-assets.js +12 -4
- package/src/scene-fbx.js +1 -1
- package/src/scene-mesh-cache.js +0 -1
- package/src/scene-objects.js +319 -19
- package/src/scenes.js +58 -9
- package/src/sculpt-blueprint.js +65 -0
- package/src/sculpt-compare.js +384 -0
- package/src/sculpt-geometry.js +141 -0
- package/src/sculpt-mode.js +168 -0
- package/src/sculpt-recipe.js +385 -0
- package/src/sculpt-run.js +351 -0
- package/src/sculpt-stage.jsx +221 -0
- package/src/settings-menu.jsx +1 -1
- package/src/shell/BoardSlot.jsx +341 -0
- package/src/shell/BottomDock.jsx +60 -16
- package/src/shell/CompositionGuideButton.jsx +20 -0
- package/src/shell/DetailsSlot.jsx +26 -6
- package/src/shell/MenuBar.jsx +78 -6
- package/src/shell/OutlinerSlot.jsx +3 -1
- package/src/shell/ShotPreviewHeader.jsx +17 -0
- package/src/shell/TopBar.jsx +18 -3
- package/src/shell/ViewportToolbar.jsx +36 -31
- package/src/shell/dock.css +239 -0
- package/src/shell/glass-regions.css +3 -2
- package/src/shell/log-store.js +4 -4
- package/src/shell/mode.css +20 -0
- package/src/shell/studio-shell-context.js +4 -1
- package/src/shell/viewport.css +12 -0
- package/src/shot-authoring.js +69 -6
- package/src/stable-items.js +1 -1
- package/src/stage-attach-frames.js +169 -0
- package/src/stage-canvas-rigs.jsx +402 -0
- package/src/stage-capture.jsx +216 -0
- package/src/stage-characters.jsx +302 -0
- package/src/stage-editor-gizmos.jsx +1229 -0
- package/src/stage-labels-ko.js +204 -0
- package/src/stage-startup-defaults.js +182 -0
- package/src/starter-scenes.js +1 -1
- package/src/storyboard.js +24 -5
- package/src/studio-actions.js +42 -9
- package/src/studio-agent-commands.js +213 -23
- package/src/studio-agent-context.js +11 -9
- package/src/studio-agent-motion.js +2 -1
- package/src/studio-agent-protocol.js +60 -24
- package/src/studio-app-binding.js +56 -23
- package/src/studio-contact-sheet.js +3 -3
- package/src/studio-elements.js +11 -2
- package/src/studio-geometry-facts.js +114 -0
- package/src/styles.css +92 -9
- package/src/ui-scrub.js +4 -4
- package/src/ui.jsx +6 -4
- package/src/use-asset-shelf.js +60 -0
- package/src/use-camera-tutorial.js +50 -0
- package/src/use-embed-bridge.js +12 -0
- package/src/use-first-success-prompt.js +7 -0
- package/src/use-i2v-capture-modal.js +15 -0
- package/src/use-sculpt-mode.js +95 -0
- package/src/workflow/AgentPanel.jsx +106 -18
- package/src/workflow/WorkflowBuilder.jsx +1 -1
- package/src/workflow/agent-client.js +113 -45
- package/src/workflow/agent-panel.css +35 -0
- package/src/workflow/attachment-image.js +1 -1
- package/src/workflow/canvas-commands.js +3 -3
- package/src/workflow/cozy-scene-node.js +3 -3
- package/src/workflow/local-workflow.js +2 -2
- package/src/workflow/motion-input.js +3 -3
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/scene-asset-sync.js +2 -9
- package/src/workflow/shot-prompt-node.js +1 -1
- package/src/workflow/video-contract.js +1 -1
- package/src/workflow/workflow-resources.js +0 -8
- package/src/workflow-send.js +87 -0
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/check-eslint.mjs +57 -0
- package/tools/check-knip.mjs +60 -0
- package/tools/check-loc.mjs +54 -0
- package/tools/demo-worker/api-client.mjs +7 -13
- package/tools/demo-worker/generate.mjs +2 -4
- package/tools/eslint-baseline.json +23 -0
- package/tools/gt-render/browser.mjs +23 -0
- package/tools/headless-studio.mjs +85 -0
- package/tools/kimodo/effector-constraints.mjs +4 -4
- package/tools/kimodo/generate.mjs +1 -1
- package/tools/knip-baseline.json +331 -0
- package/tools/loc-baseline.json +126 -0
- package/tools/process-supervisor.mjs +1 -1
- package/tools/projflow/replay.mjs +4 -4
- package/tools/projflow/runner.mjs +3 -3
- package/tools/qa/studio-control-count.mjs +2 -0
- package/tools/run-tests.mjs +95 -7
- package/dist/assets/analytics-MVZOEW8O.js +0 -1
- package/dist/assets/app-BxBLC6GT.js +0 -4876
- package/dist/assets/app-CJdxvnrl.css +0 -1
- package/dist/assets/shot-prompt-hN0j_O-p.js +0 -17
- package/dist/assets/workflow-B5XZwVfe.js +0 -179
package/dist/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
6
|
<meta name="description" content="Free, open source previs software that runs in the browser. Block a scene, pose characters, and author camera moves and cuts, then hand the same shots to an AI video model. No Blender, no Unity — one command." />
|
|
7
|
-
<meta name="theme-color" content="#
|
|
7
|
+
<meta name="theme-color" content="#f5f5f7" />
|
|
8
8
|
<meta name="apple-mobile-web-app-title" content="CozyClay" />
|
|
9
9
|
<link rel="canonical" href="https://cozyclay.org/" />
|
|
10
10
|
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png" />
|
|
@@ -59,13 +59,18 @@
|
|
|
59
59
|
|
|
60
60
|
<style>
|
|
61
61
|
:root {
|
|
62
|
-
--bg: #
|
|
63
|
-
--
|
|
64
|
-
--
|
|
65
|
-
--
|
|
66
|
-
--
|
|
67
|
-
--
|
|
68
|
-
--
|
|
62
|
+
--bg: #f5f5f7;
|
|
63
|
+
--alt: #ececf0;
|
|
64
|
+
--panel: #ffffff;
|
|
65
|
+
--line: #d2d2d7;
|
|
66
|
+
--line-strong: #c7c7cc;
|
|
67
|
+
--ink: #1d1d1f;
|
|
68
|
+
--muted: #636366;
|
|
69
|
+
--accent: #0066cc;
|
|
70
|
+
--ok: #2f6b3a;
|
|
71
|
+
--shadow-card: 0 1px 2px rgba(0, 0, 0, .04), 0 8px 24px rgba(0, 0, 0, .06);
|
|
72
|
+
--shadow-window: 0 2px 6px rgba(0, 0, 0, .06), 0 30px 60px rgba(0, 0, 0, .18);
|
|
73
|
+
--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
69
74
|
}
|
|
70
75
|
* { box-sizing: border-box; }
|
|
71
76
|
html { scroll-behavior: smooth; }
|
|
@@ -73,237 +78,271 @@
|
|
|
73
78
|
margin: 0;
|
|
74
79
|
background: var(--bg);
|
|
75
80
|
color: var(--ink);
|
|
76
|
-
font:
|
|
81
|
+
font: 17px/1.5 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;
|
|
77
82
|
-webkit-font-smoothing: antialiased;
|
|
78
83
|
}
|
|
79
84
|
a { color: var(--accent); }
|
|
80
|
-
|
|
85
|
+
button { font-family: inherit; }
|
|
86
|
+
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
|
|
87
|
+
.wrap { max-width: 1160px; margin: 0 auto; padding: 0 24px; }
|
|
88
|
+
.wrap.narrow { max-width: 820px; }
|
|
89
|
+
|
|
90
|
+
/* Type scale: 64 / 36 / 19 / 17 / 14. Nothing else. */
|
|
91
|
+
h1 { font-size: clamp(40px, 6vw, 64px); line-height: 1.05; letter-spacing: -.02em; font-weight: 700; margin: 0; max-width: 820px; }
|
|
92
|
+
h1 em { font-style: normal; color: var(--accent); }
|
|
93
|
+
h2 { font-size: clamp(28px, 3.4vw, 36px); line-height: 1.15; letter-spacing: -.01em; font-weight: 700; margin: 0 0 32px; }
|
|
94
|
+
h3 { font-size: 19px; font-weight: 600; margin: 0; }
|
|
95
|
+
.small, figcaption { font-size: 14px; color: var(--muted); }
|
|
96
|
+
code, pre, kbd { font-family: var(--mono); font-size: 14px; }
|
|
97
|
+
|
|
81
98
|
header.site {
|
|
99
|
+
position: sticky; top: 0; z-index: 10;
|
|
100
|
+
background: rgba(245, 245, 247, .8);
|
|
101
|
+
backdrop-filter: saturate(180%) blur(20px); -webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
82
102
|
border-bottom: 1px solid var(--line);
|
|
83
|
-
position: sticky; top: 0; background: rgba(27,27,27,.9);
|
|
84
|
-
backdrop-filter: blur(8px); z-index: 10;
|
|
85
|
-
}
|
|
86
|
-
header.site .wrap {
|
|
87
|
-
display: flex; align-items: center; gap: 16px;
|
|
88
|
-
min-height: 60px; flex-wrap: wrap;
|
|
89
103
|
}
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
header.site .wrap { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; padding-top: 10px; padding-bottom: 10px; }
|
|
105
|
+
.brand { display: flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 600; color: var(--ink); text-decoration: none; }
|
|
106
|
+
.brand img { width: 32px; height: auto; border-radius: 8px; background: #fff; padding: 3px 2px; }
|
|
107
|
+
header.site nav { display: flex; align-items: center; gap: 4px 24px; flex-wrap: wrap; font-size: 14px; }
|
|
108
|
+
header.site nav a { display: flex; align-items: center; min-height: 44px; color: var(--muted); text-decoration: none; }
|
|
93
109
|
header.site nav a:hover { color: var(--ink); }
|
|
110
|
+
header.site nav a.btn, header.site nav a.btn:hover { color: #fff; font-size: 14px; min-height: 44px; padding: 0 16px; }
|
|
94
111
|
|
|
95
|
-
.hero { padding: 48px 0 40px; }
|
|
96
|
-
h1 { font-size: clamp(30px, 5.2vw, 46px); line-height: 1.12; margin: 0 0 18px; letter-spacing: -.02em; color: var(--clay); }
|
|
97
|
-
.lede { font-size: clamp(17px, 2.2vw, 20px); color: var(--muted); margin: 0 0 28px; max-width: 44em; }
|
|
98
|
-
.cta { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
|
|
99
112
|
.btn {
|
|
100
|
-
display: inline-
|
|
101
|
-
|
|
113
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
114
|
+
min-height: 48px; padding: 0 24px; border-radius: 8px; border: 1px solid transparent;
|
|
115
|
+
font-size: 17px; font-weight: 600; text-decoration: none; cursor: pointer;
|
|
116
|
+
transition: filter .15s, transform .15s;
|
|
102
117
|
}
|
|
103
|
-
.btn
|
|
104
|
-
.btn
|
|
105
|
-
.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
width: 72px; height: auto; flex: none; border: 0;
|
|
116
|
-
border-radius: 12px; background: var(--clay); padding: 6px 5px;
|
|
117
|
-
}
|
|
118
|
-
.hero-head h1 { margin: 0; }
|
|
119
|
-
|
|
120
|
-
.reels {
|
|
121
|
-
display: grid;
|
|
122
|
-
grid-template-columns: 1.778fr 1.167fr;
|
|
123
|
-
gap: 16px;
|
|
124
|
-
align-items: start;
|
|
125
|
-
margin: 0 0 30px;
|
|
118
|
+
.btn:hover { filter: brightness(1.08); }
|
|
119
|
+
.btn:active { transform: scale(.98); }
|
|
120
|
+
.btn.primary { background: var(--accent); color: #fff; }
|
|
121
|
+
.btn.ghost { background: var(--panel); color: var(--ink); border-color: var(--line-strong); }
|
|
122
|
+
.cta { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
|
|
123
|
+
|
|
124
|
+
.hero { padding: 80px 0 48px; }
|
|
125
|
+
.hero .wrap { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 24px; }
|
|
126
|
+
.lede { margin: 0; color: var(--muted); }
|
|
127
|
+
.cmd {
|
|
128
|
+
display: inline-flex; align-items: center; gap: 4px; padding: 0 4px 0 14px;
|
|
129
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
|
|
126
130
|
}
|
|
127
|
-
.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
.cmd .copy { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; background: none; border: 0; color: var(--muted); cursor: pointer; }
|
|
132
|
+
.cmd .copy .ic-done { display: none; color: var(--ok); }
|
|
133
|
+
.cmd .copy[data-state="copied"] .ic-copy { display: none; }
|
|
134
|
+
.cmd .copy[data-state="copied"] .ic-done { display: block; }
|
|
135
|
+
|
|
136
|
+
.window { border: 1px solid var(--line-strong); border-radius: 12px; overflow: hidden; background: var(--panel); box-shadow: var(--shadow-window); }
|
|
137
|
+
.titlebar { display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 14px; background: #e8e8ed; border-bottom: 1px solid var(--line); }
|
|
138
|
+
.titlebar i { width: 12px; height: 12px; border-radius: 50%; background: #ff5f57; }
|
|
139
|
+
.titlebar i:nth-child(2) { background: #febc2e; }
|
|
140
|
+
.titlebar i:nth-child(3) { background: #28c840; }
|
|
141
|
+
.titlebar span { flex: 1; text-align: center; margin-right: 52px; font-size: 14px; font-weight: 600; color: var(--muted); }
|
|
142
|
+
|
|
143
|
+
.proof { padding: 0 0 96px; }
|
|
144
|
+
.proof figure { margin: 0; }
|
|
145
|
+
.proof video { display: block; width: 100%; height: auto; background: #000; }
|
|
146
|
+
.proof figcaption { margin-top: 16px; text-align: center; }
|
|
147
|
+
|
|
148
|
+
section { padding: 88px 0; border-top: 1px solid var(--line); }
|
|
149
|
+
section.alt { background: var(--alt); }
|
|
150
|
+
section.hero, section.proof { border-top: 0; }
|
|
151
|
+
|
|
152
|
+
.cards { display: flex; flex-wrap: wrap; gap: 20px; }
|
|
153
|
+
.card {
|
|
154
|
+
flex: 1 1 240px; min-width: 0; padding: 24px;
|
|
155
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow-card);
|
|
134
156
|
}
|
|
135
|
-
.
|
|
136
|
-
.
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
157
|
+
.card p { margin: 4px 0 0; color: var(--muted); }
|
|
158
|
+
.card .n { display: block; margin-bottom: 16px; font-size: clamp(28px, 3.4vw, 36px); font-weight: 700; line-height: 1; color: var(--accent); }
|
|
159
|
+
a.card { color: var(--ink); text-decoration: none; font-size: 19px; font-weight: 600; min-height: 96px; transition: transform .2s; }
|
|
160
|
+
a.card:hover { transform: translateY(-2px); }
|
|
161
|
+
|
|
162
|
+
/* Playground. The ids and data-state values belong to the tutorial script below. */
|
|
163
|
+
/* The steps sit in the window's title bar so the studio gets the full
|
|
164
|
+
content width and height; started, the demo scrolls up to fill the screen. */
|
|
165
|
+
.demo { scroll-margin-top: 76px; }
|
|
166
|
+
.demo .window { min-width: 0; box-shadow: 0 2px 6px rgba(0, 0, 0, .06), 0 24px 48px rgba(0, 0, 0, .14); }
|
|
167
|
+
.tutorial-steps { flex: 1; min-width: 0; display: flex; justify-content: center; gap: 4px; margin: 0 52px 0 0; padding: 0; list-style: none; overflow: hidden; }
|
|
168
|
+
.tutorial-steps[hidden] { display: none; }
|
|
169
|
+
.tutorial-steps li {
|
|
170
|
+
display: flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 10px; border-radius: 999px; white-space: nowrap;
|
|
171
|
+
background: var(--panel); border: 1px solid var(--line); color: var(--ink); font-size: 14px;
|
|
172
|
+
opacity: .55; transition: opacity .2s, background .15s;
|
|
140
173
|
}
|
|
141
|
-
.
|
|
174
|
+
.playground-live .tutorial-steps li { opacity: 1; }
|
|
175
|
+
.tutorial-steps li[data-done="1"] { color: var(--ok); border-color: var(--ok); }
|
|
176
|
+
.tutorial-steps li[data-done="1"]::after { content: "✓"; font-weight: 700; }
|
|
177
|
+
.tutorial-steps li[data-current="1"] { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
|
|
142
178
|
|
|
143
179
|
.playground {
|
|
144
180
|
position: relative;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
border-radius: 12px;
|
|
181
|
+
/* Header 64 + margin 12 + title bar 40 + bottom bar 52 + 12. */
|
|
182
|
+
height: clamp(480px, calc(100vh - 180px), 900px);
|
|
148
183
|
overflow: hidden;
|
|
149
|
-
background: #
|
|
150
|
-
box-shadow: 0 24px 60px rgba(0, 0, 0, .45);
|
|
184
|
+
background: #1b1b1b center / cover no-repeat;
|
|
151
185
|
}
|
|
152
186
|
.playground iframe { display: block; width: 100%; height: 100%; border: 0; background: #1b1b1b; }
|
|
153
187
|
.playground-cover {
|
|
154
188
|
position: absolute; inset: 0; display: flex; flex-direction: column;
|
|
155
189
|
align-items: center; justify-content: center; gap: 12px;
|
|
156
|
-
background: rgba(
|
|
190
|
+
background: rgba(245, 245, 247, .55); cursor: pointer; border: 0; color: var(--ink);
|
|
157
191
|
font: inherit; padding: 0; width: 100%;
|
|
158
192
|
}
|
|
159
|
-
.playground-cover:hover { background: rgba(
|
|
193
|
+
.playground-cover:hover { background: rgba(245, 245, 247, .4); }
|
|
160
194
|
.playground-cover[hidden] { display: none; }
|
|
195
|
+
.playground-cover .btn { pointer-events: none; }
|
|
196
|
+
.playground-cover small { font-size: 14px; font-weight: 600; color: var(--ink); }
|
|
161
197
|
.playground[data-state="loading"] iframe { opacity: 0; }
|
|
162
198
|
.playground-loading {
|
|
163
199
|
position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
|
|
164
|
-
color:
|
|
200
|
+
color: #fff; font-size: 14px; background: rgba(0, 0, 0, .45); pointer-events: none;
|
|
165
201
|
}
|
|
166
202
|
.playground[data-state="loading"] .playground-loading { display: flex; }
|
|
167
|
-
.playground-
|
|
168
|
-
.playground-cover small { color: var(--ink); font-size: 13px; opacity: .85; }
|
|
203
|
+
.playground-phone { display: none; }
|
|
169
204
|
.playground-bar {
|
|
170
|
-
display: none; gap:
|
|
171
|
-
|
|
205
|
+
display: none; gap: 8px 12px; align-items: center; flex-wrap: wrap;
|
|
206
|
+
padding: 10px 14px; border-top: 1px solid var(--line); background: #e8e8ed;
|
|
207
|
+
font-size: 14px; color: var(--muted);
|
|
172
208
|
}
|
|
173
|
-
.playground-bar a { color: var(--muted); }
|
|
174
209
|
.playground[data-state="live"] + .playground-bar,
|
|
175
210
|
.playground[data-state="loading"] + .playground-bar { display: flex; }
|
|
176
|
-
.playground-bar
|
|
177
|
-
|
|
178
|
-
|
|
211
|
+
.playground-bar a { color: var(--muted); }
|
|
212
|
+
.playground-bar button, button.copy {
|
|
213
|
+
min-height: 32px; padding: 0 12px; border-radius: 6px; cursor: pointer;
|
|
214
|
+
background: var(--panel); border: 1px solid var(--line-strong); color: var(--ink); font-size: 14px;
|
|
179
215
|
}
|
|
180
216
|
.playground-bar .spacer { flex: 1; }
|
|
181
|
-
.
|
|
217
|
+
button.copy[data-state="copied"] { border-color: var(--ok); color: var(--ok); }
|
|
182
218
|
|
|
183
|
-
.tutorial-steps { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; padding: 0; list-style: none; }
|
|
184
|
-
.tutorial-steps li {
|
|
185
|
-
font-size: 13px; color: var(--muted); border: 1px solid var(--line); border-radius: 999px;
|
|
186
|
-
padding: 4px 11px; background: var(--panel); opacity: .55; transition: opacity .2s;
|
|
187
|
-
}
|
|
188
|
-
.playground-live .tutorial-steps li { opacity: 1; }
|
|
189
|
-
.tutorial-steps li[data-done="1"] { color: var(--ink); border-color: #4f7a4a; background: #24301f; }
|
|
190
|
-
.tutorial-steps li[data-done="1"]::before { content: "✓ "; color: #8fd47f; }
|
|
191
|
-
.tutorial-steps li[data-current="1"] { color: var(--clay); border-color: var(--accent); }
|
|
192
219
|
.tutorial-card {
|
|
193
220
|
position: absolute; left: 14px; top: 14px; z-index: 2; max-width: 46%;
|
|
194
221
|
display: flex; gap: 10px; align-items: baseline;
|
|
195
222
|
padding: 10px 14px; border-radius: 10px; pointer-events: none;
|
|
196
|
-
background: rgba(
|
|
197
|
-
font-size:
|
|
223
|
+
background: rgba(255, 255, 255, .92); border: 1px solid var(--line); color: var(--ink);
|
|
224
|
+
font-size: 17px; line-height: 1.45; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
225
|
+
box-shadow: var(--shadow-card);
|
|
198
226
|
}
|
|
199
227
|
.tutorial-card[hidden] { display: none; }
|
|
200
|
-
.tutorial-card-step { color: var(--accent); font-size:
|
|
201
|
-
.tutorial-card kbd[data-done="1"] { border-color: #4f7a4a; color: #8fd47f; background: #24301f; }
|
|
228
|
+
.tutorial-card-step { color: var(--accent); font-size: 14px; font-weight: 600; white-space: nowrap; }
|
|
202
229
|
.tutorial-card b { color: var(--accent); font-weight: 600; }
|
|
203
230
|
.tutorial-card kbd, .tutorial-done kbd {
|
|
204
|
-
|
|
205
|
-
border: 1px solid var(--line); background: var(--
|
|
231
|
+
padding: 2px 6px; border-radius: 5px;
|
|
232
|
+
border: 1px solid var(--line-strong); background: var(--bg); color: var(--ink);
|
|
206
233
|
}
|
|
207
|
-
.tutorial-done {
|
|
208
|
-
.tutorial-done
|
|
209
|
-
.related { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
|
|
210
|
-
.related a { display: block; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px; text-decoration: none; color: var(--clay); font-weight: 600; }
|
|
211
|
-
.related a small { display: block; color: var(--muted); margin-top: 4px; font-weight: 400; }
|
|
212
|
-
.related a:hover { border-color: var(--muted); }
|
|
234
|
+
.tutorial-card kbd[data-done="1"] { border-color: var(--ok); color: var(--ok); background: #e6f2e7; }
|
|
235
|
+
.tutorial-done { flex-basis: 100%; margin: 0 0 4px; color: var(--ink); display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
|
|
213
236
|
.tutorial-done[hidden] { display: none; }
|
|
214
|
-
.tutorial-steps[hidden] { display: none; }
|
|
215
237
|
.tutorial-done p { flex-basis: 100%; margin: 0; }
|
|
216
238
|
#playground-download-status, #playground-download-error { flex-basis: 100%; margin: 0; }
|
|
217
|
-
.
|
|
218
|
-
button.copy {
|
|
219
|
-
background: var(--panel); border: 1px solid var(--line); color: var(--ink);
|
|
220
|
-
border-radius: 6px; padding: 5px 10px; font: inherit; font-size: 13px; cursor: pointer;
|
|
221
|
-
}
|
|
222
|
-
button.copy[data-state="copied"] { border-color: #4f7a4a; color: #8fd47f; }
|
|
223
|
-
pre.with-copy { position: relative; }
|
|
224
|
-
pre.with-copy .copy { position: absolute; right: 10px; top: 10px; }
|
|
225
|
-
@media (max-width: 720px), (hover: none) {
|
|
226
|
-
.playground-cover .btn, .playground-cover small { display: none; }
|
|
227
|
-
.playground-phone { display: block; color: var(--ink); font-size: 14px; padding: 0 24px; text-align: center; }
|
|
228
|
-
.playground-cover { cursor: default; }
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
section { padding: 40px 0; border-top: 1px solid var(--line); }
|
|
232
|
-
h2 { font-size: clamp(22px, 3.2vw, 28px); margin: 0 0 8px; color: var(--clay); letter-spacing: -.01em; }
|
|
233
|
-
h3 { font-size: 17px; margin: 0 0 6px; color: var(--clay); }
|
|
234
|
-
.sub { color: var(--muted); margin: 0 0 26px; max-width: 48em; }
|
|
239
|
+
.demo-note { margin: 24px 0 0; }
|
|
235
240
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
.
|
|
240
|
-
.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
/* Quick start */
|
|
242
|
+
.start { display: flex; flex-wrap: wrap; gap: 32px 40px; }
|
|
243
|
+
.start-head { flex: 1 1 280px; }
|
|
244
|
+
.start-head h2 { margin-bottom: 8px; }
|
|
245
|
+
.start-head p { margin: 0 0 8px; color: var(--muted); }
|
|
246
|
+
.start-head a { display: inline-flex; align-items: center; min-height: 44px; font-size: 14px; text-decoration: none; }
|
|
247
|
+
.start-body { flex: 999 1 480px; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
|
|
248
|
+
.seg { align-self: flex-start; display: flex; gap: 2px; padding: 2px; background: #dcdce1; border-radius: 10px; }
|
|
249
|
+
.seg button {
|
|
250
|
+
min-height: 44px; padding: 0 18px; border: 0; border-radius: 8px; background: transparent;
|
|
251
|
+
color: var(--ink); font-size: 14px; font-weight: 600; cursor: pointer; transition: background .15s;
|
|
252
|
+
}
|
|
253
|
+
.seg button[aria-pressed="true"] { background: var(--panel); box-shadow: 0 1px 2px rgba(0, 0, 0, .12); }
|
|
254
|
+
.code {
|
|
255
|
+
position: relative; min-height: 140px; padding: 16px 96px 16px 20px;
|
|
256
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow-card);
|
|
245
257
|
}
|
|
246
|
-
code {
|
|
258
|
+
.code[hidden] { display: none; }
|
|
259
|
+
.code pre { margin: 0; overflow-x: auto; line-height: 1.7; }
|
|
260
|
+
.code .copy { position: absolute; right: 12px; top: 12px; min-height: 44px; padding: 0 14px; border: 0; background: none; color: var(--accent); font-weight: 600; }
|
|
247
261
|
|
|
248
|
-
table { width: 100%; border-collapse: collapse;
|
|
262
|
+
table { width: 100%; border-collapse: collapse; }
|
|
249
263
|
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); }
|
|
250
|
-
th {
|
|
264
|
+
th { font-weight: 600; white-space: nowrap; }
|
|
251
265
|
td { color: var(--muted); }
|
|
252
266
|
.scroller { overflow-x: auto; }
|
|
253
267
|
|
|
254
|
-
details { border-bottom: 1px solid var(--line); padding:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
#controls
|
|
258
|
-
|
|
259
|
-
|
|
268
|
+
details { border-bottom: 1px solid var(--line); padding: 6px 0; }
|
|
269
|
+
details summary { display: flex; align-items: center; min-height: 44px; cursor: pointer; font-weight: 600; }
|
|
270
|
+
details p { color: var(--muted); margin: 0 0 12px; }
|
|
271
|
+
#controls { padding: 0 0 88px; border-top: 0; }
|
|
272
|
+
#controls .scroller { margin: 12px 0; }
|
|
273
|
+
#faq h2 { margin-bottom: 16px; }
|
|
274
|
+
|
|
275
|
+
.closing .wrap { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 24px; }
|
|
276
|
+
.closing h2 { margin: 0; }
|
|
260
277
|
|
|
261
|
-
footer.site { border-top: 1px solid var(--line); padding:
|
|
262
|
-
footer.site
|
|
278
|
+
footer.site { border-top: 1px solid var(--line); padding: 20px 0 32px; color: var(--muted); font-size: 14px; }
|
|
279
|
+
footer.site .wrap { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 24px; }
|
|
280
|
+
footer.site p { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 20px; }
|
|
281
|
+
footer.site a { display: inline-flex; align-items: center; min-height: 44px; color: var(--muted); text-decoration: none; }
|
|
282
|
+
footer.site a:hover { color: var(--ink); }
|
|
263
283
|
|
|
284
|
+
@media (max-width: 720px), (hover: none) {
|
|
285
|
+
.playground-cover .btn, .playground-cover small { display: none; }
|
|
286
|
+
.playground-phone { display: block; font-size: 14px; padding: 0 24px; text-align: center; }
|
|
287
|
+
.playground-cover { cursor: default; }
|
|
288
|
+
/* No playground here, so no steps squeezed into the title bar. */
|
|
289
|
+
.tutorial-steps { visibility: hidden; }
|
|
290
|
+
}
|
|
264
291
|
@media (max-width: 720px) {
|
|
265
|
-
.
|
|
292
|
+
.tutorial-card { max-width: 90%; }
|
|
293
|
+
section { padding: 64px 0; }
|
|
294
|
+
.hero { padding: 56px 0 40px; }
|
|
295
|
+
.proof { padding-bottom: 64px; }
|
|
296
|
+
.cta .btn { width: 100%; }
|
|
297
|
+
.code { padding-right: 20px; padding-top: 60px; }
|
|
266
298
|
}
|
|
267
|
-
@media (
|
|
268
|
-
|
|
269
|
-
.
|
|
270
|
-
.tutorial-card { max-width: 90%; font-size: 14px; }
|
|
271
|
-
.btn { width: 100%; text-align: center; }
|
|
272
|
-
header.site nav { gap: 14px; width: 100%; margin-left: 0; padding-bottom: 10px; }
|
|
299
|
+
@media (prefers-reduced-motion: reduce) {
|
|
300
|
+
html { scroll-behavior: auto; }
|
|
301
|
+
.btn, a.card, .seg button, .tutorial-steps li { transition: none; }
|
|
273
302
|
}
|
|
274
303
|
</style>
|
|
275
|
-
<script type="module" crossorigin src="/assets/landing-
|
|
276
|
-
<link rel="modulepreload" crossorigin href="/assets/analytics-
|
|
277
|
-
<link rel="modulepreload" crossorigin href="/assets/first-shot-handoff-
|
|
304
|
+
<script type="module" crossorigin src="/assets/landing-ChUvB_zL.js"></script>
|
|
305
|
+
<link rel="modulepreload" crossorigin href="/assets/analytics-C9pMpW7s.js">
|
|
306
|
+
<link rel="modulepreload" crossorigin href="/assets/first-shot-handoff-msLI71g1.js">
|
|
278
307
|
</head>
|
|
279
308
|
<body>
|
|
280
309
|
<header class="site">
|
|
281
310
|
<div class="wrap">
|
|
282
|
-
<a class="brand" href="/"
|
|
311
|
+
<a class="brand" href="/"><img src="/media/cozyclay-logo.png" width="880" height="714" alt="" />CozyClay</a>
|
|
283
312
|
<nav>
|
|
284
|
-
<a href="#
|
|
313
|
+
<a href="#how">How it works</a>
|
|
314
|
+
<a href="#try">Demo</a>
|
|
285
315
|
<a href="#start">Quick start</a>
|
|
286
|
-
<a href="/greybox-to-video/">Greybox to video</a>
|
|
287
|
-
<a href="/previs-software/">Previs software</a>
|
|
288
316
|
<a href="https://github.com/NomaDamas/CozyClay">GitHub</a>
|
|
317
|
+
<a class="btn primary" href="#try">Try it</a>
|
|
289
318
|
</nav>
|
|
290
319
|
</div>
|
|
291
320
|
</header>
|
|
292
321
|
|
|
293
|
-
<main
|
|
294
|
-
<
|
|
295
|
-
<div class="
|
|
296
|
-
<
|
|
297
|
-
<
|
|
322
|
+
<main>
|
|
323
|
+
<section class="hero">
|
|
324
|
+
<div class="wrap">
|
|
325
|
+
<h1>Block the shot before you <em>pay to render it</em></h1>
|
|
326
|
+
<p class="lede">Free, open source previs in your browser.</p>
|
|
327
|
+
<div class="cta">
|
|
328
|
+
<a class="btn primary" href="#try">Try it in your browser</a>
|
|
329
|
+
<a class="btn ghost" href="https://github.com/NomaDamas/CozyClay">View on GitHub</a>
|
|
330
|
+
</div>
|
|
331
|
+
<span class="cmd">
|
|
332
|
+
<code>npx cozyclay --via site</code>
|
|
333
|
+
<button type="button" class="copy" data-copy="npx cozyclay --via site" aria-label="Copy command">
|
|
334
|
+
<svg class="ic-copy" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"></rect><path d="M5 15V6a2 2 0 0 1 2-2h9"></path></svg>
|
|
335
|
+
<svg class="ic-done" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5 9-10"></path></svg>
|
|
336
|
+
</button>
|
|
337
|
+
</span>
|
|
298
338
|
</div>
|
|
299
|
-
|
|
300
|
-
Free, open source previs in your browser. Block the scene, pose the characters,
|
|
301
|
-
set the camera, then hand that exact shot to an AI video model.
|
|
302
|
-
</p>
|
|
339
|
+
</section>
|
|
303
340
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
341
|
+
<section class="proof">
|
|
342
|
+
<div class="wrap">
|
|
343
|
+
<figure>
|
|
344
|
+
<div class="window">
|
|
345
|
+
<div class="titlebar" aria-hidden="true"><i></i><i></i><i></i><span>CozyClay</span></div>
|
|
307
346
|
<video
|
|
308
347
|
src="/media/cozyclay-demo.mp4"
|
|
309
348
|
poster="/media/cozyclay-demo-poster.jpg"
|
|
@@ -311,38 +350,44 @@
|
|
|
311
350
|
autoplay muted loop playsinline preload="metadata"
|
|
312
351
|
></video>
|
|
313
352
|
</div>
|
|
314
|
-
<
|
|
315
|
-
</
|
|
316
|
-
<div>
|
|
317
|
-
<div class="reel">
|
|
318
|
-
<video
|
|
319
|
-
src="/media/cozyclay-seedance-vs-greybox.mp4"
|
|
320
|
-
poster="/media/cozyclay-seedance-vs-greybox-poster.jpg"
|
|
321
|
-
width="1104" height="946"
|
|
322
|
-
autoplay muted loop playsinline preload="metadata"
|
|
323
|
-
></video>
|
|
324
|
-
</div>
|
|
325
|
-
<p class="reel-note">Top: blocked here. Bottom: Seedance 2.5, same camera. <a class="chip" href="https://x.com/Yun_HDY/status/2091577179914338583">the post ↗</a></p>
|
|
326
|
-
</div>
|
|
353
|
+
<figcaption>Greybox left, generated right. Same camera, every cut.</figcaption>
|
|
354
|
+
</figure>
|
|
327
355
|
</div>
|
|
356
|
+
</section>
|
|
328
357
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<
|
|
358
|
+
<section id="how">
|
|
359
|
+
<div class="wrap">
|
|
360
|
+
<h2>How it works</h2>
|
|
361
|
+
<div class="cards">
|
|
362
|
+
<div class="card">
|
|
363
|
+
<span class="n">1</span>
|
|
364
|
+
<h3>Block the scene</h3>
|
|
365
|
+
<p>Set pieces and characters.</p>
|
|
366
|
+
</div>
|
|
367
|
+
<div class="card">
|
|
368
|
+
<span class="n">2</span>
|
|
369
|
+
<h3>Set the camera</h3>
|
|
370
|
+
<p>Moves and cuts on a timeline.</p>
|
|
371
|
+
</div>
|
|
372
|
+
<div class="card">
|
|
373
|
+
<span class="n">3</span>
|
|
374
|
+
<h3>Hand off the shot</h3>
|
|
375
|
+
<p>Export the move, not a prompt.</p>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
332
378
|
</div>
|
|
333
|
-
|
|
334
|
-
Or run it on your machine: <code>npx cozyclay --via site</code>. No Blender, no Unity. Open a saved <code>.cclayproject</code> from the first dialog.
|
|
335
|
-
</p>
|
|
336
|
-
</div>
|
|
379
|
+
</section>
|
|
337
380
|
|
|
338
|
-
<section id="try">
|
|
381
|
+
<section id="try" class="alt">
|
|
382
|
+
<div class="wrap">
|
|
339
383
|
<h2>Try it</h2>
|
|
340
|
-
<
|
|
341
|
-
<
|
|
384
|
+
<div class="demo">
|
|
385
|
+
<div class="window">
|
|
386
|
+
<div class="titlebar"><i aria-hidden="true"></i><i aria-hidden="true"></i><i aria-hidden="true"></i><ol class="tutorial-steps" id="tutorial-steps" aria-label="Tutorial steps"></ol></div>
|
|
342
387
|
<div class="playground" id="playground" style="background-image: url('/media/playground-poster.jpg')">
|
|
343
388
|
<button class="playground-cover" id="playground-start" type="button" aria-label="Start the playground">
|
|
344
389
|
<span class="btn primary">Play with the scene</span>
|
|
345
|
-
<small>
|
|
390
|
+
<small>About 2 MB</small>
|
|
346
391
|
<span class="playground-phone">Needs a mouse and keyboard. Come back on a computer, or run <code>npx cozyclay --via site</code>.</span>
|
|
347
392
|
</button>
|
|
348
393
|
<div class="playground-loading">Loading the studio…</div>
|
|
@@ -365,44 +410,67 @@
|
|
|
365
410
|
<a href="/app/" target="_blank" rel="noopener">Open studio ↗</a>
|
|
366
411
|
<button type="button" id="playground-close">Close</button>
|
|
367
412
|
</div>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
<p class="small demo-note">Needs a mouse and keyboard.</p>
|
|
416
|
+
</div>
|
|
368
417
|
</section>
|
|
369
418
|
|
|
370
419
|
<section id="what">
|
|
371
|
-
<
|
|
372
|
-
|
|
373
|
-
<div class="
|
|
374
|
-
<
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
<
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
<
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
<
|
|
387
|
-
|
|
420
|
+
<div class="wrap">
|
|
421
|
+
<h2>What you can do</h2>
|
|
422
|
+
<div class="cards">
|
|
423
|
+
<div class="card">
|
|
424
|
+
<h3>Stage a scene</h3>
|
|
425
|
+
<p>Primitives, set pieces, plan view.</p>
|
|
426
|
+
</div>
|
|
427
|
+
<div class="card">
|
|
428
|
+
<h3>Move through the set</h3>
|
|
429
|
+
<p>Fly, walk, orbit, frame.</p>
|
|
430
|
+
</div>
|
|
431
|
+
<div class="card">
|
|
432
|
+
<h3>Author the camera</h3>
|
|
433
|
+
<p>Lens, dolly, crane, cuts.</p>
|
|
434
|
+
</div>
|
|
435
|
+
<div class="card">
|
|
436
|
+
<h3>Generate motion</h3>
|
|
437
|
+
<p>Poses, Prompt Blocks, IK fixes.</p>
|
|
438
|
+
</div>
|
|
388
439
|
</div>
|
|
389
440
|
</div>
|
|
390
441
|
</section>
|
|
391
442
|
|
|
392
|
-
<section id="start">
|
|
393
|
-
<
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
443
|
+
<section id="start" class="alt">
|
|
444
|
+
<div class="wrap start">
|
|
445
|
+
<div class="start-head">
|
|
446
|
+
<h2>Quick start</h2>
|
|
447
|
+
<p>Node.js 22.13+ and a Chromium browser.</p>
|
|
448
|
+
<a href="#controls" id="controls-link">Full control list</a>
|
|
449
|
+
</div>
|
|
450
|
+
<div class="start-body">
|
|
451
|
+
<div class="seg" id="start-tabs">
|
|
452
|
+
<button type="button" aria-pressed="true" data-panel="start-npx">npx</button>
|
|
453
|
+
<button type="button" aria-pressed="false" data-panel="start-src">From source</button>
|
|
454
|
+
</div>
|
|
455
|
+
<div class="code" id="start-npx">
|
|
456
|
+
<pre><code>npx cozyclay --via site</code></pre>
|
|
457
|
+
<button type="button" class="copy" data-copy="npx cozyclay --via site">Copy</button>
|
|
458
|
+
</div>
|
|
459
|
+
<div class="code" id="start-src" hidden>
|
|
460
|
+
<pre><code>git clone https://github.com/NomaDamas/CozyClay.git
|
|
398
461
|
cd CozyClay
|
|
399
462
|
npm install
|
|
400
463
|
npm run dev</code></pre>
|
|
464
|
+
<button type="button" class="copy" data-copy="git clone https://github.com/NomaDamas/CozyClay.git cd CozyClay npm install npm run dev">Copy</button>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
401
468
|
</section>
|
|
402
469
|
|
|
403
|
-
<section id="controls">
|
|
470
|
+
<section id="controls" class="alt">
|
|
471
|
+
<div class="wrap">
|
|
404
472
|
<details>
|
|
405
|
-
<summary>Full control list
|
|
473
|
+
<summary>Full control list</summary>
|
|
406
474
|
<div class="scroller">
|
|
407
475
|
<table>
|
|
408
476
|
<thead><tr><th>Input</th><th>Action</th></tr></thead>
|
|
@@ -421,21 +489,25 @@ npm run dev</code></pre>
|
|
|
421
489
|
</table>
|
|
422
490
|
</div>
|
|
423
491
|
</details>
|
|
492
|
+
</div>
|
|
424
493
|
</section>
|
|
425
494
|
|
|
426
495
|
<section id="read">
|
|
427
|
-
<
|
|
428
|
-
|
|
429
|
-
<
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
496
|
+
<div class="wrap">
|
|
497
|
+
<h2>Read</h2>
|
|
498
|
+
<div class="cards">
|
|
499
|
+
<a class="card" href="/greybox-to-video/">Greybox to AI video</a>
|
|
500
|
+
<a class="card" href="/seedance-camera-control/">Seedance 2.5 camera control</a>
|
|
501
|
+
<a class="card" href="/previs-software/">Previs software compared</a>
|
|
502
|
+
<a class="card" href="/ai-camera-control/">Camera control for AI video</a>
|
|
503
|
+
</div>
|
|
433
504
|
</div>
|
|
434
505
|
</section>
|
|
435
506
|
|
|
436
507
|
<section id="faq">
|
|
508
|
+
<div class="wrap narrow">
|
|
437
509
|
<h2>FAQ</h2>
|
|
438
|
-
<details
|
|
510
|
+
<details>
|
|
439
511
|
<summary>What is CozyClay?</summary>
|
|
440
512
|
<p>Open source previs software in a browser: block a scene, pose characters, author camera moves and cuts, preview motion.</p>
|
|
441
513
|
</details>
|
|
@@ -455,14 +527,48 @@ npm run dev</code></pre>
|
|
|
455
527
|
<summary>Is it free? Does it phone home?</summary>
|
|
456
528
|
<p>Free, AGPL-3.0, runs on your machine and works offline. Project content is never uploaded. The npm package sends anonymous usage metrics; <code>cclay telemetry off</code> disables them.</p>
|
|
457
529
|
</details>
|
|
530
|
+
</div>
|
|
531
|
+
</section>
|
|
532
|
+
|
|
533
|
+
<section class="closing alt">
|
|
534
|
+
<div class="wrap">
|
|
535
|
+
<h2>Block your first shot</h2>
|
|
536
|
+
<div class="cta">
|
|
537
|
+
<a class="btn primary" href="#try">Try it in your browser</a>
|
|
538
|
+
<a class="btn ghost" href="https://github.com/NomaDamas/CozyClay">View on GitHub</a>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
458
541
|
</section>
|
|
459
542
|
</main>
|
|
460
543
|
|
|
544
|
+
<script>
|
|
545
|
+
// Quick start: one code block at a time. The link to the control list opens it.
|
|
546
|
+
(() => {
|
|
547
|
+
const tabs = document.querySelectorAll("#start-tabs button");
|
|
548
|
+
tabs.forEach((tab) => tab.addEventListener("click", () => {
|
|
549
|
+
tabs.forEach((other) => {
|
|
550
|
+
const on = other === tab;
|
|
551
|
+
other.setAttribute("aria-pressed", String(on));
|
|
552
|
+
document.getElementById(other.dataset.panel).hidden = !on;
|
|
553
|
+
});
|
|
554
|
+
}));
|
|
555
|
+
document.getElementById("controls-link").addEventListener("click", () => {
|
|
556
|
+
document.querySelector("#controls details").open = true;
|
|
557
|
+
});
|
|
558
|
+
// A started playground takes the screen: steps, window and its bar in view.
|
|
559
|
+
document.getElementById("playground-start").addEventListener("click", () => {
|
|
560
|
+
if (!matchMedia("(min-width: 721px) and (hover: hover)").matches) return;
|
|
561
|
+
const still = matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
562
|
+
document.querySelector("#try .demo").scrollIntoView({ block: "start", behavior: still ? "auto" : "smooth" });
|
|
563
|
+
});
|
|
564
|
+
})();
|
|
565
|
+
</script>
|
|
566
|
+
|
|
461
567
|
<footer class="site">
|
|
462
568
|
<div class="wrap">
|
|
463
569
|
<p>
|
|
464
|
-
<a href="https://github.com/NomaDamas/CozyClay">Source
|
|
465
|
-
<a href="https://www.npmjs.com/package/cozyclay">npm</a>
|
|
570
|
+
<a href="https://github.com/NomaDamas/CozyClay">Source (AGPL)</a>
|
|
571
|
+
<a href="https://www.npmjs.com/package/cozyclay">npm</a>
|
|
466
572
|
<a href="/privacy/">Privacy</a>
|
|
467
573
|
</p>
|
|
468
574
|
<p>
|