@bendyline/squisq 1.5.2 → 2.0.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 (263) hide show
  1. package/README.md +63 -10
  2. package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
  3. package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
  4. package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
  5. package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
  6. package/dist/chunk-3E5F2XMR.js.map +1 -0
  7. package/dist/chunk-4X3JQXNM.js +35 -0
  8. package/dist/chunk-4X3JQXNM.js.map +1 -0
  9. package/dist/{chunk-P3K7NLHF.js → chunk-5DKBFXPY.js} +31 -121
  10. package/dist/chunk-5DKBFXPY.js.map +1 -0
  11. package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
  12. package/dist/chunk-5J4HKRJF.js.map +1 -0
  13. package/dist/chunk-5UYI3RJB.js +2503 -0
  14. package/dist/chunk-5UYI3RJB.js.map +1 -0
  15. package/dist/{chunk-BEQODJWV.js → chunk-66QO7XFB.js} +11 -291
  16. package/dist/chunk-66QO7XFB.js.map +1 -0
  17. package/dist/{chunk-KKNUBQ6Y.js → chunk-6PJRB2CF.js} +156 -91
  18. package/dist/chunk-6PJRB2CF.js.map +1 -0
  19. package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
  20. package/dist/chunk-AMIR72JP.js.map +1 -0
  21. package/dist/chunk-FVJUUTEM.js +74 -0
  22. package/dist/chunk-FVJUUTEM.js.map +1 -0
  23. package/dist/{chunk-5TYS5V3G.js → chunk-GF3BVNLU.js} +4127 -3538
  24. package/dist/chunk-GF3BVNLU.js.map +1 -0
  25. package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
  26. package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
  27. package/dist/chunk-JOQYPRDZ.js +127 -0
  28. package/dist/chunk-JOQYPRDZ.js.map +1 -0
  29. package/dist/{chunk-A4O7GIWE.js → chunk-LYNJEOAC.js} +10 -73
  30. package/dist/chunk-LYNJEOAC.js.map +1 -0
  31. package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
  32. package/dist/chunk-PXLVXTLW.js.map +1 -0
  33. package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
  34. package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
  35. package/dist/{chunk-T5UK6YOB.js → chunk-QTSJOY54.js} +60 -17
  36. package/dist/chunk-QTSJOY54.js.map +1 -0
  37. package/dist/chunk-QVANWDPH.js +2358 -0
  38. package/dist/chunk-QVANWDPH.js.map +1 -0
  39. package/dist/{chunk-GPLTCSXO.js → chunk-R2GC6RLD.js} +7 -7
  40. package/dist/chunk-R2GC6RLD.js.map +1 -0
  41. package/dist/chunk-R2YZTCLO.js +292 -0
  42. package/dist/chunk-R2YZTCLO.js.map +1 -0
  43. package/dist/chunk-S7A5D7ZJ.js +174 -0
  44. package/dist/chunk-S7A5D7ZJ.js.map +1 -0
  45. package/dist/chunk-T3TI7GSZ.js +884 -0
  46. package/dist/chunk-T3TI7GSZ.js.map +1 -0
  47. package/dist/{chunk-LTN6I7QW.js → chunk-TUWMK62B.js} +55 -4
  48. package/dist/chunk-TUWMK62B.js.map +1 -0
  49. package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
  50. package/dist/chunk-VR7UPJ7C.js.map +1 -0
  51. package/dist/doc/index.d.ts +2334 -5
  52. package/dist/doc/index.js +127 -33
  53. package/dist/generate/index.d.ts +7 -2
  54. package/dist/generate/index.js +1 -1
  55. package/dist/imageEdit/index.d.ts +9 -6
  56. package/dist/imageEdit/index.js +3 -3
  57. package/dist/index.d.ts +12 -10
  58. package/dist/index.js +246 -80
  59. package/dist/jsonForm/index.d.ts +7 -3
  60. package/dist/jsonForm/index.js +9 -4
  61. package/dist/markdown/index.d.ts +6 -70
  62. package/dist/markdown/index.js +13 -9
  63. package/dist/narration/index.d.ts +618 -0
  64. package/dist/narration/index.js +82 -0
  65. package/dist/recommend/index.d.ts +15 -1
  66. package/dist/recommend/index.js +2 -2
  67. package/dist/schemas/index.d.ts +28 -6
  68. package/dist/schemas/index.js +15 -13
  69. package/dist/spatial/index.d.ts +0 -1
  70. package/dist/spatial/index.js +1 -1
  71. package/dist/storage/index.js +1 -1
  72. package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
  73. package/dist/timing/index.js +5 -3
  74. package/dist/transform/index.d.ts +35 -24
  75. package/dist/transform/index.js +9 -10
  76. package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
  77. package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
  78. package/dist/versions/index.d.ts +2 -1
  79. package/dist/versions/index.js +2 -2
  80. package/package.json +6 -6
  81. package/src/__tests__/applyNarrationTiming.test.ts +190 -0
  82. package/src/__tests__/applyRenderStyle.test.ts +3 -3
  83. package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
  84. package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
  85. package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
  86. package/src/__tests__/asciiDiagramParse.test.ts +233 -0
  87. package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
  88. package/src/__tests__/asciiDiagramRender.test.ts +162 -0
  89. package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
  90. package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
  91. package/src/__tests__/asciiTimelineParse.test.ts +205 -0
  92. package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
  93. package/src/__tests__/asciiTimelineRender.test.ts +376 -0
  94. package/src/__tests__/attrTokens.test.ts +5 -0
  95. package/src/__tests__/contentContainer.test.ts +43 -0
  96. package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
  97. package/src/__tests__/dataTable.test.ts +25 -15
  98. package/src/__tests__/diagramBlock.test.ts +3 -3
  99. package/src/__tests__/diagramText.test.ts +26 -0
  100. package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
  101. package/src/__tests__/drawingBlock.test.ts +3 -3
  102. package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
  103. package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
  104. package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
  105. package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
  106. package/src/__tests__/getLayers.test.ts +32 -18
  107. package/src/__tests__/getLayersFallback.test.ts +8 -8
  108. package/src/__tests__/imageEditVersions.test.ts +2 -0
  109. package/src/__tests__/jsonForm.pointer.test.ts +47 -1
  110. package/src/__tests__/layoutBlock.test.ts +3 -3
  111. package/src/__tests__/majorApiTypes.test.ts +18 -0
  112. package/src/__tests__/markdown.test.ts +41 -0
  113. package/src/__tests__/matchFontFamily.test.ts +114 -0
  114. package/src/__tests__/materializeBlockLayers.test.ts +135 -0
  115. package/src/__tests__/materializeTestUtils.ts +17 -0
  116. package/src/__tests__/narrationAlign.test.ts +150 -0
  117. package/src/__tests__/narrationFeatures.test.ts +71 -0
  118. package/src/__tests__/narrationNuclei.test.ts +45 -0
  119. package/src/__tests__/narrationPacing.test.ts +189 -0
  120. package/src/__tests__/narrationScript.test.ts +149 -0
  121. package/src/__tests__/narrationSessionRepro.test.ts +62 -0
  122. package/src/__tests__/narrationSidecar.test.ts +88 -0
  123. package/src/__tests__/narrationSyllables.test.ts +65 -0
  124. package/src/__tests__/narrationTestSignals.ts +167 -0
  125. package/src/__tests__/narrationVad.test.ts +66 -0
  126. package/src/__tests__/resolveDocTheme.test.ts +16 -2
  127. package/src/__tests__/rootExports.test.ts +18 -0
  128. package/src/__tests__/scopedContentContainer.test.ts +20 -0
  129. package/src/__tests__/shapeGeometry.test.ts +12 -0
  130. package/src/__tests__/templateAnnotationParse.test.ts +10 -0
  131. package/src/__tests__/templateInputs.test.ts +69 -0
  132. package/src/__tests__/templateMetadata.test.ts +2 -1
  133. package/src/__tests__/templates.test.ts +143 -17
  134. package/src/__tests__/themeCompile.test.ts +49 -22
  135. package/src/__tests__/transformProvenance.test.ts +160 -0
  136. package/src/__tests__/transformV2.test.ts +40 -14
  137. package/src/__tests__/treeviewBattle.test.ts +76 -0
  138. package/src/__tests__/treeviewDetect.test.ts +168 -0
  139. package/src/__tests__/treeviewParse.test.ts +118 -0
  140. package/src/__tests__/treeviewPipeline.test.ts +183 -0
  141. package/src/__tests__/treeviewRender.test.ts +91 -0
  142. package/src/__tests__/versions.test.ts +44 -0
  143. package/src/doc/applyNarrationTiming.ts +244 -0
  144. package/src/doc/asciiDiagram/chars.ts +210 -0
  145. package/src/doc/asciiDiagram/detect.ts +175 -0
  146. package/src/doc/asciiDiagram/index.ts +38 -0
  147. package/src/doc/asciiDiagram/mapping.ts +225 -0
  148. package/src/doc/asciiDiagram/parse.ts +1095 -0
  149. package/src/doc/asciiDiagram/render.ts +963 -0
  150. package/src/doc/asciiDiagram/repair.ts +400 -0
  151. package/src/doc/asciiDiagram/types.ts +65 -0
  152. package/src/doc/asciiTimeline/detect.ts +138 -0
  153. package/src/doc/asciiTimeline/index.ts +26 -0
  154. package/src/doc/asciiTimeline/mapping.ts +43 -0
  155. package/src/doc/asciiTimeline/parse.ts +870 -0
  156. package/src/doc/asciiTimeline/render.ts +427 -0
  157. package/src/doc/asciiTimeline/types.ts +73 -0
  158. package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
  159. package/src/doc/audioMapping.ts +60 -46
  160. package/src/doc/customTemplatesFrontmatter.ts +0 -41
  161. package/src/doc/docToMarkdown.ts +70 -2
  162. package/src/doc/index.ts +76 -4
  163. package/src/doc/markdownToDoc.ts +135 -1
  164. package/src/doc/materializeBlockLayers.ts +304 -0
  165. package/src/doc/mediaAnnotations.ts +20 -0
  166. package/src/doc/resolveDocTheme.ts +8 -7
  167. package/src/doc/templateInputs.ts +185 -2
  168. package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
  169. package/src/doc/templates/diagramBlock.ts +237 -38
  170. package/src/doc/templates/fallbackBlock.ts +1 -1
  171. package/src/doc/templates/index.ts +134 -279
  172. package/src/doc/templates/inputDescriptors.ts +20 -1
  173. package/src/doc/templates/metadata.ts +10 -0
  174. package/src/doc/templates/persistentLayers.ts +12 -126
  175. package/src/doc/templates/registry.ts +88 -0
  176. package/src/doc/templates/templateNames.ts +22 -0
  177. package/src/doc/templates/timelineBlock.ts +613 -0
  178. package/src/doc/templates/treeBlock.ts +131 -0
  179. package/src/doc/treeview/chars.ts +72 -0
  180. package/src/doc/treeview/detect.ts +145 -0
  181. package/src/doc/treeview/index.ts +30 -0
  182. package/src/doc/treeview/mapping.ts +95 -0
  183. package/src/doc/treeview/parse.ts +201 -0
  184. package/src/doc/treeview/render.ts +41 -0
  185. package/src/doc/treeview/types.ts +43 -0
  186. package/src/doc/utils/applyRenderStyle.ts +2 -9
  187. package/src/doc/utils/diagramText.ts +78 -0
  188. package/src/doc/utils/shapeGeometry.ts +67 -5
  189. package/src/doc/validate.ts +1 -1
  190. package/src/generate/templateMapper.ts +7 -0
  191. package/src/imageEdit/export.ts +6 -5
  192. package/src/imageEdit/versionPaths.ts +13 -26
  193. package/src/imageEdit/versions.ts +21 -100
  194. package/src/index.ts +1 -0
  195. package/src/internal/immutable.ts +58 -0
  196. package/src/jsonForm/index.ts +9 -1
  197. package/src/jsonForm/pointer.ts +68 -23
  198. package/src/markdown/attrTokens.ts +7 -5
  199. package/src/markdown/index.ts +1 -0
  200. package/src/markdown/stringify.ts +4 -9
  201. package/src/markdown/utils.ts +36 -14
  202. package/src/narration/align.ts +514 -0
  203. package/src/narration/features.ts +231 -0
  204. package/src/narration/index.ts +86 -0
  205. package/src/narration/nuclei.ts +118 -0
  206. package/src/narration/pacing.ts +211 -0
  207. package/src/narration/script.ts +239 -0
  208. package/src/narration/session.ts +100 -0
  209. package/src/narration/sidecar.ts +187 -0
  210. package/src/narration/syllables.ts +85 -0
  211. package/src/narration/trace.ts +50 -0
  212. package/src/narration/types.ts +299 -0
  213. package/src/narration/vad.ts +131 -0
  214. package/src/recommend/numberHighlight.ts +25 -0
  215. package/src/recommend/templates.ts +108 -12
  216. package/src/schemas/BlockTemplates.ts +156 -7
  217. package/src/schemas/Doc.ts +72 -9
  218. package/src/schemas/Media.ts +12 -2
  219. package/src/schemas/Theme.ts +45 -25
  220. package/src/schemas/Viewport.ts +2 -2
  221. package/src/schemas/fontStacks.ts +79 -0
  222. package/src/schemas/themeCompile.ts +15 -0
  223. package/src/schemas/themeConstants.ts +2 -0
  224. package/src/schemas/themeLibrary.ts +25 -19
  225. package/src/schemas/themeValidator.ts +1 -1
  226. package/src/spatial/Geohash.ts +0 -3
  227. package/src/storage/ContentContainer.ts +17 -9
  228. package/src/storage/ScopedContentContainer.ts +45 -15
  229. package/src/transform/applyTransform.ts +5 -5
  230. package/src/transform/index.ts +3 -1
  231. package/src/transform/registry.ts +169 -49
  232. package/src/transform/templateSelector.ts +21 -2
  233. package/src/transform/timingAllocator.ts +152 -21
  234. package/src/transform/types.ts +14 -1
  235. package/src/versions/gitignore.ts +34 -0
  236. package/src/versions/index.ts +2 -0
  237. package/src/versions/operations.ts +18 -104
  238. package/src/versions/paths.ts +13 -28
  239. package/src/versions/snapshotStore.ts +202 -0
  240. package/src/versions/types.ts +3 -1
  241. package/dist/chunk-5TYS5V3G.js.map +0 -1
  242. package/dist/chunk-A4O7GIWE.js.map +0 -1
  243. package/dist/chunk-BEQODJWV.js.map +0 -1
  244. package/dist/chunk-DLXZMS5K.js.map +0 -1
  245. package/dist/chunk-GPLTCSXO.js.map +0 -1
  246. package/dist/chunk-HWVFJAAH.js.map +0 -1
  247. package/dist/chunk-IMSCRLLV.js.map +0 -1
  248. package/dist/chunk-JELIRVDP.js +0 -24
  249. package/dist/chunk-JELIRVDP.js.map +0 -1
  250. package/dist/chunk-KKNUBQ6Y.js.map +0 -1
  251. package/dist/chunk-LDQ2HJIX.js.map +0 -1
  252. package/dist/chunk-LTN6I7QW.js.map +0 -1
  253. package/dist/chunk-P3K7NLHF.js.map +0 -1
  254. package/dist/chunk-T5UK6YOB.js.map +0 -1
  255. package/dist/chunk-UY7KGQ5R.js +0 -192
  256. package/dist/chunk-UY7KGQ5R.js.map +0 -1
  257. package/dist/chunk-VLJJHDAC.js +0 -218
  258. package/dist/chunk-VLJJHDAC.js.map +0 -1
  259. package/dist/chunk-VWUFZ6ZG.js.map +0 -1
  260. package/dist/story/index.d.ts +0 -1801
  261. package/dist/story/index.js +0 -279
  262. package/src/doc/getLayers.ts +0 -195
  263. /package/dist/{story → narration}/index.js.map +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/markdown/htmlParse.ts","../src/markdown/utils.ts"],"sourcesContent":["/**\n * HTML ↔ HtmlNode Conversion\n *\n * Parses raw HTML strings into the squisq HtmlNode tree representation\n * using hast-util-from-html (parse5-backed), and serializes HtmlNode trees\n * back to HTML strings with a lightweight custom serializer.\n */\n\nimport { fromHtml } from 'hast-util-from-html';\nimport type { HtmlNode } from './types.js';\n\n// ============================================\n// Hast → HtmlNode conversion\n// ============================================\n\n/**\n * Mapping from hast DOM-style property names to HTML attribute names.\n * Only includes names where the property and attribute differ.\n */\nconst HAST_PROP_TO_ATTR: Record<string, string> = {\n className: 'class',\n htmlFor: 'for',\n httpEquiv: 'http-equiv',\n acceptCharset: 'accept-charset',\n};\n\n/** HTML void elements that are self-closing. */\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\n/**\n * Convert a hast property name to an HTML attribute name.\n */\nfunction propertyToAttribute(prop: string): string {\n if (HAST_PROP_TO_ATTR[prop]) return HAST_PROP_TO_ATTR[prop];\n\n // data-* attributes: dataFooBar → data-foo-bar\n if (prop.length > 4 && prop.startsWith('data') && prop[4] >= 'A' && prop[4] <= 'Z') {\n return (\n 'data-' +\n prop\n .slice(4)\n .replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n .replace(/^-/, '')\n );\n }\n\n // aria-* attributes: ariaLabel → aria-label\n if (prop.length > 4 && prop.startsWith('aria') && prop[4] >= 'A' && prop[4] <= 'Z') {\n return (\n 'aria-' +\n prop\n .slice(4)\n .replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())\n .replace(/^-/, '')\n );\n }\n\n // Most HTML attributes are lowercase (tabIndex → tabindex, readOnly → readonly, etc.)\n return prop.toLowerCase();\n}\n\n/**\n * Convert hast element properties to a flat HTML attribute map.\n */\nfunction convertHastProperties(properties: Record<string, unknown>): Record<string, string> {\n const attrs: Record<string, string> = {};\n for (const [key, value] of Object.entries(properties)) {\n if (value === false || value === undefined || value === null) continue;\n\n const attrName = propertyToAttribute(key);\n\n if (value === true) {\n attrs[attrName] = '';\n } else if (Array.isArray(value)) {\n attrs[attrName] = value.join(' ');\n } else {\n attrs[attrName] = String(value);\n }\n }\n return attrs;\n}\n\n/**\n * Recursively convert hast child nodes to HtmlNode[].\n */\nfunction hastChildrenToNodes(children: unknown[]): HtmlNode[] {\n const result: HtmlNode[] = [];\n for (const child of children) {\n const node = hastNodeToHtmlNode(child as Record<string, unknown>);\n if (node) result.push(node);\n }\n return result;\n}\n\n/**\n * Convert a single hast node to an HtmlNode.\n */\nfunction hastNodeToHtmlNode(node: Record<string, unknown>): HtmlNode | null {\n switch (node.type) {\n case 'element': {\n const tagName = node.tagName as string;\n const properties = (node.properties ?? {}) as Record<string, unknown>;\n const children = (node.children ?? []) as unknown[];\n return {\n type: 'htmlElement',\n tagName,\n attributes: convertHastProperties(properties),\n children: hastChildrenToNodes(children),\n selfClosing: VOID_ELEMENTS.has(tagName) && children.length === 0,\n };\n }\n case 'text':\n return {\n type: 'htmlText',\n value: node.value as string,\n };\n case 'comment':\n return {\n type: 'htmlComment',\n value: node.value as string,\n };\n case 'doctype':\n // Doctype nodes are rare in markdown HTML; skip them\n return null;\n default:\n return null;\n }\n}\n\n// ============================================\n// Public API\n// ============================================\n\n/**\n * Parse a raw HTML string into an HtmlNode[] tree.\n *\n * Uses the HTML5 parsing algorithm (via parse5) for correct handling of\n * self-closing tags, optional end tags, entity decoding, etc.\n *\n * @param html - Raw HTML string to parse\n * @returns Array of top-level HtmlNode elements\n */\nexport function parseHtmlToNodes(html: string): HtmlNode[] {\n if (!html || !html.trim()) return [];\n\n try {\n const tree = fromHtml(html, { fragment: true });\n return hastChildrenToNodes(tree.children as unknown[]);\n } catch {\n // If parsing fails, return the raw text as a single text node\n return [{ type: 'htmlText', value: html }];\n }\n}\n\n/**\n * Escape special characters in HTML attribute values.\n */\nfunction escapeHtmlAttr(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\n/**\n * Serialize an HtmlNode back to an HTML string.\n */\nfunction stringifyNode(node: HtmlNode): string {\n switch (node.type) {\n case 'htmlElement': {\n const attrs = Object.entries(node.attributes)\n .map(([k, v]) => (v === '' ? k : `${k}=\"${escapeHtmlAttr(v)}\"`))\n .join(' ');\n const open = attrs ? `<${node.tagName} ${attrs}>` : `<${node.tagName}>`;\n\n if (node.selfClosing) return open;\n\n const inner = node.children.map(stringifyNode).join('');\n return `${open}${inner}</${node.tagName}>`;\n }\n case 'htmlText':\n return node.value;\n case 'htmlComment':\n return `<!--${node.value}-->`;\n }\n}\n\n/**\n * Serialize an HtmlNode[] tree back to an HTML string.\n *\n * @param nodes - Array of HtmlNode elements to serialize\n * @returns HTML string\n */\nexport function stringifyHtmlNodes(nodes: HtmlNode[]): string {\n return nodes.map(stringifyNode).join('');\n}\n","/**\n * Markdown Tree Utilities\n *\n * Helper functions for traversing and querying the MarkdownDocument tree.\n * All functions are pure and operate on the JSON node interfaces.\n */\n\nimport type { MarkdownNode, MarkdownDocument, HtmlNode } from './types.js';\nimport { parseHtmlToNodes } from './htmlParse.js';\n\n/**\n * Get the children of any markdown node, if it has children.\n * Returns an empty array for leaf nodes (text, code, break, etc.).\n *\n * This is useful for generic tree walking where you don't want to\n * check the specific node type.\n */\nexport function getChildren(node: MarkdownNode): MarkdownNode[] {\n if ('children' in node && Array.isArray(node.children)) {\n return node.children as MarkdownNode[];\n }\n return [];\n}\n\n/**\n * Walk the markdown tree depth-first, calling the visitor for each node.\n *\n * The visitor receives the current node and its parent. Return `true`\n * from the visitor to skip the node's children (prune).\n *\n * @param node - The root node to start walking from\n * @param visitor - Called for each node; return true to skip children\n * @param parent - (internal) Parent node\n */\nexport function walkMarkdownTree(\n node: MarkdownNode,\n visitor: (node: MarkdownNode, parent?: MarkdownNode) => void | boolean,\n parent?: MarkdownNode,\n): void {\n const skip = visitor(node, parent);\n if (skip === true) return;\n\n const children = getChildren(node);\n for (const child of children) {\n walkMarkdownTree(child, visitor, node);\n }\n}\n\n/**\n * Find all nodes of a specific type in the tree.\n *\n * @param root - The document or node to search within\n * @param type - The node type to find (e.g., 'heading', 'link', 'text')\n * @returns Array of matching nodes\n *\n * @example\n * ```ts\n * const headings = findNodesByType(doc, 'heading');\n * const links = findNodesByType(doc, 'link');\n * ```\n */\nexport function findNodesByType<T extends MarkdownNode>(root: MarkdownNode, type: T['type']): T[] {\n const results: T[] = [];\n walkMarkdownTree(root, (node) => {\n if (node.type === type) {\n results.push(node as T);\n }\n });\n return results;\n}\n\n/**\n * Extract all plain text content from a node and its descendants.\n * Concatenates text values, ignoring formatting, links, etc.\n *\n * @param node - The node to extract text from\n * @returns Plain text content\n *\n * @example\n * ```ts\n * const heading = doc.children[0]; // { type: 'heading', children: [{ type: 'text', value: 'Hello' }] }\n * extractPlainText(heading); // 'Hello'\n * ```\n */\nexport function extractPlainText(node: MarkdownNode): string {\n if ('value' in node && typeof node.value === 'string') {\n return node.value;\n }\n\n const children = getChildren(node);\n // Preserve boundaries between block-level elements (list items, paragraphs\n // inside list items, blockquotes) so downstream consumers like caption\n // splitting can treat each item as a separate phrase.\n const separator = node.type === 'list' || node.type === 'listItem' ? '\\n' : '';\n return children.map(extractPlainText).join(separator);\n}\n\n/**\n * Count the total number of nodes in the tree.\n *\n * @param node - The root node\n * @returns Total node count (including the root)\n */\nexport function countNodes(node: MarkdownNode): number {\n let count = 1;\n const children = getChildren(node);\n for (const child of children) {\n count += countNodes(child);\n }\n return count;\n}\n\n/**\n * Parse a YAML frontmatter string into a key-value record.\n *\n * Handles simple `key: value` pairs common in markdown frontmatter.\n * Values are trimmed; quoted strings have their quotes removed.\n * Returns `null` if parsing fails or the input is empty.\n *\n * @param yaml - The raw YAML string (without the `---` delimiters)\n * @returns A record of string keys to parsed values, or null\n */\nexport function parseFrontmatter(yaml: string): Record<string, unknown> | null {\n if (!yaml || !yaml.trim()) return null;\n\n const result: Record<string, unknown> = {};\n const lines = yaml.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n const colonIdx = trimmed.indexOf(':');\n if (colonIdx < 1) continue;\n\n const key = trimmed.slice(0, colonIdx).trim();\n let value: string | boolean | number = trimmed.slice(colonIdx + 1).trim();\n\n // YAML literal block scalar: `key: |` or `key: |-`. Subsequent lines\n // that are more-indented than the key belong to the scalar; they are\n // dedented by their common leading indent and joined with `\\n`. A line\n // at the key's indent (or less) ends the scalar. Both `|` and `|-`\n // yield the joined string here (`|-` without a trailing newline); we do\n // not model `|`'s trailing-newline / `+`/`-` chomping nuances beyond\n // stripping trailing blank lines.\n if (value === '|' || value === '|-') {\n const keyIndent = line.length - line.trimStart().length;\n const blockLines: string[] = [];\n let j = i + 1;\n for (; j < lines.length; j++) {\n const bl = lines[j];\n if (bl.trim() === '') {\n blockLines.push('');\n continue;\n }\n const indent = bl.length - bl.trimStart().length;\n if (indent <= keyIndent) break; // dedent ends the scalar\n blockLines.push(bl);\n }\n i = j - 1; // resume the outer walk at the terminating line\n\n // Drop trailing blank lines captured inside the scalar.\n while (blockLines.length > 0 && blockLines[blockLines.length - 1] === '') {\n blockLines.pop();\n }\n\n // Dedent by the common leading whitespace of the non-blank lines.\n let commonIndent = Infinity;\n for (const bl of blockLines) {\n if (bl === '') continue;\n commonIndent = Math.min(commonIndent, bl.length - bl.trimStart().length);\n }\n if (!isFinite(commonIndent)) commonIndent = 0;\n result[key] = blockLines.map((bl) => (bl === '' ? '' : bl.slice(commonIndent))).join('\\n');\n continue;\n }\n\n // Remove surrounding quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Parse booleans and numbers\n if (value === 'true') {\n result[key] = true;\n } else if (value === 'false') {\n result[key] = false;\n } else if (value !== '' && !isNaN(Number(value))) {\n result[key] = Number(value);\n } else {\n result[key] = value;\n }\n }\n\n return Object.keys(result).length > 0 ? result : null;\n}\n\n/**\n * Format a multi-line string as a YAML literal block scalar body, i.e.\n * `|-` followed by each source line indented two spaces. Paired with\n * {@link parseFrontmatter}'s block-scalar reader so multi-line frontmatter\n * values (e.g. pretty-printed JSON payloads) round-trip. Blank lines stay\n * blank (no trailing whitespace) so the output diffs cleanly.\n */\nexport function formatBlockScalar(value: string): string {\n const body = value\n .split('\\n')\n .map((line) => (line === '' ? '' : ` ${line}`))\n .join('\\n');\n return `|-\\n${body}`;\n}\n\nconst FRONTMATTER_BLOCK_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---(\\r?\\n)?/;\n\n/** Quote a frontmatter scalar so it round-trips cleanly through `parseFrontmatter`. */\nfunction formatFrontmatterValue(value: string | number | boolean): string {\n if (typeof value === 'boolean' || typeof value === 'number') return String(value);\n // Multi-line strings can't live on one line — emit a YAML literal block\n // scalar (`|-`) that `parseFrontmatter` reads back. This carries pretty-\n // printed JSON payloads (opt-in custom templates/themes). Single-line\n // values keep their exact historical output below.\n if (/[\\r\\n]/.test(value)) return formatBlockScalar(value.replace(/\\r\\n?/g, '\\n'));\n // A single-line JSON object/array literal round-trips verbatim through\n // the line-based `parseFrontmatter` (no leading quote to strip, no\n // newline to split on), so write it unquoted to keep it human-readable\n // — matching how `stringifyMarkdown` emits string values. Used by the\n // compact custom-layouts payload.\n if (/^[{[]/.test(value) && !/[\\r\\n]/.test(value)) return value;\n // Quote when needed: leading/trailing whitespace, leading punctuation that\n // could trigger YAML modes, or values that look like reserved literals.\n const needsQuote =\n /^\\s|\\s$/.test(value) ||\n /^[!&*?|>%@`]/.test(value) ||\n /[:#]/.test(value) ||\n value === '' ||\n value === 'true' ||\n value === 'false' ||\n /^-?\\d+(\\.\\d+)?$/.test(value);\n if (!needsQuote) return value;\n // Prefer double quotes; escape any embedded double-quote / backslash.\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n return `\"${escaped}\"`;\n}\n\n/**\n * Update a markdown source string's YAML frontmatter block, applying the\n * given key/value updates. A `null` or `undefined` value removes the key.\n * If no frontmatter block exists and any non-null update is supplied, a\n * new block is prepended; if every update is a removal and no block\n * exists, the source is returned unchanged.\n *\n * Existing key order is preserved; new keys are appended in the order\n * they appear in `updates`. The simple parser used here handles plain\n * `key: value` pairs only — comments, multi-line scalars, and nested\n * structures are left untouched (we only rewrite lines whose key matches\n * one in `updates`).\n *\n * @param source - The markdown source string.\n * @param updates - Map of key → new value (or null/undefined to remove).\n * @returns The updated markdown source string.\n */\nexport function setFrontmatterValues(\n source: string,\n updates: Record<string, string | number | boolean | null | undefined>,\n): string {\n const updateKeys = Object.keys(updates);\n if (updateKeys.length === 0) return source;\n\n const match = source.match(FRONTMATTER_BLOCK_RE);\n const handled = new Set<string>();\n\n // Existing frontmatter block — rewrite line-by-line, preserving order.\n if (match) {\n const inner = match[1];\n const lines = inner.split(/\\r?\\n/);\n const newLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) {\n newLines.push(line);\n continue;\n }\n const colonIdx = trimmed.indexOf(':');\n if (colonIdx < 1) {\n newLines.push(line);\n continue;\n }\n const key = trimmed.slice(0, colonIdx).trim();\n if (!Object.prototype.hasOwnProperty.call(updates, key)) {\n newLines.push(line);\n continue;\n }\n handled.add(key);\n const next = updates[key];\n if (next === null || next === undefined) continue; // remove\n newLines.push(`${key}: ${formatFrontmatterValue(next)}`);\n }\n\n // Append any keys that weren't already present.\n for (const key of updateKeys) {\n if (handled.has(key)) continue;\n const next = updates[key];\n if (next === null || next === undefined) continue;\n newLines.push(`${key}: ${formatFrontmatterValue(next)}`);\n }\n\n // If every line got removed, drop the block entirely.\n const nonEmpty = newLines.filter((l) => l.trim().length > 0);\n const rest = source.slice(match[0].length);\n if (nonEmpty.length === 0) return rest;\n return `---\\n${newLines.join('\\n')}\\n---\\n${rest}`;\n }\n\n // No existing block — only create one if there's at least one non-null\n // value to write.\n const fresh: string[] = [];\n for (const key of updateKeys) {\n const next = updates[key];\n if (next === null || next === undefined) continue;\n fresh.push(`${key}: ${formatFrontmatterValue(next)}`);\n }\n if (fresh.length === 0) return source;\n return `---\\n${fresh.join('\\n')}\\n---\\n${source}`;\n}\n\n/**\n * Create a minimal MarkdownDocument from a list of block nodes.\n * Convenience function for programmatic document construction.\n */\nexport function createDocument(...children: MarkdownDocument['children']): MarkdownDocument {\n return {\n type: 'document',\n children,\n };\n}\n\n/**\n * Infer a human-readable title for a markdown document.\n *\n * Resolution order:\n * 1. `title:` value in YAML frontmatter (when present and non-empty)\n * 2. Text of the first heading found, walking top-level depth (H1, then\n * H2, etc.) — the shallowest heading wins regardless of source order\n *\n * Returns `undefined` when no usable title is found.\n */\nexport function inferDocumentTitle(doc: MarkdownDocument): string | undefined {\n const fmTitle = doc.frontmatter?.title;\n if (typeof fmTitle === 'string') {\n const trimmed = fmTitle.trim();\n if (trimmed) return trimmed;\n }\n\n let best: { depth: number; text: string } | null = null;\n for (const node of doc.children) {\n if (node.type !== 'heading') continue;\n const text = extractPlainText(node).trim();\n if (!text) continue;\n if (best === null || node.depth < best.depth) {\n best = { depth: node.depth, text };\n if (best.depth === 1) break;\n }\n }\n\n return best?.text;\n}\n\n/**\n * Read a theme id from a markdown document's frontmatter.\n *\n * Checks the editor's canonical `squisq-theme` key first, then the\n * shorter legacy aliases (`themeId`, `theme`). Returns `undefined`\n * when none of them carry a non-empty string. Centralizing the lookup\n * keeps the export pipelines (DOCX, PPTX, HTML, plain-HTML bundle) in\n * sync with whatever the editor writes — adding a new frontmatter\n * spelling later is a one-file change.\n */\nexport function readFrontmatterThemeId(\n frontmatter: Record<string, unknown> | undefined,\n): string | undefined {\n if (!frontmatter) return undefined;\n const keys = ['squisq-theme', 'themeId', 'theme'] as const;\n for (const key of keys) {\n const raw = frontmatter[key];\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n if (trimmed) return trimmed;\n }\n }\n return undefined;\n}\n\n/**\n * Project an inline-HTML string (as stored on `TextLayer.content.html`) down\n * to plain text — the value mirrored into `content.text` for plain consumers\n * (PDF/markdown export, search, accessibility) and the SVG `<text>` fallback.\n *\n * `<br>` and block-level tags (`p`, `div`, `h1`–`h6`, `li`, `blockquote`,\n * `pre`) become line breaks so multi-line rich content reads sensibly. Entity\n * decoding is handled by {@link parseHtmlToNodes} (parse5-backed), so this is\n * more correct than a regex tag-stripper.\n */\nexport function plainTextFromInlineHtml(html: string): string {\n const BLOCK = new Set([\n 'p',\n 'div',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'li',\n 'blockquote',\n 'pre',\n ]);\n const walk = (nodes: HtmlNode[]): string =>\n nodes\n .map((n) => {\n if (n.type === 'htmlText') return n.value;\n if (n.type !== 'htmlElement') return '';\n const tag = n.tagName.toLowerCase();\n if (tag === 'br') return '\\n';\n const inner = walk(n.children);\n return BLOCK.has(tag) ? `${inner}\\n` : inner;\n })\n .join('');\n return walk(parseHtmlToNodes(html))\n .replace(/\\u00A0/g, ' ')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage/MemoryStorageAdapter.ts","../src/storage/LocalStorageAdapter.ts","../src/storage/LocalForageAdapter.ts","../src/storage/ContentContainer.ts","../src/storage/ScopedContentContainer.ts","../src/storage/MediaProviderFromContainer.ts"],"sourcesContent":["/**\n * In-memory storage adapter for testing and SSR environments.\n * Data does not persist across page reloads.\n */\n\nimport type { StorageAdapter } from './Storage.js';\n\nexport class MemoryStorageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private store = new Map<string, string>();\n\n async get<T>(key: string): Promise<T | null> {\n const val = this.store.get(key);\n if (val === undefined) return null;\n try {\n return JSON.parse(val) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, JSON.stringify(value));\n }\n\n async remove(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n\n async keys(): Promise<string[]> {\n return Array.from(this.store.keys());\n }\n}\n","/**\n * localStorage adapter for web browsers.\n * Supports a configurable key prefix to namespace stored data.\n */\n\nimport type { StorageAdapter } from './Storage.js';\n\nexport class LocalStorageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private prefix: string;\n\n constructor(prefix = '') {\n this.prefix = prefix;\n }\n\n async get<T>(key: string): Promise<T | null> {\n try {\n const raw = localStorage.getItem(this.prefix + key);\n if (raw === null) return null;\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n localStorage.setItem(this.prefix + key, JSON.stringify(value));\n }\n\n async remove(key: string): Promise<void> {\n localStorage.removeItem(this.prefix + key);\n }\n\n async clear(): Promise<void> {\n const keysToRemove: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(this.prefix)) {\n keysToRemove.push(k);\n }\n }\n for (const k of keysToRemove) {\n localStorage.removeItem(k);\n }\n }\n\n async keys(): Promise<string[]> {\n const result: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(this.prefix)) {\n result.push(k.slice(this.prefix.length));\n }\n }\n return result;\n }\n}\n","/**\n * LocalForage adapter - IndexedDB storage with automatic fallbacks.\n *\n * Uses localforage which provides IndexedDB storage with automatic\n * fallbacks to WebSQL and localStorage. This allows storing much more\n * data than raw localStorage (which is limited to ~5MB).\n *\n * Unlike LocalStorageAdapter, this adapter can store binary data\n * (ArrayBuffer, Blob, Uint8Array) natively without JSON serialization.\n *\n * Ported from qualla-internal/shared/services/StorageAdapters.ts with\n * configurable store name and key prefix.\n */\n\nimport localforage from 'localforage';\nimport type { StorageAdapter } from './Storage.js';\n\nexport interface LocalForageAdapterOptions {\n /** IndexedDB database name (default: 'squisq') */\n name?: string;\n /** IndexedDB object store name (default: 'data') */\n storeName?: string;\n /** Key prefix for namespacing (default: '') */\n prefix?: string;\n /** Human-readable description (default: 'Squisq storage') */\n description?: string;\n}\n\nexport class LocalForageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private store: LocalForage;\n private prefix: string;\n\n constructor(options: LocalForageAdapterOptions = {}) {\n const {\n name = 'squisq',\n storeName = 'data',\n prefix = '',\n description = 'Squisq storage',\n } = options;\n\n this.prefix = prefix;\n this.store = localforage.createInstance({ name, storeName, description });\n }\n\n async get<T>(key: string): Promise<T | null> {\n try {\n const value = await this.store.getItem<T>(this.prefix + key);\n return value;\n } catch (e: unknown) {\n console.warn('[Storage] get (IndexedDB) failed:', key, e);\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n try {\n await this.store.setItem(this.prefix + key, value);\n } catch (e: unknown) {\n console.error('[Storage] set (IndexedDB) failed:', key, e);\n throw e;\n }\n }\n\n async remove(key: string): Promise<void> {\n try {\n await this.store.removeItem(this.prefix + key);\n } catch (e: unknown) {\n console.warn('[Storage] remove (IndexedDB) failed:', key, e);\n }\n }\n\n async clear(): Promise<void> {\n try {\n if (this.prefix) {\n // Only remove keys with our prefix\n const keys = await this.store.keys();\n const keysToRemove = keys.filter((k) => k.startsWith(this.prefix));\n await Promise.all(keysToRemove.map((k) => this.store.removeItem(k)));\n } else {\n // No prefix — clear the entire store\n await this.store.clear();\n }\n } catch (e: unknown) {\n console.error('[Storage] clear (IndexedDB) failed:', e);\n }\n }\n\n async keys(): Promise<string[]> {\n try {\n const allKeys = await this.store.keys();\n if (this.prefix) {\n return allKeys\n .filter((k) => k.startsWith(this.prefix))\n .map((k) => k.slice(this.prefix.length));\n }\n return allKeys;\n } catch (e: unknown) {\n console.warn('[Storage] keys (IndexedDB) failed:', e);\n return [];\n }\n }\n}\n","/**\n * ContentContainer — virtual file system for document containers.\n *\n * A Squisq document is more than just markdown: it's a container of files\n * including the primary markdown document, images, audio, timing data, and\n * other media. ContentContainer provides an abstract async file system\n * interface for reading, writing, and listing these files.\n *\n * Paths are forward-slash separated strings relative to the container root\n * (e.g., 'images/hero.jpg', 'index.md'). No leading slash.\n *\n * Implementations (in core):\n * - MemoryContentContainer — in-memory Map (for zip import, tests, transient use)\n * - ScopedContentContainer — a prefix-scoped view onto a parent container\n */\n\n/**\n * Metadata about a file in a ContentContainer.\n */\nexport interface ContentEntry {\n /** Relative path within the container (e.g., 'images/hero.jpg') */\n path: string;\n /** MIME type (e.g., 'image/jpeg') */\n mimeType: string;\n /** File size in bytes */\n size: number;\n}\n\n/**\n * Abstract async file system for document containers.\n *\n * All paths are forward-slash separated, relative to the container root,\n * with no leading slash. Example: 'images/hero.jpg', 'index.md'.\n */\nexport interface ContentContainer {\n /** Read a file's binary content. Returns null if the file does not exist. */\n readFile(path: string): Promise<ArrayBuffer | null>;\n\n /** Write a file. Creates or overwrites. */\n writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void>;\n\n /** Remove a file. No-op if the file does not exist. */\n removeFile(path: string): Promise<void>;\n\n /**\n * List files in the container.\n *\n * Returns file **entries** (`ContentEntry[]` with `.path`/`.mimeType`/`.size`),\n * NOT bare path strings — despite the name. Read `entry.path` for the path;\n * calling string methods (e.g. `.startsWith`) directly on an entry will throw.\n * @param prefix — Optional path prefix to filter by (e.g., 'images/')\n */\n listFiles(prefix?: string): Promise<ContentEntry[]>;\n\n /** Check whether a file exists. */\n exists(path: string): Promise<boolean>;\n\n /**\n * Find the primary markdown document path.\n *\n * Discovery order: index.md → doc.md → document.md → first *.md at root.\n * Returns null if no markdown file is found at the root level.\n */\n getDocumentPath(): Promise<string | null>;\n\n /**\n * Convenience: read the primary markdown document as a UTF-8 string.\n * Returns null if no markdown file is found.\n */\n readDocument(): Promise<string | null>;\n\n /**\n * Convenience: write a markdown document.\n * @param markdown — The markdown content\n * @param filename — Filename to use (defaults to 'index.md')\n */\n writeDocument(markdown: string, filename?: string): Promise<void>;\n}\n\n// ============================================\n// Well-known markdown filenames in priority order\n// ============================================\n\nconst MARKDOWN_PRIORITY = ['index.md', 'doc.md', 'document.md'];\n\n/**\n * Find the primary markdown path from a list of file entries.\n * Exported for reuse by other ContentContainer implementations.\n */\nexport function findDocumentPath(entries: ContentEntry[]): string | null {\n // Only consider root-level files (no '/' in path)\n const rootFiles = entries.filter((e) => !e.path.includes('/'));\n\n for (const name of MARKDOWN_PRIORITY) {\n if (rootFiles.some((e) => e.path.toLowerCase() === name)) {\n return name;\n }\n }\n\n // Fallback: first .md file at root\n const firstMd = rootFiles.find((e) => e.path.toLowerCase().endsWith('.md'));\n return firstMd?.path ?? null;\n}\n\n// ============================================\n// MemoryContentContainer\n// ============================================\n\ninterface MemoryFile {\n data: ArrayBuffer;\n mimeType: string;\n}\n\n/**\n * In-memory ContentContainer backed by a Map.\n *\n * Used for zip import (deserialize into memory), tests, and transient operations.\n */\nexport class MemoryContentContainer implements ContentContainer {\n private files = new Map<string, MemoryFile>();\n\n async readFile(path: string): Promise<ArrayBuffer | null> {\n return this.files.get(path)?.data ?? null;\n }\n\n async writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void> {\n // Copy to a standalone ArrayBuffer. Uint8Array/Buffer may share a larger\n // backing buffer (e.g., Node's buffer pool), so we must slice to the\n // exact byte range to avoid storing stale pool data.\n let buffer: ArrayBuffer;\n if (data instanceof ArrayBuffer) {\n buffer = data;\n } else {\n buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer;\n }\n this.files.set(path, {\n data: buffer,\n mimeType: mimeType ?? guessMimeType(path),\n });\n }\n\n async removeFile(path: string): Promise<void> {\n this.files.delete(path);\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const entries: ContentEntry[] = [];\n for (const [path, file] of this.files) {\n if (prefix && !path.startsWith(prefix)) continue;\n entries.push({\n path,\n mimeType: file.mimeType,\n size: file.data.byteLength,\n });\n }\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n return this.files.has(path);\n }\n\n async getDocumentPath(): Promise<string | null> {\n return findDocumentPath(await this.listFiles());\n }\n\n async readDocument(): Promise<string | null> {\n const docPath = await this.getDocumentPath();\n if (!docPath) return null;\n const data = await this.readFile(docPath);\n if (!data) return null;\n return new TextDecoder().decode(data);\n }\n\n async writeDocument(markdown: string, filename?: string): Promise<void> {\n const name = filename ?? 'index.md';\n const data = new TextEncoder().encode(markdown);\n await this.writeFile(name, data, 'text/markdown');\n }\n}\n\n// ============================================\n// MIME type guessing\n// ============================================\n\nconst EXTENSION_MIME_MAP: Record<string, string> = {\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.json': 'application/json',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'application/javascript',\n};\n\nfunction guessMimeType(path: string): string {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return 'application/octet-stream';\n const ext = path.slice(dot).toLowerCase();\n return EXTENSION_MIME_MAP[ext] ?? 'application/octet-stream';\n}\n","/**\n * ScopedContentContainer\n *\n * Wraps a parent {@link ContentContainer} and prefixes every path with a\n * fixed subfolder, presenting that subfolder as the root. Useful for\n * sidecar folders (e.g. `<imagebasename>_files/`) where a component\n * should be able to read/write/list files relative to its own root\n * without knowing where it lives in the parent tree.\n *\n * Scopes nest: `scopeContainer(scopeContainer(parent, 'a'), 'b')` is\n * equivalent to `scopeContainer(parent, 'a/b')`.\n *\n * `getDocumentPath()` always returns `null` for scoped sidecars — they\n * are not document roots.\n */\n\nimport type { ContentContainer, ContentEntry } from './ContentContainer.js';\n\n/** Normalize a prefix: strip leading/trailing slashes, ensure no `..` segments. */\nfunction normalizePrefix(prefix: string): string {\n let p = prefix.trim();\n while (p.startsWith('/')) p = p.slice(1);\n while (p.endsWith('/')) p = p.slice(0, -1);\n if (p.length === 0) {\n throw new Error('ScopedContentContainer: prefix must not be empty');\n }\n if (p.split('/').some((seg) => seg === '..' || seg === '.')) {\n throw new Error(\n `ScopedContentContainer: prefix must not contain '.' or '..' segments: ${prefix}`,\n );\n }\n return p;\n}\n\n/**\n * A ContentContainer view rooted at a subfolder of a parent container.\n * All paths passed to / returned from this container are relative to\n * the subfolder; the parent never sees an unprefixed path.\n */\nexport class ScopedContentContainer implements ContentContainer {\n private readonly parent: ContentContainer;\n /** Prefix without trailing slash. */\n readonly prefix: string;\n /** Prefix with trailing slash. */\n private readonly prefixSlash: string;\n\n constructor(parent: ContentContainer, prefix: string) {\n this.parent = parent;\n this.prefix = normalizePrefix(prefix);\n this.prefixSlash = `${this.prefix}/`;\n }\n\n private toParent(path: string): string {\n let p = path;\n while (p.startsWith('/')) p = p.slice(1);\n return this.prefixSlash + p;\n }\n\n /** Strip the prefix from a parent-space path. Returns null if the path is outside the scope. */\n private fromParent(parentPath: string): string | null {\n if (!parentPath.startsWith(this.prefixSlash)) return null;\n return parentPath.slice(this.prefixSlash.length);\n }\n\n readFile(path: string): Promise<ArrayBuffer | null> {\n return this.parent.readFile(this.toParent(path));\n }\n\n writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void> {\n return this.parent.writeFile(this.toParent(path), data, mimeType);\n }\n\n removeFile(path: string): Promise<void> {\n return this.parent.removeFile(this.toParent(path));\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const parentPrefix = prefix ? this.toParent(prefix) : this.prefixSlash;\n const entries = await this.parent.listFiles(parentPrefix);\n const out: ContentEntry[] = [];\n for (const e of entries) {\n const local = this.fromParent(e.path);\n if (local === null) continue;\n out.push({ path: local, mimeType: e.mimeType, size: e.size });\n }\n return out;\n }\n\n exists(path: string): Promise<boolean> {\n return this.parent.exists(this.toParent(path));\n }\n\n /** Sidecars are not document roots. */\n async getDocumentPath(): Promise<string | null> {\n return null;\n }\n\n async readDocument(): Promise<string | null> {\n return null;\n }\n\n async writeDocument(): Promise<void> {\n throw new Error(\n 'ScopedContentContainer is a sidecar view and does not support writeDocument(). ' +\n 'Write to a specific path with writeFile() instead.',\n );\n }\n}\n\n/** Factory: convenience wrapper for `new ScopedContentContainer(parent, prefix)`. */\nexport function scopeContainer(parent: ContentContainer, prefix: string): ScopedContentContainer {\n return new ScopedContentContainer(parent, prefix);\n}\n","/**\n * MediaProviderFromContainer — bridges ContentContainer to MediaProvider.\n *\n * Creates a MediaProvider that resolves relative paths by reading binary data\n * from a ContentContainer and generating blob URLs. Blob URLs are cached and\n * revoked on dispose().\n *\n * This allows any ContentContainer (memory, slot-backed, zip-loaded) to be\n * used with existing rendering components (DocPlayer, ImageLayer, VideoLayer)\n * that consume MediaProvider.\n */\n\nimport type { MediaProvider, MediaEntry } from '../schemas/MediaProvider.js';\nimport type { ContentContainer } from './ContentContainer.js';\n\n/**\n * Create a MediaProvider backed by a ContentContainer.\n *\n * @param container — The ContentContainer to read/write media from\n * @returns A MediaProvider that resolves paths to blob URLs\n */\nexport function createMediaProviderFromContainer(container: ContentContainer): MediaProvider {\n const blobUrlCache = new Map<string, string>();\n\n return {\n async resolveUrl(relativePath: string): Promise<string> {\n const cached = blobUrlCache.get(relativePath);\n if (cached) return cached;\n\n const data = await container.readFile(relativePath);\n if (!data) return relativePath;\n\n const entries = await container.listFiles();\n const entry = entries.find((e) => e.path === relativePath);\n const mimeType = entry?.mimeType ?? 'application/octet-stream';\n\n const blob = new Blob([data], { type: mimeType });\n const url = URL.createObjectURL(blob);\n blobUrlCache.set(relativePath, url);\n return url;\n },\n\n async listMedia(): Promise<MediaEntry[]> {\n const entries = await container.listFiles();\n return entries\n .filter((e) => !e.path.toLowerCase().endsWith('.md'))\n .map((e) => ({\n name: e.path,\n mimeType: e.mimeType,\n size: e.size,\n }));\n },\n\n async addMedia(\n name: string,\n data: ArrayBuffer | Blob | Uint8Array,\n mimeType: string,\n ): Promise<string> {\n // Invalidate any cached blob URL for this path before overwriting\n const cached = blobUrlCache.get(name);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(name);\n }\n\n let buffer: ArrayBuffer | Uint8Array;\n if (data instanceof Blob) {\n buffer = await data.arrayBuffer();\n } else {\n buffer = data;\n }\n await container.writeFile(name, buffer, mimeType);\n return name;\n },\n\n async removeMedia(relativePath: string): Promise<void> {\n const cached = blobUrlCache.get(relativePath);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(relativePath);\n }\n await container.removeFile(relativePath);\n },\n\n dispose(): void {\n for (const url of blobUrlCache.values()) {\n URL.revokeObjectURL(url);\n }\n blobUrlCache.clear();\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,24 +0,0 @@
1
- // src/versions/timestamp.ts
2
- var TIMESTAMP_RE = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/;
3
- function pad2(n) {
4
- return n < 10 ? `0${n}` : String(n);
5
- }
6
- function formatVersionTimestamp(date) {
7
- return String(date.getUTCFullYear()).padStart(4, "0") + pad2(date.getUTCMonth() + 1) + pad2(date.getUTCDate()) + "T" + pad2(date.getUTCHours()) + pad2(date.getUTCMinutes()) + pad2(date.getUTCSeconds()) + "Z";
8
- }
9
- function parseVersionTimestamp(stamp) {
10
- const m = TIMESTAMP_RE.exec(stamp);
11
- if (!m) return null;
12
- const [, y, mo, d, h, mi, s] = m;
13
- const ms = Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));
14
- if (Number.isNaN(ms)) return null;
15
- return new Date(ms);
16
- }
17
- var VERSION_TIMESTAMP_PATTERN = TIMESTAMP_RE;
18
-
19
- export {
20
- formatVersionTimestamp,
21
- parseVersionTimestamp,
22
- VERSION_TIMESTAMP_PATTERN
23
- };
24
- //# sourceMappingURL=chunk-JELIRVDP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/versions/timestamp.ts"],"sourcesContent":["/**\n * Sortable, human-readable timestamps for version filenames.\n *\n * Format: ISO 8601 basic, UTC, second precision, `Z` suffix —\n * e.g. `20260430T152030Z`. Lexicographic order matches chronological order,\n * so `listFiles` returns versions in time order without parsing.\n */\n\nconst TIMESTAMP_RE = /^(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})Z$/;\n\nfunction pad2(n: number): string {\n return n < 10 ? `0${n}` : String(n);\n}\n\n/**\n * Format a Date as a sortable, filename-safe UTC timestamp string.\n */\nexport function formatVersionTimestamp(date: Date): string {\n return (\n String(date.getUTCFullYear()).padStart(4, '0') +\n pad2(date.getUTCMonth() + 1) +\n pad2(date.getUTCDate()) +\n 'T' +\n pad2(date.getUTCHours()) +\n pad2(date.getUTCMinutes()) +\n pad2(date.getUTCSeconds()) +\n 'Z'\n );\n}\n\n/**\n * Parse a version timestamp string back to a Date. Returns null if the input\n * doesn't match the expected format.\n */\nexport function parseVersionTimestamp(stamp: string): Date | null {\n const m = TIMESTAMP_RE.exec(stamp);\n if (!m) return null;\n const [, y, mo, d, h, mi, s] = m;\n const ms = Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));\n if (Number.isNaN(ms)) return null;\n return new Date(ms);\n}\n\n/**\n * The pattern a valid version timestamp matches. Exported so other modules\n * can validate filenames without re-deriving the regex.\n */\nexport const VERSION_TIMESTAMP_PATTERN = TIMESTAMP_RE;\n"],"mappings":";AAQA,IAAM,eAAe;AAErB,SAAS,KAAK,GAAmB;AAC/B,SAAO,IAAI,KAAK,IAAI,CAAC,KAAK,OAAO,CAAC;AACpC;AAKO,SAAS,uBAAuB,MAAoB;AACzD,SACE,OAAO,KAAK,eAAe,CAAC,EAAE,SAAS,GAAG,GAAG,IAC7C,KAAK,KAAK,YAAY,IAAI,CAAC,IAC3B,KAAK,KAAK,WAAW,CAAC,IACtB,MACA,KAAK,KAAK,YAAY,CAAC,IACvB,KAAK,KAAK,cAAc,CAAC,IACzB,KAAK,KAAK,cAAc,CAAC,IACzB;AAEJ;AAMO,SAAS,sBAAsB,OAA4B;AAChE,QAAM,IAAI,aAAa,KAAK,KAAK;AACjC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,CAAC,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI;AAC/B,QAAM,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC;AAC1F,MAAI,OAAO,MAAM,EAAE,EAAG,QAAO;AAC7B,SAAO,IAAI,KAAK,EAAE;AACpB;AAMO,IAAM,4BAA4B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/schemas/CustomTemplates.ts","../src/schemas/Theme.ts","../src/schemas/colorUtils.ts","../src/schemas/themeValidator.ts","../src/schemas/themes/standard.json","../src/schemas/themes/standard-dark.json","../src/schemas/themes/documentary.json","../src/schemas/themes/minimalist.json","../src/schemas/themes/bold.json","../src/schemas/themes/morning-light.json","../src/schemas/themes/tech-dark.json","../src/schemas/themes/magazine.json","../src/schemas/themes/cinematic.json","../src/schemas/themes/warm-earth.json","../src/schemas/themes/gezellig.json","../src/schemas/themes/index.ts","../src/schemas/themeLibrary.ts","../src/schemas/fontStacks.ts"],"sourcesContent":["/**\n * Custom Templates Schema\n *\n * User-defined block layout templates. The author designs a visual\n * layout once (in the editor's TemplateDesigner) and saves it as a\n * `CustomTemplateDefinition`. The definition lives either in the\n * document's frontmatter (per-doc, portable, ships with the markdown)\n * or in the user's local library (cross-doc reuse via localStorage).\n *\n * A custom template's content is just a `Layer[]` — the same shape that\n * built-in templates emit at expansion time. The novel bit is\n * *placeholder tokens*: TextLayer / ImageLayer content fields may carry\n * strings like `{title}`, `{content}`, `{children}`, or `{image:N}`\n * that the resolver (see `doc/templates/tokens/resolveTokens.ts`)\n * substitutes against the source Block at render time.\n *\n * Responsiveness model: every numeric position field in `layers` is\n * stored as a `%`-string relative to `viewport`, so the same template\n * renders correctly at any of Squisq's viewport presets (landscape,\n * portrait, square). The `viewport` field itself is purely an\n * authoring-time reference — it tells the designer canvas which aspect\n * ratio to mount with, and the thumbnail renderer which viewBox to use.\n */\n\nimport type { Layer } from './Doc.js';\n\n/**\n * Iteration directive for a custom-template layer.\n *\n * A layer that carries a `repeat` is cloned once per item of a source\n * collection at render time (see `resolveTokens`). The clones are laid\n * out in a row or column, offset from the base position by the layer's\n * own width/height plus `gap`, and each clone resolves per-item tokens\n * (`{item}`, `{item:src}`, `{item:label}`, `{index}`) against its item.\n */\nexport interface LayerRepeat {\n /**\n * Which of the source Block's collections to iterate:\n * - `images` — every image in the block body (alt + url)\n * - `children` — child block titles\n * - `listItems` — top-level list-item text in the block body\n */\n source: 'images' | 'children' | 'listItems';\n\n /**\n * Layout axis for the clones. `column` (default) stacks them\n * vertically (offsets `position.y`); `row` lays them out horizontally\n * (offsets `position.x`).\n */\n direction?: 'row' | 'column';\n\n /**\n * Extra spacing added between consecutive clones, in the same unit as\n * the layer's `width`/`height`. Defaults to 24.\n */\n gap?: number;\n\n /** Cap on the number of clones rendered (omit for \"all items\"). */\n max?: number;\n}\n\n/**\n * A custom-template layer: a normal render `Layer` that may additionally\n * carry a `repeat` directive. This is a strict superset of the core\n * `Layer` type used only inside `CustomTemplateDefinition.layers`; the\n * resolver strips `repeat` before emitting the final `Layer[]`, so the\n * core `Layer` type is never widened.\n */\nexport type CustomTemplateLayer = Layer & { repeat?: LayerRepeat };\n\n/**\n * A single user-defined template. Stored in `Doc.customTemplates`\n * (frontmatter-backed) or in the user's local library.\n */\nexport interface CustomTemplateDefinition {\n /**\n * Stable id used in heading annotations (`### Foo {[name]}`). Must be\n * a slug — lowercase alphanumerics, hyphens. The picker enforces\n * uniqueness within a (doc + library) merged namespace.\n */\n name: string;\n\n /** Human-readable label shown in the template picker. */\n label: string;\n\n /** Optional one-sentence description for the picker card. */\n description?: string;\n\n /**\n * Authoring viewport — the canvas size the designer drew against.\n * Stored so the designer and thumbnail renderer can reproduce the\n * same canvas. Layer positions are stored as `%`-strings, so the\n * actual render-time viewport can differ from this without breaking\n * the layout. Defaults to 1920×1080 landscape.\n */\n viewport: {\n width: number;\n height: number;\n };\n\n /**\n * The visual content. Every `position.x` / `position.y` /\n * `position.width` / `position.height` should be a `%`-string at\n * save time (the designer's normalizePositions step enforces this).\n *\n * Tokens supported (grammar v2):\n * - TextLayer.content.text — `{title}`, `{content}`, `{children}`,\n * `{image:N}` (Nth image's alt text), `{attr:key}` (block\n * attribute), plus a pipe default on any token\n * (`{attr:subtitle|Untitled}`).\n * - ImageLayer.content.src — `{image:N}` (the URL) and `{attr:key}`,\n * with pipe defaults (`{image:1|fallback.jpg}`).\n * - Inside a layer with `repeat`, per-item tokens: `{item}`,\n * `{item:src}`, `{item:label}`, `{index}` (1-based).\n *\n * A layer may carry a `repeat` directive (see {@link LayerRepeat}) to\n * be cloned once per item of a source collection.\n */\n layers: CustomTemplateLayer[];\n}\n\n/**\n * Tag value for the YAML frontmatter key that carries inlined custom\n * template definitions. Exported so the markdown bridge stays in sync.\n */\nexport const FRONTMATTER_CUSTOM_TEMPLATES_KEY = 'squisq-custom-templates';\n","/**\n * Theme System\n *\n * A Theme bundles color palette, typography, visual style, render-style\n * algorithm, and per-block color schemes into one JSON-serializable object.\n *\n * Built-in themes and customizer-authored themes share this exact schema.\n * Customizer-authored themes additionally specify `seedColors` so the few\n * fields the user picked can be re-edited later; built-ins typically omit\n * `seedColors` and ship with explicit `colors` already filled in.\n *\n * Design principles:\n * - Fully JSON-serializable. No functions; no raw CSS font strings.\n * - Font families are structured `FontFamily` references resolved by\n * `resolveFontFamily()` at render time.\n * - Doc carries an optional `themeId`; resolution happens at render time\n * via `resolveTheme(id)`.\n * - `createTheme` deep-merges a base theme with partial overrides;\n * `compileTheme` fills in defaults and derives missing color slots from\n * `seedColors`; both produce a complete `Theme`.\n */\n\nimport type { LayoutHints } from './LayoutStrategy.js';\nimport type { AnimationType, ImageTreatment, TransitionType } from './Doc.js';\nimport type { PersistentLayerConfig } from './BlockTemplates.js';\n\n// ============================================\n// Schema version\n// ============================================\n\n/** Current Theme schema version. Bump on breaking changes; loader migrates. */\nexport const THEME_SCHEMA_VERSION = '1' as const;\nexport type ThemeSchemaVersion = typeof THEME_SCHEMA_VERSION;\n\n/**\n * Frontmatter key under which a document inlines its custom Theme\n * definitions. The theme analog of `FRONTMATTER_CUSTOM_TEMPLATES_KEY`\n * (custom block templates). See `doc/customThemesFrontmatter.ts` for the\n * codec and `doc/resolveDocTheme.ts` for doc-scoped resolution.\n */\nexport const FRONTMATTER_CUSTOM_THEMES_KEY = 'squisq-custom-themes';\n\n// ============================================\n// Color Palette\n// ============================================\n\n/**\n * Core color palette for a theme. Every color is a `#rrggbb` hex string.\n */\nexport interface ThemeColorPalette {\n /** Primary accent color */\n primary: string;\n /** Secondary accent color */\n secondary: string;\n /** Background color (typically dark) */\n background: string;\n /** Lighter background for contrast panels */\n backgroundLight: string;\n /** Main text color */\n text: string;\n /** Muted/secondary text color */\n textMuted: string;\n /** Highlight/emphasis color */\n highlight: string;\n /** Warning/alert color */\n warning: string;\n}\n\n/**\n * A named color scheme used by templates for per-block color variation\n * (e.g., statHighlight or sectionHeader).\n */\nexport interface ThemeColorScheme {\n /** Background fill */\n bg: string;\n /** Primary text tint */\n text: string;\n /** Accent / secondary tint */\n accent: string;\n}\n\n/**\n * Optional authoring metadata. When present and `colors` is partial,\n * `compileTheme` derives missing color slots from these seeds via OKLCh\n * lightening / darkening. Round-trips a customizer-authored theme back\n * into editable form.\n */\nexport interface ThemeSeedColors {\n primary: string;\n secondary?: string;\n accent?: string;\n background?: string;\n text?: string;\n}\n\n// ============================================\n// Typography\n// ============================================\n\n/** Categorical bucket for a font family — drives default fallback. */\nexport type FontFamilyKind = 'sans' | 'serif' | 'mono' | 'display';\n\n/**\n * Structured reference to a font family. Either a curated stack id (looked\n * up in `AVAILABLE_FONT_STACKS`) or a custom user-supplied name with a\n * structured fallback bucket. Themes never carry raw CSS family strings.\n */\nexport type FontFamily =\n | { stackId: string }\n | {\n custom: {\n name: string;\n fallback: 'serif' | 'sans-serif' | 'monospace' | 'system-ui';\n };\n };\n\n/**\n * Typography settings for a theme.\n */\nexport interface ThemeTypography {\n /** Font family for body / description text */\n bodyFont: FontFamily;\n /** Font family for titles and headings */\n titleFont: FontFamily;\n /** Font family for code / monospaced text (optional) */\n monoFont?: FontFamily;\n /** Multiplier applied to LayoutHints.titleScale (default 1.0) */\n titleScale?: number;\n /** Multiplier applied to LayoutHints.bodyScale (default 1.0) */\n bodyScale?: number;\n /** Default body line height (default 1.4) */\n lineHeight?: number;\n /** Default title line height */\n titleLineHeight?: number;\n /** Default title font weight */\n titleWeight?: 'normal' | 'bold';\n}\n\n// ============================================\n// Visual Style\n// ============================================\n\n/**\n * Global visual-style knobs that templates consult.\n */\nexport interface ThemeStyle {\n /** Default border radius for cards / shapes (px) */\n borderRadius?: number;\n /** Whether templates should default to text shadows */\n textShadow?: boolean;\n /** Darkness of overlay on image-backed blocks (0–1) */\n overlayOpacity?: number;\n /** Multiplier on all animation durations (1.0 = normal, <1 faster, >1 slower) */\n animationSpeed?: number;\n /** Default horizontal padding for text (percentage string, e.g. \"5%\") */\n blockPadding?: string;\n /**\n * Photographic grade applied to template imagery (full-bleed photos,\n * feature halves, accent strips) so photos look native to the theme.\n * Duotone tints default to the theme primary. Blocks opt out per\n * template via `imageTreatment: 'none'`.\n */\n imageTreatment?: ImageTreatment;\n}\n\n// ============================================\n// Render Style\n// ============================================\n\n/**\n * Render-style algorithm preset. Controls layout tweaks, default animations,\n * transitions, and per-template behavioral hints.\n */\nexport interface RenderStyle {\n /** Identifier for this algorithmic approach (e.g. \"documentary\", \"magazine\") */\n name: string;\n /** Partial overrides merged onto the orientation-based LayoutHints */\n layoutOverrides?: Partial<LayoutHints>;\n /** Default entrance animation for text layers */\n defaultTextAnimation?: AnimationType;\n /** Default animation for background / image layers */\n defaultImageAnimation?: AnimationType;\n /** Whether to apply Ken Burns ambient motion to images by default */\n ambientMotion?: boolean;\n /** Default block-to-block transition */\n defaultTransition?: { type: TransitionType; duration?: number };\n /**\n * Per-template behavioral hints. Keys are template names, values are\n * string/number/boolean maps that templates can read to vary their output.\n * Templates that consume hints publish a `hintSchema` export documenting\n * the keys they recognise.\n */\n templateHints?: Record<string, Record<string, string | number | boolean>>;\n}\n\n// ============================================\n// Theme\n// ============================================\n\n/**\n * A complete, JSON-serializable theme definition. Built-in and customizer-\n * authored themes share this exact shape.\n */\nexport interface Theme {\n /** Schema version. Always '1' for now. */\n schemaVersion: ThemeSchemaVersion;\n /** Unique identifier (e.g. \"documentary\") */\n id: string;\n /** Human-readable display name */\n name: string;\n /** Short description for theme pickers */\n description?: string;\n /**\n * Id of the theme this custom theme was derived from, if any. Recorded\n * by `compileTheme({ base })` so a customizer can re-open the theme and\n * re-inherit the base's render style / color schemes / typography.\n * Absent on built-ins.\n */\n basedOn?: string;\n /** Optional authoring seeds (customizer fills these; built-ins typically omit) */\n seedColors?: ThemeSeedColors;\n /** Color palette */\n colors: ThemeColorPalette;\n /** Typography settings */\n typography: ThemeTypography;\n /** Global visual-style knobs */\n style: ThemeStyle;\n /** Algorithmic render-style preset */\n renderStyle: RenderStyle;\n /**\n * Named color schemes for per-block color variation.\n * Templates reference these by name (e.g. \"blue\", \"warm\").\n */\n colorSchemes: Record<string, ThemeColorScheme>;\n /** Optional persistent layers baked into the theme */\n persistentLayers?: PersistentLayerConfig;\n}\n\n// ============================================\n// Deep-Partial helper type\n// ============================================\n\n/**\n * Recursively makes every property optional.\n */\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n\n// ============================================\n// Helpers\n// ============================================\n\n/**\n * Deep-merge `source` into `target`, returning a new object.\n * Arrays are replaced wholesale (not concatenated).\n */\nfunction deepMerge<T extends Record<string, unknown>>(target: T, source: DeepPartial<T>): T {\n const result = { ...target } as Record<string, unknown>;\n for (const key of Object.keys(source)) {\n const srcVal = (source as Record<string, unknown>)[key];\n const tgtVal = (target as Record<string, unknown>)[key];\n if (\n srcVal !== null &&\n srcVal !== undefined &&\n typeof srcVal === 'object' &&\n !Array.isArray(srcVal) &&\n tgtVal !== null &&\n tgtVal !== undefined &&\n typeof tgtVal === 'object' &&\n !Array.isArray(tgtVal)\n ) {\n result[key] = deepMerge(\n tgtVal as Record<string, unknown>,\n srcVal as DeepPartial<Record<string, unknown>>,\n );\n } else if (srcVal !== undefined) {\n result[key] = srcVal;\n }\n }\n return result as T;\n}\n\n/**\n * Create a new theme by deep-merging overrides onto a base theme.\n * The returned theme gets its own `id` if one is provided in overrides,\n * otherwise keeps the base theme's `id` suffixed with \"-custom\".\n */\nexport function createTheme(base: Theme, overrides: DeepPartial<Theme>): Theme {\n const merged = deepMerge(\n base as unknown as Record<string, unknown>,\n overrides as DeepPartial<Record<string, unknown>>,\n ) as unknown as Theme;\n if (!overrides.id && merged.id === base.id) {\n merged.id = `${base.id}-custom`;\n }\n if (!merged.schemaVersion) merged.schemaVersion = THEME_SCHEMA_VERSION;\n return merged;\n}\n\n// ============================================\n// Surface Schemes — orthogonal to Theme\n// ============================================\n\n/**\n * A Surface Scheme is the light/dark axis, orthogonal to the editorial\n * identity of a Theme. A Theme chooses voice (serif vs sans, muted vs\n * bold, documentary vs magazine); a SurfaceScheme chooses what the paper\n * looks like. Any theme can render on either surface.\n */\nexport interface SurfaceScheme {\n /** Identifier — 'light', 'dark', or a custom id. */\n id: string;\n background: string;\n backgroundLight: string;\n text: string;\n textMuted: string;\n}\n\n/** Near-white paper with dark text — standard light mode. */\nexport const LIGHT_SURFACE: SurfaceScheme = {\n id: 'light',\n background: '#ffffff',\n backgroundLight: '#f5f5f5',\n text: '#1a1a1a',\n textMuted: '#666666',\n};\n\n/** Dark charcoal paper with light text — standard dark mode. */\nexport const DARK_SURFACE: SurfaceScheme = {\n id: 'dark',\n background: '#1a202c',\n backgroundLight: '#2d3748',\n text: '#f0f0f0',\n textMuted: '#a0aec0',\n};\n\n/**\n * Overlay a SurfaceScheme's surface colors onto a Theme's palette,\n * leaving everything else (primary, highlight, warning, typography,\n * style, renderStyle, colorSchemes) untouched.\n */\nexport function applySurface(theme: Theme, surface: SurfaceScheme): Theme {\n return {\n ...theme,\n colors: {\n ...theme.colors,\n background: surface.background,\n backgroundLight: surface.backgroundLight,\n text: surface.text,\n textMuted: surface.textMuted,\n },\n };\n}\n\n// ============================================\n// Runtime registry — for custom themes\n// ============================================\n\nconst CUSTOM_THEME_REGISTRY = new Map<string, Theme>();\n\n/**\n * Register a Theme so it can be looked up by id via `resolveTheme(id)`.\n * Lets `Doc.themeId` round-trip through Doc serialization for custom themes.\n *\n * Registered themes take precedence over built-ins with the same id.\n */\nexport function registerTheme(theme: Theme): void {\n CUSTOM_THEME_REGISTRY.set(theme.id, theme);\n}\n\n/** Remove a previously registered theme. */\nexport function unregisterTheme(id: string): void {\n CUSTOM_THEME_REGISTRY.delete(id);\n}\n\n/** Snapshot of all currently registered (non-built-in) themes. */\nexport function getRegisteredThemes(): Theme[] {\n return Array.from(CUSTOM_THEME_REGISTRY.values());\n}\n\n/** @internal — used by themeLibrary's `resolveTheme` to check the registry first. */\nexport function lookupRegisteredTheme(id: string | undefined): Theme | undefined {\n if (!id) return undefined;\n return CUSTOM_THEME_REGISTRY.get(id);\n}\n","/**\n * Color Utilities\n *\n * Pure-JS color math used by theme compilation and contrast checks.\n * No dependencies. Operates on `#rrggbb` hex strings.\n *\n * Internally uses OKLCh — perceptually uniform, so lightening by 0.1\n * looks like the same change at any starting point. Out-of-gamut\n * results are clamped to sRGB.\n */\n\nconst HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\n/** Test whether a string is a valid `#rgb` or `#rrggbb` hex color. */\nexport function isHex(value: string): boolean {\n return HEX_RE.test(value);\n}\n\n/** Parse `#rgb` or `#rrggbb` into 0..1 sRGB triplet. Returns null on failure. */\nfunction parseHex(hex: string): [number, number, number] | null {\n if (!HEX_RE.test(hex)) return null;\n let body = hex.slice(1);\n if (body.length === 3)\n body = body\n .split('')\n .map((c) => c + c)\n .join('');\n return [\n parseInt(body.slice(0, 2), 16) / 255,\n parseInt(body.slice(2, 4), 16) / 255,\n parseInt(body.slice(4, 6), 16) / 255,\n ];\n}\n\nfunction toHex(rgb: [number, number, number]): string {\n const ch = (v: number) => {\n const c = Math.max(0, Math.min(255, Math.round(v * 255)));\n return c.toString(16).padStart(2, '0');\n };\n return '#' + ch(rgb[0]) + ch(rgb[1]) + ch(rgb[2]);\n}\n\nfunction srgbToLinear(c: number): number {\n return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(c: number): number {\n return c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;\n}\n\ninterface OKLCh {\n L: number;\n C: number;\n h: number;\n}\n\nfunction rgbToOklch(rgb: [number, number, number]): OKLCh {\n const [sr, sg, sb] = rgb;\n const r = srgbToLinear(sr);\n const g = srgbToLinear(sg);\n const b = srgbToLinear(sb);\n\n const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;\n const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;\n const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;\n\n const l_ = Math.cbrt(l);\n const m_ = Math.cbrt(m);\n const s_ = Math.cbrt(s);\n\n const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;\n const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;\n const bb = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;\n\n const C = Math.sqrt(a * a + bb * bb);\n let h = (Math.atan2(bb, a) * 180) / Math.PI;\n if (h < 0) h += 360;\n return { L, C, h };\n}\n\nfunction oklchToRgb({ L, C, h }: OKLCh): [number, number, number] {\n const hr = (h * Math.PI) / 180;\n const a = C * Math.cos(hr);\n const bb = C * Math.sin(hr);\n\n const l_ = L + 0.3963377774 * a + 0.2158037573 * bb;\n const m_ = L - 0.1055613458 * a - 0.0638541728 * bb;\n const s_ = L - 0.0894841775 * a - 1.291485548 * bb;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n const r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;\n const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;\n const b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;\n\n return [\n Math.max(0, Math.min(1, linearToSrgb(r))),\n Math.max(0, Math.min(1, linearToSrgb(g))),\n Math.max(0, Math.min(1, linearToSrgb(b))),\n ];\n}\n\n/**\n * Lighten a color by `amount` (0..1) in OKLCh L space.\n * Falls back to the input on parse failure.\n */\nexport function oklchLighten(hex: string, amount: number): string {\n const rgb = parseHex(hex);\n if (!rgb) return hex;\n const lch = rgbToOklch(rgb);\n lch.L = Math.max(0, Math.min(1, lch.L + amount));\n return toHex(oklchToRgb(lch));\n}\n\n/**\n * Darken a color by `amount` (0..1) in OKLCh L space.\n * Falls back to the input on parse failure.\n */\nexport function oklchDarken(hex: string, amount: number): string {\n return oklchLighten(hex, -amount);\n}\n\n/**\n * Adjust the OKLCh chroma of a color by a multiplier (e.g. 0.7 to mute).\n */\nexport function oklchSetChroma(hex: string, multiplier: number): string {\n const rgb = parseHex(hex);\n if (!rgb) return hex;\n const lch = rgbToOklch(rgb);\n lch.C = Math.max(0, lch.C * multiplier);\n return toHex(oklchToRgb(lch));\n}\n\n/**\n * WCAG relative luminance of a hex color, returned as 0..1.\n */\nexport function relativeLuminance(hex: string): number {\n const rgb = parseHex(hex);\n if (!rgb) return 0;\n const [r, g, b] = rgb.map(srgbToLinear) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Hue of a hex color in HSL degrees (0..360). Returns 0 for pure grays\n * and on parse failure. Used by the duotone image treatment to aim its\n * `hue-rotate()` at the theme's tint color.\n */\nexport function hexHueDegrees(hex: string): number {\n const rgb = parseHex(hex);\n if (!rgb) return 0;\n const [r, g, b] = rgb;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n if (max === min) return 0;\n const d = max - min;\n let h: number;\n if (max === r) h = ((g - b) / d) % 6;\n else if (max === g) h = (b - r) / d + 2;\n else h = (r - g) / d + 4;\n return Math.round((h * 60 + 360) % 360);\n}\n\n/**\n * Convert a hex color + alpha (0..1) to an `rgba()` string.\n * Falls back to the input on parse failure (e.g. a value that is\n * already an rgba()/gradient string).\n */\nexport function withAlpha(hex: string, alpha: number): string {\n const rgb = parseHex(hex);\n if (!rgb) return hex;\n const a = Math.max(0, Math.min(1, alpha));\n const ch = (v: number) => Math.round(v * 255);\n return `rgba(${ch(rgb[0])}, ${ch(rgb[1])}, ${ch(rgb[2])}, ${a})`;\n}\n\n/**\n * WCAG contrast ratio between two hex colors. Returns 1..21.\n */\nexport function contrastRatio(a: string, b: string): number {\n const la = relativeLuminance(a);\n const lb = relativeLuminance(b);\n const lighter = Math.max(la, lb);\n const darker = Math.min(la, lb);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick a near-white or near-black text color that contrasts well against `bg`.\n */\nexport function pickContrastingText(bg: string, light = '#f7fafc', dark = '#1a202c'): string {\n return contrastRatio(bg, dark) >= contrastRatio(bg, light) ? dark : light;\n}\n\n/**\n * Derive a 5-step lighter→darker scale from a seed color.\n * Stops are evenly spaced in OKLCh L space around the seed.\n * `spread` controls amplitude (0.05 = subtle, 0.15 = balanced, 0.22 = high).\n */\nexport function deriveScale(\n seedHex: string,\n spread = 0.15,\n): {\n lighter2: string;\n lighter1: string;\n base: string;\n darker1: string;\n darker2: string;\n} {\n return {\n lighter2: oklchLighten(seedHex, spread),\n lighter1: oklchLighten(seedHex, spread / 2),\n base: seedHex,\n darker1: oklchDarken(seedHex, spread / 2),\n darker2: oklchDarken(seedHex, spread),\n };\n}\n","/**\n * Theme Validator\n *\n * Hand-rolled validator for `Theme` JSON. No dependencies. Produces a\n * flat list of typed errors with JSON paths, suitable for surfacing in\n * the customizer UI or throwing at module init for built-in themes.\n *\n * Design: walk the candidate object, push errors for each violation.\n * Coverage is exhaustive for required fields and shapes; permissive on\n * forward-compatible fields (unknown keys are ignored, not rejected).\n */\n\nimport type { Theme, ThemeColorPalette } from './Theme.js';\nimport { THEME_SCHEMA_VERSION } from './Theme.js';\nimport { isHex } from './colorUtils.js';\nimport { isTransitionType } from './Transitions.js';\n\nexport interface ValidationError {\n path: string;\n message: string;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n /** Present only when `valid === true`. The same input typed as `Theme`. */\n theme?: Theme;\n}\n\nconst VALID_FALLBACK = new Set(['serif', 'sans-serif', 'monospace', 'system-ui']);\nconst VALID_TITLE_WEIGHT = new Set(['normal', 'bold']);\nconst VALID_GRADIENT_PRESETS = new Set([\n 'dark-vignette',\n 'radial-dark',\n 'warm-sunset',\n 'cool-blue',\n 'earth-tones',\n]);\n\nclass V {\n errors: ValidationError[] = [];\n err(path: string, message: string): void {\n this.errors.push({ path, message });\n }\n isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n }\n isString(v: unknown): v is string {\n return typeof v === 'string';\n }\n isNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n }\n isBoolean(v: unknown): v is boolean {\n return typeof v === 'boolean';\n }\n hex(path: string, v: unknown): void {\n if (!this.isString(v)) {\n this.err(path, `expected hex color string, got ${typeof v}`);\n } else if (!isHex(v)) {\n this.err(path, `expected #rgb or #rrggbb hex color, got \"${v}\"`);\n }\n }\n\n palette(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n const required: (keyof ThemeColorPalette)[] = [\n 'primary',\n 'secondary',\n 'background',\n 'backgroundLight',\n 'text',\n 'textMuted',\n 'highlight',\n 'warning',\n ];\n for (const k of required) this.hex(`${path}.${k}`, v[k]);\n }\n\n colorScheme(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n this.hex(`${path}.bg`, v.bg);\n this.hex(`${path}.text`, v.text);\n this.hex(`${path}.accent`, v.accent);\n }\n\n colorSchemes(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object map');\n return;\n }\n for (const key of Object.keys(v)) {\n this.colorScheme(`${path}.${key}`, v[key]);\n }\n }\n\n fontFamily(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected FontFamily object ({ stackId } or { custom })');\n return;\n }\n if ('stackId' in v) {\n if (!this.isString(v.stackId) || v.stackId.length === 0) {\n this.err(`${path}.stackId`, 'expected non-empty string');\n }\n return;\n }\n if ('custom' in v) {\n const c = v.custom;\n if (!this.isObject(c)) {\n this.err(`${path}.custom`, 'expected { name, fallback } object');\n return;\n }\n if (!this.isString(c.name) || c.name.length === 0) {\n this.err(`${path}.custom.name`, 'expected non-empty string');\n }\n if (!this.isString(c.fallback) || !VALID_FALLBACK.has(c.fallback)) {\n this.err(\n `${path}.custom.fallback`,\n `expected one of: serif, sans-serif, monospace, system-ui`,\n );\n }\n return;\n }\n this.err(path, 'expected { stackId } or { custom: { name, fallback } }');\n }\n\n typography(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n this.fontFamily(`${path}.bodyFont`, v.bodyFont);\n this.fontFamily(`${path}.titleFont`, v.titleFont);\n if (v.monoFont !== undefined) this.fontFamily(`${path}.monoFont`, v.monoFont);\n for (const k of ['titleScale', 'bodyScale', 'lineHeight', 'titleLineHeight']) {\n if (v[k] !== undefined && !this.isNumber(v[k])) {\n this.err(`${path}.${k}`, `expected number, got ${typeof v[k]}`);\n }\n }\n if (v.titleWeight !== undefined) {\n if (!this.isString(v.titleWeight) || !VALID_TITLE_WEIGHT.has(v.titleWeight)) {\n this.err(`${path}.titleWeight`, 'expected \"normal\" or \"bold\"');\n }\n }\n }\n\n style(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n if (v.borderRadius !== undefined && !this.isNumber(v.borderRadius)) {\n this.err(`${path}.borderRadius`, 'expected number');\n }\n if (v.textShadow !== undefined && !this.isBoolean(v.textShadow)) {\n this.err(`${path}.textShadow`, 'expected boolean');\n }\n for (const k of ['overlayOpacity', 'animationSpeed']) {\n if (v[k] !== undefined && !this.isNumber(v[k])) {\n this.err(`${path}.${k}`, 'expected number');\n }\n }\n if (v.blockPadding !== undefined && !this.isString(v.blockPadding)) {\n this.err(`${path}.blockPadding`, 'expected string (percentage e.g. \"5%\")');\n }\n if (v.imageTreatment !== undefined) {\n this.imageTreatment(`${path}.imageTreatment`, v.imageTreatment);\n }\n }\n\n imageTreatment(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n const kinds = ['none', 'mono', 'duotone', 'warm', 'cool'];\n if (!this.isString(v.type) || !kinds.includes(v.type)) {\n this.err(`${path}.type`, `expected one of ${kinds.join('|')}`);\n }\n if (v.strength !== undefined && !this.isNumber(v.strength)) {\n this.err(`${path}.strength`, 'expected number (0..1)');\n }\n if (v.color !== undefined) this.hex(`${path}.color`, v.color);\n }\n\n renderStyle(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n if (!this.isString(v.name) || v.name.length === 0) {\n this.err(`${path}.name`, 'expected non-empty string');\n }\n if (v.ambientMotion !== undefined && !this.isBoolean(v.ambientMotion)) {\n this.err(`${path}.ambientMotion`, 'expected boolean');\n }\n for (const k of ['defaultTextAnimation', 'defaultImageAnimation']) {\n if (v[k] !== undefined && !this.isString(v[k])) {\n this.err(`${path}.${k}`, 'expected animation type string');\n }\n }\n if (v.defaultTransition !== undefined) {\n const t = v.defaultTransition;\n if (!this.isObject(t)) {\n this.err(`${path}.defaultTransition`, 'expected object');\n } else {\n if (!this.isString(t.type) || !isTransitionType(t.type)) {\n this.err(`${path}.defaultTransition.type`, 'expected valid transition type');\n }\n if (t.duration !== undefined && !this.isNumber(t.duration)) {\n this.err(`${path}.defaultTransition.duration`, 'expected number');\n }\n }\n }\n if (v.layoutOverrides !== undefined && !this.isObject(v.layoutOverrides)) {\n this.err(`${path}.layoutOverrides`, 'expected object');\n }\n if (v.templateHints !== undefined) {\n if (!this.isObject(v.templateHints)) {\n this.err(`${path}.templateHints`, 'expected object map');\n } else {\n for (const tplName of Object.keys(v.templateHints)) {\n const hints = v.templateHints[tplName];\n if (!this.isObject(hints)) {\n this.err(`${path}.templateHints.${tplName}`, 'expected object');\n continue;\n }\n for (const key of Object.keys(hints)) {\n const val = hints[key];\n const t = typeof val;\n if (t !== 'string' && t !== 'number' && t !== 'boolean') {\n this.err(\n `${path}.templateHints.${tplName}.${key}`,\n `expected string|number|boolean, got ${t}`,\n );\n }\n }\n }\n }\n }\n }\n\n seedColors(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n if (v.primary === undefined) {\n this.err(`${path}.primary`, 'required when seedColors is present');\n } else {\n this.hex(`${path}.primary`, v.primary);\n }\n for (const k of ['secondary', 'accent', 'background', 'text']) {\n if (v[k] !== undefined) this.hex(`${path}.${k}`, v[k]);\n }\n }\n\n persistentLayer(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n // Either { template, config } or a raw Layer — only validate the template form here\n if ('template' in v) {\n if (!this.isString(v.template)) {\n this.err(`${path}.template`, 'expected string');\n return;\n }\n const cfg = v.config;\n if (!this.isObject(cfg)) {\n this.err(`${path}.config`, 'expected object');\n return;\n }\n if (cfg.type !== v.template) {\n this.err(`${path}.config.type`, `expected \"${v.template}\", got \"${String(cfg.type)}\"`);\n }\n if (v.template === 'gradientBackground' && cfg.preset !== undefined) {\n if (!this.isString(cfg.preset) || !VALID_GRADIENT_PRESETS.has(cfg.preset)) {\n this.err(\n `${path}.config.preset`,\n `expected one of: ${Array.from(VALID_GRADIENT_PRESETS).join(', ')}`,\n );\n }\n }\n if (v.template === 'gradientBackground' && 'gradient' in cfg) {\n this.err(\n `${path}.config.gradient`,\n 'raw CSS gradient strings are not allowed in Theme JSON; use a `preset`',\n );\n }\n if (v.template === 'patternBackground') {\n const patterns = ['dots', 'grid', 'diagonal', 'noise'];\n if (!this.isString(cfg.pattern) || !patterns.includes(cfg.pattern)) {\n this.err(`${path}.config.pattern`, `expected one of ${patterns.join('|')}`);\n }\n for (const k of ['opacity', 'scale']) {\n if (cfg[k] !== undefined && !this.isNumber(cfg[k])) {\n this.err(`${path}.config.${k}`, 'expected number');\n }\n }\n if (cfg.color !== undefined) this.hex(`${path}.config.color`, cfg.color);\n }\n if (v.template === 'vignette') {\n if (cfg.strength !== undefined && !this.isNumber(cfg.strength)) {\n this.err(`${path}.config.strength`, 'expected number (0..1)');\n }\n if (cfg.color !== undefined) this.hex(`${path}.config.color`, cfg.color);\n }\n if (v.template === 'ambientGradient') {\n if (cfg.duration !== undefined && !this.isNumber(cfg.duration)) {\n this.err(`${path}.config.duration`, 'expected number (seconds)');\n }\n for (const k of ['from', 'to']) {\n if (cfg[k] !== undefined) this.hex(`${path}.config.${k}`, cfg[k]);\n }\n }\n }\n // Raw Layer form is permissive — no schema check here\n }\n\n persistentLayers(path: string, v: unknown): void {\n if (!this.isObject(v)) {\n this.err(path, 'expected object');\n return;\n }\n for (const side of ['bottomLayers', 'topLayers']) {\n const arr = v[side];\n if (arr === undefined) continue;\n if (!Array.isArray(arr)) {\n this.err(`${path}.${side}`, 'expected array');\n continue;\n }\n arr.forEach((entry, i) => this.persistentLayer(`${path}.${side}[${i}]`, entry));\n }\n }\n}\n\nexport function validateTheme(input: unknown): ValidationResult {\n const v = new V();\n if (!v.isObject(input)) {\n return { valid: false, errors: [{ path: '', message: 'expected object' }] };\n }\n\n if (input.schemaVersion !== THEME_SCHEMA_VERSION) {\n v.err(\n 'schemaVersion',\n `expected \"${THEME_SCHEMA_VERSION}\", got \"${String(input.schemaVersion)}\"`,\n );\n }\n if (!v.isString(input.id) || input.id.length === 0) {\n v.err('id', 'expected non-empty string');\n }\n if (!v.isString(input.name) || input.name.length === 0) {\n v.err('name', 'expected non-empty string');\n }\n if (input.description !== undefined && !v.isString(input.description)) {\n v.err('description', 'expected string');\n }\n if (input.basedOn !== undefined && !v.isString(input.basedOn)) {\n v.err('basedOn', 'expected string');\n }\n\n if (input.seedColors !== undefined) v.seedColors('seedColors', input.seedColors);\n\n if (input.colors === undefined) {\n v.err('colors', 'required');\n } else {\n v.palette('colors', input.colors);\n }\n\n if (input.typography === undefined) {\n v.err('typography', 'required');\n } else {\n v.typography('typography', input.typography);\n }\n\n if (input.style === undefined) {\n v.err('style', 'required');\n } else {\n v.style('style', input.style);\n }\n\n if (input.renderStyle === undefined) {\n v.err('renderStyle', 'required');\n } else {\n v.renderStyle('renderStyle', input.renderStyle);\n }\n\n if (input.colorSchemes === undefined) {\n v.err('colorSchemes', 'required');\n } else {\n v.colorSchemes('colorSchemes', input.colorSchemes);\n }\n\n if (input.persistentLayers !== undefined) {\n v.persistentLayers('persistentLayers', input.persistentLayers);\n }\n\n if (v.errors.length === 0) {\n return { valid: true, errors: [], theme: input as unknown as Theme };\n }\n return { valid: false, errors: v.errors };\n}\n\n/** Throws on invalid input. Useful at module init for built-in themes. */\nexport function assertTheme(input: unknown, source = 'theme'): Theme {\n const result = validateTheme(input);\n if (!result.valid || !result.theme) {\n const summary = result.errors\n .slice(0, 5)\n .map((e) => ` ${e.path || '<root>'}: ${e.message}`)\n .join('\\n');\n const more = result.errors.length > 5 ? `\\n ... and ${result.errors.length - 5} more` : '';\n throw new Error(`Invalid ${source}:\\n${summary}${more}`);\n }\n return result.theme;\n}\n\n// (Theme types are re-exported from `./Theme.js` via the schemas barrel.)\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"standard\",\n \"name\": \"Standard Light\",\n \"description\": \"Clean and safe — black-on-white, system fonts only, no external font dependencies. Default theme.\",\n \"colors\": {\n \"primary\": \"#2563eb\",\n \"secondary\": \"#475569\",\n \"background\": \"#ffffff\",\n \"backgroundLight\": \"#f1f5f9\",\n \"text\": \"#0f172a\",\n \"textMuted\": \"#475569\",\n \"highlight\": \"#1d4ed8\",\n \"warning\": \"#dc2626\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"system-sans\"\n },\n \"titleFont\": {\n \"stackId\": \"system-serif\"\n },\n \"monoFont\": {\n \"stackId\": \"system-mono\"\n },\n \"titleWeight\": \"bold\"\n },\n \"style\": {\n \"textShadow\": false,\n \"overlayOpacity\": 0.35,\n \"animationSpeed\": 1.0\n },\n \"renderStyle\": {\n \"name\": \"standard\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"ambientMotion\": false,\n \"defaultTransition\": {\n \"type\": \"fade\",\n \"duration\": 0.7\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#dbeafe\",\n \"text\": \"#1d4ed8\",\n \"accent\": \"#2563eb\"\n },\n \"green\": {\n \"bg\": \"#dcfce7\",\n \"text\": \"#166534\",\n \"accent\": \"#16a34a\"\n },\n \"purple\": {\n \"bg\": \"#ede9fe\",\n \"text\": \"#5b21b6\",\n \"accent\": \"#7c3aed\"\n },\n \"red\": {\n \"bg\": \"#fee2e2\",\n \"text\": \"#991b1b\",\n \"accent\": \"#dc2626\"\n },\n \"orange\": {\n \"bg\": \"#ffedd5\",\n \"text\": \"#9a3412\",\n \"accent\": \"#ea580c\"\n },\n \"teal\": {\n \"bg\": \"#ccfbf1\",\n \"text\": \"#115e59\",\n \"accent\": \"#0d9488\"\n }\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"standard-dark\",\n \"name\": \"Standard Dark\",\n \"description\": \"Standard, dark variant. System fonts, dark navy background, light text.\",\n \"colors\": {\n \"primary\": \"#3182ce\",\n \"secondary\": \"#4a5568\",\n \"background\": \"#1a202c\",\n \"backgroundLight\": \"#2d3748\",\n \"text\": \"#f7fafc\",\n \"textMuted\": \"#a0aec0\",\n \"highlight\": \"#4299e1\",\n \"warning\": \"#fc8181\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"system-sans\"\n },\n \"titleFont\": {\n \"stackId\": \"system-serif\"\n },\n \"monoFont\": {\n \"stackId\": \"system-mono\"\n },\n \"titleWeight\": \"bold\"\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.45,\n \"animationSpeed\": 1.0\n },\n \"renderStyle\": {\n \"name\": \"standard\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"ambientMotion\": false,\n \"defaultTransition\": {\n \"type\": \"fade\",\n \"duration\": 0.7\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#1a365d\",\n \"text\": \"#63b3ed\",\n \"accent\": \"#90cdf4\"\n },\n \"green\": {\n \"bg\": \"#22543d\",\n \"text\": \"#9ae6b4\",\n \"accent\": \"#68d391\"\n },\n \"purple\": {\n \"bg\": \"#44337a\",\n \"text\": \"#d6bcfa\",\n \"accent\": \"#b794f4\"\n },\n \"red\": {\n \"bg\": \"#742a2a\",\n \"text\": \"#fc8181\",\n \"accent\": \"#feb2b2\"\n },\n \"orange\": {\n \"bg\": \"#744210\",\n \"text\": \"#fbd38d\",\n \"accent\": \"#f6ad55\"\n },\n \"teal\": {\n \"bg\": \"#234e52\",\n \"text\": \"#81e6d9\",\n \"accent\": \"#4fd1c5\"\n }\n },\n \"persistentLayers\": {\n \"bottomLayers\": [\n {\n \"template\": \"gradientBackground\",\n \"config\": {\n \"type\": \"gradientBackground\",\n \"preset\": \"dark-vignette\"\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"documentary\",\n \"name\": \"Documentary\",\n \"description\": \"Classic dark cinematic look with elegant serif typography.\",\n \"colors\": {\n \"primary\": \"#3d5a80\",\n \"secondary\": \"#63b3ed\",\n \"background\": \"#1a202c\",\n \"backgroundLight\": \"#2d3748\",\n \"text\": \"#ffffff\",\n \"textMuted\": \"#a0aec0\",\n \"highlight\": \"#63b3ed\",\n \"warning\": \"#fc8181\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"source-serif\"\n },\n \"titleFont\": {\n \"stackId\": \"playfair\"\n },\n \"titleWeight\": \"bold\"\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.5,\n \"animationSpeed\": 1.0,\n \"imageTreatment\": {\n \"type\": \"mono\",\n \"strength\": 0.35\n }\n },\n \"renderStyle\": {\n \"name\": \"documentary\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": true,\n \"defaultTransition\": {\n \"type\": \"fade\",\n \"duration\": 0.8\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#22354d\",\n \"text\": \"#a8c3e0\",\n \"accent\": \"#7fa3c9\"\n },\n \"green\": {\n \"bg\": \"#26382e\",\n \"text\": \"#a9c6ae\",\n \"accent\": \"#82a88a\"\n },\n \"purple\": {\n \"bg\": \"#35304a\",\n \"text\": \"#beb3d6\",\n \"accent\": \"#9d8fc2\"\n },\n \"red\": {\n \"bg\": \"#45262a\",\n \"text\": \"#d9a2a2\",\n \"accent\": \"#c37f7c\"\n },\n \"orange\": {\n \"bg\": \"#453522\",\n \"text\": \"#d9bb90\",\n \"accent\": \"#c29a64\"\n },\n \"teal\": {\n \"bg\": \"#1f3a3d\",\n \"text\": \"#9cc4c4\",\n \"accent\": \"#6fa5a5\"\n }\n },\n \"persistentLayers\": {\n \"bottomLayers\": [\n {\n \"template\": \"gradientBackground\",\n \"config\": {\n \"type\": \"gradientBackground\",\n \"preset\": \"dark-vignette\"\n }\n }\n ],\n \"topLayers\": [\n {\n \"template\": \"vignette\",\n \"config\": {\n \"type\": \"vignette\",\n \"strength\": 0.25\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"minimalist\",\n \"name\": \"Minimalist\",\n \"description\": \"Clean near-white background with sans-serif type and minimal animation.\",\n \"colors\": {\n \"primary\": \"#2d3748\",\n \"secondary\": \"#4a5568\",\n \"background\": \"#f7fafc\",\n \"backgroundLight\": \"#edf2f7\",\n \"text\": \"#1a202c\",\n \"textMuted\": \"#718096\",\n \"highlight\": \"#3182ce\",\n \"warning\": \"#e53e3e\"\n },\n \"typography\": {\n \"bodyFont\": { \"stackId\": \"inter\" },\n \"titleFont\": { \"stackId\": \"inter\" },\n \"titleWeight\": \"bold\",\n \"lineHeight\": 1.6\n },\n \"style\": {\n \"textShadow\": false,\n \"overlayOpacity\": 0.3,\n \"animationSpeed\": 1.2,\n \"borderRadius\": 8\n },\n \"renderStyle\": {\n \"name\": \"minimalist\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"ambientMotion\": false,\n \"defaultTransition\": { \"type\": \"fade\", \"duration\": 0.6 },\n \"templateHints\": {\n \"title\": { \"showAccentLine\": false }\n }\n },\n \"colorSchemes\": {\n \"blue\": { \"bg\": \"#ebf8ff\", \"text\": \"#2b6cb0\", \"accent\": \"#3182ce\" },\n \"green\": { \"bg\": \"#f0fff4\", \"text\": \"#276749\", \"accent\": \"#38a169\" },\n \"purple\": { \"bg\": \"#faf5ff\", \"text\": \"#553c9a\", \"accent\": \"#805ad5\" },\n \"red\": { \"bg\": \"#fff5f5\", \"text\": \"#c53030\", \"accent\": \"#e53e3e\" },\n \"orange\": { \"bg\": \"#fffaf0\", \"text\": \"#c05621\", \"accent\": \"#dd6b20\" },\n \"teal\": { \"bg\": \"#e6fffa\", \"text\": \"#285e61\", \"accent\": \"#319795\" }\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"bold\",\n \"name\": \"Bold\",\n \"description\": \"High-contrast black with vivid accents and dramatic animations.\",\n \"colors\": {\n \"primary\": \"#e53e3e\",\n \"secondary\": \"#ed8936\",\n \"background\": \"#000000\",\n \"backgroundLight\": \"#1a1a1a\",\n \"text\": \"#ffffff\",\n \"textMuted\": \"#cbd5e0\",\n \"highlight\": \"#f6e05e\",\n \"warning\": \"#fc8181\"\n },\n \"typography\": {\n \"bodyFont\": { \"stackId\": \"roboto\" },\n \"titleFont\": { \"stackId\": \"oswald\" },\n \"titleWeight\": \"bold\",\n \"titleScale\": 1.15,\n \"bodyScale\": 1.0,\n \"titleLineHeight\": 1.1\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.6,\n \"animationSpeed\": 0.8\n },\n \"renderStyle\": {\n \"name\": \"bold\",\n \"defaultTextAnimation\": \"zoomIn\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": true,\n \"defaultTransition\": { \"type\": \"dissolve\", \"duration\": 0.5 },\n \"templateHints\": {\n \"statHighlight\": { \"entrance\": \"dramatic\" },\n \"fullBleedQuote\": { \"entrance\": \"dramatic\" }\n }\n },\n \"colorSchemes\": {\n \"blue\": { \"bg\": \"#1a202c\", \"text\": \"#63b3ed\", \"accent\": \"#90cdf4\" },\n \"green\": { \"bg\": \"#1a202c\", \"text\": \"#48bb78\", \"accent\": \"#68d391\" },\n \"purple\": { \"bg\": \"#1a202c\", \"text\": \"#b794f4\", \"accent\": \"#d6bcfa\" },\n \"red\": { \"bg\": \"#1a202c\", \"text\": \"#fc8181\", \"accent\": \"#feb2b2\" },\n \"orange\": { \"bg\": \"#1a202c\", \"text\": \"#f6ad55\", \"accent\": \"#fbd38d\" },\n \"teal\": { \"bg\": \"#1a202c\", \"text\": \"#4fd1c5\", \"accent\": \"#81e6d9\" }\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"morning-light\",\n \"name\": \"Morning Light\",\n \"description\": \"Warm light background with dark text and gentle serif typography.\",\n \"colors\": {\n \"primary\": \"#744210\",\n \"secondary\": \"#975a16\",\n \"background\": \"#faf8f5\",\n \"backgroundLight\": \"#f5f0eb\",\n \"text\": \"#2d3748\",\n \"textMuted\": \"#718096\",\n \"highlight\": \"#dd6b20\",\n \"warning\": \"#c53030\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"lora\"\n },\n \"titleFont\": {\n \"stackId\": \"merriweather\"\n },\n \"titleWeight\": \"bold\",\n \"lineHeight\": 1.7\n },\n \"style\": {\n \"textShadow\": false,\n \"overlayOpacity\": 0.35,\n \"animationSpeed\": 1.1,\n \"borderRadius\": 4\n },\n \"renderStyle\": {\n \"name\": \"morning-light\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"ambientMotion\": false,\n \"defaultTransition\": {\n \"type\": \"fade\",\n \"duration\": 1.0\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#ebf8ff\",\n \"text\": \"#2c5282\",\n \"accent\": \"#4299e1\"\n },\n \"green\": {\n \"bg\": \"#f0fff4\",\n \"text\": \"#22543d\",\n \"accent\": \"#48bb78\"\n },\n \"purple\": {\n \"bg\": \"#faf5ff\",\n \"text\": \"#44337a\",\n \"accent\": \"#9f7aea\"\n },\n \"red\": {\n \"bg\": \"#fff5f5\",\n \"text\": \"#9b2c2c\",\n \"accent\": \"#fc8181\"\n },\n \"orange\": {\n \"bg\": \"#fffaf0\",\n \"text\": \"#744210\",\n \"accent\": \"#ed8936\"\n },\n \"teal\": {\n \"bg\": \"#e6fffa\",\n \"text\": \"#234e52\",\n \"accent\": \"#38b2ac\"\n }\n },\n \"persistentLayers\": {\n \"topLayers\": [\n {\n \"template\": \"patternBackground\",\n \"config\": {\n \"type\": \"patternBackground\",\n \"pattern\": \"noise\",\n \"opacity\": 0.03\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"tech-dark\",\n \"name\": \"Tech Dark\",\n \"description\": \"True black with neon cyan/green accents and monospace titles.\",\n \"colors\": {\n \"primary\": \"#00e5ff\",\n \"secondary\": \"#00e676\",\n \"background\": \"#0a0a0a\",\n \"backgroundLight\": \"#1a1a2e\",\n \"text\": \"#e0e0e0\",\n \"textMuted\": \"#9e9e9e\",\n \"highlight\": \"#00e5ff\",\n \"warning\": \"#ff5252\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"ibm-plex-sans\"\n },\n \"titleFont\": {\n \"stackId\": \"jetbrains-mono\"\n },\n \"monoFont\": {\n \"stackId\": \"jetbrains-mono\"\n },\n \"titleWeight\": \"bold\",\n \"titleScale\": 0.9,\n \"lineHeight\": 1.5\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.55,\n \"animationSpeed\": 0.9,\n \"borderRadius\": 2,\n \"imageTreatment\": {\n \"type\": \"cool\",\n \"strength\": 0.45\n }\n },\n \"renderStyle\": {\n \"name\": \"tech-dark\",\n \"defaultTextAnimation\": \"typewriter\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": true,\n \"defaultTransition\": {\n \"type\": \"dissolve\",\n \"duration\": 0.4\n },\n \"templateHints\": {\n \"statHighlight\": {\n \"entrance\": \"dramatic\"\n }\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#0d1b2a\",\n \"text\": \"#00b0ff\",\n \"accent\": \"#40c4ff\"\n },\n \"green\": {\n \"bg\": \"#0d1b0d\",\n \"text\": \"#00e676\",\n \"accent\": \"#69f0ae\"\n },\n \"purple\": {\n \"bg\": \"#1a0d2e\",\n \"text\": \"#d500f9\",\n \"accent\": \"#ea80fc\"\n },\n \"red\": {\n \"bg\": \"#2e0d0d\",\n \"text\": \"#ff5252\",\n \"accent\": \"#ff8a80\"\n },\n \"orange\": {\n \"bg\": \"#2e1a0d\",\n \"text\": \"#ff9100\",\n \"accent\": \"#ffab40\"\n },\n \"teal\": {\n \"bg\": \"#0d2e2e\",\n \"text\": \"#1de9b6\",\n \"accent\": \"#64ffda\"\n }\n },\n \"persistentLayers\": {\n \"topLayers\": [\n {\n \"template\": \"patternBackground\",\n \"config\": {\n \"type\": \"patternBackground\",\n \"pattern\": \"grid\",\n \"color\": \"#00e5ff\",\n \"opacity\": 0.04,\n \"scale\": 1.5\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"magazine\",\n \"name\": \"Magazine\",\n \"description\": \"Rich editorial palette with mixed serif/sans typography and slide transitions.\",\n \"colors\": {\n \"primary\": \"#c53030\",\n \"secondary\": \"#2b6cb0\",\n \"background\": \"#1a202c\",\n \"backgroundLight\": \"#2d3748\",\n \"text\": \"#f7fafc\",\n \"textMuted\": \"#cbd5e0\",\n \"highlight\": \"#ed8936\",\n \"warning\": \"#fc8181\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"dm-sans\"\n },\n \"titleFont\": {\n \"stackId\": \"dm-serif\"\n },\n \"titleWeight\": \"bold\",\n \"titleScale\": 1.05,\n \"lineHeight\": 1.5\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.45,\n \"animationSpeed\": 1.0,\n \"borderRadius\": 6\n },\n \"renderStyle\": {\n \"name\": \"magazine\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": true,\n \"defaultTransition\": {\n \"type\": \"slideLeft\",\n \"duration\": 0.7\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#1d3a6e\",\n \"text\": \"#a3c9f5\",\n \"accent\": \"#4d9de0\"\n },\n \"green\": {\n \"bg\": \"#14532d\",\n \"text\": \"#86efac\",\n \"accent\": \"#22c55e\"\n },\n \"purple\": {\n \"bg\": \"#3b2a70\",\n \"text\": \"#c4b5fd\",\n \"accent\": \"#a78bfa\"\n },\n \"red\": {\n \"bg\": \"#7f1d1d\",\n \"text\": \"#fca5a5\",\n \"accent\": \"#f87171\"\n },\n \"orange\": {\n \"bg\": \"#7c2d12\",\n \"text\": \"#fdba74\",\n \"accent\": \"#f97316\"\n },\n \"teal\": {\n \"bg\": \"#134e4a\",\n \"text\": \"#5eead4\",\n \"accent\": \"#14b8a6\"\n }\n },\n \"persistentLayers\": {\n \"topLayers\": [\n {\n \"template\": \"patternBackground\",\n \"config\": {\n \"type\": \"patternBackground\",\n \"pattern\": \"diagonal\",\n \"color\": \"#f7fafc\",\n \"opacity\": 0.03,\n \"scale\": 1.2\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"cinematic\",\n \"name\": \"Cinematic\",\n \"description\": \"Ultra-dark with moody gradients, gold accents, and slow dissolve transitions.\",\n \"colors\": {\n \"primary\": \"#d69e2e\",\n \"secondary\": \"#b7791f\",\n \"background\": \"#0a0f1a\",\n \"backgroundLight\": \"#1a202c\",\n \"text\": \"#f7fafc\",\n \"textMuted\": \"#a0aec0\",\n \"highlight\": \"#ecc94b\",\n \"warning\": \"#fc8181\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"crimson\"\n },\n \"titleFont\": {\n \"stackId\": \"cormorant\"\n },\n \"titleWeight\": \"bold\",\n \"lineHeight\": 1.5,\n \"titleLineHeight\": 1.2\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.55,\n \"animationSpeed\": 1.2,\n \"imageTreatment\": {\n \"type\": \"warm\",\n \"strength\": 0.5\n }\n },\n \"renderStyle\": {\n \"name\": \"cinematic\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": true,\n \"defaultTransition\": {\n \"type\": \"dissolve\",\n \"duration\": 1.2\n },\n \"templateHints\": {\n \"title\": {\n \"showAccentLine\": true\n }\n }\n },\n \"colorSchemes\": {\n \"blue\": {\n \"bg\": \"#0f1d33\",\n \"text\": \"#9db8dc\",\n \"accent\": \"#5d84b8\"\n },\n \"green\": {\n \"bg\": \"#10251c\",\n \"text\": \"#9ecfae\",\n \"accent\": \"#55a878\"\n },\n \"purple\": {\n \"bg\": \"#1f1433\",\n \"text\": \"#c3aede\",\n \"accent\": \"#8f74c0\"\n },\n \"red\": {\n \"bg\": \"#2e1114\",\n \"text\": \"#e0959a\",\n \"accent\": \"#c05f66\"\n },\n \"orange\": {\n \"bg\": \"#2e1d0b\",\n \"text\": \"#e3b978\",\n \"accent\": \"#d69e2e\"\n },\n \"teal\": {\n \"bg\": \"#0d2626\",\n \"text\": \"#93cfc7\",\n \"accent\": \"#4d9e94\"\n }\n },\n \"persistentLayers\": {\n \"bottomLayers\": [\n {\n \"template\": \"gradientBackground\",\n \"config\": {\n \"type\": \"gradientBackground\",\n \"preset\": \"radial-dark\"\n }\n }\n ],\n \"topLayers\": [\n {\n \"template\": \"vignette\",\n \"config\": {\n \"type\": \"vignette\",\n \"strength\": 0.35\n }\n },\n {\n \"template\": \"patternBackground\",\n \"config\": {\n \"type\": \"patternBackground\",\n \"pattern\": \"noise\",\n \"opacity\": 0.05\n }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"warm-earth\",\n \"name\": \"Warm Earth\",\n \"description\": \"Natural warm tones with earthy browns and terracotta accents.\",\n \"colors\": {\n \"primary\": \"#9c4221\",\n \"secondary\": \"#c05621\",\n \"background\": \"#1c1410\",\n \"backgroundLight\": \"#2d241e\",\n \"text\": \"#faf5f0\",\n \"textMuted\": \"#c4a882\",\n \"highlight\": \"#dd6b20\",\n \"warning\": \"#e53e3e\"\n },\n \"typography\": {\n \"bodyFont\": { \"stackId\": \"pt-serif\" },\n \"titleFont\": { \"stackId\": \"pt-serif\" },\n \"titleWeight\": \"bold\",\n \"lineHeight\": 1.6\n },\n \"style\": {\n \"textShadow\": true,\n \"overlayOpacity\": 0.5,\n \"animationSpeed\": 1.1\n },\n \"renderStyle\": {\n \"name\": \"warm-earth\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"defaultImageAnimation\": \"panLeft\",\n \"ambientMotion\": true,\n \"defaultTransition\": { \"type\": \"fade\", \"duration\": 0.9 }\n },\n \"colorSchemes\": {\n \"blue\": { \"bg\": \"#2a1f14\", \"text\": \"#90cdf4\", \"accent\": \"#63b3ed\" },\n \"green\": { \"bg\": \"#1e2a14\", \"text\": \"#9ae6b4\", \"accent\": \"#68d391\" },\n \"purple\": { \"bg\": \"#2a142a\", \"text\": \"#d6bcfa\", \"accent\": \"#b794f4\" },\n \"red\": { \"bg\": \"#2a1414\", \"text\": \"#fc8181\", \"accent\": \"#feb2b2\" },\n \"orange\": { \"bg\": \"#2a1e0a\", \"text\": \"#fbd38d\", \"accent\": \"#f6ad55\" },\n \"teal\": { \"bg\": \"#142a28\", \"text\": \"#81e6d9\", \"accent\": \"#4fd1c5\" }\n },\n \"persistentLayers\": {\n \"bottomLayers\": [\n {\n \"template\": \"gradientBackground\",\n \"config\": { \"type\": \"gradientBackground\", \"preset\": \"earth-tones\" }\n }\n ]\n }\n}\n","{\n \"schemaVersion\": \"1\",\n \"id\": \"gezellig\",\n \"name\": \"Gezellig\",\n \"description\": \"Warm sage + terracotta palette inspired by the Gezel desktop app. Subtle orange-tinted dark background, cream text, sage and terracotta accents.\",\n \"colors\": {\n \"primary\": \"#b0724c\",\n \"secondary\": \"#667f62\",\n \"background\": \"#1f1a17\",\n \"backgroundLight\": \"#2b2420\",\n \"text\": \"#f3ede0\",\n \"textMuted\": \"#a89b85\",\n \"highlight\": \"#c0875d\",\n \"warning\": \"#e07a6b\"\n },\n \"typography\": {\n \"bodyFont\": {\n \"stackId\": \"system-sans-emoji\"\n },\n \"titleFont\": {\n \"stackId\": \"system-serif-emoji\"\n },\n \"monoFont\": {\n \"stackId\": \"system-mono\"\n },\n \"titleWeight\": \"bold\",\n \"lineHeight\": 1.55\n },\n \"style\": {\n \"textShadow\": false,\n \"overlayOpacity\": 0.4,\n \"animationSpeed\": 1.0,\n \"borderRadius\": 6,\n \"imageTreatment\": {\n \"type\": \"warm\",\n \"strength\": 0.3\n }\n },\n \"renderStyle\": {\n \"name\": \"gezellig\",\n \"defaultTextAnimation\": \"fadeIn\",\n \"defaultImageAnimation\": \"slowZoom\",\n \"ambientMotion\": false,\n \"defaultTransition\": {\n \"type\": \"fade\",\n \"duration\": 0.6\n }\n },\n \"colorSchemes\": {\n \"terracotta\": {\n \"bg\": \"#3d2620\",\n \"text\": \"#f3ede0\",\n \"accent\": \"#c0875d\"\n },\n \"sage\": {\n \"bg\": \"#28332a\",\n \"text\": \"#e3ead9\",\n \"accent\": \"#8aa589\"\n },\n \"amber\": {\n \"bg\": \"#3d2e17\",\n \"text\": \"#fbe3a8\",\n \"accent\": \"#d4a149\"\n },\n \"plum\": {\n \"bg\": \"#2e1f2a\",\n \"text\": \"#e8d4e0\",\n \"accent\": \"#b088a5\"\n },\n \"ink\": {\n \"bg\": \"#1a1f26\",\n \"text\": \"#d5dde8\",\n \"accent\": \"#7b8fa8\"\n },\n \"cream\": {\n \"bg\": \"#f3ede0\",\n \"text\": \"#2b2420\",\n \"accent\": \"#b0724c\"\n }\n },\n \"persistentLayers\": {\n \"topLayers\": [\n {\n \"template\": \"patternBackground\",\n \"config\": {\n \"type\": \"patternBackground\",\n \"pattern\": \"noise\",\n \"opacity\": 0.04\n }\n }\n ]\n }\n}\n","/**\n * Built-in Theme Library\n *\n * Loads each built-in theme from its JSON sidecar, validates it, and\n * exports the typed `Theme` constants. The JSON files in this directory\n * are syntactically identical to customizer-authored themes — they just\n * use more of the schema.\n *\n * Validation runs at module init: if a built-in JSON drifts from the\n * schema, the import fails loudly during build / startup.\n */\n\nimport type { Theme } from '../Theme.js';\nimport { assertTheme } from '../themeValidator.js';\n\nimport standardJson from './standard.json' with { type: 'json' };\nimport standardDarkJson from './standard-dark.json' with { type: 'json' };\nimport documentaryJson from './documentary.json' with { type: 'json' };\nimport minimalistJson from './minimalist.json' with { type: 'json' };\nimport boldJson from './bold.json' with { type: 'json' };\nimport morningLightJson from './morning-light.json' with { type: 'json' };\nimport techDarkJson from './tech-dark.json' with { type: 'json' };\nimport magazineJson from './magazine.json' with { type: 'json' };\nimport cinematicJson from './cinematic.json' with { type: 'json' };\nimport warmEarthJson from './warm-earth.json' with { type: 'json' };\nimport gezelligJson from './gezellig.json' with { type: 'json' };\n\nexport const standard: Theme = assertTheme(standardJson, 'standard.json');\nexport const standardDark: Theme = assertTheme(standardDarkJson, 'standard-dark.json');\nexport const documentary: Theme = assertTheme(documentaryJson, 'documentary.json');\nexport const minimalist: Theme = assertTheme(minimalistJson, 'minimalist.json');\nexport const bold: Theme = assertTheme(boldJson, 'bold.json');\nexport const morningLight: Theme = assertTheme(morningLightJson, 'morning-light.json');\nexport const techDark: Theme = assertTheme(techDarkJson, 'tech-dark.json');\nexport const magazine: Theme = assertTheme(magazineJson, 'magazine.json');\nexport const cinematic: Theme = assertTheme(cinematicJson, 'cinematic.json');\nexport const warmEarth: Theme = assertTheme(warmEarthJson, 'warm-earth.json');\nexport const gezellig: Theme = assertTheme(gezelligJson, 'gezellig.json');\n\n/** All built-in themes, keyed by id. */\nexport const BUILTIN_THEMES: Record<string, Theme> = {\n standard,\n 'standard-dark': standardDark,\n documentary,\n minimalist,\n bold,\n 'morning-light': morningLight,\n 'tech-dark': techDark,\n magazine,\n cinematic,\n 'warm-earth': warmEarth,\n gezellig,\n};\n","/**\n * Built-in Theme Library\n *\n * Public entry point for theme lookup. Built-in themes live as JSON\n * sidecars in [./themes/](./themes/) — they share the exact same shape\n * as customizer-authored themes (no two-tier distinction).\n *\n * Usage:\n * ```ts\n * import { THEMES, resolveTheme } from '@bendyline/squisq/schemas';\n *\n * const theme = resolveTheme('minimalist'); // by id, with registry override\n * const theme = THEMES.documentary; // direct access to a built-in\n * ```\n */\n\nimport type { Theme } from './Theme.js';\nimport { lookupRegisteredTheme } from './Theme.js';\nimport { BUILTIN_THEMES } from './themes/index.js';\n\n/** All built-in themes, keyed by id. */\nexport const THEMES: Record<string, Theme> = BUILTIN_THEMES;\n\n/** The default theme id. */\nexport const DEFAULT_THEME_ID = 'standard';\n\n/** The default theme (standard — safe system fonts, no external dependencies). */\nexport const DEFAULT_THEME: Theme = THEMES[DEFAULT_THEME_ID];\n\n/**\n * Resolve a theme by id. Custom themes registered via `registerTheme()`\n * take precedence over built-ins; otherwise built-ins are searched and\n * the default theme is returned for unknown ids.\n */\nexport function resolveTheme(id: string | undefined): Theme {\n const registered = lookupRegisteredTheme(id);\n if (registered) return registered;\n if (id && id in THEMES) return THEMES[id];\n return DEFAULT_THEME;\n}\n\n/** Get all built-in theme ids. */\nexport function getAvailableThemes(): string[] {\n return Object.keys(THEMES);\n}\n\n/** Get a summary of all built-in themes (id + name + description) for theme pickers. */\nexport function getThemeSummaries(): Array<{ id: string; name: string; description?: string }> {\n return Object.values(THEMES).map((t) => ({\n id: t.id,\n name: t.name,\n description: t.description,\n }));\n}\n","/**\n * Font Stacks\n *\n * Curated registry of font families used by built-in themes and offered in\n * the theme customizer. Each stack has a stable `id` (referenced by JSON\n * theme files via `{ stackId }`) and a CSS `family` string that resolves\n * to the actual font when rendered.\n *\n * Themes never carry raw CSS font strings — they reference a `stackId` or\n * specify a `{ custom: { name, fallback } }` form, both of which resolve\n * here at render time.\n */\n\nimport type { FontFamily, FontFamilyKind } from './Theme.js';\n\nexport interface FontStack {\n /** Stable identifier referenced by Theme JSON. */\n id: string;\n /** Display label for pickers. */\n label: string;\n /** Full CSS font-family string with safe fallbacks. */\n family: string;\n /** Categorical bucket for the picker UI. */\n kind: FontFamilyKind;\n /**\n * Google Fonts family name, when this stack is served by Google Fonts.\n * Used by exports that bundle a `<link>` to fonts.googleapis.com so the\n * face renders correctly even when the host page doesn't preload it.\n * Omit (or set to undefined) for purely system stacks.\n */\n googleFontFamily?: string;\n}\n\n/** All curated stacks, in the order they should appear in pickers. */\nexport const AVAILABLE_FONT_STACKS: FontStack[] = [\n // System defaults\n {\n id: 'system-sans',\n label: 'System Sans',\n family: 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n kind: 'sans',\n },\n {\n id: 'system-serif',\n label: 'System Serif',\n family: 'Georgia, \"Times New Roman\", serif',\n kind: 'serif',\n },\n {\n id: 'system-mono',\n label: 'System Mono',\n family: 'Consolas, \"Courier New\", monospace',\n kind: 'mono',\n },\n // Curated Google Fonts. `googleFontFamily` is the canonical family\n // name Google serves the face under (used by exports that emit a\n // `<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/...\">`\n // so the face renders even when the host doesn't preload it).\n {\n id: 'inter',\n label: 'Inter',\n family: '\"Inter\", \"Segoe UI\", Roboto, sans-serif',\n kind: 'sans',\n googleFontFamily: 'Inter',\n },\n {\n id: 'ibm-plex-sans',\n label: 'IBM Plex Sans',\n family: '\"IBM Plex Sans\", \"Segoe UI\", Roboto, sans-serif',\n kind: 'sans',\n googleFontFamily: 'IBM Plex Sans',\n },\n {\n id: 'roboto',\n label: 'Roboto',\n family: '\"Roboto\", \"Segoe UI\", Arial, sans-serif',\n kind: 'sans',\n googleFontFamily: 'Roboto',\n },\n {\n id: 'dm-sans',\n label: 'DM Sans',\n family: '\"DM Sans\", \"Segoe UI\", Roboto, sans-serif',\n kind: 'sans',\n googleFontFamily: 'DM Sans',\n },\n {\n id: 'oswald',\n label: 'Oswald',\n // Condensed grotesques make a far better stand-in for Oswald than\n // Impact/Arial Black, whose extreme weight distorts every layout\n // tuned for the real face.\n family: '\"Oswald\", \"Arial Narrow\", \"Helvetica Neue Condensed\", \"Roboto Condensed\", sans-serif',\n kind: 'display',\n googleFontFamily: 'Oswald',\n },\n {\n id: 'playfair',\n label: 'Playfair Display',\n family: '\"Playfair Display\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Playfair Display',\n },\n {\n id: 'source-serif',\n label: 'Source Serif',\n family: '\"Source Serif 4\", \"PT Serif\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Source Serif 4',\n },\n {\n id: 'merriweather',\n label: 'Merriweather',\n family: '\"Merriweather\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Merriweather',\n },\n {\n id: 'lora',\n label: 'Lora',\n family: '\"Lora\", \"Merriweather\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Lora',\n },\n {\n id: 'pt-serif',\n label: 'PT Serif',\n family: '\"PT Serif\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'PT Serif',\n },\n {\n id: 'crimson',\n label: 'Crimson Text',\n family: '\"Crimson Text\", Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Crimson Text',\n },\n {\n id: 'cormorant',\n label: 'Cormorant Garamond',\n family: '\"Cormorant Garamond\", Garamond, Georgia, serif',\n kind: 'serif',\n googleFontFamily: 'Cormorant Garamond',\n },\n {\n id: 'dm-serif',\n label: 'DM Serif Display',\n family: '\"DM Serif Display\", Georgia, serif',\n kind: 'display',\n googleFontFamily: 'DM Serif Display',\n },\n {\n id: 'jetbrains-mono',\n label: 'JetBrains Mono',\n family: '\"JetBrains Mono\", \"Fira Code\", Consolas, monospace',\n kind: 'mono',\n googleFontFamily: 'JetBrains Mono',\n },\n // Themed system stacks with emoji fallbacks (used by gezellig)\n {\n id: 'system-sans-emoji',\n label: 'System Sans + Emoji',\n family:\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, \"OpenMoji Color\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Noto Color Emoji\", sans-serif',\n kind: 'sans',\n },\n {\n id: 'system-serif-emoji',\n label: 'System Serif + Emoji',\n family:\n 'Georgia, \"Times New Roman\", \"OpenMoji Color\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Noto Color Emoji\", serif',\n kind: 'serif',\n },\n];\n\nconst STACKS_BY_ID: Record<string, FontStack> = Object.fromEntries(\n AVAILABLE_FONT_STACKS.map((s) => [s.id, s]),\n);\n\n/** Look up a stack by id. Returns undefined if not registered. */\nexport function getFontStack(id: string): FontStack | undefined {\n return STACKS_BY_ID[id];\n}\n\n/** Default fallback CSS family per kind, used when a custom font has no fallback specified. */\nconst FALLBACK_BY_KIND: Record<FontFamilyKind, string> = {\n sans: 'system-ui, sans-serif',\n serif: 'Georgia, serif',\n mono: 'Consolas, monospace',\n display: '\"Arial Narrow\", \"Helvetica Neue\", Arial, sans-serif',\n};\n\n/**\n * Resolve a `FontFamily` reference (or legacy raw string) to a CSS family string.\n * Used by `getThemeFont` at render time. Never returns an empty string —\n * unrecognized stackIds fall back to the requested role's default.\n */\nexport function resolveFontFamily(\n family: FontFamily | string | undefined,\n roleFallback: string,\n): string {\n if (!family) return roleFallback;\n if (typeof family === 'string') return family;\n if ('stackId' in family) {\n const stack = STACKS_BY_ID[family.stackId];\n return stack ? stack.family : roleFallback;\n }\n if ('custom' in family) {\n const { name, fallback } = family.custom;\n const fb =\n fallback === 'system-ui'\n ? 'system-ui, sans-serif'\n : fallback === 'serif'\n ? 'Georgia, serif'\n : fallback === 'monospace'\n ? 'Consolas, monospace'\n : 'system-ui, sans-serif';\n const safeName = name.includes(' ') || name.includes(',') ? `\"${name}\"` : name;\n return `${safeName}, ${fb}`;\n }\n return roleFallback;\n}\n\n/** Convenience: quick `{ stackId }` factory for code that constructs themes. */\nexport function fontStack(id: string): FontFamily {\n return { stackId: id };\n}\n\n/**\n * Build a `https://fonts.googleapis.com/css2?...` URL that loads the\n * subset of supplied `FontFamily` references that are served by Google\n * Fonts. Returns `null` when nothing in the list needs Google hosting\n * (system stacks, custom fonts, or unknown stack ids) — callers can use\n * that to skip emitting a `<link>` entirely.\n *\n * The URL requests regular + bold (400/700) for each family, which is\n * what the templates use. `display=swap` keeps the fallback visible\n * while the web font streams in.\n */\nexport function buildGoogleFontsUrl(families: Array<FontFamily | undefined>): string | null {\n const names = new Set<string>();\n for (const f of families) {\n if (!f || typeof f === 'string') continue;\n if ('stackId' in f) {\n const stack = STACKS_BY_ID[f.stackId];\n if (stack?.googleFontFamily) names.add(stack.googleFontFamily);\n }\n }\n if (names.size === 0) return null;\n // css2 syntax: ?family=Name+With+Spaces:wght@400;700&family=Other:wght@400;700&display=swap\n const params = Array.from(names)\n .sort()\n .map((name) => `family=${encodeURIComponent(name).replace(/%20/g, '+')}:wght@400;700`)\n .join('&');\n return `https://fonts.googleapis.com/css2?${params}&display=swap`;\n}\n\n/** Default fallback families exposed for tools that need them. */\nexport const FONT_FALLBACKS = FALLBACK_BY_KIND;\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transform/styles/documentary.ts","../src/transform/styles/magazine.ts","../src/transform/styles/dataDriven.ts","../src/transform/styles/narrative.ts","../src/transform/styles/minimal.ts","../src/transform/registry.ts","../src/transform/blockAnalyzer.ts","../src/transform/templateSelector.ts","../src/transform/timingAllocator.ts","../src/transform/applyTransform.ts"],"sourcesContent":["import type { TransformStyleConfig } from '../types.js';\n\n/** Conservative style — sparse highlights, preserves most text as-is. */\nexport const documentaryStyle: TransformStyleConfig = {\n id: 'documentary',\n name: 'Documentary',\n description: 'Conservative — highlights only the strongest stats, dates, and quotes',\n minConfidence: 0.5,\n transformRatio: 0.3,\n preferredTypes: ['stat', 'date', 'quote', 'fact'],\n colorSchemes: ['blue', 'green', 'purple'],\n insertSectionHeaders: false,\n interleaveImages: true,\n blocksPerSection: { max: 3 },\n transitionStyle: 'fade',\n suggestedThemeId: 'documentary',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Visual variety — pull quotes, definitions, image-heavy layout. */\nexport const magazineStyle: TransformStyleConfig = {\n id: 'magazine',\n name: 'Magazine',\n description: 'Visual variety with pull quotes, facts, and rich image layouts',\n minConfidence: 0.4,\n transformRatio: 0.6,\n preferredTypes: ['quote', 'fact', 'list', 'definition', 'stat', 'impactLine'],\n colorSchemes: ['blue', 'green', 'purple', 'orange', 'red'],\n insertSectionHeaders: true,\n interleaveImages: true,\n blocksPerSection: { max: 5 },\n transitionStyle: 'dissolve',\n suggestedThemeId: 'magazine',\n templateMap: { quote: 'pullQuote', impactLine: 'fullBleedQuote' },\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Numbers-forward — aggressively extracts stats, comparisons, and dates. */\nexport const dataDrivenStyle: TransformStyleConfig = {\n id: 'data-driven',\n name: 'Data-Driven',\n description: 'Aggressively highlights statistics, comparisons, and timelines',\n minConfidence: 0.3,\n transformRatio: 0.8,\n preferredTypes: ['stat', 'comparison', 'date', 'list', 'fact'],\n colorSchemes: ['blue', 'orange', 'green', 'purple', 'red'],\n insertSectionHeaders: true,\n interleaveImages: false,\n blocksPerSection: { max: 6 },\n transitionStyle: 'cut',\n suggestedThemeId: 'tech-dark',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Timeline-focused — emphasizes dates, quotes, and story arc. */\nexport const narrativeStyle: TransformStyleConfig = {\n id: 'narrative',\n name: 'Narrative',\n description: 'Story-driven with timeline events, quotes, and impact moments',\n minConfidence: 0.4,\n transformRatio: 0.5,\n preferredTypes: ['date', 'quote', 'impactLine', 'fact', 'stat'],\n colorSchemes: ['blue', 'purple', 'green'],\n insertSectionHeaders: true,\n interleaveImages: true,\n blocksPerSection: { max: 4 },\n transitionStyle: 'fade',\n suggestedThemeId: 'cinematic',\n pacing: { intro: true, outro: true },\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Light touch — only the highest-confidence items get transformed. */\nexport const minimalStyle: TransformStyleConfig = {\n id: 'minimal',\n name: 'Minimal',\n description: 'Light touch — only the strongest highlights, mostly text',\n minConfidence: 0.6,\n transformRatio: 0.2,\n preferredTypes: ['stat', 'quote'],\n colorSchemes: ['blue', 'green'],\n insertSectionHeaders: false,\n interleaveImages: false,\n blocksPerSection: { max: 2 },\n transitionStyle: 'fade',\n suggestedThemeId: 'minimalist',\n};\n","/**\n * Transform Style Registry\n *\n * Central registry of built-in transform styles plus a dynamic\n * registration API. Follows the same pattern as themeLibrary.ts /\n * `registerTheme` — registered styles take precedence over built-ins,\n * unknown ids fall back to the default.\n */\n\nimport type { TransformStyleConfig, TransformStyleSummary } from './types.js';\nimport { documentaryStyle } from './styles/documentary.js';\nimport { magazineStyle } from './styles/magazine.js';\nimport { dataDrivenStyle } from './styles/dataDriven.js';\nimport { narrativeStyle } from './styles/narrative.js';\nimport { minimalStyle } from './styles/minimal.js';\n\n/** All built-in transform styles, keyed by id. */\nconst TRANSFORM_STYLES: Record<string, TransformStyleConfig> = {\n [documentaryStyle.id]: documentaryStyle,\n [magazineStyle.id]: magazineStyle,\n [dataDrivenStyle.id]: dataDrivenStyle,\n [narrativeStyle.id]: narrativeStyle,\n [minimalStyle.id]: minimalStyle,\n};\n\n/**\n * Id aliases: the data-driven style's file/export are named `dataDriven`\n * but its registered id is hyphenated — accept both.\n */\nconst STYLE_ALIASES: Record<string, string> = {\n dataDriven: 'data-driven',\n};\n\n/** Host-registered custom styles (registered ids win over built-ins). */\nconst registeredStyles = new Map<string, TransformStyleConfig>();\n\n/** Default style used when no id is provided. */\nexport const DEFAULT_TRANSFORM_STYLE_ID = 'documentary';\n\n/**\n * Register (or replace) a custom transform style at runtime. Hosts use\n * this the same way they use `registerTheme` — to add product-specific\n * styles without forking the registry.\n */\nexport function registerTransformStyle(style: TransformStyleConfig): void {\n registeredStyles.set(style.id, style);\n}\n\n/** Remove a previously registered custom style. */\nexport function unregisterTransformStyle(id: string): void {\n registeredStyles.delete(id);\n}\n\n/**\n * Resolve a transform style by id. Registered styles win over built-ins;\n * aliases are honored; unknown ids fall back to the default style.\n */\nexport function resolveTransformStyle(id: string): TransformStyleConfig {\n const canonical = STYLE_ALIASES[id] ?? id;\n return (\n registeredStyles.get(canonical) ??\n TRANSFORM_STYLES[canonical] ??\n TRANSFORM_STYLES[DEFAULT_TRANSFORM_STYLE_ID]\n );\n}\n\n/** Get all known style ids (built-ins plus registered). */\nexport function getTransformStyleIds(): string[] {\n return Array.from(new Set([...Object.keys(TRANSFORM_STYLES), ...registeredStyles.keys()]));\n}\n\n/** Get summary info for all styles (for UI dropdowns). */\nexport function getTransformStyleSummaries(): TransformStyleSummary[] {\n return getTransformStyleIds().map((id) => {\n const { name, description } = resolveTransformStyle(id);\n return { id, name, description };\n });\n}\n","/**\n * Block Analyzer\n *\n * Walks Doc blocks, extracts plain text from their markdown contents,\n * and runs the content extractor on each block to identify stats, dates,\n * quotes, etc. that can be promoted to visual template blocks.\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type { MarkdownBlockNode, MarkdownNode } from '../markdown/types.js';\nimport type { ExtractedElement, ExtractionOptions } from '../generate/contentExtractor.js';\nimport type { TransformImage } from './types.js';\nimport { extractContent, stripMarkdown } from '../generate/contentExtractor.js';\nimport { extractPlainText, getChildren } from '../markdown/utils.js';\n\n/** An image found in a block's markdown contents. */\nexport interface BlockImage {\n /** Image URL (relative or absolute). */\n src: string;\n /** Alt text. */\n alt: string;\n /** Index of the source block in the analyzed array. */\n sourceBlockIndex: number;\n}\n\n/** A block enriched with extraction analysis. */\nexport interface AnalyzedBlock {\n /** The original block. */\n block: Block;\n /** Plain text extracted from the block's contents. */\n plainText: string;\n /** Content extractions found in the block's text. */\n extractions: ExtractedElement[];\n /** Whether this block has child blocks. */\n hasChildren: boolean;\n /** Word count of the block's body text. */\n bodyWordCount: number;\n /** Images found in this block's markdown contents. */\n images: BlockImage[];\n}\n\n/**\n * Extract plain text from an array of MarkdownBlockNodes.\n */\nfunction contentsToPlainText(contents: MarkdownBlockNode[]): string {\n return contents.map((node) => extractPlainText(node)).join('\\n');\n}\n\n/**\n * Recursively walk a markdown node tree and collect all images.\n */\nfunction collectImages(node: MarkdownNode): Array<{ src: string; alt: string }> {\n const results: Array<{ src: string; alt: string }> = [];\n\n if ('type' in node && node.type === 'image' && 'url' in node) {\n const img = node as { url: string; alt?: string };\n if (img.url) {\n results.push({ src: img.url, alt: img.alt ?? '' });\n }\n }\n\n for (const child of getChildren(node)) {\n results.push(...collectImages(child));\n }\n\n return results;\n}\n\n/**\n * Extract images from a block's markdown contents.\n */\nfunction extractBlockImages(block: Block, blockIndex: number): BlockImage[] {\n if (!block.contents || block.contents.length === 0) return [];\n\n const images: BlockImage[] = [];\n for (const node of block.contents) {\n for (const img of collectImages(node)) {\n images.push({ ...img, sourceBlockIndex: blockIndex });\n }\n }\n return images;\n}\n\n/**\n * Collect all unique images from all blocks in a Doc.\n * Returns them as TransformImages for use in the transform pipeline.\n */\nexport function extractDocImages(blocks: Block[]): TransformImage[] {\n const seen = new Set<string>();\n const images: TransformImage[] = [];\n\n function walk(blockList: Block[]): void {\n for (const block of blockList) {\n if (block.contents) {\n for (const node of block.contents) {\n for (const img of collectImages(node)) {\n if (!seen.has(img.src)) {\n seen.add(img.src);\n images.push({ src: img.src, alt: img.alt });\n }\n }\n }\n }\n if (block.children) {\n walk(block.children);\n }\n }\n }\n\n walk(blocks);\n return images;\n}\n\n/**\n * Collect leaf blocks from a nested block tree.\n * Only returns blocks that have their own `contents` but no children,\n * preventing parent blocks from duplicating text that also appears\n * in their children. Parent-only blocks (with a title but no body\n * content) are included as structural placeholders.\n */\nfunction collectLeafBlocks(blocks: Block[]): Block[] {\n const result: Block[] = [];\n for (const block of blocks) {\n if (block.children && block.children.length > 0) {\n // Parent block — only include it as a structural marker\n // (title only, no body extraction) if it has no contents of its own.\n // Then recurse into children for the actual content.\n if (!block.contents || block.contents.length === 0) {\n result.push(block);\n }\n result.push(...collectLeafBlocks(block.children));\n } else {\n // Leaf block — include for content analysis\n result.push(block);\n }\n }\n return result;\n}\n\n/**\n * Analyze all blocks in a Doc, extracting text and running content extraction.\n *\n * @param blocks - The Doc's block array (may be nested via children).\n * @param options - Extraction options (minConfidence, types filter).\n * @returns Analyzed blocks with extractions, in flattened order.\n */\nexport function analyzeBlocks(blocks: Block[], options?: ExtractionOptions): AnalyzedBlock[] {\n const flat = collectLeafBlocks(blocks);\n const results: AnalyzedBlock[] = [];\n\n for (const block of flat) {\n let plainText = '';\n\n if (block.contents && block.contents.length > 0) {\n plainText = contentsToPlainText(block.contents);\n } else if (block.title) {\n plainText = block.title;\n }\n\n // Strip any remaining markdown syntax\n const stripped = stripMarkdown(plainText);\n const bodyWordCount = stripped.split(/\\s+/).filter((w) => w.length > 0).length;\n\n // Run content extraction\n const extraction = extractContent(stripped, options);\n\n // Extract images from markdown contents\n const images = extractBlockImages(block, results.length);\n\n results.push({\n block,\n plainText: stripped,\n extractions: extraction.elements,\n hasChildren: !!(block.children && block.children.length > 0),\n bodyWordCount,\n images,\n });\n }\n\n return results;\n}\n","/**\n * Template Selector\n *\n * Selects which extracted elements to promote to visual template blocks\n * and handles color scheme rotation, image interleaving, and template\n * variety. Ported and generalized from qualla-internal's TemplateSelector.\n */\n\nimport type { Block, TransitionType } from '../schemas/Doc.js';\nimport type {\n TemplateBlock,\n AccentImage,\n AccentPosition,\n ImageWithCaptionInput,\n SectionHeaderInput,\n QuoteBlockInput,\n FullBleedQuoteInput,\n StatHighlightInput,\n} from '../schemas/BlockTemplates.js';\nimport type { ExtractedElement } from '../generate/contentExtractor.js';\nimport type { TransformStyleConfig, TransformImage } from './types.js';\nimport type { AnalyzedBlock } from './blockAnalyzer.js';\nimport { mapElementToBlock } from '../generate/templateMapper.js';\nimport { SeededRandom } from '../random/SeededRandom.js';\n\n/** Accent positions to rotate through. */\nconst ACCENT_POSITIONS: AccentPosition[] = [\n 'left-strip',\n 'right-strip',\n 'bottom-strip',\n 'corner-inset',\n];\n\n/** Ambient motions to rotate on image blocks. */\nconst AMBIENT_MOTIONS: Array<'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight'> = [\n 'zoomIn',\n 'zoomOut',\n 'panLeft',\n 'panRight',\n];\n\n/** A selected element paired with its source block. */\ninterface SelectedExtraction {\n element: ExtractedElement;\n sourceBlock: Block;\n /** Index in the original analyzed blocks array. */\n sourceIndex: number;\n}\n\n/** Result of template selection. */\nexport interface SelectionResult {\n /** Replacement blocks: a mix of original blocks and new template blocks. */\n blocks: Array<Block | TemplateBlock>;\n /** How many blocks were transformed. */\n transformedCount: number;\n /** How many blocks were inserted (images, section headers). */\n insertedCount: number;\n}\n\n/**\n * Select extractions and build a transformed block sequence.\n *\n * @param analyzed - Analyzed blocks from blockAnalyzer.\n * @param config - The transform style configuration.\n * @param images - Available images for interleaving.\n * @param seed - Random seed for deterministic output.\n */\nexport function selectAndBuild(\n analyzed: AnalyzedBlock[],\n config: TransformStyleConfig,\n images: TransformImage[],\n seed: number,\n): SelectionResult {\n const rng = new SeededRandom(seed);\n\n // 1. Collect all extractions across all blocks, filtered by config\n const candidates = collectCandidates(analyzed, config);\n\n // 2. Determine how many blocks to transform. `transformRatio` scales\n // with block count; an optional duration-based budget (slides per\n // minute) caps runaway promotion on long dense documents.\n const ratioCap = Math.max(1, Math.floor(analyzed.length * config.transformRatio));\n const slidesPerMinute = config.budget?.slidesPerMinute;\n const totalDurationSeconds = analyzed.reduce((sum, ab) => sum + (ab.block.duration || 0), 0);\n const budgetCap =\n slidesPerMinute && totalDurationSeconds > 0\n ? Math.max(1, Math.round((totalDurationSeconds / 60) * slidesPerMinute))\n : Infinity;\n const maxTransforms = Math.min(ratioCap, budgetCap);\n const selected = candidates.slice(0, maxTransforms);\n\n // 3. Build the output block sequence\n const result = buildBlockSequence(analyzed, selected, config, images, rng);\n\n return result;\n}\n\n/**\n * Collect candidate extractions from all analyzed blocks, sorted by\n * a combined score of confidence and type preference.\n */\nfunction collectCandidates(\n analyzed: AnalyzedBlock[],\n config: TransformStyleConfig,\n): SelectedExtraction[] {\n const candidates: SelectedExtraction[] = [];\n\n for (let i = 0; i < analyzed.length; i++) {\n const ab = analyzed[i];\n // Skip blocks with no meaningful text\n if (ab.bodyWordCount < 5) continue;\n\n for (const element of ab.extractions) {\n if (element.confidence < config.minConfidence) continue;\n\n candidates.push({\n element,\n sourceBlock: ab.block,\n sourceIndex: i,\n });\n }\n }\n\n // Sort by: preferred type rank (lower = better), then confidence (higher = better)\n const typeRank = new Map(config.preferredTypes.map((t, i) => [t, i]));\n const maxRank = config.preferredTypes.length;\n\n candidates.sort((a, b) => {\n const rankA = typeRank.get(a.element.type) ?? maxRank;\n const rankB = typeRank.get(b.element.type) ?? maxRank;\n if (rankA !== rankB) return rankA - rankB;\n return b.element.confidence - a.element.confidence;\n });\n\n // Deduplicate: if the same extracted text appears multiple times\n // (e.g., from overlapping parent/child blocks), keep only the\n // highest-ranked occurrence.\n const seenTexts = new Set<string>();\n const deduplicated: SelectedExtraction[] = [];\n for (const candidate of candidates) {\n const key = candidate.element.text.trim().toLowerCase();\n if (seenTexts.has(key)) continue;\n seenTexts.add(key);\n deduplicated.push(candidate);\n }\n\n return deduplicated;\n}\n\n/**\n * Build the output block sequence, replacing source blocks with template\n * blocks where extractions were selected, and interleaving images.\n */\nfunction buildBlockSequence(\n analyzed: AnalyzedBlock[],\n selected: SelectedExtraction[],\n config: TransformStyleConfig,\n images: TransformImage[],\n rng: SeededRandom,\n): SelectionResult {\n // Map: sourceIndex → list of selected extractions for that block\n const blockExtractions = new Map<number, SelectedExtraction[]>();\n for (const sel of selected) {\n const list = blockExtractions.get(sel.sourceIndex) ?? [];\n list.push(sel);\n blockExtractions.set(sel.sourceIndex, list);\n }\n\n // Limit extractions per block: cap at blocksPerSection.max and ensure\n // template type variety within each block (no two same-type extractions).\n for (const [idx, list] of blockExtractions) {\n const diverse: SelectedExtraction[] = [];\n const usedTypes = new Set<string>();\n for (const sel of list) {\n if (usedTypes.has(sel.element.type)) continue;\n usedTypes.add(sel.element.type);\n diverse.push(sel);\n if (diverse.length >= config.blocksPerSection.max) break;\n }\n blockExtractions.set(idx, diverse);\n }\n\n const blocks: Array<Block | TemplateBlock> = [];\n let transformedCount = 0;\n let insertedCount = 0;\n let colorIndex = 0;\n let blockIdCounter = 0;\n let imageIndex = 0;\n let accentPositionIndex = 0;\n let elementsSinceImage = 0;\n let prevTemplateType = '';\n\n // Calculate image interleaving interval\n const totalTransformed = Array.from(blockExtractions.values()).reduce(\n (sum, list) => sum + list.length,\n 0,\n );\n const imageInterval =\n config.interleaveImages && images.length > 0 && totalTransformed > 0\n ? Math.max(2, Math.floor(totalTransformed / (images.length + 1)))\n : Infinity;\n\n for (let i = 0; i < analyzed.length; i++) {\n const ab = analyzed[i];\n const extractions = blockExtractions.get(i);\n\n if (!extractions || extractions.length === 0) {\n // Keep the original block unchanged\n blocks.push(ab.block);\n continue;\n }\n\n // Insert section header before a group of transformed blocks (if enabled)\n if (config.insertSectionHeaders && ab.block.title) {\n const headerBlock: SectionHeaderInput = {\n template: 'sectionHeader',\n id: `transform-header-${blockIdCounter++}`,\n duration: ab.block.duration > 0 ? Math.min(3, ab.block.duration * 0.2) : 3,\n audioSegment: ab.block.audioSegment,\n title: ab.block.title,\n colorScheme: config.colorSchemes[colorIndex % config.colorSchemes.length],\n };\n blocks.push(headerBlock);\n insertedCount++;\n }\n\n // Convert each selected extraction to a template block.\n // Track the last template used globally (not just within this block)\n // to avoid consecutive same-template slides across the entire output.\n for (const sel of extractions) {\n const colorScheme = config.colorSchemes[colorIndex % config.colorSchemes.length];\n\n // Build accent image if we have images in the pool\n let accentImage: AccentImage | undefined;\n if (images.length > 0 && config.interleaveImages) {\n const img = images[imageIndex % images.length];\n accentImage = {\n src: img.src,\n alt: img.alt ?? '',\n position: ACCENT_POSITIONS[accentPositionIndex % ACCENT_POSITIONS.length],\n ambientMotion: rng.pick(AMBIENT_MOTIONS) ?? 'zoomIn',\n credit: img.credit,\n license: img.license,\n };\n accentPositionIndex++;\n }\n\n let templateBlock = mapElementToBlock(sel.element, {\n id: `transform-${blockIdCounter++}`,\n duration: ab.block.duration > 0 ? ab.block.duration / extractions.length : 6,\n audioSegment: ab.block.audioSegment,\n colorScheme,\n accentImage,\n sourceStartTime: sel.element.sourcePosition,\n });\n\n // Style-level extraction→template remap (v2 contract). Only known\n // text-compatible pairings translate; image-backed targets consume\n // the accent image as their background. Unknown pairings keep the\n // default mapping.\n const remapTarget = config.templateMap?.[sel.element.data.type];\n if (remapTarget && remapTarget !== templateBlock.template) {\n const translated = translateTemplateBlock(templateBlock, remapTarget);\n if (translated) templateBlock = translated;\n }\n\n // Apply transition based on style\n if (config.transitionStyle !== 'cut') {\n const transitionType: TransitionType =\n config.transitionStyle === 'mixed'\n ? (rng.pick<TransitionType>(['fade', 'dissolve']) ?? 'fade')\n : config.transitionStyle;\n templateBlock.transition = {\n type: transitionType,\n duration: 0.5,\n };\n }\n\n // Avoid consecutive same-template blocks by bumping color for variety\n if (templateBlock.template === prevTemplateType) {\n colorIndex++;\n }\n prevTemplateType = templateBlock.template;\n\n blocks.push(templateBlock);\n transformedCount++;\n colorIndex++;\n elementsSinceImage++;\n\n // Interleave standalone image at intervals\n if (\n config.interleaveImages &&\n imageIndex < images.length &&\n elementsSinceImage >= imageInterval\n ) {\n const img = images[imageIndex];\n const imageBlock: ImageWithCaptionInput = {\n template: 'imageWithCaption',\n id: `transform-img-${blockIdCounter++}`,\n duration: 4,\n audioSegment: ab.block.audioSegment,\n imageSrc: img.src,\n imageAlt: img.alt ?? '',\n ambientMotion: rng.pick(AMBIENT_MOTIONS) ?? 'zoomIn',\n };\n blocks.push(imageBlock);\n imageIndex++;\n insertedCount++;\n elementsSinceImage = 0;\n }\n }\n }\n\n return { blocks, transformedCount, insertedCount };\n}\n\n/**\n * Translate a mapped template block into a style-requested target\n * template. Only text-compatible pairings are supported; returns null\n * (keep the default) for unknown pairs or when a required input —\n * a background image for `pullQuote` — is unavailable.\n */\nfunction translateTemplateBlock(block: TemplateBlock, target: string): TemplateBlock | null {\n const base = {\n id: block.id,\n duration: block.duration,\n audioSegment: block.audioSegment,\n sourceStartTime: block.sourceStartTime,\n sourceDuration: block.sourceDuration,\n };\n\n if (block.template === 'quote') {\n const quote = block as QuoteBlockInput;\n if (target === 'fullBleedQuote') {\n return { ...base, template: 'fullBleedQuote', text: quote.quote };\n }\n if (target === 'pullQuote') {\n // pullQuote requires a full-bleed background image — reuse the\n // accent image the selector already assigned to this block.\n const bg = quote.accentImage;\n if (!bg) return null;\n return {\n ...base,\n template: 'pullQuote',\n text: quote.quote,\n attribution: quote.attribution,\n backgroundImage: { src: bg.src, alt: bg.alt, credit: bg.credit, license: bg.license },\n };\n }\n return null;\n }\n\n if (block.template === 'fullBleedQuote' && target === 'quote') {\n const fbq = block as FullBleedQuoteInput;\n return { ...base, template: 'quote', quote: fbq.text };\n }\n\n if (block.template === 'statHighlight' && target === 'factCard') {\n const stat = block as StatHighlightInput;\n return {\n ...base,\n template: 'factCard',\n fact: stat.stat,\n explanation: stat.description,\n accentImage: stat.accentImage,\n };\n }\n\n return null;\n}\n","/**\n * Timing Allocator\n *\n * Distributes timing (startTime, duration) across transformed blocks.\n * When the source Doc has audio, blocks are fitted to the overall duration.\n * When no audio is present, uses reading-time estimation.\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type { TemplateBlock } from '../schemas/BlockTemplates.js';\nimport { isTemplateBlock } from '../schemas/BlockTemplates.js';\n\n/** Minimum block duration in seconds. */\nconst MIN_BLOCK_DURATION = 3;\n/** Maximum block duration in seconds. */\nconst MAX_BLOCK_DURATION = 20;\n/** Default duration when no timing info is available. */\nconst DEFAULT_BLOCK_DURATION = 6;\n\n/**\n * Allocate startTime and duration across a mixed array of blocks and\n * template blocks. Template blocks get timing assigned; existing blocks\n * retain their original timing when possible.\n *\n * @param blocks - The output from templateSelector (mixed Block | TemplateBlock).\n * @param totalDuration - The Doc's total duration (from audio or estimation).\n * @returns A new array of Blocks with consistent timing. Template blocks\n * are returned as Blocks (with startTime/duration set, layers empty).\n */\nexport function allocateTiming(\n blocks: Array<Block | TemplateBlock>,\n totalDuration: number,\n): Block[] {\n if (blocks.length === 0) return [];\n\n const effectiveDuration = totalDuration > 0 ? totalDuration : estimateDefaultDuration(blocks);\n\n // First pass: assign raw durations\n const durations = blocks.map((block) => {\n if (!isTemplateBlock(block) && block.duration > 0) {\n // Existing block with known duration — keep it\n return block.duration;\n }\n if (isTemplateBlock(block) && block.duration > 0) {\n return block.duration;\n }\n return DEFAULT_BLOCK_DURATION;\n });\n\n // Scale durations to fit the total\n const rawTotal = durations.reduce((sum, d) => sum + d, 0);\n if (rawTotal > 0 && effectiveDuration > 0) {\n const scale = effectiveDuration / rawTotal;\n for (let i = 0; i < durations.length; i++) {\n durations[i] = clampDuration(durations[i] * scale);\n }\n }\n\n // Second pass: assign startTimes and build output Blocks\n let currentTime = 0;\n const result: Block[] = [];\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const duration = durations[i];\n\n if (isTemplateBlock(block)) {\n // Convert TemplateBlock to Block shell, preserving all template-specific\n // fields (stat, quote, description, etc.) so they survive through to\n // the player's template expansion step.\n const outputBlock = {\n ...block,\n startTime: currentTime,\n duration,\n title: getTemplateTitle(block),\n } as unknown as Block;\n result.push(outputBlock);\n } else {\n // Existing block — update timing\n result.push({\n ...block,\n startTime: currentTime,\n duration,\n });\n }\n\n currentTime += duration;\n }\n\n return result;\n}\n\n/** Clamp a duration to the min/max range. */\nfunction clampDuration(d: number): number {\n return Math.max(MIN_BLOCK_DURATION, Math.min(MAX_BLOCK_DURATION, d));\n}\n\n/** Estimate a total duration from block contents when no audio is available. */\nfunction estimateDefaultDuration(blocks: Array<Block | TemplateBlock>): number {\n let totalSeconds = 0;\n for (const block of blocks) {\n if (!isTemplateBlock(block) && block.duration > 0) {\n totalSeconds += block.duration;\n } else {\n totalSeconds += DEFAULT_BLOCK_DURATION;\n }\n }\n return Math.max(totalSeconds, blocks.length * MIN_BLOCK_DURATION);\n}\n\n/** Extract a display title from a template block if available. */\nfunction getTemplateTitle(block: TemplateBlock): string | undefined {\n if ('title' in block && typeof block.title === 'string') {\n return block.title;\n }\n if ('stat' in block && typeof block.stat === 'string') {\n return block.stat;\n }\n if ('fact' in block && typeof block.fact === 'string') {\n return block.fact;\n }\n if ('quote' in block && typeof block.quote === 'string') {\n return block.quote.slice(0, 60);\n }\n return undefined;\n}\n","/**\n * Apply Transform\n *\n * Main entry point for the transform module. Takes a Doc and a style,\n * analyzes block content, selects extractions to promote, and returns\n * a new Doc with blocks optimized for visual presentation.\n *\n * The input Doc is never mutated — a fresh Doc is always returned.\n */\n\nimport type { Doc } from '../schemas/Doc.js';\nimport type { DocBlock, TitleBlockInput, SectionHeaderInput } from '../schemas/BlockTemplates.js';\nimport type { TransformStyleId, TransformOptions, TransformResult } from './types.js';\nimport { resolveTransformStyle } from './registry.js';\nimport { analyzeBlocks, extractDocImages } from './blockAnalyzer.js';\nimport { selectAndBuild } from './templateSelector.js';\nimport { allocateTiming } from './timingAllocator.js';\nimport { hashString } from '../random/SeededRandom.js';\n\n/**\n * Apply a transform style to a Doc, producing a new Doc with blocks\n * optimized for visual presentation.\n *\n * @param doc - The source Doc (not mutated).\n * @param styleId - Registered transform style id (e.g. 'documentary', 'magazine').\n * @param options - Optional seed, images, theme override.\n * @returns TransformResult with the new Doc and stats.\n */\nexport function applyTransform(\n doc: Doc,\n styleId: TransformStyleId,\n options?: TransformOptions,\n): TransformResult {\n const baseConfig = resolveTransformStyle(styleId);\n const config = options?.overrides\n ? { ...baseConfig, ...options.overrides, id: baseConfig.id }\n : baseConfig;\n\n const seed = options?.seed ?? hashString(doc.articleId || 'transform');\n\n // Use provided images or auto-extract from the doc's markdown content\n const images = options?.images ?? extractDocImages(doc.blocks);\n\n // 1. Analyze blocks\n const analyzed = analyzeBlocks(doc.blocks, {\n minConfidence: config.minConfidence,\n types: config.preferredTypes,\n });\n\n // If no blocks have meaningful content, return the doc unchanged\n const hasContent = analyzed.some((ab) => ab.bodyWordCount >= 5);\n if (!hasContent) {\n return {\n doc: { ...doc },\n stats: {\n totalInputBlocks: doc.blocks.length,\n transformedBlocks: 0,\n insertedBlocks: 0,\n },\n };\n }\n\n // 2. Select extractions and build template blocks\n const selection = selectAndBuild(analyzed, config, images, seed);\n\n // 2b. Pacing bookends: an opening title beat and/or a closing beat.\n let paced: DocBlock[] = selection.blocks;\n let pacingInserted = 0;\n const docTitle = firstTitle(doc);\n if (config.pacing?.intro && docTitle && !doc.startBlock) {\n const intro: TitleBlockInput = {\n template: 'title',\n id: 'transform-intro',\n duration: 4,\n audioSegment: 0,\n title: docTitle,\n };\n paced = [intro, ...paced];\n pacingInserted++;\n }\n if (config.pacing?.outro && docTitle) {\n const outro: SectionHeaderInput = {\n template: 'sectionHeader',\n id: 'transform-outro',\n duration: 3,\n audioSegment: 0,\n title: docTitle,\n colorScheme: config.colorSchemes[0],\n };\n paced = [...paced, outro];\n pacingInserted++;\n }\n\n // 3. Allocate timing across the new block sequence\n const timedBlocks = allocateTiming(paced, doc.duration);\n\n // 4. Assemble the output Doc. A style's suggested theme applies only\n // when neither the caller nor the doc declares one.\n const transformedDoc: Doc = {\n ...doc,\n blocks: timedBlocks,\n themeId: options?.themeId ?? doc.themeId ?? config.suggestedThemeId,\n };\n\n return {\n doc: transformedDoc,\n stats: {\n totalInputBlocks: doc.blocks.length,\n transformedBlocks: selection.transformedCount,\n insertedBlocks: selection.insertedCount + pacingInserted,\n },\n };\n}\n\n/** First non-empty block title (the doc's working title). */\nfunction firstTitle(doc: Doc): string | undefined {\n if (doc.startBlock?.title) return doc.startBlock.title;\n for (const block of doc.blocks) {\n if (block.title) return block.title;\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}