@pixerate/flair 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +52 -10
  3. package/dist/catalog/index.d.ts +11 -6
  4. package/dist/catalog/index.js +1 -1
  5. package/dist/{chunk-DBNSI4MF.js → chunk-6GFOLHCT.js} +952 -35
  6. package/dist/chunk-6GFOLHCT.js.map +1 -0
  7. package/dist/{chunk-JL6TI6II.js → chunk-7KYQ4R76.js} +2 -2
  8. package/dist/chunk-7KYQ4R76.js.map +1 -0
  9. package/dist/{chunk-STKEKXCK.js → chunk-AUH3PEFW.js} +2 -2
  10. package/dist/{chunk-PFGGPIMT.js → chunk-DA4UUSDO.js} +58 -3
  11. package/dist/chunk-DA4UUSDO.js.map +1 -0
  12. package/dist/{chunk-RDU63CDO.js → chunk-HDYBY3PQ.js} +380 -1
  13. package/dist/chunk-HDYBY3PQ.js.map +1 -0
  14. package/dist/{chunk-FJ5ZJGOL.js → chunk-KZYZX3V5.js} +260 -33
  15. package/dist/chunk-KZYZX3V5.js.map +1 -0
  16. package/dist/{chunk-PFUTUR7T.js → chunk-MBKNTXQX.js} +9 -9
  17. package/dist/chunk-MBKNTXQX.js.map +1 -0
  18. package/dist/{chunk-H6VDFBIO.js → chunk-SMR2MJXB.js} +156 -5
  19. package/dist/chunk-SMR2MJXB.js.map +1 -0
  20. package/dist/{chunk-YBGRXVAE.js → chunk-X3C2VFTM.js} +3 -3
  21. package/dist/{chunk-CK6EV37I.js → chunk-ZULFHADW.js} +69 -6
  22. package/dist/chunk-ZULFHADW.js.map +1 -0
  23. package/dist/cli.js +6 -6
  24. package/dist/editor/index.d.ts +3 -3
  25. package/dist/editor/index.js +3 -3
  26. package/dist/{effect-M5T4ICIP.js → effect-YBWDNIYG.js} +10 -10
  27. package/dist/embed/index.d.ts +36 -8
  28. package/dist/embed/index.js +5 -5
  29. package/dist/{frames-VEcqa40g.d.ts → frames-CGJudAbu.d.ts} +11 -1
  30. package/dist/index.d.ts +69 -6
  31. package/dist/index.js +35 -7
  32. package/dist/index.js.map +1 -1
  33. package/dist/node.d.ts +4 -4
  34. package/dist/node.js +9 -9
  35. package/dist/react/index.d.ts +4 -4
  36. package/dist/react/index.js +7 -7
  37. package/dist/react/index.js.map +1 -1
  38. package/dist/{recorder-CDPPTJMG.js → recorder-TYMEZHOT.js} +3 -3
  39. package/dist/{renderer-teaa98RE.d.ts → renderer-tk1nbVkW.d.ts} +252 -2
  40. package/dist/svelte/index.d.ts +4 -4
  41. package/dist/svelte/index.js +7 -7
  42. package/dist/svelte/index.js.map +1 -1
  43. package/dist/{svg-BhRboN9q.d.ts → svg-DaKRPA9v.d.ts} +39 -7
  44. package/dist/{types-DUOMxZaq.d.ts → types-wh28fXW4.d.ts} +2 -2
  45. package/dist/vector/index.d.ts +2 -2
  46. package/dist/vector/index.js +5 -3
  47. package/package.json +1 -1
  48. package/dist/chunk-CK6EV37I.js.map +0 -1
  49. package/dist/chunk-DBNSI4MF.js.map +0 -1
  50. package/dist/chunk-FJ5ZJGOL.js.map +0 -1
  51. package/dist/chunk-H6VDFBIO.js.map +0 -1
  52. package/dist/chunk-JL6TI6II.js.map +0 -1
  53. package/dist/chunk-PFGGPIMT.js.map +0 -1
  54. package/dist/chunk-PFUTUR7T.js.map +0 -1
  55. package/dist/chunk-RDU63CDO.js.map +0 -1
  56. /package/dist/{chunk-STKEKXCK.js.map → chunk-AUH3PEFW.js.map} +0 -0
  57. /package/dist/{chunk-YBGRXVAE.js.map → chunk-X3C2VFTM.js.map} +0 -0
  58. /package/dist/{effect-M5T4ICIP.js.map → effect-YBWDNIYG.js.map} +0 -0
  59. /package/dist/{recorder-CDPPTJMG.js.map → recorder-TYMEZHOT.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/export/mp4mux.ts","../src/export/webmmux.ts","../src/export/zip.ts","../src/embed/record.ts","../src/embed/index.ts"],"sourcesContent":["/**\n * A small MP4 (ISO BMFF) writer for one H.264 video track, with no\n * dependencies, for video encoded in the browser (WebCodecs' `VideoEncoder`\n * with `avc: { format: \"avc\" }`).\n *\n * The file is \"faststart\": `ftyp`, then `moov` (the index), then one `mdat`\n * holding every sample in a single chunk, so a page can start playing it\n * before it has all arrived. Samples are in presentation order (browser\n * encoders make no B-frames), so there is no `ctts`.\n */\n\n/** One encoded frame: its bytes (length-prefixed NAL units), when it shows, and whether it is a keyframe. */\nexport interface Mp4Sample {\n data: Uint8Array;\n /** Presentation time in microseconds (WebCodecs' `timestamp`). */\n timestamp: number;\n /** How long it shows, in microseconds (default: until the next sample, or the one before's). */\n duration?: number;\n key: boolean;\n}\n\nexport interface Mp4Options {\n width: number;\n height: number;\n /** The `avcC` record: the encoder's `decoderConfig.description`. */\n avcC: Uint8Array;\n samples: readonly Mp4Sample[];\n /** Ticks per second of the track's times (default 90000, as for broadcast video). */\n timescale?: number;\n}\n\nconst MOVIE_TIMESCALE = 1000;\nconst UINT32 = 0x1_0000_0000;\n\nconst ascii = (s: string) => Uint8Array.from(s, (c) => c.charCodeAt(0));\n\n/** Big-endian fields, written into a growing list of parts. */\nclass Writer {\n parts: Uint8Array[] = [];\n size = 0;\n bytes(b: Uint8Array) {\n this.parts.push(b);\n this.size += b.length;\n return this;\n }\n u8(n: number) {\n return this.bytes(Uint8Array.of(n & 0xff));\n }\n u16(n: number) {\n return this.bytes(Uint8Array.of((n >>> 8) & 0xff, n & 0xff));\n }\n u32(n: number) {\n const b = new Uint8Array(4);\n new DataView(b.buffer).setUint32(0, n >>> 0);\n return this.bytes(b);\n }\n u64(n: number) {\n return this.u32(Math.floor(n / UINT32)).u32(n % UINT32);\n }\n zeros(n: number) {\n return this.bytes(new Uint8Array(n));\n }\n done(): Uint8Array {\n const out = new Uint8Array(this.size);\n let at = 0;\n for (const p of this.parts) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n }\n}\n\n/** A box: size, type, then its fields and children. */\nfunction box(type: string, ...content: Uint8Array[]): Uint8Array {\n const w = new Writer();\n const size = 8 + content.reduce((n, c) => n + c.length, 0);\n w.u32(size).bytes(ascii(type));\n for (const c of content) w.bytes(c);\n return w.done();\n}\n\n/** A full box: a box whose fields start with a version and flags. */\nfunction fullBox(type: string, version: number, flags: number, ...content: Uint8Array[]): Uint8Array {\n return box(type, Uint8Array.of(version, (flags >> 16) & 0xff, (flags >> 8) & 0xff, flags & 0xff), ...content);\n}\n\nconst fields = (fill: (w: Writer) => unknown) => {\n const w = new Writer();\n fill(w);\n return w.done();\n};\n\n/** The identity transform, as `tkhd` and `mvhd` write it (16.16 and 2.30 fixed point). */\nconst MATRIX = fields((w) => [0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000].forEach((n) => w.u32(n)));\n\n/**\n * Each sample's duration in track ticks, from the gaps between timestamps\n * (the last keeps its own duration, or the gap before it).\n */\nfunction sampleTicks(samples: readonly Mp4Sample[], timescale: number): number[] {\n const tick = (us: number) => Math.round((us * timescale) / 1e6);\n return samples.map((s, i) => {\n const next = samples[i + 1];\n if (next) return Math.max(1, tick(next.timestamp) - tick(s.timestamp));\n if (s.duration) return Math.max(1, tick(s.duration));\n const prev = samples[i - 1];\n return prev ? Math.max(1, tick(s.timestamp) - tick(prev.timestamp)) : Math.max(1, tick(1e6 / 30));\n });\n}\n\n/** `stts`: the durations, run-length coded. */\nfunction stts(ticks: number[]): Uint8Array {\n const runs: [number, number][] = [];\n for (const t of ticks) {\n const last = runs[runs.length - 1];\n if (last && last[1] === t) last[0]++;\n else runs.push([1, t]);\n }\n return fullBox(\"stts\", 0, 0, fields((w) => {\n w.u32(runs.length);\n for (const [count, delta] of runs) w.u32(count).u32(delta);\n }));\n}\n\nfunction moov(options: Mp4Options, ticks: number[], dataOffset: number, wide: boolean): Uint8Array {\n const { width, height, avcC, samples } = options;\n const timescale = options.timescale ?? 90000;\n const trackTicks = ticks.reduce((a, b) => a + b, 0);\n const movieTicks = Math.round((trackTicks * MOVIE_TIMESCALE) / timescale);\n\n const mvhd = fullBox(\"mvhd\", 0, 0, fields((w) =>\n w.u32(0).u32(0).u32(MOVIE_TIMESCALE).u32(movieTicks)\n .u32(0x00010000).u16(0x0100).zeros(10) // rate 1.0, volume 1.0, reserved\n .bytes(MATRIX).zeros(24).u32(2), // pre_defined, next track id\n ));\n const tkhd = fullBox(\"tkhd\", 0, 3, fields((w) => // enabled, in the movie\n w.u32(0).u32(0).u32(1).u32(0).u32(movieTicks)\n .zeros(8).u16(0).u16(0).u16(0).u16(0) // reserved, layer, group, volume (none for video), reserved\n .bytes(MATRIX).u32(width * 0x10000).u32(height * 0x10000),\n ));\n const mdhd = fullBox(\"mdhd\", 0, 0, fields((w) => w.u32(0).u32(0).u32(timescale).u32(trackTicks).u16(0x55c4).u16(0))); // \"und\"\n const hdlr = fullBox(\"hdlr\", 0, 0, fields((w) => w.u32(0).bytes(ascii(\"vide\")).zeros(12).bytes(ascii(\"VideoHandler\\0\"))));\n const vmhd = fullBox(\"vmhd\", 0, 1, new Uint8Array(8));\n const dinf = box(\"dinf\", fullBox(\"dref\", 0, 0, fields((w) => w.u32(1)), fullBox(\"url \", 0, 1)));\n\n const avc1 = box(\n \"avc1\",\n fields((w) =>\n w.zeros(6).u16(1) // reserved, data reference index\n .zeros(16).u16(width).u16(height)\n .u32(0x00480000).u32(0x00480000).u32(0).u16(1) // 72 dpi, reserved, one frame per sample\n .zeros(32).u16(0x0018).u16(0xffff), // compressor name, depth, pre_defined\n ),\n box(\"avcC\", avcC),\n );\n const stsd = fullBox(\"stsd\", 0, 0, fields((w) => w.u32(1)), avc1);\n const keys = samples.flatMap((s, i) => (s.key ? [i + 1] : []));\n // Every sample a keyframe: leave stss out, which says so.\n const stss = keys.length === samples.length ? [] : [fullBox(\"stss\", 0, 0, fields((w) => {\n w.u32(keys.length);\n for (const k of keys) w.u32(k);\n }))];\n const stsz = fullBox(\"stsz\", 0, 0, fields((w) => {\n w.u32(0).u32(samples.length);\n for (const s of samples) w.u32(s.data.length);\n }));\n // One chunk with every sample, starting at the mdat's data.\n const stsc = fullBox(\"stsc\", 0, 0, fields((w) => (samples.length ? w.u32(1).u32(1).u32(samples.length).u32(1) : w.u32(0))));\n const stco = wide\n ? fullBox(\"co64\", 0, 0, fields((w) => w.u32(1).u64(dataOffset)))\n : fullBox(\"stco\", 0, 0, fields((w) => w.u32(1).u32(dataOffset)));\n const stbl = box(\"stbl\", stsd, stts(ticks), ...stss, stsz, stsc, stco);\n const minf = box(\"minf\", vmhd, dinf, stbl);\n const trak = box(\"trak\", tkhd, box(\"mdia\", mdhd, hdlr, minf));\n return box(\"moov\", mvhd, trak);\n}\n\n/**\n * An MP4 file of one H.264 track: `ftyp`, `moov`, then the samples in one\n * `mdat`. Throws when there are no samples or the first is not a keyframe.\n */\nexport function muxMp4(options: Mp4Options): Uint8Array {\n const { samples } = options;\n if (!samples.length) throw new Error(\"An MP4 needs at least one frame.\");\n if (!samples[0]!.key) throw new Error(\"An MP4's first frame must be a keyframe.\");\n const ftyp = box(\"ftyp\", ascii(\"isom\"), fields((w) => w.u32(0x200)), ascii(\"isomiso2avc1mp41\"));\n const ticks = sampleTicks(samples, options.timescale ?? 90000);\n const payload = samples.reduce((n, s) => n + s.data.length, 0);\n const large = payload + 8 >= UINT32;\n const mdatHeader = large ? 16 : 8;\n // The index's size does not depend on the offset it holds, so measure it once and write it again.\n const wide = ftyp.length + moov(options, ticks, 0, large).length + mdatHeader + payload >= UINT32;\n const index = moov(options, ticks, 0, wide);\n const dataOffset = ftyp.length + index.length + mdatHeader;\n const head = fields((w) => {\n w.bytes(ftyp).bytes(moov(options, ticks, dataOffset, wide));\n if (large) w.u32(1).bytes(ascii(\"mdat\")).u64(payload + 16);\n else w.u32(payload + 8).bytes(ascii(\"mdat\"));\n });\n const out = new Uint8Array(head.length + payload);\n out.set(head);\n let at = head.length;\n for (const s of samples) {\n out.set(s.data, at);\n at += s.data.length;\n }\n return out;\n}\n","/**\n * A small WebM (Matroska) writer for one VP8 or VP9 video track, with no\n * dependencies, for video encoded in the browser (WebCodecs' `VideoEncoder`).\n *\n * The file is an EBML header and one Segment of known size: `Info` (with the\n * duration), `Tracks`, then `Cluster`s of `SimpleBlock`s, a new cluster at\n * each keyframe. There are no `Cues`, so a player seeks by scanning, which\n * is quick for short clips. Frames with an alpha plane (VP9 or VP8 encoded\n * with `alpha: \"keep\"`) go in `BlockGroup`s with the alpha as a\n * `BlockAdditional` (id 1), and the track says `AlphaMode` 1, as Chrome's\n * own recordings do.\n */\n\n/** One encoded frame. */\nexport interface WebmFrame {\n data: Uint8Array;\n /** Presentation time in microseconds (WebCodecs' `timestamp`). */\n timestamp: number;\n key: boolean;\n /** The frame's alpha plane, encoded (WebCodecs' `metadata.alphaSideData`). */\n alpha?: Uint8Array;\n}\n\nexport interface WebmOptions {\n codec: \"vp8\" | \"vp9\";\n width: number;\n height: number;\n frames: readonly WebmFrame[];\n /** The length in microseconds (default: the last frame's time plus one frame). */\n duration?: number;\n /** Frames per second, written as the track's default frame duration. */\n fps?: number;\n /** `WritingApp` (default \"flair\"). */\n app?: string;\n}\n\n/** Element ids (their own leading-bits coding is part of the id). */\nconst ID = {\n EBML: 0x1a45dfa3,\n EBMLVersion: 0x4286,\n EBMLReadVersion: 0x42f7,\n EBMLMaxIDLength: 0x42f2,\n EBMLMaxSizeLength: 0x42f3,\n DocType: 0x4282,\n DocTypeVersion: 0x4287,\n DocTypeReadVersion: 0x4285,\n Segment: 0x18538067,\n Info: 0x1549a966,\n TimestampScale: 0x2ad7b1,\n Duration: 0x4489,\n MuxingApp: 0x4d80,\n WritingApp: 0x5741,\n Tracks: 0x1654ae6b,\n TrackEntry: 0xae,\n TrackNumber: 0xd7,\n TrackUID: 0x73c5,\n TrackType: 0x83,\n FlagLacing: 0x9c,\n CodecID: 0x86,\n DefaultDuration: 0x23e383,\n MaxBlockAdditionID: 0x55ee,\n Video: 0xe0,\n PixelWidth: 0xb0,\n PixelHeight: 0xba,\n AlphaMode: 0x53c0,\n Cluster: 0x1f43b675,\n Timestamp: 0xe7,\n SimpleBlock: 0xa3,\n BlockGroup: 0xa0,\n Block: 0xa1,\n ReferenceBlock: 0xfb,\n BlockAdditions: 0x75a1,\n BlockMore: 0xa6,\n BlockAddID: 0xee,\n BlockAdditional: 0xa5,\n} as const;\n\n/** Timestamps count milliseconds (TimestampScale 1 000 000 ns). */\nconst SCALE_NS = 1_000_000;\n/** A block's time is a signed 16-bit offset from its cluster's. */\nconst MAX_OFFSET = 32767;\n\nconst concat = (parts: readonly Uint8Array[]) => {\n const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));\n let at = 0;\n for (const p of parts) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n};\n\n/** An element id's bytes (ids already carry their length marker). */\nfunction idBytes(id: number): Uint8Array {\n const out: number[] = [];\n for (let n = id; n > 0; n = Math.floor(n / 256)) out.unshift(n & 0xff);\n return Uint8Array.from(out);\n}\n\n/** A size as an EBML variable-length integer, in the fewest bytes (1–8). */\nexport function vint(n: number): Uint8Array {\n for (let len = 1; len <= 8; len++) {\n // All ones is reserved for \"unknown size\".\n if (n < 2 ** (7 * len) - 1) {\n const out = new Uint8Array(len);\n let v = n;\n for (let i = len - 1; i >= 0; i--) {\n out[i] = v % 256;\n v = Math.floor(v / 256);\n }\n out[0]! |= 1 << (8 - len);\n return out;\n }\n }\n throw new RangeError(`An EBML size cannot be ${n}.`);\n}\n\nconst el = (id: number, ...content: Uint8Array[]) => {\n const body = concat(content);\n return concat([idBytes(id), vint(body.length), body]);\n};\n\nconst uint = (id: number, n: number) => {\n const out: number[] = [];\n for (let v = n; v > 0 || out.length === 0; v = Math.floor(v / 256)) out.unshift(v % 256);\n return el(id, Uint8Array.from(out));\n};\n\nconst float = (id: number, n: number) => {\n const b = new Uint8Array(8);\n new DataView(b.buffer).setFloat64(0, n);\n return el(id, b);\n};\n\nconst str = (id: number, s: string) => el(id, new TextEncoder().encode(s));\n\n/** A block's header: track 1, its time from the cluster's, its flags. */\nfunction blockHeader(offset: number, flags: number): Uint8Array {\n const b = new Uint8Array(4);\n b[0] = 0x81;\n new DataView(b.buffer).setInt16(1, offset);\n b[3] = flags;\n return b;\n}\n\n/**\n * A WebM file of one VP8 or VP9 track. Throws when there are no frames or\n * the first is not a keyframe.\n */\nexport function muxWebm(options: WebmOptions): Uint8Array {\n const { codec, width, height, frames, fps } = options;\n if (!frames.length) throw new Error(\"A WebM needs at least one frame.\");\n if (!frames[0]!.key) throw new Error(\"A WebM's first frame must be a keyframe.\");\n const alpha = frames.some((f) => f.alpha);\n const ms = (us: number) => Math.round(us / 1000);\n const last = frames[frames.length - 1]!;\n const frameUs = fps ? 1e6 / fps : frames.length > 1 ? (last.timestamp - frames[0]!.timestamp) / (frames.length - 1) : 1e6 / 30;\n const durationUs = options.duration ?? last.timestamp + frameUs;\n\n const header = el(\n ID.EBML,\n uint(ID.EBMLVersion, 1),\n uint(ID.EBMLReadVersion, 1),\n uint(ID.EBMLMaxIDLength, 4),\n uint(ID.EBMLMaxSizeLength, 8),\n str(ID.DocType, \"webm\"),\n // BlockAdditions came in version 4.\n uint(ID.DocTypeVersion, alpha ? 4 : 2),\n uint(ID.DocTypeReadVersion, 2),\n );\n const info = el(\n ID.Info,\n uint(ID.TimestampScale, SCALE_NS),\n float(ID.Duration, durationUs / 1000),\n str(ID.MuxingApp, \"flair\"),\n str(ID.WritingApp, options.app ?? \"flair\"),\n );\n const tracks = el(\n ID.Tracks,\n el(\n ID.TrackEntry,\n uint(ID.TrackNumber, 1),\n uint(ID.TrackUID, 1),\n uint(ID.TrackType, 1), // video\n uint(ID.FlagLacing, 0),\n str(ID.CodecID, codec === \"vp9\" ? \"V_VP9\" : \"V_VP8\"),\n ...(fps ? [uint(ID.DefaultDuration, Math.round(1e9 / fps))] : []),\n ...(alpha ? [uint(ID.MaxBlockAdditionID, 1)] : []),\n el(ID.Video, uint(ID.PixelWidth, width), uint(ID.PixelHeight, height), ...(alpha ? [uint(ID.AlphaMode, 1)] : [])),\n ),\n );\n\n const clusters: Uint8Array[] = [];\n let blocks: Uint8Array[] = [];\n let clusterMs = 0;\n let previousMs = 0;\n const close = () => {\n if (blocks.length) clusters.push(el(ID.Cluster, uint(ID.Timestamp, clusterMs), ...blocks));\n blocks = [];\n };\n frames.forEach((frame, i) => {\n const at = ms(frame.timestamp);\n if (i === 0 || frame.key || at - clusterMs > MAX_OFFSET) {\n close();\n clusterMs = at;\n }\n const offset = at - clusterMs;\n if (frame.alpha) {\n blocks.push(\n el(\n ID.BlockGroup,\n el(ID.Block, blockHeader(offset, 0), frame.data),\n el(ID.BlockAdditions, el(ID.BlockMore, uint(ID.BlockAddID, 1), el(ID.BlockAdditional, frame.alpha))),\n // A group without a reference is a keyframe; point delta frames at the one before.\n ...(frame.key ? [] : [el(ID.ReferenceBlock, signed(previousMs - at))]),\n ),\n );\n } else {\n blocks.push(el(ID.SimpleBlock, blockHeader(offset, frame.key ? 0x80 : 0), frame.data));\n }\n previousMs = at;\n });\n close();\n\n const segment = el(ID.Segment, info, tracks, ...clusters);\n return concat([header, segment]);\n}\n\n/** A signed integer's bytes, big-endian, in the fewest bytes (ReferenceBlock is signed). */\nfunction signed(n: number): Uint8Array {\n for (let len = 1; len <= 8; len++) {\n if (n >= -(2 ** (8 * len - 1)) && n < 2 ** (8 * len - 1)) {\n const out = new Uint8Array(len);\n let v = n < 0 ? 2 ** (8 * len) + n : n;\n for (let i = len - 1; i >= 0; i--) {\n out[i] = v % 256;\n v = Math.floor(v / 256);\n }\n return out;\n }\n }\n throw new RangeError(`${n} is out of range.`);\n}\n","/**\n * A store-only ZIP writer (no compression, no dependencies), for handing\n * over many already-compressed files at once: a PNG sequence, say.\n */\n\nexport interface ZipEntry {\n name: string;\n data: Uint8Array;\n}\n\nlet table: Uint32Array | undefined;\n\n/** CRC-32 (IEEE), as ZIP wants it. */\nexport function crc32(data: Uint8Array): number {\n table ??= Uint32Array.from({ length: 256 }, (_, n) => {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n return c >>> 0;\n });\n let crc = 0xffffffff;\n for (let i = 0; i < data.length; i++) crc = table[(crc ^ data[i]!) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n/** 1 January 1980, the earliest time a ZIP can hold, so the same frames make the same file. */\nconst DOS_DATE = (0 << 9) | (1 << 5) | 1;\n\n/**\n * A ZIP holding `entries` as they are (method 0, \"stored\"). Names are UTF-8.\n * Each file and the whole must stay under 4 GB (no ZIP64).\n */\nexport function zipStore(entries: readonly ZipEntry[]): Uint8Array {\n const encoder = new TextEncoder();\n const locals: Uint8Array[] = [];\n const centrals: Uint8Array[] = [];\n let offset = 0;\n for (const { name, data } of entries) {\n const nameBytes = encoder.encode(name);\n const crc = crc32(data);\n const local = new Uint8Array(30 + nameBytes.length);\n const l = new DataView(local.buffer);\n l.setUint32(0, 0x04034b50, true);\n l.setUint16(4, 20, true); // version needed: 2.0\n l.setUint16(6, 0x0800, true); // UTF-8 names\n l.setUint16(8, 0, true); // stored\n l.setUint16(10, 0, true); // time\n l.setUint16(12, DOS_DATE, true);\n l.setUint32(14, crc, true);\n l.setUint32(18, data.length, true);\n l.setUint32(22, data.length, true);\n l.setUint16(26, nameBytes.length, true);\n local.set(nameBytes, 30);\n\n const central = new Uint8Array(46 + nameBytes.length);\n const c = new DataView(central.buffer);\n c.setUint32(0, 0x02014b50, true);\n c.setUint16(4, 20, true); // made by\n c.setUint16(6, 20, true); // needed\n c.setUint16(8, 0x0800, true);\n c.setUint16(10, 0, true);\n c.setUint16(12, 0, true);\n c.setUint16(14, DOS_DATE, true);\n c.setUint32(16, crc, true);\n c.setUint32(20, data.length, true);\n c.setUint32(24, data.length, true);\n c.setUint16(28, nameBytes.length, true);\n c.setUint32(42, offset, true);\n central.set(nameBytes, 46);\n\n locals.push(local, data);\n centrals.push(central);\n offset += local.length + data.length;\n }\n const centralSize = centrals.reduce((n, c) => n + c.length, 0);\n const end = new Uint8Array(22);\n const e = new DataView(end.buffer);\n e.setUint32(0, 0x06054b50, true);\n e.setUint16(8, entries.length, true);\n e.setUint16(10, entries.length, true);\n e.setUint32(12, centralSize, true);\n e.setUint32(16, offset, true);\n\n const out = new Uint8Array(offset + centralSize + 22);\n let at = 0;\n for (const part of [...locals, ...centrals, end]) {\n out.set(part, at);\n at += part.length;\n }\n return out;\n}\n","// gifenc ships without types. The reference (not an import) brings them along when a host\n// type-checks these sources through the `workspace` condition.\n// eslint-disable-next-line @typescript-eslint/triple-slash-reference\n/// <reference path=\"../shader/gifenc.d.ts\" />\nimport { effectDefaults, getEffect, type EffectDefinition } from \"../catalog/index.js\";\nimport { renderVectorEffect } from \"../catalog/types.js\";\nimport { muxMp4 } from \"../export/mp4mux.js\";\nimport { muxWebm, type WebmFrame } from \"../export/webmmux.js\";\nimport { zipStore, type ZipEntry } from \"../export/zip.js\";\nimport { parseColor, type ControlValue } from \"../shader/controls.js\";\nimport { ShaderFrames, type RenderOptions } from \"../shader/frames.js\";\nimport { seekVideo, type LiveSource } from \"../shader/textures.js\";\nimport { svgDuration, svgView } from \"../vector/svg.js\";\nimport { subjectValues, type EffectSubject } from \"./index.js\";\n\n/** What {@link recordEffect} makes: a video (`mp4`, `webm`), an animated `gif`, or `png` frames in a ZIP. */\nexport type RecordFormat = \"mp4\" | \"webm\" | \"gif\" | \"png\";\n\n/** The pointer for one frame of a shader: `iPointer`, `iMouse`, and clicks and trail so far (times in seconds). */\nexport type RecordPointer = Pick<RenderOptions, \"pointer\" | \"mouse\" | \"clicks\" | \"trail\">;\n\nexport interface RecordOptions {\n /** What to apply the effect to (see {@link EffectSubject}); several fill several controls in order. */\n subject?: EffectSubject | readonly EffectSubject[];\n /** A preset by name, then these values, over the effect's defaults. */\n preset?: string;\n values?: Record<string, ControlValue>;\n /**\n * The file to make (default `mp4` where the browser encodes H.264, else\n * `webm`; `webm` when `alpha` is on).\n */\n format?: RecordFormat;\n /** Pixels (default 1280 × 720). Videos round them up to even numbers, as their encoders need. */\n width?: number;\n height?: number;\n /** Frames per second (default 30). GIF delays are whole hundredths of a second, so 10, 20, 25 and 50 play back exactly there. */\n fps?: number;\n /**\n * Seconds to record (default: a shader's `loop`, or a vector effect's\n * picture plus its `hold`, else 4).\n */\n duration?: number;\n /** The time of the first frame, in seconds (default 0). */\n start?: number;\n /** Bits per second for `mp4` and `webm` (default `width × height × fps × 0.15`). */\n bitrate?: number;\n /**\n * Keep transparency (default: the effect's `transparent`): `webm` (VP9\n * or VP8 with an alpha channel, which Chrome, Edge and Firefox play),\n * `png`, and `gif` (one see-through colour). `mp4` cannot, so it lays the\n * picture over `background` unless `alpha: true` was asked for. Without\n * it, transparent pixels are laid over `background`.\n */\n alpha?: boolean;\n /** A CSS colour under the picture when `alpha` is off (default black for shaders, white for vector effects). */\n background?: string;\n /**\n * The pointer, for shaders that answer it: the same every frame, or a\n * function of the frame's time in seconds. Without it, interactive\n * effects play their idle demos, as on a page nobody has touched.\n *\n * ```ts\n * pointer: { clicks: [{ x: 640, y: 360, time: 0.5 }] }\n * pointer: (t) => ({ pointer: [640 + 200 * Math.sin(t), 360, 1, 0] })\n * ```\n */\n pointer?: RecordPointer | ((time: number) => RecordPointer);\n /** A vector effect's step start times in ms, for pictures that change on steps (default none). */\n steps?: readonly number[];\n /**\n * Called before each frame is drawn, with its time in seconds: draw a\n * canvas subject for that time here. (A `<video>` subject is paused and\n * sought to each frame's time for you.)\n */\n beforeFrame?: (time: number, index: number) => void | Promise<void>;\n /** Called after each frame with the share done, 0–1. */\n onProgress?: (fraction: number) => void;\n /** Aborting rejects with an `AbortError` `DOMException`. */\n signal?: AbortSignal;\n}\n\n/** What a recording will be, worked out from the options before any frame is drawn (see {@link recordingPlan}). */\nexport interface RecordingPlan {\n effect: EffectDefinition;\n format: RecordFormat;\n width: number;\n height: number;\n fps: number;\n duration: number;\n start: number;\n frames: number;\n alpha: boolean;\n /** For `mp4` and `webm`: the encoder's settings. */\n encoder?: VideoEncoderConfig;\n}\n\nconst DEFAULT_SECONDS = 4;\n\n/** Lets the page repaint between frames so progress shows and Cancel works. */\nconst yieldToBrowser = () => new Promise<void>((resolve) => setTimeout(resolve, 0));\n\nconst formats = (list: RecordFormat[]) => list.map((f) => `\"${f}\"`).join(\", \").replace(/, ([^,]*)$/, \" or $1\");\n\n/** H.264 levels by the most macroblocks a frame and a second may hold, for the codec string. */\nconst AVC_LEVELS: [level: number, frame: number, second: number][] = [\n [0x1f, 3600, 108000], // 3.1\n [0x28, 8192, 245760], // 4.0\n [0x2a, 8704, 522240], // 4.2\n [0x32, 22080, 589824], // 5.0\n [0x33, 36864, 983040], // 5.1\n [0x34, 36864, 2073600], // 5.2\n [0x3c, 139264, 4177920], // 6.0\n];\n\n/** H.264 codec strings to try, High profile first, at the lowest level that holds the picture. */\nfunction avcCodecs(width: number, height: number, fps: number): string[] {\n const mbs = Math.ceil(width / 16) * Math.ceil(height / 16);\n const level = (AVC_LEVELS.find(([, f, s]) => mbs <= f && mbs * fps <= s) ?? AVC_LEVELS[AVC_LEVELS.length - 1]!)[0];\n const hex = level.toString(16).toUpperCase().padStart(2, \"0\");\n return [\"avc1.6400\", \"avc1.4D00\", \"avc1.42E0\"].map((p) => p + hex);\n}\n\n/** The first of `codecs` the browser encodes with these settings, as a config; undefined when none. */\nasync function supported(codecs: string[], base: Omit<VideoEncoderConfig, \"codec\">): Promise<VideoEncoderConfig | undefined> {\n for (const codec of codecs) {\n const config: VideoEncoderConfig = { ...base, codec };\n try {\n const answer = await VideoEncoder.isConfigSupported(config);\n if (answer.supported) return config;\n } catch {\n // A codec string the browser does not know: try the next.\n }\n }\n return undefined;\n}\n\nconst hasWebCodecs = () => typeof VideoEncoder !== \"undefined\" && typeof VideoFrame !== \"undefined\";\n\n/** A video's encoder config, or undefined when the browser cannot encode it. */\nasync function videoConfig(format: \"mp4\" | \"webm\", width: number, height: number, fps: number, bitrate: number) {\n const base: Omit<VideoEncoderConfig, \"codec\"> = {\n width,\n height,\n bitrate,\n framerate: fps,\n latencyMode: \"quality\",\n ...(format === \"mp4\" ? { avc: { format: \"avc\" as const } } : {}),\n };\n return supported(format === \"mp4\" ? avcCodecs(width, height, fps) : [\"vp09.00.10.08\", \"vp8\"], base);\n}\n\nconst resolveEffect = (effect: EffectDefinition | string) => {\n const def = typeof effect === \"string\" ? getEffect(effect) : effect;\n if (!def) throw new Error(`There is no effect \"${String(effect)}\" in the catalog; findEffects() lists them.`);\n return def;\n};\n\n/** A positive number option, or a sentence saying what it should be. */\nfunction positive(name: string, value: number | undefined, fallback: number): number {\n const n = value ?? fallback;\n if (!Number.isFinite(n) || n <= 0) throw new Error(`${name} must be a number above 0 (it was ${String(value)}).`);\n return n;\n}\n\nconst even = (n: number) => Math.max(2, Math.ceil(n / 2) * 2);\n\n/**\n * What {@link recordEffect} would make of these options, without drawing a\n * frame: the format (after falling back where the browser cannot encode\n * one), size, length, frame count, whether it keeps transparency, and the\n * encoder settings. Rejects with a sentence when the effect is unknown, an\n * option is out of range, or the browser cannot make the format asked for.\n */\nexport async function recordingPlan(effect: EffectDefinition | string, options: RecordOptions = {}): Promise<RecordingPlan> {\n const def = resolveEffect(effect);\n if (options.preset && !def.presets?.some((p) => p.name === options.preset)) {\n const names = def.presets?.map((p) => `\"${p.name}\"`).join(\", \");\n throw new Error(`\"${def.id}\" has no preset \"${options.preset}\"${names ? `; it has ${names}` : \"\"}.`);\n }\n const fps = positive(\"fps\", options.fps, 30);\n const start = options.start ?? 0;\n if (!Number.isFinite(start) || start < 0) throw new Error(`start must be 0 or more seconds (it was ${String(options.start)}).`);\n const duration = positive(\"duration\", options.duration, defaultDuration(def, options));\n let width = Math.round(positive(\"width\", options.width, 1280));\n let height = Math.round(positive(\"height\", options.height, 720));\n const explicitAlpha = options.alpha === true;\n let alpha = options.alpha ?? (def.kind === \"shader\" && Boolean(def.transparent));\n let format = options.format;\n if (format && ![\"mp4\", \"webm\", \"gif\", \"png\"].includes(format)) throw new Error(`format is one of \"mp4\", \"webm\", \"gif\" or \"png\" (it was \"${format}\").`);\n if (format === \"mp4\" && alpha) {\n if (explicitAlpha) throw new Error(`An mp4 (H.264) cannot keep transparency; record ${formats([\"webm\", \"png\", \"gif\"])} to keep it, or pass alpha: false.`);\n alpha = false;\n }\n\n let encoder: VideoEncoderConfig | undefined;\n if (format !== \"gif\" && format !== \"png\") {\n if (!hasWebCodecs())\n throw new Error(`This browser cannot encode video (it has no WebCodecs VideoEncoder), so it cannot record ${format ?? \"a video\"}; record ${formats([\"gif\", \"png\"])} instead.`);\n const w = even(width);\n const h = even(height);\n const bitrate = Math.round(positive(\"bitrate\", options.bitrate, w * h * fps * 0.15));\n const tryFormat = (f: \"mp4\" | \"webm\") => videoConfig(f, w, h, fps, bitrate);\n // Transparency needs webm; mp4 is the first choice otherwise, as it plays everywhere.\n const choices: (\"mp4\" | \"webm\")[] = format ? [format] : alpha ? [\"webm\"] : [\"mp4\", \"webm\"];\n for (const f of choices) {\n encoder = await tryFormat(f);\n if (encoder) {\n format = f;\n break;\n }\n }\n if (!encoder && !format && alpha && !explicitAlpha) {\n // Transparency was only the effect's default: an opaque mp4 will do.\n encoder = await tryFormat(\"mp4\");\n if (encoder) {\n format = \"mp4\";\n alpha = false;\n }\n }\n if (!encoder) {\n const asked = format ?? (alpha ? \"webm\" : \"mp4\");\n const other = asked === \"mp4\" ? \"webm\" : \"mp4\";\n if (alpha && asked === \"webm\") throw new Error(`This browser cannot encode VP8 or VP9, so it cannot record a webm with transparency; record ${formats([\"png\", \"gif\"])} to keep it, or pass alpha: false.`);\n const otherWorks = format && (await tryFormat(other));\n const codec = asked === \"mp4\" ? \"H.264\" : \"VP8 or VP9\";\n throw new Error(\n format\n ? `This browser cannot encode ${codec} at ${w} × ${h}, so it cannot record ${asked}; record ${formats(otherWorks ? [other, \"gif\", \"png\"] : [\"gif\", \"png\"])} instead.`\n : `This browser cannot encode H.264, VP8 or VP9 at ${w} × ${h}; record ${formats([\"gif\", \"png\"])} instead.`,\n );\n }\n width = w;\n height = h;\n }\n return { effect: def, format: format!, width, height, fps, duration, start, frames: Math.max(1, Math.round(duration * fps)), alpha, ...(encoder ? { encoder } : {}) };\n}\n\n/** A shader's loop, or a vector effect's picture plus its hold, else 4 seconds. */\nfunction defaultDuration(def: EffectDefinition, options: RecordOptions): number {\n if (def.kind === \"shader\") return def.loop ?? DEFAULT_SECONDS;\n const motion = renderVectorEffect(def, effectValues(def, options).values);\n return (svgDuration(motion, options.steps ?? []) + (def.hold ?? 600)) / 1000;\n}\n\nfunction effectValues(def: EffectDefinition, options: RecordOptions) {\n const values = effectDefaults(def, { ...(options.preset ? { preset: options.preset } : {}), ...(options.values ? { values: options.values } : {}) });\n if (!options.subject) return { values, live: {} as Record<string, LiveSource> };\n const s = subjectValues(def, options.subject);\n return { values: { ...values, ...s.values }, live: s.live };\n}\n\n/** RGBA bytes of one frame. */\ntype Pixels = Uint8ClampedArray<ArrayBuffer>;\n\n/** Draws frames as straight (not premultiplied) RGBA, rows top down. */\ninterface FrameSource {\n frame(time: number, index: number, out: Pixels): Promise<void>;\n dispose(): void;\n}\n\nfunction shaderSource(plan: RecordingPlan, values: Record<string, ControlValue>, live: Record<string, LiveSource>, options: RecordOptions): FrameSource {\n const def = plan.effect as Extract<EffectDefinition, { kind: \"shader\" }>;\n // A transparent effect is drawn with its alpha even when it is not kept, to be laid over the background.\n const frames = new ShaderFrames({ source: def.source, values, width: plan.width, height: plan.height, alpha: plan.alpha || Boolean(def.transparent) });\n const videos: { video: HTMLVideoElement; time: number; paused: boolean }[] = [];\n for (const [name, source] of Object.entries(live)) {\n frames.setLiveSource(name, source);\n if (typeof HTMLVideoElement !== \"undefined\" && source instanceof HTMLVideoElement) {\n videos.push({ video: source, time: source.currentTime, paused: source.paused });\n source.pause();\n }\n }\n const script = options.pointer;\n return {\n async frame(time, index, out) {\n for (const { video } of videos) await seekVideo(video, time);\n await options.beforeFrame?.(time, index);\n await frames.ready();\n const pointer = typeof script === \"function\" ? script(time) : script;\n frames.render(time, { frame: index, delta: 1 / plan.fps, ...pointer });\n frames.readPixels(out);\n },\n dispose() {\n frames.dispose();\n for (const { video, time, paused } of videos) {\n video.currentTime = time;\n if (!paused) void video.play().catch(() => undefined);\n }\n },\n };\n}\n\nfunction vectorSource(plan: RecordingPlan, values: Record<string, ControlValue>, options: RecordOptions): FrameSource {\n const def = plan.effect as Extract<EffectDefinition, { kind: \"vector\" }>;\n const view = svgView(renderVectorEffect(def, values));\n // In the page (out of sight) so its fonts, sizes and colours resolve as they would on screen.\n const host = document.createElement(\"div\");\n host.setAttribute(\"aria-hidden\", \"true\");\n host.style.cssText = `position:fixed;left:-100000px;top:0;width:${plan.width}px;height:${plan.height}px;pointer-events:none;`;\n host.appendChild(view.element);\n document.body.appendChild(host);\n const steps = options.steps ?? [];\n return {\n async frame(time, index, out) {\n await options.beforeFrame?.(time, index);\n view.draw(time * 1000, steps);\n const canvas = await view.capture({ width: plan.width, height: plan.height });\n if (!canvas) throw new Error(`\"${def.id}\" has no picture to record: its SVG does not parse.`);\n out.set(canvas.getContext(\"2d\")!.getImageData(0, 0, plan.width, plan.height).data);\n },\n dispose: () => host.remove(),\n };\n}\n\n/** Lays straight-alpha pixels over an opaque colour, in place. */\nfunction flatten(rgba: Pixels, background: [number, number, number]) {\n const [br, bg, bb] = background;\n for (let i = 0; i < rgba.length; i += 4) {\n const a = rgba[i + 3]!;\n if (a === 255) continue;\n const k = a / 255;\n rgba[i] = rgba[i]! * k + br * (1 - k);\n rgba[i + 1] = rgba[i + 1]! * k + bg * (1 - k);\n rgba[i + 2] = rgba[i + 2]! * k + bb * (1 - k);\n rgba[i + 3] = 255;\n }\n}\n\n/** Turns frames into a file, one at a time. */\ninterface Encoder {\n add(rgba: Pixels, index: number): Promise<void>;\n finish(): Promise<Blob>;\n close(): void;\n}\n\nasync function gifEncoder(plan: RecordingPlan): Promise<Encoder> {\n const { GIFEncoder, quantize, applyPalette } = await import(\"gifenc\");\n const gif = GIFEncoder();\n const delay = 1000 / plan.fps;\n return {\n async add(rgba, i) {\n const repeat = i === 0 ? { repeat: 0 } : {};\n if (!plan.alpha) {\n const palette = quantize(rgba, 256);\n gif.writeFrame(applyPalette(rgba, palette), plan.width, plan.height, { palette, delay, ...repeat });\n return;\n }\n // One colour is see-through: pixels at most half covered. Each frame replaces the last (dispose 2).\n const palette = quantize(rgba, 256, { format: \"rgba4444\", oneBitAlpha: true });\n const transparentIndex = palette.findIndex((c) => c[3] === 0);\n gif.writeFrame(applyPalette(rgba, palette, \"rgba4444\"), plan.width, plan.height, {\n palette,\n delay,\n dispose: 2,\n ...(transparentIndex >= 0 ? { transparent: true, transparentIndex } : {}),\n ...repeat,\n });\n },\n async finish() {\n gif.finish();\n return new Blob([gif.bytes()], { type: \"image/gif\" });\n },\n close() {},\n };\n}\n\nfunction pngEncoder(plan: RecordingPlan): Encoder {\n const canvas = document.createElement(\"canvas\");\n canvas.width = plan.width;\n canvas.height = plan.height;\n const context = canvas.getContext(\"2d\");\n if (!context) throw new Error(\"This browser cannot draw on a canvas, so it cannot make PNG frames.\");\n const entries: ZipEntry[] = [];\n const digits = Math.max(4, String(plan.frames).length);\n return {\n async add(rgba, i) {\n context.putImageData(new ImageData(rgba, plan.width, plan.height), 0, 0);\n const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, \"image/png\"));\n if (!blob) throw new Error(\"The browser could not encode a PNG frame.\");\n entries.push({ name: `frame-${String(i + 1).padStart(digits, \"0\")}.png`, data: new Uint8Array(await blob.arrayBuffer()) });\n },\n async finish() {\n return new Blob([zipStore(entries) as Uint8Array<ArrayBuffer>], { type: \"application/zip\" });\n },\n close() {},\n };\n}\n\nconst bytesOf = (source: AllowSharedBufferSource) =>\n source instanceof ArrayBuffer || (typeof SharedArrayBuffer !== \"undefined\" && source instanceof SharedArrayBuffer)\n ? new Uint8Array(source.slice(0))\n : new Uint8Array((source as ArrayBufferView).buffer.slice((source as ArrayBufferView).byteOffset, (source as ArrayBufferView).byteOffset + (source as ArrayBufferView).byteLength));\n\n/** A WebCodecs encoder whose chunks are collected, with the first decoder description it gives. */\nfunction collector(config: VideoEncoderConfig, fail: (e: Error) => void) {\n const chunks: { data: Uint8Array; timestamp: number; duration?: number; key: boolean }[] = [];\n const out = { chunks, description: undefined as Uint8Array | undefined, encoder: undefined as unknown as VideoEncoder };\n out.encoder = new VideoEncoder({\n output(chunk, metadata) {\n const data = new Uint8Array(chunk.byteLength);\n chunk.copyTo(data);\n const desc = metadata?.decoderConfig?.description;\n if (desc && !out.description) out.description = bytesOf(desc);\n chunks.push({ data, timestamp: chunk.timestamp, ...(chunk.duration ? { duration: chunk.duration } : {}), key: chunk.type === \"key\" });\n },\n error: (e) => fail(new Error(`The video encoder failed: ${e.message}`, { cause: e })),\n });\n out.encoder.configure(config);\n return out;\n}\n\n/**\n * Encodes with WebCodecs and muxes into mp4 or webm. With `alpha`, a second\n * encoder (same codec) takes the alpha as a greyscale picture, and each\n * frame's alpha goes beside it in the webm, as Chrome's own recordings do:\n * browsers' encoders do not keep alpha themselves.\n */\nfunction videoEncoder(plan: RecordingPlan): Encoder {\n const config = plan.encoder!;\n let failure: Error | undefined;\n const fail = (e: Error) => (failure ??= e);\n const color = collector(config, fail);\n const alpha = plan.alpha ? collector(config, fail) : undefined;\n const encoders = [color.encoder, ...(alpha ? [alpha.encoder] : [])];\n const frameUs = 1e6 / plan.fps;\n // A keyframe every two seconds, so players can seek.\n const keyEvery = Math.max(1, Math.round(plan.fps * 2));\n const { width, height } = plan;\n // I420: the alpha as luma, with neutral chroma.\n const plane = alpha ? new Uint8Array(width * height * 1.5).fill(128) : undefined;\n const check = () => {\n if (failure) throw failure;\n };\n const encode = (encoder: VideoEncoder, frame: VideoFrame, key: boolean) => {\n try {\n encoder.encode(frame, { keyFrame: key });\n } finally {\n frame.close();\n }\n };\n return {\n async add(rgba, i) {\n check();\n const timing = { codedWidth: width, codedHeight: height, timestamp: Math.round(i * frameUs), duration: Math.round(frameUs) };\n const key = i % keyEvery === 0;\n encode(color.encoder, new VideoFrame(rgba, { format: \"RGBX\", ...timing }), key);\n if (alpha && plane) {\n for (let p = 0, q = 3; p < width * height; p++, q += 4) plane[p] = rgba[q]!;\n encode(alpha.encoder, new VideoFrame(plane, { format: \"I420\", ...timing }), key);\n }\n // Hold back while an encoder is behind, so frames don't pile up in memory.\n while (encoders.some((e) => e.encodeQueueSize > 4) && !failure) await new Promise((resolve) => setTimeout(resolve, 1));\n },\n async finish() {\n await Promise.all(encoders.map((e) => e.flush()));\n check();\n for (const e of encoders) e.close();\n const byTime = (a: { timestamp: number }, b: { timestamp: number }) => a.timestamp - b.timestamp;\n const chunks = color.chunks.sort(byTime);\n if (plan.format === \"mp4\") {\n if (!color.description) throw new Error(\"The H.264 encoder gave no decoder configuration (avcC), so the mp4 cannot be written.\");\n const file = muxMp4({ width, height, avcC: color.description, samples: chunks });\n return new Blob([file as Uint8Array<ArrayBuffer>], { type: \"video/mp4\" });\n }\n const alphas = new Map(alpha?.chunks.map((c) => [c.timestamp, c.data]));\n const frames: WebmFrame[] = chunks.map((c) => {\n const a = alphas.get(c.timestamp);\n if (alpha && !a) throw new Error(`The alpha encoder dropped the frame at ${c.timestamp / 1e6} s, so the webm cannot keep transparency; record \"png\" or \"gif\" instead.`);\n return { ...c, ...(a ? { alpha: a } : {}) };\n });\n const codec = config.codec.startsWith(\"vp8\") ? \"vp8\" : \"vp9\";\n const file = muxWebm({ codec, width, height, frames, duration: plan.frames * frameUs, fps: plan.fps });\n return new Blob([file as Uint8Array<ArrayBuffer>], { type: \"video/webm\" });\n },\n close() {\n for (const e of encoders) if (e.state !== \"closed\") e.close();\n },\n };\n}\n\n/**\n * Records a catalog effect (by id or definition), applied to `subject`, to a\n * file in the browser: an `mp4` or `webm` video (WebCodecs, muxed here with\n * no dependencies), an animated `gif`, or `png` frames.\n *\n * Frames are drawn off screen at exact times (`start + i / fps`), so the\n * result is smooth whatever the page's frame rate, and the same on every\n * machine. Shaders render with `ShaderFrames` (a `<video>` subject is paused\n * and sought to each frame, and put back after); vector effects are drawn\n * with `svgView` and rasterised. Shaders that answer the pointer play their\n * idle demos unless `pointer` scripts it.\n *\n * `png` resolves to a ZIP of numbered frames (`frame-0001.png`, …), so every\n * format is one `Blob` to save or upload.\n *\n * Rejects with a sentence when the effect is unknown, takes no such\n * subject, or the browser cannot make the format (naming the formats that\n * would work); with a `ShaderCompileError` or `ImageLoadError` as\n * `ShaderFrames` does; and with an `AbortError` when `signal` aborts.\n *\n * ```ts\n * const mp4 = await recordEffect(\"image-duotone\", { subject: { image: \"/team.jpg\" }, preset: \"Spotify\" });\n * const gif = await recordEffect(\"typewriter\", { subject: { text: \"Hello\" }, format: \"gif\", width: 640, height: 360, fps: 25 });\n * const webm = await recordEffect(\"click-ripple\", { format: \"webm\", alpha: true, pointer: { clicks: [{ x: 640, y: 360, time: 0.2 }] } });\n * ```\n */\nexport async function recordEffect(effect: EffectDefinition | string, options: RecordOptions = {}): Promise<Blob> {\n const plan = await recordingPlan(effect, options);\n const { signal, onProgress } = options;\n const { values, live } = effectValues(plan.effect, options);\n const background = (parseColor(options.background ?? (plan.effect.kind === \"shader\" ? \"#000000\" : \"#ffffff\")) ?? [0, 0, 0]).map((c) => Math.round(c * 255)) as [number, number, number];\n\n const source = plan.effect.kind === \"shader\" ? shaderSource(plan, values, live, options) : vectorSource(plan, values, options);\n let encoder: Encoder | undefined;\n try {\n encoder = plan.format === \"gif\" ? await gifEncoder(plan) : plan.format === \"png\" ? pngEncoder(plan) : videoEncoder(plan);\n const rgba = new Uint8ClampedArray(plan.width * plan.height * 4);\n for (let i = 0; i < plan.frames; i++) {\n if (signal?.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n await source.frame(plan.start + i / plan.fps, i, rgba);\n if (!plan.alpha) flatten(rgba, background);\n await encoder.add(rgba, i);\n onProgress?.((i + 1) / plan.frames);\n if (i % 2 === 1) await yieldToBrowser();\n }\n if (signal?.aborted) throw new DOMException(\"Cancelled\", \"AbortError\");\n return await encoder.finish();\n } finally {\n encoder?.close();\n source.dispose();\n }\n}\n","/**\n * Catalog effects on a page in one call: pick an effect, give it what it\n * takes (a picture, a video, an SVG, words or a path) and get it running.\n *\n * - Pairing: `subjectValues` turns a subject into the control values (and\n * live sources) an effect needs, using `effectInputs`.\n * - Embedding: `mountEffect` runs a shader effect (`ShaderRenderer`) or a\n * vector effect (`SvgPlayer`) in an element, with its subject.\n *\n * @packageDocumentation\n */\n\nimport { effectDefaults, effectInputs, getEffect, textImage, type EffectDefinition, type ImageSlot, type TextSlot } from \"../catalog/index.js\";\nimport { renderVectorEffect } from \"../catalog/types.js\";\nimport type { ControlValue } from \"../shader/controls.js\";\nimport { ShaderRenderer } from \"../shader/renderer.js\";\nimport type { LiveSource } from \"../shader/textures.js\";\nimport { SvgPlayer } from \"../vector/svg.js\";\n\nexport { recordEffect, recordingPlan, type RecordFormat, type RecordOptions, type RecordPointer, type RecordingPlan } from \"./record.js\";\n\n/**\n * What an effect is applied to:\n * - `{ image }`: a picture's URL (or `data:` URL).\n * - `{ video }`: a playing `<video>` (or a canvas), shown live.\n * - `{ svg }`: an SVG, as markup (`\"<svg …>\"`) or a URL; drawn as a picture, keeping its transparency.\n * - `{ text }`: words, for a vector effect's text, or drawn with `textImage` for a shader's text or mask.\n * - `{ path }`: SVG path data (`d`), for a shape control.\n */\nexport type EffectSubject =\n | { image: string }\n | { video: LiveSource }\n | { svg: string }\n | { text: string; font?: string; weight?: number | string }\n | { path: string };\n\n/** What a subject becomes for an effect: control values, and live sources by image control. */\nexport interface SubjectValues {\n values: Record<string, ControlValue>;\n live: Record<string, LiveSource>;\n}\n\nconst kindOf = (subject: EffectSubject) => Object.keys(subject).find((k) => k !== \"font\" && k !== \"weight\") as \"image\" | \"video\" | \"svg\" | \"text\" | \"path\";\n\n/** An SVG as a URL: markup becomes a UTF-8 `data:` URL; a URL stays as it is. */\nfunction svgUrl(svg: string): string {\n const markup = svg.trim();\n if (!markup.startsWith(\"<\")) return svg;\n const withNs = /\\sxmlns\\s*=/.test(markup.slice(0, markup.indexOf(\">\") + 1)) ? markup : markup.replace(/^<svg/i, '<svg xmlns=\"http://www.w3.org/2000/svg\"');\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(withNs)}`;\n}\n\nfunction pick<T extends { name: string }>(slots: T[], wanted: (s: T) => boolean, name: string | undefined, effect: EffectDefinition, what: string): T {\n const slot = name ? slots.find((s) => s.name === name) : slots.find(wanted);\n if (!slot) {\n const names = slots.map((s) => s.name).join(\", \");\n throw new Error(\n name\n ? `\"${effect.id}\" has no control \"${name}\" for ${what}${names ? `; it has ${names}` : \"\"}.`\n : `\"${effect.id}\" takes no ${what}; see effectInputs(effect).accepts, or findEffects({ accepts: [...] }) for effects that do.`,\n );\n }\n return slot;\n}\n\n/**\n * The control values (and live sources) that put `subject` in `effect`,\n * into the control named `slot` or the first that suits it: a picture or\n * SVG into an image control, a video into a picture control as a live\n * source, words into a vector effect's text or (drawn by `textImage`) a\n * shader's text or mask control, path data into a shape control. Several\n * subjects fill several controls in order (a transition's from and to).\n * Throws a sentence when the effect takes no such thing.\n */\nexport function subjectValues(effect: EffectDefinition, subject: EffectSubject | readonly EffectSubject[], slot?: string): SubjectValues {\n const out: SubjectValues = { values: {}, live: {} };\n const inputs = effectInputs(effect);\n const used = new Set<string>();\n for (const s of Array.isArray(subject) ? subject : [subject as EffectSubject]) {\n const kind = kindOf(s);\n const free = <T extends { name: string }>(slots: T[]) => slots.filter((x) => !used.has(x.name));\n if (kind === \"path\" || (kind === \"text\" && effect.kind === \"vector\")) {\n const holds = kind === \"path\" ? \"path\" : \"copy\";\n const text = pick<TextSlot>(free(inputs.texts), (t) => t.holds === holds, slot, effect, kind === \"path\" ? \"path data\" : \"text\");\n out.values[text.name] = kind === \"path\" ? (s as { path: string }).path : (s as { text: string }).text;\n used.add(text.name);\n continue;\n }\n if (effect.kind === \"vector\")\n throw new Error(`\"${effect.id}\" is a vector effect: it draws its own picture and takes words or path data (${inputs.accepts.join(\", \") || \"nothing\"}), not ${{ svg: \"an SVG\", image: \"an image\", video: \"a video\" }[kind as \"svg\" | \"image\" | \"video\"]}.`);\n const wanted = (x: ImageSlot) =>\n kind === \"text\" ? x.wants !== \"picture\" : kind === \"video\" ? x.wants === \"picture\" : true;\n const image = pick<ImageSlot>(free(inputs.images), wanted, slot, effect, kind === \"text\" ? \"text\" : `${kind === \"svg\" ? \"SVG\" : kind}`);\n used.add(image.name);\n if (kind === \"video\") {\n if (!inputs.accepts.includes(\"video\")) throw new Error(`\"${effect.id}\" is not made for video (video: \"${inputs.video}\"); give it a picture.`);\n out.live[image.name] = (s as { video: LiveSource }).video;\n } else if (kind === \"text\") {\n const t = s as { text: string; font?: string; weight?: number | string };\n out.values[image.name] = textImage(t.text, { ...(t.font ? { font: t.font } : {}), ...(t.weight !== undefined ? { weight: t.weight } : {}) });\n } else out.values[image.name] = kind === \"svg\" ? svgUrl((s as { svg: string }).svg) : (s as { image: string }).image;\n }\n return out;\n}\n\nexport interface MountOptions {\n /** What to apply the effect to (see {@link EffectSubject}); several fill several controls in order. */\n subject?: EffectSubject | readonly EffectSubject[];\n /** A preset by name, then these values, over the effect's defaults. */\n preset?: string;\n values?: Record<string, ControlValue>;\n /** Start playing at once (default true). */\n autoplay?: boolean;\n /** Class for the canvas (shaders) or the player's element (vector effects). */\n className?: string;\n /** Pause while scrolled out of view (default true). */\n pauseWhenHidden?: boolean;\n}\n\n/** A running effect, from {@link mountEffect}. */\nexport interface MountedEffect {\n readonly effect: EffectDefinition;\n /** What it draws into: the shader's canvas, or the vector player's element. */\n readonly element: HTMLElement;\n /** The shader renderer, for a shader effect. */\n readonly renderer?: ShaderRenderer;\n /** The vector player, for a vector effect (replaced when values change). */\n readonly player?: SvgPlayer;\n /** Applies it to something else. */\n setSubject(subject: EffectSubject | readonly EffectSubject[]): void;\n /** Changes control values (merged over the current ones). */\n setValues(values: Record<string, ControlValue>): void;\n play(): void;\n pause(): void;\n /** Stops it and removes what it drew. */\n dispose(): void;\n}\n\n/**\n * Runs a catalog effect (by id or definition) in `host`, applied to\n * `subject`: a shader on a canvas (transparent for overlays, so it lays over\n * the page), or a vector effect in an SVG player that answers its trigger\n * (hover, press, click). Throws a sentence when the effect is unknown or\n * takes no such subject.\n *\n * ```ts\n * mountEffect(el, \"image-duotone\", { subject: { image: \"/team.jpg\" }, preset: \"Spotify\" });\n * mountEffect(el, \"crt\", { subject: { video: videoElement } });\n * mountEffect(el, \"typewriter\", { subject: { text: \"Hello there\" } });\n * mountEffect(el, \"neon-outline\", { subject: { svg: logoMarkup } });\n * ```\n */\nexport function mountEffect(host: HTMLElement, effect: EffectDefinition | string, options: MountOptions = {}): MountedEffect {\n const def = typeof effect === \"string\" ? getEffect(effect) : effect;\n if (!def) throw new Error(`There is no effect \"${String(effect)}\" in the catalog; findEffects() lists them.`);\n let values: Record<string, ControlValue> = { ...effectDefaults(def, { ...(options.preset ? { preset: options.preset } : {}), ...(options.values ? { values: options.values } : {}) }) };\n let live: Record<string, LiveSource> = {};\n const apply = (subject: EffectSubject | readonly EffectSubject[] | undefined) => {\n if (!subject) return;\n const s = subjectValues(def, subject);\n values = { ...values, ...s.values };\n live = s.live;\n };\n apply(options.subject);\n\n if (def.kind === \"shader\") {\n const renderer = new ShaderRenderer(host, {\n alpha: Boolean(def.transparent),\n autoplay: options.autoplay ?? true,\n pauseWhenHidden: options.pauseWhenHidden ?? true,\n ...(options.className ? { className: options.className } : {}),\n });\n renderer.setSource(def.source);\n renderer.setValues(values);\n const setLive = (previous: Record<string, LiveSource>) => {\n for (const name of Object.keys(previous)) if (!(name in live)) renderer.setLiveSource(name, null);\n for (const [name, source] of Object.entries(live)) renderer.setLiveSource(name, source);\n };\n setLive({});\n return {\n effect: def,\n element: renderer.canvas,\n renderer,\n setSubject(subject) {\n const before = live;\n apply(subject);\n renderer.setValues(values);\n setLive(before);\n },\n setValues(next) {\n values = { ...values, ...next };\n renderer.setValues(values);\n },\n play: () => renderer.play(),\n pause: () => renderer.pause(),\n dispose: () => renderer.dispose(),\n };\n }\n\n let player: SvgPlayer;\n const build = () => {\n player?.dispose();\n player = new SvgPlayer(host, renderVectorEffect(def, values), {\n hold: def.hold,\n ...(def.trigger ? { trigger: def.trigger } : {}),\n autoplay: options.autoplay ?? true,\n pauseWhenHidden: options.pauseWhenHidden ?? true,\n });\n if (options.className) player.view.element.className = options.className;\n };\n build();\n return {\n effect: def,\n get element() {\n return player.view.element;\n },\n get player() {\n return player;\n },\n setSubject(subject) {\n apply(subject);\n build();\n },\n setValues(next) {\n values = { ...values, ...next };\n build();\n },\n play: () => player.play(),\n pause: () => player.pause(),\n dispose: () => player.dispose(),\n };\n}\n"],"mappings":"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","names":["palette","file"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shader/renderer.ts","../src/shader/frames.ts"],"sourcesContent":["import { imageUrls, parseControls, type ControlDef, type ControlValue } from \"./controls.js\";\nimport {\n compileShader,\n createContext,\n drawFrame,\n resetGlCaches,\n type CompileError,\n type CompiledShader,\n} from \"./program.js\";\nimport { PointerTracker } from \"./pointer.js\";\nimport { TextureCache, type ImageLoadError, type LiveSource } from \"./textures.js\";\n\n/** Whether the latest source compiled, and if not, why. */\nexport interface CompileStatus {\n ok: boolean;\n errors: CompileError[];\n}\n\n/** What `onStats` reports: on play, pause, seek and restart, and twice a second while running. */\nexport interface RendererStats {\n /** `iTime`, in seconds. */\n time: number;\n /** Frames drawn per second over the last half second (0 while paused). */\n fps: number;\n playing: boolean;\n /** The drawing buffer's size in device pixels. */\n width: number;\n height: number;\n}\n\nexport interface ShaderRendererOptions {\n className?: string;\n /** Enable a transparent WebGL drawing buffer so shader alpha (`fragColor.a`) composites over the page (default false). */\n alpha?: boolean;\n /** Pause rendering when scrolled out of view via IntersectionObserver (default false). */\n pauseWhenHidden?: boolean;\n /** Start playing at once (default true). Set to false to start paused. */\n autoplay?: boolean;\n /** Wait to start playing until the canvas enters the viewport via IntersectionObserver (default false). When true, autoplay is deferred until first visible. */\n playOnEnter?: boolean;\n}\n\n/**\n * Runs one shader on a canvas: the editor's live preview. A source that does\n * not compile leaves the last working program on screen, so a typo never\n * blanks the preview; the errors are reported instead.\n *\n * The renderer owns its canvas (added to `host`, removed on dispose): a\n * canvas keeps its WebGL context for life, so reusing one after disposing\n * (a remount, hot reload) would get the released, lost context back.\n */\nexport class ShaderRenderer {\n readonly canvas: HTMLCanvasElement;\n private gl: WebGL2RenderingContext | null;\n private readonly alpha: boolean;\n private shader: CompiledShader | null = null;\n private textures: TextureCache | null = null;\n /** Live sources by image control, kept to set again on a restored context. */\n private live = new Map<string, LiveSource>();\n private controls: ControlDef[] = [];\n private values: Record<string, ControlValue> | undefined;\n private source = \"\";\n private raf = 0;\n private lastNow = 0;\n private frame = 0;\n private fpsFrames = 0;\n private fpsSince = 0;\n private ownsCanvas = false;\n private resizeObserver: ResizeObserver;\n private intersectionObserver?: IntersectionObserver;\n private wasPlayingBeforeHidden = false;\n private hasEnteredViewport = false;\n private mouse: [number, number, number, number] = [0, 0, 0, 0];\n /** `iPointer` and `iClicks`. */\n private pointer = new PointerTracker();\n private disposed = false;\n /** The latest source's status. */\n status: CompileStatus = { ok: true, errors: [] };\n /** `iTime`, in seconds. Use `seek` to change it. */\n time = 0;\n /** Playback speed: 1 is real time. */\n speed = 1;\n /** Device pixels per CSS pixel; lower renders faster. Use `setPixelRatio` to change it. */\n pixelRatio = Math.min(window.devicePixelRatio || 1, 2);\n playing = true;\n fps = 0;\n onStats?: (stats: RendererStats) => void;\n /** Called with `true` when the GL context is lost and `false` once it is restored and recompiled. */\n onContextLost?: (lost: boolean) => void;\n /** Called when an image control's URL (or live video) cannot be loaded; the control shows black. */\n onImageError?: (error: ImageLoadError) => void;\n\n /**\n * Creates a canvas in `target` (with `className` or options), or attaches to an existing\n * `HTMLCanvasElement`, and starts the animation loop. Size the canvas with CSS.\n */\n constructor(target: HTMLElement | HTMLCanvasElement, options?: string | ShaderRendererOptions) {\n const opts: ShaderRendererOptions =\n typeof options === \"string\" ? { className: options } : (options ?? {});\n let canvas: HTMLCanvasElement;\n if (target instanceof HTMLCanvasElement || (\"tagName\" in target && target.tagName === \"CANVAS\")) {\n canvas = target as HTMLCanvasElement;\n if (opts.className) canvas.className = opts.className;\n } else {\n canvas = document.createElement(\"canvas\");\n if (opts.className) canvas.className = opts.className;\n target.appendChild(canvas);\n this.ownsCanvas = true;\n }\n this.canvas = canvas;\n this.alpha = Boolean(opts.alpha);\n this.gl = createContext(canvas, true, this.alpha);\n this.textures = this.gl && this.textureCache(this.gl);\n this.resizeObserver = new ResizeObserver(() => this.resize());\n this.resizeObserver.observe(canvas);\n\n const needsObserver =\n (opts.pauseWhenHidden || opts.playOnEnter) && typeof IntersectionObserver !== \"undefined\";\n\n if (needsObserver) {\n this.intersectionObserver = new IntersectionObserver(([entry]) => {\n if (!entry) return;\n if (entry.isIntersecting) {\n if (opts.playOnEnter && !this.hasEnteredViewport) {\n this.hasEnteredViewport = true;\n if (opts.autoplay ?? true) {\n this.play();\n }\n } else if (this.wasPlayingBeforeHidden) {\n this.wasPlayingBeforeHidden = false;\n this.play();\n }\n } else {\n if (this.playing && opts.pauseWhenHidden) {\n this.wasPlayingBeforeHidden = true;\n this.pause();\n }\n }\n });\n this.intersectionObserver.observe(canvas);\n }\n\n const shouldAutoplay = (opts.autoplay ?? true) && !opts.playOnEnter;\n this.playing = shouldAutoplay;\n\n canvas.addEventListener(\"webglcontextlost\", this.onLost);\n canvas.addEventListener(\"webglcontextrestored\", this.onRestored);\n canvas.addEventListener(\"pointerdown\", this.onPointerDown);\n canvas.addEventListener(\"pointermove\", this.onPointerMove);\n canvas.addEventListener(\"pointerenter\", this.onPointerEnter);\n canvas.addEventListener(\"pointerleave\", this.onPointerLeave);\n window.addEventListener(\"pointerup\", this.onPointerUp);\n this.resize();\n this.raf = requestAnimationFrame(this.tick);\n }\n\n /** False when the browser has no WebGL2. */\n get supported(): boolean {\n return this.gl !== null;\n }\n\n /** Compiles a new source; returns its status. Keeps the previous program when it fails. */\n setSource(source: string): CompileStatus {\n this.source = source;\n const controls = parseControls(source);\n if (!this.gl) {\n this.status = {\n ok: false,\n errors: [{ line: 0, message: \"WebGL2 is not available in this browser.\" }],\n };\n return this.status;\n }\n const result = compileShader(this.gl, source, controls);\n if (result.ok) {\n if (this.shader) this.gl.deleteProgram(this.shader.program);\n this.shader = result.shader;\n this.controls = controls;\n this.status = { ok: true, errors: [] };\n } else {\n this.status = { ok: false, errors: result.errors };\n }\n this.syncTextures();\n if (!this.playing) this.render();\n return this.status;\n }\n\n /**\n * Sets control values (see `controlValue`); a paused preview redraws.\n * Images load in the background and show once they arrive: await\n * `ready()` before a `capture` that needs them.\n */\n setValues(values: Record<string, ControlValue> | undefined) {\n this.values = values;\n this.syncTextures();\n if (!this.playing) this.render();\n }\n\n /**\n * Shows a `<video>` (or a canvas) in the image control `name` (the\n * uniform's name, such as `uImage`) in place of its URL, frame by frame;\n * `null` goes back to the URL. The preview follows the video even while\n * the shader's own clock is paused, and the video plays, seeks and loops\n * on its own: the renderer never controls it. A video from another site\n * needs `crossOrigin = \"anonymous\"` and CORS, or `onImageError` hears why\n * it shows black. The value stays as it is, so documents, presets and\n * agents keep seeing the URL.\n */\n setLiveSource(name: string, source: LiveSource | null) {\n if (source) this.live.set(name, source);\n else this.live.delete(name);\n this.textures?.setLive(name, source);\n if (!this.playing) this.render();\n }\n\n /**\n * Settles once the images the current controls show have loaded, and\n * every live video has a frame. Rejects with an {@link ImageLoadError}\n * when one cannot be (it shows black).\n */\n async ready(): Promise<void> {\n await Promise.all([\n this.textures?.ready(imageUrls(this.controls, this.values)),\n this.textures?.liveReady(),\n ]);\n }\n\n play() {\n this.playing = true;\n this.emit();\n }\n\n pause() {\n this.playing = false;\n this.emit();\n }\n\n /** Back to `iTime` 0 and frame 0. */\n restart() {\n this.time = 0;\n this.pointer.clear();\n this.frame = 0;\n this.render();\n this.emit();\n }\n\n /** Jumps to `time` seconds (not below 0) and draws it. */\n seek(time: number) {\n // Clicks are stamped with iTime: going back would replay them.\n if (time < this.time) this.pointer.clear();\n this.time = Math.max(0, time);\n this.render();\n this.emit();\n }\n\n setPixelRatio(ratio: number) {\n this.pixelRatio = ratio;\n this.resize();\n }\n\n /**\n * Captures the current frame (optionally at another time) as a data URL\n * (JPEG unless `type` says PNG), at most `maxEdge` pixels on the long side\n * (default 1024). Playback time is left as it was. Null when nothing has\n * compiled yet.\n */\n capture(\n options: { time?: number; maxEdge?: number; type?: \"image/jpeg\" | \"image/png\" } = {},\n ): string | null {\n if (!this.gl || !this.shader) return null;\n const saved = this.time;\n if (options.time !== undefined) this.time = Math.max(0, options.time);\n this.render();\n const { width, height } = this.canvas;\n const scale = Math.min(1, (options.maxEdge ?? 1024) / Math.max(width, height));\n const out = document.createElement(\"canvas\");\n out.width = Math.max(1, Math.round(width * scale));\n out.height = Math.max(1, Math.round(height * scale));\n out.getContext(\"2d\")!.drawImage(this.canvas, 0, 0, out.width, out.height);\n this.time = saved;\n if (options.time !== undefined) this.render();\n return out.toDataURL(options.type ?? \"image/jpeg\", 0.85);\n }\n\n /** Stops the loop, releases the context and removes the canvas. The renderer cannot be used again. */\n dispose() {\n this.disposed = true;\n cancelAnimationFrame(this.raf);\n this.resizeObserver.disconnect();\n this.intersectionObserver?.disconnect();\n this.canvas.removeEventListener(\"webglcontextlost\", this.onLost);\n this.canvas.removeEventListener(\"webglcontextrestored\", this.onRestored);\n this.canvas.removeEventListener(\"pointerdown\", this.onPointerDown);\n this.canvas.removeEventListener(\"pointermove\", this.onPointerMove);\n this.canvas.removeEventListener(\"pointerenter\", this.onPointerEnter);\n this.canvas.removeEventListener(\"pointerleave\", this.onPointerLeave);\n window.removeEventListener(\"pointerup\", this.onPointerUp);\n if (this.gl && this.shader) this.gl.deleteProgram(this.shader.program);\n this.textures?.dispose();\n this.textures = null;\n // Free the context now rather than waiting for GC (browsers cap live contexts).\n this.gl?.getExtension(\"WEBGL_lose_context\")?.loseContext();\n this.gl = null;\n if (this.ownsCanvas) this.canvas.remove();\n }\n\n private resize() {\n // The layout size, not the bounding box: a rotated or scaled canvas keeps its own proportions.\n const w = Math.max(1, Math.round(this.canvas.clientWidth * this.pixelRatio));\n const h = Math.max(1, Math.round(this.canvas.clientHeight * this.pixelRatio));\n if (this.canvas.width !== w || this.canvas.height !== h) {\n this.canvas.width = w;\n this.canvas.height = h;\n this.render();\n }\n }\n\n private render(delta = 0) {\n if (!this.gl || !this.shader || this.gl.isContextLost()) return;\n drawFrame(\n this.gl,\n this.shader,\n this.controls,\n this.values,\n {\n width: this.canvas.width,\n height: this.canvas.height,\n time: this.time,\n delta,\n frame: this.frame,\n mouse: this.mouse,\n pointer: this.pointer.pointer(this.time),\n clicks: this.pointer.clicksAt(this.time),\n trail: this.pointer.trailAt(this.time),\n },\n this.textures ?? undefined,\n );\n }\n\n private textureCache(gl: WebGL2RenderingContext): TextureCache {\n const cache = new TextureCache(gl, (_url, error) => {\n if (error) this.onImageError?.(error);\n else if (!this.playing) this.render();\n });\n for (const [name, source] of this.live) cache.setLive(name, source);\n return cache;\n }\n\n /** Starts loading the images now shown, and frees the ones no longer shown. */\n private syncTextures() {\n if (!this.textures) return;\n const urls = imageUrls(this.controls, this.values);\n this.textures.retain(urls);\n for (const url of urls) this.textures.request(url);\n }\n\n private tick = (now: number) => {\n if (this.disposed) return;\n this.raf = requestAnimationFrame(this.tick);\n const delta = this.lastNow ? Math.min((now - this.lastNow) / 1000, 0.1) : 0;\n this.lastNow = now;\n if (this.playing) {\n this.time += delta * this.speed;\n this.frame += 1;\n this.render(delta * this.speed);\n this.fpsFrames += 1;\n } else if (this.textures?.liveChanged()) {\n // A live video moved on (played, seeked or loaded) while the clock is paused.\n this.render();\n }\n if (now - this.fpsSince >= 500) {\n this.fps = this.playing\n ? Math.round((this.fpsFrames * 1000) / (now - this.fpsSince || 1))\n : 0;\n this.fpsFrames = 0;\n this.fpsSince = now;\n this.emit();\n }\n };\n\n private emit() {\n this.onStats?.({\n time: this.time,\n fps: this.fps,\n playing: this.playing,\n width: this.canvas.width,\n height: this.canvas.height,\n });\n }\n\n /** Pointer position in shader pixels (origin bottom-left, like gl_FragCoord). */\n private toPixels(e: PointerEvent): [number, number] {\n const rect = this.canvas.getBoundingClientRect();\n return [\n (e.clientX - rect.left) * (this.canvas.width / rect.width),\n (rect.bottom - e.clientY) * (this.canvas.height / rect.height),\n ];\n }\n\n private onPointerDown = (e: PointerEvent) => {\n const [x, y] = this.toPixels(e);\n this.mouse = [x, y, x, y];\n this.pointer.down(x, y, this.time);\n if (!this.playing) this.render();\n };\n\n private onPointerMove = (e: PointerEvent) => {\n const [x, y] = this.toPixels(e);\n this.pointer.move(x, y, this.time);\n if (this.mouse[2] <= 0 || e.buttons === 0) {\n if (!this.playing) this.render();\n return;\n }\n this.mouse = [x, y, this.mouse[2], this.mouse[3]];\n if (!this.playing) this.render();\n };\n\n private onPointerEnter = (e: PointerEvent) => {\n this.pointer.move(...this.toPixels(e), this.time);\n this.pointer.hover(true, this.time);\n };\n\n private onPointerLeave = () => {\n this.pointer.hover(false, this.time);\n };\n\n private onPointerUp = () => {\n this.pointer.up(this.time);\n if (this.mouse[2] > 0)\n this.mouse = [this.mouse[0], this.mouse[1], -this.mouse[2], -Math.abs(this.mouse[3])];\n };\n\n private onLost = (e: Event) => {\n e.preventDefault();\n this.shader = null;\n this.textures?.dispose();\n this.textures = null;\n this.onContextLost?.(true);\n };\n\n private onRestored = () => {\n resetGlCaches();\n this.gl = createContext(this.canvas, true, this.alpha);\n this.textures = this.gl && this.textureCache(this.gl);\n this.setSource(this.source);\n this.onContextLost?.(false);\n };\n}\n","import { imageUrls, parseControls, type ControlDef, type ControlValue } from \"./controls.js\";\nimport {\n compileShader,\n createContext,\n drawFrame,\n ShaderCompileError,\n type CompiledShader,\n} from \"./program.js\";\nimport { clicksUniform, trailUniform, type ShaderClick } from \"./pointer.js\";\nimport { TextureCache, type LiveSource } from \"./textures.js\";\n\nexport interface ShaderFramesOptions {\n source: string;\n values?: Record<string, ControlValue>;\n width: number;\n height: number;\n /** Draw on this canvas instead of a new, detached one. It is resized to `width` × `height`. */\n canvas?: HTMLCanvasElement;\n /** Keep the shader's alpha (`fragColor.a`) in the frames, for transparent recordings (default false: opaque). */\n alpha?: boolean;\n}\n\nexport interface RenderOptions {\n /** `iFrame` (default: the number of frames rendered so far). */\n frame?: number;\n /** `iTimeDelta` in seconds (default: the time since the previous `render`, else 0). */\n delta?: number;\n /** `iMouse` (default: all zero, as on a page nobody has touched). */\n mouse?: [number, number, number, number];\n /** `iPointer`: x, y, how hovered (0–1), the press (seconds held, or minus seconds since release; default all zero). */\n pointer?: [number, number, number, number];\n /** Clicks so far, for `iClicks` (the latest `MAX_CLICKS` at or before the frame's time count). */\n clicks?: readonly ShaderClick[];\n /** Where the pointer has been, oldest first, for `iTrail` (the latest `MAX_TRAIL` at or before the frame's time count). */\n trail?: readonly ShaderClick[];\n}\n\n/**\n * Renders a shader at exact times you choose, off screen. There is no\n * animation loop and no clock: frame `n` of a recording at `fps` is\n * `render(start + n / fps)`, so the output is the same on any machine. It\n * suits recorders, video pipelines and anything else stepped by its own\n * clock. The constructor throws a {@link ShaderCompileError} when the source\n * does not compile.\n *\n * Image controls load in the background: `await frames.ready()` before the\n * first `render`, or the frames show black where the images go.\n *\n * A video in an image control (see `setLiveSource`) is drawn at whatever\n * frame it is on. To step it with the shader, seek it first: `await\n * seekVideo(video, t); frames.render(t)`.\n */\nexport class ShaderFrames {\n readonly canvas: HTMLCanvasElement;\n readonly width: number;\n readonly height: number;\n readonly controls: ControlDef[];\n private gl: WebGL2RenderingContext | null;\n private shader: CompiledShader;\n private textures: TextureCache;\n private values: Record<string, ControlValue> | undefined;\n private rendered = 0;\n private lastTime: number | null = null;\n private pixels: Uint8Array;\n\n constructor(options: ShaderFramesOptions) {\n const { source, values, width, height } = options;\n this.width = Math.max(1, Math.round(width));\n this.height = Math.max(1, Math.round(height));\n this.canvas = options.canvas ?? document.createElement(\"canvas\");\n this.canvas.width = this.width;\n this.canvas.height = this.height;\n this.values = values;\n const gl = createContext(this.canvas, true, Boolean(options.alpha));\n if (!gl) throw new Error(\"WebGL2 is not available in this browser.\");\n this.gl = gl;\n this.controls = parseControls(source);\n const compiled = compileShader(gl, source, this.controls);\n if (!compiled.ok) {\n this.dispose();\n throw new ShaderCompileError(compiled.errors);\n }\n this.shader = compiled.shader;\n this.textures = new TextureCache(gl);\n this.syncTextures();\n this.pixels = new Uint8Array(this.width * this.height * 4);\n }\n\n /** Changes control values for the frames that follow. */\n setValues(values: Record<string, ControlValue> | undefined) {\n this.values = values;\n this.syncTextures();\n }\n\n /**\n * Draws a `<video>` (or a canvas) in the image control `name` instead of\n * its URL, at the frame it is on when `render` runs; `null` goes back to\n * the URL. See `ShaderRenderer.setLiveSource`.\n */\n setLiveSource(name: string, source: LiveSource | null) {\n this.textures.setLive(name, source);\n }\n\n /**\n * Settles once every image the controls show has loaded, and every live\n * video has a frame. Rejects with an {@link ImageLoadError} when one\n * cannot be.\n */\n async ready(): Promise<void> {\n await Promise.all([this.textures.ready(imageUrls(this.controls, this.values)), this.textures.liveReady()]);\n }\n\n /** Draws the frame at `time` seconds onto `canvas`. */\n render(time: number, options: RenderOptions = {}) {\n const gl = this.context();\n const delta = options.delta ?? (this.lastTime === null ? 0 : time - this.lastTime);\n drawFrame(\n gl,\n this.shader,\n this.controls,\n this.values,\n {\n width: this.width,\n height: this.height,\n time,\n delta,\n frame: options.frame ?? this.rendered,\n mouse: options.mouse ?? [0, 0, 0, 0],\n pointer: options.pointer,\n clicks: options.clicks && clicksUniform(options.clicks, time),\n trail: options.trail && trailUniform(options.trail, time),\n },\n this.textures,\n );\n this.rendered += 1;\n this.lastTime = time;\n }\n\n /**\n * The last rendered frame as RGBA bytes, rows top down (as in `ImageData`;\n * WebGL itself reads bottom up). Pass `out` to reuse a buffer of\n * `width * height * 4` bytes.\n */\n readPixels(out?: Uint8Array | Uint8ClampedArray): Uint8Array | Uint8ClampedArray {\n const gl = this.context();\n const { width, height } = this;\n const target = out ?? new Uint8Array(width * height * 4);\n if (target.length !== width * height * 4) {\n throw new RangeError(`readPixels needs a buffer of ${width * height * 4} bytes.`);\n }\n gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this.pixels);\n const row = width * 4;\n for (let y = 0; y < height; y++) {\n target.set(this.pixels.subarray((height - 1 - y) * row, (height - y) * row), y * row);\n }\n return target;\n }\n\n /** Releases the GL context now rather than at garbage collection (browsers cap live contexts). */\n dispose() {\n if (!this.gl) return;\n if (this.shader) this.gl.deleteProgram(this.shader.program);\n this.textures?.dispose();\n this.gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n this.gl = null;\n }\n\n private syncTextures() {\n const urls = imageUrls(this.controls, this.values);\n this.textures.retain(urls);\n for (const url of urls) this.textures.request(url);\n }\n\n private context(): WebGL2RenderingContext {\n if (!this.gl) throw new Error(\"These frames have been disposed.\");\n if (this.gl.isContextLost()) throw new Error(\"The graphics context was lost.\");\n return this.gl;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/export/recorder.ts"],"sourcesContent":["// gifenc ships without types; the reference brings them along.\n/// <reference path=\"../shader/gifenc.d.ts\" />\nimport http from 'node:http';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { controlValue, parseControls, type ControlValue, type TextureSettings } from '../shader/controls.js';\nimport { MAX_CLICKS, MAX_TRAIL, PointerTracker, TRAIL_SECONDS } from '../shader/pointer.js';\nimport { VERTEX_SOURCE, wrapSource } from '../shader/program.js';\nimport { SVG_EDGE } from '../shader/textures.js';\n\n// ==========================================\n// Tools: Chrome and ffmpeg\n// ==========================================\n\nconst CHROME_CANDIDATES = [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium',\n '/usr/bin/chromium-browser',\n];\n\n/** Chromium builds Playwright downloaded (`npx playwright install chromium`), newest first. */\nfunction playwrightChromes(): string[] {\n const roots = [\n process.env.PLAYWRIGHT_BROWSERS_PATH,\n path.join(os.homedir(), 'Library/Caches/ms-playwright'),\n path.join(os.homedir(), '.cache/ms-playwright'),\n ].filter((r): r is string => Boolean(r));\n const found: string[] = [];\n for (const root of roots) {\n let dirs: string[] = [];\n try {\n dirs = fs.readdirSync(root).filter((d) => /^chromium-\\d+$/.test(d));\n } catch {\n continue;\n }\n dirs.sort((a, b) => Number(b.split('-')[1]) - Number(a.split('-')[1]));\n for (const dir of dirs) {\n for (const bin of [\n 'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',\n 'chrome-mac/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',\n 'chrome-mac/Chromium.app/Contents/MacOS/Chromium',\n 'chrome-linux/chrome',\n 'chrome-linux64/chrome',\n ]) found.push(path.join(root, dir, bin));\n }\n }\n return found;\n}\n\n/**\n * Finds a local Chrome or Chromium executable, or `null`: `CHROME_PATH` (or\n * `CHROME_BIN`), then the usual install places, then a Chromium Playwright\n * downloaded.\n */\nexport function findChrome(): string | null {\n const env = process.env.CHROME_PATH || process.env.CHROME_BIN;\n if (env) return env;\n return [...CHROME_CANDIDATES, ...playwrightChromes()].find((candidate) => fs.existsSync(candidate)) ?? null;\n}\n\n/** The ffmpeg to run: `FFMPEG_PATH`, else `ffmpeg` on the `PATH`. */\nexport function ffmpegPath(): string {\n return process.env.FFMPEG_PATH || 'ffmpeg';\n}\n\nconst NO_FFMPEG =\n 'ffmpeg is not installed (or not on the PATH). Install it (brew install ffmpeg, apt install ffmpeg), or set FFMPEG_PATH; GIF, PNG and SVG output do not need it.';\n\n// ==========================================\n// Output formats\n// ==========================================\n\n/** A file type the exporter writes, from the output path. */\nexport type OutputFormat = 'mp4' | 'webm' | 'mov' | 'gif' | 'png' | 'svg';\n\n/** What to write and how. */\nexport interface OutputPlan {\n format: OutputFormat;\n /** The output path, resolved. For a PNG sequence, a printf pattern (`…/frame_%04d.png`). */\n path: string;\n /** Whether the frames keep their alpha. */\n alpha: boolean;\n /** ffmpeg's arguments after the input (for mp4, webm and mov). */\n ffmpegArgs?: string[];\n}\n\n/**\n * Works out the format from `outputPath`'s extension and what alpha it can\n * keep. A path with no extension, or ending in a slash, is a folder of PNG\n * frames; a `.png` path with a `%d` pattern (`out_%04d.png`) names each\n * frame, and one without gets `_%04d` added (unless there is one frame).\n * Throws a sentence for formats it cannot write, and for alpha in MP4.\n */\nexport function planOutput(outputPath: string, options: { alpha?: boolean; frames?: number } = {}): OutputPlan {\n const resolved = path.resolve(process.cwd(), outputPath);\n const trailingSlash = /[\\\\/]$/.test(outputPath);\n const ext = trailingSlash ? '' : path.extname(resolved).toLowerCase();\n const alpha = Boolean(options.alpha);\n switch (ext) {\n case '': {\n return { format: 'png', path: path.join(resolved, 'frame_%04d.png'), alpha };\n }\n case '.png': {\n if (/%0?\\d*d/.test(resolved) || (options.frames ?? 2) === 1) return { format: 'png', path: resolved, alpha };\n return { format: 'png', path: resolved.replace(/\\.png$/i, '_%04d.png'), alpha };\n }\n case '.gif':\n return { format: 'gif', path: resolved, alpha };\n case '.svg':\n return { format: 'svg', path: resolved, alpha };\n case '.mp4':\n case '.m4v': {\n if (alpha) throw new Error('MP4 (H.264) cannot hold alpha; write .webm, .mov, .gif or .png frames for a transparent render, or drop --alpha.');\n return {\n format: 'mp4',\n path: resolved,\n alpha,\n ffmpegArgs: [\n // yuv420p needs even sizes; sRGB pixels go to BT.709, tagged so players show the same colours.\n '-vf', 'pad=ceil(iw/2)*2:ceil(ih/2)*2,scale=out_color_matrix=bt709:out_range=tv,format=yuv420p',\n '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-crf', '18', '-preset', 'medium',\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709', '-color_range', 'tv',\n '-movflags', '+faststart',\n ],\n };\n }\n case '.webm':\n return {\n format: 'webm',\n path: resolved,\n alpha,\n ffmpegArgs: alpha\n ? ['-c:v', 'libvpx-vp9', '-pix_fmt', 'yuva420p', '-b:v', '0', '-crf', '30', '-auto-alt-ref', '0', '-row-mt', '1']\n : ['-vf', 'scale=out_color_matrix=bt709:out_range=tv,format=yuv420p', '-c:v', 'libvpx-vp9', '-pix_fmt', 'yuv420p', '-b:v', '0', '-crf', '30', '-row-mt', '1',\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709'],\n };\n case '.mov':\n return {\n format: 'mov',\n path: resolved,\n alpha,\n ffmpegArgs: [\n '-c:v', 'prores_ks', '-profile:v', '4444', '-vendor', 'apl0',\n '-pix_fmt', alpha ? 'yuva444p10le' : 'yuv444p10le',\n ...(alpha ? ['-alpha_bits', '16'] : []),\n '-colorspace', 'bt709', '-color_primaries', 'bt709', '-color_trc', 'bt709',\n ],\n };\n default:\n throw new Error(`Flair cannot write \"${ext}\" files; write .mp4, .webm, .mov, .gif, .svg, or .png frames (a folder, or a pattern like out_%04d.png).`);\n }\n}\n\n/** A frame number put into a PNG sequence's printf pattern (`%04d`, `%d`). */\nexport function sequencePath(pattern: string, frame: number): string {\n return pattern.replace(/%(0?)(\\d*)d/, (_, zero: string, width: string) => String(frame).padStart(Number(width || 0), zero ? '0' : ' '));\n}\n\n// ==========================================\n// The pointer, scripted\n// ==========================================\n\n/** Pointer uniforms for one frame. */\nexport interface PointerFrame {\n mouse: [number, number, number, number];\n pointer: [number, number, number, number];\n /** `iClicks`, MAX_CLICKS × 4 numbers. */\n clicks: number[];\n /** `iTrail`, MAX_TRAIL × 4 numbers. */\n trail: number[];\n}\n\n/**\n * A pointer that shows off an interactive shader in a recording: it hovers\n * over the canvas from the start, wanders a figure-of-eight (so trails have\n * a path), and clicks every `interval` seconds, holding each press for a\n * moment. Returns the uniforms for each frame time, in order.\n */\nexport function scriptedPointer(width: number, height: number, times: readonly number[], options: { interval?: number; period?: number } = {}): PointerFrame[] {\n const interval = options.interval ?? 0.8;\n const period = Math.max(2, options.period ?? (times[times.length - 1] ?? 2));\n const at = (t: number): [number, number] => [\n width * (0.5 + 0.3 * Math.sin((2 * Math.PI * t) / period)),\n height * (0.5 + 0.22 * Math.sin((4 * Math.PI * t) / period)),\n ];\n const press = 0.25;\n const tracker = new PointerTracker();\n tracker.hover(true, 0);\n tracker.move(...at(0), 0);\n let clock = 0;\n let nextClick = 0.25;\n let release = Infinity;\n let mouse: [number, number, number, number] = [0, 0, 0, 0];\n const frames: PointerFrame[] = [];\n for (const time of times) {\n // Walk the script up to `time` in trail-sized steps, so the trail and clicks land where they would live.\n while (clock < time) {\n const next = Math.min(time, clock + TRAIL_SECONDS, nextClick, release);\n clock = next;\n const [x, y] = at(clock);\n tracker.move(x, y, clock);\n if (mouse[2] > 0) mouse = [x, y, mouse[2], mouse[3]];\n if (clock >= release) {\n tracker.up(clock);\n mouse = [mouse[0], mouse[1], -mouse[2], -Math.abs(mouse[3])];\n release = Infinity;\n }\n if (clock >= nextClick) {\n tracker.down(x, y, clock);\n mouse = [x, y, x, y];\n release = clock + press;\n nextClick = clock + interval;\n }\n }\n frames.push({\n mouse: [...mouse],\n pointer: tracker.pointer(time),\n clicks: [...tracker.clicksAt(time)],\n trail: [...tracker.trailAt(time)],\n });\n }\n return frames;\n}\n\n// ==========================================\n// The page\n// ==========================================\n\n/** A shader control as the page sets it. */\nexport interface PageControl {\n name: string;\n type: string;\n value: ControlValue;\n texture?: TextureSettings;\n}\n\n/** What the render page draws. */\nexport interface PageConfig {\n width: number;\n height: number;\n frames: number;\n /** Keep alpha in the frames (else they are composited over `background`). */\n alpha: boolean;\n /** CSS colour under transparent pixels when `alpha` is false. */\n background: string;\n /** How frames go back: PNG files, or raw RGBA (rows top down). */\n send: 'png' | 'rgba';\n /** A shader to run, or (when absent) SVG frame markup from `/state`. */\n shader?: {\n /** The full GLSL ES 3.00 fragment shader (see {@link fragmentSource}). */\n fragment: string;\n controls: PageControl[];\n /** Draws its frame opaque, as `ShaderRenderer` does without `alpha`: its own alpha is ignored. */\n opaque: boolean;\n };\n}\n\n/** JSON that is safe inside a `<script>`. */\nconst scriptJson = (value: unknown) => JSON.stringify(value).replace(/</g, '\\\\u003c');\n\n/**\n * The page headless Chrome runs: it compiles the shader with the same\n * wrapper as `ShaderRenderer` (`wrapSource`, so every built-in, `iPointer`,\n * `iClicks` and `iTrail` included, is declared), sets each control by its\n * type (`int` and `bool` as integers), loads image controls the way\n * `loadImage` does (SVGs sized to their long edge first) before the first\n * frame, and flips them as the renderer does. Each frame asks `/state` for\n * its time, pointer, video frames or SVG markup, draws, and posts the\n * pixels to `/frame`.\n */\nexport function renderPageHtml(config: PageConfig): string {\n return `<!doctype html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<style>html,body{margin:0;background:transparent;overflow:hidden}</style>\n</head>\n<body>\n<script>\nconst CONFIG = ${scriptJson(config)};\nconst VERTEX = ${scriptJson(VERTEX_SOURCE)};\nconst W = CONFIG.width, H = CONFIG.height;\nconst report = (message) => fetch(\"/error\", { method: \"POST\", body: String(message) });\naddEventListener(\"error\", (e) => report(\"The render page failed: \" + e.message));\naddEventListener(\"unhandledrejection\", (e) => report((e.reason && e.reason.message) || String(e.reason)));\n\n// SVGs decode at their own (often icon) size: give them ${SVG_EDGE} px on the long edge, and a viewBox.\nfunction sizeSvg(markup, w0, h0) {\n const doc = new DOMParser().parseFromString(markup, \"image/svg+xml\");\n const svg = doc.documentElement;\n if (svg.localName !== \"svg\" || doc.getElementsByTagName(\"parsererror\").length) throw new Error(\"Not an SVG document.\");\n const len = (n) => { const m = (svg.getAttribute(n) || \"\").trim().match(/^([\\\\d.]+)(px)?$/); return m && +m[1] > 0 ? +m[1] : 0; };\n const box = (svg.getAttribute(\"viewBox\") || \"\").trim().split(/[\\\\s,]+/).map(Number);\n const hasBox = box.length === 4 && box[2] > 0 && box[3] > 0;\n const w = len(\"width\") || (hasBox ? box[2] : 300), h = len(\"height\") || (hasBox ? box[3] : 150);\n if (!hasBox) svg.setAttribute(\"viewBox\", \"0 0 \" + w + \" \" + h);\n const scale = w0 ? 1 : ${SVG_EDGE} / Math.max(w, h);\n svg.setAttribute(\"width\", w0 || Math.max(1, Math.round(w * scale)));\n svg.setAttribute(\"height\", h0 || Math.max(1, Math.round(h * scale)));\n return new XMLSerializer().serializeToString(svg);\n}\nconst isSvg = (url) => /^data:image\\\\/svg\\\\+xml[;,]/i.test(url) || /^(?!data:)[^?#]*\\\\.svg([?#]|$)/i.test(url);\nasync function decode(src, name) {\n const img = new Image();\n img.src = src;\n try { await img.decode(); } catch (e) { throw new Error(\"Could not load the image \" + name + \".\"); }\n return img;\n}\nasync function loadImage(url, name) {\n if (!isSvg(url)) return decode(url, name);\n const text = await (await fetch(url)).text();\n const blob = URL.createObjectURL(new Blob([sizeSvg(text)], { type: \"image/svg+xml\" }));\n try { return await decode(blob, name); } finally { URL.revokeObjectURL(blob); }\n}\n\nconst out = document.createElement(\"canvas\");\nout.width = W; out.height = H;\nconst ctx = out.getContext(\"2d\", { willReadFrequently: CONFIG.send === \"rgba\" });\nlet gl = null, glCanvas = null, u = null;\nconst textures = {};\n\nfunction setupShader() {\n glCanvas = document.createElement(\"canvas\");\n glCanvas.width = W; glCanvas.height = H;\n // As createContext: no antialiasing, depth or stencil; unpremultiplied alpha so pixels read back exactly.\n gl = glCanvas.getContext(\"webgl2\", { alpha: true, premultipliedAlpha: false, preserveDrawingBuffer: true, antialias: false, depth: false, stencil: false, powerPreference: \"high-performance\" });\n if (!gl) throw new Error(\"WebGL2 is not available in headless Chrome.\");\n const compile = (type, src) => {\n const s = gl.createShader(type);\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(\"The shader does not compile: \" + gl.getShaderInfoLog(s));\n return s;\n };\n const program = gl.createProgram();\n gl.attachShader(program, compile(gl.VERTEX_SHADER, VERTEX));\n gl.attachShader(program, compile(gl.FRAGMENT_SHADER, CONFIG.shader.fragment));\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(\"The shader does not link: \" + gl.getProgramInfoLog(program));\n gl.useProgram(program);\n u = (n) => gl.getUniformLocation(program, n);\n gl.viewport(0, 0, W, H);\n if (CONFIG.shader.opaque) {\n // An opaque canvas, as ShaderRenderer has without alpha: alpha stays 1 whatever the shader writes.\n gl.clearColor(0, 0, 0, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.colorMask(true, true, true, false);\n }\n}\n\nfunction makeTexture(unit, texture) {\n const t = gl.createTexture();\n const settings = texture || { filter: \"mipmap\", wrap: \"repeat\" };\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, t);\n // Black until (or unless) a picture arrives, as TextureCache does.\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255]));\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, { mipmap: gl.LINEAR_MIPMAP_LINEAR, linear: gl.LINEAR, nearest: gl.NEAREST }[settings.filter]);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, settings.filter === \"nearest\" ? gl.NEAREST : gl.LINEAR);\n const wrap = { repeat: gl.REPEAT, clamp: gl.CLAMP_TO_EDGE, mirror: gl.MIRRORED_REPEAT }[settings.wrap];\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);\n return { unit, texture: t };\n}\n\nfunction upload(name, img) {\n const slot = textures[name];\n if (!slot) return;\n gl.activeTexture(gl.TEXTURE0 + slot.unit);\n gl.bindTexture(gl.TEXTURE_2D, slot.texture);\n // Rows bottom up, as the renderer's TextureCache uploads them.\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.generateMipmap(gl.TEXTURE_2D);\n}\n\nasync function setControls() {\n let unit = 0;\n const loads = [];\n for (const c of CONFIG.shader.controls) {\n const loc = u(c.name);\n const v = c.value;\n if (c.type === \"sampler2D\") {\n textures[c.name] = makeTexture(unit, c.texture);\n if (loc) gl.uniform1i(loc, unit);\n unit++;\n if (v) loads.push(loadImage(v, \"for \" + c.name).then((img) => upload(c.name, img)));\n continue;\n }\n if (!loc) continue;\n if (c.type === \"float\") gl.uniform1f(loc, v);\n else if (c.type === \"int\") gl.uniform1i(loc, Math.round(v));\n else if (c.type === \"bool\") gl.uniform1i(loc, v ? 1 : 0);\n else if (Array.isArray(v)) gl[\"uniform\" + v.length + \"fv\"](loc, v);\n }\n await Promise.all(loads);\n}\n\nfunction drawShader(s) {\n gl.viewport(0, 0, W, H);\n const set = (n, f) => { const l = u(n); if (l) f(l); };\n set(\"iResolution\", (l) => gl.uniform3f(l, W, H, 1));\n set(\"iTime\", (l) => gl.uniform1f(l, s.time));\n set(\"iTimeDelta\", (l) => gl.uniform1f(l, s.delta));\n set(\"iFrame\", (l) => gl.uniform1i(l, s.frame));\n set(\"iMouse\", (l) => gl.uniform4fv(l, s.mouse));\n set(\"iPointer\", (l) => gl.uniform4fv(l, s.pointer));\n set(\"iClicks\", (l) => gl.uniform4fv(l, new Float32Array(s.clicks)));\n set(\"iTrail\", (l) => gl.uniform4fv(l, new Float32Array(s.trail)));\n // glslsandbox-style names, for complete programs.\n set(\"u_resolution\", (l) => gl.uniform2f(l, W, H));\n set(\"u_time\", (l) => gl.uniform1f(l, s.time));\n set(\"u_mouse\", (l) => gl.uniform2f(l, s.pointer[0], s.pointer[1]));\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nasync function frameImage(s) {\n if (CONFIG.shader) {\n for (const [name, url] of Object.entries(s.video || {})) upload(name, await decode(url, \"of the video frame\"));\n drawShader(s);\n return glCanvas;\n }\n const markup = sizeSvg(s.svg, W, H);\n const url = URL.createObjectURL(new Blob([markup], { type: \"image/svg+xml\" }));\n try { return await decode(url, \"of the SVG frame\"); } finally { URL.revokeObjectURL(url); }\n}\n\nasync function capture(src) {\n // The WebGL canvas reads back exactly when nothing is composited under it.\n const direct = CONFIG.shader && (CONFIG.alpha || CONFIG.shader.opaque);\n if (direct) {\n if (CONFIG.send === \"png\") return new Promise((r) => glCanvas.toBlob(r, \"image/png\"));\n const px = new Uint8Array(W * H * 4);\n gl.readPixels(0, 0, W, H, gl.RGBA, gl.UNSIGNED_BYTE, px);\n const flipped = new Uint8Array(px.length), row = W * 4;\n for (let y = 0; y < H; y++) flipped.set(px.subarray((H - 1 - y) * row, (H - y) * row), y * row);\n return flipped;\n }\n ctx.clearRect(0, 0, W, H);\n if (!CONFIG.alpha) { ctx.fillStyle = CONFIG.background; ctx.fillRect(0, 0, W, H); }\n ctx.drawImage(src, 0, 0, W, H);\n if (CONFIG.send === \"png\") return new Promise((r) => out.toBlob(r, \"image/png\"));\n return ctx.getImageData(0, 0, W, H).data;\n}\n\n(async () => {\n if (CONFIG.shader) { setupShader(); await setControls(); }\n for (let i = 0; i < CONFIG.frames; i++) {\n const s = await (await fetch(\"/state?i=\" + i)).json();\n const body = await capture(await frameImage(s));\n const r = await fetch(\"/frame?i=\" + i, { method: \"POST\", body });\n if (!r.ok) return;\n }\n})().catch((e) => report((e && e.message) || String(e)));\n</script>\n</body>\n</html>\n`;\n}\n\n// ==========================================\n// The render loop\n// ==========================================\n\n/** One frame's state, as the page asks for it. */\nexport interface FrameState {\n time: number;\n delta: number;\n frame: number;\n mouse: [number, number, number, number];\n pointer: [number, number, number, number];\n clicks: number[];\n trail: number[];\n /** SVG markup to draw (vector frames). */\n svg?: string;\n /** Image control → local file to show this frame (video frames). */\n video?: Record<string, string>;\n}\n\n/** A render: the page to run, each frame's state, and where it goes. */\nexport interface RenderJob {\n page: PageConfig;\n state: (frame: number) => FrameState;\n plan: OutputPlan;\n fps: number;\n onProgress?: (frame: number, total: number) => void;\n}\n\n/** Frames written somewhere: a sink takes them in order and finishes. */\ninterface Sink {\n write(frame: number, data: Buffer): Promise<void>;\n finish(): Promise<void>;\n abort(): void;\n}\n\nfunction ffmpegSink(plan: OutputPlan, fps: number): Sink {\n const args = ['-y', '-hide_banner', '-loglevel', 'error', '-f', 'image2pipe', '-framerate', String(fps), '-c:v', 'png', '-i', '-', ...plan.ffmpegArgs!, '-r', String(fps), plan.path];\n const proc = spawn(ffmpegPath(), args, { stdio: ['pipe', 'ignore', 'pipe'] });\n let stderr = '';\n let failed: Error | null = null;\n proc.stderr!.on('data', (d) => (stderr += d.toString()));\n const done = new Promise<void>((resolve, reject) => {\n proc.on('error', (err: NodeJS.ErrnoException) => {\n failed = err.code === 'ENOENT' ? new Error(NO_FFMPEG) : new Error(`ffmpeg could not start: ${err.message}`);\n reject(failed);\n });\n proc.on('close', (code) => {\n if (code === 0) resolve();\n else reject((failed ??= new Error(`ffmpeg failed (exit ${code}): ${stderr.trim() || 'no message'}`)));\n });\n });\n done.catch(() => {});\n proc.stdin!.on('error', () => {});\n return {\n async write(_frame, data) {\n if (failed) throw failed;\n if (!proc.stdin!.write(data)) await new Promise((r) => proc.stdin!.once('drain', r));\n },\n async finish() {\n proc.stdin!.end();\n await done;\n },\n abort() {\n proc.kill('SIGKILL');\n },\n };\n}\n\nfunction pngSink(plan: OutputPlan): Sink {\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n return {\n async write(frame, data) {\n await fs.promises.writeFile(plan.path.includes('%') ? sequencePath(plan.path, frame) : plan.path, data);\n },\n async finish() {},\n abort() {},\n };\n}\n\nasync function gifSink(plan: OutputPlan, width: number, height: number, fps: number): Promise<Sink> {\n // gifenc is CommonJS in Node: its functions may only be on the default export.\n const mod = (await import('gifenc')) as Partial<typeof import('gifenc')> & { default?: typeof import('gifenc') };\n const { GIFEncoder, quantize, applyPalette } = (typeof mod.GIFEncoder === 'function' ? mod : mod.default!) as typeof import('gifenc');\n const gif = GIFEncoder();\n const delay = 1000 / fps;\n return {\n async write(frame, data) {\n const rgba = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n const first = frame === 0 ? { repeat: 0 } : {};\n if (plan.alpha) {\n // One-bit alpha: each frame replaces the last (dispose 2), with a transparent palette entry.\n const palette = quantize(rgba, 256, { format: 'rgba4444', oneBitAlpha: true });\n const transparentIndex = palette.findIndex((c) => c[3] === 0);\n gif.writeFrame(applyPalette(rgba, palette, 'rgba4444'), width, height, {\n palette,\n delay,\n dispose: 2,\n ...(transparentIndex >= 0 ? { transparent: true, transparentIndex } : {}),\n ...first,\n });\n } else {\n const palette = quantize(rgba, 256);\n gif.writeFrame(applyPalette(rgba, palette), width, height, { palette, delay, ...first });\n }\n },\n async finish() {\n gif.finish();\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n await fs.promises.writeFile(plan.path, gif.bytes());\n },\n abort() {},\n };\n}\n\n/** Chrome's flags: GPU WebGL where there is one (Metal on macOS), SwiftShader otherwise. */\nfunction chromeArgs(userDataDir: string, width: number, height: number, url: string): string[] {\n return [\n '--headless=new',\n `--user-data-dir=${userDataDir}`,\n `--window-size=${Math.max(64, width)},${Math.max(64, height)}`,\n '--use-gl=angle',\n ...(process.platform === 'darwin' ? ['--use-angle=metal'] : []),\n '--enable-webgl',\n '--enable-unsafe-swiftshader',\n '--ignore-gpu-blocklist',\n '--disable-gpu-sandbox',\n '--force-color-profile=srgb',\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-renderer-backgrounding',\n '--disable-extensions',\n url,\n ];\n}\n\nconst STALL_MS = 60_000;\n\n/**\n * Runs a render: serves the page to headless Chrome on 127.0.0.1, hands it\n * each frame's state, and writes the frames it posts back. Resolves with the\n * output path (a PNG sequence's pattern).\n */\nexport async function runRender(job: RenderJob): Promise<string> {\n const { page, plan, fps, onProgress } = job;\n const total = page.frames;\n const chromeBin = findChrome();\n if (!chromeBin) {\n throw new Error('Chrome or Chromium is needed to render, and none was found. Install Google Chrome, run \"npx playwright install chromium\", or set CHROME_PATH.');\n }\n fs.mkdirSync(path.dirname(plan.path), { recursive: true });\n const sink = plan.format === 'gif' ? await gifSink(plan, page.width, page.height, fps) : plan.format === 'png' ? pngSink(plan) : ffmpegSink(plan, fps);\n const html = renderPageHtml(page);\n const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flair-chrome-'));\n\n return new Promise<string>((resolve, reject) => {\n let chrome: ChildProcess | null = null;\n let finished = false;\n let written = 0;\n let stall: NodeJS.Timeout | undefined;\n const sockets = new Set<import('node:net').Socket>();\n\n const cleanup = () => {\n clearTimeout(stall);\n try {\n chrome?.kill('SIGKILL');\n } catch {}\n for (const s of sockets) s.destroy();\n server.close();\n fs.rm(userDataDir, { recursive: true, force: true }, () => {});\n };\n const fail = (err: Error) => {\n if (finished) return;\n finished = true;\n sink.abort();\n cleanup();\n reject(err);\n };\n const succeed = () => {\n if (finished) return;\n finished = true;\n cleanup();\n resolve(plan.path);\n };\n const watchdog = () => {\n clearTimeout(stall);\n stall = setTimeout(() => fail(new Error(`The render stalled: no frame for ${STALL_MS / 1000} s after frame ${written} of ${total}. Is WebGL2 available to headless Chrome?`)), STALL_MS);\n };\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || '/', 'http://127.0.0.1');\n if (url.pathname === '/' && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-store' });\n res.end(html);\n return;\n }\n if (url.pathname === '/state') {\n const i = Number(url.searchParams.get('i'));\n try {\n const s = job.state(i);\n const body = { ...s, ...(s.video ? { video: Object.fromEntries(Object.keys(s.video).map((k) => [k, `/video?i=${i}&name=${encodeURIComponent(k)}`])) } : {}) };\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(body));\n } catch (e) {\n res.writeHead(500);\n res.end();\n fail(e as Error);\n }\n return;\n }\n if (url.pathname === '/video') {\n const i = Number(url.searchParams.get('i'));\n const file = job.state(i).video?.[url.searchParams.get('name') ?? ''];\n if (!file) {\n res.writeHead(404);\n res.end();\n return;\n }\n res.writeHead(200, { 'Content-Type': 'image/png' });\n fs.createReadStream(file).pipe(res);\n return;\n }\n if (url.pathname === '/frame' && req.method === 'POST') {\n const i = Number(url.searchParams.get('i'));\n const chunks: Buffer[] = [];\n req.on('data', (c: Buffer) => chunks.push(c));\n req.on('end', () => {\n sink\n .write(i, Buffer.concat(chunks))\n .then(async () => {\n written++;\n watchdog();\n onProgress?.(written, total);\n res.writeHead(200);\n res.end('ok');\n if (written >= total) {\n await sink.finish();\n succeed();\n }\n })\n .catch((e: Error) => {\n res.writeHead(500);\n res.end();\n fail(e);\n });\n });\n return;\n }\n if (url.pathname === '/error' && req.method === 'POST') {\n let message = '';\n req.on('data', (c) => (message += c));\n req.on('end', () => {\n res.writeHead(200);\n res.end();\n fail(new Error(message || 'The render page failed.'));\n });\n return;\n }\n res.writeHead(404);\n res.end();\n });\n server.on('connection', (s) => {\n sockets.add(s);\n s.on('close', () => sockets.delete(s));\n });\n\n server.listen(0, '127.0.0.1', () => {\n const { port } = server.address() as import('node:net').AddressInfo;\n chrome = spawn(chromeBin, chromeArgs(userDataDir, page.width, page.height, `http://127.0.0.1:${port}/`), { stdio: 'ignore' });\n chrome.on('error', (err) => fail(new Error(`Could not launch Chrome at ${chromeBin}: ${err.message}`)));\n chrome.on('exit', (code) => {\n if (!finished && written < total) fail(new Error(`Chrome quit (exit ${code}) after ${written} of ${total} frames.`));\n });\n watchdog();\n });\n });\n}\n\n// ==========================================\n// Shader export\n// ==========================================\n\n/** Where the pointer is in a recording: nowhere (`none`), or the scripted pointer of {@link scriptedPointer} (`auto`). */\nexport type PointerMode = 'none' | 'auto';\n\nexport interface ExportOptions {\n /** GLSL fragment shader source (Shadertoy-style `mainImage`). */\n source: string;\n /**\n * Control values over the declared defaults. An image control takes a\n * URL, a `data:` URL, or a local file path (read into a `data:` URL).\n */\n values?: Record<string, ControlValue>;\n /** Destination: .mp4, .webm, .mov, .gif, or PNG frames (a folder or `out_%04d.png`). */\n outputPath: string;\n width?: number;\n height?: number;\n fps?: number;\n /** Seconds (default 3). */\n duration?: number;\n /** Keep the shader's alpha (WebM, MOV, GIF and PNG; MP4 is always opaque). */\n alpha?: boolean;\n /**\n * The shader draws over other content (`fragColor.a` is coverage): without\n * `alpha` it is composited over `background`. Otherwise its alpha is\n * ignored without `alpha`, as on an opaque canvas.\n */\n transparent?: boolean;\n /** CSS colour under transparent pixels when `alpha` is off (default black). */\n background?: string;\n /** The pointer: `none` (default) or `auto`, a scripted pointer that hovers, wanders and clicks. */\n pointer?: PointerMode;\n onProgress?: (frame: number, total: number) => void;\n}\n\nconst MIME: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.svg': 'image/svg+xml',\n};\n\n/**\n * An image for the page, as a `data:` URL: a local file is read, an\n * `http(s):` URL fetched (so CORS does not matter); `data:` URLs stay.\n */\nexport async function imageDataUrl(source: string, cwd = process.cwd()): Promise<string> {\n if (/^data:/i.test(source) || source === '') return source;\n if (/^https?:/i.test(source)) {\n const res = await fetch(source);\n if (!res.ok) throw new Error(`Could not download the image at ${source} (HTTP ${res.status}).`);\n const type = res.headers.get('content-type')?.split(';')[0] || MIME[path.extname(new URL(source).pathname).toLowerCase()] || 'application/octet-stream';\n return `data:${type};base64,${Buffer.from(await res.arrayBuffer()).toString('base64')}`;\n }\n const file = path.resolve(cwd, source.replace(/^file:\\/\\//, ''));\n if (!fs.existsSync(file)) throw new Error(`There is no image at ${file}.`);\n const type = MIME[path.extname(file).toLowerCase()];\n if (!type) throw new Error(`${path.basename(file)} is not an image Flair can show; give it a PNG, JPEG, GIF, WebP, AVIF, BMP or SVG.`);\n return `data:${type};base64,${fs.readFileSync(file).toString('base64')}`;\n}\n\n/**\n * The fragment shader the page compiles: a Shadertoy-style `mainImage`\n * source goes in `wrapSource`, as `ShaderRenderer` compiles it. A complete\n * program (one with its own `void main()`, glslsandbox-style, reading\n * `u_time` and `u_resolution`) is kept as written, with `#version 300 es`\n * added when it has none.\n */\nexport function fragmentSource(source: string): string {\n if (!/\\bvoid\\s+main\\s*\\(\\s*\\)/.test(source)) return wrapSource(source);\n return /^\\s*#version\\b/.test(source) ? source : `#version 300 es\\n#line 1\\n${source}`;\n}\n\n/** Shader controls with their values, images as `data:` URLs, ready for the page. */\nexport async function pageControls(source: string, values: Record<string, ControlValue> = {}): Promise<PageControl[]> {\n return Promise.all(\n parseControls(source).map(async (c) => {\n let value = controlValue(c, values);\n if (c.type === 'sampler2D' && typeof value === 'string') value = await imageDataUrl(value);\n return { name: c.name, type: c.type, value, ...(c.texture ? { texture: c.texture } : {}) };\n }),\n );\n}\n\n/** Frame times and pointer uniforms for `frames` frames at `fps`. */\nexport function frameStates(frames: number, fps: number, width: number, height: number, pointer: PointerMode): FrameState[] {\n const times = Array.from({ length: frames }, (_, i) => i / fps);\n const scripted = pointer === 'auto' ? scriptedPointer(width, height, times) : undefined;\n const none = { mouse: [0, 0, 0, 0] as [number, number, number, number], pointer: [0, 0, 0, 0] as [number, number, number, number], clicks: new Array(MAX_CLICKS * 4).fill(0), trail: new Array(MAX_TRAIL * 4).fill(0) };\n return times.map((time, i) => ({ time, delta: i === 0 ? 0 : 1 / fps, frame: i, ...(scripted?.[i] ?? none) }));\n}\n\n/**\n * Renders a shader animation frame by frame with WebGL2 in headless Chrome,\n * the way `ShaderRenderer` draws it (the same GLSL wrapper and built-ins,\n * images, int and bool controls), and writes MP4 (H.264), WebM (VP9, with\n * alpha when asked), MOV (ProRes 4444), GIF or PNG frames. MP4, WebM and\n * MOV need ffmpeg; GIF and PNG do not.\n */\nexport async function exportMotionGraphic(options: ExportOptions): Promise<string> {\n const { source, values = {}, outputPath, fps = 30, duration = 3, onProgress } = options;\n const width = Math.max(1, Math.round(options.width ?? 720));\n const height = Math.max(1, Math.round(options.height ?? 720));\n const frames = Math.max(1, Math.round(duration * fps));\n const plan = planOutput(outputPath, { alpha: options.alpha, frames });\n if (plan.format === 'svg') throw new Error('A shader cannot be written as SVG; write .mp4, .webm, .mov, .gif or .png frames.');\n const states = frameStates(frames, fps, width, height, options.pointer ?? 'none');\n return runRender({\n page: {\n width,\n height,\n frames,\n alpha: plan.alpha,\n background: options.background ?? '#000000',\n send: plan.format === 'gif' ? 'rgba' : 'png',\n shader: {\n fragment: fragmentSource(source),\n controls: await pageControls(source, values),\n opaque: !plan.alpha && !options.transparent,\n },\n },\n state: (i) => states[i]!,\n plan,\n fps,\n onProgress,\n });\n}\n"],"mappings":"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","names":["type"]}