retake-demos 0.2.0 → 0.2.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/README.md +12 -10
- package/dist/cli.js +14 -3
- package/dist/manifest.js +8 -1
- package/dist/presets.js +7 -4
- package/dist/ui/index.html +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ Exit codes: `0` good · `2` a step failed or the video is a raw fallback · `3`
|
|
|
78
78
|
name: first-project
|
|
79
79
|
title: "Creating your first project"
|
|
80
80
|
url: http://localhost:3000
|
|
81
|
-
preset: post-landscape #
|
|
81
|
+
preset: post-landscape # `retake presets` — 1920×1080 page + caption band
|
|
82
82
|
viewport: { width: 1440, height: 1080 }
|
|
83
83
|
scale: 1.8 # page drawn at 1.8× so text stays crisp
|
|
84
84
|
reducedMotion: true
|
|
@@ -113,15 +113,17 @@ The full template is [`demos/example.yaml`](demos/example.yaml); `retake init` c
|
|
|
113
113
|
|
|
114
114
|
Think in the publishing format, not the browser window.
|
|
115
115
|
|
|
116
|
-
| Preset |
|
|
117
|
-
|
|
118
|
-
| `draft` | 960×
|
|
119
|
-
| `preview-fast` | 1920×
|
|
120
|
-
| `post-landscape` *(default)* | 1920×
|
|
121
|
-
| `post-square` | 1080×1080
|
|
122
|
-
| `post-vertical` | 1080×1920
|
|
123
|
-
| `docs-gif` | 1440×
|
|
124
|
-
| `master` | 1920×
|
|
116
|
+
| Preset | Video | Page area | For |
|
|
117
|
+
|---|---:|---:|---|
|
|
118
|
+
| `draft` | 960×616 | 960×540 | iterating — the finals' layout at a quarter of the pixels, fastest |
|
|
119
|
+
| `preview-fast` | 1920×1230 | 1920×1080 | checking timing and framing, hardware-encoded |
|
|
120
|
+
| `post-landscape` *(default)* | 1920×1230 | 1920×1080 | the general-purpose demo, plus a CRF-14 master |
|
|
121
|
+
| `post-square` | 1080×1080 | 1080×950 | feeds — a true square |
|
|
122
|
+
| `post-vertical` | 1080×1920 | 1080×1750 | shorts and reels — a true 9:16 |
|
|
123
|
+
| `docs-gif` | 1440×1000 | 1440×900 | README and docs GIFs |
|
|
124
|
+
| `master` | 1920×1230 | 1920×1080 | archive, CRF 12 |
|
|
125
|
+
|
|
126
|
+
**The video is the page area plus the caption band.** Landscape keeps a full 1920×1080 page and the band goes under it (1920×1230) — the captions never cover the app. Square and vertical fit the band inside the canvas, because a feed that wants 1:1 or 9:16 will letterbox anything else. A manifest's `viewport` replaces the page area and the video follows it, so a 1240×1080 viewport gives a 1240×1230 video. `retake presets` prints this table, and `retake validate` tells you the exact size of the video a manifest will produce before you record it.
|
|
125
127
|
|
|
126
128
|
**Page scale** is what makes it crisp: the page lays out as if the viewport were smaller and every glyph is drawn at 2×, so 1080p text reads on a phone. **Camera** eases toward whatever the demo just touched, at render time, clamped so it can never crop the thing it points at — per scene: `camera: static` or `camera: { focus: ".result", zoom: 1.3 }`. Captions, camera, speed, trim, format and layout are all render-time: change them and `retake render` takes seconds, never touches the browser.
|
|
127
129
|
|
package/dist/cli.js
CHANGED
|
@@ -384,15 +384,26 @@ program
|
|
|
384
384
|
.description("list quality presets")
|
|
385
385
|
.action(async () => {
|
|
386
386
|
const { PRESETS } = await import("./presets.js");
|
|
387
|
-
|
|
388
|
-
|
|
387
|
+
say(`${"preset".padEnd(16)} ${"video".padEnd(11)} ${"page".padEnd(11)} fps layout`);
|
|
388
|
+
for (const p of Object.values(PRESETS)) {
|
|
389
|
+
const video = p.layout === "card" ? `${p.width}×${p.height}` : `${p.width}×${p.height + (p.layout === "band" ? p.bandHeight : 0)}`;
|
|
390
|
+
say(`${p.name.padEnd(16)} ${video.padEnd(11)} ${String(p.width + "×" + p.height).padEnd(11)} ${String(p.fps).padEnd(4)} ${p.layout.padEnd(5)} — ${p.description}`);
|
|
391
|
+
}
|
|
392
|
+
say(`\nvideo = page + caption band. A manifest's \`viewport\` replaces the page size (the video follows it).`);
|
|
389
393
|
});
|
|
390
394
|
program
|
|
391
395
|
.command("validate")
|
|
392
396
|
.argument("<manifest>")
|
|
393
|
-
.action((file) => {
|
|
397
|
+
.action(async (file) => {
|
|
394
398
|
const { manifest } = loadManifest(file);
|
|
399
|
+
const { resolve } = await import("./manifest.js");
|
|
400
|
+
const q = resolve(manifest);
|
|
401
|
+
// The video is the page area plus the caption band, so say the real number
|
|
402
|
+
// here rather than letting it surprise someone after a two-minute take.
|
|
403
|
+
const outW = q.layout === "card" ? q.width : q.viewport.width;
|
|
404
|
+
const outH = (q.layout === "card" ? q.height : q.viewport.height) + (q.layout === "band" ? q.bandHeight : 0);
|
|
395
405
|
say(`ok: ${manifest.name} · ${manifest.steps.length} steps · ${manifest.steps.filter((s) => s.action === "scene").length} scenes`);
|
|
406
|
+
say(` ${q.name} · video ${outW}×${outH}${q.layout === "band" ? ` (page ${q.viewport.width}×${q.viewport.height} + ${q.bandHeight}px caption band)` : ""} @ ${q.fps}fps${q.gif ? ` · gif ${q.gif.width}px` : ""}`);
|
|
396
407
|
for (const w of warnings(manifest))
|
|
397
408
|
say(`⚠ ${w}`);
|
|
398
409
|
});
|
package/dist/manifest.js
CHANGED
|
@@ -339,7 +339,14 @@ export function resolve(m) {
|
|
|
339
339
|
const p = PRESETS[m.preset] ?? PRESETS[DEFAULT_PRESET];
|
|
340
340
|
const viewport = { width: m.viewport?.width ?? p.width, height: m.viewport?.height ?? p.height };
|
|
341
341
|
const gifOverride = m.outputs.gif;
|
|
342
|
-
|
|
342
|
+
/* `gif: true` means "yes, a GIF" on any preset. Only docs-gif carries GIF
|
|
343
|
+
settings, so asking for one anywhere else used to resolve to the preset's
|
|
344
|
+
`false` and produce nothing, silently. */
|
|
345
|
+
const GIF_DEFAULT = { width: 900, fps: 15 };
|
|
346
|
+
const gif = gifOverride === false ? false
|
|
347
|
+
: gifOverride === true ? (p.gif === false ? GIF_DEFAULT : p.gif)
|
|
348
|
+
: p.gif === false ? { width: gifOverride.width ?? GIF_DEFAULT.width, fps: gifOverride.fps ?? GIF_DEFAULT.fps }
|
|
349
|
+
: { width: gifOverride.width ?? p.gif.width, fps: gifOverride.fps ?? p.gif.fps };
|
|
343
350
|
const cursor = m.cursor === false ? false : { style: (m.cursor === true ? "default" : m.cursor.style ?? "default"), size: m.cursor === true ? p.cursorSize : m.cursor.size ?? p.cursorSize, idleHideMs: m.cursor === true ? 2000 : m.cursor.idleHideMs ?? 2000, idleHide: m.cursor === true ? undefined : m.cursor.idleHide };
|
|
344
351
|
const captions = m.captions === false ? false : { fontSize: m.captions === true ? p.captionFontSize : m.captions.fontSize ?? p.captionFontSize, color: m.captions === true ? undefined : m.captions.color };
|
|
345
352
|
return {
|
package/dist/presets.js
CHANGED
|
@@ -38,19 +38,22 @@ export const PRESETS = {
|
|
|
38
38
|
},
|
|
39
39
|
"post-square": {
|
|
40
40
|
name: "post-square",
|
|
41
|
-
|
|
41
|
+
/* The page area is the canvas minus the caption band, so the file really
|
|
42
|
+
is 1080×1080 — a square preset that produced 1080×1210 got letterboxed
|
|
43
|
+
by every feed. Landscape keeps its full-height page on purpose. */
|
|
44
|
+
width: 1080, height: 950, scale: 1.6, fps: 30, crf: 17,
|
|
42
45
|
gif: false, layout: "band", cameraZoom: 1.25,
|
|
43
46
|
cursorSize: 60, captionFontSize: 40, bandHeight: 130,
|
|
44
47
|
encoder: "x264", master: true,
|
|
45
|
-
description: "1080×1080, feed-friendly.",
|
|
48
|
+
description: "A true 1080×1080 (page 1080×950 + caption band), feed-friendly.",
|
|
46
49
|
},
|
|
47
50
|
"post-vertical": {
|
|
48
51
|
name: "post-vertical",
|
|
49
|
-
width: 1080, height:
|
|
52
|
+
width: 1080, height: 1750, scale: 2, fps: 30, crf: 17,
|
|
50
53
|
gif: false, layout: "band", cameraZoom: 1.3,
|
|
51
54
|
cursorSize: 60, captionFontSize: 44, bandHeight: 170,
|
|
52
55
|
encoder: "x264", master: true,
|
|
53
|
-
description: "
|
|
56
|
+
description: "A true 1080×1920 (page 1080×1750 + caption band) for shorts/reels. Narrow-column apps suit it best.",
|
|
54
57
|
},
|
|
55
58
|
"docs-gif": {
|
|
56
59
|
name: "docs-gif",
|
package/dist/ui/index.html
CHANGED
|
@@ -381,7 +381,9 @@ function saveDraftSoon() { clearTimeout(draftTimer); draftTimer = setTimeout(asy
|
|
|
381
381
|
}, 500); }
|
|
382
382
|
|
|
383
383
|
// ---------- demo view ----------
|
|
384
|
-
|
|
384
|
+
// Shape, not a resolution: the video is the page plus the caption band, so
|
|
385
|
+
// "1080p" was never true of what post-landscape actually writes (1920×1230).
|
|
386
|
+
const PRESET_LABEL = { 'post-landscape': 'landscape', 'post-square': 'square', 'post-vertical': 'vertical', 'docs-gif': 'docs', 'proof-fast': 'small', 'master': 'master', 'preview-fast': 'preview', 'draft': 'draft' };
|
|
385
387
|
async function select(name) {
|
|
386
388
|
if (dirty && !confirm('Discard unsaved manifest edits?')) return;
|
|
387
389
|
current = name; dirty = false; setMsg('');
|
|
@@ -708,7 +710,7 @@ document.addEventListener('keydown', (e) => {
|
|
|
708
710
|
// ---------- boot ----------
|
|
709
711
|
(async () => {
|
|
710
712
|
setQuality(quality);
|
|
711
|
-
try { const ps = await api('/api/presets'); $('sPreset').innerHTML = ps.filter((p) => p.name !== 'preview-fast').map((p) => `<option value="${p.name}">${p.name} — ${p.width}×${
|
|
713
|
+
try { const ps = await api('/api/presets'); $('sPreset').innerHTML = ps.filter((p) => p.name !== 'preview-fast').map((p) => { const h = p.layout === 'card' ? p.height : p.height + (p.layout === 'band' ? p.bandHeight : 0); return `<option value="${p.name}">${p.name} — ${p.width}×${h}</option>`; }).join(''); } catch {}
|
|
712
714
|
try { settings = await api('/api/settings'); $('modelTag').textContent = settings.active ? 'model: ' + settings.active : 'no model — set one in Settings'; } catch {}
|
|
713
715
|
const list = await loadDemos();
|
|
714
716
|
// Arriving from the review page's Edit link: /classic#<demo> opens that demo.
|
package/package.json
CHANGED