@vosjs/cli 0.60.0 → 0.60.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 +1 -1
- package/dist/{assetManifest-MM5WGOWG.js → assetManifest-Y5FYTZW6.js} +3 -3
- package/dist/{chunk-OMDRILG7.js → chunk-LWHVZ5WI.js} +12 -6
- package/dist/chunk-LWHVZ5WI.js.map +1 -0
- package/dist/{chunk-NE5MHC3D.js → chunk-QL25OPZB.js} +6 -6
- package/dist/{chunk-NE5MHC3D.js.map → chunk-QL25OPZB.js.map} +1 -1
- package/dist/{chunk-36P5RREC.js → chunk-WCF6KIOK.js} +240 -118
- package/dist/chunk-WCF6KIOK.js.map +1 -0
- package/dist/{chunk-PUXY32AP.js → chunk-YMVRTZ4L.js} +69 -20
- package/dist/chunk-YMVRTZ4L.js.map +1 -0
- package/dist/cli.js +17 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{run-5DLEKBK2.js → run-BJ77A4G6.js} +5 -5
- package/package.json +5 -5
- package/skills/VERSION +1 -1
- package/skills/vos-authoring/references/schema-reference.md +40 -2
- package/skills/vos-port/SKILL.md +3 -1
- package/skills/vos-port/references/elements-and-context.md +5 -0
- package/skills/vos-port/references/hyperframes.md +1 -1
- package/skills/vos-port/references/remotion.md +1 -1
- package/dist/chunk-36P5RREC.js.map +0 -1
- package/dist/chunk-OMDRILG7.js.map +0 -1
- package/dist/chunk-PUXY32AP.js.map +0 -1
- /package/dist/{assetManifest-MM5WGOWG.js.map → assetManifest-Y5FYTZW6.js.map} +0 -0
- /package/dist/{run-5DLEKBK2.js.map → run-BJ77A4G6.js.map} +0 -0
package/README.md
CHANGED
|
@@ -334,7 +334,7 @@ vos recipe push <FILE.md> --folder <slug> | --asset <id> # the one recipe writ
|
|
|
334
334
|
|
|
335
335
|
`push` is polymorphic by a deterministic sniff, never a flag: a take directory (a `doc.json` carrying `source`) pushes recording and document through the take pipeline; a `config.json` (or a directory holding one) pushes the program, and a `doc.json` beside it that carries `program` (a program document: overlays, objects, audio, speed, tween edits, its own length; `program.config` omitted on disk) rides along, lint-gated. `fetch` and `pull` write a program document back the same way. `pull` takes `--since <versionId>` (walk the changelog from that base instead of the tracked one) and `--check` (print what changed and stop: nothing on disk moves) on both paths. A program push LANDS where `vos.json` says: a directory that tracks a vos iterates it, so the fetch, edit, check, push, pull loop needs no flags, and making something separate from the same config is the explicit `--remix-of` door. Program pushes take `--vos`, `--title`, `--slug`, `--desc`, `--tags`, `--folder`, `--remix-of`, `--base`, `--label`, `--note`, `--override <id>` (repeatable) and `--claimable`; take pushes take `--title`, `--label`, `--note`, `--folder`, `--override` and `--yes`. Both take `--wait`. A new vos pushed without `--folder` lands unfiled, at the root of the shelf, and the done line says so.
|
|
336
336
|
|
|
337
|
-
**A program's files are declared, never typed into a function.** `config.json` names each file it uses in `assets` (`"assets": { "logo": { "ref": "./logo.png", "kind": "image" }, "shots": { "ref": ["./shots/1.png", "./shots/2.png"] } }`) and reads `ctx.assets.logo`, or `"$assets.logo"` in an element, object or font. On disk a `ref` is a path
|
|
337
|
+
**A program's files are declared, never typed into a function.** `config.json` names each file it uses in `assets` (`"assets": { "logo": { "ref": "./logo.png", "kind": "image" }, "shots": { "ref": ["./shots/1.png", "./shots/2.png"] } }`) and reads `ctx.assets.logo`, or `"$assets.logo"` in an element, object or font. On disk a `ref` is a path in the config's own directory or below, so `vos render`, `vos still` and `vos preview` serve the file to the page from disk. A path that climbs out of that directory (`../`, an absolute path, a link that points away) is not served and not uploaded, and a config loaded from a URL reads no local file: a program's code runs in a page, and what the page is served the program can send anywhere. `vos push` uploads each local file (content-addressed, so a re-push sends nothing; pictures, video, sound and `.glb` models go, while a font or an HDR is named by URL) and what it stores names the hosted file as `asset:<id>`, the one spelling the platform resolves for every render; the config on disk keeps its paths. `vos fetch --media` brings a program's hosted files home under `assets/` and re-points the manifest at them (`assets/.hosted.json` remembers which hosted file each one is, so a later fetch replaces one that changed); without `--media` the manifest keeps `asset:<id>` and a local render reads each file with your key. `vos check` says when a `"$assets.<name>"` names nothing, when a declared path is not a file, and when a function names a hosted file in code instead of the manifest: a file named only in code does not load on a render of a private program and does not follow a remix. A `--claimable` push carries no files, so it is refused when the manifest names local ones.
|
|
338
338
|
|
|
339
339
|
**Sound is a track, never an element.** A document's added sound lives in `doc.json` (`audio: [{ id, key, name, start, in, out, duration, gain, fadeIn, fadeOut }]`) for a program as for a take: `vos push` uploads each local file its keys name and keys the hosted asset; `vos render` of a program mixes it locally; the studio shows it as a track with gain and fades. An `audio` element embedded in the config is not a track (renders do not mix it, and a `data:` source can push a config past what a claimable push carries); `vos check` says so. `vos asset push score.ogg` uploads a sound on its own and prints the url a key takes; an unfiled sound that no document uses is removed after 7 days, so pass `--folder` or reference it.
|
|
340
340
|
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
localManifestRefs,
|
|
5
5
|
pullManifest,
|
|
6
6
|
uploadManifest
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-YMVRTZ4L.js";
|
|
8
|
+
import "./chunk-WCF6KIOK.js";
|
|
9
9
|
export {
|
|
10
10
|
hostedLiteralWarnings,
|
|
11
11
|
localManifestRefs,
|
|
12
12
|
pullManifest,
|
|
13
13
|
uploadManifest
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=assetManifest-
|
|
15
|
+
//# sourceMappingURL=assetManifest-Y5FYTZW6.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ASSET_ROUTE,
|
|
4
|
-
UsageError
|
|
5
|
-
|
|
4
|
+
UsageError,
|
|
5
|
+
serveFile
|
|
6
|
+
} from "./chunk-WCF6KIOK.js";
|
|
6
7
|
|
|
7
8
|
// src/loadConfig.ts
|
|
8
9
|
import { readFile } from "fs/promises";
|
|
@@ -248,9 +249,14 @@ async function runCapturePage(browser, html, opts) {
|
|
|
248
249
|
);
|
|
249
250
|
const files = opts.files ?? {};
|
|
250
251
|
if (Object.keys(files).length > 0) {
|
|
251
|
-
await page.route(`${RENDER_ORIGIN}${ASSET_ROUTE}**`, (route) => {
|
|
252
|
-
const
|
|
253
|
-
|
|
252
|
+
await page.route(`${RENDER_ORIGIN}${ASSET_ROUTE}**`, async (route) => {
|
|
253
|
+
const request = route.request();
|
|
254
|
+
const file = files[new URL(request.url()).pathname];
|
|
255
|
+
if (!file) {
|
|
256
|
+
return route.fulfill({ status: 404, body: "no such declared file" });
|
|
257
|
+
}
|
|
258
|
+
const answer = serveFile(file, await request.headerValue("range"));
|
|
259
|
+
return route.fulfill(answer);
|
|
254
260
|
});
|
|
255
261
|
}
|
|
256
262
|
await page.goto(`${RENDER_ORIGIN}/render`, {
|
|
@@ -555,4 +561,4 @@ export {
|
|
|
555
561
|
setFlags,
|
|
556
562
|
applyDataSets
|
|
557
563
|
};
|
|
558
|
-
//# sourceMappingURL=chunk-
|
|
564
|
+
//# sourceMappingURL=chunk-LWHVZ5WI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/loadConfig.ts","../src/browser.ts","../src/render.ts","../src/outputs.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { existsSync, readFileSync, statSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport {\n CURRENT_CONFIG_VERSION,\n migrateConfig,\n vosConfigJsonSchema,\n} from '@vosjs/core'\nimport { UsageError } from './args'\n\nexport interface LoadedConfig {\n config: Record<string, unknown>\n warnings: string[]\n}\n\n/**\n * What a directory holds, by one deterministic sniff and never a flag:\n * a TAKE carries a recording document (`doc.json` with `source`); a PROGRAM\n * directory carries `config.json`, optionally beside a program document\n * (`doc.json` without `source`: the shared layers, the tween overlay, the\n * program's own length, with `program.config` omitted on disk). An unparsable\n * doc.json counts as a take so the take path reports the real error.\n */\nexport type DirectoryKind = 'take' | 'program' | 'none'\n\nexport function directoryKind(target: string): DirectoryKind {\n try {\n if (!statSync(target).isDirectory()) return 'none'\n } catch {\n return 'none'\n }\n const docPath = join(target, 'doc.json')\n if (existsSync(docPath)) {\n try {\n const doc: unknown = JSON.parse(readFileSync(docPath, 'utf8'))\n if (typeof doc === 'object' && doc !== null && 'source' in doc)\n return 'take'\n } catch {\n return 'take'\n }\n }\n return existsSync(join(target, 'config.json')) ? 'program' : 'none'\n}\n\n/** A directory holding a PROGRAM document (`doc.json` without `source`). */\nfunction hasProgramDoc(dir: string): boolean {\n const docPath = join(dir, 'doc.json')\n if (!existsSync(docPath)) return false\n try {\n const doc: unknown = JSON.parse(readFileSync(docPath, 'utf8'))\n return typeof doc === 'object' && doc !== null && !('source' in doc)\n } catch {\n return false\n }\n}\n\n/**\n * A program directory's config: `config.json`, composed with the program\n * document beside it when there is one (the layers ride as the studio stack\n * entry, the tween overlay is baked into `createTimeline`), so a render of\n * the directory is a render of what the studio and vos.so play.\n */\nexport async function loadProgramDirectory(\n dir: string,\n warnings: string[],\n): Promise<unknown> {\n const config: unknown = JSON.parse(\n await readFile(join(dir, 'config.json'), 'utf8'),\n )\n const docPath = join(dir, 'doc.json')\n if (!existsSync(docPath)) return config\n const doc: unknown = JSON.parse(await readFile(docPath, 'utf8'))\n if (typeof doc !== 'object' || doc === null || 'source' in doc) return config\n if (typeof config !== 'object' || config === null) {\n throw new UsageError(`${dir}/config.json does not contain a JSON object`)\n }\n const raw = doc as Record<string, unknown>\n const program =\n raw.program && typeof raw.program === 'object'\n ? (raw.program as Record<string, unknown>)\n : {}\n const { lowerProgramDoc } = await import('@vosjs/studio-core')\n const composed = lowerProgramDoc(\n { ...raw, program: { ...program, config } } as never,\n { bake: true },\n ).config\n warnings.push(\n 'composed config.json with doc.json (a program document: its layers and tween edits ride the render)',\n )\n return composed\n}\n\n/**\n * The text of a config source: an http(s) URL or a file. A directory that is\n * neither a take nor a program directory is refused in words, since the raw\n * read would report a bare EISDIR.\n */\nexport async function readSourceText(source: string): Promise<string> {\n if (/^https?:\\/\\//.test(source)) {\n const res = await fetch(source)\n if (!res.ok) throw new Error(`fetch ${source} → ${res.status}`)\n return await res.text()\n }\n let isDir = false\n try {\n isDir = statSync(source).isDirectory()\n } catch {\n /* a missing path reads below and reports itself */\n }\n if (isDir) {\n throw new UsageError(\n `${source} is a directory with no config.json and no doc.json — pass a config file, a URL, a program directory or a take`,\n )\n }\n return await readFile(source, 'utf8')\n}\n\n/**\n * Load a VosConfigJson from a file path, an http(s) URL, or a program\n * directory (config.json, composed with a program document when one sits\n * beside it); unwrap API `{ config }` envelopes, migrate old versions, and\n * validate against the schema. A take directory is refused here in words:\n * takes render through the take pipeline (`vos render <take>`).\n */\nexport async function loadVosConfig(source: string): Promise<LoadedConfig> {\n const warnings: string[] = []\n let parsed: unknown\n const kind = /^https?:\\/\\//.test(source) ? 'none' : directoryKind(source)\n if (kind === 'take') {\n throw new UsageError(\n `${source} is a take (its doc.json is a recording document). Render it through the take pipeline: vos render ${source} [out]; vos frames ${source} for stills.`,\n )\n }\n if (kind === 'program') {\n parsed = await loadProgramDirectory(source, warnings)\n return finish(source, parsed, warnings)\n }\n // A program's config.json named directly, with its document beside it:\n // read the directory, or the document's sound and layers silently drop\n // out of a render that looks complete.\n if (\n !/^https?:\\/\\//.test(source) &&\n basename(source) === 'config.json' &&\n hasProgramDoc(dirname(source))\n ) {\n parsed = await loadProgramDirectory(dirname(source), warnings)\n return finish(source, parsed, warnings)\n }\n const raw = await readSourceText(source)\n\n try {\n parsed = JSON.parse(raw)\n } catch (e) {\n throw new UsageError(`${source} is not valid JSON: ${(e as Error).message}`)\n }\n return finish(source, parsed, warnings)\n}\n\nfunction finish(\n source: string,\n parsed: unknown,\n warnings: string[],\n): LoadedConfig {\n if (typeof parsed !== 'object' || parsed === null) {\n throw new UsageError(`${source} does not contain a JSON object`)\n }\n\n // API endpoints wrap the config: { config: {...} }.\n let obj = parsed as Record<string, unknown>\n if (\n typeof obj.config === 'object' &&\n obj.config !== null &&\n !('createTimeline' in obj)\n ) {\n obj = obj.config as Record<string, unknown>\n warnings.push('unwrapped { config } envelope')\n }\n\n const version = obj.version\n const migrated = migrateConfig(obj)\n if (version === undefined) {\n // Plays fine (the stamp happens above), but a storer refuses it.\n warnings.push(\n `config declares no \"version\". Add \"version\": ${CURRENT_CONFIG_VERSION} before pushing it.`,\n )\n } else if (version !== CURRENT_CONFIG_VERSION) {\n warnings.push(\n `migrated config v${String(version)} to v${CURRENT_CONFIG_VERSION}`,\n )\n }\n\n const check = vosConfigJsonSchema.safeParse(migrated)\n if (!check.success) {\n const issues = check.error.issues\n .slice(0, 5)\n .map((i) => ` ${i.path.join('.') || '(root)'}: ${i.message}`)\n .join('\\n')\n throw new UsageError(`invalid vos config:\\n${issues}`)\n }\n\n return { config: migrated, warnings }\n}\n\n/** Best-effort duration from the config (seconds). */\nexport function configDuration(\n config: Record<string, unknown>,\n): number | undefined {\n const d = config.duration\n return typeof d === 'number' && Number.isFinite(d) && d > 0 ? d : undefined\n}\n","import { chromium } from 'playwright'\nimport type { Browser } from 'playwright'\n\nexport class BrowserUnavailableError extends Error {\n constructor(cause: string) {\n super(\n `Could not launch a Chromium-family browser (${cause}).\\n` +\n `Fixes, in order of preference:\\n` +\n ` 1. Install Google Chrome (used automatically), or\\n` +\n ` 2. npx playwright install chromium, or\\n` +\n ` 3. Set VOS_BROWSER_PATH to a Chrome/Chromium executable.`,\n )\n }\n}\n\n/**\n * Launch headless Chromium: explicit VOS_BROWSER_PATH → system Chrome\n * (no download needed) → Playwright's bundled Chromium.\n *\n * `args` are extra Chromium switches (`--browser-arg` on the verbs that\n * record). Some product surfaces cannot be reached without one: a recorder\n * needs a fake capture device to get past a permission prompt, an extension\n * page needs the extension loaded. Passed through verbatim.\n */\nexport async function launchBrowser(args: string[] = []): Promise<Browser> {\n const opts = args.length ? { args } : {}\n const explicit = process.env.VOS_BROWSER_PATH\n if (explicit) {\n return chromium.launch({ ...opts, executablePath: explicit }).catch((e) => {\n throw new BrowserUnavailableError(\n `VOS_BROWSER_PATH failed: ${(e as Error).message}`,\n )\n })\n }\n try {\n return await chromium.launch({ ...opts, channel: 'chrome' })\n } catch {\n try {\n return await chromium.launch(opts)\n } catch (e) {\n throw new BrowserUnavailableError(\n (e as Error).message.split('\\n')[0] ?? 'unknown',\n )\n }\n }\n}\n","import { compileVosConfig, programSize } from '@vosjs/core'\nimport { generateRenderTemplate } from '@vosjs/core/runtime'\nimport { elementsBundleCode } from '@vosjs/elements/bundle'\nimport { tweenRuntimeCode } from '@vosjs/tween/bundle'\nimport type { Browser, Page } from 'playwright'\nimport { ASSET_ROUTE, serveFile } from './programAssets'\nimport type { ProgramAssets } from './programAssets'\n\n/** Fake secure origin the render page is served from (WebCodecs needs one). */\nconst RENDER_ORIGIN = 'https://vos-cli.render'\n\nexport interface RenderCommonOptions {\n config: Record<string, unknown>\n width: number\n height: number\n /** Phase callback for progress reporting. */\n onPhase?: (phase: string) => void\n /**\n * The program's declared files made reachable for this page\n * (`programAssets`): handed to the engine as `ctx.assets`, with the local\n * ones served from disk on the page's own origin.\n */\n assets?: ProgramAssets | null\n}\n\nexport interface RenderVideoOptions extends RenderCommonOptions {\n fps: number\n /** Output duration in seconds. */\n duration: number\n format: 'webm' | 'mp4'\n /** The page's audio producer (a program document's sound); absent = silent. */\n audioProducerCode?: string\n}\n\nexport interface RenderStillOptions extends RenderCommonOptions {\n /** Seek time for the captured frame, seconds. */\n time: number\n}\n\nexport interface RenderResult {\n bytes: Uint8Array\n mimeType: string\n /** Uncaught exceptions the page threw while it rendered (it may still have\n * written a frame, so a caller says them instead of hiding them). */\n pageErrors: string[]\n /** The engine's own '[vos] …' warnings: causes a picture cannot show. */\n engineNotes: string[]\n}\n\ninterface RenderComplete {\n success: boolean\n data?: string\n error?: string\n}\n\n/** What a captured still shows, measured from its pixels. */\nexport interface StillPicture {\n /** Every pixel has alpha 0: the frame is empty, whatever the preview showed. */\n transparent: boolean\n /** Every pixel is the same colour. */\n flat: boolean\n}\n\n/**\n * The sentences a still earns before anyone looks at it (pure). A fully\n * transparent frame is the one a custom blend or a cleared alpha leaves, and\n * it reads as black in most viewers while the live preview draws over its\n * page: say so, because nothing else will.\n */\nexport function stillWarnings(\n picture: StillPicture,\n pageErrors: readonly string[],\n engineNotes: readonly string[] = [],\n): string[] {\n const out: string[] = []\n if (picture.transparent) {\n out.push(\n 'the still is fully transparent (every pixel has alpha 0), though the preview may draw it: something wrote alpha 0, most often a custom material blending (blendDst / blendEquation) or a scene with no background. Give the scene a background or keep the destination alpha in the blend.',\n )\n } else if (picture.flat) {\n out.push(\n 'the still is a single flat colour: nothing drew at this time, or everything is hidden; check the time and the program for errors.',\n )\n }\n // The engine's own notes ('[vos] …') name a cause the picture cannot.\n for (const n of new Set(engineNotes)) out.push(n.replace(/^\\[vos\\]\\s*/, ''))\n for (const e of pageErrors.slice(0, 3)) out.push(`the page threw: ${e}`)\n if (pageErrors.length > 3)\n out.push(`the page threw ${pageErrors.length - 3} more errors`)\n return out\n}\n\nfunction compile(\n config: Record<string, unknown>,\n /** Bake these URLs as the program's `ctx.assets` defaults (a preview). */\n assets?: ProgramAssets | null,\n): string {\n if (!assets) return compileVosConfig(config as never, { tweenEngine: 'vos' })\n // The compiler asks per ref; the resolved table is per name, so walk the\n // manifest in the same order to answer.\n const byRef = new Map<string, string>()\n const manifest = (config.assets ?? {}) as Record<\n string,\n { ref: string | string[] }\n >\n for (const [name, decl] of Object.entries(manifest)) {\n const got = assets.assets[name]\n const refs = Array.isArray(decl.ref) ? decl.ref : [decl.ref]\n const urls = Array.isArray(got) ? got : [got]\n refs.forEach((ref, i) => {\n if (typeof urls[i] === 'string') byRef.set(`${name}\\u0000${ref}`, urls[i])\n })\n }\n return compileVosConfig(config as never, {\n tweenEngine: 'vos',\n resolveAssetRef: (ref, name) => byRef.get(`${name}\\u0000${ref}`) ?? ref,\n })\n}\n\n/** A page on the render origin reads a served file by its full URL. */\nfunction captureAssets(assets: ProgramAssets | null | undefined): {\n assets?: Record<string, string | string[]>\n} {\n if (!assets) return {}\n const absolute = (url: string) =>\n url.startsWith(ASSET_ROUTE) ? `${RENDER_ORIGIN}${url}` : url\n const out: Record<string, string | string[]> = {}\n for (const [name, url] of Object.entries(assets.assets)) {\n out[name] = Array.isArray(url) ? url.map(absolute) : absolute(url)\n }\n return { assets: out }\n}\n\nasync function runCapturePage(\n browser: Browser,\n html: string,\n opts: {\n width: number\n height: number\n timeoutMs: number\n /** Served path → file on disk (a program's declared files). */\n files?: Record<string, string>\n },\n): Promise<RenderComplete & { pageErrors: string[]; engineNotes: string[] }> {\n const context = await browser.newContext({\n viewport: { width: opts.width, height: opts.height },\n })\n const page: Page = await context.newPage()\n const errors: string[] = []\n const pageErrors: string[] = []\n const engineNotes: string[] = []\n page.on('console', (m) => {\n if (m.type() === 'error') errors.push(m.text())\n else if (m.type() === 'warning' && m.text().startsWith('[vos] '))\n engineNotes.push(m.text())\n })\n page.on('pageerror', (e) => {\n pageErrors.push(String(e.message || e))\n })\n try {\n await page.route(`${RENDER_ORIGIN}/**`, (route) =>\n route.fulfill({ status: 200, contentType: 'text/html', body: html }),\n )\n // The program's own files, on the page's origin. Registered after the\n // page route on purpose: the newest matching route answers first.\n const files = opts.files ?? {}\n if (Object.keys(files).length > 0) {\n await page.route(`${RENDER_ORIGIN}${ASSET_ROUTE}**`, async (route) => {\n const request = route.request()\n const file = files[new URL(request.url()).pathname]\n if (!file) {\n return route.fulfill({ status: 404, body: 'no such declared file' })\n }\n const answer = serveFile(file, await request.headerValue('range'))\n return route.fulfill(answer)\n })\n }\n await page.goto(`${RENDER_ORIGIN}/render`, {\n waitUntil: 'domcontentloaded',\n })\n const start = Date.now()\n for (;;) {\n const done = (await page.evaluate(\n 'window.__renderComplete ?? null',\n )) as RenderComplete | null\n if (done) return { ...done, pageErrors, engineNotes }\n if (Date.now() - start > opts.timeoutMs) {\n const all = [...pageErrors, ...errors]\n return {\n success: false,\n error: `render timed out after ${Math.round(opts.timeoutMs / 1000)}s${\n all.length ? ` (page errors: ${all.slice(0, 3).join(' | ')})` : ''\n }`,\n pageErrors,\n engineNotes,\n }\n }\n await new Promise((r) => setTimeout(r, 400))\n }\n } finally {\n await context.close()\n }\n}\n\nfunction decodeDataUrl(\n dataUrl: string,\n pageErrors: string[] = [],\n engineNotes: string[] = [],\n): RenderResult {\n const m = /^data:([^;,]+);base64,(.*)$/s.exec(dataUrl)\n if (!m) throw new Error('capture page returned an unexpected payload')\n return {\n bytes: Uint8Array.from(Buffer.from(m[2], 'base64')),\n mimeType: m[1],\n pageErrors,\n engineNotes,\n }\n}\n\n/** Render a vos config to a video (WebM/MP4) in a headless browser. */\nexport async function renderVideo(\n browser: Browser,\n opts: RenderVideoOptions,\n): Promise<RenderResult> {\n opts.onPhase?.('compile')\n const code = compile(opts.config)\n const html = generateRenderTemplate(code, {\n mode: 'capture-video',\n capture: {\n width: opts.width,\n height: opts.height,\n duration: opts.duration,\n fps: opts.fps,\n format: opts.format,\n ...(opts.audioProducerCode\n ? { audioProducerCode: opts.audioProducerCode }\n : {}),\n ...captureAssets(opts.assets),\n },\n elementsBundleCode,\n tweenEngine: 'vos',\n tweenBundleCode: tweenRuntimeCode,\n })\n opts.onPhase?.('render')\n // Generous ceiling: startup + CDN module fetch + ~4× realtime per frame batch.\n const timeoutMs = 90_000 + opts.duration * opts.fps * 400\n const done = await runCapturePage(browser, html, {\n width: opts.width,\n height: opts.height,\n timeoutMs,\n files: opts.assets?.files,\n })\n if (!done.success || !done.data)\n throw new Error(done.error ?? 'render failed')\n return decodeDataUrl(done.data, done.pageErrors, done.engineNotes)\n}\n\n/** Render a single frame of a vos config to an image in a headless browser. */\nexport async function renderStill(\n browser: Browser,\n opts: RenderStillOptions,\n): Promise<RenderResult> {\n opts.onPhase?.('compile')\n const code = compile(opts.config)\n const html = generateRenderTemplate(code, {\n mode: 'capture-thumbnail',\n capture: {\n width: opts.width,\n height: opts.height,\n duration: Math.max(1, opts.time + 1),\n fps: 30,\n thumbnailTime: opts.time,\n ...captureAssets(opts.assets),\n },\n elementsBundleCode,\n tweenEngine: 'vos',\n tweenBundleCode: tweenRuntimeCode,\n })\n opts.onPhase?.('render')\n const done = await runCapturePage(browser, html, {\n width: opts.width,\n height: opts.height,\n timeoutMs: 120_000,\n files: opts.assets?.files,\n })\n if (!done.success || !done.data)\n throw new Error(done.error ?? 'still render failed')\n return decodeDataUrl(done.data, done.pageErrors, done.engineNotes)\n}\n\n/**\n * Measure a captured still's pixels in a browser page (the canvas is the\n * decoder): whether every pixel is transparent, and whether it is one flat\n * colour. Sampled on a grid, so a large still stays cheap.\n */\nexport async function inspectStill(\n browser: Browser,\n webp: Uint8Array,\n): Promise<StillPicture> {\n const page = await browser.newPage()\n try {\n const src = `data:image/webp;base64,${Buffer.from(webp).toString('base64')}`\n return (await page.evaluate(\n `(async () => {\n const img = new Image()\n img.src = ${JSON.stringify(src)}\n await img.decode()\n const w = img.naturalWidth, h = img.naturalHeight\n const c = document.createElement('canvas')\n c.width = w\n c.height = h\n const g = c.getContext('2d', { willReadFrequently: true })\n g.drawImage(img, 0, 0)\n const d = g.getImageData(0, 0, w, h).data\n const step = Math.max(1, Math.floor(Math.sqrt((w * h) / 40000)))\n let transparent = true, flat = true, first = null\n for (let y = 0; y < h; y += step) {\n for (let x = 0; x < w; x += step) {\n const i = (y * w + x) * 4\n if (d[i + 3] !== 0) transparent = false\n const px = d[i] + ',' + d[i + 1] + ',' + d[i + 2] + ',' + d[i + 3]\n if (first === null) first = px\n else if (px !== first) flat = false\n }\n }\n return { transparent, flat }\n })()`,\n )) as StillPicture\n } finally {\n await page.close()\n }\n}\n\n/**\n * Re-encode a captured WebP still as PNG or JPEG in a browser page, so a\n * still named `.png` holds PNG bytes. The canvas is the encoder; nothing\n * else is installed for it.\n */\nexport async function reencodeStill(\n browser: Browser,\n webp: Uint8Array,\n format: 'png' | 'jpeg',\n): Promise<Uint8Array> {\n const page = await browser.newPage()\n try {\n const src = `data:image/webp;base64,${Buffer.from(webp).toString('base64')}`\n // A string body: a serialized function would carry the bundler's\n // helpers into a page that has none.\n const dataUrl = (await page.evaluate(\n `(async () => {\n const img = new Image()\n img.src = ${JSON.stringify(src)}\n await img.decode()\n const c = document.createElement('canvas')\n c.width = img.naturalWidth\n c.height = img.naturalHeight\n const g = c.getContext('2d')\n ${format === 'jpeg' ? \"g.fillStyle = '#fff'; g.fillRect(0, 0, c.width, c.height)\" : ''}\n g.drawImage(img, 0, 0)\n return c.toDataURL(${JSON.stringify(`image/${format}`)}, 0.92)\n })()`,\n )) as string\n return decodeDataUrl(dataUrl).bytes\n } finally {\n await page.close()\n }\n}\n\nexport interface PreviewPages {\n /** Host page: iframes the player and drives it over the bridge. */\n hostHtml: string\n /** The engine's playback-mode player (waits for a LOAD postMessage). */\n playerHtml: string\n}\n\n/**\n * Pages for `vos preview`. The playback template is the iframe HALF of the\n * player bridge — it renders nothing until a host posts `LOAD`, so the CLI\n * serves a minimal host page that sends `LOAD { code, autoplay }` and shows\n * a transport line (time / duration, click to play-pause).\n */\nexport function previewPages(\n config: Record<string, unknown>,\n /** Declared files, served by the preview server under `ASSET_ROUTE`. */\n assets?: ProgramAssets | null,\n): PreviewPages {\n const code = compile(config, assets)\n const playerHtml = generateRenderTemplate(code, {\n mode: 'playback',\n elementsBundleCode,\n tweenEngine: 'vos',\n tweenBundleCode: tweenRuntimeCode,\n })\n const codeJson = JSON.stringify(code).replace(/<\\//g, '<\\\\/')\n // A program that declares its size plays letterboxed at that aspect, the\n // frame it was designed for; one that declares none fills the window.\n const size = programSize(config)\n const frameCss = size\n ? `iframe{position:absolute;inset:0;margin:auto;border:0;width:min(100vw,calc(100vh * ${size.width} / ${size.height}));height:min(100vh,calc(100vw * ${size.height} / ${size.width}))}`\n : 'iframe{position:absolute;inset:0;width:100%;height:100%;border:0}'\n const hostHtml = `<!doctype html><html><head><meta charset=\"utf-8\"><title>vos preview</title>\n<style>\n html,body{margin:0;height:100%;background:#000;overflow:hidden}\n ${frameCss}\n #cover{position:fixed;inset:0;cursor:pointer}\n #hud{position:fixed;left:12px;bottom:10px;color:#fff;opacity:.75;font:12px/1.4 ui-monospace,monospace;\n background:rgba(0,0,0,.45);padding:4px 8px;border-radius:6px;pointer-events:none}\n</style></head><body>\n<iframe id=\"p\" src=\"/player\" allow=\"autoplay\"></iframe>\n<div id=\"cover\"></div>\n<div id=\"hud\">loading…</div>\n<script>\n const code = ${codeJson}\n const frame = document.getElementById('p')\n const hud = document.getElementById('hud')\n let ready = false\n let playing = true\n const post = (msg) => frame.contentWindow && frame.contentWindow.postMessage(msg, '*')\n const load = () => post({ type: 'LOAD', code, autoplay: true })\n window.addEventListener('message', (e) => {\n const msg = e.data || {}\n if (msg.type === 'BRIDGE_READY') load()\n if (msg.type === 'READY') { ready = true; hud.textContent = '0.0 / ' + msg.duration.toFixed(1) + 's — click to pause' }\n if (msg.type === 'UPDATE') hud.textContent = msg.time.toFixed(1) + ' / ' + msg.duration.toFixed(1) + 's — click to ' + (playing ? 'pause' : 'play')\n if (msg.type === 'ERROR') hud.textContent = 'error: ' + msg.error\n })\n // Belt and braces: if BRIDGE_READY raced the host, retry LOAD until READY.\n let tries = 0\n const iv = setInterval(() => {\n if (ready || tries++ > 20) return clearInterval(iv)\n load()\n }, 400)\n // The iframe swallows clicks — capture them on an overlay above it.\n document.getElementById('cover').addEventListener('click', () => {\n if (!ready) return\n playing = !playing\n post({ type: playing ? 'PLAY' : 'PAUSE' })\n hud.textContent = hud.textContent.replace(/click to (pause|play)/, 'click to ' + (playing ? 'pause' : 'play'))\n })\n</script></body></html>`\n return { hostHtml, playerHtml }\n}\n","/**\n * What the output is, decided from what the person asked for.\n *\n * Pure, so the engine verbs (a program) and the take verbs agree: a file\n * named `out.mp4` IS an mp4, an explicit `--format` that contradicts the\n * name is refused instead of writing one container under the other's name,\n * and a still named `.png` is a PNG.\n */\nimport { UsageError } from './args'\n\nexport type VideoFormat = 'webm' | 'mp4'\nexport type StillFormat = 'webp' | 'png' | 'jpeg'\n\nfunction extOf(path: string | undefined): string {\n return /\\.([a-z0-9]+)$/i.exec(path ?? '')?.[1]?.toLowerCase() ?? ''\n}\n\n/** The video container: the flag, else the output's name, else WebM. */\nexport function videoFormat(\n flag: string | undefined,\n out: string | undefined,\n): VideoFormat {\n const named = extOf(out)\n const fromName: VideoFormat | null =\n named === 'mp4' ? 'mp4' : named === 'webm' ? 'webm' : null\n if (flag !== undefined) {\n if (flag !== 'webm' && flag !== 'mp4')\n throw new UsageError('--format must be webm or mp4')\n if (fromName && fromName !== flag)\n throw new UsageError(\n `--format ${flag} contradicts the output name ${out}: name it .${flag}, or drop --format and the name decides`,\n )\n return flag\n }\n return fromName ?? 'webm'\n}\n\n/** The still's encoding, from its name. The engine captures WebP. */\nexport function stillFormat(out: string): StillFormat {\n const ext = extOf(out)\n if (ext === 'png') return 'png'\n if (ext === 'jpg' || ext === 'jpeg') return 'jpeg'\n if (ext === 'webp' || ext === '') return 'webp'\n throw new UsageError(\n `vos still writes .webp, .png or .jpg, not .${ext}: rename ${out}`,\n )\n}\n\n/**\n * `--times 0,1.5,50%,100%`: seconds or percentages of the duration, in the\n * order given. 100% is clamped a hair inside the end, where the last frame is.\n */\nexport function parseTimes(raw: string, duration: number): number[] {\n const times = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n .map((s) => {\n const pct = /^(\\d+(?:\\.\\d+)?)%$/.exec(s)\n const t = pct ? (Number(pct[1]) / 100) * duration : Number(s)\n if (!Number.isFinite(t) || t < 0)\n throw new UsageError(\n `--times expects seconds or percentages (0,1.5,50%), got \"${s}\"`,\n )\n return Math.min(t, Math.max(0, duration - 1 / 60))\n })\n if (!times.length) throw new UsageError('--times needs at least one time')\n return times\n}\n\n/** Where the still for one time of several goes: `name-1.50s.ext`. */\nexport function stillOutFor(out: string, time: number, many: boolean): string {\n if (!many) return out\n const m = /^(.*?)(\\.[a-z0-9]+)?$/i.exec(out)\n return `${m?.[1] ?? out}-${time.toFixed(2)}s${m?.[2] ?? ''}`\n}\n\n/** Every `--set` value in argv, in order (the parser keeps only the last). */\nexport function setFlags(argv: string[]): string[] {\n const out: string[] = []\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]\n if (a === '--set' && argv[i + 1] !== undefined) out.push(argv[++i])\n else if (a.startsWith('--set=')) out.push(a.slice('--set='.length))\n }\n return out\n}\n\n/**\n * `--set data.<key>=<value>` on a PROGRAM: the knob-honesty check without a\n * second config. The value reads as JSON when it parses (numbers, booleans,\n * arrays) and as a string otherwise. Patched in memory, never written back.\n */\nexport function applyDataSets(\n config: Record<string, unknown>,\n sets: string[],\n): Record<string, unknown> {\n if (!sets.length) return config\n const data: Record<string, unknown> = {\n ...((config.data as Record<string, unknown> | undefined) ?? {}),\n }\n for (const set of sets) {\n const eq = set.indexOf('=')\n const path = eq === -1 ? set : set.slice(0, eq)\n const m = /^data\\.([A-Za-z0-9_$-]+)$/.exec(path)\n if (eq === -1 || !m)\n throw new UsageError(\n `--set on a program takes data.<key>=<value> (a knob's value), got \"${set}\"`,\n )\n const raw = set.slice(eq + 1)\n let value: unknown = raw\n try {\n value = JSON.parse(raw)\n } catch {\n // a bare word is a string: --set data.name=ROBIN\n }\n data[m[1]] = value\n }\n return { ...config, data }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
reencodeStill,
|
|
10
10
|
renderStill,
|
|
11
11
|
videoFormat
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LWHVZ5WI.js";
|
|
13
13
|
import {
|
|
14
14
|
PREV_DOC_NAME,
|
|
15
15
|
RECORDING_NAME,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
uploadDocRefs,
|
|
35
35
|
uploadManifest,
|
|
36
36
|
writeJson
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-YMVRTZ4L.js";
|
|
38
38
|
import {
|
|
39
39
|
CREDENTIALS_PATH,
|
|
40
40
|
MEDIA_HEAD_BYTES,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
strFlag,
|
|
65
65
|
writeCredential,
|
|
66
66
|
writeSyncState
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-WCF6KIOK.js";
|
|
68
68
|
import {
|
|
69
69
|
deadLine,
|
|
70
70
|
deadWarns
|
|
@@ -7752,7 +7752,7 @@ async function cmdFetch(argv) {
|
|
|
7752
7752
|
const configPath = join15(out, "config.json");
|
|
7753
7753
|
const written = JSON.parse(await readFile13(configPath, "utf8"));
|
|
7754
7754
|
const hostedCount = manifestRefs(written).filter(
|
|
7755
|
-
({ ref }) => hostedAssetId(ref)
|
|
7755
|
+
({ ref }) => hostedAssetId(ref, [origin, "https://vos.so", "https://www.vos.so"])
|
|
7756
7756
|
).length;
|
|
7757
7757
|
if (hostedCount && flags.media === true) {
|
|
7758
7758
|
const pulled = await pullManifest({ origin, key }, out, written, r.log);
|
|
@@ -9045,7 +9045,7 @@ async function cmdCompare(argv) {
|
|
|
9045
9045
|
const config = loaded.config;
|
|
9046
9046
|
const duration = configDuration(config) ?? 5;
|
|
9047
9047
|
const assets = await programAssets(config, {
|
|
9048
|
-
baseDir: existsSync15(source) && statSync4(source).isDirectory() ? source : dirname5(source),
|
|
9048
|
+
baseDir: /^https?:\/\//.test(source) ? null : existsSync15(source) && statSync4(source).isDirectory() ? source : dirname5(source),
|
|
9049
9049
|
origin: platformOrigin({}),
|
|
9050
9050
|
key: resolveCredential(),
|
|
9051
9051
|
log: (line) => r.log(line)
|
|
@@ -14643,4 +14643,4 @@ export {
|
|
|
14643
14643
|
verbHelp,
|
|
14644
14644
|
run
|
|
14645
14645
|
};
|
|
14646
|
-
//# sourceMappingURL=chunk-
|
|
14646
|
+
//# sourceMappingURL=chunk-QL25OPZB.js.map
|