@bendyline/squisq 1.3.0 → 1.4.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 (419) hide show
  1. package/dist/{Doc-Ch4tc3vv.d.ts → Doc-BeSeH2iX.d.ts} +118 -41
  2. package/dist/ImageEditDoc-BTIvw0oq.d.ts +84 -0
  3. package/dist/__tests__/colorUtils.test.d.ts +2 -0
  4. package/dist/__tests__/colorUtils.test.d.ts.map +1 -0
  5. package/dist/__tests__/colorUtils.test.js +94 -0
  6. package/dist/__tests__/colorUtils.test.js.map +1 -0
  7. package/dist/__tests__/getLayers.test.js +31 -7
  8. package/dist/__tests__/getLayers.test.js.map +1 -1
  9. package/dist/__tests__/iconResolve.test.d.ts +2 -0
  10. package/dist/__tests__/iconResolve.test.d.ts.map +1 -0
  11. package/dist/__tests__/iconResolve.test.js +99 -0
  12. package/dist/__tests__/iconResolve.test.js.map +1 -0
  13. package/dist/__tests__/imageEditState.test.d.ts +2 -0
  14. package/dist/__tests__/imageEditState.test.d.ts.map +1 -0
  15. package/dist/__tests__/imageEditState.test.js +61 -0
  16. package/dist/__tests__/imageEditState.test.js.map +1 -0
  17. package/dist/__tests__/imageEditVersions.test.d.ts +2 -0
  18. package/dist/__tests__/imageEditVersions.test.d.ts.map +1 -0
  19. package/dist/__tests__/imageEditVersions.test.js +141 -0
  20. package/dist/__tests__/imageEditVersions.test.js.map +1 -0
  21. package/dist/__tests__/inferDocumentTitle.test.d.ts +2 -0
  22. package/dist/__tests__/inferDocumentTitle.test.d.ts.map +1 -0
  23. package/dist/__tests__/inferDocumentTitle.test.js +42 -0
  24. package/dist/__tests__/inferDocumentTitle.test.js.map +1 -0
  25. package/dist/__tests__/jsonForm.chooseControl.test.d.ts +2 -0
  26. package/dist/__tests__/jsonForm.chooseControl.test.d.ts.map +1 -0
  27. package/dist/__tests__/jsonForm.chooseControl.test.js +74 -0
  28. package/dist/__tests__/jsonForm.chooseControl.test.js.map +1 -0
  29. package/dist/__tests__/jsonForm.evaluateWhen.test.d.ts +2 -0
  30. package/dist/__tests__/jsonForm.evaluateWhen.test.d.ts.map +1 -0
  31. package/dist/__tests__/jsonForm.evaluateWhen.test.js +51 -0
  32. package/dist/__tests__/jsonForm.evaluateWhen.test.js.map +1 -0
  33. package/dist/__tests__/jsonForm.inferSchema.test.d.ts +2 -0
  34. package/dist/__tests__/jsonForm.inferSchema.test.d.ts.map +1 -0
  35. package/dist/__tests__/jsonForm.inferSchema.test.js +23 -0
  36. package/dist/__tests__/jsonForm.inferSchema.test.js.map +1 -0
  37. package/dist/__tests__/jsonForm.pointer.test.d.ts +2 -0
  38. package/dist/__tests__/jsonForm.pointer.test.d.ts.map +1 -0
  39. package/dist/__tests__/jsonForm.pointer.test.js +94 -0
  40. package/dist/__tests__/jsonForm.pointer.test.js.map +1 -0
  41. package/dist/__tests__/markdownIcons.test.d.ts +2 -0
  42. package/dist/__tests__/markdownIcons.test.d.ts.map +1 -0
  43. package/dist/__tests__/markdownIcons.test.js +93 -0
  44. package/dist/__tests__/markdownIcons.test.js.map +1 -0
  45. package/dist/__tests__/markdownToDoc.test.js +15 -4
  46. package/dist/__tests__/markdownToDoc.test.js.map +1 -1
  47. package/dist/__tests__/recommendTemplates.test.d.ts +2 -0
  48. package/dist/__tests__/recommendTemplates.test.d.ts.map +1 -0
  49. package/dist/__tests__/recommendTemplates.test.js +158 -0
  50. package/dist/__tests__/recommendTemplates.test.js.map +1 -0
  51. package/dist/__tests__/scopedContentContainer.test.d.ts +2 -0
  52. package/dist/__tests__/scopedContentContainer.test.d.ts.map +1 -0
  53. package/dist/__tests__/scopedContentContainer.test.js +74 -0
  54. package/dist/__tests__/scopedContentContainer.test.js.map +1 -0
  55. package/dist/__tests__/slideshowGenerator.test.js +1 -1
  56. package/dist/__tests__/slideshowGenerator.test.js.map +1 -1
  57. package/dist/__tests__/templateAnnotationParse.test.d.ts +2 -0
  58. package/dist/__tests__/templateAnnotationParse.test.d.ts.map +1 -0
  59. package/dist/__tests__/templateAnnotationParse.test.js +42 -0
  60. package/dist/__tests__/templateAnnotationParse.test.js.map +1 -0
  61. package/dist/__tests__/templates.test.js +90 -9
  62. package/dist/__tests__/templates.test.js.map +1 -1
  63. package/dist/__tests__/themeCompile.test.d.ts +2 -0
  64. package/dist/__tests__/themeCompile.test.d.ts.map +1 -0
  65. package/dist/__tests__/themeCompile.test.js +134 -0
  66. package/dist/__tests__/themeCompile.test.js.map +1 -0
  67. package/dist/__tests__/themeValidator.test.d.ts +2 -0
  68. package/dist/__tests__/themeValidator.test.d.ts.map +1 -0
  69. package/dist/__tests__/themeValidator.test.js +107 -0
  70. package/dist/__tests__/themeValidator.test.js.map +1 -0
  71. package/dist/__tests__/versions.test.d.ts +2 -0
  72. package/dist/__tests__/versions.test.d.ts.map +1 -0
  73. package/dist/__tests__/versions.test.js +339 -0
  74. package/dist/__tests__/versions.test.js.map +1 -0
  75. package/dist/{chunk-CYQHG27J.js → chunk-2TMAWB4Y.js} +74 -1
  76. package/dist/chunk-2TMAWB4Y.js.map +1 -0
  77. package/dist/{chunk-OASJKWO5.js → chunk-3K5OG6KI.js} +92 -7
  78. package/dist/chunk-3K5OG6KI.js.map +1 -0
  79. package/dist/chunk-57CVQCFX.js +193 -0
  80. package/dist/chunk-57CVQCFX.js.map +1 -0
  81. package/dist/{chunk-QM5PKNPW.js → chunk-5WFRKURX.js} +1 -1
  82. package/dist/chunk-5WFRKURX.js.map +1 -0
  83. package/dist/chunk-B4EEON3N.js +1317 -0
  84. package/dist/chunk-B4EEON3N.js.map +1 -0
  85. package/dist/chunk-DBS6RIFL.js +81 -0
  86. package/dist/chunk-DBS6RIFL.js.map +1 -0
  87. package/dist/{chunk-MIBRIRGJ.js → chunk-FR2RBTKO.js} +3 -3
  88. package/dist/{chunk-MIBRIRGJ.js.map → chunk-FR2RBTKO.js.map} +1 -1
  89. package/dist/chunk-H3AXU4MJ.js +179 -0
  90. package/dist/chunk-H3AXU4MJ.js.map +1 -0
  91. package/dist/chunk-JELIRVDP.js +24 -0
  92. package/dist/chunk-JELIRVDP.js.map +1 -0
  93. package/dist/chunk-K32VJONL.js +193 -0
  94. package/dist/chunk-K32VJONL.js.map +1 -0
  95. package/dist/{chunk-6BAVXFYC.js → chunk-KSWJR66U.js} +218 -42
  96. package/dist/chunk-KSWJR66U.js.map +1 -0
  97. package/dist/{chunk-TSG2OSE6.js → chunk-MYIH7FWD.js} +3 -3
  98. package/dist/chunk-MYIH7FWD.js.map +1 -0
  99. package/dist/chunk-VLJJHDAC.js +218 -0
  100. package/dist/chunk-VLJJHDAC.js.map +1 -0
  101. package/dist/chunk-WMOI7FN3.js +182 -0
  102. package/dist/chunk-WMOI7FN3.js.map +1 -0
  103. package/dist/chunk-ZTX4PFFT.js +520 -0
  104. package/dist/chunk-ZTX4PFFT.js.map +1 -0
  105. package/dist/doc/audioMapping.d.ts.map +1 -1
  106. package/dist/doc/audioMapping.js +42 -7
  107. package/dist/doc/audioMapping.js.map +1 -1
  108. package/dist/doc/getLayers.d.ts.map +1 -1
  109. package/dist/doc/getLayers.js +29 -18
  110. package/dist/doc/getLayers.js.map +1 -1
  111. package/dist/doc/markdownToDoc.d.ts.map +1 -1
  112. package/dist/doc/markdownToDoc.js +40 -6
  113. package/dist/doc/markdownToDoc.js.map +1 -1
  114. package/dist/doc/templates/featureBlock.d.ts +18 -0
  115. package/dist/doc/templates/featureBlock.d.ts.map +1 -0
  116. package/dist/doc/templates/featureBlock.js +180 -0
  117. package/dist/doc/templates/featureBlock.js.map +1 -0
  118. package/dist/doc/templates/fullBleedQuote.d.ts +12 -0
  119. package/dist/doc/templates/fullBleedQuote.d.ts.map +1 -1
  120. package/dist/doc/templates/fullBleedQuote.js +12 -0
  121. package/dist/doc/templates/fullBleedQuote.js.map +1 -1
  122. package/dist/doc/templates/index.d.ts +28 -4
  123. package/dist/doc/templates/index.d.ts.map +1 -1
  124. package/dist/doc/templates/index.js +45 -12
  125. package/dist/doc/templates/index.js.map +1 -1
  126. package/dist/doc/templates/listBlock.d.ts.map +1 -1
  127. package/dist/doc/templates/listBlock.js +22 -5
  128. package/dist/doc/templates/listBlock.js.map +1 -1
  129. package/dist/doc/templates/statHighlight.d.ts +12 -0
  130. package/dist/doc/templates/statHighlight.d.ts.map +1 -1
  131. package/dist/doc/templates/statHighlight.js +12 -0
  132. package/dist/doc/templates/statHighlight.js.map +1 -1
  133. package/dist/doc/templates/titleBlock.d.ts +11 -0
  134. package/dist/doc/templates/titleBlock.d.ts.map +1 -1
  135. package/dist/doc/templates/titleBlock.js +8 -0
  136. package/dist/doc/templates/titleBlock.js.map +1 -1
  137. package/dist/doc/utils/themeUtils.d.ts +4 -4
  138. package/dist/doc/utils/themeUtils.d.ts.map +1 -1
  139. package/dist/doc/utils/themeUtils.js +8 -7
  140. package/dist/doc/utils/themeUtils.js.map +1 -1
  141. package/dist/generate/slideshowGenerator.js +1 -1
  142. package/dist/generate/slideshowGenerator.js.map +1 -1
  143. package/dist/generate/templateMapper.js +2 -2
  144. package/dist/generate/templateMapper.js.map +1 -1
  145. package/dist/icons/iconData.d.ts +26 -0
  146. package/dist/icons/iconData.d.ts.map +1 -0
  147. package/dist/icons/iconData.js +12 -0
  148. package/dist/icons/iconData.js.map +1 -0
  149. package/dist/icons/index.d.ts +12 -0
  150. package/dist/icons/index.d.ts.map +1 -0
  151. package/dist/icons/index.js +10 -0
  152. package/dist/icons/index.js.map +1 -0
  153. package/dist/icons/resolve.d.ts +61 -0
  154. package/dist/icons/resolve.d.ts.map +1 -0
  155. package/dist/icons/resolve.js +130 -0
  156. package/dist/icons/resolve.js.map +1 -0
  157. package/dist/imageEdit/ImageEditVersionManager.d.ts +31 -0
  158. package/dist/imageEdit/ImageEditVersionManager.d.ts.map +1 -0
  159. package/dist/imageEdit/ImageEditVersionManager.js +39 -0
  160. package/dist/imageEdit/ImageEditVersionManager.js.map +1 -0
  161. package/dist/imageEdit/export.d.ts +33 -0
  162. package/dist/imageEdit/export.d.ts.map +1 -0
  163. package/dist/imageEdit/export.js +253 -0
  164. package/dist/imageEdit/export.js.map +1 -0
  165. package/dist/imageEdit/index.d.ts +14 -0
  166. package/dist/imageEdit/index.d.ts.map +1 -0
  167. package/dist/imageEdit/index.js +22 -0
  168. package/dist/imageEdit/index.js.map +1 -0
  169. package/dist/imageEdit/persistence.d.ts +15 -0
  170. package/dist/imageEdit/persistence.d.ts.map +1 -0
  171. package/dist/imageEdit/persistence.js +49 -0
  172. package/dist/imageEdit/persistence.js.map +1 -0
  173. package/dist/imageEdit/state.d.ts +42 -0
  174. package/dist/imageEdit/state.d.ts.map +1 -0
  175. package/dist/imageEdit/state.js +98 -0
  176. package/dist/imageEdit/state.js.map +1 -0
  177. package/dist/imageEdit/versionPaths.d.ts +27 -0
  178. package/dist/imageEdit/versionPaths.d.ts.map +1 -0
  179. package/dist/imageEdit/versionPaths.js +57 -0
  180. package/dist/imageEdit/versionPaths.js.map +1 -0
  181. package/dist/imageEdit/versions.d.ts +67 -0
  182. package/dist/imageEdit/versions.d.ts.map +1 -0
  183. package/dist/imageEdit/versions.js +161 -0
  184. package/dist/imageEdit/versions.js.map +1 -0
  185. package/dist/index.d.ts +4 -0
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +4 -0
  188. package/dist/index.js.map +1 -1
  189. package/dist/jsonForm/chooseControl.d.ts +20 -0
  190. package/dist/jsonForm/chooseControl.d.ts.map +1 -0
  191. package/dist/jsonForm/chooseControl.js +82 -0
  192. package/dist/jsonForm/chooseControl.js.map +1 -0
  193. package/dist/jsonForm/evaluateWhen.d.ts +12 -0
  194. package/dist/jsonForm/evaluateWhen.d.ts.map +1 -0
  195. package/dist/jsonForm/evaluateWhen.js +65 -0
  196. package/dist/jsonForm/evaluateWhen.js.map +1 -0
  197. package/dist/jsonForm/index.d.ts +14 -0
  198. package/dist/jsonForm/index.d.ts.map +1 -0
  199. package/dist/jsonForm/index.js +12 -0
  200. package/dist/jsonForm/index.js.map +1 -0
  201. package/dist/jsonForm/inferSchema.d.ts +12 -0
  202. package/dist/jsonForm/inferSchema.d.ts.map +1 -0
  203. package/dist/jsonForm/inferSchema.js +15 -0
  204. package/dist/jsonForm/inferSchema.js.map +1 -0
  205. package/dist/jsonForm/pointer.d.ts +26 -0
  206. package/dist/jsonForm/pointer.d.ts.map +1 -0
  207. package/dist/jsonForm/pointer.js +102 -0
  208. package/dist/jsonForm/pointer.js.map +1 -0
  209. package/dist/jsonForm/types.d.ts +120 -0
  210. package/dist/jsonForm/types.d.ts.map +1 -0
  211. package/dist/jsonForm/types.js +10 -0
  212. package/dist/jsonForm/types.js.map +1 -0
  213. package/dist/markdown/convert.d.ts +11 -1
  214. package/dist/markdown/convert.d.ts.map +1 -1
  215. package/dist/markdown/convert.js +135 -5
  216. package/dist/markdown/convert.js.map +1 -1
  217. package/dist/markdown/index.d.ts +1 -1
  218. package/dist/markdown/index.d.ts.map +1 -1
  219. package/dist/markdown/index.js +1 -1
  220. package/dist/markdown/index.js.map +1 -1
  221. package/dist/markdown/types.d.ts +17 -2
  222. package/dist/markdown/types.d.ts.map +1 -1
  223. package/dist/markdown/utils.d.ts +40 -0
  224. package/dist/markdown/utils.d.ts.map +1 -1
  225. package/dist/markdown/utils.js +155 -0
  226. package/dist/markdown/utils.js.map +1 -1
  227. package/dist/recommend/index.d.ts +16 -0
  228. package/dist/recommend/index.d.ts.map +1 -0
  229. package/dist/recommend/index.js +15 -0
  230. package/dist/recommend/index.js.map +1 -0
  231. package/dist/recommend/templates.d.ts +39 -0
  232. package/dist/recommend/templates.d.ts.map +1 -0
  233. package/dist/recommend/templates.js +235 -0
  234. package/dist/recommend/templates.js.map +1 -0
  235. package/dist/schemas/BlockTemplates.d.ts +46 -8
  236. package/dist/schemas/BlockTemplates.d.ts.map +1 -1
  237. package/dist/schemas/BlockTemplates.js +3 -3
  238. package/dist/schemas/BlockTemplates.js.map +1 -1
  239. package/dist/schemas/ImageEditDoc.d.ts +81 -0
  240. package/dist/schemas/ImageEditDoc.d.ts.map +1 -0
  241. package/dist/schemas/ImageEditDoc.js +20 -0
  242. package/dist/schemas/ImageEditDoc.js.map +1 -0
  243. package/dist/schemas/Theme.d.ts +70 -31
  244. package/dist/schemas/Theme.d.ts.map +1 -1
  245. package/dist/schemas/Theme.js +48 -16
  246. package/dist/schemas/Theme.js.map +1 -1
  247. package/dist/schemas/colorUtils.d.ts +51 -0
  248. package/dist/schemas/colorUtils.d.ts.map +1 -0
  249. package/dist/schemas/colorUtils.js +154 -0
  250. package/dist/schemas/colorUtils.js.map +1 -0
  251. package/dist/schemas/fontStacks.d.ts +57 -0
  252. package/dist/schemas/fontStacks.d.ts.map +1 -0
  253. package/dist/schemas/fontStacks.js +227 -0
  254. package/dist/schemas/fontStacks.js.map +1 -0
  255. package/dist/schemas/index.d.ts +5 -0
  256. package/dist/schemas/index.d.ts.map +1 -1
  257. package/dist/schemas/index.js +4 -0
  258. package/dist/schemas/index.js.map +1 -1
  259. package/dist/schemas/themeCompile.d.ts +45 -0
  260. package/dist/schemas/themeCompile.d.ts.map +1 -0
  261. package/dist/schemas/themeCompile.js +160 -0
  262. package/dist/schemas/themeCompile.js.map +1 -0
  263. package/dist/schemas/themeLibrary.d.ts +11 -15
  264. package/dist/schemas/themeLibrary.d.ts.map +1 -1
  265. package/dist/schemas/themeLibrary.js +18 -566
  266. package/dist/schemas/themeLibrary.js.map +1 -1
  267. package/dist/schemas/themeValidator.d.ts +26 -0
  268. package/dist/schemas/themeValidator.d.ts.map +1 -0
  269. package/dist/schemas/themeValidator.js +352 -0
  270. package/dist/schemas/themeValidator.js.map +1 -0
  271. package/dist/schemas/themes/bold.json +48 -0
  272. package/dist/schemas/themes/cinematic.json +54 -0
  273. package/dist/schemas/themes/documentary.json +49 -0
  274. package/dist/schemas/themes/gezellig.json +44 -0
  275. package/dist/schemas/themes/index.d.ts +26 -0
  276. package/dist/schemas/themes/index.d.ts.map +1 -0
  277. package/dist/schemas/themes/index.js +49 -0
  278. package/dist/schemas/themes/index.js.map +1 -0
  279. package/dist/schemas/themes/magazine.json +44 -0
  280. package/dist/schemas/themes/minimalist.json +45 -0
  281. package/dist/schemas/themes/morning-light.json +42 -0
  282. package/dist/schemas/themes/standard-dark.json +50 -0
  283. package/dist/schemas/themes/standard.json +42 -0
  284. package/dist/schemas/themes/tech-dark.json +48 -0
  285. package/dist/schemas/themes/warm-earth.json +50 -0
  286. package/dist/storage/ScopedContentContainer.d.ts +44 -0
  287. package/dist/storage/ScopedContentContainer.d.ts.map +1 -0
  288. package/dist/storage/ScopedContentContainer.js +94 -0
  289. package/dist/storage/ScopedContentContainer.js.map +1 -0
  290. package/dist/storage/index.d.ts +1 -0
  291. package/dist/storage/index.d.ts.map +1 -1
  292. package/dist/storage/index.js +1 -0
  293. package/dist/storage/index.js.map +1 -1
  294. package/dist/story/index.d.ts +53 -13
  295. package/dist/story/index.js +12 -4
  296. package/dist/themeLibrary-BHjJ0Qx6.d.ts +40 -0
  297. package/dist/{types-CkNttVSF.d.ts → types-BdZkdJ3z.d.ts} +17 -2
  298. package/dist/types-D98li1gV.d.ts +93 -0
  299. package/dist/versions/DocumentVersionManager.d.ts +31 -0
  300. package/dist/versions/DocumentVersionManager.d.ts.map +1 -0
  301. package/dist/versions/DocumentVersionManager.js +33 -0
  302. package/dist/versions/DocumentVersionManager.js.map +1 -0
  303. package/dist/versions/index.d.ts +29 -0
  304. package/dist/versions/index.d.ts.map +1 -0
  305. package/dist/versions/index.js +28 -0
  306. package/dist/versions/index.js.map +1 -0
  307. package/dist/versions/operations.d.ts +44 -0
  308. package/dist/versions/operations.d.ts.map +1 -0
  309. package/dist/versions/operations.js +190 -0
  310. package/dist/versions/operations.js.map +1 -0
  311. package/dist/versions/paths.d.ts +29 -0
  312. package/dist/versions/paths.d.ts.map +1 -0
  313. package/dist/versions/paths.js +66 -0
  314. package/dist/versions/paths.js.map +1 -0
  315. package/dist/versions/timestamp.d.ts +22 -0
  316. package/dist/versions/timestamp.d.ts.map +1 -0
  317. package/dist/versions/timestamp.js +44 -0
  318. package/dist/versions/timestamp.js.map +1 -0
  319. package/dist/versions/types.d.ts +92 -0
  320. package/dist/versions/types.d.ts.map +1 -0
  321. package/dist/versions/types.js +11 -0
  322. package/dist/versions/types.js.map +1 -0
  323. package/package.json +28 -1
  324. package/src/__tests__/colorUtils.test.ts +112 -0
  325. package/src/__tests__/getLayers.test.ts +32 -7
  326. package/src/__tests__/iconResolve.test.ts +122 -0
  327. package/src/__tests__/imageEditState.test.ts +74 -0
  328. package/src/__tests__/imageEditVersions.test.ts +169 -0
  329. package/src/__tests__/inferDocumentTitle.test.ts +50 -0
  330. package/src/__tests__/jsonForm.chooseControl.test.ts +86 -0
  331. package/src/__tests__/jsonForm.evaluateWhen.test.ts +59 -0
  332. package/src/__tests__/jsonForm.inferSchema.test.ts +25 -0
  333. package/src/__tests__/jsonForm.pointer.test.ts +103 -0
  334. package/src/__tests__/markdownIcons.test.ts +104 -0
  335. package/src/__tests__/markdownToDoc.test.ts +19 -4
  336. package/src/__tests__/recommendTemplates.test.ts +183 -0
  337. package/src/__tests__/scopedContentContainer.test.ts +89 -0
  338. package/src/__tests__/slideshowGenerator.test.ts +1 -1
  339. package/src/__tests__/templateAnnotationParse.test.ts +42 -0
  340. package/src/__tests__/templates.test.ts +93 -9
  341. package/src/__tests__/themeCompile.test.ts +156 -0
  342. package/src/__tests__/themeValidator.test.ts +125 -0
  343. package/src/__tests__/versions.test.ts +415 -0
  344. package/src/doc/audioMapping.ts +55 -11
  345. package/src/doc/getLayers.ts +32 -21
  346. package/src/doc/markdownToDoc.ts +45 -7
  347. package/src/doc/templates/featureBlock.ts +202 -0
  348. package/src/doc/templates/fullBleedQuote.ts +13 -0
  349. package/src/doc/templates/index.ts +50 -16
  350. package/src/doc/templates/listBlock.ts +24 -5
  351. package/src/doc/templates/statHighlight.ts +13 -0
  352. package/src/doc/templates/titleBlock.ts +9 -0
  353. package/src/doc/utils/themeUtils.ts +8 -7
  354. package/src/generate/slideshowGenerator.ts +1 -1
  355. package/src/generate/templateMapper.ts +2 -2
  356. package/src/icons/iconData.ts +31 -0
  357. package/src/icons/index.ts +18 -0
  358. package/src/icons/resolve.ts +139 -0
  359. package/src/imageEdit/ImageEditVersionManager.ts +73 -0
  360. package/src/imageEdit/export.ts +326 -0
  361. package/src/imageEdit/index.ts +71 -0
  362. package/src/imageEdit/persistence.ts +62 -0
  363. package/src/imageEdit/state.ts +112 -0
  364. package/src/imageEdit/versionPaths.ts +57 -0
  365. package/src/imageEdit/versions.ts +231 -0
  366. package/src/index.ts +4 -0
  367. package/src/jsonForm/chooseControl.ts +88 -0
  368. package/src/jsonForm/evaluateWhen.ts +59 -0
  369. package/src/jsonForm/index.ts +22 -0
  370. package/src/jsonForm/inferSchema.ts +25 -0
  371. package/src/jsonForm/pointer.ts +109 -0
  372. package/src/jsonForm/types.ts +167 -0
  373. package/src/markdown/convert.ts +145 -5
  374. package/src/markdown/index.ts +3 -0
  375. package/src/markdown/types.ts +19 -2
  376. package/src/markdown/utils.ts +159 -0
  377. package/src/recommend/index.ts +16 -0
  378. package/src/recommend/templates.ts +273 -0
  379. package/src/schemas/BlockTemplates.ts +50 -7
  380. package/src/schemas/ImageEditDoc.ts +95 -0
  381. package/src/schemas/Theme.ts +98 -31
  382. package/src/schemas/colorUtils.ts +186 -0
  383. package/src/schemas/fontStacks.ts +257 -0
  384. package/src/schemas/index.ts +12 -0
  385. package/src/schemas/themeCompile.ts +203 -0
  386. package/src/schemas/themeLibrary.ts +18 -597
  387. package/src/schemas/themeValidator.ts +388 -0
  388. package/src/schemas/themes/bold.json +48 -0
  389. package/src/schemas/themes/cinematic.json +54 -0
  390. package/src/schemas/themes/documentary.json +49 -0
  391. package/src/schemas/themes/gezellig.json +44 -0
  392. package/src/schemas/themes/index.ts +53 -0
  393. package/src/schemas/themes/magazine.json +44 -0
  394. package/src/schemas/themes/minimalist.json +45 -0
  395. package/src/schemas/themes/morning-light.json +42 -0
  396. package/src/schemas/themes/standard-dark.json +50 -0
  397. package/src/schemas/themes/standard.json +42 -0
  398. package/src/schemas/themes/tech-dark.json +48 -0
  399. package/src/schemas/themes/warm-earth.json +50 -0
  400. package/src/storage/ScopedContentContainer.ts +113 -0
  401. package/src/storage/index.ts +1 -0
  402. package/src/versions/DocumentVersionManager.ts +70 -0
  403. package/src/versions/index.ts +54 -0
  404. package/src/versions/operations.ts +230 -0
  405. package/src/versions/paths.ts +66 -0
  406. package/src/versions/timestamp.ts +48 -0
  407. package/src/versions/types.ts +91 -0
  408. package/dist/chunk-6BAVXFYC.js.map +0 -1
  409. package/dist/chunk-7GF6RDED.js +0 -82
  410. package/dist/chunk-7GF6RDED.js.map +0 -1
  411. package/dist/chunk-CYQHG27J.js.map +0 -1
  412. package/dist/chunk-F22AE6BY.js +0 -121
  413. package/dist/chunk-F22AE6BY.js.map +0 -1
  414. package/dist/chunk-FIQR4AJG.js +0 -517
  415. package/dist/chunk-FIQR4AJG.js.map +0 -1
  416. package/dist/chunk-OASJKWO5.js.map +0 -1
  417. package/dist/chunk-QM5PKNPW.js.map +0 -1
  418. package/dist/chunk-TSG2OSE6.js.map +0 -1
  419. package/dist/themeLibrary-CEo2D4b6.d.ts +0 -44
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/doc/templates/persistentLayers.ts","../src/doc/utils/themeUtils.ts","../src/doc/templates/titleBlock.ts","../src/doc/templates/sectionHeader.ts","../src/doc/templates/accentImage.ts","../src/doc/templates/captionUtils.ts","../src/doc/templates/statHighlight.ts","../src/doc/templates/quoteBlock.ts","../src/doc/templates/factCard.ts","../src/doc/templates/twoColumn.ts","../src/doc/templates/dateEvent.ts","../src/doc/templates/imageWithCaption.ts","../src/doc/templates/mapBlock.ts","../src/doc/templates/fullBleedQuote.ts","../src/doc/templates/listBlock.ts","../src/doc/templates/photoGrid.ts","../src/doc/templates/definitionCard.ts","../src/doc/templates/comparisonBar.ts","../src/doc/templates/pullQuote.ts","../src/doc/templates/videoWithCaption.ts","../src/doc/templates/videoPullQuote.ts","../src/doc/templates/dataTable.ts","../src/doc/templates/coverBlock.ts","../src/doc/templates/index.ts","../src/doc/utils/animationUtils.ts","../src/doc/markdownToDoc.ts","../src/doc/docToMarkdown.ts","../src/doc/getLayers.ts","../src/doc/audioMapping.ts"],"sourcesContent":["/**\n * Persistent Layers Expansion\n *\n * Expands persistent layer templates (solid backgrounds, gradients, overlays)\n * into raw Layer arrays. These layers are injected into each block based on\n * per-block flags (useBottomLayer, useTopLayer).\n *\n * This is shared code used by both site and efb-app doc renderers.\n *\n * Related Files:\n * - schemas/BlockTemplates.ts - PersistentLayerConfig types\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type {\n PersistentLayer,\n PersistentLayerTemplate,\n PersistentLayerConfig,\n SolidBackgroundConfig,\n GradientBackgroundConfig,\n ImageBackgroundConfig,\n PatternBackgroundConfig,\n TitleCaptionConfig,\n CornerBrandingConfig,\n ProgressIndicatorConfig,\n} from '../../schemas/BlockTemplates.js';\nimport type { Theme } from '../../schemas/Theme.js';\nimport { isPersistentLayerTemplate } from '../../schemas/BlockTemplates.js';\n\n// ============================================\n// Gradient Presets\n// ============================================\n\nconst GRADIENT_PRESETS: Record<string, string> = {\n 'dark-vignette':\n 'radial-gradient(ellipse at center, rgba(26,32,44,0.8) 0%, rgba(0,0,0,0.95) 100%)',\n 'radial-dark': 'radial-gradient(ellipse at center, #1a202c 0%, #000000 100%)',\n 'warm-sunset': 'linear-gradient(135deg, rgba(124,58,48,0.9) 0%, rgba(26,32,44,0.95) 100%)',\n 'cool-blue': 'linear-gradient(135deg, rgba(26,54,93,0.9) 0%, rgba(26,32,44,0.95) 100%)',\n 'earth-tones': 'linear-gradient(135deg, rgba(68,51,34,0.9) 0%, rgba(26,32,44,0.95) 100%)',\n};\n\n// ============================================\n// Background Layer Expansion\n// ============================================\n\n/**\n * Expand a solid background config to a Layer.\n */\nfunction expandSolidBackground(config: SolidBackgroundConfig): Layer {\n return {\n type: 'shape',\n id: 'persistent-bg-solid',\n content: {\n shape: 'rect',\n fill: config.color,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n\n/**\n * Expand a gradient background config to a Layer.\n */\nfunction expandGradientBackground(config: GradientBackgroundConfig): Layer {\n const gradient = config.gradient ?? GRADIENT_PRESETS[config.preset ?? 'dark-vignette'];\n\n return {\n type: 'shape',\n id: 'persistent-bg-gradient',\n content: {\n shape: 'rect',\n fill: gradient,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n\n/**\n * Expand an image background config to Layers.\n * Returns multiple layers: base image + dark overlay for readability.\n */\nfunction expandImageBackground(config: ImageBackgroundConfig): Layer[] {\n const layers: Layer[] = [];\n const opacity = config.opacity ?? 0.4;\n\n // Base image layer\n const imageLayer: Layer = {\n type: 'image',\n id: 'persistent-bg-image',\n content: {\n src: config.src,\n alt: 'Background',\n fit: 'cover',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: config.ambientMotion\n ? {\n type: config.ambientMotion,\n duration: 30, // Long ambient motion\n }\n : undefined,\n };\n\n layers.push(imageLayer);\n\n // Add dark overlay for text readability\n layers.push({\n type: 'shape',\n id: 'persistent-bg-overlay',\n content: {\n shape: 'rect',\n fill: `rgba(0,0,0,${0.5 + (1 - opacity) * 0.3})`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n });\n\n return layers;\n}\n\n/**\n * Expand a pattern background config to a Layer.\n */\nfunction expandPatternBackground(config: PatternBackgroundConfig): Layer {\n const opacity = config.opacity ?? 0.1;\n const color = config.color ?? `rgba(255,255,255,${opacity})`;\n\n // Pattern as SVG data URI for rect patterns\n // For simplicity, use a solid subtle color with reduced opacity\n return {\n type: 'shape',\n id: 'persistent-bg-pattern',\n content: {\n shape: 'rect',\n fill: color,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n\n// ============================================\n// Overlay Layer Expansion\n// ============================================\n\n/**\n * Expand a title caption config to Layers.\n */\nfunction expandTitleCaption(config: TitleCaptionConfig): Layer[] {\n const layers: Layer[] = [];\n const fontSize = config.fontSize ?? 18;\n const hasSubtitle = !!config.subtitle;\n\n // Position calculations\n const isBottom = config.position.includes('bottom');\n const isLeft = config.position.includes('left');\n\n // Even padding around the pill (3% from edges)\n const pad = 3; // percent\n\n // Pill dimensions — taller when subtitle present\n const pillHeight = hasSubtitle ? '15%' : '7%';\n // Position above player controls\n const bgYPos = isBottom ? (hasSubtitle ? '78%' : '84%') : '2%';\n const bgXPos = isLeft ? `${pad}%` : '68%';\n\n // Thumbnail sizing — use different width/height to appear square in 16:9 viewport\n // In 16:9, 6% of width ≈ 10.7% of height in pixels, so use ~6%w x 10%h for visual square\n const thumbW = hasSubtitle ? '6%' : '5%';\n const thumbH = hasSubtitle ? '10%' : '5%';\n const thumbPad = 1.5; // padding inside pill around thumbnail (percent)\n\n // Text X offset: after thumbnail + padding, or just pill padding\n const textX =\n config.showThumbnail && isLeft\n ? `${pad + thumbPad + 6 + thumbPad}%` // pill edge + thumb padding + thumb width + gap\n : `${pad + thumbPad}%`;\n // Text area width: pill width minus thumbnail area minus padding\n const textWidth = config.showThumbnail\n ? '19%' // narrower when thumbnail takes space\n : '24%';\n\n // Title Y: top of text area inside pill\n const titleYPos = isBottom ? (hasSubtitle ? '80%' : '86%') : '4%';\n\n // Background pill for readability\n layers.push({\n type: 'shape',\n id: 'persistent-caption-bg',\n content: {\n shape: 'rect',\n fill: 'rgba(0,0,0,0.6)',\n borderRadius: 8,\n },\n position: {\n x: bgXPos,\n y: bgYPos,\n width: config.showThumbnail ? '30%' : '28%',\n height: pillHeight,\n },\n });\n\n // Thumbnail if configured\n if (config.showThumbnail && config.thumbnailSrc) {\n const thumbX = isLeft ? `${pad + thumbPad}%` : '93%';\n // Center thumbnail vertically in pill\n const thumbY = isBottom ? (hasSubtitle ? `${78 + thumbPad}%` : '85%') : '3%';\n\n layers.push({\n type: 'image',\n id: 'persistent-caption-thumb',\n content: {\n src: config.thumbnailSrc,\n alt: 'Article thumbnail',\n fit: 'cover',\n },\n position: {\n x: thumbX,\n y: thumbY,\n width: thumbW,\n height: thumbH,\n },\n });\n }\n\n // Title text — single line, cropped with ellipsis\n layers.push({\n type: 'text',\n id: 'persistent-caption-title',\n content: {\n text: config.title,\n style: {\n fontSize,\n fontWeight: 'bold',\n color: 'rgba(255,255,255,0.9)',\n textAlign: isLeft ? 'left' : 'right',\n maxLines: 1,\n },\n },\n position: {\n x: textX,\n y: titleYPos,\n width: textWidth,\n },\n });\n\n // Subtitle text (e.g., short URL)\n if (hasSubtitle) {\n const subtitleYPos = isBottom ? '85.5%' : '8%';\n\n layers.push({\n type: 'text',\n id: 'persistent-caption-subtitle',\n content: {\n text: config.subtitle!,\n style: {\n fontSize: 18,\n fontWeight: 'normal',\n color: 'rgba(255,255,255,0.55)',\n textAlign: isLeft ? 'left' : 'right',\n },\n },\n position: {\n x: textX,\n y: subtitleYPos,\n width: textWidth,\n },\n });\n }\n\n return layers;\n}\n\n/**\n * Expand a corner branding config to a Layer.\n */\nfunction expandCornerBranding(config: CornerBrandingConfig): Layer {\n const isBottom = config.position.includes('bottom');\n const isLeft = config.position.includes('left');\n\n const xPos = isLeft ? '3%' : '90%';\n const yPos = isBottom ? '94%' : '3%';\n\n if (config.isImage) {\n return {\n type: 'image',\n id: 'persistent-branding',\n content: {\n src: config.content,\n alt: 'Branding',\n fit: 'contain',\n },\n position: {\n x: xPos,\n y: yPos,\n width: '8%',\n height: '4%',\n },\n };\n }\n\n return {\n type: 'text',\n id: 'persistent-branding',\n content: {\n text: config.content,\n style: {\n fontSize: 14,\n fontWeight: 'normal',\n color: 'rgba(255,255,255,0.6)',\n },\n },\n position: {\n x: xPos,\n y: yPos,\n },\n };\n}\n\n/**\n * Expand a progress indicator config to a Layer.\n * Note: Progress requires block context, returns placeholder bar.\n */\nfunction expandProgressIndicator(config: ProgressIndicatorConfig): Layer {\n const color = config.color ?? 'rgba(255,255,255,0.3)';\n const y = config.position === 'top' ? '1%' : '98%';\n\n // Simple bar style - actual progress would need to be set per-block\n return {\n type: 'shape',\n id: 'persistent-progress',\n content: {\n shape: 'rect',\n fill: color,\n borderRadius: 2,\n },\n position: {\n x: '5%',\n y,\n width: '90%',\n height: '0.5%',\n },\n };\n}\n\n// ============================================\n// Main Expansion Function\n// ============================================\n\n/**\n * Expand a single persistent layer (template or raw) to raw Layer(s).\n */\nexport function expandPersistentLayer(layer: PersistentLayer): Layer[] {\n // If already a raw Layer, return as-is\n if (!isPersistentLayerTemplate(layer)) {\n return [layer as Layer];\n }\n\n const template = layer as PersistentLayerTemplate;\n const config = template.config;\n\n switch (config.type) {\n case 'solidBackground':\n return [expandSolidBackground(config)];\n case 'gradientBackground':\n return [expandGradientBackground(config)];\n case 'imageBackground':\n return expandImageBackground(config);\n case 'patternBackground':\n return [expandPatternBackground(config)];\n case 'titleCaption':\n return expandTitleCaption(config);\n case 'cornerBranding':\n return [expandCornerBranding(config)];\n case 'progressIndicator':\n return [expandProgressIndicator(config)];\n default:\n console.warn('Unknown persistent layer template:', (config as Record<string, unknown>).type);\n return [];\n }\n}\n\n/**\n * Expand all persistent layers in a config to raw Layer arrays.\n */\nexport function expandPersistentLayers(layers: PersistentLayer[] | undefined): Layer[] {\n if (!layers || layers.length === 0) {\n return [];\n }\n\n // Use reduce+concat instead of flatMap for Coherent GT compatibility (ES2017)\n return layers.reduce<Layer[]>((acc, layer) => acc.concat(expandPersistentLayer(layer)), []);\n}\n\n// ============================================\n// Style Presets (legacy helper — prefer theme.persistentLayers)\n// ============================================\n\n/** Legacy style preset names. Prefer using `Theme.persistentLayers` directly. */\nexport type DocStylePreset = 'minimal' | 'documentary' | 'branded' | 'cinematic' | 'clean';\n\n/**\n * Get a PersistentLayerConfig from a style preset.\n *\n * @param preset - Style preset name\n * @param articleTitle - Article title for title caption\n * @param heroSrc - Optional hero image for cinematic style\n */\nexport function getDocStyleConfig(\n preset: DocStylePreset,\n articleTitle: string,\n heroSrc?: string,\n subtitle?: string,\n): PersistentLayerConfig {\n switch (preset) {\n case 'minimal':\n return {};\n\n case 'documentary':\n return {\n bottomLayers: [\n {\n template: 'gradientBackground',\n config: { type: 'gradientBackground', preset: 'dark-vignette' },\n },\n ],\n topLayers: [\n {\n template: 'titleCaption',\n config: {\n type: 'titleCaption',\n title: articleTitle,\n subtitle,\n position: 'bottom-left',\n fontSize: 24,\n showThumbnail: !!heroSrc,\n thumbnailSrc: heroSrc,\n },\n },\n ],\n };\n\n case 'branded':\n return {\n bottomLayers: [\n {\n template: 'gradientBackground',\n config: { type: 'gradientBackground', preset: 'cool-blue' },\n },\n ],\n topLayers: [\n {\n template: 'titleCaption',\n config: {\n type: 'titleCaption',\n title: articleTitle,\n subtitle,\n position: 'bottom-left',\n fontSize: 26,\n showThumbnail: !!heroSrc,\n thumbnailSrc: heroSrc,\n },\n },\n ],\n };\n\n case 'cinematic':\n return {\n bottomLayers: heroSrc\n ? [\n {\n template: 'imageBackground',\n config: {\n type: 'imageBackground',\n src: heroSrc,\n blur: 12,\n opacity: 0.3,\n ambientMotion: 'zoomIn',\n },\n },\n ]\n : [\n {\n template: 'gradientBackground',\n config: { type: 'gradientBackground', preset: 'radial-dark' },\n },\n ],\n topLayers: [\n {\n template: 'titleCaption',\n config: {\n type: 'titleCaption',\n title: articleTitle,\n subtitle,\n position: 'bottom-right',\n fontSize: 22,\n },\n },\n ],\n };\n\n case 'clean':\n return {\n bottomLayers: [\n {\n template: 'solidBackground',\n config: { type: 'solidBackground', color: '#1a202c' },\n },\n ],\n };\n\n default:\n return {};\n }\n}\n\n/**\n * Get persistent layers from a Theme. Returns the theme's baked-in\n * persistentLayers config, or an empty config when the theme has none.\n */\nexport function getPersistentLayersFromTheme(theme: Theme): PersistentLayerConfig {\n return theme.persistentLayers ?? {};\n}\n","/**\n * Theme Utilities\n *\n * Template-facing helpers that read from the Theme object on the\n * TemplateContext. Templates call these instead of hard-coding style\n * decisions, so the same template code adapts to any theme.\n */\n\nimport type { TemplateContext } from '../../schemas/BlockTemplates.js';\nimport type { ThemeColorScheme, RenderStyle } from '../../schemas/Theme.js';\nimport type { AnimationType } from '../../schemas/Doc.js';\n\n// ============================================\n// Color Scheme Resolution\n// ============================================\n\n/** Fallback color scheme when a name is not found in the theme. */\nconst FALLBACK_COLOR_SCHEME: ThemeColorScheme = {\n bg: '#1a365d',\n text: '#63b3ed',\n accent: '#90cdf4',\n};\n\n/**\n * Resolve a named color scheme from the theme, with a safe fallback.\n * Templates call this instead of `COLOR_SCHEMES[name]`.\n */\nexport function resolveColorScheme(\n context: TemplateContext,\n name: string | undefined,\n): ThemeColorScheme {\n const schemes = context.theme.colorSchemes;\n if (name && name in schemes) return schemes[name];\n // Fall back to first defined scheme, then hard fallback\n const keys = Object.keys(schemes);\n if (keys.length > 0) return schemes[keys[0]];\n return FALLBACK_COLOR_SCHEME;\n}\n\n// ============================================\n// Font Family Resolution\n// ============================================\n\n/** Safe system font fallbacks. */\nconst FALLBACK_BODY = 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif';\nconst FALLBACK_TITLE = 'Georgia, \"Times New Roman\", serif';\nconst FALLBACK_MONO = 'Consolas, \"Courier New\", monospace';\n\n/**\n * Get the theme font family for a given role.\n * Templates call this to set `fontFamily` on text layers.\n *\n * @param context Template context (includes theme with typography settings)\n * @param role 'title' for headings, 'body' for descriptions, 'mono' for code\n * @returns A CSS font-family string with the theme's font and safe fallbacks\n */\nexport function getThemeFont(context: TemplateContext, role: 'title' | 'body' | 'mono'): string {\n const { typography } = context.theme;\n switch (role) {\n case 'title':\n return typography.titleFontFamily || FALLBACK_TITLE;\n case 'body':\n return typography.bodyFontFamily || FALLBACK_BODY;\n case 'mono':\n return typography.monoFontFamily || FALLBACK_MONO;\n }\n}\n\n// ============================================\n// Font Sizing\n// ============================================\n\n/**\n * Calculate a theme-aware scaled font size.\n * Applies the theme's typography scale multipliers on top of the\n * viewport-based font scale from LayoutStrategy.\n *\n * @param basePx Base font size designed for 1920×1080\n * @param context Template context (includes fontScale, layout, theme)\n * @param isTitle Whether this is title text (uses titleScale) or body (bodyScale)\n */\nexport function themedFontSize(\n basePx: number,\n context: TemplateContext,\n isTitle: boolean = false,\n): number {\n const { fontScale, layout, theme } = context;\n\n // Base scale from viewport + orientation\n const layoutScale = isTitle ? layout.titleScale : layout.bodyScale;\n\n // Theme multiplier (defaults to 1.0 when not set)\n const themeScale = isTitle\n ? (theme.typography.titleScale ?? 1.0)\n : (theme.typography.bodyScale ?? 1.0);\n\n return Math.round(basePx * fontScale * layoutScale * themeScale);\n}\n\n// ============================================\n// Animation Helpers\n// ============================================\n\n/**\n * Scale an animation duration by the theme's animationSpeed multiplier.\n * A speed of 1.0 returns the base duration unchanged.\n */\nexport function scaleAnimationDuration(baseDuration: number, context: TemplateContext): number {\n const speed = context.theme.style.animationSpeed ?? 1.0;\n return baseDuration * speed;\n}\n\n/**\n * Get the theme's default animation type for a layer kind.\n * Returns `undefined` when the theme doesn't specify one (template picks its own).\n */\nexport function getDefaultAnimation(\n context: TemplateContext,\n layerType: 'text' | 'image',\n): AnimationType | undefined {\n const rs: RenderStyle = context.theme.renderStyle;\n return layerType === 'text' ? rs.defaultTextAnimation : rs.defaultImageAnimation;\n}\n\n// ============================================\n// Style Helpers\n// ============================================\n\n/**\n * Whether the theme defaults to text shadows.\n * Templates should consult this when choosing `shadow: true/false`.\n */\nexport function shouldUseShadow(context: TemplateContext): boolean {\n return context.theme.style.textShadow ?? true;\n}\n\n/**\n * Get the theme's overlay opacity for image-backed blocks.\n */\nexport function getOverlayOpacity(context: TemplateContext): number {\n return context.theme.style.overlayOpacity ?? 0.5;\n}\n\n// ============================================\n// Template Hint Access\n// ============================================\n\n/**\n * Read a per-template hint from the theme's renderStyle.\n * Returns `fallback` when the hint isn't defined.\n *\n * @example\n * ```ts\n * const entrance = getTemplateHint(context, 'statHighlight', 'entrance', 'subtle');\n * ```\n */\nexport function getTemplateHint<T extends string | number | boolean>(\n context: TemplateContext,\n templateName: string,\n key: string,\n fallback: T,\n): T {\n const hints = context.theme.renderStyle.templateHints;\n if (!hints) return fallback;\n const tplHints = hints[templateName];\n if (!tplHints || !(key in tplHints)) return fallback;\n return tplHints[key] as T;\n}\n","/**\n * Title Block Template\n *\n * Large title with optional subtitle for doc intros.\n * Centered text with fade-in animations.\n * Adapts font sizes and positioning for different viewports.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { TitleBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\n\nexport function titleBlock(input: TitleBlockInput, context: TemplateContext): Layer[] {\n const { title, subtitle, backgroundColor } = input;\n const { theme, layout } = context;\n\n // Scale font sizes for viewport\n const titleFontSize = scaledFontSize(96, context, true);\n const subtitleFontSize = scaledFontSize(36, context, false);\n\n const baseBg = backgroundColor || theme.colors.primary;\n\n const layers: Layer[] = [\n // Background — radial gradient for depth instead of flat color\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 40%, ${baseBg} 0%, ${theme.colors.background} 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n // Subtle decorative line above title\n {\n type: 'shape',\n id: 'accent-line',\n content: {\n shape: 'rect',\n fill: 'rgba(255, 255, 255, 0.2)',\n },\n position: {\n x: '40%',\n y: subtitle ? '28%' : '38%',\n width: '20%',\n height: '2px',\n },\n },\n // Title\n {\n type: 'text',\n id: 'title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: subtitle ? layout.primaryY : '50%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 2 },\n },\n ];\n\n // Add subtitle if provided\n if (subtitle) {\n layers.push({\n type: 'text',\n id: 'subtitle',\n content: {\n text: subtitle,\n style: {\n fontSize: subtitleFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.5,\n },\n },\n position: {\n x: '50%',\n y: layout.secondaryY,\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1.5, delay: 1 },\n });\n }\n\n return layers;\n}\n","/**\n * Section Header Template\n *\n * Section title card with optional background image.\n * Used to introduce new sections of a story.\n * When an image is provided, displays like a title slide with the image as background.\n * Without an image, falls back to a colored background.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer, AnimationType } from '../../schemas/Doc.js';\nimport type { SectionHeaderInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\n\nexport function sectionHeader(input: SectionHeaderInput, context: TemplateContext): Layer[] {\n const { title = '', colorScheme = 'blue', imageSrc, imageAlt, ambientMotion } = input;\n const { layout } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Scale font sizes for viewport\n const titleFontSize = scaledFontSize(72, context, true);\n\n const layers: Layer[] = [];\n\n // Background - either image or solid color\n if (imageSrc) {\n // Image background with Ken Burns effect\n layers.push({\n type: 'image',\n id: 'bg-image',\n content: {\n src: imageSrc,\n alt: imageAlt || title,\n fit: 'cover',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: ambientMotion\n ? { type: ambientMotion as AnimationType, duration: 8 }\n : { type: 'slowZoom', duration: 8, direction: 'in' },\n });\n\n // Dark overlay for text readability\n layers.push({\n type: 'shape',\n id: 'overlay',\n content: {\n shape: 'rect',\n fill: 'rgba(0, 0, 0, 0.5)',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n });\n } else {\n // Solid color background\n layers.push({\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: colors.bg,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n });\n\n // Decorative lines above and below title\n layers.push({\n type: 'shape',\n id: 'line-top',\n content: { shape: 'rect', fill: `${colors.text}33` },\n position: { x: '50%', y: '40%', width: '20%', height: '2px', anchor: 'center' },\n });\n layers.push({\n type: 'shape',\n id: 'line-bottom',\n content: { shape: 'rect', fill: `${colors.text}33` },\n position: { x: '50%', y: '60%', width: '20%', height: '2px', anchor: 'center' },\n });\n }\n\n // Section title - white text with shadow for readability over images\n layers.push({\n type: 'text',\n id: 'title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: imageSrc ? '#ffffff' : colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '50%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1.5 },\n });\n\n return layers;\n}\n","/**\n * Accent Image Utility\n *\n * Creates image layers and layout adjustments for accent images on text-based slides.\n * Accent images are tasteful additions that complement text without overwhelming it.\n *\n * Layout patterns:\n * - left-strip: 35% width vertical strip on left, text area shifted to right 65%\n * - right-strip: 35% width vertical strip on right, text area shifted to left 65%\n * - bottom-strip: 35% height horizontal strip at bottom, text area in upper 65%\n * - corner-inset: Small 25% corner image with gradient vignette\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer, ImageLayer, ShapeLayer, Animation } from '../../schemas/Doc.js';\nimport type { AccentImage, AccentPosition } from '../../schemas/BlockTemplates.js';\n\nconst PERCENTAGE_RE = /^(\\d+(?:\\.\\d+)?)\\s*%?$/;\n\n/**\n * Layout adjustments when an accent image is present.\n * Templates use these values to reposition their text content.\n */\nexport interface AccentLayout {\n /** X offset for text center (e.g., '64%' for left-strip) */\n textCenterX: string;\n /** Width available for text content */\n textWidth: string;\n /** Y offset adjustment for vertical positioning */\n textYAdjust: number;\n /** Whether to adjust Y positions (for bottom-strip) */\n adjustY: boolean;\n}\n\n/**\n * Default layout when no accent image is present.\n */\nexport const DEFAULT_LAYOUT: AccentLayout = {\n textCenterX: '50%',\n textWidth: '85%',\n textYAdjust: 0,\n adjustY: false,\n};\n\n/**\n * Map ambientMotion values to proper Ken Burns animations.\n * Uses slowZoom variants which provide smooth pan/zoom without opacity changes.\n * Supports both standard values ('zoomIn', 'panLeft', etc.) and legacy\n * aliases ('in', 'out', 'left', 'right') for backward compatibility.\n *\n * @param motion - The ambient motion value (e.g., 'zoomIn', 'panLeft')\n * @param duration - Optional animation duration in seconds\n */\nexport function mapAmbientMotion(\n motion: string | undefined,\n duration?: number,\n): Animation | undefined {\n if (!motion) return undefined;\n const base = duration !== undefined ? { duration } : {};\n switch (motion) {\n case 'zoomIn':\n case 'in':\n return { type: 'slowZoom', direction: 'in', ...base };\n case 'zoomOut':\n case 'out':\n return { type: 'slowZoom', direction: 'out', ...base };\n case 'panLeft':\n case 'left':\n return { type: 'slowZoom', panDirection: 'left', ...base };\n case 'panRight':\n case 'right':\n return { type: 'slowZoom', panDirection: 'right', ...base };\n default:\n return undefined;\n }\n}\n\n/**\n * Accent strip width/height as percentage.\n * 35% gives the image enough presence to complement the text without overwhelming it.\n */\nconst STRIP_SIZE = 35;\nconst STRIP_SIZE_PCT = `${STRIP_SIZE}%`;\n\n/**\n * Get layout adjustments based on accent position.\n */\nexport function getAccentLayout(position: AccentPosition): AccentLayout {\n switch (position) {\n case 'left-strip':\n return {\n textCenterX: `${50 + STRIP_SIZE / 2}%`, // Shift center right\n textWidth: `${100 - STRIP_SIZE - 8}%`, // Leave margin\n textYAdjust: 0,\n adjustY: false,\n };\n case 'right-strip':\n return {\n textCenterX: `${50 - STRIP_SIZE / 2}%`, // Shift center left\n textWidth: `${100 - STRIP_SIZE - 8}%`,\n textYAdjust: 0,\n adjustY: false,\n };\n case 'bottom-strip':\n return {\n textCenterX: '50%',\n textWidth: '85%',\n textYAdjust: -10, // Shift content up by 10%\n adjustY: true,\n };\n case 'corner-inset':\n return {\n textCenterX: '45%', // Slight shift to avoid corner\n textWidth: '70%',\n textYAdjust: 0,\n adjustY: false,\n };\n default:\n return DEFAULT_LAYOUT;\n }\n}\n\n/**\n * Create layers for an accent image.\n * Returns the image layer and any overlay/gradient layers needed.\n */\nexport function createAccentLayers(accent: AccentImage, slideId: string): Layer[] {\n const layers: Layer[] = [];\n const { src, alt, position, ambientMotion, credit, license } = accent;\n\n switch (position) {\n case 'left-strip':\n layers.push(createStripImage(src, alt, 'left', slideId, ambientMotion, credit, license));\n layers.push(createStripGradient('left', slideId));\n break;\n\n case 'right-strip':\n layers.push(createStripImage(src, alt, 'right', slideId, ambientMotion, credit, license));\n layers.push(createStripGradient('right', slideId));\n break;\n\n case 'bottom-strip':\n layers.push(createBottomStripImage(src, alt, slideId, ambientMotion, credit, license));\n layers.push(createBottomStripGradient(slideId));\n break;\n\n case 'corner-inset':\n layers.push(createCornerInsetImage(src, alt, slideId, ambientMotion, credit, license));\n layers.push(createCornerVignette(slideId));\n break;\n }\n\n return layers;\n}\n\n/**\n * Create a vertical strip image layer.\n */\nfunction createStripImage(\n src: string,\n alt: string,\n side: 'left' | 'right',\n slideId: string,\n ambientMotion?: AccentImage['ambientMotion'],\n credit?: string,\n license?: string,\n): ImageLayer {\n return {\n type: 'image',\n id: `${slideId}-accent-img`,\n content: {\n src,\n alt,\n fit: 'cover',\n credit,\n license,\n },\n position: {\n x: side === 'left' ? 0 : `${100 - STRIP_SIZE}%`,\n y: 0,\n width: STRIP_SIZE_PCT,\n height: '100%',\n },\n animation: mapAmbientMotion(ambientMotion, 15),\n };\n}\n\n/**\n * Create a gradient overlay for strip images (fades to background).\n */\nfunction createStripGradient(side: 'left' | 'right', slideId: string): ShapeLayer {\n // Gradient from transparent to background color at the edge\n const gradientId = side === 'left' ? 'accent-gradient-left' : 'accent-gradient-right';\n\n return {\n type: 'shape',\n id: `${slideId}-accent-fade`,\n content: {\n shape: 'rect',\n // SVG gradient will be handled by the renderer\n // Using a semi-transparent overlay as fallback\n fill: `url(#${gradientId})`,\n },\n position: {\n x: side === 'left' ? `${STRIP_SIZE - 8}%` : `${100 - STRIP_SIZE}%`,\n y: 0,\n width: '10%',\n height: '100%',\n },\n };\n}\n\n/**\n * Create a horizontal bottom strip image layer.\n */\nfunction createBottomStripImage(\n src: string,\n alt: string,\n slideId: string,\n ambientMotion?: AccentImage['ambientMotion'],\n credit?: string,\n license?: string,\n): ImageLayer {\n return {\n type: 'image',\n id: `${slideId}-accent-img`,\n content: {\n src,\n alt,\n fit: 'cover',\n credit,\n license,\n },\n position: {\n x: 0,\n y: `${100 - STRIP_SIZE}%`,\n width: '100%',\n height: STRIP_SIZE_PCT,\n },\n animation: mapAmbientMotion(ambientMotion, 15),\n };\n}\n\n/**\n * Create a gradient overlay for bottom strip (fades up to background).\n */\nfunction createBottomStripGradient(slideId: string): ShapeLayer {\n return {\n type: 'shape',\n id: `${slideId}-accent-fade`,\n content: {\n shape: 'rect',\n fill: 'url(#accent-gradient-bottom)',\n },\n position: {\n x: 0,\n y: `${100 - STRIP_SIZE - 8}%`,\n width: '100%',\n height: '12%',\n },\n };\n}\n\n/**\n * Create a corner inset image layer.\n */\nfunction createCornerInsetImage(\n src: string,\n alt: string,\n slideId: string,\n ambientMotion?: AccentImage['ambientMotion'],\n credit?: string,\n license?: string,\n): ImageLayer {\n return {\n type: 'image',\n id: `${slideId}-accent-img`,\n content: {\n src,\n alt,\n fit: 'cover',\n credit,\n license,\n },\n position: {\n x: '70%',\n y: '60%',\n width: '28%',\n height: '38%',\n anchor: 'top-left',\n },\n animation: mapAmbientMotion(ambientMotion, 15) ?? { type: 'fadeIn', duration: 2, delay: 0.5 },\n };\n}\n\n/**\n * Create a vignette overlay around corner inset.\n */\nfunction createCornerVignette(slideId: string): ShapeLayer {\n return {\n type: 'shape',\n id: `${slideId}-accent-vignette`,\n content: {\n shape: 'rect',\n fill: 'url(#accent-vignette-corner)',\n borderRadius: 8,\n },\n position: {\n x: '69%',\n y: '59%',\n width: '30%',\n height: '40%',\n },\n };\n}\n\n/**\n * Adjust a Y position value based on accent layout.\n * Used by templates to shift content when bottom-strip is present.\n */\nexport function adjustY(originalY: string | number, layout: AccentLayout): string {\n if (!layout.adjustY || layout.textYAdjust === 0) {\n return typeof originalY === 'number' ? `${originalY}%` : originalY;\n }\n\n // Parse percentage value\n const yStr = typeof originalY === 'number' ? `${originalY}` : originalY;\n const match = yStr.match(PERCENTAGE_RE);\n\n if (match) {\n const yValue = parseFloat(match[1]);\n const adjusted = Math.max(5, yValue + layout.textYAdjust);\n return `${adjusted}%`;\n }\n\n return yStr;\n}\n","/**\n * Template Utilities\n *\n * Shared helpers for doc block templates:\n * - Caption text cleaning\n * - Common layer construction patterns\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\n\nconst TRAILING_PUNCT_RE = /[.;:!?]+$/;\n\n/**\n * Strip trailing punctuation from a caption string.\n * Image captions on blocks look cleaner without terminal periods,\n * semicolons, or other sentence-ending punctuation.\n */\nexport function cleanCaption(text: string): string {\n return text.replace(TRAILING_PUNCT_RE, '').trim();\n}\n\n/**\n * Create a full-screen background shape layer.\n * Most text-based templates start with this as their first layer.\n */\nexport function createBackgroundLayer(id: string, fill: string): Layer {\n return {\n type: 'shape',\n id,\n content: { shape: 'rect', fill },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n","/**\n * Stat Highlight Template\n *\n * Large statistic/number with description and optional detail.\n * Great for emphasizing key data points.\n * Adapts font sizes and positioning for different viewports.\n *\n * Supports optional accent images that appear as tasteful side/bottom strips.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { StatHighlightInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\nexport function statHighlight(input: StatHighlightInput, context: TemplateContext): Layer[] {\n const { stat, description, detail, colorScheme = 'blue', accentImage } = input;\n const { theme } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n // Scale font sizes — stat is dramatically large, description is understated\n const statFontSize = scaledFontSize(148, context, true);\n const descFontSize = scaledFontSize(32, context, false);\n const detailFontSize = scaledFontSize(26, context, false);\n\n const layers: Layer[] = [\n createBackgroundLayer(\n 'bg',\n `linear-gradient(180deg, ${theme.colors.background} 0%, #0f1520 100%)`,\n ),\n ];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Big stat — hero element, dominates the slide\n layers.push({\n type: 'text',\n id: 'stat',\n content: {\n text: stat,\n style: {\n fontSize: statFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: colors.text,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('32%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'zoomIn', duration: 0.6 },\n });\n\n // Description — smaller and understated beneath the stat\n layers.push({\n type: 'text',\n id: 'description',\n content: {\n text: description,\n style: {\n fontSize: descFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.6,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('58%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.3 },\n });\n\n // Add detail if provided\n if (detail) {\n layers.push({\n type: 'text',\n id: 'detail',\n content: {\n text: detail,\n style: {\n fontSize: detailFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: colors.accent,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('75%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 1 },\n });\n }\n\n return layers;\n}\n","/**\n * Quote Block Template\n *\n * Large centered quote with optional attribution.\n * Good for impactful statements or descriptions.\n * Adapts font sizes and positioning for different viewports.\n *\n * Supports optional accent images that appear as tasteful side/bottom strips.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { QuoteBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\nexport function quoteBlock(input: QuoteBlockInput, context: TemplateContext): Layer[] {\n const { quote, attribution, accentImage } = input;\n const { theme, layout } = context;\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n // Scale font sizes for viewport\n const quoteFontSize = scaledFontSize(48, context, true);\n const attrFontSize = scaledFontSize(24, context, false);\n\n // Decorative quotation mark font size\n const decorativeQuoteFontSize = scaledFontSize(280, context, true);\n\n const layers: Layer[] = [\n createBackgroundLayer(\n 'bg',\n `linear-gradient(160deg, ${theme.colors.backgroundLight} 0%, #1e2636 100%)`,\n ),\n ];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Decorative opening quotation mark — oversized, low-opacity behind quote\n layers.push({\n type: 'text',\n id: 'deco-quote',\n content: {\n text: '\\u201C',\n style: {\n fontSize: decorativeQuoteFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: 'rgba(255, 255, 255, 0.06)',\n textAlign: 'center',\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('18%', accentLayout),\n anchor: 'center',\n },\n });\n\n // Quote text - positioned based on accent layout\n const quoteY = attribution ? layout.primaryY : '50%';\n layers.push({\n type: 'text',\n id: 'quote',\n content: {\n text: quote,\n style: {\n fontSize: quoteFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: theme.colors.text,\n textAlign: 'center',\n lineHeight: 1.6,\n shadow: true,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(quoteY, accentLayout),\n anchor: 'center',\n width: accentLayout.textWidth,\n },\n animation: { type: 'fadeIn', duration: 2 },\n });\n\n // Add attribution if provided\n if (attribution) {\n layers.push({\n type: 'text',\n id: 'attribution',\n content: {\n text: `— ${attribution}`,\n style: {\n fontSize: attrFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(layout.captionY, accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 1.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Fact Card Template\n *\n * Key fact with explanation and optional source.\n * Useful for presenting important information clearly.\n * Adapts font sizes and positioning for different viewports.\n *\n * Supports optional accent images that appear as tasteful side/bottom strips.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { FactCardInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\nexport function factCard(input: FactCardInput, context: TemplateContext): Layer[] {\n const { fact, explanation, source, accentImage } = input;\n const { theme } = context;\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n // Scale font sizes for viewport\n const factFontSize = scaledFontSize(56, context, true);\n const explainFontSize = scaledFontSize(32, context, false);\n const sourceFontSize = scaledFontSize(20, context, false);\n\n const layers: Layer[] = [\n createBackgroundLayer(\n 'bg',\n `linear-gradient(170deg, #1e2030 0%, ${theme.colors.background} 100%)`,\n ),\n ];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Fact (main statement)\n layers.push({\n type: 'text',\n id: 'fact',\n content: {\n text: fact,\n style: {\n fontSize: factFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n lineHeight: 1.4,\n shadow: true,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('35%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1.5 },\n });\n\n // Explanation\n layers.push({\n type: 'text',\n id: 'explanation',\n content: {\n text: explanation,\n style: {\n fontSize: explainFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.5,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('60%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.8 },\n });\n\n // Add source if provided\n if (source) {\n layers.push({\n type: 'text',\n id: 'source',\n content: {\n text: source,\n style: {\n fontSize: sourceFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('85%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 1.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Two Column Template\n *\n * Side-by-side comparison of two items.\n * Each column has a label and optional sublabel.\n * Adapts font sizes and positioning for different viewports.\n *\n * Portrait mode: Stacks columns vertically (top/bottom) instead of side-by-side.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { TwoColumnInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\nimport { getTwoColumnPositions } from '../../schemas/LayoutStrategy.js';\n\nexport function twoColumn(input: TwoColumnInput, context: TemplateContext): Layer[] {\n const { left, right, header, leftColor = 'green', rightColor = 'blue' } = input;\n\n // Guard: required fields may be absent when generated from sparse markdown\n if (!left?.label || !right?.label) return [];\n\n const { theme, layout, orientation } = context;\n const leftColors = resolveColorScheme(context, leftColor);\n const rightColors = resolveColorScheme(context, rightColor);\n\n // Get column positions based on orientation\n const positions = getTwoColumnPositions(orientation);\n const isStacked = layout.stackColumns;\n\n // Column width ~42% for side-by-side, ~85% for stacked\n const columnWidth = isStacked ? '85%' : '42%';\n\n // Calculate font sizes based on viewport\n const headerFontSize = scaledFontSize(32, context, false);\n const labelFontSize = scaledFontSize(44, context, true);\n const sublabelFontSize = scaledFontSize(22, context, false);\n\n const layers: Layer[] = [\n // Background — subtle gradient to add depth\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `linear-gradient(135deg, ${theme.colors.background} 0%, #16202e 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n if (!isStacked) {\n // Left column background panel\n layers.push({\n type: 'shape',\n id: 'left-panel',\n content: {\n shape: 'rect',\n fill: 'rgba(255, 255, 255, 0.04)',\n },\n position: { x: '3%', y: '15%', width: '44%', height: '70%' },\n });\n\n // Right column background panel\n layers.push({\n type: 'shape',\n id: 'right-panel',\n content: {\n shape: 'rect',\n fill: 'rgba(255, 255, 255, 0.04)',\n },\n position: { x: '53%', y: '15%', width: '44%', height: '70%' },\n });\n }\n\n // Header position adjusts based on layout\n const headerY = isStacked ? '12%' : '22%';\n\n // Add header if provided\n if (header) {\n layers.push({\n type: 'text',\n id: 'header',\n content: {\n text: header,\n style: {\n fontSize: headerFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: headerY, anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n }\n\n // Calculate Y positions based on layout mode and header presence\n let leftY: string;\n let leftSublabelY: string;\n let rightY: string;\n let rightSublabelY: string;\n\n if (isStacked) {\n // Portrait: stacked vertically\n leftY = header ? '30%' : '25%';\n leftSublabelY = header ? '40%' : '35%';\n rightY = header ? '60%' : '55%';\n rightSublabelY = header ? '70%' : '65%';\n } else {\n // Landscape/square: side by side — vertically centered in panels (15%-85%)\n const baseY = header ? '47%' : '45%';\n const sublabelOffset = header ? '58%' : '56%';\n leftY = baseY;\n leftSublabelY = sublabelOffset;\n rightY = baseY;\n rightSublabelY = sublabelOffset;\n }\n\n // Left column (or top in portrait)\n layers.push({\n type: 'text',\n id: 'left-label',\n content: {\n text: left.label,\n style: {\n fontSize: labelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: leftColors.text,\n textAlign: 'center',\n lineHeight: 1.3,\n },\n },\n position: {\n x: positions.left.x,\n y: leftY,\n anchor: 'center',\n width: columnWidth,\n },\n animation: { type: 'fadeIn', duration: 1 },\n });\n\n if (left.sublabel) {\n layers.push({\n type: 'text',\n id: 'left-sublabel',\n content: {\n text: left.sublabel,\n style: {\n fontSize: sublabelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.4,\n },\n },\n position: {\n x: positions.left.x,\n y: leftSublabelY,\n anchor: 'center',\n width: columnWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.3 },\n });\n }\n\n // Visual connector between columns (bold arrow)\n const connectorFontSize = scaledFontSize(120, context, true);\n const connectorY = isStacked ? '48%' : '50%'; // Centered in viewport\n const connectorSymbol = isStacked ? '\\u2193' : '\\u2192'; // ↓ for stacked, → for side-by-side\n\n layers.push({\n type: 'text',\n id: 'connector',\n content: {\n text: connectorSymbol,\n style: {\n fontSize: connectorFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: 'rgba(255, 255, 255, 0.6)',\n textAlign: 'center',\n },\n },\n position: {\n x: '50%',\n y: connectorY,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.6, delay: 0.4 },\n });\n\n // Right column (or bottom in portrait)\n layers.push({\n type: 'text',\n id: 'right-label',\n content: {\n text: right.label,\n style: {\n fontSize: labelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: rightColors.text,\n textAlign: 'center',\n lineHeight: 1.3,\n },\n },\n position: {\n x: positions.right.x,\n y: rightY,\n anchor: 'center',\n width: columnWidth,\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.5 },\n });\n\n if (right.sublabel) {\n layers.push({\n type: 'text',\n id: 'right-sublabel',\n content: {\n text: right.sublabel,\n style: {\n fontSize: sublabelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.4,\n },\n },\n position: {\n x: positions.right.x,\n y: rightSublabelY,\n anchor: 'center',\n width: columnWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.8 },\n });\n }\n\n return layers;\n}\n","/**\n * Date Event Template\n *\n * Timeline-style slide with prominent date and description.\n * Supports different moods: neutral, somber, celebratory.\n * Adapts font sizes and positioning for different viewports.\n *\n * Supports optional accent images that appear as tasteful side/bottom strips.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { DateEventInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\n\nconst MOOD_COLORS = {\n neutral: { bg: '#1a202c', date: '#63b3ed', text: '#ffffff' },\n somber: { bg: '#1a1a2e', date: '#e53e3e', text: '#a0aec0' },\n celebratory: { bg: '#1a365d', date: '#68d391', text: '#ffffff' },\n};\n\nexport function dateEvent(input: DateEventInput, context: TemplateContext): Layer[] {\n const { date, description, footer, mood = 'neutral', accentImage } = input;\n const { theme } = context;\n const colors = MOOD_COLORS[mood];\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n // Scale font sizes — date is the hero element\n const dateFontSize = scaledFontSize(96, context, true);\n const descFontSize = scaledFontSize(30, context, false);\n const footerFontSize = scaledFontSize(26, context, false);\n\n const layers: Layer[] = [\n // Background — unique diagonal gradient to differentiate from other dark templates\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `linear-gradient(135deg, ${colors.bg} 0%, #0d1117 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Date — hero element, much larger\n layers.push({\n type: 'text',\n id: 'date',\n content: {\n text: date,\n style: {\n fontSize: dateFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: colors.date,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('35%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1.5 },\n });\n\n // Description - constrained width for proper text wrapping\n layers.push({\n type: 'text',\n id: 'description',\n content: {\n text: description,\n style: {\n fontSize: descFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: colors.text,\n textAlign: 'center',\n lineHeight: 1.8,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('58%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 2, delay: 1 },\n });\n\n // Add footer if provided\n if (footer) {\n layers.push({\n type: 'text',\n id: 'footer',\n content: {\n text: footer,\n style: {\n fontSize: footerFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('82%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 3 },\n });\n }\n\n return layers;\n}\n","/**\n * Image With Caption Template\n *\n * Full-screen background image with text overlay.\n * Supports Ken Burns animation effects (zoom, pan).\n * Adapts caption positioning and font sizes for different viewports.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { ImageWithCaptionInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { cleanCaption } from './captionUtils.js';\nimport { mapAmbientMotion } from './accentImage.js';\n\nexport function imageWithCaption(input: ImageWithCaptionInput, context: TemplateContext): Layer[] {\n const {\n imageSrc,\n imageAlt,\n caption: rawCaption,\n captionPosition: _captionPosition = 'bottom',\n ambientMotion,\n isTitle,\n subtitle,\n imageCredit,\n imageLicense,\n } = input;\n const caption = rawCaption ? cleanCaption(rawCaption) : rawCaption;\n const { theme, layout } = context;\n\n // Scale font sizes for viewport\n const captionFontSize = scaledFontSize(36, context, false);\n const titleFontSize = scaledFontSize(96, context, true);\n const subtitleFontSize = scaledFontSize(36, context, false);\n\n // Determine animation based on ambientMotion setting\n // Support both new 'ambientMotion' and legacy 'kenBurns' property\n const legacyKenBurns = (input as unknown as Record<string, unknown>).kenBurns as\n | string\n | undefined;\n const motion: string | undefined = ambientMotion || legacyKenBurns;\n const imageAnimation = mapAmbientMotion(motion);\n\n const layers: Layer[] = [\n // Background image\n {\n type: 'image',\n id: 'bg-image',\n content: {\n src: imageSrc,\n alt: imageAlt,\n fit: 'cover',\n credit: imageCredit,\n license: imageLicense,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: imageAnimation,\n },\n ];\n\n // TITLE MODE: Large centered title over hero image (like cover slide)\n if (isTitle && caption) {\n // Full gradient overlay for title readability (similar to cover slide)\n layers.push({\n type: 'shape',\n id: 'title-gradient',\n content: {\n shape: 'rect',\n fill: 'linear-gradient(0deg, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.4) 40%, rgba(0,0,0,0.1) 70%, transparent 100%)',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n });\n\n // Title text - large and centered in lower portion\n layers.push({\n type: 'text',\n id: 'title',\n content: {\n text: caption,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: subtitle ? '70%' : '75%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n\n // Optional subtitle\n if (subtitle) {\n layers.push({\n type: 'text',\n id: 'subtitle',\n content: {\n text: subtitle,\n style: {\n fontSize: subtitleFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.5,\n },\n },\n position: {\n x: '50%',\n y: '82%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.2 },\n });\n }\n\n return layers;\n }\n\n // STANDARD MODE: Caption at bottom\n if (caption) {\n // Subtle gradient at bottom for caption readability (raised above media controls)\n layers.push({\n type: 'shape',\n id: 'caption-gradient',\n content: {\n shape: 'rect',\n fill: 'linear-gradient(0deg, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 60%, transparent 100%)',\n },\n position: {\n x: 0,\n y: '65%',\n width: '100%',\n height: '35%',\n },\n });\n\n // Caption text - raised above media controls\n layers.push({\n type: 'text',\n id: 'caption',\n content: {\n text: caption,\n style: {\n fontSize: captionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '82%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1.5, delay: 0.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Map Block Template\n *\n * Full-screen geographic map with optional title and caption overlays.\n * Great for establishing geographic context at the start of a doc\n * or when discussing location-specific content.\n * Adapts font sizes and positioning for different viewports.\n *\n * Map tiles are fetched from free/open-source providers.\n * See docs/MAP_TILES.md for available styles and attribution requirements.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { MapBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { mapAmbientMotion } from './accentImage.js';\n\nexport function mapBlock(input: MapBlockInput, context: TemplateContext): Layer[] {\n const {\n center,\n zoom,\n mapStyle = 'terrain',\n title,\n caption,\n markers,\n ambientMotion,\n staticSrc,\n } = input;\n const { theme, layout } = context;\n\n // Scale font sizes for viewport\n const titleFontSize = scaledFontSize(64, context, true);\n const captionFontSize = scaledFontSize(32, context, false);\n\n // Determine animation based on ambientMotion setting\n const mapAnimation = mapAmbientMotion(ambientMotion);\n\n const layers: Layer[] = [\n // Map background\n {\n type: 'map',\n id: 'map-bg',\n content: {\n center,\n zoom,\n style: mapStyle,\n markers,\n showAttribution: true,\n staticSrc, // Use pre-rendered image if available\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: mapAnimation,\n },\n ];\n\n // Add title overlay if provided\n if (title) {\n // Gradient overlay at top for title readability\n layers.push({\n type: 'shape',\n id: 'title-overlay',\n content: {\n shape: 'rect',\n fill: 'rgba(0,0,0,0.6)',\n },\n position: { x: 0, y: 0, width: '100%', height: '18%' },\n });\n\n // Title text - positioned at top of slide\n layers.push({\n type: 'text',\n id: 'title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '9%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.3 },\n });\n }\n\n // Add caption if provided\n if (caption) {\n // Gradient overlay at bottom for caption readability\n layers.push({\n type: 'shape',\n id: 'caption-overlay',\n content: {\n shape: 'rect',\n fill: 'rgba(0,0,0,0.6)',\n },\n position: { x: 0, y: '82%', width: '100%', height: '18%' },\n });\n\n // Caption text\n layers.push({\n type: 'text',\n id: 'caption',\n content: {\n text: caption,\n style: {\n fontSize: captionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: layout.captionY,\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Full Bleed Quote Template\n *\n * Short dramatic text filling the viewport like a movie title card.\n * Designed for punchy text under 60 characters. Uses massive font\n * centered on a dark vignette background.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { FullBleedQuoteInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\n\nexport function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateContext): Layer[] {\n const { text, colorScheme = 'blue' } = input;\n const { theme } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Massive font for dramatic impact\n const textFontSize = scaledFontSize(120, context, true);\n\n return [\n // Background — dark radial vignette for cinematic feel\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 50%, ${theme.colors.backgroundLight} 0%, #000000 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n // The text — massive, centered\n {\n type: 'text',\n id: 'impact-text',\n content: {\n text,\n style: {\n fontSize: textFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: colors.text,\n textAlign: 'center',\n lineHeight: 1.2,\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '50%',\n anchor: 'center',\n width: '85%',\n },\n animation: { type: 'fadeIn', duration: 1.5 },\n },\n ];\n}\n","/**\n * List Block Template\n *\n * Displays 3-5 items in a numbered vertical list with staggered animations.\n * Good for enumerations like \"things to see\", \"key features\", or \"tips\".\n * Supports optional accent images.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { ListBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\n\nexport function listBlock(input: ListBlockInput, context: TemplateContext): Layer[] {\n const { items, title, accentImage } = input;\n const { theme } = context;\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n const titleFontSize = scaledFontSize(44, context, true);\n const itemFontSize = scaledFontSize(34, context, false);\n\n const layers: Layer[] = [\n // Background — gradient\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `linear-gradient(155deg, ${theme.colors.backgroundLight} 0%, ${theme.colors.background} 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n // Add accent image layers\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Title if provided\n const startY = title ? 30 : 22;\n if (title) {\n layers.push({\n type: 'text',\n id: 'list-title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('16%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1 },\n });\n }\n\n // Calculate vertical spacing for items\n const endY = 80;\n const spacing = items.length > 1 ? (endY - startY) / (items.length - 1) : 0;\n\n // List items with staggered animation\n for (let i = 0; i < items.length; i++) {\n const y = startY + spacing * i;\n const itemText = `${i + 1}. ${items[i]}`;\n\n layers.push({\n type: 'text',\n id: `item-${i}`,\n content: {\n text: itemText,\n style: {\n fontSize: itemFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n lineHeight: 1.4,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${y}%`, accentLayout),\n anchor: 'center',\n width: accentLayout.textWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.3 + 0.3 * i },\n });\n }\n\n return layers;\n}\n","/**\n * Photo Grid Template\n *\n * Displays 2-4 images in a tiled layout for visual variety.\n * Layout adapts based on image count and viewport orientation:\n *\n * Landscape:\n * - 2 images: side-by-side 50/50\n * - 3 images: one large left (60%) + two stacked right\n * - 4 images: 2x2 grid\n *\n * Portrait (9:16): images stack horizontally (top/bottom) instead of\n * side-by-side, giving each image full width on narrow screens.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { PhotoGridInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { cleanCaption } from './captionUtils.js';\n\n/** Gap between images as percentage */\nconst GAP = 0.5;\n\nexport function photoGrid(input: PhotoGridInput, context: TemplateContext): Layer[] {\n const { images, caption: rawCaption, ambientMotion } = input;\n\n // Guard: images array is required\n if (!images || images.length === 0) return [];\n\n const caption = rawCaption ? cleanCaption(rawCaption) : rawCaption;\n const { theme, layout } = context;\n\n const layers: Layer[] = [\n // Black background (visible in gaps between images)\n {\n type: 'shape',\n id: 'bg',\n content: { shape: 'rect', fill: '#000000' },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n // Reserve bottom space for caption — more room in landscape for larger text\n const captionHeight = caption ? (layout.stackColumns ? 18 : 22) : 0;\n const gridHeight = 100 - captionHeight;\n\n // Generate image positions based on count; stack vertically in portrait\n const positions = getGridPositions(images.length, gridHeight, layout.stackColumns);\n\n const altFontSize = scaledFontSize(24, context, false);\n\n for (let i = 0; i < Math.min(images.length, 4); i++) {\n const img = images[i];\n const pos = positions[i];\n\n // Placeholder behind image (visible if image fails to load)\n layers.push({\n type: 'shape',\n id: `grid-placeholder-${i}`,\n content: { shape: 'rect', fill: theme.colors.background },\n position: { x: `${pos.x}%`, y: `${pos.y}%`, width: `${pos.w}%`, height: `${pos.h}%` },\n });\n\n // Alt-text label on placeholder\n if (img.alt) {\n layers.push({\n type: 'text',\n id: `grid-alt-${i}`,\n content: {\n text: img.alt,\n style: {\n fontSize: altFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center' as const,\n },\n },\n position: { x: `${pos.x + pos.w / 2}%`, y: `${pos.y + pos.h / 2}%`, anchor: 'center' },\n });\n }\n\n // Image layer (covers placeholder when loaded)\n layers.push({\n type: 'image',\n id: `grid-img-${i}`,\n content: {\n src: img.src,\n alt: img.alt,\n fit: 'cover',\n credit: img.credit,\n license: img.license,\n },\n position: {\n x: `${pos.x}%`,\n y: `${pos.y}%`,\n width: `${pos.w}%`,\n height: `${pos.h}%`,\n },\n // Apply ambient motion to the first (largest) image only\n animation:\n i === 0 && ambientMotion\n ? { type: ambientMotion, duration: 15 }\n : { type: 'fadeIn', duration: 1, delay: 0.2 * i },\n });\n }\n\n // Caption with gradient overlay\n if (caption) {\n const captionFontSize = scaledFontSize(layout.stackColumns ? 28 : 40, context, false);\n\n layers.push({\n type: 'shape',\n id: 'caption-bg',\n content: {\n shape: 'rect',\n fill: 'linear-gradient(transparent, rgba(0,0,0,0.8))',\n },\n position: { x: 0, y: `${gridHeight - 4}%`, width: '100%', height: `${captionHeight + 4}%` },\n });\n\n layers.push({\n type: 'text',\n id: 'caption',\n content: {\n text: caption,\n style: {\n fontSize: captionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: `${gridHeight + (layout.stackColumns ? captionHeight / 2 : captionHeight * 0.3)}%`,\n anchor: 'center',\n width: '90%',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.5 },\n });\n }\n\n return layers;\n}\n\ninterface GridPos {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nfunction getGridPositions(count: number, gridHeight: number, stacked: boolean): GridPos[] {\n const halfW = 50 - GAP / 2;\n const halfH = gridHeight / 2 - GAP / 2;\n\n switch (count) {\n case 2:\n if (stacked) {\n // Portrait: stack top/bottom\n return [\n { x: 0, y: 0, w: 100, h: halfH },\n { x: 0, y: gridHeight / 2 + GAP / 2, w: 100, h: halfH },\n ];\n }\n return [\n { x: 0, y: 0, w: halfW, h: gridHeight },\n { x: 50 + GAP / 2, y: 0, w: halfW, h: gridHeight },\n ];\n case 3: {\n if (stacked) {\n // Portrait: stack all three vertically\n const thirdH = gridHeight / 3 - (GAP * 2) / 3;\n return [\n { x: 0, y: 0, w: 100, h: thirdH },\n { x: 0, y: gridHeight / 3 + GAP / 3, w: 100, h: thirdH },\n { x: 0, y: (gridHeight * 2) / 3 + (GAP * 2) / 3, w: 100, h: thirdH },\n ];\n }\n const leftW = 60 - GAP / 2;\n const rightW = 40 - GAP / 2;\n return [\n { x: 0, y: 0, w: leftW, h: gridHeight },\n { x: 60 + GAP / 2, y: 0, w: rightW, h: halfH },\n { x: 60 + GAP / 2, y: gridHeight / 2 + GAP / 2, w: rightW, h: halfH },\n ];\n }\n case 4:\n default:\n // 2x2 grid works well in both orientations\n return [\n { x: 0, y: 0, w: halfW, h: halfH },\n { x: 50 + GAP / 2, y: 0, w: halfW, h: halfH },\n { x: 0, y: gridHeight / 2 + GAP / 2, w: halfW, h: halfH },\n { x: 50 + GAP / 2, y: gridHeight / 2 + GAP / 2, w: halfW, h: halfH },\n ];\n }\n}\n","/**\n * Definition Card Template\n *\n * Dictionary-style slide with a large term and its definition.\n * Good for explaining local words, place names, or cultural concepts.\n * Supports optional accent images.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { DefinitionCardInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\nexport function definitionCard(input: DefinitionCardInput, context: TemplateContext): Layer[] {\n const { term, definition, origin, colorScheme = 'blue', accentImage } = input;\n const { theme } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Get layout adjustments if accent image is present\n const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;\n\n const termFontSize = scaledFontSize(72, context, true);\n const defFontSize = scaledFontSize(32, context, false);\n const originFontSize = scaledFontSize(22, context, false);\n\n const layers: Layer[] = [\n createBackgroundLayer(\n 'bg',\n `linear-gradient(145deg, #1e2030 0%, ${theme.colors.background} 100%)`,\n ),\n ];\n\n // Add accent image layers\n if (accentImage) {\n layers.push(...createAccentLayers(accentImage, input.id));\n }\n\n // Term — large, accent-colored\n layers.push({\n type: 'text',\n id: 'term',\n content: {\n text: term,\n style: {\n fontSize: termFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: colors.text,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('30%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1.5 },\n });\n\n // Horizontal separator line\n layers.push({\n type: 'shape',\n id: 'separator',\n content: {\n shape: 'rect',\n fill: `${colors.text}33`, // accent color at 20% opacity\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('42%', accentLayout),\n width: '30%',\n height: '2px',\n anchor: 'center',\n },\n });\n\n // Definition text\n layers.push({\n type: 'text',\n id: 'definition',\n content: {\n text: definition,\n style: {\n fontSize: defFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n textAlign: 'center',\n lineHeight: 1.6,\n maxLines: 4,\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('55%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.8 },\n });\n\n // Origin if provided\n if (origin) {\n layers.push({\n type: 'text',\n id: 'origin',\n content: {\n text: origin,\n style: {\n fontSize: originFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n shadow: !!accentImage,\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('78%', accentLayout),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 1.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Comparison Bar Template\n *\n * Two horizontal bars showing relative numeric values side by side.\n * Bar widths are proportional to the values for immediate visual comparison.\n * Good for population, distance, or measurement comparisons.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { ComparisonBarInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont } from '../utils/themeUtils.js';\n\nexport function comparisonBar(input: ComparisonBarInput, context: TemplateContext): Layer[] {\n const { leftLabel, leftValue, rightLabel, rightValue, unit, colorScheme = 'blue' } = input;\n const { theme } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n const labelFontSize = scaledFontSize(28, context, false);\n const valueFontSize = scaledFontSize(48, context, true);\n\n // Calculate proportional bar widths (max bar = 65% of viewport width)\n const maxValue = Math.max(leftValue, rightValue, 1);\n const maxBarWidth = 65;\n const leftBarWidth = (leftValue / maxValue) * maxBarWidth;\n const rightBarWidth = (rightValue / maxValue) * maxBarWidth;\n\n // Bar positioning\n const barStartX = 15;\n const barHeight = 6; // % of viewport height\n const topBarY = 36;\n const bottomBarY = 58;\n\n // Format values for display\n const formatValue = (v: number): string => {\n if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`;\n if (v >= 1_000) return `${(v / 1_000).toFixed(v >= 10_000 ? 0 : 1)}K`;\n return v.toLocaleString();\n };\n\n const leftDisplay = unit ? `${formatValue(leftValue)} ${unit}` : formatValue(leftValue);\n const rightDisplay = unit ? `${formatValue(rightValue)} ${unit}` : formatValue(rightValue);\n\n return [\n // Background\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `linear-gradient(180deg, ${theme.colors.background} 0%, #0f1520 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n\n // Top bar label\n {\n type: 'text',\n id: 'left-label',\n content: {\n text: leftLabel,\n style: {\n fontSize: labelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n },\n },\n position: { x: `${barStartX}%`, y: `${topBarY - 8}%` },\n },\n\n // Top bar value\n {\n type: 'text',\n id: 'left-value',\n content: {\n text: leftDisplay,\n style: {\n fontSize: valueFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: colors.text,\n },\n },\n position: { x: `${barStartX + leftBarWidth + 2}%`, y: `${topBarY - 1}%` },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.3 },\n },\n\n // Top bar\n {\n type: 'shape',\n id: 'left-bar',\n content: {\n shape: 'rect',\n fill: colors.text,\n borderRadius: 4,\n },\n position: {\n x: `${barStartX}%`,\n y: `${topBarY}%`,\n width: `${leftBarWidth}%`,\n height: `${barHeight}%`,\n },\n animation: { type: 'fadeIn', duration: 1 },\n },\n\n // Bottom bar label\n {\n type: 'text',\n id: 'right-label',\n content: {\n text: rightLabel,\n style: {\n fontSize: labelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n },\n },\n position: { x: `${barStartX}%`, y: `${bottomBarY - 8}%` },\n },\n\n // Bottom bar value\n {\n type: 'text',\n id: 'right-value',\n content: {\n text: rightDisplay,\n style: {\n fontSize: valueFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: colors.accent,\n },\n },\n position: { x: `${barStartX + rightBarWidth + 2}%`, y: `${bottomBarY - 1}%` },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.6 },\n },\n\n // Bottom bar\n {\n type: 'shape',\n id: 'right-bar',\n content: {\n shape: 'rect',\n fill: colors.accent,\n borderRadius: 4,\n },\n position: {\n x: `${barStartX}%`,\n y: `${bottomBarY}%`,\n width: `${rightBarWidth}%`,\n height: `${barHeight}%`,\n },\n animation: { type: 'fadeIn', duration: 1, delay: 0.3 },\n },\n ];\n}\n","/**\n * Pull Quote Template\n *\n * Quote text over a full-bleed background image with dark overlay.\n * Cinematic alternative to quoteBlock when a high-quality image is available.\n * Combines the visual impact of imageWithCaption with the text focus of quoteBlock.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { PullQuoteInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\n\nexport function pullQuote(input: PullQuoteInput, context: TemplateContext): Layer[] {\n const { text, attribution, backgroundImage, ambientMotion } = input;\n\n // Guard: backgroundImage is required\n if (!backgroundImage?.src) return [];\n\n const quoteFontSize = scaledFontSize(52, context, true);\n const attrFontSize = scaledFontSize(24, context, false);\n const decoFontSize = scaledFontSize(200, context, true);\n\n const layers: Layer[] = [\n // Full-bleed background image\n {\n type: 'image',\n id: 'bg-image',\n content: {\n src: backgroundImage.src,\n alt: backgroundImage.alt,\n fit: 'cover',\n credit: backgroundImage.credit,\n license: backgroundImage.license,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: ambientMotion ? { type: ambientMotion, duration: 15 } : undefined,\n },\n\n // Dark overlay for text readability\n {\n type: 'shape',\n id: 'overlay',\n content: {\n shape: 'rect',\n fill: 'rgba(0, 0, 0, 0.55)',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n\n // Decorative quotation mark\n {\n type: 'text',\n id: 'deco-quote',\n content: {\n text: '\\u201C',\n style: {\n fontSize: decoFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: 'rgba(255, 255, 255, 0.08)',\n textAlign: 'center',\n },\n },\n position: {\n x: '50%',\n y: '20%',\n anchor: 'center',\n },\n },\n\n // Quote text\n {\n type: 'text',\n id: 'quote-text',\n content: {\n text,\n style: {\n fontSize: quoteFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: '#ffffff',\n textAlign: 'center',\n lineHeight: 1.5,\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: attribution ? '45%' : '50%',\n anchor: 'center',\n width: '80%',\n },\n animation: { type: 'fadeIn', duration: 2 },\n },\n ];\n\n // Attribution\n if (attribution) {\n layers.push({\n type: 'text',\n id: 'attribution',\n content: {\n text: `\\u2014 ${attribution}`,\n style: {\n fontSize: attrFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: 'rgba(255, 255, 255, 0.7)',\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '72%',\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 1.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Video With Caption Template\n *\n * Full-screen background video clip with text overlay. Mirrors the structure of\n * imageWithCaption but uses a VideoLayer instead of an ImageLayer. The video\n * plays muted — narration audio is the only sound track.\n *\n * Adapts caption positioning and font sizes for different viewports.\n *\n * This is shared code used by both site and efb-app doc renderers.\n *\n * Related Files:\n * - shared/story/templates/imageWithCaption.ts — image equivalent\n * - schemas/StoryScript.ts — VideoLayer type\n * - site/src/components/story/layers/VideoLayer.tsx — rendering component\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { VideoWithCaptionInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { cleanCaption } from './captionUtils.js';\n\nexport function videoWithCaption(input: VideoWithCaptionInput, context: TemplateContext): Layer[] {\n const {\n videoSrc,\n posterSrc,\n videoAlt,\n clipStart,\n clipEnd,\n sourceDuration,\n caption: rawCaption,\n captionPosition = 'bottom',\n videoCredit,\n videoLicense,\n } = input;\n const caption = rawCaption ? cleanCaption(rawCaption) : rawCaption;\n const { theme, layout } = context;\n\n const captionFontSize = scaledFontSize(36, context, false);\n const creditFontSize = scaledFontSize(16, context, false);\n\n const layers: Layer[] = [\n // Background video clip\n {\n type: 'video',\n id: 'bg-video',\n content: {\n src: videoSrc,\n posterSrc,\n alt: videoAlt,\n fit: 'cover',\n clipStart,\n clipEnd,\n sourceDuration,\n credit: videoCredit,\n license: videoLicense,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n // Caption text at bottom with gradient for readability\n if (caption) {\n layers.push({\n type: 'shape',\n id: 'caption-gradient',\n content: {\n shape: 'rect',\n fill: 'linear-gradient(0deg, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 60%, transparent 100%)',\n },\n position: {\n x: 0,\n y: captionPosition === 'top' ? 0 : '65%',\n width: '100%',\n height: '35%',\n },\n });\n\n const captionY =\n captionPosition === 'top' ? '15%' : captionPosition === 'center' ? '50%' : '82%';\n\n layers.push({\n type: 'text',\n id: 'caption',\n content: {\n text: caption,\n style: {\n fontSize: captionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: captionY,\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 1.5, delay: 0.5 },\n });\n }\n\n // Small credit text in bottom-right corner\n if (videoCredit) {\n layers.push({\n type: 'text',\n id: 'credit',\n content: {\n text: videoCredit,\n style: {\n fontSize: creditFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: 'rgba(255, 255, 255, 0.5)',\n textAlign: 'right',\n },\n },\n position: {\n x: '96%',\n y: '96%',\n anchor: 'bottom-right',\n },\n });\n }\n\n return layers;\n}\n","/**\n * Video Pull Quote Template\n *\n * Quote text over a video clip background with dark overlay.\n * Cinematic alternative to pullQuote when a video clip is available.\n * Combines the visual dynamism of live video with the text focus of quoteBlock.\n *\n * The video plays muted — narration audio is the only sound track.\n *\n * This is shared code used by both site and efb-app doc renderers.\n *\n * Related Files:\n * - shared/story/templates/pullQuote.ts — image-based equivalent\n * - schemas/StoryScript.ts — VideoLayer type\n * - site/src/components/story/layers/VideoLayer.tsx — rendering component\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { VideoPullQuoteInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\n\nexport function videoPullQuote(input: VideoPullQuoteInput, context: TemplateContext): Layer[] {\n const { text, attribution, backgroundVideo } = input;\n\n // Guard: backgroundVideo is required\n if (!backgroundVideo?.src) return [];\n\n const quoteFontSize = scaledFontSize(52, context, true);\n const attrFontSize = scaledFontSize(24, context, false);\n const decoFontSize = scaledFontSize(200, context, true);\n\n const layers: Layer[] = [\n // Full-bleed background video clip\n {\n type: 'video',\n id: 'bg-video',\n content: {\n src: backgroundVideo.src,\n posterSrc: backgroundVideo.posterSrc,\n alt: backgroundVideo.alt,\n fit: 'cover',\n clipStart: backgroundVideo.clipStart,\n clipEnd: backgroundVideo.clipEnd,\n credit: backgroundVideo.credit,\n license: backgroundVideo.license,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n\n // Dark overlay for text readability\n {\n type: 'shape',\n id: 'overlay',\n content: {\n shape: 'rect',\n fill: 'rgba(0, 0, 0, 0.55)',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n\n // Decorative quotation mark\n {\n type: 'text',\n id: 'deco-quote',\n content: {\n text: '\\u201C',\n style: {\n fontSize: decoFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: 'rgba(255, 255, 255, 0.08)',\n textAlign: 'center',\n },\n },\n position: {\n x: '50%',\n y: '20%',\n anchor: 'center',\n },\n },\n\n // Quote text\n {\n type: 'text',\n id: 'quote-text',\n content: {\n text,\n style: {\n fontSize: quoteFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: '#ffffff',\n textAlign: 'center',\n lineHeight: 1.5,\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: attribution ? '45%' : '50%',\n anchor: 'center',\n width: '80%',\n },\n animation: { type: 'fadeIn', duration: 2 },\n },\n ];\n\n // Attribution\n if (attribution) {\n layers.push({\n type: 'text',\n id: 'attribution',\n content: {\n text: `\\u2014 ${attribution}`,\n style: {\n fontSize: attrFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: 'rgba(255, 255, 255, 0.7)',\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: '72%',\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 1, delay: 1.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Data Table Template\n *\n * Renders a themed table with header row and data rows.\n * Uses a TableLayer (foreignObject-based HTML table inside SVG)\n * for proper table layout within the viewport.\n *\n * Adapts font sizes for different viewports and uses theme colors\n * for header background, text, borders, and body cells.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { DataTableInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont, resolveColorScheme } from '../utils/themeUtils.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\nexport function dataTable(input: DataTableInput, context: TemplateContext): Layer[] {\n const { title, headers, rows, align, colorScheme } = input;\n const { theme } = context;\n\n const colors = resolveColorScheme(context, colorScheme);\n const titleFontSize = scaledFontSize(48, context, true);\n const tableFontSize = scaledFontSize(28, context, false);\n\n const layers: Layer[] = [\n createBackgroundLayer(\n 'bg',\n `linear-gradient(170deg, ${theme.colors.background} 0%, #0f1520 100%)`,\n ),\n ];\n\n // Optional title above the table\n if (title) {\n layers.push({\n type: 'text',\n id: 'title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: { x: '50%', y: '10%', width: '80%', anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n }\n\n // Table layer\n layers.push({\n type: 'table',\n id: 'table',\n content: {\n headers,\n rows,\n align,\n style: {\n headerBackground: colors.accent,\n headerColor: colors.text,\n cellBackground: 'rgba(255,255,255,0.05)',\n cellColor: theme.colors.text,\n borderColor: 'rgba(255,255,255,0.12)',\n fontSize: tableFontSize,\n fontFamily: getThemeFont(context, 'body'),\n headerFontFamily: getThemeFont(context, 'title'),\n borderRadius: 8,\n },\n },\n position: {\n x: '10%',\n y: title ? '18%' : '8%',\n width: '80%',\n height: title ? '74%' : '84%',\n },\n animation: { type: 'fadeIn', duration: 1, delay: title ? 0.4 : 0 },\n });\n\n return layers;\n}\n","/**\n * Cover Block Template\n *\n * Full-screen hero image with title overlay, shown before playback starts.\n * This is the \"poster for the doc, displaying the\n * article's hero image with elegant title treatment.\n *\n * Features:\n * - Full-screen hero image with Ken Burns ambient motion\n * - Gradient overlay for text readability\n * - Large centered title with optional subtitle\n * - No animation delays (shown at rest, not during playback)\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport type { StartBlockConfig } from '../../schemas/Doc.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { mapAmbientMotion } from './accentImage.js';\n\n/**\n * Input for coverBlock template - matches StartBlockConfig\n */\nexport interface CoverBlockInput {\n /** Path to hero image (omit for theme-driven background) */\n heroSrc?: string;\n /** Alt text for the hero image */\n heroAlt?: string;\n /** Title to display over the hero */\n title: string;\n /** Optional subtitle */\n subtitle?: string;\n /** Ambient motion for the hero image */\n ambientMotion?: 'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight';\n /** Photo credit / artist name */\n heroCredit?: string;\n /** License identifier */\n heroLicense?: string;\n}\n\n/**\n * Generate cover block layers from StartBlockConfig.\n */\nexport function coverBlock(input: CoverBlockInput, context: TemplateContext): Layer[] {\n const { heroSrc, heroAlt, title, subtitle, ambientMotion, heroCredit, heroLicense } = input;\n const { theme, layout } = context;\n\n // Scale font sizes for viewport - cover titles are larger than regular title blocks\n const titleFontSize = scaledFontSize(120, context, true);\n const subtitleFontSize = scaledFontSize(40, context, false);\n\n const layers: Layer[] = [];\n\n if (heroSrc) {\n // Hero image path: full-screen image with gradient overlay for text readability\n const imageAnimation = mapAmbientMotion(ambientMotion);\n\n layers.push(\n {\n type: 'image',\n id: 'cover-hero',\n content: {\n src: heroSrc,\n alt: heroAlt || title,\n fit: 'cover',\n credit: heroCredit,\n license: heroLicense,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: imageAnimation,\n },\n {\n type: 'shape',\n id: 'cover-gradient',\n content: {\n shape: 'rect',\n fill: 'linear-gradient(0deg, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0.4) 40%, rgba(0,0,0,0.1) 70%, transparent 100%)',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n );\n } else {\n // No hero image: use a rich theme-driven background with radial gradient\n layers.push({\n type: 'shape',\n id: 'cover-bg',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 40%, ${theme.colors.primary} 0%, ${theme.colors.background} 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n });\n\n // Subtle decorative accent line below title\n layers.push({\n type: 'shape',\n id: 'cover-accent',\n content: {\n shape: 'rect',\n fill: 'rgba(255, 255, 255, 0.2)',\n },\n position: {\n x: '35%',\n y: subtitle ? '42%' : '58%',\n width: '30%',\n height: '2px',\n },\n });\n }\n\n // Title - positioned lower when over hero, centered when over solid background\n layers.push({\n type: 'text',\n id: 'cover-title',\n content: {\n text: title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: heroSrc ? (subtitle ? '70%' : '75%') : subtitle ? layout.primaryY : '50%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n // No animation delay - shown immediately at rest\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n\n // Add subtitle if provided\n if (subtitle) {\n layers.push({\n type: 'text',\n id: 'cover-subtitle',\n content: {\n text: subtitle,\n style: {\n fontSize: subtitleFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: 1.5,\n },\n },\n position: {\n x: '50%',\n y: heroSrc ? '82%' : layout.secondaryY,\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: { type: 'fadeIn', duration: 0.8, delay: 0.2 },\n });\n }\n\n return layers;\n}\n\n/**\n * Convert StartBlockConfig to CoverBlockInput.\n */\nexport function startBlockToCoverInput(config: StartBlockConfig): CoverBlockInput {\n return {\n heroSrc: config.heroSrc,\n heroAlt: config.heroAlt,\n title: config.title,\n subtitle: config.subtitle,\n ambientMotion: config.ambientMotion,\n heroCredit: config.heroCredit,\n heroLicense: config.heroLicense,\n };\n}\n\n/**\n * Expand a StartBlockConfig into a renderable Block.\n * This is used by the player to render the cover block at rest.\n */\nexport function expandCoverBlock(config: StartBlockConfig, context: TemplateContext): Layer[] {\n const input = startBlockToCoverInput(config);\n return coverBlock(input, context);\n}\n","/**\n * Block Template Registry\n *\n * Central registry of all block templates. Provides functions to:\n * - Look up templates by name\n * - Expand template blocks into full Layer arrays\n * - Convert a template-based doc script into a renderable format\n *\n * Supports multiple viewport configurations for different aspect ratios.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Block, Layer } from '../../schemas/Doc.js';\nimport type {\n TemplateBlock,\n TemplateContext,\n TemplateRegistry,\n DocBlock,\n PersistentLayerConfig,\n} from '../../schemas/BlockTemplates.js';\nimport type { Theme } from '../../schemas/Theme.js';\nimport { isTemplateBlock, createTemplateContext } from '../../schemas/BlockTemplates.js';\nimport { DEFAULT_THEME as defaultTheme } from '../../schemas/themeLibrary.js';\nimport { expandPersistentLayers } from './persistentLayers.js';\nimport type { ViewportConfig } from '../../schemas/Viewport.js';\nimport { VIEWPORT_PRESETS } from '../../schemas/Viewport.js';\n\n// Import all template functions\nimport { titleBlock } from './titleBlock.js';\nimport { sectionHeader } from './sectionHeader.js';\nimport { statHighlight } from './statHighlight.js';\nimport { quoteBlock } from './quoteBlock.js';\nimport { factCard } from './factCard.js';\nimport { twoColumn } from './twoColumn.js';\nimport { dateEvent } from './dateEvent.js';\nimport { imageWithCaption } from './imageWithCaption.js';\nimport { mapBlock } from './mapBlock.js';\nimport { fullBleedQuote } from './fullBleedQuote.js';\nimport { listBlock } from './listBlock.js';\nimport { photoGrid } from './photoGrid.js';\nimport { definitionCard } from './definitionCard.js';\nimport { comparisonBar } from './comparisonBar.js';\nimport { pullQuote } from './pullQuote.js';\nimport { videoWithCaption } from './videoWithCaption.js';\nimport { videoPullQuote } from './videoPullQuote.js';\nimport { dataTable } from './dataTable.js';\n\n/**\n * Registry mapping template names to their implementation functions.\n * Note: coverBlock is not in the registry as it's used directly for start blocks,\n * not as a regular template in the block sequence.\n */\nexport const templateRegistry: TemplateRegistry = {\n titleBlock,\n sectionHeader,\n statHighlight,\n quoteBlock,\n factCard,\n twoColumn,\n dateEvent,\n imageWithCaption,\n mapBlock,\n fullBleedQuote,\n listBlock,\n photoGrid,\n definitionCard,\n comparisonBar,\n pullQuote,\n videoWithCaption,\n videoPullQuote,\n dataTable,\n};\n\n/**\n * Expand a template block into a full Block with layers.\n */\nexport function expandTemplateBlock(templateBlock: TemplateBlock, context: TemplateContext): Block {\n const templateFn = templateRegistry[templateBlock.template];\n\n if (!templateFn) {\n console.warn(`Unknown template: ${templateBlock.template}`);\n // Return block with no layers\n return {\n id: templateBlock.id,\n startTime: 0,\n duration: templateBlock.duration,\n audioSegment: templateBlock.audioSegment,\n transition: templateBlock.transition,\n template: templateBlock.template, // Preserve for debugging\n };\n }\n\n // Generate layers from template with error handling\n let layers: Layer[];\n try {\n // Each registry entry accepts its specific TemplateBlock variant; the\n // discriminated union guarantees the shapes match at runtime.\n layers = (templateFn as (input: TemplateBlock, ctx: TemplateContext) => Layer[])(\n templateBlock,\n context,\n );\n if (!Array.isArray(layers)) {\n console.error(\n `Template ${templateBlock.template} did not return an array, got:`,\n typeof layers,\n );\n layers = [];\n }\n } catch (err: unknown) {\n console.error(`Error expanding template ${templateBlock.template}:`, err);\n layers = [];\n }\n\n return {\n id: templateBlock.id,\n startTime: 0, // Will be calculated later\n duration: templateBlock.duration,\n audioSegment: templateBlock.audioSegment,\n ...(layers.length > 0 ? { layers } : {}),\n transition: templateBlock.transition,\n template: templateBlock.template, // Preserve for debugging\n };\n}\n\n/**\n * Audio segment timing info for aligning blocks with audio.\n */\nexport interface AudioSegmentTiming {\n /** Start time of this segment in the overall timeline */\n startTime: number;\n /** Duration of this segment */\n duration: number;\n}\n\n/**\n * Options for expanding doc blocks.\n */\nexport interface ExpandDocBlocksOptions {\n /** Theme for template rendering (defaults to DEFAULT_THEME) */\n theme?: Theme;\n /** Viewport configuration (defaults to 16:9 landscape) */\n viewport?: ViewportConfig;\n /** Persistent layers for visual consistency across blocks */\n persistentLayers?: PersistentLayerConfig;\n /**\n * Audio segment timing information.\n * When provided, blocks are timed relative to their audio segment's start time,\n * ensuring proper synchronization with audio playback.\n */\n audioSegments?: AudioSegmentTiming[];\n}\n\n/**\n * Expand all template blocks in a doc, calculating start times.\n * Injects persistent layers (bottom/top) based on per-block flags.\n *\n * When audioSegments is provided, blocks are timed relative to their audio segment's\n * start time, ensuring blocks appear when their audio is playing. Blocks within each\n * segment are distributed proportionally across the segment duration.\n *\n * @param blocks - Array of template or raw blocks\n * @param options - Expansion options including theme, viewport, and persistent layers\n */\nexport function expandDocBlocks(blocks: DocBlock[], options: ExpandDocBlocksOptions = {}): Block[] {\n const opts: ExpandDocBlocksOptions = options;\n\n const theme = opts.theme ?? defaultTheme;\n const viewport = opts.viewport ?? VIEWPORT_PRESETS.landscape;\n const { persistentLayers, audioSegments } = opts;\n const totalBlocks = blocks.length;\n\n // Pre-expand persistent layers once\n const bottomLayers = expandPersistentLayers(persistentLayers?.bottomLayers);\n const topLayers = expandPersistentLayers(persistentLayers?.topLayers);\n\n // If no audio segments provided, use simple cumulative timing\n if (!audioSegments || audioSegments.length === 0) {\n let currentTime = 0;\n return blocks.map((block, index) => {\n const context = createTemplateContext(theme, index, totalBlocks, viewport);\n const expandedBlock = isTemplateBlock(block)\n ? expandTemplateBlock(block, context)\n : (block as Block);\n\n // Inject persistent layers\n const templateBlock = block as TemplateBlock;\n const useBottom = templateBlock.useBottomLayer !== false;\n const useTop = templateBlock.useTopLayer !== false;\n if (bottomLayers.length > 0 || topLayers.length > 0) {\n expandedBlock.layers = [\n ...(useBottom ? bottomLayers : []),\n ...(expandedBlock.layers ?? []),\n ...(useTop ? topLayers : []),\n ];\n }\n\n expandedBlock.startTime = currentTime;\n currentTime += expandedBlock.duration;\n return expandedBlock;\n });\n }\n\n // Group blocks by their audioSegment index\n const blocksBySegment = new Map<number, { block: DocBlock; originalIndex: number }[]>();\n blocks.forEach((block, index) => {\n const segmentIndex = (block as TemplateBlock).audioSegment ?? 0;\n if (!blocksBySegment.has(segmentIndex)) {\n blocksBySegment.set(segmentIndex, []);\n }\n blocksBySegment.get(segmentIndex)!.push({ block, originalIndex: index });\n });\n\n // Expand blocks, timing them relative to their audio segment\n const expandedBlocks: Block[] = new Array(blocks.length);\n\n for (const [segmentIndex, segmentBlocks] of blocksBySegment) {\n const audioSegment = audioSegments[segmentIndex];\n if (!audioSegment) {\n // No audio segment info - use simple sequential timing within the segment\n let offsetTime = 0;\n for (const { block, originalIndex } of segmentBlocks) {\n const context = createTemplateContext(theme, originalIndex, totalBlocks, viewport);\n const expandedBlock = isTemplateBlock(block)\n ? expandTemplateBlock(block, context)\n : (block as Block);\n\n const templateBlock = block as TemplateBlock;\n const useBottom = templateBlock.useBottomLayer !== false;\n const useTop = templateBlock.useTopLayer !== false;\n if (bottomLayers.length > 0 || topLayers.length > 0) {\n expandedBlock.layers = [\n ...(useBottom ? bottomLayers : []),\n ...(expandedBlock.layers ?? []),\n ...(useTop ? topLayers : []),\n ];\n }\n\n expandedBlock.startTime = offsetTime;\n offsetTime += expandedBlock.duration;\n expandedBlocks[originalIndex] = expandedBlock;\n }\n continue;\n }\n\n // Section headers (sectionHeader template) get their original duration since\n // the title is spoken at the start of the segment. Other blocks are scaled\n // to fill the remaining time.\n const sectionHeaderBlocks: typeof segmentBlocks = [];\n const contentBlocks: typeof segmentBlocks = [];\n\n for (const item of segmentBlocks) {\n const templateBlock = item.block as TemplateBlock;\n if (templateBlock.template === 'sectionHeader') {\n sectionHeaderBlocks.push(item);\n } else {\n contentBlocks.push(item);\n }\n }\n\n // Calculate fixed duration (section headers) and scalable duration (content)\n const fixedDuration = sectionHeaderBlocks.reduce((sum, { block }) => {\n return sum + ((block as TemplateBlock).duration ?? 0);\n }, 0);\n\n const contentBlockDuration = contentBlocks.reduce((sum, { block }) => {\n return sum + ((block as TemplateBlock).duration ?? 0);\n }, 0);\n\n // Remaining time after section header(s) for content blocks\n const remainingDuration = audioSegment.duration - fixedDuration;\n\n // Scale factor only applies to content blocks\n const scaleFactor =\n contentBlockDuration > 0 && remainingDuration > 0\n ? remainingDuration / contentBlockDuration\n : 1;\n\n // First pass: expand all blocks and track which have source timing\n interface ExpandedSlideInfo {\n block: Block;\n originalIndex: number;\n templateBlock: TemplateBlock;\n hasSourceTiming: boolean;\n }\n const expandedInfos: ExpandedSlideInfo[] = [];\n\n for (const { block, originalIndex } of segmentBlocks) {\n const context = createTemplateContext(theme, originalIndex, totalBlocks, viewport);\n const expandedBlock = isTemplateBlock(block)\n ? expandTemplateBlock(block, context)\n : (block as Block);\n\n const templateBlock = block as TemplateBlock;\n const useBottom = templateBlock.useBottomLayer !== false;\n const useTop = templateBlock.useTopLayer !== false;\n if (bottomLayers.length > 0 || topLayers.length > 0) {\n expandedBlock.layers = [\n ...(useBottom ? bottomLayers : []),\n ...(expandedBlock.layers ?? []),\n ...(useTop ? topLayers : []),\n ];\n }\n\n expandedInfos.push({\n block: expandedBlock,\n originalIndex,\n templateBlock,\n hasSourceTiming: typeof templateBlock.sourceStartTime === 'number',\n });\n }\n\n // Sort blocks within this segment.\n // When ANY block has source timing (from audio analysis), section headers\n // are placed first since they are intro cards for the segment. When there\n // is no source timing (e.g., preview/synthetic mode), keep original\n // document order so the slideshow matches what the author wrote.\n const hasAnySourceTiming = expandedInfos.some((info) => info.hasSourceTiming);\n\n expandedInfos.sort((a, b) => {\n if (hasAnySourceTiming) {\n const aIsHeader = a.templateBlock.template === 'sectionHeader';\n const bIsHeader = b.templateBlock.template === 'sectionHeader';\n\n // Section headers come first when we have audio-based timing\n if (aIsHeader && !bIsHeader) return -1;\n if (!aIsHeader && bIsHeader) return 1;\n\n // Both have source timing - sort by time\n if (a.hasSourceTiming && b.hasSourceTiming) {\n return a.templateBlock.sourceStartTime! - b.templateBlock.sourceStartTime!;\n }\n\n // One has timing, one doesn't - timing comes first\n if (a.hasSourceTiming && !b.hasSourceTiming) return -1;\n if (!a.hasSourceTiming && b.hasSourceTiming) return 1;\n }\n\n // Keep original document order\n return a.originalIndex - b.originalIndex;\n });\n\n // Second pass: assign start times\n // Slides with sourceStartTime use that; others fill gaps\n let offsetWithinSegment = 0;\n for (let i = 0; i < expandedInfos.length; i++) {\n const info = expandedInfos[i];\n const { block: expandedBlock, templateBlock } = info;\n\n // Use source timing if available, otherwise use sequential offset\n if (info.hasSourceTiming) {\n // Use the source timing - this is when the content is spoken\n const sourceStart = templateBlock.sourceStartTime!;\n expandedBlock.startTime = audioSegment.startTime + sourceStart;\n // Use source duration if available, otherwise use block duration\n if (typeof templateBlock.sourceDuration === 'number') {\n expandedBlock.duration = Math.max(5, templateBlock.sourceDuration);\n }\n // Update offset for next block\n offsetWithinSegment = sourceStart + expandedBlock.duration;\n } else if (templateBlock.template === 'sectionHeader') {\n // Section headers start at the beginning of the segment\n expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;\n offsetWithinSegment += expandedBlock.duration;\n } else {\n // No source timing - place after previous block\n expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;\n // Scale content block duration to fit\n const scaledDuration = expandedBlock.duration * scaleFactor;\n expandedBlock.duration = scaledDuration;\n offsetWithinSegment += scaledDuration;\n }\n\n expandedBlocks[info.originalIndex] = expandedBlock;\n }\n\n // Third pass: fix overlaps and gaps by adjusting durations\n // Sort by startTime for overlap detection\n const segmentExpandedBlocks = expandedInfos\n .map((info) => expandedBlocks[info.originalIndex])\n .sort((a, b) => a.startTime - b.startTime);\n\n for (let i = 0; i < segmentExpandedBlocks.length - 1; i++) {\n const current = segmentExpandedBlocks[i];\n const next = segmentExpandedBlocks[i + 1];\n const currentEnd = current.startTime + current.duration;\n\n if (currentEnd > next.startTime) {\n // Overlap - shorten current block to end when next begins\n current.duration = next.startTime - current.startTime;\n } else if (currentEnd < next.startTime - 0.5) {\n // Gap > 0.5s - extend current block to fill (visual continuity)\n // Same formula as overlap: snap to next block start\n current.duration = Math.max(0.1, next.startTime - current.startTime);\n }\n }\n\n // Minimum gap between any two transitions (including section boundaries).\n // No block should be visible for less than this before a transition occurs.\n const MIN_TRANSITION_GAP = 5;\n const segmentEnd = audioSegment.startTime + audioSegment.duration;\n\n // Fourth pass: enforce minimum transition gap at section boundary.\n // Eliminate blocks from the end that would start within MIN_TRANSITION_GAP\n // of the section end (creating a jarring transition right before the next\n // section header). Loop to handle cascading eliminations.\n while (segmentExpandedBlocks.length > 1) {\n const lastBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 1];\n const timeFromLastToEnd = segmentEnd - lastBlock.startTime;\n\n if (timeFromLastToEnd < MIN_TRANSITION_GAP && lastBlock.template !== 'sectionHeader') {\n const prevBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 2];\n prevBlock.duration = segmentEnd - prevBlock.startTime;\n lastBlock.duration = 0;\n lastBlock.startTime = segmentEnd;\n segmentExpandedBlocks.pop();\n } else {\n // Extend last block to fill to segment end\n if (lastBlock.startTime + lastBlock.duration < segmentEnd) {\n lastBlock.duration = segmentEnd - lastBlock.startTime;\n }\n break;\n }\n }\n\n // Handle single-block segment\n if (segmentExpandedBlocks.length === 1) {\n const onlyBlock = segmentExpandedBlocks[0];\n if (onlyBlock.startTime + onlyBlock.duration < segmentEnd) {\n onlyBlock.duration = segmentEnd - onlyBlock.startTime;\n }\n }\n\n // Fifth pass: eliminate any remaining blocks shorter than MIN_TRANSITION_GAP.\n // Walk backwards and merge short blocks into their predecessor.\n // Skip index 0 (first block, typically section header) to preserve segment start.\n let changed = true;\n while (changed) {\n changed = false;\n for (let i = segmentExpandedBlocks.length - 1; i >= 1; i--) {\n const block = segmentExpandedBlocks[i];\n if (block.duration > 0 && block.duration < MIN_TRANSITION_GAP) {\n const prev = segmentExpandedBlocks[i - 1];\n const blockEnd = block.startTime + block.duration;\n prev.duration = blockEnd - prev.startTime;\n block.duration = 0;\n block.startTime = segmentEnd;\n segmentExpandedBlocks.splice(i, 1);\n changed = true;\n break; // Restart loop after modification\n }\n }\n }\n\n // Sixth pass: split blocks that are too long (>20s)\n // This ensures no single block lingers for too long\n const MAX_BLOCK_DURATION = 20;\n\n for (let i = 0; i < segmentExpandedBlocks.length; i++) {\n const block = segmentExpandedBlocks[i];\n\n if (block.duration > MAX_BLOCK_DURATION) {\n // Calculate how many parts we need\n const numParts = Math.ceil(block.duration / MAX_BLOCK_DURATION);\n const partDuration = block.duration / numParts;\n\n // Only split if each part would meet minimum transition gap\n if (partDuration >= MIN_TRANSITION_GAP) {\n // Shorten original block to first part\n block.duration = partDuration;\n\n // Create additional blocks for remaining parts\n for (let p = 1; p < numParts; p++) {\n const splitBlock: Block = {\n id: `${block.id}-split-${p}`,\n startTime: block.startTime + p * partDuration,\n duration: partDuration,\n audioSegment: block.audioSegment,\n layers: (block.layers ?? []).map((layer) => ({\n ...layer,\n id: `${layer.id}-split-${p}`,\n })),\n transition: { type: 'dissolve', duration: 1.0 },\n template: block.template,\n };\n // Insert into expanded blocks array\n expandedBlocks.push(splitBlock);\n }\n }\n }\n }\n }\n\n // Filter out zero-duration blocks (eliminated in earlier passes)\n return expandedBlocks.filter((block) => block && block.duration > 0);\n}\n\n/**\n * Get list of available template names.\n */\nexport function getAvailableTemplates(): string[] {\n return Object.keys(templateRegistry);\n}\n\n/**\n * Check if a template exists.\n */\nexport function hasTemplate(name: string): boolean {\n return name in templateRegistry;\n}\n\n// Re-export types and utilities from schemas\nexport {\n isTemplateBlock,\n createTemplateContext,\n scaledFontSize,\n} from '../../schemas/BlockTemplates.js';\nexport type {\n TemplateBlock,\n DocBlock,\n TemplateContext,\n PersistentLayerConfig,\n} from '../../schemas/BlockTemplates.js';\nexport {\n DEFAULT_THEME,\n resolveTheme,\n getAvailableThemes,\n getThemeSummaries,\n} from '../../schemas/themeLibrary.js';\nexport type {\n Theme,\n ThemeColorPalette,\n ThemeColorScheme,\n ThemeTypography,\n ThemeStyle,\n RenderStyle,\n} from '../../schemas/Theme.js';\nexport type { DocStylePreset } from './persistentLayers.js';\n// Re-export timing types (AudioSegmentTiming and ExpandDocBlocksOptions are already exported above)\nexport { VIEWPORT_PRESETS, getViewport, getViewportOrientation } from '../../schemas/Viewport.js';\nexport type {\n ViewportConfig,\n ViewportPreset,\n ViewportOrientation,\n} from '../../schemas/Viewport.js';\nexport { getLayoutHints, getTwoColumnPositions } from '../../schemas/LayoutStrategy.js';\nexport type { LayoutHints } from '../../schemas/LayoutStrategy.js';\nexport { expandPersistentLayers, getDocStyleConfig } from './persistentLayers.js';\n\n// Re-export individual templates for direct access\nexport { titleBlock } from './titleBlock.js';\nexport { sectionHeader } from './sectionHeader.js';\nexport { statHighlight } from './statHighlight.js';\nexport { quoteBlock } from './quoteBlock.js';\nexport { factCard } from './factCard.js';\nexport { twoColumn } from './twoColumn.js';\nexport { dateEvent } from './dateEvent.js';\nexport { imageWithCaption } from './imageWithCaption.js';\nexport { mapBlock } from './mapBlock.js';\nexport { coverBlock, expandCoverBlock } from './coverBlock.js';\nexport type { CoverBlockInput } from './coverBlock.js';\nexport { fullBleedQuote } from './fullBleedQuote.js';\nexport { listBlock } from './listBlock.js';\nexport { photoGrid } from './photoGrid.js';\nexport { definitionCard } from './definitionCard.js';\nexport { comparisonBar } from './comparisonBar.js';\nexport { pullQuote } from './pullQuote.js';\nexport { videoWithCaption } from './videoWithCaption.js';\nexport { videoPullQuote } from './videoPullQuote.js';\nexport { dataTable } from './dataTable.js';\n\n// Re-export accent image utilities\nexport { getAccentLayout, createAccentLayers, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nexport type { AccentLayout } from './accentImage.js';\n","/**\n * Animation Utilities\n *\n * Helper functions for mapping Doc animations to CSS classes and styles.\n * Generates the appropriate animation class names and CSS custom properties\n * for duration, delay, and easing.\n *\n * This is shared code used by both site and efb-app doc renderers.\n */\n\nimport type { Animation, AnimationType, TransitionType } from '../../schemas/Doc.js';\n\ninterface AnimationResult {\n /** CSS class name to apply */\n className: string;\n /** Inline styles for CSS custom properties */\n style: Record<string, string>;\n}\n\n/**\n * Get CSS class and styles for an animation.\n */\nexport function getAnimationStyle(\n animation: Animation | undefined,\n _currentTime: number = 0,\n): AnimationResult {\n if (!animation || animation.type === 'none') {\n return { className: '', style: {} };\n }\n\n const className = getAnimationClassName(animation);\n const style = getAnimationCSSVars(animation);\n\n return { className, style };\n}\n\n/**\n * Map animation type to CSS class name.\n */\nfunction getAnimationClassName(animation: Animation): string {\n const { type, direction, panDirection } = animation;\n\n switch (type) {\n case 'fadeIn':\n return 'anim-fadeIn';\n case 'fadeOut':\n return 'anim-fadeOut';\n case 'slowZoom':\n // Slow zoom (Ken Burns style) has variants based on direction and pan\n if (panDirection === 'left') return 'anim-slowZoom-panLeft';\n if (panDirection === 'right') return 'anim-slowZoom-panRight';\n if (direction === 'out') return 'anim-slowZoom-out';\n return 'anim-slowZoom-in';\n case 'zoomIn':\n return 'anim-zoomIn';\n case 'zoomOut':\n return 'anim-zoomOut';\n case 'panLeft':\n return 'anim-panLeft';\n case 'panRight':\n return 'anim-panRight';\n case 'typewriter':\n return 'anim-typewriter';\n default:\n return '';\n }\n}\n\n/**\n * Generate CSS custom properties for animation timing.\n */\nfunction getAnimationCSSVars(animation: Animation): Record<string, string> {\n const vars: Record<string, string> = {};\n\n if (animation.duration !== undefined) {\n vars['--anim-duration'] = `${animation.duration}s`;\n }\n\n if (animation.delay !== undefined) {\n vars['--anim-delay'] = `${animation.delay}s`;\n }\n\n if (animation.easing) {\n vars['--anim-easing'] = animation.easing;\n }\n\n return vars;\n}\n\n/**\n * Get default duration for an animation type.\n */\nexport function getDefaultAnimationDuration(type: AnimationType): number {\n switch (type) {\n case 'slowZoom':\n case 'panLeft':\n case 'panRight':\n return 8; // Long, slow animations\n case 'typewriter':\n return 3;\n case 'fadeIn':\n case 'fadeOut':\n return 1;\n case 'zoomIn':\n case 'zoomOut':\n return 0.5;\n default:\n return 1;\n }\n}\n\n/**\n * Get transition class for slide entry/exit.\n */\nexport function getTransitionClass(type: TransitionType, entering: boolean): string {\n const mode = entering ? 'enter' : 'exit';\n return `transition-${type}-${mode}`;\n}\n\n/**\n * Calculate animation progress (0-1) based on current time.\n */\nexport function getAnimationProgress(\n animation: Animation,\n currentTime: number,\n slideDuration: number,\n): number {\n const delay = animation.delay || 0;\n const duration = animation.duration || slideDuration;\n\n if (currentTime < delay) return 0;\n if (currentTime >= delay + duration) return 1;\n\n return (currentTime - delay) / duration;\n}\n","/**\n * Markdown → Doc Conversion\n *\n * Converts a MarkdownDocument into a hierarchical Doc whose Block tree\n * mirrors the heading structure of the markdown. Every heading (H1–H6)\n * becomes a Block; body content between headings populates `contents`;\n * sub-headings nest as `children`.\n *\n * This enables using BlockTemplates to supply alternate visualizations\n * for each section of a markdown document.\n *\n * @example\n * ```ts\n * import { parseMarkdown } from '@bendyline/squisq/markdown';\n * import { markdownToDoc } from '@bendyline/squisq/doc';\n *\n * const md = parseMarkdown('# Intro\\n\\nHello world\\n\\n## Details\\n\\nMore text');\n * const doc = markdownToDoc(md);\n * // doc.blocks[0].sourceHeading.depth === 1 (\"# Intro\")\n * // doc.blocks[0].contents → [paragraph(\"Hello world\")]\n * // doc.blocks[0].children[0].sourceHeading.depth === 2 (\"## Details\")\n * ```\n */\n\nimport type { Doc, Block, CaptionTrack, CaptionPhrase, StartBlockConfig } from '../schemas/Doc.js';\nimport type {\n MarkdownDocument,\n MarkdownBlockNode,\n MarkdownHeading,\n MarkdownNode,\n MarkdownImage,\n} from '../markdown/types.js';\nimport { extractPlainText } from '../markdown/utils.js';\nimport { estimateReadingTime } from '../timing/readingTime.js';\n\n// ============================================\n// Options\n// ============================================\n\n/**\n * Options for markdownToDoc().\n */\nexport interface MarkdownToDocOptions {\n /** Article ID for the generated Doc. Default: 'markdown-doc' */\n articleId?: string;\n\n /** Default template name for heading blocks. Default: 'sectionHeader' */\n defaultTemplate?: string;\n\n /** Default duration per block in seconds. Default: 5 */\n defaultDuration?: number;\n\n /** Custom ID generator. Receives the heading node and its index. */\n generateId?: (heading: MarkdownHeading, index: number) => string;\n\n /**\n * Whether to auto-generate a cover startBlock from the first H1 heading.\n * When true (default), a StartBlockConfig is created using the first H1's\n * text as the title. If the document contains an image, the first image\n * is used as the hero. Set to false to suppress automatic cover generation.\n */\n generateCoverBlock?: boolean;\n}\n\n// ============================================\n// ID Generation\n// ============================================\n\n/**\n * Convert text to a URL-friendly slug.\n * \"Getting Started & More\" → \"getting-started-more\"\n */\nconst SLUG_NON_WORD_RE = /[^\\w\\s-]/g;\nconst SLUG_SPACES_RE = /[\\s_]+/g;\nconst SLUG_MULTI_HYPHEN_RE = /-+/g;\nconst SLUG_TRIM_HYPHEN_RE = /^-|-$/g;\n\nfunction slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(SLUG_NON_WORD_RE, '') // Remove non-word chars (except spaces and hyphens)\n .replace(SLUG_SPACES_RE, '-') // Replace spaces/underscores with hyphens\n .replace(SLUG_MULTI_HYPHEN_RE, '-') // Collapse multiple hyphens\n .replace(SLUG_TRIM_HYPHEN_RE, '') || // Trim leading/trailing hyphens\n 'block'\n ); // Fallback for empty result\n}\n\n/**\n * Creates an ID generator that produces unique slugified IDs.\n * Appends -2, -3, etc. for duplicate headings.\n */\nfunction createIdGenerator() {\n const used = new Map<string, number>();\n\n return (heading: MarkdownHeading, _index: number): string => {\n const text = extractPlainText(heading);\n const base = slugify(text);\n const count = used.get(base) ?? 0;\n used.set(base, count + 1);\n\n if (count === 0) return base;\n return `${base}-${count + 1}`;\n };\n}\n\n// ============================================\n// Core Conversion\n// ============================================\n\n/**\n * Convert a MarkdownDocument into a Doc with a heading-driven Block hierarchy.\n *\n * **Algorithm:**\n * 1. Walk the document's top-level children sequentially\n * 2. Each MarkdownHeading starts a new block at its depth level\n * 3. Non-heading nodes accumulate as `contents` on the current block\n * 4. Sub-headings (deeper depth) nest as `children` of the current block\n * 5. Same-level or shallower headings close the current block and start a sibling/ancestor\n * 6. Content before the first heading goes into a \"preamble\" block with no sourceHeading\n *\n * @param markdownDoc - A parsed MarkdownDocument\n * @param options - Conversion options\n * @returns A Doc whose blocks mirror the markdown heading structure\n */\nexport function markdownToDoc(markdownDoc: MarkdownDocument, options?: MarkdownToDocOptions): Doc {\n const articleId = options?.articleId ?? 'markdown-doc';\n const defaultTemplate = options?.defaultTemplate ?? 'sectionHeader';\n const defaultDuration = options?.defaultDuration ?? 5;\n const generateId = options?.generateId ?? createIdGenerator();\n\n const rootBlocks: Block[] = [];\n let headingIndex = 0;\n\n // Stack tracks the nesting context: each entry is a block and its heading depth.\n // We push when we go deeper, pop when we come back up.\n const stack: Array<{ block: Block; depth: number }> = [];\n\n // Accumulator for content nodes that appear before any heading (preamble)\n // or between the current heading and the next heading/sub-heading.\n let pendingContents: MarkdownBlockNode[] = [];\n let currentBlock: Block | null = null;\n\n function flushContents() {\n if (currentBlock && pendingContents.length > 0) {\n currentBlock.contents = (currentBlock.contents ?? []).concat(pendingContents);\n pendingContents = [];\n }\n }\n\n function makeBlock(heading: MarkdownHeading | null): Block {\n const id = heading ? generateId(heading, headingIndex++) : 'preamble';\n\n // Use template from annotation if present, otherwise fall back to default\n const annotation = heading?.templateAnnotation;\n const template = annotation?.template ?? (heading ? defaultTemplate : undefined);\n\n // Extract heading text so templates (e.g. sectionHeader) that expect a\n // `title` property receive it without having to reach into sourceHeading.\n const title = heading ? extractPlainText(heading) : undefined;\n\n const block: Block = {\n id,\n startTime: 0,\n duration: defaultDuration,\n audioSegment: 0,\n template,\n ...(heading ? { sourceHeading: heading } : {}),\n ...(title ? { title } : {}),\n };\n\n // Propagate key-value params from annotation to templateOverrides\n if (annotation?.params) {\n block.templateOverrides = annotation.params;\n }\n\n return block;\n }\n\n for (const node of markdownDoc.children) {\n if (node.type === 'heading') {\n const heading = node as MarkdownHeading;\n const depth = heading.depth;\n\n // Flush any accumulated content to the current block\n flushContents();\n\n // Create the new block for this heading\n const newBlock = makeBlock(heading);\n\n if (stack.length === 0) {\n // If there's a preamble block with no heading, push it first\n if (currentBlock && !currentBlock.sourceHeading) {\n rootBlocks.push(currentBlock);\n }\n\n // This is a root-level block (or the first heading)\n rootBlocks.push(newBlock);\n stack.push({ block: newBlock, depth });\n } else {\n // Find where this heading fits in the hierarchy\n // Pop blocks from the stack until we find a parent with lower depth\n while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {\n stack.pop();\n }\n\n if (stack.length === 0) {\n // Same level as root or shallower — new root block\n rootBlocks.push(newBlock);\n stack.push({ block: newBlock, depth });\n } else {\n // Deeper — child of the current stack top\n const parent = stack[stack.length - 1].block;\n if (!parent.children) parent.children = [];\n parent.children.push(newBlock);\n stack.push({ block: newBlock, depth });\n }\n }\n\n currentBlock = newBlock;\n } else {\n // Non-heading block node — accumulate as content\n if (!currentBlock) {\n // Content before any heading → create preamble block\n currentBlock = makeBlock(null);\n }\n pendingContents.push(node);\n }\n }\n\n // Flush remaining content\n flushContents();\n\n // If we only had preamble content (no headings at all), push it\n if (currentBlock && !currentBlock.sourceHeading && !rootBlocks.includes(currentBlock)) {\n rootBlocks.push(currentBlock);\n }\n\n // Calculate reading-time-based durations and generate captions\n const allBlocks = flattenBlocks(rootBlocks);\n const minDuration = 3; // seconds — minimum for blocks with little/no text\n const phrases: CaptionPhrase[] = [];\n\n // First pass: compute duration from body-content reading time\n for (const block of allBlocks) {\n const bodyText = getBlockBodyText(block);\n if (bodyText.length > 0) {\n const estimate = estimateReadingTime(bodyText);\n block.duration = Math.max(minDuration, estimate.seconds);\n } else {\n block.duration = defaultDuration;\n }\n }\n\n // Second pass: assign start times sequentially and build caption phrases\n let currentTime = 0;\n for (const block of allBlocks) {\n block.startTime = currentTime;\n\n // Generate caption phrases from the block's body content\n const bodyText = getBlockBodyText(block);\n if (bodyText.length > 0) {\n const sentences = splitIntoSentences(bodyText);\n if (sentences.length > 0) {\n const timePerSentence = block.duration / sentences.length;\n for (let i = 0; i < sentences.length; i++) {\n phrases.push({\n text: sentences[i],\n startTime: currentTime + i * timePerSentence,\n endTime: currentTime + (i + 1) * timePerSentence,\n audioSegment: 0,\n });\n }\n }\n }\n\n currentTime += block.duration;\n }\n\n const captions: CaptionTrack | undefined =\n phrases.length > 0 ? { phrases, generatedAt: new Date().toISOString(), version: 1 } : undefined;\n\n const doc: Doc = {\n articleId,\n duration: currentTime,\n blocks: rootBlocks,\n audio: {\n segments: [],\n },\n ...(captions ? { captions } : {}),\n ...(markdownDoc.frontmatter ? { frontmatter: markdownDoc.frontmatter } : {}),\n };\n\n // Auto-generate cover startBlock from the first H1 heading\n if (options?.generateCoverBlock ?? true) {\n const coverConfig = buildStartBlock(markdownDoc, rootBlocks);\n if (coverConfig) {\n doc.startBlock = coverConfig;\n }\n }\n\n return doc;\n}\n\n// ============================================\n// Utilities\n// ============================================\n\n/**\n * Flatten a nested block tree into a depth-first ordered array.\n * Useful for calculating sequential timing or iterating all blocks.\n */\nexport function flattenBlocks(blocks: Block[]): Block[] {\n const result: Block[] = [];\n for (const block of blocks) {\n result.push(block);\n if (block.children) {\n result.push(...flattenBlocks(block.children));\n }\n }\n return result;\n}\n\n/**\n * Count the total number of blocks in a nested tree (including children at all levels).\n */\nexport function countBlocks(blocks: Block[]): number {\n let count = 0;\n for (const block of blocks) {\n count += 1;\n if (block.children) {\n count += countBlocks(block.children);\n }\n }\n return count;\n}\n\n/**\n * Get the heading depth for a block. Returns 0 for preamble blocks (no heading).\n */\nexport function getBlockDepth(block: Block): number {\n return block.sourceHeading?.depth ?? 0;\n}\n\n// ============================================\n// Internal helpers\n// ============================================\n\n/**\n * Extract the plain text from a block's body contents (excluding heading text).\n */\nfunction getBlockBodyText(block: Block): string {\n if (!block.contents || block.contents.length === 0) return '';\n // Join with newlines to preserve paragraph/list-item boundaries.\n // splitIntoPhrases uses these newlines as natural split points.\n return block.contents\n .map((node) => extractPlainText(node))\n .join('\\n')\n .trim();\n}\n\n/** Maximum words per caption phrase. Long sentences get split at this point. */\nconst MAX_PHRASE_WORDS = 12;\n\n/**\n * Split text into caption-sized phrases.\n *\n * Splits on:\n * 1. Newlines (paragraph/list-item boundaries from markdown)\n * 2. Sentence endings (.!?) followed by whitespace\n * 3. Long fragments (> MAX_PHRASE_WORDS) at clause boundaries (commas, semicolons, dashes)\n *\n * Merges very short fragments (< 15 chars) with the previous phrase.\n */\nfunction splitIntoSentences(text: string): string[] {\n // First split on newlines (each paragraph/list item becomes separate)\n const lines = text\n .split(/\\n+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n\n // Then split each line on sentence boundaries\n const sentenceRe = /(?<=[.!?])\\s+/;\n const fragments: string[] = [];\n for (const line of lines) {\n const sentences = line\n .split(sentenceRe)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n fragments.push(...sentences);\n }\n\n if (fragments.length === 0) return [];\n\n // Split long fragments at clause boundaries\n const split: string[] = [];\n for (const frag of fragments) {\n const words = frag.split(/\\s+/);\n if (words.length > MAX_PHRASE_WORDS) {\n // Try to split at comma, semicolon, or dash near the midpoint\n const mid = Math.floor(frag.length / 2);\n const clauseRe = /[,;]\\s+|\\s+—\\s+|\\s+-\\s+/g;\n let bestSplit = -1;\n let bestDist = Infinity;\n let match;\n while ((match = clauseRe.exec(frag)) !== null) {\n const dist = Math.abs(match.index - mid);\n if (dist < bestDist) {\n bestDist = dist;\n bestSplit = match.index + match[0].length;\n }\n }\n if (bestSplit > 0 && bestSplit < frag.length - 5) {\n split.push(frag.slice(0, bestSplit).trim());\n split.push(frag.slice(bestSplit).trim());\n } else {\n split.push(frag);\n }\n } else {\n split.push(frag);\n }\n }\n\n // Merge very short fragments (< 15 chars) with the previous phrase\n const merged: string[] = [split[0]];\n for (let i = 1; i < split.length; i++) {\n if (split[i].length < 15 && merged.length > 0) {\n merged[merged.length - 1] += ' ' + split[i];\n } else {\n merged.push(split[i]);\n }\n }\n return merged;\n}\n\n/**\n * Walk a MarkdownNode tree depth-first to find the first image node.\n * Returns the MarkdownImage or undefined if none found.\n */\nfunction findFirstImage(node: MarkdownNode): MarkdownImage | undefined {\n if (node.type === 'image') return node as MarkdownImage;\n if ('children' in node && Array.isArray((node as { children?: unknown[] }).children)) {\n for (const child of (node as { children: MarkdownNode[] }).children) {\n const found = findFirstImage(child);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/**\n * Build a StartBlockConfig from the document's first H1 heading and optional\n * first image. Returns undefined if the document has no H1 heading.\n */\nfunction buildStartBlock(\n markdownDoc: MarkdownDocument,\n rootBlocks: Block[],\n): StartBlockConfig | undefined {\n // Find the first H1 block — it provides the cover title\n const firstH1 = rootBlocks.find((b) => b.sourceHeading?.depth === 1);\n if (!firstH1) return undefined;\n\n const title = firstH1.title ?? extractPlainText(firstH1.sourceHeading!);\n if (!title) return undefined;\n\n // Look for the first paragraph immediately after the H1 to use as subtitle\n const subtitle =\n firstH1.contents?.[0]?.type === 'paragraph' ? extractPlainText(firstH1.contents[0]) : undefined;\n\n // Scan the whole document for the first image to use as the hero\n const firstImage = findFirstImage(markdownDoc);\n\n const config: StartBlockConfig = {\n title,\n ...(subtitle ? { subtitle } : {}),\n ...(firstImage ? { heroSrc: firstImage.url, heroAlt: firstImage.alt ?? title } : {}),\n ambientMotion: 'zoomIn',\n };\n\n return config;\n}\n","/**\n * Doc → Markdown Conversion\n *\n * Converts a Doc with a heading-driven Block hierarchy back into a\n * MarkdownDocument. This is the reverse of markdownToDoc() and enables\n * round-tripping: edit a Doc's block tree, then serialize back to markdown.\n *\n * **Algorithm:**\n * Walk the block tree depth-first. For each block:\n * 1. If it has a `sourceHeading`, emit that heading node\n * 2. Emit all nodes in `contents`\n * 3. Recurse into `children`\n *\n * @example\n * ```ts\n * import { markdownToDoc, docToMarkdown } from '@bendyline/squisq/doc';\n * import { parseMarkdown, stringifyMarkdown } from '@bendyline/squisq/markdown';\n *\n * const md = '# Hello\\n\\nWorld\\n';\n * const doc = markdownToDoc(parseMarkdown(md));\n * const roundTripped = stringifyMarkdown(docToMarkdown(doc));\n * ```\n */\n\nimport type { Doc, Block } from '../schemas/Doc.js';\nimport type { MarkdownDocument, MarkdownBlockNode, MarkdownHeading } from '../markdown/types.js';\n\n/**\n * Convert a Doc with heading-driven blocks back to a MarkdownDocument.\n *\n * Walks the block tree depth-first, emitting heading nodes and contents\n * in document order. Blocks without a `sourceHeading` (preamble blocks)\n * emit only their contents.\n *\n * If a block has a `template` or `templateOverrides` that aren't already\n * reflected in the heading's `templateAnnotation`, the annotation is\n * injected so the round-trip preserves template assignments.\n *\n * @param doc - A Doc whose blocks may have `sourceHeading`, `contents`, and `children`\n * @returns A MarkdownDocument that can be stringified back to markdown\n */\nexport function docToMarkdown(doc: Doc): MarkdownDocument {\n const children: MarkdownBlockNode[] = [];\n\n function emitBlock(block: Block): void {\n // Emit the heading node if present\n if (block.sourceHeading) {\n const heading = ensureAnnotation(block, block.sourceHeading);\n children.push(heading);\n }\n\n // Emit body content\n if (block.contents) {\n children.push(...block.contents);\n }\n\n // Recurse into children (sub-headings)\n if (block.children) {\n for (const child of block.children) {\n emitBlock(child);\n }\n }\n }\n\n for (const block of doc.blocks) {\n emitBlock(block);\n }\n\n return {\n type: 'document',\n children,\n };\n}\n\n/**\n * Ensure the heading's `templateAnnotation` reflects the block's\n * template and templateOverrides. Returns a (possibly cloned) heading.\n */\nfunction ensureAnnotation(block: Block, heading: MarkdownHeading): MarkdownHeading {\n // If the heading already has an annotation, trust it (it came from parsing)\n if (heading.templateAnnotation) return heading;\n\n // If the block has a non-default template or overrides, inject an annotation\n const hasExplicitTemplate = block.template && block.template !== 'sectionHeader';\n const hasOverrides = block.templateOverrides && Object.keys(block.templateOverrides).length > 0;\n\n if (!hasExplicitTemplate && !hasOverrides) return heading;\n\n // Clone to avoid mutating the original\n return {\n ...heading,\n children: [...heading.children],\n templateAnnotation: {\n template: block.template ?? 'sectionHeader',\n ...(hasOverrides ? { params: block.templateOverrides } : {}),\n },\n };\n}\n","/**\n * getLayers — Compute visual layers for a block on demand.\n *\n * This is the preferred way to obtain renderable layers for a block.\n * Instead of storing pre-computed layers on the Block object, call\n * `getLayers(block, context)` to derive them from the block's template\n * name, content, and the current render context (theme, viewport, etc.).\n *\n * For raw blocks that already carry a `layers` array, those layers are\n * returned directly (with optional persistent layer injection).\n *\n * @example\n * ```ts\n * import { getLayers } from '@bendyline/squisq/doc';\n *\n * const layers = getLayers(block, {\n * theme: DEFAULT_THEME,\n * viewport: VIEWPORT_PRESETS.landscape,\n * blockIndex: 0,\n * totalBlocks: 10,\n * });\n * ```\n */\n\nimport type { Block, Layer } from '../schemas/Doc.js';\nimport type {\n TemplateBlock,\n TemplateContext,\n PersistentLayerConfig,\n DocBlock,\n} from '../schemas/BlockTemplates.js';\nimport type { Theme } from '../schemas/Theme.js';\nimport type { ViewportConfig } from '../schemas/Viewport.js';\nimport { VIEWPORT_PRESETS } from '../schemas/Viewport.js';\nimport { createTemplateContext, isTemplateBlock } from '../schemas/BlockTemplates.js';\nimport { DEFAULT_THEME } from '../schemas/themeLibrary.js';\nimport { templateRegistry } from './templates/index.js';\nimport { expandPersistentLayers } from './templates/persistentLayers.js';\n\n// ============================================\n// RenderContext\n// ============================================\n\n/**\n * Context needed to compute layers for a block.\n *\n * Captures the visual rendering parameters: theme colors, viewport\n * configuration, persistent layers, and the block's position within\n * the doc (for template functions that vary output by index).\n */\nexport interface RenderContext {\n /** Theme for template rendering. Defaults to DEFAULT_THEME (documentary). */\n theme?: Theme;\n\n /** Target viewport configuration. Defaults to 16:9 landscape. */\n viewport?: ViewportConfig;\n\n /** Persistent layers injected behind and/or on top of all block content. */\n persistentLayers?: PersistentLayerConfig;\n\n /** 0-based index of this block in the sequence. Defaults to 0. */\n blockIndex?: number;\n\n /** Total number of blocks in the doc. Defaults to 1. */\n totalBlocks?: number;\n}\n\n// ============================================\n// getLayers\n// ============================================\n\n/**\n * Compute the visual layers for a block.\n *\n * Resolution order:\n * 1. If the block already has a non-empty `layers` array, use it (raw block).\n * 2. If the block has a `template` name that exists in the registry,\n * call the template function to generate layers.\n * 3. Otherwise return an empty array.\n *\n * Persistent layers (bottom/top) from the render context are injected\n * around the result unless the block opts out via `useBottomLayer: false`\n * or `useTopLayer: false`.\n *\n * @param block A Block or TemplateBlock to render.\n * @param context Render context (theme, viewport, persistent layers, position).\n * @returns The computed Layer[] for the block, ready for BlockRenderer.\n */\nexport function getLayers(block: DocBlock, context: RenderContext = {}): Layer[] {\n const theme = context.theme ?? DEFAULT_THEME;\n const viewport = context.viewport ?? VIEWPORT_PRESETS.landscape;\n const blockIndex = context.blockIndex ?? 0;\n const totalBlocks = context.totalBlocks ?? 1;\n\n // 1. Raw block path: block already has pre-computed layers\n const existingLayers = (block as Block).layers;\n if (existingLayers && existingLayers.length > 0 && !isTemplateBlock(block)) {\n return injectPersistentLayers(existingLayers, block, context);\n }\n\n // 2. Template path: look up and call the template function\n if (isTemplateBlock(block) && block.template in templateRegistry) {\n const templateName = block.template as keyof typeof templateRegistry;\n const templateCtx = createTemplateContext(theme, blockIndex, totalBlocks, viewport);\n let layers: Layer[];\n try {\n // Each registry entry accepts its specific TemplateBlock variant; the\n // discriminated union guarantees the shapes match at runtime.\n const templateFn = templateRegistry[templateName] as (\n input: TemplateBlock,\n ctx: TemplateContext,\n ) => Layer[];\n layers = templateFn(block, templateCtx);\n if (!Array.isArray(layers)) {\n console.error(`Template ${templateName} did not return an array, got:`, typeof layers);\n layers = [];\n }\n } catch (err: unknown) {\n console.error(`Error expanding template ${templateName}:`, err);\n layers = [];\n }\n\n return injectPersistentLayers(layers, block, context);\n }\n\n // 3. Fallback: no layers and no known template\n return injectPersistentLayers([], block, context);\n}\n\n// ============================================\n// Internal helpers\n// ============================================\n\n/**\n * Inject persistent bottom/top layers around the block's own layers,\n * respecting per-block opt-out flags.\n */\nfunction injectPersistentLayers(layers: Layer[], block: DocBlock, context: RenderContext): Layer[] {\n const { persistentLayers } = context;\n if (!persistentLayers) return layers;\n\n const bottomLayers = expandPersistentLayers(persistentLayers.bottomLayers);\n const topLayers = expandPersistentLayers(persistentLayers.topLayers);\n\n if (bottomLayers.length === 0 && topLayers.length === 0) return layers;\n\n const templateBlock = block as TemplateBlock;\n const useBottom = templateBlock.useBottomLayer !== false;\n const useTop = templateBlock.useTopLayer !== false;\n\n return [...(useBottom ? bottomLayers : []), ...layers, ...(useTop ? topLayers : [])];\n}\n","/**\n * Audio Mapping\n *\n * Associates audio segments (MP3 files) with document blocks.\n * Supports two modes:\n *\n * 1. **Explicit annotation**: Blocks with `{[audio=filename.mp3]}` in their\n * heading annotation are directly mapped to that audio file.\n *\n * 2. **Auto-matching**: When no annotations exist but the container has MP3s\n * with `.timing.json` files, matches MP3s to blocks by comparing the\n * timing.json `sourceText` against block text content (word overlap).\n * Falls back to filename-based matching (slugified title comparison).\n */\n\nimport type { Doc, Block, AudioSegment, AudioTimingData } from '../schemas/Doc.js';\nimport type { ContentContainer } from '../storage/ContentContainer.js';\nimport { extractPlainText } from '../markdown/utils.js';\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\n/**\n * Parse a timing.json file from raw data.\n */\nfunction parseTimingJson(data: ArrayBuffer): AudioTimingData | null {\n try {\n const text = new TextDecoder().decode(data);\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed.sourceText === 'string' && typeof parsed.duration === 'number') {\n return {\n sourceText: parsed.sourceText,\n bookmarks: Array.isArray(parsed.bookmarks) ? parsed.bookmarks : [],\n duration: parsed.duration,\n };\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Normalize text for comparison: lowercase, strip punctuation, split into word set.\n */\nfunction normalizeToWords(text: string): Set<string> {\n const words = text\n .toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n return new Set(words);\n}\n\n/**\n * Calculate Jaccard similarity between two texts (word overlap).\n * Returns 0–1 where 1 = identical word sets.\n */\nexport function scoreTextSimilarity(a: string, b: string): number {\n const wordsA = normalizeToWords(a);\n const wordsB = normalizeToWords(b);\n if (wordsA.size === 0 || wordsB.size === 0) return 0;\n\n let intersection = 0;\n for (const w of wordsA) {\n if (wordsB.has(w)) intersection++;\n }\n\n const union = new Set([...wordsA, ...wordsB]).size;\n return union > 0 ? intersection / union : 0;\n}\n\n/**\n * Slugify a title for filename comparison.\n * \"The Behring Gambit\" → \"the-behring-gambit\"\n */\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/**\n * Extract plain text from a block's contents and title.\n */\nfunction blockToPlainText(block: Block): string {\n const parts: string[] = [];\n if (block.title) parts.push(block.title);\n if (block.contents) {\n for (const node of block.contents) {\n parts.push(extractPlainText(node));\n }\n }\n return parts.join('\\n');\n}\n\n/**\n * Flatten a block tree into a linear array of leaf blocks\n * (blocks that represent actual content sections).\n */\nfunction flattenForAudio(blocks: Block[]): Block[] {\n const result: Block[] = [];\n for (const block of blocks) {\n if (block.children && block.children.length > 0) {\n result.push(...flattenForAudio(block.children));\n } else {\n result.push(block);\n }\n }\n return result;\n}\n\n/** Info about an MP3 file found in the container. */\ninterface Mp3Info {\n /** Path in the container (e.g., \"images/c23n-issaquah-highlands-intro.mp3\") */\n path: string;\n /** Filename without path (e.g., \"c23n-issaquah-highlands-intro.mp3\") */\n filename: string;\n /** Parsed timing data (if .timing.json exists) */\n timing: AudioTimingData | null;\n}\n\n// ── Core Functions ───────────────────────────────────────────────────\n\n/**\n * Parse a consolidated timing.json (version 2) which contains all section\n * timing data in a single file.\n */\nfunction parseConsolidatedTiming(data: ArrayBuffer): Record<string, AudioTimingData> | null {\n try {\n const text = new TextDecoder().decode(data);\n const parsed = JSON.parse(text);\n if (parsed && parsed.version === 2 && parsed.sections) {\n return parsed.sections as Record<string, AudioTimingData>;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Discover all MP3 files in a container and load their timing data.\n * Checks for a consolidated timing.json first, then falls back to per-file .timing.json.\n */\nasync function discoverMp3s(container: ContentContainer): Promise<Mp3Info[]> {\n const files = await container.listFiles();\n const mp3Files = files.filter((f) => f.path.endsWith('.mp3'));\n const results: Mp3Info[] = [];\n\n // Try to load consolidated timing.json\n let consolidatedSections: Record<string, AudioTimingData> | null = null;\n const consolidatedData = await container.readFile('timing.json');\n if (consolidatedData) {\n consolidatedSections = parseConsolidatedTiming(consolidatedData);\n }\n\n for (const file of mp3Files) {\n const filename = file.path.split('/').pop() ?? file.path;\n let timing: AudioTimingData | null = null;\n\n // Try consolidated timing first: match section name from filename\n if (consolidatedSections) {\n const mp3Base = filename.replace(/\\.mp3$/, '');\n for (const [sectionName, sectionTiming] of Object.entries(consolidatedSections)) {\n if (mp3Base.endsWith(`-${sectionName}`)) {\n timing = sectionTiming;\n break;\n }\n }\n }\n\n // Fall back to per-file .timing.json\n if (!timing) {\n const timingPath = `${file.path}.timing.json`;\n const timingData = await container.readFile(timingPath);\n if (timingData) {\n timing = parseTimingJson(timingData);\n }\n }\n\n results.push({ path: file.path, filename, timing });\n }\n\n return results;\n}\n\n/**\n * Resolve audio from explicit `{[audio=filename.mp3]}` annotations on blocks.\n * Returns the matched pairs or an empty array if no annotations found.\n */\nfunction resolveFromAnnotations(\n blocks: Block[],\n mp3s: Mp3Info[],\n): Array<{ block: Block; mp3: Mp3Info }> {\n const matches: Array<{ block: Block; mp3: Mp3Info }> = [];\n const flat = flattenForAudio(blocks);\n\n for (const block of flat) {\n const audioRef = block.templateOverrides?.audio;\n if (!audioRef) continue;\n\n // Find the MP3 by filename (exact or suffix match)\n const mp3 = mp3s.find(\n (m) => m.filename === audioRef || m.path === audioRef || m.path.endsWith(`/${audioRef}`),\n );\n\n if (mp3) {\n matches.push({ block, mp3 });\n }\n }\n\n return matches;\n}\n\n/** Minimum similarity score to consider a content match. */\nconst MIN_CONTENT_SIMILARITY = 0.35;\n\n/** Minimum similarity score for filename-based matching. */\nconst MIN_FILENAME_SIMILARITY = 0.5;\n\n/**\n * Auto-match MP3 files to blocks by content similarity.\n * Uses timing.json sourceText when available, falls back to filename matching.\n */\nfunction autoMatchBlocks(\n blocks: Block[],\n mp3s: Mp3Info[],\n): Array<{ block: Block; mp3: Mp3Info; score: number }> {\n const flat = flattenForAudio(blocks);\n if (flat.length === 0 || mp3s.length === 0) return [];\n\n // Score all (mp3, block) pairs\n const scoredPairs: Array<{\n block: Block;\n blockIndex: number;\n mp3: Mp3Info;\n mp3Index: number;\n score: number;\n }> = [];\n\n for (let mi = 0; mi < mp3s.length; mi++) {\n const mp3 = mp3s[mi];\n\n for (let bi = 0; bi < flat.length; bi++) {\n const block = flat[bi];\n const blockText = blockToPlainText(block);\n if (!blockText.trim()) continue;\n\n let score = 0;\n\n // Primary: content similarity via timing.json sourceText\n if (mp3.timing?.sourceText) {\n score = scoreTextSimilarity(mp3.timing.sourceText, blockText);\n }\n\n // Fallback: filename-based matching\n if (score < MIN_CONTENT_SIMILARITY && block.title) {\n const titleSlug = slugify(block.title);\n const fileSlug = slugify(mp3.filename.replace(/\\.mp3$/, ''));\n // Check if the title slug appears in the filename slug\n if (fileSlug.includes(titleSlug) && titleSlug.length >= 3) {\n score = Math.max(score, MIN_FILENAME_SIMILARITY + 0.1);\n }\n }\n\n if (score >= MIN_CONTENT_SIMILARITY) {\n scoredPairs.push({ block, blockIndex: bi, mp3, mp3Index: mi, score });\n }\n }\n }\n\n // Greedy assignment: highest score first, each mp3 and block used at most once\n scoredPairs.sort((a, b) => b.score - a.score);\n const usedBlocks = new Set<number>();\n const usedMp3s = new Set<number>();\n const matches: Array<{ block: Block; mp3: Mp3Info; score: number }> = [];\n\n for (const pair of scoredPairs) {\n if (usedBlocks.has(pair.blockIndex) || usedMp3s.has(pair.mp3Index)) continue;\n usedBlocks.add(pair.blockIndex);\n usedMp3s.add(pair.mp3Index);\n matches.push({ block: pair.block, mp3: pair.mp3, score: pair.score });\n }\n\n return matches;\n}\n\n// ── Public API ───────────────────────────────────────────────────────\n\n/**\n * Resolve audio mapping for a Doc using a ContentContainer.\n *\n * Tries explicit `{[audio=filename.mp3]}` annotations first,\n * then falls back to auto-matching by content similarity.\n *\n * Returns a new Doc with `audio.segments` populated and blocks\n * assigned to the correct `audioSegment` indices.\n *\n * @param doc - The source Doc (not mutated).\n * @param container - ContentContainer with MP3 and timing files.\n * @returns New Doc with audio segments resolved, or original doc if no matches.\n */\nexport async function resolveAudioMapping(doc: Doc, container: ContentContainer): Promise<Doc> {\n // Discover MP3 files and their timing data\n const mp3s = await discoverMp3s(container);\n if (mp3s.length === 0) return doc;\n\n // Try annotations first\n let matches = resolveFromAnnotations(doc.blocks, mp3s);\n\n // Fall back to auto-matching if no annotations found\n if (matches.length === 0) {\n matches = autoMatchBlocks(doc.blocks, mp3s).map((m) => ({\n block: m.block,\n mp3: m.mp3,\n }));\n }\n\n if (matches.length === 0) return doc;\n\n // Build audio segments in document order\n // Sort matches by the block's position in the flattened tree\n const flat = flattenForAudio(doc.blocks);\n const blockOrder = new Map(flat.map((b, i) => [b.id, i]));\n matches.sort((a, b) => (blockOrder.get(a.block.id) ?? 0) - (blockOrder.get(b.block.id) ?? 0));\n\n // Build segment list and assign indices\n const segments: AudioSegment[] = [];\n const blockToSegment = new Map<string, number>();\n let startTime = 0;\n\n for (let i = 0; i < matches.length; i++) {\n const { block, mp3 } = matches[i];\n const duration = mp3.timing?.duration ?? 30; // Fallback duration if no timing\n\n segments.push({\n src: mp3.path,\n name: block.title ?? block.id,\n duration,\n startTime,\n });\n\n blockToSegment.set(block.id, i);\n startTime += duration;\n }\n\n // Deep clone blocks and assign audioSegment indices\n const newBlocks = assignSegmentIndices(doc.blocks, blockToSegment);\n\n return {\n ...doc,\n blocks: newBlocks,\n duration: startTime,\n audio: { segments },\n };\n}\n\n/**\n * Recursively clone blocks and assign audioSegment indices.\n * Blocks not in the map keep their original audioSegment.\n * Children of a matched block inherit the parent's segment.\n */\nfunction assignSegmentIndices(\n blocks: Block[],\n blockToSegment: Map<string, number>,\n inheritedSegment?: number,\n): Block[] {\n return blocks.map((block) => {\n const segment = blockToSegment.get(block.id) ?? inheritedSegment ?? block.audioSegment;\n const newBlock: Block = {\n ...block,\n audioSegment: segment,\n };\n\n if (block.children) {\n newBlock.children = assignSegmentIndices(block.children, blockToSegment, segment);\n }\n\n return newBlock;\n });\n}\n"],"mappings":"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","names":["slugify"]}