@bendyline/squisq 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -10
- package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
- package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
- package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
- package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
- package/dist/chunk-3E5F2XMR.js.map +1 -0
- package/dist/chunk-4X3JQXNM.js +35 -0
- package/dist/chunk-4X3JQXNM.js.map +1 -0
- package/dist/{chunk-2OIBZYKP.js → chunk-5DKBFXPY.js} +31 -121
- package/dist/chunk-5DKBFXPY.js.map +1 -0
- package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
- package/dist/chunk-5J4HKRJF.js.map +1 -0
- package/dist/chunk-5UYI3RJB.js +2503 -0
- package/dist/chunk-5UYI3RJB.js.map +1 -0
- package/dist/{chunk-TEEEILMP.js → chunk-66QO7XFB.js} +19 -292
- package/dist/chunk-66QO7XFB.js.map +1 -0
- package/dist/{chunk-KKNUBQ6Y.js → chunk-6PJRB2CF.js} +156 -91
- package/dist/chunk-6PJRB2CF.js.map +1 -0
- package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
- package/dist/chunk-AMIR72JP.js.map +1 -0
- package/dist/chunk-FVJUUTEM.js +74 -0
- package/dist/chunk-FVJUUTEM.js.map +1 -0
- package/dist/{chunk-LH7I6SH7.js → chunk-GF3BVNLU.js} +6360 -5723
- package/dist/chunk-GF3BVNLU.js.map +1 -0
- package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
- package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
- package/dist/chunk-JOQYPRDZ.js +127 -0
- package/dist/chunk-JOQYPRDZ.js.map +1 -0
- package/dist/{chunk-A4O7GIWE.js → chunk-LYNJEOAC.js} +10 -73
- package/dist/chunk-LYNJEOAC.js.map +1 -0
- package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
- package/dist/chunk-PXLVXTLW.js.map +1 -0
- package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
- package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
- package/dist/{chunk-T5UK6YOB.js → chunk-QTSJOY54.js} +60 -17
- package/dist/chunk-QTSJOY54.js.map +1 -0
- package/dist/chunk-QVANWDPH.js +2358 -0
- package/dist/chunk-QVANWDPH.js.map +1 -0
- package/dist/{chunk-6ATE2PSM.js → chunk-R2GC6RLD.js} +7 -7
- package/dist/chunk-R2GC6RLD.js.map +1 -0
- package/dist/chunk-R2YZTCLO.js +292 -0
- package/dist/chunk-R2YZTCLO.js.map +1 -0
- package/dist/chunk-S7A5D7ZJ.js +174 -0
- package/dist/chunk-S7A5D7ZJ.js.map +1 -0
- package/dist/chunk-T3TI7GSZ.js +884 -0
- package/dist/chunk-T3TI7GSZ.js.map +1 -0
- package/dist/{chunk-RUDYOTA6.js → chunk-TUWMK62B.js} +110 -4
- package/dist/chunk-TUWMK62B.js.map +1 -0
- package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
- package/dist/chunk-VR7UPJ7C.js.map +1 -0
- package/dist/doc/index.d.ts +2334 -5
- package/dist/doc/index.js +134 -34
- package/dist/generate/index.d.ts +7 -2
- package/dist/generate/index.js +1 -1
- package/dist/imageEdit/index.d.ts +9 -6
- package/dist/imageEdit/index.js +3 -3
- package/dist/index.d.ts +12 -10
- package/dist/index.js +253 -81
- package/dist/jsonForm/index.d.ts +7 -3
- package/dist/jsonForm/index.js +9 -4
- package/dist/markdown/index.d.ts +6 -70
- package/dist/markdown/index.js +13 -9
- package/dist/narration/index.d.ts +618 -0
- package/dist/narration/index.js +82 -0
- package/dist/recommend/index.d.ts +15 -1
- package/dist/recommend/index.js +2 -2
- package/dist/schemas/index.d.ts +28 -6
- package/dist/schemas/index.js +15 -13
- package/dist/spatial/index.d.ts +0 -1
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
- package/dist/timing/index.js +5 -3
- package/dist/transform/index.d.ts +35 -24
- package/dist/transform/index.js +9 -10
- package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
- package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
- package/dist/versions/index.d.ts +2 -1
- package/dist/versions/index.js +2 -2
- package/package.json +6 -6
- package/src/__tests__/applyNarrationTiming.test.ts +190 -0
- package/src/__tests__/applyRenderStyle.test.ts +3 -3
- package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
- package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
- package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
- package/src/__tests__/asciiDiagramParse.test.ts +233 -0
- package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
- package/src/__tests__/asciiDiagramRender.test.ts +162 -0
- package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
- package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
- package/src/__tests__/asciiTimelineParse.test.ts +205 -0
- package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
- package/src/__tests__/asciiTimelineRender.test.ts +376 -0
- package/src/__tests__/attrTokens.test.ts +5 -0
- package/src/__tests__/contentContainer.test.ts +43 -0
- package/src/__tests__/coverBlock.test.ts +33 -2
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
- package/src/__tests__/dataTable.test.ts +25 -15
- package/src/__tests__/diagramBlock.test.ts +3 -3
- package/src/__tests__/diagramText.test.ts +26 -0
- package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
- package/src/__tests__/drawingBlock.test.ts +3 -3
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
- package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
- package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
- package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
- package/src/__tests__/getLayers.test.ts +32 -18
- package/src/__tests__/getLayersFallback.test.ts +8 -8
- package/src/__tests__/imageEditVersions.test.ts +2 -0
- package/src/__tests__/jsonForm.pointer.test.ts +47 -1
- package/src/__tests__/layoutBlock.test.ts +3 -3
- package/src/__tests__/majorApiTypes.test.ts +18 -0
- package/src/__tests__/markdown.test.ts +41 -0
- package/src/__tests__/markdownToDoc.test.ts +5 -2
- package/src/__tests__/matchFontFamily.test.ts +114 -0
- package/src/__tests__/materializeBlockLayers.test.ts +135 -0
- package/src/__tests__/materializeTestUtils.ts +17 -0
- package/src/__tests__/narrationAlign.test.ts +150 -0
- package/src/__tests__/narrationFeatures.test.ts +71 -0
- package/src/__tests__/narrationNuclei.test.ts +45 -0
- package/src/__tests__/narrationPacing.test.ts +189 -0
- package/src/__tests__/narrationScript.test.ts +149 -0
- package/src/__tests__/narrationSessionRepro.test.ts +62 -0
- package/src/__tests__/narrationSidecar.test.ts +88 -0
- package/src/__tests__/narrationSyllables.test.ts +65 -0
- package/src/__tests__/narrationTestSignals.ts +167 -0
- package/src/__tests__/narrationVad.test.ts +66 -0
- package/src/__tests__/resolveDocTheme.test.ts +16 -2
- package/src/__tests__/rootExports.test.ts +18 -0
- package/src/__tests__/scopedContentContainer.test.ts +20 -0
- package/src/__tests__/shapeGeometry.test.ts +49 -0
- package/src/__tests__/templateAnnotationParse.test.ts +10 -0
- package/src/__tests__/templateInputs.test.ts +69 -0
- package/src/__tests__/templateMetadata.test.ts +2 -1
- package/src/__tests__/templates.test.ts +143 -17
- package/src/__tests__/themeCompile.test.ts +49 -22
- package/src/__tests__/transformProvenance.test.ts +160 -0
- package/src/__tests__/transformV2.test.ts +40 -14
- package/src/__tests__/treeviewBattle.test.ts +76 -0
- package/src/__tests__/treeviewDetect.test.ts +168 -0
- package/src/__tests__/treeviewParse.test.ts +118 -0
- package/src/__tests__/treeviewPipeline.test.ts +183 -0
- package/src/__tests__/treeviewRender.test.ts +91 -0
- package/src/__tests__/versions.test.ts +44 -0
- package/src/doc/applyNarrationTiming.ts +244 -0
- package/src/doc/asciiDiagram/chars.ts +210 -0
- package/src/doc/asciiDiagram/detect.ts +175 -0
- package/src/doc/asciiDiagram/index.ts +38 -0
- package/src/doc/asciiDiagram/mapping.ts +225 -0
- package/src/doc/asciiDiagram/parse.ts +1095 -0
- package/src/doc/asciiDiagram/render.ts +963 -0
- package/src/doc/asciiDiagram/repair.ts +400 -0
- package/src/doc/asciiDiagram/types.ts +65 -0
- package/src/doc/asciiTimeline/detect.ts +138 -0
- package/src/doc/asciiTimeline/index.ts +26 -0
- package/src/doc/asciiTimeline/mapping.ts +43 -0
- package/src/doc/asciiTimeline/parse.ts +870 -0
- package/src/doc/asciiTimeline/render.ts +427 -0
- package/src/doc/asciiTimeline/types.ts +73 -0
- package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
- package/src/doc/audioMapping.ts +60 -46
- package/src/doc/customTemplatesFrontmatter.ts +0 -41
- package/src/doc/docToMarkdown.ts +126 -39
- package/src/doc/index.ts +76 -4
- package/src/doc/markdownToDoc.ts +135 -1
- package/src/doc/materializeBlockLayers.ts +304 -0
- package/src/doc/mediaAnnotations.ts +20 -0
- package/src/doc/resolveDocTheme.ts +8 -7
- package/src/doc/templateInputs.ts +185 -2
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
- package/src/doc/templates/coverBlock.ts +49 -13
- package/src/doc/templates/diagramBlock.ts +237 -38
- package/src/doc/templates/drawingBlock.ts +2 -2
- package/src/doc/templates/fallbackBlock.ts +1 -1
- package/src/doc/templates/index.ts +134 -279
- package/src/doc/templates/inputDescriptors.ts +20 -1
- package/src/doc/templates/metadata.ts +10 -0
- package/src/doc/templates/persistentLayers.ts +12 -126
- package/src/doc/templates/registry.ts +88 -0
- package/src/doc/templates/templateNames.ts +22 -0
- package/src/doc/templates/timelineBlock.ts +613 -0
- package/src/doc/templates/treeBlock.ts +131 -0
- package/src/doc/treeview/chars.ts +72 -0
- package/src/doc/treeview/detect.ts +145 -0
- package/src/doc/treeview/index.ts +30 -0
- package/src/doc/treeview/mapping.ts +95 -0
- package/src/doc/treeview/parse.ts +201 -0
- package/src/doc/treeview/render.ts +41 -0
- package/src/doc/treeview/types.ts +43 -0
- package/src/doc/utils/applyRenderStyle.ts +2 -9
- package/src/doc/utils/diagramText.ts +78 -0
- package/src/doc/utils/shapeGeometry.ts +157 -7
- package/src/doc/validate.ts +1 -1
- package/src/generate/templateMapper.ts +7 -0
- package/src/imageEdit/export.ts +6 -5
- package/src/imageEdit/versionPaths.ts +13 -26
- package/src/imageEdit/versions.ts +21 -100
- package/src/index.ts +1 -0
- package/src/internal/immutable.ts +58 -0
- package/src/jsonForm/index.ts +9 -1
- package/src/jsonForm/pointer.ts +68 -23
- package/src/markdown/attrTokens.ts +7 -5
- package/src/markdown/convert.ts +11 -1
- package/src/markdown/index.ts +1 -0
- package/src/markdown/stringify.ts +4 -9
- package/src/markdown/utils.ts +36 -14
- package/src/narration/align.ts +514 -0
- package/src/narration/features.ts +231 -0
- package/src/narration/index.ts +86 -0
- package/src/narration/nuclei.ts +118 -0
- package/src/narration/pacing.ts +211 -0
- package/src/narration/script.ts +239 -0
- package/src/narration/session.ts +100 -0
- package/src/narration/sidecar.ts +187 -0
- package/src/narration/syllables.ts +85 -0
- package/src/narration/trace.ts +50 -0
- package/src/narration/types.ts +299 -0
- package/src/narration/vad.ts +131 -0
- package/src/recommend/numberHighlight.ts +25 -0
- package/src/recommend/templates.ts +108 -12
- package/src/schemas/BlockTemplates.ts +156 -7
- package/src/schemas/Doc.ts +72 -9
- package/src/schemas/Media.ts +12 -2
- package/src/schemas/Theme.ts +45 -25
- package/src/schemas/Viewport.ts +2 -2
- package/src/schemas/fontStacks.ts +79 -0
- package/src/schemas/themeCompile.ts +15 -0
- package/src/schemas/themeConstants.ts +2 -0
- package/src/schemas/themeLibrary.ts +25 -19
- package/src/schemas/themeValidator.ts +1 -1
- package/src/spatial/Geohash.ts +0 -3
- package/src/storage/ContentContainer.ts +17 -9
- package/src/storage/ScopedContentContainer.ts +45 -15
- package/src/transform/applyTransform.ts +5 -5
- package/src/transform/index.ts +3 -1
- package/src/transform/registry.ts +169 -49
- package/src/transform/templateSelector.ts +21 -2
- package/src/transform/timingAllocator.ts +152 -21
- package/src/transform/types.ts +14 -1
- package/src/versions/gitignore.ts +34 -0
- package/src/versions/index.ts +2 -0
- package/src/versions/operations.ts +18 -104
- package/src/versions/paths.ts +13 -28
- package/src/versions/snapshotStore.ts +202 -0
- package/src/versions/types.ts +3 -1
- package/dist/chunk-2OIBZYKP.js.map +0 -1
- package/dist/chunk-6ATE2PSM.js.map +0 -1
- package/dist/chunk-A4O7GIWE.js.map +0 -1
- package/dist/chunk-DLXZMS5K.js.map +0 -1
- package/dist/chunk-HWVFJAAH.js.map +0 -1
- package/dist/chunk-IMSCRLLV.js.map +0 -1
- package/dist/chunk-JELIRVDP.js +0 -24
- package/dist/chunk-JELIRVDP.js.map +0 -1
- package/dist/chunk-KKNUBQ6Y.js.map +0 -1
- package/dist/chunk-LDQ2HJIX.js.map +0 -1
- package/dist/chunk-LH7I6SH7.js.map +0 -1
- package/dist/chunk-RUDYOTA6.js.map +0 -1
- package/dist/chunk-T5UK6YOB.js.map +0 -1
- package/dist/chunk-TEEEILMP.js.map +0 -1
- package/dist/chunk-UY7KGQ5R.js +0 -192
- package/dist/chunk-UY7KGQ5R.js.map +0 -1
- package/dist/chunk-VLJJHDAC.js +0 -218
- package/dist/chunk-VLJJHDAC.js.map +0 -1
- package/dist/chunk-VWUFZ6ZG.js.map +0 -1
- package/dist/story/index.d.ts +0 -1777
- package/dist/story/index.js +0 -273
- package/src/doc/getLayers.ts +0 -195
- /package/dist/{story → narration}/index.js.map +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/doc/templates/persistentLayers.ts","../src/doc/templates/templateNames.ts","../src/doc/utils/themeUtils.ts","../src/doc/templates/captionUtils.ts","../src/doc/templates/titleBlock.ts","../src/doc/templates/sectionHeader.ts","../src/doc/templates/accentImage.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/featureBlock.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/utils/diagramText.ts","../src/doc/templates/diagramLayout.ts","../src/doc/templates/diagramBlock.ts","../src/doc/templates/treeBlock.ts","../src/doc/templates/timelineBlock.ts","../src/doc/templates/drawingLayout.ts","../src/doc/templates/drawingBlock.ts","../src/doc/templates/layoutLayout.ts","../src/doc/templates/layoutBlock.ts","../src/doc/templates/tokens/resolveTokens.ts","../src/doc/templates/customTemplate.ts","../src/doc/templates/registry.ts","../src/doc/utils/applyRenderStyle.ts","../src/doc/utils/nearest.ts","../src/doc/templates/inputDescriptors.ts","../src/doc/templates/fallbackBlock.ts","../src/doc/materializeBlockLayers.ts","../src/doc/templates/metadata.ts","../src/doc/templates/coverBlock.ts","../src/doc/templates/index.ts","../src/doc/asciiDiagram/types.ts","../src/doc/asciiDiagram/mapping.ts","../src/doc/asciiTimeline/mapping.ts","../src/doc/treeview/mapping.ts","../src/doc/templateInputs.ts","../src/doc/customTemplatesFrontmatter.ts","../src/doc/customThemesFrontmatter.ts","../src/doc/structuredData.ts","../src/doc/standaloneAnnotation.ts","../src/doc/mediaAnnotations.ts","../src/doc/annotationBlocks.ts","../src/doc/markdownToDoc.ts","../src/narration/syllables.ts","../src/narration/script.ts","../src/narration/sidecar.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 VignetteConfig,\n AmbientGradientConfig,\n TitleCaptionConfig,\n CornerBrandingConfig,\n ProgressIndicatorConfig,\n} from '../../schemas/BlockTemplates.js';\nimport type { Theme } from '../../schemas/Theme.js';\nimport { cloneData } from '../../internal/immutable.js';\nimport { isPersistentLayerTemplate } from '../../schemas/BlockTemplates.js';\nimport { oklchDarken, withAlpha } from '../../schemas/colorUtils.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 presets deepen within their own hue — ending in the shared navy\n // made warm themes drift cold halfway down the frame.\n 'warm-sunset': 'linear-gradient(135deg, rgba(124,58,48,0.9) 0%, rgba(46,20,16,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(30,22,15,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. `blur` softens the photo into an atmosphere layer\n // (the ImageLayer renderer over-scans blurred images so soft edges never\n // reveal the frame).\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 ...(config.blur != null && config.blur > 0 ? { blur: config.blur } : {}),\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 // 'noise' is film grain: a full-bleed rect whose paint is replaced by a\n // static feTurbulence field clipped to the rect (see ShapeFilter).\n if (config.pattern === 'noise') {\n return {\n type: 'shape',\n id: 'persistent-grain',\n content: {\n shape: 'rect',\n fill: '#000000',\n filter: { type: 'noise', opacity: config.opacity ?? 0.05 },\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n }\n\n // dots / grid / diagonal render as native SVG <pattern> fills.\n const opacity = config.opacity ?? 0.06;\n return {\n type: 'shape',\n id: 'persistent-bg-pattern',\n content: {\n shape: 'rect',\n pattern: {\n kind: config.pattern,\n color: config.color ?? '#ffffff',\n size: Math.round(24 * (config.scale ?? 1)),\n opacity,\n },\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n\n/**\n * Expand a vignette config: transparent center darkening toward the frame\n * edges. Rides the CSS-gradient rect path in the renderer.\n */\nfunction expandVignette(config: VignetteConfig): Layer {\n const strength = Math.max(0, Math.min(1, config.strength ?? 0.3));\n const color = config.color ?? '#000000';\n const edge = withAlpha(color, strength);\n const clear = withAlpha(color, 0);\n return {\n type: 'shape',\n id: 'persistent-vignette',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at center, ${clear} 55%, ${edge} 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n}\n\n/**\n * Expand an ambient drifting gradient: an oversized surface gradient with\n * a very slow Ken Burns loop. Deterministic (no randomness).\n */\nfunction expandAmbientGradient(config: AmbientGradientConfig, theme?: Theme): Layer {\n const from = config.from ?? theme?.colors.backgroundLight ?? '#1a202c';\n const to = config.to ?? (theme ? oklchDarken(theme.colors.background, 0.04) : '#0f141d');\n return {\n type: 'shape',\n id: 'persistent-ambient-gradient',\n content: {\n shape: 'rect',\n fill: `linear-gradient(150deg, ${from} 0%, ${to} 100%)`,\n },\n // Oversized so the slow pan never reveals the frame edge.\n position: { x: '-5%', y: '-5%', width: '110%', height: '110%' },\n animation: { type: 'slowZoom', panDirection: 'left', duration: config.duration ?? 40 },\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, theme?: Theme): Layer[] {\n // If already a raw Layer, return an owned copy.\n if (!isPersistentLayerTemplate(layer)) {\n return [cloneData(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 'vignette':\n return [expandVignette(config)];\n case 'ambientGradient':\n return [expandAmbientGradient(config, theme)];\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(\n layers: PersistentLayer[] | undefined,\n theme?: Theme,\n): 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[]>(\n (acc, layer) => acc.concat(expandPersistentLayer(layer, theme)),\n [],\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/**\n * Resolve the effective persistent-layer config for a doc: the doc's own\n * config wins **wholesale** when present; only docs with no persistent\n * layers inherit the theme's.\n *\n * Doc-wins-wholesale (rather than merging) protects pre-baked documents\n * that carry their own background/branding layers — merging a theme's\n * atmosphere on top of those would double up backgrounds and stack\n * overlays the doc author never saw.\n */\nexport function resolvePersistentLayers(\n doc: { persistentLayers?: PersistentLayerConfig },\n theme: Theme,\n): PersistentLayerConfig | undefined {\n const docConfig = doc.persistentLayers;\n const hasDocLayers =\n !!docConfig &&\n ((docConfig.bottomLayers?.length ?? 0) > 0 || (docConfig.topLayers?.length ?? 0) > 0);\n if (hasDocLayers) return docConfig;\n const themeConfig = theme.persistentLayers;\n const hasThemeLayers =\n !!themeConfig &&\n ((themeConfig.bottomLayers?.length ?? 0) > 0 || (themeConfig.topLayers?.length ?? 0) > 0);\n return hasThemeLayers ? themeConfig : docConfig;\n}\n\n/**\n * Compose a block's layers between pre-expanded persistent bottom/top\n * layers, honoring the per-block `useBottomLayer` / `useTopLayer` opt-outs.\n * Shared persistent-layer primitive used by `materializeBlockLayers`.\n */\nexport function wrapWithPersistentLayers(\n layers: Layer[],\n block: { useBottomLayer?: boolean; useTopLayer?: boolean },\n bottomLayers: Layer[],\n topLayers: Layer[],\n): Layer[] {\n if (bottomLayers.length === 0 && topLayers.length === 0) return layers;\n const useBottom = block.useBottomLayer !== false;\n const useTop = block.useTopLayer !== false;\n // Each expanded block owns its persistent layers. This prevents a renderer\n // (or a later timing/style pass) from mutating the caller's config or a\n // sibling block through a shared layer reference.\n return [\n ...(useBottom ? bottomLayers.map((layer) => cloneData(layer)) : []),\n ...layers,\n ...(useTop ? topLayers.map((layer) => cloneData(layer)) : []),\n ];\n}\n","/** Canonical aliases for historical template ids. Kept dependency-free. */\nexport const TEMPLATE_ALIASES: Readonly<Record<string, string>> = Object.freeze({\n titleBlock: 'title',\n quoteBlock: 'quote',\n mapBlock: 'map',\n listBlock: 'list',\n diagramBlock: 'diagram',\n diagramNode: 'diagram',\n});\n\n/** Resolve a historical template id to its canonical registry key. */\nexport function resolveTemplateName(name: string): string {\n return TEMPLATE_ALIASES[name] ?? name;\n}\n\n/** Templates that consume their child headings rather than rendering them. */\nexport const CONTAINER_TEMPLATES: ReadonlySet<string> = new Set(['diagram', 'drawing', 'layout']);\n\n/** True when `name` (or its alias) consumes child blocks. */\nexport function isContainerTemplate(name: string | undefined): boolean {\n return !!name && CONTAINER_TEMPLATES.has(resolveTemplateName(name));\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 { Animation, AnimationType, ImageTreatment } from '../../schemas/Doc.js';\nimport { resolveFontFamily } from '../../schemas/fontStacks.js';\nimport { oklchDarken, withAlpha } from '../../schemas/colorUtils.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, resolved to a CSS string.\n * Templates call this to set `fontFamily` on text layers.\n *\n * Theme fields are structured `FontFamily` references (`{ stackId }` or\n * `{ custom: { name, fallback } }`); this helper resolves them to a\n * CSS font-family string with 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 resolveFontFamily(typography.titleFont, FALLBACK_TITLE);\n case 'body':\n return resolveFontFamily(typography.bodyFont, FALLBACK_BODY);\n case 'mono':\n return resolveFontFamily(typography.monoFont, 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 * Theme-aware entrance animation for a template layer.\n *\n * The theme's `renderStyle.defaultTextAnimation` / `defaultImageAnimation`\n * overrides the entrance *type*; the template keeps its authored duration,\n * delay, and stagger. Templates opt in per layer:\n *\n * ```ts\n * animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 })\n * ```\n *\n * `slowZoom` is excluded — it's an ambient treatment handled by the\n * `applyRenderStyleToLayers` post-pass, not an entrance.\n */\nexport function themedEntrance(\n context: TemplateContext,\n layerType: 'text' | 'image',\n fallback: Animation,\n): Animation {\n const type = getDefaultAnimation(context, layerType);\n if (!type || type === 'slowZoom' || type === fallback.type) return fallback;\n return { ...fallback, type };\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 * Resolve the effective photographic treatment for a block's imagery.\n *\n * Precedence: the block's `imageTreatment` override ('none' opts out, a\n * type forces that grade) → the theme's `style.imageTreatment` → none.\n * Duotone tints default to the theme primary. Templates pass the result\n * straight into `ImageLayer.content.treatment`.\n */\nexport function themedImageTreatment(\n context: TemplateContext,\n override?: 'none' | 'mono' | 'duotone' | 'warm' | 'cool',\n): ImageTreatment | undefined {\n if (override === 'none') return undefined;\n const themeTreatment = context.theme.style.imageTreatment;\n const base: ImageTreatment | undefined = override\n ? { type: override, strength: themeTreatment?.strength }\n : themeTreatment;\n if (!base || base.type === 'none') return undefined;\n if (base.type === 'duotone' && !base.color) {\n return { ...base, color: context.theme.colors.primary };\n }\n return base;\n}\n\n/**\n * Theme-derived surface gradient for text-first templates.\n *\n * Runs from the theme's alternate surface into a slightly deepened\n * background, staying inside the theme's own hue. Templates must use\n * this instead of hard-coding a dark endpoint (`#0f1520`, `#1e2030`, …):\n * hard-coded navy endpoints made light themes render dark panels and\n * warm themes drift cold halfway down the block.\n */\nexport function themedSurfaceGradient(context: TemplateContext, angleDeg = 160): string {\n const { background, backgroundLight } = context.theme.colors;\n return `linear-gradient(${angleDeg}deg, ${backgroundLight} 0%, ${oklchDarken(background, 0.04)} 100%)`;\n}\n\n/**\n * Translucent overlay tint derived from the theme background, for text\n * bands/scrims painted over imagery. Light themes get a light scrim with\n * dark theme text on top; dark themes get the familiar dark scrim —\n * `theme.colors.text` stays legible on it by construction.\n */\nexport function themedScrim(context: TemplateContext, alpha?: number): string {\n const a = alpha ?? Math.max(0.55, getOverlayOpacity(context));\n return withAlpha(context.theme.colors.background, a);\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 * 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/**\n * Estimate the rendered height (px) of a wrapped text block.\n *\n * Templates are pure functions with no access to real text metrics, but\n * stacked lockups (quote + attribution, fact + explanation + source) need\n * to place each element relative to the previous one instead of at fixed\n * slots — fixed slots leave 200px voids for short content and collide for\n * long content. The 0.52 average-glyph-width factor is tuned for the\n * sans/serif faces the built-in themes use; it only needs to be right\n * within ~20% for spacing purposes.\n */\nexport function estimateTextHeight(\n text: string,\n fontSizePx: number,\n maxWidthPx: number,\n lineHeight: number,\n): number {\n const avgCharWidth = fontSizePx * 0.52;\n const charsPerLine = Math.max(8, Math.floor(maxWidthPx / avgCharWidth));\n const lines = Math.max(1, Math.ceil(text.length / charsPerLine));\n return lines * fontSizePx * lineHeight;\n}\n","/**\n * Title Block Template\n *\n * Large title with optional subtitle for doc intros.\n * Centered text with fade-in animations, composed as one lockup:\n * accent rule, title, and subtitle are spaced from the title's\n * estimated height instead of fixed slots that collide on wrap.\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 {\n getTemplateHint,\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n} from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.js';\nimport { estimateTextHeight } from './captionUtils.js';\n\n/**\n * Hint schema published for the theme validator + future customizer hint UI.\n * Themes may set `templateHints.title` entries matching these keys.\n */\nexport const titleBlockHintSchema = {\n /** Whether to render a thin accent line above the title. Default: theme-dependent. */\n showAccentLine: { type: 'boolean' as const, default: true },\n} as const;\n\nexport function titleBlock(input: TitleBlockInput, context: TemplateContext): Layer[] {\n const { title, subtitle, backgroundColor } = input;\n const { theme, layout, viewport } = context;\n\n // Scale font sizes for viewport\n const titleFontSize = themedFontSize(96, context, true);\n const subtitleFontSize = themedFontSize(36, context, false);\n\n const baseBg = backgroundColor || theme.colors.primary;\n\n // Estimate the title's rendered height so the rule and subtitle key off\n // its real extent — fixed slots let the rule overlap the ascenders and\n // stranded the subtitle when the title wrapped.\n const maxWidthPx = (parseFloat(layout.maxTextWidth) / 100) * viewport.width;\n const titleH = estimateTextHeight(title, titleFontSize, maxWidthPx, 1.15);\n const titleYPct = subtitle ? 42 : 48;\n const px = (v: number) => (v / viewport.height) * 100;\n\n const layers: Layer[] = [\n // Background — theme surface with a soft radial accent tint. The tint\n // is translucent so the theme's text color keeps its contrast with the\n // surface; a full-strength `primary` hotspot behind the title made\n // dark-primary light themes unreadable.\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: theme.colors.background,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n {\n type: 'shape',\n id: 'bg-tint',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 40%, ${withAlpha(baseBg, 0.32)} 0%, ${withAlpha(baseBg, 0)} 75%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n // Subtle decorative line, clear above the title's ascenders. Themes can\n // hide it via `templateHints.title.showAccentLine: false` (the line is\n // decorative; title/subtitle positions don't depend on it).\n if (getTemplateHint(context, 'title', 'showAccentLine', true)) {\n layers.push({\n type: 'shape',\n id: 'accent-line',\n content: {\n shape: 'rect',\n fill: withAlpha(theme.colors.text, 0.3),\n },\n position: {\n x: '44%',\n y: `${titleYPct - px(titleH / 2 + 56)}%`,\n width: '12%',\n height: '3px',\n },\n });\n }\n\n layers.push(\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: shouldUseShadow(context),\n },\n },\n position: {\n x: '50%',\n y: `${titleYPct}%`,\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 }),\n },\n );\n\n // Add subtitle if provided — hangs from the title's estimated bottom edge\n if (subtitle) {\n const subH = estimateTextHeight(subtitle, subtitleFontSize, maxWidthPx, 1.5);\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: `${titleYPct + px(titleH / 2 + 56 + subH / 2)}%`,\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 {\n resolveColorScheme,\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n themedScrim,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\n\nexport function sectionHeader(input: SectionHeaderInput, context: TemplateContext): Layer[] {\n const { title = '', colorScheme = 'blue', imageSrc, imageAlt, ambientMotion } = input;\n const { theme, layout } = context;\n\n const treatment = themedImageTreatment(context, input.imageTreatment);\n const colors = resolveColorScheme(context, colorScheme);\n\n // Scale font sizes for viewport. Section dividers are the loudest\n // interstitial in a doc, so the title sits a step above ordinary\n // content-block headings.\n const titleFontSize = themedFontSize(84, 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 ...(treatment ? { treatment } : {}),\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 // Theme-tinted overlay for text readability — light themes get a\n // light scrim with dark theme text, dark themes the familiar dark one.\n layers.push({\n type: 'shape',\n id: 'overlay',\n content: {\n shape: 'rect',\n fill: themedScrim(context),\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 — theme text over the theme-tinted scrim (readable by\n // construction), scheme text on the solid-color fallback\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 ? theme.colors.text : colors.text,\n textAlign: 'center',\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: '50%',\n y: '50%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n animation: themedEntrance(context, 'text', { 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 {\n Layer,\n ImageLayer,\n ImageTreatment,\n ShapeLayer,\n Animation,\n} 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(\n accent: AccentImage,\n slideId: string,\n treatment?: ImageTreatment,\n): 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(\n createStripImage(src, alt, 'left', slideId, ambientMotion, credit, license, treatment),\n );\n layers.push(createStripGradient('left', slideId));\n break;\n\n case 'right-strip':\n layers.push(\n createStripImage(src, alt, 'right', slideId, ambientMotion, credit, license, treatment),\n );\n layers.push(createStripGradient('right', slideId));\n break;\n\n case 'bottom-strip':\n layers.push(\n createBottomStripImage(src, alt, slideId, ambientMotion, credit, license, treatment),\n );\n layers.push(createBottomStripGradient(slideId));\n break;\n\n case 'corner-inset':\n layers.push(\n createCornerInsetImage(src, alt, slideId, ambientMotion, credit, license, treatment),\n );\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 treatment?: ImageTreatment,\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 ...(treatment ? { treatment } : {}),\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 treatment?: ImageTreatment,\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 ...(treatment ? { treatment } : {}),\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 treatment?: ImageTreatment,\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 ...(treatment ? { treatment } : {}),\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 * 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 {\n resolveColorScheme,\n getTemplateHint,\n getThemeFont,\n shouldUseShadow,\n themedFontSize,\n themedSurfaceGradient,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\n/**\n * Hint schema published for the theme validator + future customizer hint UI.\n * Themes may set `templateHints.statHighlight` entries matching these keys.\n */\nexport const statHighlightHintSchema = {\n /** Entrance style for the stat number. 'subtle' or 'dramatic'. */\n entrance: {\n type: 'string' as const,\n options: ['subtle', 'dramatic'] as const,\n default: 'subtle',\n },\n} as const;\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 = themedFontSize(148, context, true);\n const descFontSize = themedFontSize(32, context, false);\n const detailFontSize = themedFontSize(26, context, false);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 180))];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('36%', accentLayout),\n anchor: 'center',\n },\n animation:\n getTemplateHint<string>(context, 'statHighlight', 'entrance', 'subtle') === 'dramatic'\n ? { type: 'zoomIn', duration: 0.4 }\n : { type: 'zoomIn', duration: 0.6 },\n });\n\n // Description — smaller and understated beneath the stat. Sits close\n // under the stat (the ~26% fixed gap it used to get read as two\n // unrelated elements floating in the panel).\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.5,\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('54%', 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 // Scheme *text* rather than *accent*: accents in the built-in\n // schemes are tuned as chart/fill colors and drop below legible\n // contrast as body copy on light surfaces.\n color: colors.text,\n textAlign: 'center',\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('66%', accentLayout),\n width: accentLayout.textWidth,\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, composed as one\n * vertically-centered lockup: the attribution hangs a fixed distance\n * below the quote's estimated bottom edge instead of being pinned to a\n * far-away layout slot.\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 {\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n themedSurfaceGradient,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer, estimateTextHeight } from './captionUtils.js';\n\nexport function quoteBlock(input: QuoteBlockInput, context: TemplateContext): Layer[] {\n const { quote, attribution, accentImage } = input;\n const { theme, viewport } = 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 = themedFontSize(48, context, true);\n const attrFontSize = themedFontSize(26, context, false);\n const quoteLineHeight = Math.max(theme.typography.titleLineHeight ?? 1.4, 1.25);\n\n // Decorative quotation mark font size\n const decorativeQuoteFontSize = themedFontSize(280, context, true);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 160))];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\n }\n\n // Decorative opening quotation mark — oversized, low-opacity behind the\n // quote. Derived from the theme text color so it stays a subtle ornament\n // on light and dark surfaces alike (a hard-coded white glyph was\n // invisible on both).\n layers.push({\n type: 'text',\n id: 'deco-quote',\n content: {\n text: '“',\n style: {\n fontSize: decorativeQuoteFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: withAlpha(theme.colors.text, 0.09),\n textAlign: 'center',\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('26%', accentLayout),\n anchor: 'center',\n },\n });\n\n // Quote text — optically centered, nudged up slightly when an\n // attribution hangs below it.\n const quoteYPct = attribution ? 45 : 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: quoteLineHeight,\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${quoteYPct}%`, accentLayout),\n anchor: 'center',\n width: accentLayout.textWidth,\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 }),\n });\n\n // Attribution hangs just below the quote's estimated bottom edge, so\n // the two read as one lockup instead of the attribution stranding near\n // the bottom of the block.\n if (attribution) {\n const quoteWidthPx = (parseFloat(accentLayout.textWidth) / 100) * viewport.width;\n const quoteHeightPx = estimateTextHeight(quote, quoteFontSize, quoteWidthPx, quoteLineHeight);\n const gapPx = quoteFontSize * 1.7;\n const attrYPct = Math.min(\n 82,\n quoteYPct + ((quoteHeightPx / 2 + gapPx) / viewport.height) * 100,\n );\n\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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${attrYPct}%`, 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, composed as one\n * vertically-centered lockup: each element is placed relative to the\n * estimated height of the one above it, so short content doesn't leave\n * fixed-slot voids and long content doesn't collide.\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 {\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n themedSurfaceGradient,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\nimport { createBackgroundLayer, estimateTextHeight } from './captionUtils.js';\n\nexport function factCard(input: FactCardInput, context: TemplateContext): Layer[] {\n const { fact, explanation, source, accentImage } = input;\n const { theme, viewport } = 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. The explanation sits at ~60% of the fact\n // size — large enough to read comfortably as the secondary line while still\n // clearly subordinate to the headline fact.\n const factFontSize = themedFontSize(56, context, true);\n const explainFontSize = themedFontSize(34, context, false);\n const sourceFontSize = themedFontSize(20, context, false);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 170))];\n\n // Add accent image layers (behind text, after background)\n if (accentImage) {\n layers.push(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\n }\n\n // Estimate each element's height so the stack reads as one lockup.\n const textWidthPx = (parseFloat(accentLayout.textWidth) / 100) * viewport.width;\n const factH = estimateTextHeight(fact, factFontSize, textWidthPx, 1.3);\n const explainH = estimateTextHeight(explanation, explainFontSize, textWidthPx, 1.5);\n const sourceH = source ? sourceFontSize * 1.4 : 0;\n const gap = factFontSize * 0.9;\n const sourceGap = source ? explainFontSize * 1.1 : 0;\n const totalH = factH + gap + explainH + sourceGap + sourceH;\n\n // Center the lockup slightly above the geometric middle (optical center).\n const groupTopPct = 47 - (totalH / 2 / viewport.height) * 100;\n const pct = (px: number) => groupTopPct + (px / viewport.height) * 100;\n\n const factY = pct(factH / 2);\n const explainY = pct(factH + gap + explainH / 2);\n const sourceY = pct(factH + gap + explainH + sourceGap + sourceH / 2);\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.3,\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${factY}%`, accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: themedEntrance(context, 'text', { 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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${explainY}%`, accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: themedEntrance(context, 'text', { 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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY(`${sourceY}%`, 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 {\n resolveColorScheme,\n getThemeFont,\n themedEntrance,\n themedFontSize,\n themedSurfaceGradient,\n} from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.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. The header is the block's\n // title, so it sits a step ABOVE the column labels in the hierarchy —\n // it used to render smaller and dimmer than the labels, which read as\n // an inverted hierarchy.\n const headerFontSize = themedFontSize(36, context, true);\n const labelFontSize = themedFontSize(44, context, true);\n const sublabelFontSize = themedFontSize(22, context, false);\n\n // Panels drop below the header band so the title never overlaps them.\n const panelTop = header && !isStacked ? 22 : 15;\n const panelHeight = header && !isStacked ? 64 : 70;\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: themedSurfaceGradient(context, 135),\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n if (!isStacked) {\n // Column background panels — tinted from the theme text color so\n // they stay visible on light and dark surfaces alike.\n const panelFill = withAlpha(theme.colors.text, 0.05);\n layers.push({\n type: 'shape',\n id: 'left-panel',\n content: {\n shape: 'rect',\n fill: panelFill,\n borderRadius: 12,\n },\n position: { x: '3%', y: `${panelTop}%`, width: '44%', height: `${panelHeight}%` },\n });\n\n layers.push({\n type: 'shape',\n id: 'right-panel',\n content: {\n shape: 'rect',\n fill: panelFill,\n borderRadius: 12,\n },\n position: { x: '53%', y: `${panelTop}%`, width: '44%', height: `${panelHeight}%` },\n });\n }\n\n // Header position adjusts based on layout — always clear of the panels.\n const headerY = isStacked ? '8%' : '12%';\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 fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: headerY, anchor: 'center' },\n animation: themedEntrance(context, 'text', { 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 the panels.\n const panelCenter = panelTop + panelHeight / 2;\n leftY = `${panelCenter - 4}%`;\n leftSublabelY = `${panelCenter + 7}%`;\n rightY = `${panelCenter - 4}%`;\n rightSublabelY = `${panelCenter + 7}%`;\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: themedEntrance(context, 'text', { 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 — sized to fit inside the gutter\n // between the panels (a 120px glyph used to cross both panel edges),\n // tinted from the theme text color so it shows on any surface.\n const connectorFontSize = themedFontSize(64, context, true);\n const connectorY = isStacked ? '48%' : `${panelTop + panelHeight / 2}%`;\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: withAlpha(theme.colors.text, 0.45),\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: themedEntrance(context, 'text', { 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 {\n getThemeFont,\n shouldUseShadow,\n themedFontSize,\n themedSurfaceGradient,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { oklchDarken, relativeLuminance } from '../../schemas/colorUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\n\n/**\n * Mood accents tint the hero date, not the surface — the surface always\n * comes from the theme. (Hard-coded dark mood panels used to turn light\n * and warm themes into a cold navy slide.)\n */\nconst MOOD_ACCENTS = {\n neutral: '#63b3ed',\n somber: '#e53e3e',\n celebratory: '#68d391',\n};\n\nexport function dateEvent(input: DateEventInput, context: TemplateContext): Layer[] {\n const { date, description, footer, mood = 'neutral', accentImage } = input;\n const { theme } = context;\n // Deepen the mood accent on light surfaces so the hero date keeps contrast.\n const moodAccent = MOOD_ACCENTS[mood];\n const dateColor =\n relativeLuminance(theme.colors.background) > 0.5 ? oklchDarken(moodAccent, 0.25) : moodAccent;\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 = themedFontSize(96, context, true);\n const descFontSize = themedFontSize(30, context, false);\n const footerFontSize = themedFontSize(26, context, false);\n\n const layers: Layer[] = [\n // Background — theme surface gradient (diagonal to differentiate\n // from other text templates)\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: themedSurfaceGradient(context, 135),\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(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\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: dateColor,\n shadow: shouldUseShadow(context),\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: theme.colors.text,\n textAlign: 'center',\n lineHeight: 1.6,\n shadow: shouldUseShadow(context),\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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('72%', 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 {\n getThemeFont,\n shouldUseShadow,\n themedFontSize,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.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 const treatment = themedImageTreatment(context, input.imageTreatment);\n\n // Scale font sizes for viewport\n const captionFontSize = themedFontSize(30, context, false);\n const titleFontSize = themedFontSize(96, context, true);\n const subtitleFontSize = themedFontSize(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 ...(treatment ? { treatment } : {}),\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: imageAnimation,\n },\n ];\n\n // Scrim gradients are tinted from the theme background so the theme\n // text color painted on top stays readable by construction — a fixed\n // black scrim put dark theme text on a dark band in light themes.\n const bg = theme.colors.background;\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, ${withAlpha(bg, 0.85)} 0%, ${withAlpha(bg, 0.45)} 40%, ${withAlpha(bg, 0.1)} 70%, ${withAlpha(bg, 0)} 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: shouldUseShadow(context),\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 // Compact caption band raised above media controls. Long archival captions\n // are clamped so they don't sprawl across the image.\n layers.push({\n type: 'shape',\n id: 'caption-gradient',\n content: {\n shape: 'rect',\n fill: `linear-gradient(90deg, ${withAlpha(bg, 0)}, ${withAlpha(bg, 0.78)} 16%, ${withAlpha(bg, 0.78)} 84%, ${withAlpha(bg, 0)})`,\n },\n position: {\n x: 0,\n y: '68%',\n width: '100%',\n height: '16%',\n },\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: shouldUseShadow(context),\n lineHeight: 1.18,\n maxLines: 2,\n },\n },\n position: {\n x: '50%',\n y: '74%',\n anchor: 'center',\n width: '78%',\n },\n animation: { type: 'fadeIn', duration: 1.5, delay: 0.5 },\n });\n }\n\n return layers;\n}\n","/**\n * Feature Block Templates — `leftFeature` and `rightFeature`\n *\n * Pairs a \"feature\" image on one side of the block with a title + body\n * paragraph on the other. The two templates are mirror images, so the\n * actual layer-builder lives here once and the per-side template files\n * just call it with a `side` parameter.\n *\n * Used for editorial layouts like product highlights, profile cards,\n * and section intros where a single image deserves to sit next to a\n * short text block rather than behind it (which is what\n * `imageWithCaption` does).\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type {\n LeftFeatureInput,\n RightFeatureInput,\n TemplateContext,\n} from '../../schemas/BlockTemplates.js';\nimport {\n getThemeFont,\n themedEntrance,\n themedFontSize,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\n\ntype FeatureInput = LeftFeatureInput | RightFeatureInput;\n\n/**\n * Build the layer list for either feature template. Layers are in\n * back-to-front order: background, image, then text.\n */\nfunction buildFeatureLayers(\n input: FeatureInput,\n context: TemplateContext,\n side: 'left' | 'right',\n): Layer[] {\n const { imageSrc, imageAlt, imageWidth, imageHeight, title, body } = input;\n const { theme, layout } = context;\n\n const treatment = themedImageTreatment(context, input.imageTreatment);\n // Treat the image as \"sized\" when the host gave us an explicit width\n // or height — that's our cue that the user resized the image in the\n // editor and we should respect that as a sizing hint instead of\n // stretching the image to fill the whole half.\n const sized = (imageWidth ?? 0) > 0 || (imageHeight ?? 0) > 0;\n // In portrait the image stacks above the text rather than splitting\n // horizontally — same flag the twoColumn template uses, so the two\n // behave consistently on narrow viewports.\n const stack = layout.stackColumns;\n\n const titleFontSize = themedFontSize(48, context, true);\n const bodyFontSize = themedFontSize(24, context, false);\n\n // Image takes the full left or right half. The text column gets the\n // opposite half, with a comfortable inset so the text doesn't kiss\n // the image edge or the card border. All values are percentages of\n // the block viewport so they scale with the card size.\n //\n // When the image is \"sized\" we shrink it inside its half: the half\n // still claims the space (so the text column stays the same width\n // and the layout doesn't shift around when dimensions are toggled)\n // but the image itself sits centered with padding around it. The\n // sized box uses a square envelope sized to the smaller dimension of\n // its half so the image breathes regardless of viewport aspect.\n let imgX: string;\n let imgY: string;\n let imgW: string;\n let imgH: string;\n let imageFit: 'cover' | 'contain';\n if (stack) {\n imgX = '0';\n imgY = '0';\n imgW = '100%';\n imgH = '50%';\n imageFit = sized ? 'contain' : 'cover';\n } else if (sized) {\n // 90% of the half (with explicit aspect via fit='contain') so the\n // image keeps its natural proportions and never touches the card\n // edges. We don't try to honor the literal pixel value — block\n // viewports are designed in their own coordinate space — but the\n // *intent* (smaller image, padded, centered) is what comes through.\n const halfStart = side === 'left' ? 5 : 55; // %\n imgX = `${halfStart}%`;\n imgY = '5%';\n imgW = '40%';\n imgH = '90%';\n imageFit = 'contain';\n } else {\n imgX = side === 'left' ? '0' : '50%';\n imgY = '0';\n imgW = '50%';\n imgH = '100%';\n imageFit = 'cover';\n }\n\n // Text-column geometry. `textX` is the LEFT edge of the column when\n // the side is \"left\" (image left, text right); when the side is\n // \"right\" the column occupies the left half, inset from the card edge.\n // The mirror lives in the layout only — fully right-aligned\n // (ragged-left) running text on rightFeature was genuinely hard to read.\n const COLUMN_INSET = 4; // % of block width — padding from card edge / divider\n const textColumnWidth = stack ? 90 : 42;\n const textX = stack\n ? `${(100 - textColumnWidth) / 2}%`\n : side === 'left'\n ? `${50 + COLUMN_INSET}%` // text column starts just past the divider\n : `${COLUMN_INSET + 2}%`; // left edge of the left-half text column\n\n // Stack the title above the body, with the pair vertically centered\n // in the text column. The title sits 8% above center; body sits 2%\n // below — these offsets keep both lines visible at the small card\n // sizes used by the inline preview gutter without overflowing.\n const titleY = stack ? '60%' : body ? '42%' : '50%';\n const bodyY = stack ? '78%' : title ? '55%' : '50%';\n const textAnchor = 'top-left';\n const textAlign = 'left' as const;\n\n // Paint our own background so the text column has a theme-paired\n // surface to sit on. The host wrapper's surface isn't always theme-\n // aware (e.g. the InlinePreviewGutter card uses a fixed light SVG\n // background), and `theme.colors.text` is only guaranteed legible\n // against `theme.colors.background` — themes like Gezellig pair\n // cream text with a dark warm-brown background, which would\n // disappear on a light wrapper. Matching the convention every other\n // text-bearing template uses (see twoColumn / listBlock).\n const layers: Layer[] = [\n {\n type: 'shape',\n id: 'feature-bg',\n content: { shape: 'rect', fill: theme.colors.background },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n if (imageSrc) {\n layers.push({\n type: 'image',\n id: 'feature-image',\n content: {\n src: imageSrc,\n alt: imageAlt ?? title ?? '',\n fit: imageFit,\n ...(treatment ? { treatment } : {}),\n },\n position: { x: imgX, y: imgY, width: imgW, height: imgH },\n });\n }\n\n if (title) {\n layers.push({\n type: 'text',\n id: 'feature-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,\n lineHeight: 1.2,\n },\n },\n position: {\n x: textX,\n y: titleY,\n anchor: textAnchor,\n width: `${textColumnWidth}%`,\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 0.8 }),\n });\n }\n\n if (body) {\n layers.push({\n type: 'text',\n id: 'feature-body',\n content: {\n text: body,\n style: {\n fontSize: bodyFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign,\n lineHeight: 1.5,\n },\n },\n position: {\n x: textX,\n y: bodyY,\n anchor: textAnchor,\n width: `${textColumnWidth}%`,\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 0.8, delay: 0.2 }),\n });\n }\n\n return layers;\n}\n\nexport function leftFeature(input: LeftFeatureInput, context: TemplateContext): Layer[] {\n return buildFeatureLayers(input, context, 'left');\n}\n\nexport function rightFeature(input: RightFeatureInput, context: TemplateContext): Layer[] {\n return buildFeatureLayers(input, context, 'right');\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 { getThemeFont, shouldUseShadow, themedFontSize } from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.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 = themedFontSize(64, context, true);\n const captionFontSize = themedFontSize(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 // Overlay bands are tinted from the theme background so the theme text\n // color on them stays readable in light and dark themes alike; they\n // fade out toward the map so the band doesn't read as a hard seam.\n const bg = theme.colors.background;\n\n // Add title overlay if provided\n if (title) {\n layers.push({\n type: 'shape',\n id: 'title-overlay',\n content: {\n shape: 'rect',\n fill: `linear-gradient(180deg, ${withAlpha(bg, 0.85)} 0%, ${withAlpha(bg, 0.6)} 70%, ${withAlpha(bg, 0)} 100%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '20%' },\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: shouldUseShadow(context),\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 layers.push({\n type: 'shape',\n id: 'caption-overlay',\n content: {\n shape: 'rect',\n fill: `linear-gradient(0deg, ${withAlpha(bg, 0.85)} 0%, ${withAlpha(bg, 0.6)} 70%, ${withAlpha(bg, 0)} 100%)`,\n },\n position: { x: 0, y: '80%', width: '100%', height: '20%' },\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: shouldUseShadow(context),\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 {\n resolveColorScheme,\n getTemplateHint,\n getThemeFont,\n shouldUseShadow,\n themedFontSize,\n} from '../utils/themeUtils.js';\nimport { oklchDarken } from '../../schemas/colorUtils.js';\n\n/**\n * Hint schema published for the theme validator + future customizer hint UI.\n * Themes may set `templateHints.fullBleedQuote` entries matching these keys.\n */\nexport const fullBleedQuoteHintSchema = {\n /** Entrance style for the quote text. 'subtle' or 'dramatic'. */\n entrance: {\n type: 'string' as const,\n options: ['subtle', 'dramatic'] as const,\n default: 'subtle',\n },\n} as const;\n\nexport function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateContext): Layer[] {\n const { text, colorScheme = 'blue' } = input;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Massive font for dramatic impact\n const textFontSize = themedFontSize(120, context, true);\n\n return [\n // Background — radial vignette built from the color scheme's own\n // surface, so the card takes on the scheme (and the theme behind it)\n // instead of vignetting every theme into hard black.\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 50%, ${colors.bg} 0%, ${oklchDarken(colors.bg, 0.12)} 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: shouldUseShadow(context),\n },\n },\n position: {\n x: '50%',\n y: '50%',\n anchor: 'center',\n width: '85%',\n },\n animation:\n getTemplateHint<string>(context, 'fullBleedQuote', 'entrance', 'subtle') === 'dramatic'\n ? { type: 'zoomIn', duration: 0.8 }\n : { 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 {\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';\n\nexport function listBlock(input: ListBlockInput, context: TemplateContext): Layer[] {\n const { title, accentImage } = input;\n // `items` is required by the schema, but malformed / partially-authored\n // blocks (e.g. someone wrote `template: list` with no items yet) reach\n // this code path during live preview. Treat missing/non-array as empty\n // so we render the title-and-background frame instead of blowing up\n // every keystroke with a TypeError.\n const items: string[] = Array.isArray(input.items) ? input.items : [];\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 = themedFontSize(44, context, true);\n const itemFontSize = themedFontSize(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(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\n }\n\n // Left edge of the text column — derived from the center+width pair so\n // the title and items share one left axis instead of a centered title\n // floating over a left-aligned column. Falls back to a safe 8% if the\n // layout strings ever turn out unparseable (they're authored, but\n // defensive against future edits to the accent-layout types).\n const centerX = parseFloat(accentLayout.textCenterX);\n const widthPct = parseFloat(accentLayout.textWidth);\n const leftX =\n Number.isFinite(centerX) && Number.isFinite(widthPct) ? `${centerX - widthPct / 2}%` : '8%';\n\n // Title if provided\n const startY = title ? 34 : 26;\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: 'left',\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: leftX,\n y: adjustY('20%', accentLayout),\n width: accentLayout.textWidth,\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 1 }),\n });\n }\n\n // Stack items with a fixed compact gap rather than stretching them\n // across the available band. Distributing items across (startY → 80%)\n // left big vertical gaps for short lists and made the slide read as a\n // sparse menu instead of a tight enumeration; conversely a bare\n // line-height gap read as a cramped paragraph — 18px of air keeps each\n // entry its own line without breaking the group.\n //\n // Spacing = item line-height (34px base × 1.2) + 18px gap, expressed\n // as % of the 1080px design canvas (~5.4%). Wrapped items push the\n // next entry down via their own line-height, so this sets the\n // minimum baseline-to-baseline distance for unwrapped items.\n const LIST_ITEM_BASE_PX = 34;\n const LIST_ITEM_LINE_HEIGHT = 1.2;\n const LIST_ITEM_GAP_PX = 18;\n const DESIGN_HEIGHT_PX = 1080;\n const spacing =\n ((LIST_ITEM_BASE_PX * LIST_ITEM_LINE_HEIGHT + LIST_ITEM_GAP_PX) / DESIGN_HEIGHT_PX) * 100;\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 textAlign: 'left',\n lineHeight: 1.2,\n shadow: shouldUseShadow(context),\n },\n },\n position: {\n x: leftX,\n y: adjustY(`${y}%`, accentLayout),\n width: accentLayout.textWidth,\n },\n animation: themedEntrance(context, 'text', {\n type: 'fadeIn',\n duration: 0.8,\n delay: 0.3 + 0.3 * i,\n }),\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 { getThemeFont, themedFontSize, themedImageTreatment } from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.js';\nimport { cleanCaption } from './captionUtils.js';\n\n/** Gap between images as percentage */\nconst GAP = 1.2;\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 treatment = themedImageTreatment(context, input.imageTreatment);\n\n const layers: Layer[] = [\n // Theme surface background (visible in gaps between images)\n {\n type: 'shape',\n id: 'bg',\n content: { shape: 'rect', fill: theme.colors.background },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n const gridHeight = 100;\n\n // Generate image positions based on count; stack vertically in portrait\n const positions = getGridPositions(images.length, gridHeight, layout.stackColumns);\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 // 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 ...(treatment ? { treatment } : {}),\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 in a compact translucent chip above player controls. Long\n // archival/Wikimedia descriptions are intentionally clamped.\n if (caption) {\n const captionFontSize = themedFontSize(layout.stackColumns ? 24 : 26, context, false);\n const captionY = layout.stackColumns ? '78%' : '74%';\n const captionBgY = layout.stackColumns ? '72%' : '68%';\n const captionHeight = layout.stackColumns ? '13%' : '16%';\n const bg = theme.colors.background;\n\n layers.push({\n type: 'shape',\n id: 'caption-bg',\n content: {\n shape: 'rect',\n fill: `linear-gradient(90deg, ${withAlpha(bg, 0)}, ${withAlpha(bg, 0.78)} 16%, ${withAlpha(bg, 0.78)} 84%, ${withAlpha(bg, 0)})`,\n },\n position: { x: 0, y: captionBgY, width: '100%', height: captionHeight },\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 lineHeight: 1.18,\n maxLines: layout.stackColumns ? 2 : 1,\n },\n },\n position: {\n x: '50%',\n y: captionY,\n anchor: 'center',\n width: '78%',\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 {\n resolveColorScheme,\n getThemeFont,\n shouldUseShadow,\n themedEntrance,\n themedFontSize,\n themedSurfaceGradient,\n themedImageTreatment,\n} 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 = themedFontSize(72, context, true);\n const defFontSize = themedFontSize(32, context, false);\n const originFontSize = themedFontSize(22, context, false);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 145))];\n\n // Add accent image layers\n if (accentImage) {\n layers.push(\n ...createAccentLayers(\n accentImage,\n input.id,\n themedImageTreatment(context, input.imageTreatment),\n ),\n );\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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('30%', accentLayout),\n anchor: 'center',\n },\n animation: themedEntrance(context, 'text', { 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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('55%', accentLayout),\n width: accentLayout.textWidth,\n anchor: 'center',\n },\n animation: themedEntrance(context, 'text', { 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: shouldUseShadow(context),\n },\n },\n position: {\n x: accentLayout.textCenterX,\n y: adjustY('70%', 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 {\n resolveColorScheme,\n getThemeFont,\n themedFontSize,\n themedSurfaceGradient,\n} from '../utils/themeUtils.js';\n\nexport function comparisonBar(input: ComparisonBarInput, context: TemplateContext): Layer[] {\n const { leftLabel, rightLabel, unit, colorScheme = 'blue' } = input;\n const { theme, viewport } = context;\n const colors = resolveColorScheme(context, colorScheme);\n\n // Defensive: coerce non-finite values to 0. Callers should pass real numbers,\n // but a NaN would otherwise render as literal \"NaN\" text and collapse every\n // bar/label to a `NaN%` position, cramming the block against its left edge.\n const leftValue = Number.isFinite(input.leftValue) ? input.leftValue : 0;\n const rightValue = Number.isFinite(input.rightValue) ? input.rightValue : 0;\n\n const labelFontSize = themedFontSize(28, context, false);\n const valueFontSize = themedFontSize(48, context, true);\n\n // Format values for display\n const formatValue = (v: number): string => {\n if (!Number.isFinite(v)) return '—';\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 // Bar positioning\n const barStartX = 15;\n const barHeight = 6; // % of viewport height\n const topBarY = 36;\n const bottomBarY = 58;\n\n // Calculate proportional bar widths. The widest bar must leave room\n // for its trailing value label inside a 96% safe area — otherwise a\n // long label (\"84 clarity score\") runs off the right edge of the block.\n const maxValue = Math.max(leftValue, rightValue, 1);\n const longestLabelPx = Math.max(leftDisplay.length, rightDisplay.length) * valueFontSize * 0.58;\n const labelWidthPct = (longestLabelPx / viewport.width) * 100;\n const maxBarWidth = Math.max(20, Math.min(65, 96 - barStartX - labelWidthPct - 2));\n const leftBarWidth = (leftValue / maxValue) * maxBarWidth;\n const rightBarWidth = (rightValue / maxValue) * maxBarWidth;\n\n return [\n // Background\n {\n type: 'shape',\n id: 'bg',\n content: {\n shape: 'rect',\n fill: themedSurfaceGradient(context, 180),\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 {\n getThemeFont,\n themedEntrance,\n themedFontSize,\n themedImageTreatment,\n} from '../utils/themeUtils.js';\nimport { estimateTextHeight } from './captionUtils.js';\n\nexport function pullQuote(input: PullQuoteInput, context: TemplateContext): Layer[] {\n const { text, attribution, backgroundImage, ambientMotion } = input;\n const { viewport } = context;\n\n const treatment = themedImageTreatment(context, input.imageTreatment);\n\n // Guard: backgroundImage is required\n if (!backgroundImage?.src) return [];\n\n const quoteFontSize = themedFontSize(52, context, true);\n const attrFontSize = themedFontSize(26, context, false);\n const decoFontSize = themedFontSize(200, context, true);\n const quoteLineHeight = 1.4;\n const quoteYPct = attribution ? 45 : 50;\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 ...(treatment ? { treatment } : {}),\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: quoteLineHeight,\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: `${quoteYPct}%`,\n anchor: 'center',\n width: '72%',\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 }),\n },\n ];\n\n // Attribution \\u2014 hangs just below the quote's estimated bottom edge so\n // the two read as one lockup instead of stranding near the bottom.\n if (attribution) {\n const quoteWidthPx = 0.72 * viewport.width;\n const quoteHeightPx = estimateTextHeight(text, quoteFontSize, quoteWidthPx, quoteLineHeight);\n const attrYPct = Math.min(\n 82,\n quoteYPct + ((quoteHeightPx / 2 + quoteFontSize * 1.7) / viewport.height) * 100,\n );\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.85)',\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: `${attrYPct}%`,\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 { getThemeFont, shouldUseShadow, themedFontSize } from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.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 } = context;\n\n const captionFontSize = themedFontSize(30, context, false);\n const creditFontSize = themedFontSize(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 with a compact translucent band. Long archival captions are\n // clamped so they don't collide with player controls or cover the frame.\n if (caption) {\n const bg = theme.colors.background;\n const captionBgY =\n captionPosition === 'top' ? '7%' : captionPosition === 'center' ? '42%' : '68%';\n const captionY =\n captionPosition === 'top' ? '13%' : captionPosition === 'center' ? '48%' : '74%';\n\n layers.push({\n type: 'shape',\n id: 'caption-gradient',\n content: {\n shape: 'rect',\n fill: `linear-gradient(90deg, ${withAlpha(bg, 0)}, ${withAlpha(bg, 0.78)} 16%, ${withAlpha(bg, 0.78)} 84%, ${withAlpha(bg, 0)})`,\n },\n position: {\n x: 0,\n y: captionBgY,\n width: '100%',\n height: '16%',\n },\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: shouldUseShadow(context),\n lineHeight: 1.18,\n maxLines: 2,\n },\n },\n position: {\n x: '50%',\n y: captionY,\n anchor: 'center',\n width: '78%',\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: withAlpha(theme.colors.text, 0.65),\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 { getThemeFont, themedEntrance, themedFontSize } from '../utils/themeUtils.js';\nimport { estimateTextHeight } from './captionUtils.js';\n\nexport function videoPullQuote(input: VideoPullQuoteInput, context: TemplateContext): Layer[] {\n const { text, attribution, backgroundVideo } = input;\n const { viewport } = context;\n\n // Guard: backgroundVideo is required\n if (!backgroundVideo?.src) return [];\n\n const quoteFontSize = themedFontSize(52, context, true);\n const attrFontSize = themedFontSize(26, context, false);\n const decoFontSize = themedFontSize(200, context, true);\n const quoteLineHeight = 1.4;\n const quoteYPct = attribution ? 45 : 50;\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: quoteLineHeight,\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: `${quoteYPct}%`,\n anchor: 'center',\n width: '72%',\n },\n animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 }),\n },\n ];\n\n // Attribution \\u2014 hangs just below the quote's estimated bottom edge so\n // the two read as one lockup instead of stranding near the bottom.\n if (attribution) {\n const quoteWidthPx = 0.72 * viewport.width;\n const quoteHeightPx = estimateTextHeight(text, quoteFontSize, quoteWidthPx, quoteLineHeight);\n const attrYPct = Math.min(\n 82,\n quoteYPct + ((quoteHeightPx / 2 + quoteFontSize * 1.7) / viewport.height) * 100,\n );\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.85)',\n textAlign: 'center',\n shadow: true,\n },\n },\n position: {\n x: '50%',\n y: `${attrYPct}%`,\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 {\n getThemeFont,\n resolveColorScheme,\n shouldUseShadow,\n themedFontSize,\n themedSurfaceGradient,\n} from '../utils/themeUtils.js';\nimport { pickContrastingText, withAlpha } from '../../schemas/colorUtils.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, viewport } = context;\n\n const colors = resolveColorScheme(context, colorScheme);\n const titleFontSize = themedFontSize(48, context, true);\n const tableFontSize = themedFontSize(28, context, false);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 170))];\n\n // Size the table band from its natural content height (header + rows at\n // ~2.4× line height for cell padding) and center the title+table as one\n // group — a full-height band left a ~200px orphan gap under the title.\n // `rows` is required by the schema but may be missing on partially-\n // authored blocks in live preview; treat it as empty rather than throwing.\n const rowCount = (Array.isArray(rows) ? rows.length : 0) + 1;\n const naturalTableHPct = Math.min(74, ((rowCount * tableFontSize * 2.4) / viewport.height) * 100);\n const titleBandPct = title ? (titleFontSize * 2.2 * 100) / viewport.height : 0;\n const groupTopPct = Math.max(8, (100 - titleBandPct - naturalTableHPct) / 2);\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: shouldUseShadow(context),\n },\n },\n position: {\n x: '50%',\n y: `${groupTopPct + titleBandPct / 2}%`,\n width: '80%',\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n }\n\n // Table layer. Header text color is picked for contrast against the\n // header fill — pairing two mid-tones from the same scheme made the\n // header row read as a smudge in most themes.\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: pickContrastingText(colors.accent),\n cellBackground: withAlpha(theme.colors.text, 0.04),\n cellColor: theme.colors.text,\n borderColor: withAlpha(theme.colors.text, 0.15),\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: `${groupTopPct + titleBandPct}%`,\n width: '80%',\n height: `${naturalTableHPct}%`,\n },\n animation: { type: 'fadeIn', duration: 1, delay: title ? 0.4 : 0 },\n });\n\n return layers;\n}\n","/** Text fitting shared by the live diagram canvas and template renderer. */\n\nexport const DIAGRAM_LABEL_LINE_HEIGHT = 1.25;\nexport const DIAGRAM_LABEL_HORIZONTAL_PADDING = 24;\nexport const DIAGRAM_LABEL_VERTICAL_PADDING = 16;\nexport const DIAGRAM_LABEL_MIN_FONT_SIZE = 10;\n\nexport interface DiagramLabelFit {\n fontSize: number;\n lineCount: number;\n /** Upward shift that centers the full line group around the node midpoint. */\n firstLineOffset: number;\n textWidth: number;\n}\n\n/**\n * Fit a plain diagram label inside a node card using the same character-width\n * estimate and word wrapping as React's `TextLayer`.\n */\nexport function fitDiagramLabel(\n text: string,\n boxWidth: number,\n boxHeight: number,\n preferredFontSize: number,\n): DiagramLabelFit {\n const textWidth = Math.max(1, boxWidth - DIAGRAM_LABEL_HORIZONTAL_PADDING);\n const textHeight = Math.max(1, boxHeight - DIAGRAM_LABEL_VERTICAL_PADDING);\n const preferred = Math.max(DIAGRAM_LABEL_MIN_FONT_SIZE, Math.floor(preferredFontSize));\n\n let fontSize = preferred;\n let lineCount = countWrappedLines(text, fontSize, textWidth);\n while (\n fontSize > DIAGRAM_LABEL_MIN_FONT_SIZE &&\n lineCount * fontSize * DIAGRAM_LABEL_LINE_HEIGHT > textHeight\n ) {\n fontSize--;\n lineCount = countWrappedLines(text, fontSize, textWidth);\n }\n\n return {\n fontSize,\n lineCount,\n firstLineOffset:\n lineCount === 1 ? 0 : -((lineCount - 1) * fontSize * DIAGRAM_LABEL_LINE_HEIGHT) / 2,\n textWidth,\n };\n}\n\nfunction countWrappedLines(text: string, fontSize: number, maxWidth: number): number {\n return text\n .split('\\n')\n .reduce((count, line) => count + wrappedLineCount(line, fontSize, maxWidth), 0);\n}\n\nfunction wrappedLineCount(text: string, fontSize: number, maxWidth: number): number {\n if (!text.trim()) return 1;\n const charsPerLine = Math.floor(maxWidth / (fontSize * 0.5));\n if (charsPerLine <= 0) return 1;\n\n let lines = 0;\n let currentLength = 0;\n for (const word of text.split(/\\s+/)) {\n const testLength = currentLength > 0 ? currentLength + 1 + word.length : word.length;\n if (testLength <= charsPerLine) {\n currentLength = testLength;\n continue;\n }\n if (currentLength > 0) lines++;\n if (word.length > charsPerLine) {\n lines += Math.floor((word.length - 1) / charsPerLine);\n currentLength = word.length % charsPerLine || charsPerLine;\n } else {\n currentLength = word.length;\n }\n }\n if (currentLength > 0) lines++;\n return Math.max(1, lines);\n}\n","/**\n * Diagram layout — shared between the read-only SVG render path\n * (`diagramBlock` template) and the interactive editor (React Flow in\n * `@bendyline/squisq-editor-react`). Same children + same options always\n * produce the same node positions and edge list, so previews and the\n * editor stay visually consistent.\n *\n * Layout rules:\n * 1. Children with both `x` and `y` set keep their authored coordinates.\n * 2. Children missing either coordinate are auto-placed in a square-ish\n * grid in declaration order, offset below the bounding box of the\n * explicitly-positioned children.\n * 3. Edges come from each child's `connectsTo`. Targets that don't match\n * any sibling id are dropped (and counted in `warnings`).\n */\n\nimport type { Block, BlockConnection } from '../../schemas/Doc.js';\n\nexport interface DiagramNodePosition {\n /** Block id (matches `Block.id`). */\n id: string;\n /** Display label (block title or fallback to id). */\n label: string;\n /** Pixel x coordinate (canvas-relative). */\n x: number;\n /** Pixel y coordinate (canvas-relative). */\n y: number;\n /** True when the position came from `x=`/`y=` attributes; false when auto-laid out. */\n pinned: boolean;\n /** Optional `.class` tokens carried over from the heading. */\n classes?: string[];\n}\n\nexport interface DiagramEdge {\n /** Synthetic stable edge id. */\n id: string;\n /** Source node id. */\n source: string;\n /** Target node id. */\n target: string;\n /** Connection type from `connectsTo=target:type` (used as edge label). */\n type?: string;\n}\n\nexport interface DiagramLayout {\n nodes: DiagramNodePosition[];\n edges: DiagramEdge[];\n warnings: string[];\n}\n\nexport interface DiagramLayoutOptions {\n /** Horizontal grid pitch between auto-laid-out nodes. Default: 260 (node width 180 + 80 air). */\n gapX?: number;\n /** Vertical grid pitch between auto-laid-out nodes. Default: 140. */\n gapY?: number;\n /** Padding around the explicit-positions bounding box before the grid starts. Default: 80. */\n gridPad?: number;\n /** Origin x for the grid when no explicit nodes anchor it. Default: 80. */\n gridOriginX?: number;\n /** Origin y for the grid when no explicit nodes anchor it. Default: 80. */\n gridOriginY?: number;\n}\n\nconst DEFAULT_OPTS: Required<DiagramLayoutOptions> = {\n gapX: 260,\n gapY: 140,\n gridPad: 80,\n gridOriginX: 80,\n gridOriginY: 80,\n};\n\n/**\n * Compute node positions and edges for a diagram from a parent block's\n * children. Pure function — same inputs always produce the same output.\n */\nexport function computeDiagramLayout(\n children: readonly Block[],\n options: DiagramLayoutOptions = {},\n): DiagramLayout {\n const opts = { ...DEFAULT_OPTS, ...options };\n const warnings: string[] = [];\n\n // First pass: extract explicit positions, record which children still need a grid slot.\n type Entry = { child: Block; pinned: boolean; x: number; y: number };\n const entries: Entry[] = [];\n const unpositionedIdx: number[] = [];\n\n for (let i = 0; i < children.length; i++) {\n const c = children[i];\n const hasX = typeof c.x === 'number';\n const hasY = typeof c.y === 'number';\n if (hasX && hasY) {\n entries.push({ child: c, pinned: true, x: c.x as number, y: c.y as number });\n } else {\n entries.push({ child: c, pinned: false, x: 0, y: 0 });\n unpositionedIdx.push(i);\n }\n }\n\n // Second pass: lay out unpositioned children in a square-ish grid.\n if (unpositionedIdx.length > 0) {\n const cols = Math.max(1, Math.ceil(Math.sqrt(unpositionedIdx.length)));\n // Find the bottom-right of the pinned bounding box so the grid sits below it.\n let baseX = opts.gridOriginX;\n let baseY = opts.gridOriginY;\n const pinned = entries.filter((e) => e.pinned);\n if (pinned.length > 0) {\n const minX = Math.min(...pinned.map((e) => e.x));\n const maxY = Math.max(...pinned.map((e) => e.y));\n baseX = minX;\n baseY = maxY + opts.gridPad + opts.gapY;\n }\n unpositionedIdx.forEach((entryIdx, k) => {\n const col = k % cols;\n const row = Math.floor(k / cols);\n entries[entryIdx].x = baseX + col * opts.gapX;\n entries[entryIdx].y = baseY + row * opts.gapY;\n });\n }\n\n // Third pass: emit nodes + the id-set used to validate edge targets.\n const nodes: DiagramNodePosition[] = entries.map((e) => ({\n id: e.child.id,\n label: e.child.title ?? e.child.id,\n x: e.x,\n y: e.y,\n pinned: e.pinned,\n ...(e.child.classes && e.child.classes.length > 0 ? { classes: e.child.classes } : {}),\n }));\n const nodeIds = new Set(nodes.map((n) => n.id));\n\n // Fourth pass: emit edges from each child's connectsTo, dropping ghosts.\n const edges: DiagramEdge[] = [];\n const seenEdgeIds = new Set<string>();\n for (const child of children) {\n if (!child.connectsTo) continue;\n for (const conn of child.connectsTo) {\n if (!nodeIds.has(conn.target)) {\n warnings.push(`Edge from \"${child.id}\" to \"${conn.target}\" dropped: no such sibling node`);\n continue;\n }\n const edgeId = makeEdgeId(child.id, conn);\n if (seenEdgeIds.has(edgeId)) continue;\n seenEdgeIds.add(edgeId);\n edges.push({\n id: edgeId,\n source: child.id,\n target: conn.target,\n ...(conn.type ? { type: conn.type } : {}),\n });\n }\n }\n\n return { nodes, edges, warnings };\n}\n\nfunction makeEdgeId(source: string, conn: BlockConnection): string {\n return conn.type ? `${source}->${conn.target}:${conn.type}` : `${source}->${conn.target}`;\n}\n","/**\n * Diagram block template.\n *\n * Renders a node-and-edge diagram from one of two data sources:\n * 1. Child headings (`context.children`) — the legacy authored form; each\n * child becomes a node positioned by `x`/`y` and connected by\n * `connectsTo` (see `diagramLayout.ts` for auto-placement rules).\n * 2. `input.nodes`/`input.edges` (usually via `templateData`) — the\n * data-driven form derived from an ASCII-art diagram fence. Nodes may\n * carry per-node sizes and a `container` reference; containers draw\n * behind their children as translucent grouping cards.\n *\n * Layout coordinates are author-defined units. The template computes a\n * bounding box of all nodes and scales it to fit the block's viewport\n * with padding, so users don't have to think about absolute pixel ranges.\n */\n\nimport type { Layer, ShapeLayer, TextLayer, PathLayer, MarkerStyle } from '../../schemas/Doc.js';\nimport type {\n DiagramBlockInput,\n DiagramEdgeAnchor,\n DiagramTemplateEdge,\n DiagramTemplateNode,\n TemplateContext,\n} from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont, themedFontSize } from '../utils/themeUtils.js';\nimport { DIAGRAM_LABEL_LINE_HEIGHT, fitDiagramLabel } from '../utils/diagramText.js';\nimport {\n anchorPoint,\n connectorPath,\n lineStyleDasharray,\n snapEndpoints,\n type ConnectorRouting,\n} from '../utils/shapeGeometry.js';\nimport { computeDiagramLayout } from './diagramLayout.js';\n\nconst NODE_WIDTH = 180;\nconst NODE_HEIGHT = 64;\nconst PADDING = 80;\n\ninterface ResolvedDiagramNode {\n id: string;\n label: string;\n x: number;\n y: number;\n w: number;\n h: number;\n /** Containment depth (0 = top level); containers draw depth-ascending. */\n depth: number;\n isContainer: boolean;\n}\n\ninterface ResolvedDiagramEdge {\n id: string;\n source: string;\n target: string;\n label?: string;\n directed: boolean;\n sourceAnchor?: DiagramEdgeAnchor;\n targetAnchor?: DiagramEdgeAnchor;\n routing?: ConnectorRouting;\n}\n\ninterface ResolvedDiagram {\n nodes: ResolvedDiagramNode[];\n edges: ResolvedDiagramEdge[];\n}\n\nfunction nodesFromChildren(context: TemplateContext): ResolvedDiagram {\n const layout = computeDiagramLayout(context.children ?? []);\n return {\n nodes: layout.nodes.map((n) => ({\n id: n.id,\n label: n.label,\n x: n.x,\n y: n.y,\n w: NODE_WIDTH,\n h: NODE_HEIGHT,\n depth: 0,\n isContainer: false,\n })),\n edges: layout.edges.map((e) => ({\n id: e.id,\n source: e.source,\n target: e.target,\n ...(e.type ? { label: e.type } : {}),\n directed: true,\n })),\n };\n}\n\n/**\n * Defensive resolution of `templateData`-supplied nodes/edges: the data is\n * untyped at runtime (it can come from a hand-written `json data` fence),\n * so malformed entries are dropped rather than crashing the template.\n */\nfunction nodesFromTemplateData(input: DiagramBlockInput): ResolvedDiagram {\n const rawNodes = Array.isArray(input.nodes) ? input.nodes : [];\n const valid = rawNodes.filter(\n (n): n is DiagramTemplateNode =>\n typeof n === 'object' &&\n n !== null &&\n typeof n.id === 'string' &&\n n.id.length > 0 &&\n typeof n.label === 'string' &&\n typeof n.x === 'number' &&\n Number.isFinite(n.x) &&\n typeof n.y === 'number' &&\n Number.isFinite(n.y),\n );\n const ids = new Set(valid.map((n) => n.id));\n const containerIds = new Set(\n valid.map((n) => n.container).filter((c): c is string => typeof c === 'string' && ids.has(c)),\n );\n const depthOf = (node: DiagramTemplateNode): number => {\n let depth = 0;\n let current: DiagramTemplateNode | undefined = node;\n const seen = new Set<string>();\n while (current?.container && ids.has(current.container) && !seen.has(current.id)) {\n seen.add(current.id);\n depth++;\n current = valid.find((n) => n.id === current?.container);\n }\n return depth;\n };\n const nodes: ResolvedDiagramNode[] = valid.map((n) => ({\n id: n.id,\n label: n.label,\n x: n.x,\n y: n.y,\n w: typeof n.w === 'number' && Number.isFinite(n.w) && n.w > 0 ? n.w : NODE_WIDTH,\n h: typeof n.h === 'number' && Number.isFinite(n.h) && n.h > 0 ? n.h : NODE_HEIGHT,\n depth: depthOf(n),\n isContainer: containerIds.has(n.id),\n }));\n\n const rawEdges = Array.isArray(input.edges) ? input.edges : [];\n const edges: ResolvedDiagramEdge[] = rawEdges\n .filter(\n (e): e is DiagramTemplateEdge =>\n typeof e === 'object' &&\n e !== null &&\n typeof e.source === 'string' &&\n typeof e.target === 'string' &&\n ids.has(e.source) &&\n ids.has(e.target),\n )\n .map((e, i) => ({\n id: e.label ? `${e.source}->${e.target}:${e.label}` : `${e.source}->${e.target}-${i}`,\n source: e.source,\n target: e.target,\n ...(e.label ? { label: e.label } : {}),\n directed: e.directed !== false,\n ...(e.sourceAnchor ? { sourceAnchor: e.sourceAnchor } : {}),\n ...(e.targetAnchor ? { targetAnchor: e.targetAnchor } : {}),\n ...(e.routing ? { routing: e.routing } : {}),\n }));\n return { nodes, edges };\n}\n\nexport function diagramBlock(input: DiagramBlockInput, context: TemplateContext): Layer[] {\n const { theme, viewport, children = [] } = context;\n const colors = resolveColorScheme(context, input.colorScheme ?? 'blue');\n\n const resolved =\n children.length > 0\n ? nodesFromChildren(context)\n : input.nodes && input.nodes.length > 0\n ? nodesFromTemplateData(input)\n : { nodes: [], edges: [] };\n\n if (resolved.nodes.length === 0) {\n // Empty diagram — render a single hint label so the block has visible content.\n return [\n {\n type: 'text',\n id: 'diagram-empty',\n content: {\n text: input.title ?? 'Empty diagram',\n style: {\n fontSize: themedFontSize(36, context, true),\n fontFamily: getThemeFont(context, 'title'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '50%', anchor: 'center' },\n },\n ];\n }\n\n // Compute the bounding box of all nodes in author coordinates.\n const minX = Math.min(...resolved.nodes.map((n) => n.x));\n const maxX = Math.max(...resolved.nodes.map((n) => n.x + n.w));\n const minY = Math.min(...resolved.nodes.map((n) => n.y));\n const maxY = Math.max(...resolved.nodes.map((n) => n.y + n.h));\n\n // Available area in viewport pixels (after reserving space for the title, if any).\n const titleHeight = input.title ? 120 : 0;\n const availW = Math.max(1, viewport.width - PADDING * 2);\n const availH = Math.max(1, viewport.height - PADDING * 2 - titleHeight);\n const contentW = Math.max(1, maxX - minX);\n const contentH = Math.max(1, maxY - minY);\n\n // Uniform scale so the diagram fits both dimensions. Small diagrams are\n // allowed to grow (everything here is vector) up to 1.8× so a three-node\n // flow doesn't render as a tiny cluster in an empty canvas; label fonts\n // and strokes scale with the nodes, clamped so text never balloons.\n const scale = Math.min(availW / contentW, availH / contentH, 1.8);\n const fontAdj = Math.min(Math.max(scale, 1), 1.5);\n const strokeW = Math.round(2 * fontAdj);\n\n // Compute viewport-pixel coordinates of each node's top-left corner.\n // The title and the scaled diagram are centered together as one group —\n // a top-pinned title over a center-floated diagram split the block into\n // two stranded pieces.\n const scaledW = contentW * scale;\n const scaledH = contentH * scale;\n const groupTop = Math.max(PADDING / 2, (viewport.height - titleHeight - scaledH) / 2);\n const offsetX = PADDING + (availW - scaledW) / 2;\n const offsetY = groupTop + titleHeight;\n const transform = (n: ResolvedDiagramNode): { x: number; y: number; w: number; h: number } => ({\n x: offsetX + (n.x - minX) * scale,\n y: offsetY + (n.y - minY) * scale,\n w: n.w * scale,\n h: n.h * scale,\n });\n\n const layers: Layer[] = [];\n\n // Optional title above the diagram.\n if (input.title) {\n layers.push({\n type: 'text',\n id: 'diagram-title',\n content: {\n text: input.title,\n style: {\n fontSize: themedFontSize(40, context, true),\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: groupTop + titleHeight / 2 - 16, anchor: 'center' },\n });\n }\n\n const containers = resolved.nodes\n .filter((n) => n.isContainer)\n .sort((a, b) => a.depth - b.depth || a.y - b.y || a.x - b.x);\n const leaves = resolved.nodes.filter((n) => !n.isContainer);\n\n // Container cards first — translucent grouping surfaces behind everything.\n for (const node of containers) {\n const t = transform(node);\n const card: ShapeLayer = {\n type: 'shape',\n id: `node-card-${node.id}`,\n content: {\n shape: 'rect',\n fill: colors.bg ?? theme.colors.backgroundLight,\n fillOpacity: 0.25,\n stroke: colors.text ?? theme.colors.primary,\n strokeWidth: Math.max(1, strokeW - 1),\n borderRadius: 10,\n },\n position: { x: t.x, y: t.y, width: t.w, height: t.h },\n };\n layers.push(card);\n }\n\n // Position lookup by id for edge routing (containers included — edges may\n // attach to them, e.g. a through-border split from a parsed fence).\n const positions = new Map<string, { cx: number; cy: number; rx: number; ry: number }>();\n for (const node of resolved.nodes) {\n const t = transform(node);\n positions.set(node.id, { cx: t.x + t.w / 2, cy: t.y + t.h / 2, rx: t.w / 2, ry: t.h / 2 });\n }\n\n // Edge styling (applies to all edges; direction comes per-edge).\n const startMarker: MarkerStyle = input.startStyle ?? 'none';\n const configuredEnd: MarkerStyle = input.endStyle ?? 'arrow';\n const edgeDash = lineStyleDasharray(input.lineStyle);\n\n // Edges above containers, behind leaf nodes.\n for (const edge of resolved.edges) {\n const a = positions.get(edge.source);\n const b = positions.get(edge.target);\n if (!a || !b) continue;\n const endMarker: MarkerStyle = edge.directed ? configuredEnd : 'none';\n const snapped = snapEndpoints(a, b);\n const start = edge.sourceAnchor ? anchorPoint(a, edge.sourceAnchor) : snapped.start;\n const end = edge.targetAnchor ? anchorPoint(b, edge.targetAnchor) : snapped.end;\n const pathLayer: PathLayer = {\n type: 'path',\n id: `edge-${edge.id}`,\n content: {\n d: connectorPath(edge.routing ?? input.edgeStyle ?? 'curved', start, end),\n stroke: colors.text ?? theme.colors.primary,\n strokeWidth: strokeW,\n fill: 'none',\n ...(edgeDash ? { dasharray: edgeDash } : {}),\n ...(startMarker !== 'none' ? { startMarker } : {}),\n ...(endMarker !== 'none' ? { endMarker } : {}),\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n layers.push(pathLayer);\n\n if (edge.label) {\n // Edge label, floated just above the edge midpoint so the line never\n // strikes through the text.\n const mx = (a.cx + b.cx) / 2;\n const my = (a.cy + b.cy) / 2;\n const labelFontSize = themedFontSize(Math.round(18 * fontAdj), context, false);\n const labelLayer: TextLayer = {\n type: 'text',\n id: `edge-label-${edge.id}`,\n content: {\n text: edge.label,\n style: {\n fontSize: labelFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: mx, y: my - labelFontSize * 0.9, anchor: 'center' },\n };\n layers.push(labelLayer);\n }\n }\n\n // Leaf nodes (card + label) on top of edges.\n for (const node of leaves) {\n const t = transform(node);\n const card: ShapeLayer = {\n type: 'shape',\n id: `node-card-${node.id}`,\n content: {\n shape: 'rect',\n fill: colors.bg ?? theme.colors.backgroundLight,\n stroke: colors.text ?? theme.colors.primary,\n strokeWidth: strokeW,\n borderRadius: input.nodeShape === 'pill' ? t.h / 2 : 10,\n },\n position: { x: t.x, y: t.y, width: t.w, height: t.h },\n };\n layers.push(card);\n\n const preferredFontSize = themedFontSize(Math.round(22 * fontAdj), context, false);\n const fit = fitDiagramLabel(node.label, t.w, t.h, preferredFontSize);\n const label: TextLayer = {\n type: 'text',\n id: `node-label-${node.id}`,\n content: {\n text: node.label,\n style: {\n fontSize: fit.fontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: colors.text ?? theme.colors.text,\n textAlign: 'center',\n lineHeight: DIAGRAM_LABEL_LINE_HEIGHT,\n },\n },\n position: {\n x: t.x + t.w / 2,\n y: t.y + t.h / 2 + fit.firstLineOffset,\n anchor: 'center',\n width: fit.textWidth,\n },\n };\n layers.push(label);\n }\n\n // Container titles last — anchored near the container's top edge, above\n // any child content that could otherwise overprint them.\n for (const node of containers) {\n const t = transform(node);\n const fontSize = themedFontSize(Math.round(20 * fontAdj), context, false);\n const label: TextLayer = {\n type: 'text',\n id: `node-label-${node.id}`,\n content: {\n text: node.label.split('\\n')[0] ?? '',\n style: {\n fontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: t.x + t.w / 2, y: t.y + fontSize, anchor: 'center', width: t.w },\n };\n layers.push(label);\n }\n\n return layers;\n}\n","/**\n * Tree Template\n *\n * Renders a hierarchical filesystem-style treeview (folder/file icons +\n * connector rails, collapsible in the live player) from an ASCII tree fence.\n * Emits a single `TreeLayer` (foreignObject HTML, like `dataTable`) plus an\n * optional title + themed background.\n *\n * Data source: `input.items` (a nested `TreeLayerItem[]`), populated from\n * `templateData.items` which the pipeline derives from the tree fence.\n */\n\nimport type { Layer, TreeLayerItem } from '../../schemas/Doc.js';\nimport type { TreeBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport {\n getThemeFont,\n resolveColorScheme,\n shouldUseShadow,\n themedFontSize,\n themedSurfaceGradient,\n} from '../utils/themeUtils.js';\nimport { withAlpha } from '../../schemas/colorUtils.js';\nimport { createBackgroundLayer } from './captionUtils.js';\n\n/** Defensive coercion of untyped `templateData.items` into valid tree items. */\nfunction coerceItems(raw: unknown): TreeLayerItem[] {\n if (!Array.isArray(raw)) return [];\n const out: TreeLayerItem[] = [];\n for (const r of raw) {\n if (typeof r !== 'object' || r === null) continue;\n const item = r as Record<string, unknown>;\n if (typeof item.label !== 'string') continue;\n const children = coerceItems(item.children);\n out.push({\n id: typeof item.id === 'string' && item.id ? item.id : slug(item.label),\n label: item.label,\n children,\n ...(item.isDir === true || children.length > 0 ? { isDir: true } : {}),\n ...(typeof item.comment === 'string' && item.comment ? { comment: item.comment } : {}),\n });\n }\n return out;\n}\n\nfunction slug(s: string): string {\n return (\n s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'node'\n );\n}\n\nexport function treeBlock(input: TreeBlockInput, context: TemplateContext): Layer[] {\n const { theme, viewport } = context;\n const colors = resolveColorScheme(context, input.colorScheme);\n const items = coerceItems(input.items);\n\n const titleFontSize = themedFontSize(48, context, true);\n const rowFontSize = themedFontSize(28, context, false);\n\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 170))];\n\n if (items.length === 0) {\n layers.push({\n type: 'text',\n id: 'tree-empty',\n content: {\n text: input.title ?? 'Empty tree',\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '50%', anchor: 'center' },\n });\n return layers;\n }\n\n const titleBandPct = input.title ? (titleFontSize * 2.2 * 100) / viewport.height : 0;\n\n if (input.title) {\n layers.push({\n type: 'text',\n id: 'title',\n content: {\n text: input.title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: shouldUseShadow(context),\n },\n },\n position: { x: '50%', y: `${8 + titleBandPct / 2}%`, width: '80%', anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.8 },\n });\n }\n\n layers.push({\n type: 'tree',\n id: 'tree',\n content: {\n items,\n style: {\n rowColor: theme.colors.text,\n dirColor: colors.accent ?? theme.colors.primary,\n connectorColor: withAlpha(theme.colors.text, 0.25),\n iconColor: colors.accent ?? theme.colors.primary,\n commentColor: theme.colors.textMuted,\n fontSize: rowFontSize,\n fontFamily: getThemeFont(context, 'body'),\n monoFontFamily: getThemeFont(context, 'mono'),\n indentPx: Math.round(rowFontSize * 1.4),\n },\n },\n position: {\n x: '10%',\n y: `${8 + titleBandPct}%`,\n width: '80%',\n height: `${Math.max(60, 90 - titleBandPct)}%`,\n },\n animation: { type: 'fadeIn', duration: 1, delay: input.title ? 0.4 : 0 },\n });\n\n return layers;\n}\n","/**\n * Timeline Template\n *\n * Renders one or more left-to-right tracks with positioned event markers,\n * callout stems/text, and optional branch links. It deliberately composes\n * existing shape/path/text layers so every current render/export surface can\n * display timelines without a timeline-specific React layer.\n */\n\nimport type { Layer, PathLayer, ShapeLayer, TextLayer } from '../../schemas/Doc.js';\nimport type {\n TemplateContext,\n TimelineBlockInput,\n TimelineTemplateEvent,\n TimelineTemplateLink,\n TimelineTemplateTrack,\n} from '../../schemas/BlockTemplates.js';\nimport { withAlpha } from '../../schemas/colorUtils.js';\nimport {\n getThemeFont,\n resolveColorScheme,\n shouldUseShadow,\n themedFontSize,\n themedSurfaceGradient,\n} from '../utils/themeUtils.js';\nimport { createBackgroundLayer, estimateTextHeight } from './captionUtils.js';\n\ntype EventPoint = {\n event: TimelineTemplateEvent;\n trackIndex: number;\n eventIndex: number;\n x: number;\n y: number;\n};\n\nconst clamp01 = (value: number): number => Math.max(0, Math.min(1, value));\nconst clamp = (value: number, min: number, max: number): number =>\n Math.max(min, Math.min(max, value));\n\nfunction safeId(value: string): string {\n return value.replace(/[^a-zA-Z0-9_-]+/g, '-').replace(/^-+|-+$/g, '') || 'item';\n}\n\n/** Defensive coercion for untyped `templateData` merged into the input. */\nfunction coerceTracks(raw: unknown): TimelineTemplateTrack[] {\n if (!Array.isArray(raw)) return [];\n const tracks: TimelineTemplateTrack[] = [];\n\n raw.forEach((candidate, trackIndex) => {\n if (typeof candidate !== 'object' || candidate === null) return;\n const record = candidate as Record<string, unknown>;\n const id =\n typeof record.id === 'string' && record.id.trim()\n ? record.id.trim()\n : `track-${trackIndex + 1}`;\n const events: TimelineTemplateEvent[] = [];\n\n if (Array.isArray(record.events)) {\n record.events.forEach((eventCandidate, eventIndex) => {\n if (typeof eventCandidate !== 'object' || eventCandidate === null) return;\n const event = eventCandidate as Record<string, unknown>;\n if (typeof event.label !== 'string') return;\n const position =\n typeof event.position === 'number' ? event.position : Number(event.position);\n if (!Number.isFinite(position)) return;\n const eventId =\n typeof event.id === 'string' && event.id.trim()\n ? event.id.trim()\n : `${id}-event-${eventIndex + 1}`;\n const side = event.side === 'above' || event.side === 'below' ? event.side : undefined;\n const descriptionSide =\n event.descriptionSide === 'above' || event.descriptionSide === 'below'\n ? event.descriptionSide\n : undefined;\n const marker =\n event.marker === 'filled' || event.marker === 'hollow' || event.marker === 'diamond'\n ? event.marker\n : undefined;\n events.push({\n id: eventId,\n label: event.label,\n position: clamp01(position),\n ...(typeof event.description === 'string' && event.description.trim()\n ? { description: event.description.trim() }\n : {}),\n ...(side ? { side } : {}),\n ...(descriptionSide ? { descriptionSide } : {}),\n ...(event.callout === false ? { callout: false } : {}),\n ...(marker ? { marker } : {}),\n });\n });\n }\n\n tracks.push({\n id,\n ...(typeof record.label === 'string' && record.label.trim()\n ? { label: record.label.trim() }\n : {}),\n ...(typeof record.endLabel === 'string' && record.endLabel.trim()\n ? { endLabel: record.endLabel.trim() }\n : {}),\n events,\n });\n });\n\n return tracks;\n}\n\nfunction coerceLinks(raw: unknown, eventIds: ReadonlySet<string>): TimelineTemplateLink[] {\n if (!Array.isArray(raw)) return [];\n const links: TimelineTemplateLink[] = [];\n for (const candidate of raw) {\n if (typeof candidate !== 'object' || candidate === null) continue;\n const link = candidate as Record<string, unknown>;\n if (typeof link.source !== 'string' || typeof link.target !== 'string') continue;\n if (!eventIds.has(link.source) || !eventIds.has(link.target) || link.source === link.target)\n continue;\n links.push({\n source: link.source,\n target: link.target,\n ...(typeof link.label === 'string' && link.label.trim() ? { label: link.label.trim() } : {}),\n });\n }\n return links;\n}\n\nfunction diamondLayer(\n id: string,\n x: number,\n y: number,\n radius: number,\n color: string,\n delay: number,\n): PathLayer {\n return {\n type: 'path',\n id,\n content: {\n d: `M ${x} ${y - radius} L ${x + radius} ${y} L ${x} ${y + radius} L ${x - radius} ${y} Z`,\n fill: color,\n stroke: color,\n strokeWidth: 2,\n },\n position: { x: x - radius, y: y - radius, width: radius * 2, height: radius * 2 },\n animation: { type: 'zoomIn', duration: 0.35, delay },\n };\n}\n\nfunction branchPath(source: EventPoint, target: EventPoint, bend: number): string {\n if (Math.abs(source.y - target.y) < 1) {\n const sourceSide = source.event.side ?? (source.eventIndex % 2 === 0 ? 'above' : 'below');\n // Route on the side opposite the source callout so the arch does not run\n // through its stem/label stack.\n const direction = sourceSide === 'above' ? 1 : -1;\n const controlY = source.y + direction * bend;\n return `M ${source.x} ${source.y} C ${source.x} ${controlY}, ${target.x} ${controlY}, ${target.x} ${target.y}`;\n }\n const midY = (source.y + target.y) / 2;\n return `M ${source.x} ${source.y} C ${source.x} ${midY}, ${target.x} ${midY}, ${target.x} ${target.y}`;\n}\n\nexport function timelineBlock(input: TimelineBlockInput, context: TemplateContext): Layer[] {\n const { theme, viewport } = context;\n const colors = resolveColorScheme(context, input.colorScheme);\n const tracks = coerceTracks(input.tracks);\n const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 165))];\n\n const titleFontSize = themedFontSize(44, context, true);\n const trackFontSize = themedFontSize(22, context, false);\n const baseEventFontSize = themedFontSize(24, context, false);\n const baseDescriptionFontSize = themedFontSize(17, context, false);\n\n if (input.title) {\n layers.push({\n type: 'text',\n id: 'timeline-title',\n content: {\n text: input.title,\n style: {\n fontSize: titleFontSize,\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n shadow: shouldUseShadow(context),\n },\n },\n position: { x: '50%', y: Math.max(50, titleFontSize * 1.2), width: '82%', anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.7 },\n });\n }\n\n if (tracks.length === 0) {\n layers.push({\n type: 'text',\n id: 'timeline-empty',\n content: {\n text: input.title ? 'No timeline events' : 'Empty timeline',\n style: {\n fontSize: themedFontSize(36, context, true),\n fontFamily: getThemeFont(context, 'title'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '50%', width: '80%', anchor: 'center' },\n });\n return layers;\n }\n\n const hasTrackLabels = tracks.some((track) => !!track.label);\n const outerMargin = Math.max(48, viewport.width * 0.065);\n const labelWidth = hasTrackLabels ? Math.min(280, viewport.width * 0.18) : 0;\n const axisStartX = outerMargin + labelWidth;\n const axisEndX = viewport.width - outerMargin;\n const axisWidth = Math.max(1, axisEndX - axisStartX);\n const contentTop = input.title\n ? Math.max(titleFontSize * 2.2, viewport.height * 0.2)\n : viewport.height * 0.09;\n const contentBottom = viewport.height * 0.91;\n const availableHeight = Math.max(1, contentBottom - contentTop);\n const trackBand = availableHeight / tracks.length;\n const markerRadius = Math.max(6, Math.min(11, Math.min(viewport.width, viewport.height) / 105));\n const trackColor = withAlpha(colors.text ?? theme.colors.primary, 0.72);\n const accentColor = colors.accent ?? theme.colors.primary;\n const branchColor = withAlpha(accentColor, 0.78);\n const calloutColor = withAlpha(theme.colors.text, 0.48);\n const maxCalloutEvents = Math.max(\n 1,\n ...tracks.map((track) => track.events.filter((event) => event.callout !== false).length),\n );\n // Alternate/opposite-side callouts can safely use more width than a naive\n // `axisWidth / total markers` split (dense cadence markers have no text).\n const calloutWidth = Math.max(\n Math.min(150, viewport.width * 0.2),\n Math.min(330, (axisWidth / Math.min(maxCalloutEvents, 4)) * 0.86),\n );\n // Theme font scaling intentionally grows in portrait, but timeline cards\n // get narrower there. Cap callout typography against the physical viewport\n // so labels wrap instead of degenerating to a few characters per line.\n const minViewportScale = Math.min(viewport.width, viewport.height) / 1080;\n const eventFontSize = Math.min(baseEventFontSize, 24 * minViewportScale);\n const descriptionFontSize = Math.min(baseDescriptionFontSize, 17 * minViewportScale);\n const trackMarkerRadii = tracks.map((track) => {\n const positions = track.events.map((event) => clamp01(event.position)).sort((a, b) => a - b);\n let minGapPx = Number.POSITIVE_INFINITY;\n for (let index = 1; index < positions.length; index++) {\n minGapPx = Math.min(minGapPx, (positions[index] - positions[index - 1]) * axisWidth);\n }\n return Number.isFinite(minGapPx)\n ? Math.min(markerRadius, Math.max(3, minGapPx * 0.32))\n : markerRadius;\n });\n const eventPoints: EventPoint[] = [];\n // Links resolve duplicate public/template-data ids deterministically to\n // their first event, while every event still receives its own marker and\n // callout layers.\n const eventPointById = new Map<string, EventPoint>();\n\n tracks.forEach((track, trackIndex) => {\n const y = contentTop + trackBand * (trackIndex + 0.5);\n const trackDelay = 0.12 + trackIndex * 0.12;\n const trackId = safeId(track.id);\n\n const line: PathLayer = {\n type: 'path',\n id: `timeline-track-${trackId}-${trackIndex}`,\n content: {\n d: `M ${axisStartX} ${y} L ${axisEndX} ${y}`,\n stroke: trackColor,\n strokeWidth: Math.max(2, markerRadius * 0.32),\n fill: 'none',\n endMarker: 'arrow',\n },\n position: { x: axisStartX, y: y - markerRadius, width: axisWidth, height: markerRadius * 2 },\n animation: { type: 'fadeIn', duration: 0.65, delay: trackDelay },\n };\n layers.push(line);\n\n if (track.label) {\n const label: TextLayer = {\n type: 'text',\n id: `timeline-track-label-${trackId}-${trackIndex}`,\n content: {\n text: track.label,\n style: {\n fontSize: trackFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: theme.colors.textMuted,\n textAlign: 'right',\n },\n },\n position: {\n x: outerMargin + labelWidth / 2 - 16,\n y,\n width: Math.max(1, labelWidth - 32),\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.5, delay: trackDelay },\n };\n layers.push(label);\n }\n\n if (track.endLabel) {\n layers.push({\n type: 'text',\n id: `timeline-track-end-label-${trackId}-${trackIndex}`,\n content: {\n text: track.endLabel,\n style: {\n fontSize: descriptionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'left',\n maxLines: 2,\n },\n },\n position: {\n x: axisEndX + markerRadius * 1.6,\n y: y - descriptionFontSize * 0.7,\n width: Math.max(48, outerMargin - markerRadius * 2),\n anchor: 'top-left',\n },\n animation: { type: 'fadeIn', duration: 0.5, delay: trackDelay },\n });\n }\n\n track.events.forEach((event, eventIndex) => {\n const point = {\n event,\n trackIndex,\n eventIndex,\n x: axisStartX + axisWidth * clamp01(event.position),\n y,\n } satisfies EventPoint;\n eventPoints.push(point);\n if (!eventPointById.has(event.id)) eventPointById.set(event.id, point);\n });\n });\n\n // Branches sit behind markers and callouts so their endpoints disappear\n // cleanly beneath the event dots.\n const links = coerceLinks(input.links, new Set(eventPointById.keys()));\n links.forEach((link, linkIndex) => {\n const source = eventPointById.get(link.source);\n const target = eventPointById.get(link.target);\n if (!source || !target) return;\n const bend = Math.min(90, Math.max(42, trackBand * 0.28));\n layers.push({\n type: 'path',\n id: `timeline-link-${safeId(link.source)}-${safeId(link.target)}-${linkIndex}`,\n content: {\n d: branchPath(source, target, bend),\n stroke: branchColor,\n strokeWidth: Math.max(2, markerRadius * 0.26),\n fill: 'none',\n endMarker: 'arrow',\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n animation: { type: 'fadeIn', duration: 0.6, delay: 0.45 + linkIndex * 0.08 },\n });\n\n if (link.label) {\n const sameTrack = source.trackIndex === target.trackIndex;\n const linkLabelWidth = Math.min(\n 320,\n Math.max(150, link.label.length * descriptionFontSize * 0.55 + 24),\n );\n const linkLabelHeight = Math.min(\n descriptionFontSize * 1.25 * 2 + 8,\n estimateTextHeight(link.label, descriptionFontSize, linkLabelWidth, 1.25) + 8,\n );\n let linkLabelX = (source.x + target.x) / 2;\n const sameTrackSourceSide =\n source.event.side ?? (source.eventIndex % 2 === 0 ? 'above' : 'below');\n const sameTrackDirection = sameTrackSourceSide === 'above' ? 1 : -1;\n let linkLabelY = sameTrack\n ? source.y + sameTrackDirection * (bend + descriptionFontSize * 0.6)\n : (source.y + target.y) / 2;\n if (!sameTrack) {\n // Offset perpendicular to the branch so vertical/cross-track paths do\n // not run through their labels. Choose the sign that stays in-frame.\n const dx = target.x - source.x;\n const dy = target.y - source.y;\n const length = Math.max(1, Math.hypot(dx, dy));\n const offset = linkLabelWidth * 0.56;\n const candidateX = linkLabelX + (-dy / length) * offset;\n const candidateY = linkLabelY + (dx / length) * offset;\n const fits =\n candidateX >= linkLabelWidth / 2 + 8 &&\n candidateX <= viewport.width - linkLabelWidth / 2 - 8 &&\n candidateY >= descriptionFontSize * 1.5 &&\n candidateY <= viewport.height - 12;\n const sign = fits ? 1 : -1;\n linkLabelX += sign * (-dy / length) * offset;\n linkLabelY += sign * (dx / length) * offset;\n }\n linkLabelX = clamp(\n linkLabelX,\n linkLabelWidth / 2 + 8,\n viewport.width - linkLabelWidth / 2 - 8,\n );\n linkLabelY = clamp(linkLabelY, descriptionFontSize * 1.5, viewport.height - 12);\n layers.push({\n type: 'text',\n id: `timeline-link-label-${linkIndex}`,\n content: {\n text: link.label,\n style: {\n fontSize: descriptionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n background: theme.colors.background,\n backgroundOpacity: 0.88,\n padding: 4,\n maxLines: 2,\n verticalAlign: 'middle',\n },\n },\n position: {\n x: linkLabelX,\n y: linkLabelY,\n width: linkLabelWidth,\n height: linkLabelHeight,\n anchor: 'center',\n },\n animation: { type: 'fadeIn', duration: 0.5, delay: 0.55 + linkIndex * 0.08 },\n });\n }\n });\n\n const stemLength = Math.min(78, Math.max(34, trackBand * 0.2));\n\n for (const point of eventPoints) {\n const { event, trackIndex, eventIndex, x, y } = point;\n const side = event.side ?? (eventIndex % 2 === 0 ? 'above' : 'below');\n const direction = side === 'above' ? -1 : 1;\n const stemEndY = y + direction * stemLength;\n const delay = 0.28 + trackIndex * 0.12 + eventIndex * 0.07;\n const eventLayerId = `${safeId(event.id)}-${trackIndex}-${eventIndex}`;\n const pointMarkerRadius = trackMarkerRadii[trackIndex] ?? markerRadius;\n const calloutX = clamp(x, calloutWidth / 2 + 8, viewport.width - calloutWidth / 2 - 8);\n\n const addStem = (stemId: string, endY: number, stemDelay: number): void => {\n layers.push({\n type: 'path',\n id: stemId,\n content: {\n d: `M ${x} ${y} L ${calloutX} ${endY}`,\n stroke: calloutColor,\n strokeWidth: Math.max(1, markerRadius * 0.18),\n fill: 'none',\n },\n position: {\n x: Math.min(x, calloutX),\n y: Math.min(y, endY),\n width: Math.max(2, Math.abs(calloutX - x)),\n height: Math.max(2, Math.abs(endY - y)),\n },\n animation: { type: 'fadeIn', duration: 0.4, delay: stemDelay },\n });\n };\n\n if (event.callout !== false) {\n addStem(`timeline-stem-${eventLayerId}`, stemEndY, delay);\n const descriptionSide = event.descriptionSide ?? side;\n if (event.description && descriptionSide !== side) {\n const descriptionDirection = descriptionSide === 'above' ? -1 : 1;\n addStem(\n `timeline-description-stem-${eventLayerId}`,\n y + descriptionDirection * stemLength,\n delay + 0.03,\n );\n }\n }\n\n const marker = event.marker ?? 'filled';\n if (marker === 'diamond') {\n layers.push(\n diamondLayer(\n `timeline-marker-${eventLayerId}`,\n x,\n y,\n pointMarkerRadius,\n accentColor,\n delay,\n ),\n );\n } else {\n const dot: ShapeLayer = {\n type: 'shape',\n id: `timeline-marker-${eventLayerId}`,\n content: {\n shape: 'circle',\n fill: marker === 'hollow' ? theme.colors.background : accentColor,\n stroke: accentColor,\n strokeWidth: Math.max(1.5, pointMarkerRadius * 0.28),\n },\n position: {\n x: x - pointMarkerRadius,\n y: y - pointMarkerRadius,\n width: pointMarkerRadius * 2,\n height: pointMarkerRadius * 2,\n },\n animation: { type: 'zoomIn', duration: 0.35, delay },\n };\n layers.push(dot);\n }\n\n if (event.callout !== false) {\n const labelLineHeight = 1.2;\n const labelHeight = Math.min(\n estimateTextHeight(event.label, eventFontSize, calloutWidth, labelLineHeight),\n eventFontSize * labelLineHeight * 2,\n );\n const labelLines = Math.max(1, Math.round(labelHeight / (eventFontSize * labelLineHeight)));\n const unclampedLabelY =\n direction > 0\n ? stemEndY + eventFontSize * 0.9\n : stemEndY - (labelLines - 1) * eventFontSize * labelLineHeight - eventFontSize * 0.9;\n const labelY = clamp(\n unclampedLabelY,\n eventFontSize,\n viewport.height - (labelLines - 1) * eventFontSize * labelLineHeight - 12,\n );\n layers.push({\n type: 'text',\n id: `timeline-event-label-${eventLayerId}`,\n content: {\n text: event.label,\n style: {\n fontSize: eventFontSize,\n fontFamily: getThemeFont(context, 'body'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n lineHeight: labelLineHeight,\n shadow: shouldUseShadow(context),\n maxLines: 2,\n },\n },\n position: { x: calloutX, y: labelY, width: calloutWidth, anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.5, delay: delay + 0.08 },\n });\n\n if (event.description) {\n const descriptionSide = event.descriptionSide ?? side;\n const descriptionDirection = descriptionSide === 'above' ? -1 : 1;\n const descriptionLineHeight = 1.25;\n const descriptionMaxLines = context.orientation === 'portrait' ? 6 : 4;\n const descriptionHeight = Math.min(\n estimateTextHeight(\n event.description,\n descriptionFontSize,\n calloutWidth,\n descriptionLineHeight,\n ),\n descriptionFontSize * descriptionLineHeight * descriptionMaxLines,\n );\n const descriptionLines = Math.max(\n 1,\n Math.round(descriptionHeight / (descriptionFontSize * descriptionLineHeight)),\n );\n const descriptionStemEndY = y + descriptionDirection * stemLength;\n let descriptionY: number;\n if (descriptionSide !== side) {\n descriptionY =\n descriptionDirection > 0\n ? descriptionStemEndY + descriptionFontSize * 0.9\n : descriptionStemEndY -\n (descriptionLines - 1) * descriptionFontSize * descriptionLineHeight -\n descriptionFontSize * 0.9;\n } else if (descriptionDirection > 0) {\n descriptionY =\n labelY + labelLines * eventFontSize * labelLineHeight + descriptionFontSize * 0.45;\n } else {\n descriptionY =\n labelY -\n descriptionLines * descriptionFontSize * descriptionLineHeight -\n descriptionFontSize * 0.45;\n }\n descriptionY = clamp(\n descriptionY,\n descriptionFontSize,\n viewport.height -\n (descriptionLines - 1) * descriptionFontSize * descriptionLineHeight -\n 12,\n );\n layers.push({\n type: 'text',\n id: `timeline-event-description-${eventLayerId}`,\n content: {\n text: event.description,\n style: {\n fontSize: descriptionFontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: theme.colors.textMuted,\n textAlign: 'center',\n lineHeight: descriptionLineHeight,\n maxLines: descriptionMaxLines,\n },\n },\n position: { x: calloutX, y: descriptionY, width: calloutWidth, anchor: 'center' },\n animation: { type: 'fadeIn', duration: 0.5, delay: delay + 0.14 },\n });\n }\n }\n }\n\n return layers;\n}\n","/**\n * Drawing layout — shared, pure derivation of shapes + connectors from a\n * drawing block's child headings. Same children always produce the same\n * shapes, so SSR previews, exports, and (eventually) the editor stay\n * visually consistent. Mirrors `diagramLayout.ts` for the richer\n * free-form shape vocabulary.\n *\n * Each child heading is one shape. Its `{[shape …]}` annotation names the\n * primitive (`child.template`) and carries geometry/style as string params\n * (`child.templateOverrides`); `child.id` makes it referenceable;\n * `child.title` is the label.\n *\n * Layout rules (parallel to the diagram):\n * 1. Shapes with both `x` and `y` keep their authored coordinates.\n * 2. Shapes missing either are auto-placed in a square-ish grid below the\n * bounding box of the explicitly-positioned shapes.\n * 3. `line`/`arrow` shapes with `from`/`to` (or any shape's `connectsTo`)\n * become connectors; endpoints that match no sibling id are dropped\n * (and counted in `warnings`).\n */\n\nimport type { Block, MarkerStyle } from '../../schemas/Doc.js';\nimport { extractPlainText } from '../../markdown/utils.js';\nimport { lineStyleDasharray, type ConnectorRouting } from '../utils/shapeGeometry.js';\n\n/**\n * The shape kinds a drawing can render. `rect`/`circle`/`line` render as a\n * native `ShapeLayer`; everything else (and `path`/`arrow`) renders as a\n * computed `PathLayer` (see `shapeGeometry.ts`). `text` is a `TextLayer`.\n */\nexport type DrawingShapeKind =\n | 'rect'\n | 'circle'\n | 'line'\n | 'arrow'\n | 'path'\n | 'text'\n | 'triangle'\n | 'right-triangle'\n | 'diamond'\n | 'pentagon'\n | 'hexagon'\n | 'octagon'\n | 'star'\n | 'star4'\n | 'star6'\n | 'parallelogram'\n | 'trapezoid'\n | 'plus'\n | 'chevron'\n | 'arrow-right'\n | 'arrow-left'\n | 'arrow-up'\n | 'arrow-down'\n | 'double-arrow'\n | 'callout'\n | 'cylinder'\n | 'cloud'\n | 'heart'\n | 'lightning';\n\n/**\n * Author-facing shape annotation names accepted on a drawing's children\n * (the `{[…]}` token). Shared with validation so an unknown shape gets a\n * \"did you mean\" suggestion. Aliases (`rectangle`→rect, `ellipse`→circle)\n * are included.\n */\nexport const SHAPE_NAMES = [\n 'rectangle',\n 'rect',\n 'square',\n 'circle',\n 'ellipse',\n 'oval',\n 'line',\n 'arrow',\n 'path',\n 'text',\n 'triangle',\n 'right-triangle',\n 'diamond',\n 'rhombus',\n 'pentagon',\n 'hexagon',\n 'octagon',\n 'star',\n 'star4',\n 'star6',\n 'parallelogram',\n 'trapezoid',\n 'plus',\n 'cross',\n 'chevron',\n 'arrow-right',\n 'arrow-left',\n 'arrow-up',\n 'arrow-down',\n 'double-arrow',\n 'callout',\n 'speech',\n 'cylinder',\n 'cloud',\n 'heart',\n 'lightning',\n 'bolt',\n] as const;\n\nconst SHAPE_ALIASES: Readonly<Record<string, DrawingShapeKind>> = {\n rectangle: 'rect',\n rect: 'rect',\n square: 'rect',\n circle: 'circle',\n ellipse: 'circle',\n oval: 'circle',\n line: 'line',\n arrow: 'arrow',\n path: 'path',\n text: 'text',\n label: 'text',\n triangle: 'triangle',\n 'right-triangle': 'right-triangle',\n righttriangle: 'right-triangle',\n diamond: 'diamond',\n rhombus: 'diamond',\n pentagon: 'pentagon',\n hexagon: 'hexagon',\n octagon: 'octagon',\n star: 'star',\n star5: 'star',\n star4: 'star4',\n star6: 'star6',\n parallelogram: 'parallelogram',\n trapezoid: 'trapezoid',\n plus: 'plus',\n cross: 'plus',\n chevron: 'chevron',\n 'arrow-right': 'arrow-right',\n arrowright: 'arrow-right',\n rightarrow: 'arrow-right',\n 'arrow-left': 'arrow-left',\n arrowleft: 'arrow-left',\n leftarrow: 'arrow-left',\n 'arrow-up': 'arrow-up',\n arrowup: 'arrow-up',\n uparrow: 'arrow-up',\n 'arrow-down': 'arrow-down',\n arrowdown: 'arrow-down',\n downarrow: 'arrow-down',\n 'double-arrow': 'double-arrow',\n doublearrow: 'double-arrow',\n callout: 'callout',\n speech: 'callout',\n bubble: 'callout',\n cylinder: 'cylinder',\n can: 'cylinder',\n cloud: 'cloud',\n heart: 'heart',\n lightning: 'lightning',\n bolt: 'lightning',\n};\n\n/**\n * Resolve a child's `{[…]}` annotation name to a shape kind, or `null`\n * when it isn't a shape. Case-insensitive.\n */\nexport function normalizeShapeKind(name: string | undefined): DrawingShapeKind | null {\n if (!name) return null;\n return SHAPE_ALIASES[name.toLowerCase()] ?? null;\n}\n\n/** True when `name` is an accepted shape annotation (any alias). */\nexport function isShapeName(name: string | undefined): boolean {\n return normalizeShapeKind(name) != null;\n}\n\n/** A positioned shape in author-defined units (top-left origin). */\nexport interface DrawingShape {\n id: string;\n kind: DrawingShapeKind;\n x: number;\n y: number;\n width: number;\n height: number;\n /** True when position came from `x=`/`y=`; false when auto-laid out. */\n pinned: boolean;\n /** Heading text used as the shape's label ('' when none). */\n label: string;\n /** Body text under the heading, used as a sublabel (when present). */\n sublabel?: string;\n /** Text content for `text` shapes (`text=` param, else label, else body). */\n text?: string;\n /** Raw SVG path `d` for `path` shapes. */\n d?: string;\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n borderRadius?: number;\n dasharray?: string;\n}\n\n/** A connector joining two shapes by id. */\nexport interface DrawingConnector {\n id: string;\n kind: 'line' | 'arrow';\n /** Source shape id (resolved to an existing shape). */\n from: string;\n /** Target shape id (resolved to an existing shape). */\n to: string;\n /** Optional midpoint label (heading text, or `connectsTo` type). */\n label?: string;\n stroke?: string;\n strokeWidth?: number;\n dasharray?: string;\n /** End-of-line markers (default: `arrow` kind → filled arrow at `to`). */\n startMarker: MarkerStyle;\n endMarker: MarkerStyle;\n /** How the line is routed between the two shapes. Default: 'straight'. */\n routing: ConnectorRouting;\n}\n\nexport interface DrawingLayout {\n shapes: DrawingShape[];\n connectors: DrawingConnector[];\n warnings: string[];\n}\n\nexport interface DrawingLayoutOptions {\n /** Horizontal spacing between auto-laid-out shapes. Default: 180. */\n gapX?: number;\n /** Vertical spacing between auto-laid-out shapes. Default: 140. */\n gapY?: number;\n /** Padding below the explicit bounding box before the grid starts. Default: 80. */\n gridPad?: number;\n /** Grid origin when no explicit shapes anchor it. Default: 80, 80. */\n gridOriginX?: number;\n gridOriginY?: number;\n}\n\nconst DEFAULT_OPTS: Required<DrawingLayoutOptions> = {\n gapX: 180,\n gapY: 140,\n gridPad: 80,\n gridOriginX: 80,\n gridOriginY: 80,\n};\n\n/** Default size (author units) per shape kind when width/height are omitted. */\nconst DEFAULT_SIZE: Partial<Record<DrawingShapeKind, { w: number; h: number }>> = {\n rect: { w: 160, h: 90 },\n circle: { w: 120, h: 120 },\n line: { w: 160, h: 0 },\n arrow: { w: 160, h: 0 },\n path: { w: 160, h: 120 },\n text: { w: 200, h: 48 },\n};\nconst FALLBACK_SIZE = { w: 120, h: 120 };\n\nfunction defaultSize(kind: DrawingShapeKind): { w: number; h: number } {\n return DEFAULT_SIZE[kind] ?? FALLBACK_SIZE;\n}\n\n/**\n * Compute shapes + connectors for a drawing from its parent block's\n * children. Pure — same inputs always produce the same output.\n */\nexport function computeDrawingLayout(\n children: readonly Block[],\n options: DrawingLayoutOptions = {},\n): DrawingLayout {\n const opts = { ...DEFAULT_OPTS, ...options };\n const warnings: string[] = [];\n\n // First pass: turn each child into a shape descriptor (or a pending\n // connector). Track which shapes still need an auto-grid slot.\n interface Entry {\n shape: DrawingShape;\n hasX: boolean;\n hasY: boolean;\n }\n const entries: Entry[] = [];\n const unpositioned: number[] = [];\n\n // Connectors are resolved after all shape ids are known.\n interface PendingConnector {\n id: string;\n kind: 'line' | 'arrow';\n from: string;\n to: string;\n label?: string;\n stroke?: string;\n strokeWidth?: number;\n dasharray?: string;\n startMarker: MarkerStyle;\n endMarker: MarkerStyle;\n routing: ConnectorRouting;\n source: string; // child id, for warning messages\n }\n const pendingConnectors: PendingConnector[] = [];\n\n for (const child of children) {\n const kind = normalizeShapeKind(child.template);\n const params = child.templateOverrides ?? {};\n const label = child.title ?? '';\n const body = bodyText(child);\n\n if (!kind) {\n warnings.push(\n `Child \"${child.id}\" is not a shape (annotation \"${child.template ?? '—'}\") and was skipped`,\n );\n continue;\n }\n\n // line/arrow with from/to (or any shape's connectsTo) → connector.\n const from = strParam(params, 'from');\n const to = strParam(params, 'to');\n if ((kind === 'line' || kind === 'arrow') && (from || to)) {\n pendingConnectors.push({\n id: child.id,\n kind,\n from: from ?? '',\n to: to ?? '',\n ...(label ? { label } : {}),\n ...connectorSemantics(params, kind),\n source: child.id,\n });\n continue;\n }\n\n // Diagram-compatible: a shape's `connectsTo` also emits arrow connectors.\n for (const conn of child.connectsTo ?? []) {\n pendingConnectors.push({\n id: `${child.id}->${conn.target}${conn.type ? `:${conn.type}` : ''}`,\n kind: 'arrow',\n from: child.id,\n to: conn.target,\n ...(conn.type ? { label: conn.type } : {}),\n ...connectorSemantics(params, 'arrow'),\n source: child.id,\n });\n }\n\n const size = defaultSize(kind);\n // Prefer annotation params; fall back to Block.x/Block.y so children\n // authored the diagram way (coordinates on the block itself) place\n // identically here instead of silently dropping into the auto-grid.\n const x = numParam(params, 'x') ?? (typeof child.x === 'number' ? child.x : undefined);\n const y = numParam(params, 'y') ?? (typeof child.y === 'number' ? child.y : undefined);\n const shape: DrawingShape = {\n id: child.id,\n kind,\n x: x ?? 0,\n y: y ?? 0,\n width: numParam(params, 'width') ?? numParam(params, 'w') ?? size.w,\n height: numParam(params, 'height') ?? numParam(params, 'h') ?? size.h,\n pinned: x != null && y != null,\n label,\n ...(body ? { sublabel: body } : {}),\n ...styleParams(params),\n };\n if (kind === 'path') {\n const d = strParam(params, 'd');\n if (d) shape.d = d;\n }\n if (kind === 'text') {\n shape.text = strParam(params, 'text') ?? label ?? body ?? '';\n }\n if (numParam(params, 'borderRadius') != null) {\n shape.borderRadius = numParam(params, 'borderRadius');\n }\n\n entries.push({ shape, hasX: x != null, hasY: y != null });\n if (x == null || y == null) unpositioned.push(entries.length - 1);\n }\n\n // Second pass: auto-place shapes missing a coordinate in a grid below\n // the pinned bounding box (mirrors diagramLayout). Grid pitch accounts\n // for the largest unpositioned shape so wide/tall shapes never overlap\n // their grid neighbors.\n if (unpositioned.length > 0) {\n const cols = Math.max(1, Math.ceil(Math.sqrt(unpositioned.length)));\n const maxW = Math.max(...unpositioned.map((i) => entries[i].shape.width));\n const maxH = Math.max(...unpositioned.map((i) => entries[i].shape.height));\n const pitchX = Math.max(opts.gapX, maxW + 60);\n const pitchY = Math.max(opts.gapY, maxH + 50);\n let baseX = opts.gridOriginX;\n let baseY = opts.gridOriginY;\n const pinned = entries.filter((e) => e.shape.pinned);\n if (pinned.length > 0) {\n baseX = Math.min(...pinned.map((e) => e.shape.x));\n baseY = Math.max(...pinned.map((e) => e.shape.y + e.shape.height)) + opts.gridPad;\n }\n unpositioned.forEach((entryIdx, k) => {\n const col = k % cols;\n const row = Math.floor(k / cols);\n entries[entryIdx].shape.x = baseX + col * pitchX;\n entries[entryIdx].shape.y = baseY + row * pitchY;\n });\n }\n\n const shapes = entries.map((e) => e.shape);\n const shapeIds = new Set(shapes.map((s) => s.id));\n\n // Third pass: resolve connectors against known shape ids, dropping ghosts.\n const connectors: DrawingConnector[] = [];\n const seen = new Set<string>();\n for (const c of pendingConnectors) {\n if (!shapeIds.has(c.from) || !shapeIds.has(c.to)) {\n const missing = !shapeIds.has(c.from) ? c.from : c.to;\n warnings.push(\n `Connector \"${c.source}\" dropped: ${missing ? `no shape with id \"${missing}\"` : 'missing from/to'}`,\n );\n continue;\n }\n const key = `${c.kind}:${c.from}->${c.to}:${c.label ?? ''}`;\n if (seen.has(key)) continue;\n seen.add(key);\n const { source: _source, ...rest } = c;\n connectors.push(rest);\n }\n\n return { shapes, connectors, warnings };\n}\n\n// ============================================\n// Param coercion\n// ============================================\n\n/** Read a raw string param (trims a trailing comma — `x=21, y=25` is tolerated). */\nfunction strParam(params: Record<string, string>, key: string): string | undefined {\n const raw = params[key];\n if (raw == null) return undefined;\n const v = raw.replace(/,\\s*$/, '').trim();\n return v.length > 0 ? v : undefined;\n}\n\n/** Coerce a numeric param, tolerating a trailing comma. Returns undefined on failure. */\nfunction numParam(params: Record<string, string>, key: string): number | undefined {\n const v = strParam(params, key);\n if (v == null) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/** Stroke style pass-throughs shared by shapes and connectors. */\nfunction connectorStyle(params: Record<string, string>): {\n stroke?: string;\n strokeWidth?: number;\n dasharray?: string;\n} {\n const out: { stroke?: string; strokeWidth?: number; dasharray?: string } = {};\n const stroke = strParam(params, 'stroke');\n const strokeWidth = numParam(params, 'strokeWidth');\n const dasharray = strParam(params, 'dasharray');\n if (stroke) out.stroke = stroke;\n if (strokeWidth != null) out.strokeWidth = strokeWidth;\n if (dasharray) out.dasharray = dasharray;\n return out;\n}\n\n/** Style pass-throughs for a fillable shape — connector stroke set plus `fill`. */\nfunction styleParams(params: Record<string, string>): {\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n dasharray?: string;\n} {\n const fill = strParam(params, 'fill');\n return { ...connectorStyle(params), ...(fill ? { fill } : {}) };\n}\n\nconst MARKER_ALIASES: Readonly<Record<string, MarkerStyle>> = {\n none: 'none',\n arrow: 'arrow',\n triangle: 'arrow',\n filled: 'arrow',\n open: 'open',\n v: 'open',\n diamond: 'diamond',\n circle: 'circle',\n dot: 'circle',\n square: 'square',\n box: 'square',\n};\n\nconst ROUTING_ALIASES: Readonly<Record<string, ConnectorRouting>> = {\n straight: 'straight',\n direct: 'straight',\n orthogonal: 'orthogonal',\n elbow: 'orthogonal',\n step: 'orthogonal',\n curved: 'curved',\n curve: 'curved',\n bezier: 'curved',\n};\n\nfunction parseMarker(raw: string | undefined): MarkerStyle | undefined {\n return raw ? MARKER_ALIASES[raw.toLowerCase()] : undefined;\n}\n\nfunction parseRouting(raw: string | undefined): ConnectorRouting | undefined {\n return raw ? ROUTING_ALIASES[raw.toLowerCase()] : undefined;\n}\n\n/**\n * Connector-only semantics: stroke style + end markers + line style + routing.\n * The default end marker is a filled `arrow` for `arrow` connectors, `none`\n * for plain `line`s; `endStyle`/`startStyle` override. `lineStyle` fills in a\n * dasharray when no explicit `dasharray` is given.\n */\nfunction connectorSemantics(\n params: Record<string, string>,\n kind: 'line' | 'arrow',\n): {\n stroke?: string;\n strokeWidth?: number;\n dasharray?: string;\n startMarker: MarkerStyle;\n endMarker: MarkerStyle;\n routing: ConnectorRouting;\n} {\n const out = connectorStyle(params);\n const dasharray = out.dasharray ?? lineStyleDasharray(strParam(params, 'lineStyle'));\n return {\n ...out,\n ...(dasharray ? { dasharray } : {}),\n startMarker: parseMarker(strParam(params, 'startStyle')) ?? 'none',\n endMarker: parseMarker(strParam(params, 'endStyle')) ?? (kind === 'arrow' ? 'arrow' : 'none'),\n routing: parseRouting(strParam(params, 'routing')) ?? 'straight',\n };\n}\n\n/** Plain text of a block's body content (sublabel source). */\nfunction bodyText(block: Block): string {\n if (!block.contents || block.contents.length === 0) return '';\n return block.contents\n .map((node) => extractPlainText(node))\n .join(' ')\n .trim();\n}\n","/**\n * Drawing block template.\n *\n * Renders the parent block's children as free-form shapes on a canvas:\n * - Each child becomes a shape (`rect`/`circle` → ShapeLayer, `line`/\n * `arrow`/`path` → PathLayer, `text` → TextLayer) with its title as a\n * centered label and its body text as an optional sublabel.\n * - `line`/`arrow` children with `from`/`to` (and any child's\n * `connectsTo`) become connectors clipped to the shapes they join.\n *\n * Coordinates from `x`/`y`/`width`/`height` are author-defined units; the\n * template fits the bounding box of all shapes to the viewport with\n * padding (same approach as `diagramBlock`), so authors don't think in\n * absolute pixels.\n */\n\nimport type { Layer, ShapeLayer, TextLayer, PathLayer } from '../../schemas/Doc.js';\nimport type { DrawingBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont, themedFontSize } from '../utils/themeUtils.js';\nimport { computeDrawingLayout, type DrawingShape, type DrawingConnector } from './drawingLayout.js';\nimport { shapePath, connectorPath, snapEndpoints } from '../utils/shapeGeometry.js';\n\nconst PADDING = 80;\n\nexport function drawingBlock(input: DrawingBlockInput, context: TemplateContext): Layer[] {\n const { theme, viewport, children = [] } = context;\n const colors = resolveColorScheme(context, input.colorScheme);\n const defaultStroke = input.stroke ?? colors.text ?? theme.colors.text;\n const defaultFill = input.fill ?? 'none';\n\n const layout = computeDrawingLayout(children);\n\n // No shapes authored as children → empty drawing hint.\n if (layout.shapes.length === 0 && layout.connectors.length === 0) {\n return [emptyHint(input, context)];\n }\n\n // Bounding box of all shapes in author coordinates.\n const minX = Math.min(...layout.shapes.map((s) => s.x));\n const maxX = Math.max(...layout.shapes.map((s) => s.x + s.width));\n const minY = Math.min(...layout.shapes.map((s) => s.y));\n const maxY = Math.max(...layout.shapes.map((s) => s.y + s.height));\n\n const titleHeight = input.title ? 120 : 0;\n const availW = Math.max(1, viewport.width - PADDING * 2);\n const availH = Math.max(1, viewport.height - PADDING * 2 - titleHeight);\n const contentW = Math.max(1, maxX - minX);\n const contentH = Math.max(1, maxY - minY);\n\n // Uniform scale that fits both dimensions. Small drawings may grow\n // (shapes are vector) up to 1.8× so a three-shape sketch doesn't render\n // as a tiny off-center cluster; the title and the scaled drawing are\n // centered together as one group.\n const scale = Math.min(availW / contentW, availH / contentH, 1.8);\n const scaledW = contentW * scale;\n const scaledH = contentH * scale;\n const groupTop = Math.max(PADDING / 2, (viewport.height - titleHeight - scaledH) / 2);\n const offsetX = PADDING + (availW - scaledW) / 2;\n const offsetY = groupTop + titleHeight;\n\n const tx = (x: number) => offsetX + (x - minX) * scale;\n const ty = (y: number) => offsetY + (y - minY) * scale;\n const fontAdj = Math.min(Math.max(scale, 1), 1.5);\n\n const layers: Layer[] = [];\n\n if (input.title) {\n layers.push({\n type: 'text',\n id: 'drawing-title',\n content: {\n text: input.title,\n style: {\n fontSize: themedFontSize(40, context, true),\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: theme.colors.text,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: groupTop + titleHeight / 2 - 16, anchor: 'center' },\n });\n }\n\n // Center lookup so connectors can clip to the shapes they join.\n const boxes = new Map<string, { cx: number; cy: number; rx: number; ry: number }>();\n for (const s of layout.shapes) {\n const x = tx(s.x);\n const y = ty(s.y);\n const w = s.width * scale;\n const h = s.height * scale;\n boxes.set(s.id, {\n cx: x + w / 2,\n cy: y + h / 2,\n rx: Math.max(1, w / 2),\n ry: Math.max(1, h / 2),\n });\n }\n\n // Connectors first so they sit behind shapes.\n for (const conn of layout.connectors) {\n const a = boxes.get(conn.from);\n const b = boxes.get(conn.to);\n if (!a || !b) continue;\n const { start, end } = snapEndpoints(a, b);\n const path: PathLayer = {\n type: 'path',\n id: `connector-${conn.id}`,\n content: {\n d: connectorPath(conn.routing, start, end),\n stroke: conn.stroke ?? defaultStroke,\n strokeWidth: conn.strokeWidth ?? Math.round(2 * fontAdj),\n fill: 'none',\n ...(conn.dasharray ? { dasharray: conn.dasharray } : {}),\n ...(conn.startMarker !== 'none' ? { startMarker: conn.startMarker } : {}),\n ...(conn.endMarker !== 'none' ? { endMarker: conn.endMarker } : {}),\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n layers.push(path);\n if (conn.label) layers.push(connectorLabel(conn, a, b, context, fontAdj));\n }\n\n // Shapes (and their labels) on top.\n for (const s of layout.shapes) {\n const x = tx(s.x);\n const y = ty(s.y);\n const w = s.width * scale;\n const h = s.height * scale;\n layers.push(...shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj));\n }\n\n return layers;\n}\n\n// ============================================\n// Per-shape layer emission\n// ============================================\n\nfunction shapeLayers(\n s: DrawingShape,\n x: number,\n y: number,\n w: number,\n h: number,\n context: TemplateContext,\n defaultStroke: string,\n defaultFill: string,\n fontAdj: number,\n): Layer[] {\n const out: Layer[] = [];\n const stroke = s.stroke ?? defaultStroke;\n const fill = s.fill ?? defaultFill;\n\n if (s.kind === 'text') {\n out.push(\n textLayer(\n `shape-${s.id}`,\n s.text ?? s.label ?? '',\n x + w / 2,\n y + h / 2,\n w,\n context,\n s.stroke ?? context.theme.colors.text,\n true,\n fontAdj,\n ),\n );\n return out;\n }\n\n if (s.kind === 'rect' || s.kind === 'circle') {\n const shape: ShapeLayer = {\n type: 'shape',\n id: `shape-${s.id}`,\n content: {\n shape: s.kind,\n fill,\n stroke,\n strokeWidth: s.strokeWidth ?? Math.round(2 * fontAdj),\n ...(s.kind === 'rect' && s.borderRadius != null ? { borderRadius: s.borderRadius } : {}),\n },\n position: { x, y, width: w, height: h },\n };\n out.push(shape);\n } else {\n // line / arrow / path / polygon shapes → PathLayer.\n const diagonal = `M ${round(x)} ${round(y)} L ${round(x + w)} ${round(y + h)}`;\n let d = diagonal;\n let pathFill = 'none';\n let endMarker: 'none' | 'arrow' = 'none';\n if (s.kind === 'path') {\n d = s.d ?? diagonal;\n pathFill = fill;\n } else if (s.kind === 'arrow') {\n endMarker = 'arrow';\n } else if (s.kind !== 'line') {\n // Named polygon / curved shape → computed filled path.\n d = shapePath(s.kind, x, y, w, h) ?? diagonal;\n pathFill = fill;\n }\n const path: PathLayer = {\n type: 'path',\n id: `shape-${s.id}`,\n content: {\n d,\n stroke,\n strokeWidth: s.strokeWidth ?? Math.round(2 * fontAdj),\n fill: pathFill,\n ...(s.dasharray ? { dasharray: s.dasharray } : {}),\n ...(endMarker !== 'none' ? { endMarker } : {}),\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n };\n out.push(path);\n }\n\n // Label (heading text) centered on the shape; sublabel (body) below it.\n if (s.label) {\n out.push(\n textLayer(\n `shape-label-${s.id}`,\n s.label,\n x + w / 2,\n y + h / 2,\n w,\n context,\n s.stroke ?? context.theme.colors.text,\n true,\n fontAdj,\n ),\n );\n }\n if (s.sublabel) {\n out.push(\n textLayer(\n `shape-sublabel-${s.id}`,\n s.sublabel,\n x + w / 2,\n y + h + 14 * fontAdj,\n w,\n context,\n context.theme.colors.textMuted,\n false,\n fontAdj,\n ),\n );\n }\n return out;\n}\n\nfunction textLayer(\n id: string,\n text: string,\n cx: number,\n cy: number,\n width: number,\n context: TemplateContext,\n color: string,\n bold: boolean,\n fontAdj: number,\n): TextLayer {\n return {\n type: 'text',\n id,\n content: {\n text,\n style: {\n fontSize: themedFontSize(Math.round((bold ? 22 : 18) * fontAdj), context, false),\n fontFamily: getThemeFont(context, 'body'),\n ...(bold ? { fontWeight: 'bold' as const } : {}),\n color,\n textAlign: 'center',\n },\n },\n position: { x: cx, y: cy, anchor: 'center', width },\n };\n}\n\nfunction connectorLabel(\n conn: DrawingConnector,\n a: { cx: number; cy: number },\n b: { cx: number; cy: number },\n context: TemplateContext,\n fontAdj: number,\n): TextLayer {\n const fontSize = themedFontSize(Math.round(18 * fontAdj), context, false);\n return {\n type: 'text',\n id: `connector-label-${conn.id}`,\n content: {\n text: conn.label ?? '',\n style: {\n fontSize,\n fontFamily: getThemeFont(context, 'body'),\n color: context.theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n // Floated just above the connector midpoint so the line never\n // strikes through the label text.\n position: { x: (a.cx + b.cx) / 2, y: (a.cy + b.cy) / 2 - fontSize * 0.9, anchor: 'center' },\n };\n}\n\nfunction emptyHint(input: DrawingBlockInput, context: TemplateContext): TextLayer {\n return {\n type: 'text',\n id: 'drawing-empty',\n content: {\n text: input.title ?? 'Empty drawing',\n style: {\n fontSize: themedFontSize(36, context, true),\n fontFamily: getThemeFont(context, 'title'),\n color: context.theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '50%', anchor: 'center' },\n };\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100;\n}\n","/**\n * Layout layout — pure derivation of positioned layers from a `layout`\n * block's child sub-blocks. The layout counterpart to `drawingLayout.ts`,\n * with two deliberate differences:\n *\n * - **Absolute** positioning. Each child's `x`/`y`/`width`/`height` are\n * used as-is in viewport units (no auto-grid, no fit-to-viewport\n * scaling). A layout is a free-form canvas; authors place things where\n * they want them.\n * - **Text content lives in the child body.** A `{[text …]}` child's\n * paragraphs/lists/marks under its heading become the text — readable\n * markdown rather than an encoded blob. (`content.html` is filled by the\n * editor for rich on-canvas rendering; SSR uses the plain `content.text`.)\n *\n * Each child heading is one layer: `### {#id} {[<type> x=.. y=.. …]}`.\n * Children are emitted in document order, so the first child is the\n * back-most layer (painters' order).\n */\n\nimport type { Layer, ShapeLayer, TextLayer, PathLayer, ImageLayer } from '../../schemas/Doc.js';\nimport { extractPlainText } from '../../markdown/utils.js';\nimport { normalizeShapeKind } from './drawingLayout.js';\nimport { shapePath } from '../utils/shapeGeometry.js';\n\nexport interface LayoutLayersResult {\n layers: Layer[];\n warnings: string[];\n}\n\nexport interface LayoutLayerDefaults {\n /**\n * Default ink — text color and path/line stroke — used when the author\n * omits `color=`/`stroke=`. `layoutBlock` passes the theme text color so\n * un-styled text stays legible on dark themes; the editor's scene canvas\n * omits it and gets the dark-slate default that suits its fixed light\n * surface.\n */\n ink?: string;\n}\n\n/** Fallback ink for callers that don't supply defaults (editor scene canvas). */\nconst DEFAULT_INK = '#1e293b';\n\n/** Minimal Block shape this derivation reads (subset of `Block`). */\ninterface LayoutChildBlock {\n id: string;\n template?: string;\n templateOverrides?: Record<string, string>;\n title?: string;\n contents?: import('../../markdown/types.js').MarkdownNode[];\n}\n\nconst DEFAULT_TEXT = { w: 300, h: 80 };\nconst DEFAULT_SHAPE = { w: 160, h: 90 };\nconst DEFAULT_IMAGE = { w: 320, h: 240 };\n\n/**\n * Map a layout block's children → positioned layers. Pure: same children\n * always produce the same layers.\n */\nexport function computeLayoutLayers(\n children: readonly LayoutChildBlock[],\n _viewport: { width: number; height: number },\n defaults: LayoutLayerDefaults = {},\n): LayoutLayersResult {\n const ink = defaults.ink ?? DEFAULT_INK;\n const layers: Layer[] = [];\n const warnings: string[] = [];\n\n for (const child of children) {\n const params = child.templateOverrides ?? {};\n const annotation = (child.template ?? '').toLowerCase();\n const x = numParam(params, 'x') ?? 0;\n const y = numParam(params, 'y') ?? 0;\n\n if (annotation === 'image' || annotation === 'img') {\n const src = strParam(params, 'src');\n if (!src) {\n warnings.push(`Layout image \"${child.id}\" has no src= and was skipped`);\n continue;\n }\n const layer: ImageLayer = {\n id: child.id,\n type: 'image',\n position: {\n x,\n y,\n width: numParam(params, 'width') ?? DEFAULT_IMAGE.w,\n height: numParam(params, 'height') ?? DEFAULT_IMAGE.h,\n },\n content: {\n src,\n alt: strParam(params, 'alt') ?? '',\n ...(strParam(params, 'fit')\n ? { fit: strParam(params, 'fit') as 'cover' | 'contain' | 'fill' }\n : {}),\n },\n };\n layers.push(layer);\n continue;\n }\n\n const kind = normalizeShapeKind(child.template);\n if (!kind) {\n warnings.push(\n `Layout child \"${child.id}\" is not a layer (annotation \"${child.template ?? '—'}\") and was skipped`,\n );\n continue;\n }\n\n if (kind === 'text') {\n const text = bodyText(child) || child.title || '';\n const layer: TextLayer = {\n id: child.id,\n type: 'text',\n position: {\n x,\n y,\n width: numParam(params, 'width') ?? DEFAULT_TEXT.w,\n height: numParam(params, 'height') ?? DEFAULT_TEXT.h,\n },\n content: { text, style: textStyleFromParams(params, ink) },\n };\n layers.push(layer);\n continue;\n }\n\n const width = numParam(params, 'width') ?? numParam(params, 'w') ?? DEFAULT_SHAPE.w;\n const height = numParam(params, 'height') ?? numParam(params, 'h') ?? DEFAULT_SHAPE.h;\n\n if (kind === 'rect' || kind === 'circle') {\n const shape: ShapeLayer = {\n id: child.id,\n type: 'shape',\n position: { x, y, width, height },\n content: {\n shape: kind,\n ...(strParam(params, 'fill') ? { fill: strParam(params, 'fill') } : {}),\n ...(strParam(params, 'stroke') ? { stroke: strParam(params, 'stroke') } : {}),\n ...(numParam(params, 'strokeWidth') != null\n ? { strokeWidth: numParam(params, 'strokeWidth') }\n : {}),\n ...(strParam(params, 'borderStyle')\n ? { borderStyle: strParam(params, 'borderStyle') as 'solid' | 'dashed' | 'dotted' }\n : {}),\n ...(kind === 'rect' && numParam(params, 'borderRadius') != null\n ? { borderRadius: numParam(params, 'borderRadius') }\n : {}),\n },\n };\n layers.push(shape);\n continue;\n }\n\n // line / arrow / path / named polygon → PathLayer (absolute geometry).\n const diagonal = `M ${round(x)} ${round(y)} L ${round(x + width)} ${round(y + height)}`;\n let d = diagonal;\n let pathFill = 'none';\n let endMarker: 'none' | 'arrow' = 'none';\n if (kind === 'path') {\n d = strParam(params, 'd') ?? diagonal;\n pathFill = strParam(params, 'fill') ?? 'none';\n } else if (kind === 'arrow') {\n endMarker = 'arrow';\n } else if (kind !== 'line') {\n d = shapePath(kind, x, y, width, height) ?? diagonal;\n pathFill = strParam(params, 'fill') ?? 'none';\n }\n const path: PathLayer = {\n id: child.id,\n type: 'path',\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n content: {\n d,\n stroke: strParam(params, 'stroke') ?? ink,\n strokeWidth: numParam(params, 'strokeWidth') ?? 2,\n fill: pathFill,\n ...(strParam(params, 'dasharray') ? { dasharray: strParam(params, 'dasharray') } : {}),\n ...(endMarker !== 'none' ? { endMarker } : {}),\n },\n };\n layers.push(path);\n }\n\n return { layers, warnings };\n}\n\n/** Build a TextStyle from a text layer's annotation params. */\nfunction textStyleFromParams(\n params: Record<string, string>,\n ink: string,\n): TextLayer['content']['style'] {\n const style: TextLayer['content']['style'] = {\n fontSize: numParam(params, 'fontSize') ?? 32,\n color: strParam(params, 'color') ?? ink,\n };\n const fontFamily = strParam(params, 'fontFamily');\n if (fontFamily) style.fontFamily = fontFamily;\n const fontWeight = strParam(params, 'fontWeight');\n if (fontWeight === 'bold' || fontWeight === 'normal') style.fontWeight = fontWeight;\n const fontStyle = strParam(params, 'fontStyle');\n if (fontStyle === 'italic' || fontStyle === 'normal') style.fontStyle = fontStyle;\n const align = strParam(params, 'align');\n if (align === 'left' || align === 'center' || align === 'right') style.textAlign = align;\n const valign = strParam(params, 'valign');\n if (valign === 'top' || valign === 'middle' || valign === 'bottom') style.verticalAlign = valign;\n const lineHeight = numParam(params, 'lineHeight');\n if (lineHeight != null) style.lineHeight = lineHeight;\n const padding = numParam(params, 'padding');\n if (padding != null) style.padding = padding;\n const background = strParam(params, 'background');\n if (background) style.background = background;\n return style;\n}\n\n/** Read a raw string param (trims a trailing comma — `x=21, y=25` tolerated). */\nfunction strParam(params: Record<string, string>, key: string): string | undefined {\n const raw = params[key];\n if (raw == null) return undefined;\n const v = raw.replace(/,\\s*$/, '').trim();\n return v.length > 0 ? v : undefined;\n}\n\n/** Coerce a numeric param, tolerating a trailing comma. Undefined on failure. */\nfunction numParam(params: Record<string, string>, key: string): number | undefined {\n const v = strParam(params, key);\n if (v == null) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/** Plain text of a block's body content. */\nfunction bodyText(block: LayoutChildBlock): string {\n if (!block.contents || block.contents.length === 0) return '';\n return block.contents\n .map((node) => extractPlainText(node))\n .join('\\n')\n .trim();\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100;\n}\n","/**\n * Layout block template.\n *\n * Renders the parent block's children as free-form, **absolutely\n * positioned** layers on a canvas (text boxes, shapes, images). Unlike\n * `drawingBlock`, coordinates are used as-is — there is no fit-to-viewport\n * scaling — because a layout is a fixed-canvas composition.\n *\n * Each child is one layer: `### {#id} {[<type> x=.. y=.. …]}`. A text box's\n * content lives in its child body as markdown (see `computeLayoutLayers`).\n * Children render in document order (first child = back-most layer).\n */\n\nimport type { Layer, TextLayer } from '../../schemas/Doc.js';\nimport type { TemplateBlock, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { scaledFontSize } from '../../schemas/BlockTemplates.js';\nimport { getThemeFont } from '../utils/themeUtils.js';\nimport { computeLayoutLayers } from './layoutLayout.js';\n\nexport function layoutBlock(input: TemplateBlock, context: TemplateContext): Layer[] {\n const { theme, viewport, children = [] } = context;\n // Theme ink for un-styled text and strokes — the fixed dark-slate\n // default disappeared on dark themes.\n const { layers } = computeLayoutLayers(children, viewport, { ink: theme.colors.text });\n return layers.length > 0 ? layers : [emptyHint(input, context)];\n}\n\nfunction emptyHint(input: TemplateBlock, context: TemplateContext): TextLayer {\n return {\n type: 'text',\n id: 'layout-empty',\n content: {\n text: (input as { title?: string }).title ?? 'Empty layout',\n style: {\n fontSize: scaledFontSize(36, context, true),\n fontFamily: getThemeFont(context, 'title'),\n color: context.theme.colors.textMuted,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '50%', anchor: 'center' },\n };\n}\n","/**\n * Token resolver for user-defined custom templates.\n *\n * Custom templates author their layers with placeholder strings — e.g.\n * a TextLayer whose `content.text` is `\"Welcome, {title}!\"` — and the\n * resolver substitutes those placeholders against the source Block's\n * actual data at render time. Built-in templates don't use the\n * resolver; they construct strings imperatively in their own\n * functions.\n *\n * Token grammar (v2):\n * {name} — bare name, e.g. `{title}`, `{content}`,\n * `{children}`\n * {name:arg} — name with a string argument, e.g. `{image:0}`\n * (Nth image in the block's body), `{attr:key}`\n * {name|default} — pipe default: used when the token resolves to\n * the empty string, e.g. `{title|Untitled}`\n * {name:arg|default}— combined, e.g. `{attr:subtitle|Untitled}` or\n * `{image:1|fallback.jpg}` (the default is applied\n * AFTER arg splitting, so it works in image src)\n * {{name}} — escaped — renders as the literal text `{name}`\n * (lets an author include a real `{title}` in body\n * text without it being interpreted as a token)\n *\n * Unknown tokens are left as literal text so the author can see what's\n * misspelled. Tokens with no value (e.g. `{title}` when block.title is\n * undefined) collapse to the empty string — or to the pipe default when\n * one is supplied.\n *\n * Token semantics:\n * - {title} — Block.title\n * - {content} — extractPlainText() of Block.contents, joined\n * with single spaces\n * - {children} — comma-separated list of Block.children[].title\n * - {attr:key} — Block.templateOverrides[key] ?? templateData[key]\n * ?? metadata[key], stringified\n * - {image:N} — In TextLayer: the Nth image's `alt` text.\n * In ImageLayer.content.src: the Nth image's URL\n * (if no Nth image exists and no default is given,\n * the layer is dropped).\n *\n * Per-item tokens (only meaningful inside a layer that carries a\n * `repeat` directive — see {@link LayerRepeat}):\n * - {item} — image alt / child title / list-item text\n * - {item:src} — image src (empty for children / list items)\n * - {item:label} — item label (same as {item} for children/list items)\n * - {index} — 1-based position of the item in its collection\n */\n\nimport type { Block, Layer, ImageLayer } from '../../../schemas/Doc.js';\nimport type { CustomTemplateLayer } from '../../../schemas/CustomTemplates.js';\nimport type { MarkdownBlockNode, MarkdownNode } from '../../../markdown/types.js';\nimport { extractPlainText, walkMarkdownTree } from '../../../markdown/utils.js';\n\ninterface ImageRef {\n url: string;\n alt: string;\n}\n\n/**\n * One resolved iteration item, produced by {@link collectRepeatItems}\n * and threaded into token resolution for a repeated layer's clone.\n */\ninterface RepeatItem {\n /** `{item}` — image alt / child title / list-item text. */\n text: string;\n /** `{item:src}` — image URL (undefined for children / list items). */\n src?: string;\n /** `{item:label}` — a display label for the item. */\n label?: string;\n /** `{index}` — 1-based position in the source collection. */\n index: number;\n}\n\n// Matches a single token: name, optional `:arg`, optional `|default`.\n// The arg stops at `|` so the default can be split off afterwards; the\n// default runs to the closing brace. Recreated per call site would be\n// wasteful, but a shared global is safe: String.replace resets a global\n// regex's lastIndex, and resolution is single-threaded/sequential.\nconst TOKEN_RE = /\\{(\\w+)(?::([^}|]+))?(?:\\|([^}]*))?\\}/g;\n// Matches an escaped `{{…}}` block (no nested braces).\nconst ESCAPE_RE = /\\{\\{([^{}]*)\\}\\}/g;\n\n// Sentinels chosen so they can't collide with real user content and\n// survive plain-text copy; safer than zero-width characters.\nconst ESCAPED_OPEN = ' ESC_OPEN ';\nconst ESCAPED_CLOSE = ' ESC_CLOSE ';\n\n/**\n * Walk the block's body content collecting every `image` node in\n * document order — including inline images nested inside paragraphs,\n * list items, etc. `findNodesByType` only knows the block-node union;\n * we use the more permissive `walkMarkdownTree` so inline image nodes\n * (`type: 'image'`, an inline type) are also picked up.\n *\n * Returns an empty array when the block has no `contents` or none of\n * the contents contain images.\n */\nfunction collectImages(block: Block): ImageRef[] {\n if (!block.contents) return [];\n const out: ImageRef[] = [];\n const visit = (node: MarkdownNode): void => {\n if (node.type === 'image') {\n const img = node as MarkdownNode & { url?: string; alt?: string };\n out.push({ url: img.url ?? '', alt: img.alt ?? '' });\n }\n };\n for (const node of block.contents as MarkdownBlockNode[]) {\n walkMarkdownTree(node, (n) => {\n visit(n);\n return;\n });\n }\n return out;\n}\n\n/**\n * Walk the block's body content collecting the plain text of every\n * top-level list item, in document order. Mirrors {@link collectImages}\n * but for `{ repeat: { source: 'listItems' } }`. Nested lists are not\n * descended into separately — a nested list's text is already folded\n * into its parent item's text, so we skip children of a `listItem` to\n * avoid double-counting.\n *\n * Exported for the same reason `resolveTokens` is: it's the collector\n * the repeat machinery relies on and is unit-tested directly.\n */\nexport function collectListItems(block: Block): string[] {\n if (!block.contents) return [];\n const out: string[] = [];\n for (const node of block.contents as MarkdownBlockNode[]) {\n walkMarkdownTree(node, (n) => {\n if (n.type === 'listItem') {\n const text = extractPlainText(n).replace(/\\s+/g, ' ').trim();\n if (text) out.push(text);\n // Skip descent: this item's nested lists are already part of\n // its plain text above; don't visit them as separate items.\n return true;\n }\n return;\n });\n }\n return out;\n}\n\n/**\n * Plain-text join of Block.contents. Block-level boundaries become\n * spaces so a `{content}` substitution reads as natural prose rather\n * than running paragraphs together.\n */\nfunction getBlockBodyText(block: Block): string {\n if (!block.contents) return '';\n return (block.contents as MarkdownBlockNode[])\n .map((node) => extractPlainText(node).trim())\n .filter((s) => s.length > 0)\n .join(' ');\n}\n\n/** Comma-joined child titles (omits children without a title). */\nfunction getChildrenSummary(block: Block): string {\n if (!block.children || block.children.length === 0) return '';\n return block.children\n .map((c) => c.title?.trim())\n .filter((t): t is string => Boolean(t))\n .join(', ');\n}\n\nfunction escapeBraces(text: string): string {\n return text.replace(ESCAPE_RE, (_match, inner: string) => ESCAPED_OPEN + inner + ESCAPED_CLOSE);\n}\n\nfunction unescapeBraces(text: string): string {\n return text\n .replace(new RegExp(ESCAPED_OPEN, 'g'), '{')\n .replace(new RegExp(ESCAPED_CLOSE, 'g'), '}');\n}\n\n/**\n * Substitute every `{token}` occurrence in `text` using `resolve`,\n * preserving `{{token}}` as a literal `{token}`.\n *\n * `resolve` returns `null` for an unknown token (the whole match,\n * including any `|default`, is left literal) or a string value. When the\n * value is the empty string and a `|default` was supplied, the default\n * is used. Escaped `{{…}}` blocks are shielded first so tokens inside\n * them are never interpreted.\n */\nfunction substitute(\n text: string,\n resolve: (name: string, arg: string | undefined) => string | null,\n): string {\n const escaped = escapeBraces(text);\n const tokenized = escaped.replace(\n TOKEN_RE,\n (match, name: string, arg: string | undefined, def: string | undefined) => {\n const value = resolve(name, arg);\n if (value == null) return match;\n if (value === '' && def !== undefined) return def;\n return value;\n },\n );\n return unescapeBraces(tokenized);\n}\n\n/**\n * Look up a single token as text. Returns null when the token is\n * unknown — caller treats null as \"leave the placeholder literal\".\n * `{item}` / `{index}` resolve to null when there is no per-item\n * context (i.e. the layer isn't inside a `repeat`).\n */\nfunction resolveToken(\n name: string,\n arg: string | undefined,\n block: Block,\n images: ImageRef[],\n item: RepeatItem | undefined,\n): string | null {\n switch (name) {\n case 'title':\n return block.title ?? '';\n case 'content':\n return getBlockBodyText(block);\n case 'children':\n return getChildrenSummary(block);\n case 'attr': {\n if (!arg) return '';\n const raw =\n block.templateOverrides?.[arg] ?? block.templateData?.[arg] ?? block.metadata?.[arg];\n return raw == null ? '' : String(raw);\n }\n case 'image': {\n const idx = arg ? parseInt(arg, 10) : 0;\n if (!Number.isFinite(idx) || idx < 0 || idx >= images.length) return '';\n return images[idx].alt;\n }\n case 'item': {\n if (!item) return null;\n if (!arg) return item.text;\n if (arg === 'src') return item.src ?? '';\n if (arg === 'label') return item.label ?? '';\n return '';\n }\n case 'index':\n return item ? String(item.index) : null;\n default:\n return null;\n }\n}\n\nfunction substituteText(\n text: string,\n block: Block,\n images: ImageRef[],\n item: RepeatItem | undefined,\n): string {\n return substitute(text, (name, arg) => resolveToken(name, arg, block, images, item));\n}\n\n/**\n * Resolve tokens inside an ImageLayer's `content.src`. `{image:N}`\n * resolves to the Nth image's URL (not its alt); `{item:src}` and\n * `{attr:key}` resolve as usual. When an `{image:N}` has no matching\n * image AND no `|default`, the whole layer is dropped (returns null) so\n * we never leave a broken URL. A supplied default suppresses the drop.\n */\nfunction resolveImageSrc(\n src: string,\n block: Block,\n images: ImageRef[],\n item: RepeatItem | undefined,\n): string | null {\n // Optimization: nothing to resolve.\n if (!src.includes('{')) return src;\n\n let dropped = false;\n const escaped = escapeBraces(src);\n const tokenized = escaped.replace(\n TOKEN_RE,\n (match, name: string, arg: string | undefined, def: string | undefined) => {\n if (name === 'image') {\n const idx = arg ? parseInt(arg, 10) : 0;\n const ok = Number.isFinite(idx) && idx >= 0 && idx < images.length;\n if (ok) return images[idx].url;\n if (def !== undefined) return def;\n dropped = true;\n return '';\n }\n const value = resolveToken(name, arg, block, images, item);\n if (value == null) return match;\n if (value === '' && def !== undefined) return def;\n return value;\n },\n );\n\n if (dropped) return null;\n return unescapeBraces(tokenized);\n}\n\n/**\n * Parse the leading numeric magnitude of a position field (px number or\n * `%`-string). Used to advance the cursor between repeated clones.\n */\nfunction parseMagnitude(value: number | string | undefined): number {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const m = value.match(/-?\\d*\\.?\\d+/);\n if (m) return parseFloat(m[0]);\n }\n return 0;\n}\n\n/**\n * Offset a position coordinate by `delta`, preserving its unit: a bare\n * number stays a number; a `%`-string (or any suffixed string) keeps\n * its suffix.\n */\nfunction offsetCoord(base: number | string | undefined, delta: number): number | string {\n if (base == null) return delta;\n if (typeof base === 'number') return base + delta;\n const m = base.match(/^(\\s*)(-?\\d*\\.?\\d+)(.*)$/);\n if (m) {\n const next = parseFloat(m[2]) + delta;\n return `${m[1]}${next}${m[3]}`;\n }\n return base;\n}\n\n/** Build the per-item list for a `repeat` source collection. */\nfunction collectRepeatItems(\n source: 'images' | 'children' | 'listItems',\n block: Block,\n images: ImageRef[],\n): RepeatItem[] {\n switch (source) {\n case 'images':\n return images.map((img, i) => ({\n text: img.alt,\n src: img.url,\n label: img.alt,\n index: i + 1,\n }));\n case 'children':\n return (block.children ?? []).map((child, i) => ({\n text: child.title ?? '',\n label: child.title ?? '',\n index: i + 1,\n }));\n case 'listItems':\n return collectListItems(block).map((text, i) => ({ text, label: text, index: i + 1 }));\n default:\n return [];\n }\n}\n\n/**\n * Expand a `repeat` layer into one clone per item of its source\n * collection. Each clone is offset along `direction` by the cumulative\n * `(width|height) + gap`, has `repeat` stripped, gets a per-clone id,\n * and resolves per-item tokens against its item.\n */\nfunction expandRepeat(layer: CustomTemplateLayer, block: Block, images: ImageRef[]): Layer[] {\n const repeat = layer.repeat;\n if (!repeat) {\n const resolved = resolveLayer(layer, block, images, undefined);\n return resolved ? [resolved] : [];\n }\n\n const items = collectRepeatItems(repeat.source, block, images);\n const direction = repeat.direction ?? 'column';\n const gap = repeat.gap ?? 24;\n const limit =\n repeat.max != null && repeat.max >= 0 ? Math.min(repeat.max, items.length) : items.length;\n\n const out: Layer[] = [];\n let cursor = 0;\n for (let i = 0; i < limit; i++) {\n const position = { ...layer.position };\n if (direction === 'row') {\n position.x = offsetCoord(position.x, cursor);\n } else {\n position.y = offsetCoord(position.y, cursor);\n }\n\n const clone = { ...layer, position, id: `${layer.id}-${i}` } as CustomTemplateLayer;\n delete clone.repeat;\n\n const resolved = resolveLayer(clone, block, images, items[i]);\n if (resolved) out.push(resolved);\n\n const dim = direction === 'row' ? layer.position.width : layer.position.height;\n cursor += parseMagnitude(dim) + gap;\n }\n return out;\n}\n\n/**\n * Walk the layer array and produce a new array with all placeholder\n * tokens resolved. Layers carrying a `repeat` directive are expanded\n * into one clone per source item. ImageLayers whose `{image:N}` token\n * doesn't match a real image (and has no default) are filtered out.\n * Other layer types pass through unchanged.\n *\n * Pure function — does not mutate the input.\n */\nexport function resolveTokens(layers: readonly CustomTemplateLayer[], block: Block): Layer[] {\n const images = collectImages(block);\n const out: Layer[] = [];\n for (const layer of layers) {\n if (layer.repeat) {\n out.push(...expandRepeat(layer, block, images));\n } else {\n const resolved = resolveLayer(layer, block, images, undefined);\n if (resolved) out.push(resolved);\n }\n }\n return out;\n}\n\nfunction resolveLayer(\n layer: CustomTemplateLayer,\n block: Block,\n images: ImageRef[],\n item: RepeatItem | undefined,\n): Layer | null {\n switch (layer.type) {\n case 'text':\n return {\n ...layer,\n content: {\n ...layer.content,\n text: substituteText(layer.content.text, block, images, item),\n },\n };\n case 'image': {\n const nextSrc = resolveImageSrc(layer.content.src, block, images, item);\n if (nextSrc == null) return null;\n const next: ImageLayer = {\n ...layer,\n content: {\n ...layer.content,\n src: nextSrc,\n },\n };\n // Also try to substitute the alt text if it carries a token.\n if (layer.content.alt && layer.content.alt.includes('{')) {\n next.content.alt = substituteText(layer.content.alt, block, images, item);\n }\n return next;\n }\n default:\n return layer;\n }\n}\n","/**\n * Custom template factory.\n *\n * Turns a `CustomTemplateDefinition` (user-authored visual design with\n * placeholder tokens) into a runtime `TemplateFunction` that can be\n * dropped into the template registry alongside built-ins.\n *\n * The generated function's job is small: read the source `Block` from\n * `context.block` and hand the definition's layers off to\n * `resolveTokens` for placeholder substitution. The hard work (drag-\n * to-position, token grammar, image lookup) happens in the designer\n * UI and the resolver, not here.\n */\n\nimport type { Block, Layer } from '../../schemas/Doc.js';\nimport type {\n RawLayersInput,\n TemplateContext,\n TemplateFunction,\n} from '../../schemas/BlockTemplates.js';\nimport type { CustomTemplateDefinition } from '../../schemas/CustomTemplates.js';\nimport { resolveTokens } from './tokens/resolveTokens.js';\n\n/**\n * Build a template function for a user-authored custom template.\n *\n * The returned function is registered under `def.name` in the merged\n * registry (see `buildRegistry` in `templates/index.ts`). At expansion\n * time it receives the standard `TemplateBlock` + `TemplateContext`\n * pair; the context's `block` field carries the source markdown-derived\n * block whose data drives token resolution.\n *\n * When `context.block` is missing (shouldn't happen in the normal\n * pipeline but defensively handled), the layers are returned with\n * tokens left unresolved — better visible placeholders than a thrown\n * error.\n */\nexport function makeCustomTemplateFn(\n def: CustomTemplateDefinition,\n): TemplateFunction<RawLayersInput> {\n return (input: RawLayersInput, context: TemplateContext): Layer[] => {\n // `{attr:…}` reads the source block's `templateOverrides` /\n // `templateData` / `metadata`. Prefer `context.block` (the raw\n // block the expander attaches); fall back to `input` (the merged\n // TemplateBlock, itself a Block superset) so attributes still\n // resolve if `context.block` is ever absent.\n const block = context.block ?? (input as unknown as Block | undefined);\n if (!block) return def.layers.slice() as Layer[];\n return resolveTokens(def.layers, block);\n };\n}\n","/** Runtime registry composition for built-in and document-scoped templates. */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type {\n TemplateBlock,\n TemplateContext,\n TemplateRegistry,\n} from '../../schemas/BlockTemplates.js';\nimport type { CustomTemplateDefinition } from '../../schemas/CustomTemplates.js';\nimport { makeCustomTemplateFn } from './customTemplate.js';\n\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 { leftFeature, rightFeature } from './featureBlock.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';\nimport { diagramBlock } from './diagramBlock.js';\nimport { treeBlock } from './treeBlock.js';\nimport { timelineBlock } from './timelineBlock.js';\nimport { drawingBlock } from './drawingBlock.js';\nimport { layoutBlock } from './layoutBlock.js';\n\n/** Built-in templates keyed by the ids used in document annotations. */\nexport const templateRegistry: TemplateRegistry = {\n title: titleBlock,\n sectionHeader,\n statHighlight,\n quote: quoteBlock,\n factCard,\n twoColumn,\n dateEvent,\n imageWithCaption,\n leftFeature,\n rightFeature,\n map: mapBlock,\n fullBleedQuote,\n list: listBlock,\n photoGrid,\n definitionCard,\n comparisonBar,\n pullQuote,\n videoWithCaption,\n videoPullQuote,\n dataTable,\n diagram: diagramBlock,\n tree: treeBlock,\n timeline: timelineBlock,\n layout: layoutBlock,\n drawing: drawingBlock,\n};\n\n/** Broad runtime view used after a template name has selected its function. */\nexport type RuntimeTemplateRegistry = Record<\n string,\n (input: TemplateBlock, context: TemplateContext) => Layer[]\n>;\n\n/** Merge document-scoped templates without mutating the built-in registry. */\nexport function buildRegistry(\n custom?: readonly CustomTemplateDefinition[],\n): RuntimeTemplateRegistry {\n const merged: RuntimeTemplateRegistry = {\n ...(templateRegistry as unknown as RuntimeTemplateRegistry),\n };\n if (custom) {\n for (const definition of custom) {\n if (merged[definition.name]) continue;\n merged[definition.name] = makeCustomTemplateFn(\n definition,\n ) as unknown as RuntimeTemplateRegistry[string];\n }\n }\n return merged;\n}\n","/**\n * Render-style post-pass — applies a theme's mechanical motion defaults to\n * template-generated layers.\n *\n * This is the intent-free half of theme motion (see `themedEntrance` in\n * [themeUtils.ts](./themeUtils.ts) for the intent-bearing half): it never\n * decides *what kind* of entrance a layer gets, only\n *\n * 1. scales existing animation durations/delays by the theme's\n * `style.animationSpeed` multiplier (1.4 = calmer/slower, 0.7 = snappier,\n * 1.0 = no-op), and\n * 2. gives full-bleed cover imagery with no authored animation a gentle,\n * deterministic Ken Burns when the theme opts into ambient motion.\n *\n * Applied ONLY to template-generated layers — raw authored `block.layers`\n * are never touched, and an explicit `animation` (including\n * `{ type: 'none' }`) always wins.\n */\n\nimport type { Layer, Animation } from '../../schemas/Doc.js';\nimport type { Theme } from '../../schemas/Theme.js';\nimport { SeededRandom, hashString } from '../../random/index.js';\n\n/** The gentle Ken Burns variants ambient motion rotates between. */\nconst AMBIENT_VARIANTS: readonly Animation[] = [\n { type: 'slowZoom', direction: 'in' },\n { type: 'slowZoom', direction: 'out' },\n { type: 'slowZoom', panDirection: 'left' },\n { type: 'slowZoom', panDirection: 'right' },\n];\n\n/** Minimum ambient Ken Burns duration — short blocks shouldn't rush the pan. */\nconst MIN_AMBIENT_DURATION_SECONDS = 8;\n\nfunction isZeroish(v: number | string | undefined): boolean {\n return v === 0 || v === '0' || v === '0%';\n}\n\n/**\n * Full-bleed cover imagery is the only shape we can safely blanket-animate:\n * anything smaller (strips, insets, grid cells) was placed deliberately and\n * a zoom would fight the composition.\n */\nfunction isFullBleedCoverMedia(layer: Layer): boolean {\n if (layer.type !== 'image' && layer.type !== 'video') return false;\n const { position } = layer;\n if (!isZeroish(position.x) || !isZeroish(position.y)) return false;\n if (position.width !== '100%' || position.height !== '100%') return false;\n const fit = (layer.content as { fit?: string }).fit;\n return fit === undefined || fit === 'cover';\n}\n\n/** Whether the theme asks for ambient Ken Burns on otherwise-static imagery. */\nexport function themeWantsAmbientMotion(theme: Theme): boolean {\n return theme.renderStyle.ambientMotion === true;\n}\n\n/**\n * Apply the theme's mechanical motion defaults to a block's\n * template-generated layers. Pure: returns new layer objects where a change\n * applies and the original objects where none does.\n *\n * @param layers Template-generated layers (never raw authored layers)\n * @param block The source block — supplies the ambient-motion seed and duration\n * @param theme Resolved theme\n */\nexport function applyRenderStyleToLayers(\n layers: Layer[],\n block: { id: string; duration?: number },\n theme: Theme,\n): Layer[] {\n const speed = theme.style.animationSpeed ?? 1.0;\n const ambient = themeWantsAmbientMotion(theme);\n if (speed === 1.0 && !ambient) return layers;\n\n return layers.map((layer) => {\n let animation = layer.animation;\n\n // Ambient Ken Burns for full-bleed cover imagery with no authored\n // animation. Deterministic per block+layer so re-renders, export\n // frames, and screenshots always agree.\n if (!animation && ambient && isFullBleedCoverMedia(layer)) {\n const rng = new SeededRandom(hashString(`${block.id}:${layer.id}`));\n const variant = rng.pickRequired(AMBIENT_VARIANTS as Animation[]);\n animation = {\n ...variant,\n duration: Math.max(MIN_AMBIENT_DURATION_SECONDS, block.duration ?? 0),\n };\n }\n\n if (!animation || animation.type === 'none') {\n return animation === layer.animation ? layer : { ...layer, animation };\n }\n\n // Speed scaling — single site so templates never double-scale.\n if (speed !== 1.0) {\n animation = {\n ...animation,\n ...(animation.duration != null ? { duration: animation.duration * speed } : {}),\n ...(animation.delay != null ? { delay: animation.delay * speed } : {}),\n };\n }\n\n return animation === layer.animation ? layer : { ...layer, animation };\n });\n}\n","/**\n * Shared \"did-you-mean\" edit-distance helpers.\n *\n * A leaf module (no imports) so both `doc/validate.ts` and\n * `doc/templates/inputDescriptors.ts` can share one implementation without\n * risking an import cycle through `templates/index.ts`.\n */\n\n/** Levenshtein edit distance between two strings. */\nexport function levenshtein(a: string, b: string): number {\n if (a === b) return 0;\n const m = a.length;\n const n = b.length;\n if (m === 0) return n;\n if (n === 0) return m;\n let prev = new Array<number>(n + 1);\n let curr = new Array<number>(n + 1);\n for (let j = 0; j <= n; j++) prev[j] = j;\n for (let i = 1; i <= m; i++) {\n curr[0] = i;\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);\n }\n [prev, curr] = [curr, prev];\n }\n return prev[n];\n}\n\n/**\n * Nearest candidate name by edit distance, or `undefined` when nothing is\n * plausibly close. \"Close\" means distance ≤ `maxDistance` (default 2) OR\n * ≤ 40% of the input length — the shared threshold both call sites use.\n *\n * @param options.map - Optional post-processor applied to the winning\n * candidate (e.g. `resolveTemplateName` to canonicalize an alias hit).\n * @param options.maxDistance - Absolute distance floor for \"close\" (default 2).\n */\nexport function nearestName(\n input: string,\n candidates: Iterable<string>,\n options?: { map?: (best: string) => string; maxDistance?: number },\n): string | undefined {\n const maxDistance = options?.maxDistance ?? 2;\n let best: string | undefined;\n let bestDist = Infinity;\n const lower = input.toLowerCase();\n for (const candidate of candidates) {\n const dist = levenshtein(lower, candidate.toLowerCase());\n if (dist < bestDist) {\n bestDist = dist;\n best = candidate;\n }\n }\n if (best && (bestDist <= maxDistance || bestDist <= Math.ceil(input.length * 0.4))) {\n return options?.map ? options.map(best) : best;\n }\n return undefined;\n}\n","/**\n * Template input descriptors — a typed catalog of the inline `{[…]}` params\n * each built-in template understands, plus the pure coercion + lint logic\n * that consumes it.\n *\n * Two jobs, one source of truth:\n *\n * - **Coercion (`coerceTemplateParams`)** turns a flat `key → raw string`\n * param map (from a `{[name key=value]}` annotation, always strings) into a\n * partial typed input the template functions can consume directly — e.g.\n * `center=\"47.6,-122.3\"` → `{ lat: 47.6, lng: -122.3 }`, `zoom=9` → `9`.\n * This is what makes `{[map center=\"47.6,-122.3\" zoom=9]}` render with no\n * changes to any template function. Unknown keys ALWAYS pass through\n * untouched (as strings), so coercion is never lossy; coercion failures are\n * returned as `warnings` and the raw string is preserved.\n *\n * - **Linting (`lintTemplateParams`)** checks a param map against the\n * descriptors and reports unknown keys (with a did-you-mean suggestion),\n * values outside a closed enum / that fail coercion, and missing required\n * inputs. The document validator surfaces these as diagnostics.\n *\n * This mirrors the proven block-meta descriptor pattern in\n * `markdown/annotationCoercion.ts` (`BLOCK_META_KEY_DESCRIPTORS`), extended\n * from block geometry/timing to per-template content inputs.\n *\n * The descriptors are the `{[…]}` counterpart of the template input\n * interfaces in `schemas/BlockTemplates.ts` — only keys/enums that provably\n * exist on those interfaces are declared. Keys that can't be meaningfully\n * expressed as a single inline string (e.g. a `dataTable`'s `rows`) are still\n * declared with `coerce: 'string'` so they aren't mis-flagged as unknown.\n */\n\nimport { KNOWN_BLOCK_META_KEYS, parseNumber } from '../../markdown/annotationCoercion.js';\nimport { resolveTemplateName } from './templateNames.js';\nimport { nearestName } from '../utils/nearest.js';\n\n// ============================================\n// Types\n// ============================================\n\n/** How a raw `{[…]}` param string is coerced into a typed input value. */\nexport type InputCoercion =\n | 'string'\n | 'number'\n | 'boolean'\n | 'latLng'\n | 'labeledPair'\n | 'stringList';\n\n/**\n * Editor/validator-facing description of a single template input key: what it\n * does, how to coerce its raw string, and either its closed set of valid\n * values or a free-form format hint. `values`/`valueHint` are mutually\n * exclusive (a key has a closed enum OR a hint, not both).\n */\nexport interface TemplateInputDescriptor {\n /** The `{[name key=…]}` param key, matching the template input interface. */\n key: string;\n /** One-line description of the input. */\n description: string;\n /** Coercion strategy for the raw string (default `'string'`). */\n coerce?: InputCoercion;\n /** Closed set of valid values, for keys backed by an enum. */\n values?: readonly string[];\n /** Format hint shown when the value is free-form (no closed set). */\n valueHint?: string;\n /** When true, the validator warns if the key is absent and can't be derived. */\n required?: boolean;\n}\n\n/** A single lint finding produced by {@link lintTemplateParams}. */\nexport interface TemplateParamFinding {\n kind: 'unknown-input' | 'invalid-input-value' | 'missing-input';\n key: string;\n message: string;\n /** Did-you-mean candidate (for `unknown-input`). */\n suggestion?: string;\n}\n\n// ============================================\n// Shared enum vocabularies (verified against BlockTemplates.ts)\n// ============================================\n\n/** `ambientMotion` on image/video/map templates. */\nconst AMBIENT_MOTION_VALUES = ['zoomIn', 'zoomOut', 'panLeft', 'panRight'] as const;\n/** `captionPosition` on imageWithCaption / videoWithCaption. */\nconst CAPTION_POSITION_VALUES = ['bottom', 'top', 'center'] as const;\n/** `mapStyle` — mirrors `MapTileStyle` in `schemas/Doc.ts`. */\nconst MAP_STYLE_VALUES = ['terrain', 'satellite', 'road', 'toner', 'watercolor'] as const;\n/** `mood` on dateEvent. */\nconst DATE_EVENT_MOOD_VALUES = ['neutral', 'somber', 'celebratory'] as const;\n\n/** Shared free-form hint for `colorScheme`-style keys. */\nconst COLOR_SCHEME_HINT = \"theme color-scheme name — e.g. 'blue', 'green'\";\n\n// ============================================\n// Descriptor tables\n// ============================================\n\n/**\n * Inputs shared by every template via `BaseTemplateBlock`. Merged into each\n * template's known-key set for coercion + lint. Block-level timing/geometry\n * keys (`duration`, `x`, `y`, …) are NOT here — those stay owned by the\n * block-meta registry (`KNOWN_BLOCK_META_KEYS`) and are folded into the lint\n * known-key set separately.\n */\nexport const BASE_INPUT_DESCRIPTORS: readonly TemplateInputDescriptor[] = [\n {\n key: 'imageTreatment',\n description: \"Per-block photographic grade override ('none' opts out)\",\n values: ['none', 'mono', 'duotone', 'warm', 'cool'],\n },\n {\n key: 'useBottomLayer',\n description: \"Show the doc's bottom persistent layers\",\n coerce: 'boolean',\n },\n { key: 'useTopLayer', description: \"Show the doc's top persistent layers\", coerce: 'boolean' },\n];\n\n/**\n * Per-template input descriptors, keyed by canonical template id. A template\n * absent from this map has no descriptors and is exempt from lint (custom\n * templates and not-yet-described built-ins).\n */\nexport const TEMPLATE_INPUT_DESCRIPTORS: Readonly<\n Record<string, readonly TemplateInputDescriptor[]>\n> = {\n title: [\n { key: 'title', description: 'Main title text' },\n { key: 'subtitle', description: 'Subtitle or tagline' },\n { key: 'backgroundColor', description: 'Background color', valueHint: 'CSS color' },\n ],\n statHighlight: [\n { key: 'stat', description: 'The statistic (e.g. \"89%\", \"2x\")' },\n { key: 'description', description: 'What the stat means' },\n { key: 'detail', description: 'Additional detail or context' },\n { key: 'colorScheme', description: 'Color scheme for the stat', valueHint: COLOR_SCHEME_HINT },\n ],\n quote: [\n { key: 'quote', description: 'The quote text' },\n { key: 'attribution', description: 'Attribution (author, source)' },\n ],\n pullQuote: [\n { key: 'text', description: 'Quote text' },\n { key: 'attribution', description: 'Attribution' },\n ],\n twoColumn: [\n {\n key: 'left',\n description: 'Left column, as \"label|sublabel\"',\n coerce: 'labeledPair',\n required: true,\n },\n {\n key: 'right',\n description: 'Right column, as \"label|sublabel\"',\n coerce: 'labeledPair',\n required: true,\n },\n { key: 'header', description: 'Optional header above the columns' },\n { key: 'leftColor', description: 'Left column color scheme', valueHint: COLOR_SCHEME_HINT },\n { key: 'rightColor', description: 'Right column color scheme', valueHint: COLOR_SCHEME_HINT },\n ],\n dateEvent: [\n { key: 'date', description: 'The date (e.g. \"July 14, 1974\")' },\n { key: 'description', description: 'What happened' },\n { key: 'footer', description: 'Optional footer text' },\n { key: 'mood', description: 'Emotional tone', values: DATE_EVENT_MOOD_VALUES },\n ],\n imageWithCaption: [\n { key: 'imageSrc', description: 'Path to the image file', required: true },\n { key: 'imageAlt', description: 'Alt text for accessibility' },\n { key: 'caption', description: 'Caption text' },\n { key: 'captionPosition', description: 'Caption placement', values: CAPTION_POSITION_VALUES },\n { key: 'ambientMotion', description: 'Slow zoom/pan effect', values: AMBIENT_MOTION_VALUES },\n { key: 'isTitle', description: 'Style the caption as a title', coerce: 'boolean' },\n { key: 'subtitle', description: 'Subtitle (only when isTitle)' },\n { key: 'imageCredit', description: 'Photo credit / artist name' },\n { key: 'imageLicense', description: 'License identifier' },\n ],\n leftFeature: FEATURE_DESCRIPTORS(),\n rightFeature: FEATURE_DESCRIPTORS(),\n map: [\n {\n key: 'center',\n description: 'Map center as \"lat,lng\"',\n coerce: 'latLng',\n required: true,\n },\n { key: 'zoom', description: 'Zoom level (4-16)', coerce: 'number' },\n { key: 'mapStyle', description: 'Map tile style', values: MAP_STYLE_VALUES },\n { key: 'title', description: 'Optional title overlay' },\n { key: 'caption', description: 'Optional caption' },\n ],\n photoGrid: [\n { key: 'images', description: 'Comma-separated image paths', coerce: 'stringList' },\n { key: 'caption', description: 'Optional caption below the grid' },\n {\n key: 'ambientMotion',\n description: 'Slow zoom/pan on the largest image',\n values: AMBIENT_MOTION_VALUES,\n },\n ],\n comparisonBar: [\n { key: 'leftLabel', description: 'Left bar label', required: true },\n { key: 'leftValue', description: 'Left bar numeric value', coerce: 'number', required: true },\n { key: 'rightLabel', description: 'Right bar label', required: true },\n { key: 'rightValue', description: 'Right bar numeric value', coerce: 'number', required: true },\n { key: 'unit', description: 'Unit label (e.g. \"km\")' },\n { key: 'colorScheme', description: 'Color scheme', valueHint: COLOR_SCHEME_HINT },\n ],\n dataTable: [\n { key: 'title', description: 'Optional title above the table' },\n { key: 'headers', description: 'Comma-separated header cells', coerce: 'stringList' },\n // `rows`/`align` are structured (string[][] / alignment[]) and can't be\n // expressed as a single inline string — declared so they aren't flagged\n // as unknown when supplied via a data fence's overriding params.\n { key: 'rows', description: 'Table rows (supply via a data fence)' },\n { key: 'align', description: 'Per-column alignment (supply via a data fence)' },\n { key: 'colorScheme', description: 'Header color scheme', valueHint: COLOR_SCHEME_HINT },\n ],\n tree: [\n { key: 'title', description: 'Optional title above the tree' },\n { key: 'colorScheme', description: 'Folder-row color scheme', valueHint: COLOR_SCHEME_HINT },\n // `items` is a nested structure derived from the tree fence, not an\n // inline string — declared so it isn't flagged as unknown.\n { key: 'items', description: 'Tree items (derived from the tree fence)' },\n ],\n timeline: [\n { key: 'title', description: 'Optional title above the timeline' },\n {\n key: 'colorScheme',\n description: 'Track and marker color scheme',\n valueHint: COLOR_SCHEME_HINT,\n },\n // Tracks/events and branch links are nested structures derived from the\n // timeline source, not values that can be expressed as one inline string.\n { key: 'tracks', description: 'Timeline tracks and events (supply via template data)' },\n { key: 'links', description: 'Branch links between event ids (supply via template data)' },\n ],\n videoWithCaption: [\n { key: 'videoSrc', description: 'Path to the video file', required: true },\n { key: 'posterSrc', description: 'Poster frame path' },\n { key: 'videoAlt', description: 'Alt text for accessibility' },\n { key: 'clipStart', description: 'Clip start time (seconds)', coerce: 'number' },\n { key: 'clipEnd', description: 'Clip end time (seconds)', coerce: 'number' },\n { key: 'caption', description: 'Caption text' },\n { key: 'captionPosition', description: 'Caption placement', values: CAPTION_POSITION_VALUES },\n { key: 'videoCredit', description: 'Video credit / artist name' },\n { key: 'videoLicense', description: 'License identifier' },\n ],\n};\n\n/** Shared descriptor list for `leftFeature`/`rightFeature` (identical inputs). */\nfunction FEATURE_DESCRIPTORS(): readonly TemplateInputDescriptor[] {\n return [\n { key: 'imageSrc', description: 'Path to the feature image', required: true },\n { key: 'imageAlt', description: 'Alt text for accessibility' },\n { key: 'imageWidth', description: 'Explicit display width in px', coerce: 'number' },\n { key: 'imageHeight', description: 'Explicit display height in px', coerce: 'number' },\n { key: 'title', description: 'Heading text next to the image' },\n { key: 'body', description: 'Body text below the title' },\n ];\n}\n\n// ============================================\n// Descriptor lookup\n// ============================================\n\n/** All descriptors (template-specific + base) for a canonical template id. */\nfunction descriptorsFor(canonical: string): readonly TemplateInputDescriptor[] | undefined {\n const specific = TEMPLATE_INPUT_DESCRIPTORS[canonical];\n if (!specific) return undefined;\n return [...specific, ...BASE_INPUT_DESCRIPTORS];\n}\n\nfunction descriptorMap(\n descriptors: readonly TemplateInputDescriptor[],\n): Map<string, TemplateInputDescriptor> {\n return new Map(descriptors.map((d) => [d.key, d]));\n}\n\n// ============================================\n// Coercion (M2)\n// ============================================\n\n/**\n * Coerce a flat `{[…]}` param map into a partial typed template input.\n *\n * Known descriptor keys are coerced per their `coerce` strategy; unknown keys\n * (and `string`-typed keys) pass through unchanged. A coercion failure leaves\n * the raw string in place and adds a human-readable `warnings` entry — the\n * output is never lossy. Returns a fresh object; the caller must NOT feed\n * `templateOverrides` back in — only the ephemeral merged input is coerced.\n */\nexport function coerceTemplateParams(\n template: string | undefined,\n params: Record<string, string>,\n): { input: Record<string, unknown>; warnings: string[] } {\n const input: Record<string, unknown> = {};\n const warnings: string[] = [];\n const descriptors = template ? descriptorsFor(resolveTemplateName(template)) : undefined;\n const byKey = descriptors ? descriptorMap(descriptors) : undefined;\n\n for (const [key, raw] of Object.entries(params)) {\n const coerce = byKey?.get(key)?.coerce ?? 'string';\n const { value, warning } = coerceValue(coerce, raw);\n if (warning) {\n warnings.push(`\"${key}\": ${warning}`);\n input[key] = raw; // preserve the raw string on failure\n } else {\n input[key] = value;\n }\n }\n\n return { input, warnings };\n}\n\n/** Coerce one raw string per a coercion kind. `warning` set on failure. */\nfunction coerceValue(coerce: InputCoercion, raw: string): { value: unknown; warning?: string } {\n switch (coerce) {\n case 'number': {\n const n = parseNumber(raw);\n return n == null\n ? { value: raw, warning: `not a number (${JSON.stringify(raw)})` }\n : { value: n };\n }\n case 'boolean':\n return coerceBoolean(raw);\n case 'latLng':\n return coerceLatLng(raw);\n case 'labeledPair':\n return { value: coerceLabeledPair(raw) };\n case 'stringList':\n return { value: coerceStringList(raw) };\n case 'string':\n default:\n return { value: raw };\n }\n}\n\n/** `'true'`/`''` (bare flag) → true, `'false'` → false; anything else fails. */\nfunction coerceBoolean(raw: string): { value: unknown; warning?: string } {\n const t = raw.trim().toLowerCase();\n if (t === 'true' || t === '') return { value: true };\n if (t === 'false') return { value: false };\n return { value: raw, warning: `not a boolean (${JSON.stringify(raw)}) — expected true or false` };\n}\n\n/** `\"47.6,-122.3\"` → `{ lat, lng }`; malformed → failure (raw preserved). */\nfunction coerceLatLng(raw: string): { value: unknown; warning?: string } {\n const parts = raw.split(',');\n if (parts.length === 2) {\n const lat = parseNumber(parts[0]);\n const lng = parseNumber(parts[1]);\n if (lat != null && lng != null) return { value: { lat, lng } };\n }\n return { value: raw, warning: `not a \"lat,lng\" pair (${JSON.stringify(raw)})` };\n}\n\n/** `\"Label|Sub\"` → `{ label, sublabel? }`; sublabel omitted when empty. */\nfunction coerceLabeledPair(raw: string): { label: string; sublabel?: string } {\n const sep = raw.indexOf('|');\n if (sep < 0) return { label: raw.trim() };\n const label = raw.slice(0, sep).trim();\n const sublabel = raw.slice(sep + 1).trim();\n return sublabel ? { label, sublabel } : { label };\n}\n\n/** `\"a, b ,c\"` → `['a','b','c']` (trimmed, empties dropped). */\nfunction coerceStringList(raw: string): string[] {\n return raw\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n}\n\n// ============================================\n// Linting (M5)\n// ============================================\n\n/**\n * Lint a template's `{[…]}` params against its descriptors. Returns findings\n * for unknown keys, values outside a closed enum / that fail coercion, and\n * missing required inputs. Templates without descriptors (custom or\n * not-yet-described built-ins) return `[]`.\n */\nexport function lintTemplateParams(\n template: string,\n params: Record<string, string>,\n): TemplateParamFinding[] {\n const canonical = resolveTemplateName(template);\n const specific = TEMPLATE_INPUT_DESCRIPTORS[canonical];\n if (!specific) return [];\n\n const findings: TemplateParamFinding[] = [];\n const allDescriptors = [...specific, ...BASE_INPUT_DESCRIPTORS];\n const byKey = descriptorMap(allDescriptors);\n // Known keys for did-you-mean: descriptor keys ∪ block-meta keys (which are\n // honored on the same annotation, e.g. `duration`, `transition`).\n const knownKeys = new Set<string>([...byKey.keys(), ...Object.keys(KNOWN_BLOCK_META_KEYS)]);\n\n for (const [key, raw] of Object.entries(params)) {\n const descriptor = byKey.get(key);\n if (!descriptor) {\n if (knownKeys.has(key)) continue; // block-meta key — valid, not a template input\n const suggestion = nearestName(key, knownKeys);\n findings.push({\n kind: 'unknown-input',\n key,\n message:\n `Unknown input \"${key}\" for template \"${canonical}\"` +\n (suggestion ? `. Did you mean \"${suggestion}\"?` : ''),\n ...(suggestion ? { suggestion } : {}),\n });\n continue;\n }\n\n // Value validation: closed enum first, then coercion.\n if (descriptor.values) {\n const v = raw.trim();\n if (v !== '' && !descriptor.values.includes(v)) {\n findings.push({\n kind: 'invalid-input-value',\n key,\n message: `Invalid value ${JSON.stringify(raw)} for \"${key}\" — expected one of: ${descriptor.values.join(', ')}`,\n });\n }\n } else if (descriptor.coerce && descriptor.coerce !== 'string') {\n const { warning } = coerceValue(descriptor.coerce, raw);\n if (warning) {\n findings.push({ kind: 'invalid-input-value', key, message: `\"${key}\": ${warning}` });\n }\n }\n }\n\n // Missing required inputs (checked over template-specific descriptors only;\n // base inputs are never required).\n for (const descriptor of specific) {\n if (descriptor.required && params[descriptor.key] == null) {\n findings.push({\n kind: 'missing-input',\n key: descriptor.key,\n message: `Missing required input \"${descriptor.key}\" for template \"${canonical}\"`,\n });\n }\n }\n\n return findings;\n}\n","/**\n * Fallback Block Rendering\n *\n * The graceful-degradation guarantee: a block whose template can't render —\n * unknown template name, template function threw, or returned a non-array —\n * still renders its heading and body text as a plain, readable card instead\n * of a blank slide. A small notice line names the problem so authors (and\n * agents reviewing screenshots) can see *why* the block degraded.\n *\n * This is intentionally not a registered template: it can't be requested by\n * name, only reached when a requested template fails. See `materializeBlockLayers()`.\n */\n\nimport type { Layer } from '../../schemas/Doc.js';\nimport type { Block } from '../../schemas/Doc.js';\nimport type { DocBlock, TemplateContext } from '../../schemas/BlockTemplates.js';\nimport { resolveColorScheme, getThemeFont, themedFontSize } from '../utils/themeUtils.js';\nimport { extractPlainText } from '../../markdown/utils.js';\n\n/** Cap body text so a long section doesn't overflow the card. */\nconst MAX_BODY_CHARS = 600;\n\n/**\n * Render a block's heading + body text as plain layers, with a notice line\n * describing why the requested template didn't render.\n *\n * @param block The block that failed to render via its template.\n * @param context Template context (theme, viewport).\n * @param notice Short problem description, e.g. `Unknown template \"photGrid\"`.\n */\nexport function fallbackBlockLayers(\n block: DocBlock,\n context: TemplateContext,\n notice: string,\n): Layer[] {\n const colors = resolveColorScheme(context, 'blue');\n const { layout } = context;\n\n const title = (block as Block).title ?? (block as Block).id ?? '';\n const body = extractBodyText(block as Block);\n\n const layers: Layer[] = [\n {\n type: 'shape',\n id: 'fallback-bg',\n content: { shape: 'rect', fill: colors.bg },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n ];\n\n if (title) {\n layers.push({\n type: 'text',\n id: 'fallback-title',\n content: {\n text: title,\n style: {\n fontSize: themedFontSize(56, context, true),\n fontFamily: getThemeFont(context, 'title'),\n fontWeight: 'bold',\n color: colors.text,\n textAlign: 'center',\n },\n },\n position: {\n x: '50%',\n y: body ? '28%' : '50%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n });\n }\n\n if (body) {\n layers.push({\n type: 'text',\n id: 'fallback-body',\n content: {\n text: body,\n style: {\n fontSize: themedFontSize(28, context),\n fontFamily: getThemeFont(context, 'body'),\n color: colors.text,\n textAlign: 'center',\n },\n },\n position: {\n x: '50%',\n y: '55%',\n anchor: 'center',\n width: layout.maxTextWidth,\n },\n });\n }\n\n layers.push({\n type: 'text',\n id: 'fallback-notice',\n content: {\n text: `⚠ ${notice}`,\n style: {\n fontSize: themedFontSize(18, context),\n fontFamily: getThemeFont(context, 'body'),\n color: `${colors.text}99`,\n textAlign: 'center',\n },\n },\n position: { x: '50%', y: '92%', anchor: 'center', width: layout.maxTextWidth },\n });\n\n return layers;\n}\n\n/** Plain text of a block's body contents, truncated for card display. */\nfunction extractBodyText(block: Block): string {\n if (!block.contents || block.contents.length === 0) return '';\n const text = block.contents\n .map((node) => extractPlainText(node))\n .join('\\n')\n .trim();\n if (text.length <= MAX_BODY_CHARS) return text;\n return `${text.slice(0, MAX_BODY_CHARS).trimEnd()}…`;\n}\n","/**\n * Canonical block-to-layer materialization contract.\n *\n * Timeline scheduling and UI components both delegate here so template\n * lookup, custom templates, ownership, render style, persistent layers,\n * failure policy, and diagnostics cannot drift by render mode.\n */\n\nimport type { Block, Layer } from '../schemas/Doc.js';\nimport type {\n DocBlock,\n PersistentLayerConfig,\n TemplateBlock,\n TemplateContext,\n} from '../schemas/BlockTemplates.js';\nimport type { CustomTemplateDefinition } from '../schemas/CustomTemplates.js';\nimport type { Theme } from '../schemas/Theme.js';\nimport type { ViewportConfig } from '../schemas/Viewport.js';\nimport { createTemplateContext, isTemplateBlock } from '../schemas/BlockTemplates.js';\nimport { DEFAULT_THEME } from '../schemas/themeLibrary.js';\nimport { VIEWPORT_PRESETS } from '../schemas/Viewport.js';\nimport { cloneData } from '../internal/immutable.js';\nimport { applyRenderStyleToLayers } from './utils/applyRenderStyle.js';\nimport { coerceTemplateParams } from './templates/inputDescriptors.js';\nimport { fallbackBlockLayers } from './templates/fallbackBlock.js';\nimport { expandPersistentLayers, wrapWithPersistentLayers } from './templates/persistentLayers.js';\nimport { resolveTemplateName } from './templates/templateNames.js';\nimport {\n buildRegistry,\n templateRegistry,\n type RuntimeTemplateRegistry,\n} from './templates/registry.js';\n\n/** Internal result from executing one template function. */\ntype TemplateLayerMaterialization =\n | { status: 'ok'; layers: Layer[] }\n | { status: 'unknown-template'; layers: [] }\n | { status: 'invalid-result'; layers: []; receivedType: string }\n | { status: 'error'; layers: []; error: unknown };\n\n/** How a failed template render is represented in the returned layer graph. */\nexport type LayerMaterializationFailureMode = 'fallback' | 'empty';\n\n/** A structured, inspectable explanation for a template render failure. */\nexport type LayerMaterializationDiagnostic =\n | {\n code: 'unknown-template';\n template: string;\n message: string;\n }\n | {\n code: 'invalid-template-result';\n template: string;\n message: string;\n receivedType: string;\n }\n | {\n code: 'template-error';\n template: string;\n message: string;\n cause: unknown;\n };\n\n/** Identifies which path produced a materialized layer graph. */\nexport type LayerMaterializationSource = 'authored' | 'template' | 'fallback' | 'empty';\n\n/**\n * Complete result from {@link materializeBlockLayers}. Failures are data, not\n * console side effects: callers can display, report, or ignore the diagnostic.\n */\nexport interface BlockLayerMaterialization {\n layers: Layer[];\n source: LayerMaterializationSource;\n diagnostic?: LayerMaterializationDiagnostic;\n}\n\n/**\n * The single public context for turning a block into renderable layers.\n *\n * Theme persistent layers are inherited by default. Pass\n * `persistentLayers: false` to opt out, or a config to replace the theme's\n * persistent layers wholesale.\n */\nexport interface MaterializeBlockLayersOptions {\n /** Theme used by templates and render-style post-processing. */\n theme?: Theme;\n /** Target viewport. Defaults to the landscape preset. */\n viewport?: ViewportConfig;\n /** Theme inheritance override for persistent layers. */\n persistentLayers?: PersistentLayerConfig | false;\n /** Zero-based position in the flattened render sequence. */\n blockIndex?: number;\n /** Number of blocks in the flattened render sequence. */\n totalBlocks?: number;\n /** Document-scoped custom templates; built-ins win name collisions. */\n customTemplates?: readonly CustomTemplateDefinition[];\n /** Failed templates render a visible fallback by default. */\n failureMode?: LayerMaterializationFailureMode;\n}\n\n/** Pre-expanded scheduling cache; not part of the public materialization API. */\nexport interface ExpandedPersistentLayerSet {\n bottomLayers: Layer[];\n topLayers: Layer[];\n}\n\n/** Internal dependencies and compatibility switches supplied by orchestrators. */\nexport interface MaterializationRuntime {\n registry: RuntimeTemplateRegistry;\n templateContext?: TemplateContext;\n applyRenderStyle?: boolean;\n expandedPersistentLayers?: ExpandedPersistentLayerSet;\n}\n\n/**\n * Turn any doc block into an owned, render-ready layer graph.\n *\n * This is the only recommended public materialization entry point.\n */\nexport function materializeBlockLayers(\n block: DocBlock,\n options: MaterializeBlockLayersOptions = {},\n): BlockLayerMaterialization {\n const registry =\n options.customTemplates && options.customTemplates.length > 0\n ? buildRegistry(options.customTemplates)\n : (templateRegistry as unknown as RuntimeTemplateRegistry);\n return materializeBlockLayersWithRuntime(block, options, { registry });\n}\n\n/** Internal entry point for schedulers that cache registry and persistent expansion. */\nexport function materializeBlockLayersWithRuntime(\n block: DocBlock,\n options: MaterializeBlockLayersOptions,\n runtime: MaterializationRuntime,\n): BlockLayerMaterialization {\n const theme = options.theme ?? DEFAULT_THEME;\n const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;\n const blockIndex = options.blockIndex ?? 0;\n const totalBlocks = options.totalBlocks ?? 1;\n const effectivePersistentLayers =\n options.persistentLayers === false\n ? undefined\n : (options.persistentLayers ?? theme.persistentLayers);\n\n const existingLayers = (block as Block).layers;\n if (existingLayers && existingLayers.length > 0 && !isTemplateBlock(block)) {\n return {\n layers: injectPersistentLayers(\n cloneData(existingLayers),\n block,\n theme,\n effectivePersistentLayers,\n runtime.expandedPersistentLayers,\n ),\n source: 'authored',\n };\n }\n\n if (!isTemplateBlock(block)) {\n return {\n layers: injectPersistentLayers(\n [],\n block,\n theme,\n effectivePersistentLayers,\n runtime.expandedPersistentLayers,\n ),\n source: 'empty',\n };\n }\n\n const context = runtime.templateContext\n ? cloneData(runtime.templateContext)\n : createTemplateContext(theme, blockIndex, totalBlocks, viewport);\n context.block = cloneData(block as Block);\n\n const execution = executeTemplateMaterialization(block, context, runtime.registry);\n if (execution.status === 'ok') {\n const styledLayers =\n runtime.applyRenderStyle !== false\n ? applyRenderStyleToLayers(execution.layers, block as Block, theme)\n : execution.layers;\n return {\n layers: injectPersistentLayers(\n styledLayers,\n block,\n theme,\n effectivePersistentLayers,\n runtime.expandedPersistentLayers,\n ),\n source: 'template',\n };\n }\n\n const diagnostic = toLayerMaterializationDiagnostic(block.template, execution);\n if ((options.failureMode ?? 'fallback') === 'empty') {\n return {\n layers: injectPersistentLayers(\n [],\n block,\n theme,\n effectivePersistentLayers,\n runtime.expandedPersistentLayers,\n ),\n source: 'empty',\n diagnostic,\n };\n }\n\n return {\n layers: injectPersistentLayers(\n fallbackBlockLayers(block, context, diagnostic.message),\n block,\n theme,\n effectivePersistentLayers,\n runtime.expandedPersistentLayers,\n ),\n source: 'fallback',\n diagnostic,\n };\n}\n\nfunction executeTemplateMaterialization(\n templateBlock: TemplateBlock,\n context: TemplateContext,\n registry: RuntimeTemplateRegistry,\n): TemplateLayerMaterialization {\n const safeTemplateBlock = cloneData(templateBlock);\n const safeContext = cloneData(context);\n const maybeChildren = (safeTemplateBlock as Block).children;\n if ((!safeContext.children || safeContext.children.length === 0) && maybeChildren?.length) {\n safeContext.children = maybeChildren;\n }\n\n const templateFn = registry[resolveTemplateName(safeTemplateBlock.template)];\n if (!templateFn) return { status: 'unknown-template', layers: [] };\n\n const { templateData, templateOverrides } = safeTemplateBlock as Block;\n const input =\n templateData || templateOverrides\n ? ({\n ...safeTemplateBlock,\n ...templateData,\n ...coerceTemplateParams(safeTemplateBlock.template, templateOverrides ?? {}).input,\n } as TemplateBlock)\n : safeTemplateBlock;\n\n try {\n const renderedLayers = templateFn(input, safeContext);\n if (!Array.isArray(renderedLayers)) {\n return {\n status: 'invalid-result',\n layers: [],\n receivedType: typeof renderedLayers,\n };\n }\n return { status: 'ok', layers: cloneData(renderedLayers) };\n } catch (error: unknown) {\n return { status: 'error', layers: [], error };\n }\n}\n\nfunction toLayerMaterializationDiagnostic(\n template: string,\n execution: Exclude<TemplateLayerMaterialization, { status: 'ok' }>,\n): LayerMaterializationDiagnostic {\n if (execution.status === 'unknown-template') {\n return {\n code: 'unknown-template',\n template,\n message: `Unknown template \"${template}\"`,\n };\n }\n if (execution.status === 'invalid-result') {\n return {\n code: 'invalid-template-result',\n template,\n receivedType: execution.receivedType,\n message: `Template \"${template}\" returned ${execution.receivedType}, not a layer array`,\n };\n }\n return {\n code: 'template-error',\n template,\n cause: execution.error,\n message: `Template \"${template}\" failed`,\n };\n}\n\nfunction injectPersistentLayers(\n layers: Layer[],\n block: DocBlock,\n theme: Theme,\n persistentLayers?: PersistentLayerConfig,\n expanded?: ExpandedPersistentLayerSet,\n): Layer[] {\n if (!persistentLayers) return layers;\n const bottomLayers =\n expanded?.bottomLayers ?? expandPersistentLayers(persistentLayers.bottomLayers, theme);\n const topLayers =\n expanded?.topLayers ?? expandPersistentLayers(persistentLayers.topLayers, theme);\n return wrapWithPersistentLayers(layers, block as TemplateBlock, bottomLayers, topLayers);\n}\n","/**\n * Canonical, framework-free UI metadata for every built-in block template.\n *\n * This is the single source of truth for the human-readable label and the\n * one-sentence description of each template id in {@link templateRegistry}.\n * The editor's `TemplatePicker` renders its gallery from this map (joining\n * each id with a locally-defined SVG icon, which can't live in this\n * framework-free package), so a template only has to be added here and to\n * `templateRegistry` for it to surface in the editor.\n *\n * `templateMetadata.test.ts` asserts this map and `templateRegistry` stay\n * exactly 1:1 — adding a template to one without the other fails the build.\n *\n * Order matters: pickers iterate this object's insertion order, so it doubles\n * as the canonical gallery order.\n */\n\nexport interface TemplateMetadata {\n /** Human-readable label shown in pickers (e.g. \"Image with Caption\"). */\n label: string;\n /** One-sentence description of when to reach for this template. */\n description: string;\n}\n\nexport const TEMPLATE_METADATA: Record<string, TemplateMetadata> = {\n title: {\n label: 'Title',\n description: 'A bold opening slide with large title text, perfect for covers and chapters.',\n },\n sectionHeader: {\n label: 'Section Header',\n description: 'A clean section break with a prominent title and optional subtitle.',\n },\n statHighlight: {\n label: 'Stat Highlight',\n description: 'Showcases a single key number or metric with supporting context.',\n },\n quote: {\n label: 'Quote',\n description: 'Displays a stylized pull quote with decorative marks and attribution.',\n },\n factCard: {\n label: 'Fact Card',\n description: 'Presents a focused fact or insight with a labeled header and body text.',\n },\n twoColumn: {\n label: 'Two Column',\n description: 'Divides the slide into two equal side-by-side content columns.',\n },\n dateEvent: {\n label: 'Date Event',\n description: 'Highlights a date-based event or milestone with a prominent date display.',\n },\n imageWithCaption: {\n label: 'Image with Caption',\n description: 'Displays a full-bleed image with an optional caption below.',\n },\n leftFeature: {\n label: 'Left Feature',\n description: 'Image on the left, title and body text stacked on the right.',\n },\n rightFeature: {\n label: 'Right Feature',\n description: 'Image on the right, title and body text stacked on the left.',\n },\n map: {\n label: 'Map',\n description: 'Embeds an interactive map centered on a geographic location.',\n },\n fullBleedQuote: {\n label: 'Full Bleed Quote',\n description: 'A full-width quote that spans the entire slide for maximum impact.',\n },\n list: {\n label: 'List',\n description: 'Renders a bulleted or numbered list in a clean, card-style layout.',\n },\n photoGrid: {\n label: 'Photo Grid',\n description: 'Arranges multiple photos in a 2×2 or 3×3 mosaic grid.',\n },\n definitionCard: {\n label: 'Definition Card',\n description: 'Shows a term and its definition in a structured, dictionary-style card.',\n },\n comparisonBar: {\n label: 'Comparison Bar',\n description: 'Visualizes two or more values side-by-side with labeled horizontal bars.',\n },\n pullQuote: {\n label: 'Pull Quote',\n description: 'A stylized pull quote with large decorative marks and centered text.',\n },\n videoWithCaption: {\n label: 'Video with Caption',\n description: 'Embeds a video player with an optional caption below.',\n },\n videoPullQuote: {\n label: 'Video Pull Quote',\n description: 'Combines a video panel with a highlighted pull quote side-by-side.',\n },\n dataTable: {\n label: 'Data Table',\n description: 'Renders tabular data in a clean, styled table with a header row.',\n },\n diagram: {\n label: 'Diagram',\n description:\n 'Renders sub-headings as connected nodes — edit visually as a node-and-edge diagram.',\n },\n tree: {\n label: 'Tree',\n description:\n 'Renders an ASCII file-tree / outline fence as a filesystem-style treeview — edit as an outline.',\n },\n timeline: {\n label: 'Timeline',\n description:\n 'Plots events across one or more horizontal tracks with callouts and optional branching links.',\n },\n layout: {\n label: 'Layout',\n description:\n \"Free-form 2D canvas — drag layers into place. Use for one-off block layouts that don't fit a template.\",\n },\n drawing: {\n label: 'Drawing',\n description: 'Free-form sketches — draw shapes, paths, and text directly on a 2D surface.',\n },\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 type { StartBlockConfig } from '../../schemas/Doc.js';\nimport { getThemeFont, themedFontSize, themedImageTreatment } from '../utils/themeUtils.js';\nimport { relativeLuminance, withAlpha } from '../../schemas/colorUtils.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 /** Per-block override for the theme's photographic image grade. */\n imageTreatment?: 'none' | 'mono' | 'duotone' | 'warm' | 'cool';\n}\n\n/** Base (pre-viewport-scale) font size for a full-size cover title. */\nconst COVER_TITLE_BASE_PX = 120;\n/** Title length (chars) that still reads well at the full base size. */\nconst COVER_TITLE_COMFORTABLE_CHARS = 26;\n/** Readability floor so very long titles never shrink to nothing. */\nconst COVER_TITLE_MIN_BASE_PX = 62;\n\n/**\n * Compute the base cover-title font size for a given title, shrinking long\n * titles so their wrapped block fits the frame. Returns the pre-viewport-scale\n * value expected by {@link themedFontSize}; short titles get the full base.\n */\nexport function fitCoverTitleSize(title: string): number {\n const len = title.trim().length;\n if (len <= COVER_TITLE_COMFORTABLE_CHARS) return COVER_TITLE_BASE_PX;\n const scaled = COVER_TITLE_BASE_PX * Math.sqrt(COVER_TITLE_COMFORTABLE_CHARS / len);\n return Math.max(COVER_TITLE_MIN_BASE_PX, Math.round(scaled));\n}\n\nfunction isStandardLightCover(context: TemplateContext): boolean {\n const { theme } = context;\n return theme.id === 'standard' && relativeLuminance(theme.colors.background) > 0.85;\n}\n\n/**\n * Generate cover block layers from StartBlockConfig.\n */\nexport function coverBlock(input: CoverBlockInput, context: TemplateContext): Layer[] {\n const treatment = themedImageTreatment(context, input.imageTreatment);\n const { heroSrc, heroAlt, title, subtitle, ambientMotion, heroCredit, heroLicense } = input;\n const { theme, layout } = context;\n const standardLightCover = !heroSrc && isStandardLightCover(context);\n\n // Scale font sizes for viewport - cover titles are larger than regular title blocks.\n // The cover title wraps within maxTextWidth but does not otherwise shrink, so a long\n // title (e.g. \"Seattle: The Emerald City That Rebuilt Itself on Top of Itself\") wrapped\n // to three 120px lines overflows the frame and is clipped by the player controls.\n // Auto-fit the base size to title length so long titles stay within the frame. The\n // wrapped title's total height grows with fontSize² × length (line count ∝ length ×\n // fontSize / width, line height ∝ fontSize), so scaling the base by √(threshold/length)\n // keeps the wrapped block's area roughly constant past the threshold. Short titles are\n // unaffected (scale clamps at 1).\n const titleFontSize = themedFontSize(fitCoverTitleSize(title), context, true);\n const subtitleFontSize = themedFontSize(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 ...(treatment ? { treatment } : {}),\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 if (standardLightCover) {\n // Standard Light needs a restrained cover-poster treatment; a\n // full-strength primary radial hotspot overwhelms dark serif text\n // and makes the subtitle muddy.\n layers.push(\n {\n type: 'shape',\n id: 'cover-bg',\n content: {\n shape: 'rect',\n fill: theme.colors.background,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n {\n type: 'shape',\n id: 'cover-bg-tint',\n content: {\n shape: 'rect',\n fill: `radial-gradient(ellipse at 50% 40%, ${withAlpha(theme.colors.primary, 0.16)} 0%, ${withAlpha(theme.colors.primary, 0.07)} 38%, ${withAlpha(theme.colors.primary, 0)} 78%)`,\n },\n position: { x: 0, y: 0, width: '100%', height: '100%' },\n },\n );\n } else {\n // Non-Standard themes keep the existing dramatic radial cover look.\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\n // Subtle decorative accent line below title\n layers.push({\n type: 'shape',\n id: 'cover-accent',\n content: {\n shape: 'rect',\n fill: standardLightCover\n ? withAlpha(theme.colors.primary, 0.24)\n : '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: !standardLightCover,\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 fontWeight: standardLightCover ? 'bold' : 'normal',\n color: standardLightCover ? withAlpha(theme.colors.text, 0.78) : 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 } from '../../schemas/Doc.js';\nimport type {\n TemplateBlock,\n DocBlock,\n PersistentLayerConfig,\n} from '../../schemas/BlockTemplates.js';\nimport type { Theme } from '../../schemas/Theme.js';\nimport type { CustomTemplateDefinition } from '../../schemas/CustomTemplates.js';\nimport { isTemplateBlock } from '../../schemas/BlockTemplates.js';\nimport { DEFAULT_THEME as defaultTheme } from '../../schemas/themeLibrary.js';\nimport { expandPersistentLayers } from './persistentLayers.js';\nimport { resolveBlockTransition } from '../../schemas/Transitions.js';\nimport { resolveTemplateName } from './templateNames.js';\nimport { cloneData } from '../../internal/immutable.js';\nimport type { ViewportConfig } from '../../schemas/Viewport.js';\nimport { VIEWPORT_PRESETS } from '../../schemas/Viewport.js';\nimport { buildRegistry, templateRegistry, type RuntimeTemplateRegistry } from './registry.js';\nimport {\n materializeBlockLayersWithRuntime,\n type ExpandedPersistentLayerSet,\n type LayerMaterializationDiagnostic,\n type LayerMaterializationFailureMode,\n} from '../materializeBlockLayers.js';\n\nexport { TEMPLATE_METADATA } from './metadata.js';\nexport type { TemplateMetadata } from './metadata.js';\n\n/**\n * Registry mapping template ids (the strings that appear in\n * `{[name]}` markdown annotations) to their implementation functions.\n *\n * Some implementation functions keep historical \"Block\" suffixes\n * (`titleBlock`, `quoteBlock`, `mapBlock`, `listBlock`) for source\n * readability — the registry surfaces them under the cleaner short\n * ids (`title`, `quote`, `map`, `list`). Internal aliases keep legacy\n * document names readable without expanding the public API surface.\n *\n * Note: coverBlock is not in the registry as it's used directly for\n * start blocks, not as a regular template in the block sequence.\n */\nexport { buildRegistry, templateRegistry } from './registry.js';\nexport type { RuntimeTemplateRegistry } from './registry.js';\n\nexport { materializeBlockLayers } from '../materializeBlockLayers.js';\nexport type {\n BlockLayerMaterialization,\n LayerMaterializationDiagnostic,\n LayerMaterializationFailureMode,\n LayerMaterializationSource,\n MaterializeBlockLayersOptions,\n} from '../materializeBlockLayers.js';\n\n/**\n * Resolve a template id through the internal compatibility table. Returns\n * the input unchanged when no alias is registered.\n */\nexport { resolveTemplateName } from './templateNames.js';\n\n/**\n * Container templates render their parent block by consuming the block's\n * child headings (via `context.children`) — `diagram` draws them as nodes,\n * `drawing` as shapes, `layout` as absolutely-positioned layers. Those\n * children are therefore NOT independently renderable slides/sections;\n * render paths use {@link isContainerTemplate} to skip descending into\n * them (see `flattenRenderableBlocks`).\n */\nexport { CONTAINER_TEMPLATES } from './templateNames.js';\n\n/** True when `name` (or its alias) is a children-consuming container template. */\nexport { isContainerTemplate } from './templateNames.js';\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 | false;\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 * User-defined custom templates to merge onto the built-in registry\n * before expanding blocks. Typically passed straight from\n * `Doc.customTemplates`. Built-in names take precedence on collision.\n */\n customTemplates?: readonly CustomTemplateDefinition[];\n /** Failed templates render a visible fallback by default. */\n failureMode?: LayerMaterializationFailureMode;\n /** Receives structured template failures without hidden console output. */\n onDiagnostic?: (\n diagnostic: LayerMaterializationDiagnostic,\n block: DocBlock,\n blockIndex: number,\n ) => void;\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 */\n/**\n * Materialize one block through the canonical layer contract, then add its\n * timeline envelope and resolved transition.\n */\nfunction materializeScheduledBlock(\n sourceBlock: DocBlock,\n blockIndex: number,\n totalBlocks: number,\n theme: Theme,\n viewport: ViewportConfig,\n persistentLayers: PersistentLayerConfig | undefined,\n expandedPersistentLayers: ExpandedPersistentLayerSet | undefined,\n registry: RuntimeTemplateRegistry,\n failureMode: LayerMaterializationFailureMode,\n onDiagnostic?: ExpandDocBlocksOptions['onDiagnostic'],\n): Block {\n const materialized = materializeBlockLayersWithRuntime(\n sourceBlock,\n {\n theme,\n viewport,\n persistentLayers: persistentLayers ?? false,\n blockIndex,\n totalBlocks,\n failureMode,\n },\n { registry, expandedPersistentLayers },\n );\n if (materialized.diagnostic) {\n onDiagnostic?.(materialized.diagnostic, sourceBlock, blockIndex);\n }\n\n const expandedBlock: Block = isTemplateBlock(sourceBlock)\n ? {\n id: sourceBlock.id,\n startTime: 0,\n duration: sourceBlock.duration,\n audioSegment: sourceBlock.audioSegment,\n ...(materialized.layers.length > 0 ? { layers: materialized.layers } : {}),\n transition: sourceBlock.transition,\n template: sourceBlock.template,\n }\n : {\n ...cloneData(sourceBlock as Block),\n ...(materialized.layers.length > 0 ? { layers: materialized.layers } : {}),\n };\n\n const transition = resolveBlockTransition(expandedBlock, theme, blockIndex);\n if (transition !== expandedBlock.transition) {\n expandedBlock.transition = transition;\n }\n return expandedBlock;\n}\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 {\n persistentLayers,\n audioSegments,\n customTemplates,\n failureMode = 'fallback',\n onDiagnostic,\n } = opts;\n const totalBlocks = blocks.length;\n // Merge user-defined templates once, then share the immutable runtime view.\n const registry: RuntimeTemplateRegistry =\n customTemplates && customTemplates.length > 0\n ? buildRegistry(customTemplates)\n : (templateRegistry as unknown as RuntimeTemplateRegistry);\n\n // Callers that pass no config inherit the theme's atmosphere.\n const effectivePersistentLayers =\n persistentLayers === false ? undefined : (persistentLayers ?? theme.persistentLayers);\n const expandedPersistentLayers = effectivePersistentLayers\n ? {\n bottomLayers: expandPersistentLayers(effectivePersistentLayers.bottomLayers, theme),\n topLayers: expandPersistentLayers(effectivePersistentLayers.topLayers, theme),\n }\n : undefined;\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 expandedBlock = materializeScheduledBlock(\n block,\n index,\n totalBlocks,\n theme,\n viewport,\n effectivePersistentLayers,\n expandedPersistentLayers,\n registry,\n failureMode,\n onDiagnostic,\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 expandedBlock = materializeScheduledBlock(\n block,\n originalIndex,\n totalBlocks,\n theme,\n viewport,\n effectivePersistentLayers,\n expandedPersistentLayers,\n registry,\n failureMode,\n onDiagnostic,\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 expandedBlock = materializeScheduledBlock(\n block,\n originalIndex,\n totalBlocks,\n theme,\n viewport,\n effectivePersistentLayers,\n expandedPersistentLayers,\n registry,\n failureMode,\n onDiagnostic,\n );\n\n const templateBlock = block as TemplateBlock;\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 ...cloneData(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. Accepts both the canonical short id\n * (`title`, `quote`, `map`, `list`) and legacy aliases\n * (`titleBlock`, `quoteBlock`, `mapBlock`, `listBlock`).\n */\nexport function hasTemplate(name: string): boolean {\n return resolveTemplateName(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';\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 {\n expandPersistentLayers,\n getPersistentLayersFromTheme,\n resolvePersistentLayers,\n wrapWithPersistentLayers,\n} 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 { leftFeature, rightFeature } from './featureBlock.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';\nexport { diagramBlock } from './diagramBlock.js';\nexport { treeBlock } from './treeBlock.js';\nexport { timelineBlock } from './timelineBlock.js';\nexport { computeDiagramLayout } from './diagramLayout.js';\nexport type {\n DiagramLayout,\n DiagramNodePosition,\n DiagramEdge,\n DiagramLayoutOptions,\n} from './diagramLayout.js';\nexport { drawingBlock } from './drawingBlock.js';\nexport {\n computeDrawingLayout,\n normalizeShapeKind,\n isShapeName,\n SHAPE_NAMES,\n} from './drawingLayout.js';\nexport type {\n DrawingLayout,\n DrawingShape,\n DrawingShapeKind,\n DrawingConnector,\n DrawingLayoutOptions,\n} from './drawingLayout.js';\nexport { layoutBlock } from './layoutBlock.js';\nexport { computeLayoutLayers } from './layoutLayout.js';\nexport type { LayoutLayersResult, LayoutLayerDefaults } from './layoutLayout.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 * Public types for the ASCII diagram codec.\n *\n * Coordinates are grid-native: `col`/`row` count character cells from the\n * top-left of the art (0-based), `wCols`/`hRows` include the borders. The\n * mapping helpers in `mapping.ts` convert to/from diagram canvas units\n * via {@link ASCII_CHAR_W} / {@link ASCII_CHAR_H}.\n */\n\nexport interface AsciiDiagramNode {\n /**\n * Stable id: slug of the first label line, deduplicated with `-2`/`-3`\n * suffixes in reading order. Identical art always re-parses to\n * identical ids (editor selection and edges resolve by id).\n */\n id: string;\n /** Interior text lines joined with `\\n` (trimmed, blank lines dropped). May be `''`. */\n label: string;\n /** Left column of the box (0-based, includes the border). */\n col: number;\n /** Top row of the box (0-based, includes the border). */\n row: number;\n /** Full box width in columns, borders included. */\n wCols: number;\n /** Full box height in rows, borders included. */\n hRows: number;\n /** Id of the box that strictly contains this one, when nested. */\n containerId?: string;\n}\n\nexport interface AsciiDiagramEdge {\n source: string;\n target: string;\n /** Edge label parsed from an embedded horizontal run (`──label──▶`). */\n label?: string;\n /** False when the line carried no arrowhead. */\n directed: boolean;\n}\n\nexport interface AsciiDiagram {\n /** Nodes in reading order (row, then col). Containers are ordinary nodes with children pointing at them. */\n nodes: AsciiDiagramNode[];\n /** Deduplicated edges, sorted by (source, target, label). */\n edges: AsciiDiagramEdge[];\n /** Character vocabulary detected in the source; render emits the same style. */\n style: 'unicode' | 'ascii';\n /** Non-fatal parse notes (loose text, dropped labels, ambiguous buses, …). */\n warnings: string[];\n}\n\nexport interface AsciiDiagramDetection {\n isDiagram: boolean;\n /** Present when `isDiagram` — avoids a second parse in callers. */\n diagram?: AsciiDiagram;\n /** Machine-greppable accept/reject reasons, e.g. `too-few-boxes(1)`, `loose-ratio(0.41)`. */\n reasons: string[];\n}\n\n/**\n * Canvas pixels per grid column/row. Sized so a typical 12-col × 3-row\n * ASCII box maps close to the native 180×64 diagram card, and a 60–100\n * column diagram fits the 1600×900 diagram viewport.\n */\nexport const ASCII_CHAR_W = 14;\nexport const ASCII_CHAR_H = 28;\n","/**\n * Mapping between the grid-native ASCII diagram model and the diagram\n * canvas / template model (canvas units, the same space as `Block.x`/`y`).\n *\n * Quantization uses plain `round()` per axis — monotonic and local, so a\n * small canvas nudge either changes nothing or moves exactly one cell\n * (cluster-based schemes flap under small moves and churn the art).\n */\n\nimport type {\n DiagramEdgeAnchor,\n DiagramTemplateEdge,\n DiagramTemplateNode,\n} from '../../schemas/BlockTemplates.js';\nimport type { Block } from '../../schemas/Doc.js';\nimport { computeDiagramLayout } from '../templates/diagramLayout.js';\nimport {\n ASCII_CHAR_H,\n ASCII_CHAR_W,\n type AsciiDiagram,\n type AsciiDiagramEdge,\n type AsciiDiagramNode,\n} from './types.js';\n\nexport function asciiCellToCanvas(col: number, row: number): { x: number; y: number } {\n return { x: col * ASCII_CHAR_W, y: row * ASCII_CHAR_H };\n}\n\nexport function canvasToAsciiCell(x: number, y: number): { col: number; row: number } {\n return {\n col: Math.max(0, Math.round(x / ASCII_CHAR_W)),\n row: Math.max(0, Math.round(y / ASCII_CHAR_H)),\n };\n}\n\n/** Grid model → template/canvas model (`templateData.nodes`/`edges`). */\nexport function asciiDiagramToTemplateData(diagram: AsciiDiagram): {\n nodes: DiagramTemplateNode[];\n edges: DiagramTemplateEdge[];\n} {\n const nodes: DiagramTemplateNode[] = diagram.nodes.map((n) => ({\n id: n.id,\n label: n.label,\n ...asciiCellToCanvas(n.col, n.row),\n w: n.wCols * ASCII_CHAR_W,\n h: n.hRows * ASCII_CHAR_H,\n ...(n.containerId ? { container: n.containerId } : {}),\n }));\n const anchors = inferEdgeAnchors(nodes, diagram.edges);\n const edges: DiagramTemplateEdge[] = diagram.edges.map((e, index) => ({\n source: e.source,\n target: e.target,\n ...(e.label ? { label: e.label } : {}),\n ...(e.directed ? {} : { directed: false }),\n ...anchors[index],\n routing: 'orthogonal',\n }));\n return { nodes, edges };\n}\n\ninterface EdgeAnchorPair {\n sourceAnchor: DiagramEdgeAnchor;\n targetAnchor: DiagramEdgeAnchor;\n}\n\n/**\n * Recover the visual intent carried by orthogonal ASCII art. Fan-out ports\n * spread across the source face; fan-in ports spread across the target face.\n * A single endpoint stays centered on its facing side.\n */\nfunction inferEdgeAnchors(\n nodes: readonly DiagramTemplateNode[],\n edges: readonly AsciiDiagramEdge[],\n): EdgeAnchorPair[] {\n const nodeById = new Map(nodes.map((node) => [node.id, node]));\n const pairs = edges.map((edge) => {\n const source = nodeById.get(edge.source);\n const target = nodeById.get(edge.target);\n if (!source || !target) {\n return {\n sourceAnchor: { side: 'right' as const, offset: 0.5 },\n targetAnchor: { side: 'left' as const, offset: 0.5 },\n };\n }\n const sourceW = source.w ?? ASCII_CHAR_W * 12;\n const sourceH = source.h ?? ASCII_CHAR_H * 3;\n const targetW = target.w ?? ASCII_CHAR_W * 12;\n const targetH = target.h ?? ASCII_CHAR_H * 3;\n const dx = target.x + targetW / 2 - (source.x + sourceW / 2);\n const dy = target.y + targetH / 2 - (source.y + sourceH / 2);\n const horizontalDistance = Math.abs(dx) / Math.max(1, (sourceW + targetW) / 2);\n const verticalDistance = Math.abs(dy) / Math.max(1, (sourceH + targetH) / 2);\n if (verticalDistance >= horizontalDistance) {\n return dy >= 0\n ? {\n sourceAnchor: { side: 'bottom' as const, offset: 0.5 },\n targetAnchor: { side: 'top' as const, offset: 0.5 },\n }\n : {\n sourceAnchor: { side: 'top' as const, offset: 0.5 },\n targetAnchor: { side: 'bottom' as const, offset: 0.5 },\n };\n }\n return dx >= 0\n ? {\n sourceAnchor: { side: 'right' as const, offset: 0.5 },\n targetAnchor: { side: 'left' as const, offset: 0.5 },\n }\n : {\n sourceAnchor: { side: 'left' as const, offset: 0.5 },\n targetAnchor: { side: 'right' as const, offset: 0.5 },\n };\n });\n\n distributeOffsets(pairs, edges, nodes, 'source');\n distributeOffsets(pairs, edges, nodes, 'target');\n return pairs;\n}\n\nfunction distributeOffsets(\n pairs: EdgeAnchorPair[],\n edges: readonly AsciiDiagramEdge[],\n nodes: readonly DiagramTemplateNode[],\n endpoint: 'source' | 'target',\n): void {\n const nodeById = new Map(nodes.map((node) => [node.id, node]));\n const groups = new Map<string, number[]>();\n for (let index = 0; index < edges.length; index++) {\n const edge = edges[index];\n const anchor = endpoint === 'source' ? pairs[index].sourceAnchor : pairs[index].targetAnchor;\n const nodeId = endpoint === 'source' ? edge.source : edge.target;\n const key = `${nodeId}:${anchor.side}`;\n const group = groups.get(key) ?? [];\n group.push(index);\n groups.set(key, group);\n }\n for (const indexes of groups.values()) {\n if (indexes.length < 2) continue;\n const side =\n endpoint === 'source'\n ? pairs[indexes[0]].sourceAnchor.side\n : pairs[indexes[0]].targetAnchor.side;\n indexes.sort((a, b) => {\n const oppositeA = nodeById.get(endpoint === 'source' ? edges[a].target : edges[a].source);\n const oppositeB = nodeById.get(endpoint === 'source' ? edges[b].target : edges[b].source);\n const axisA = side === 'top' || side === 'bottom' ? (oppositeA?.x ?? 0) : (oppositeA?.y ?? 0);\n const axisB = side === 'top' || side === 'bottom' ? (oppositeB?.x ?? 0) : (oppositeB?.y ?? 0);\n return axisA - axisB || a - b;\n });\n indexes.forEach((edgeIndex, rank) => {\n const anchor =\n endpoint === 'source' ? pairs[edgeIndex].sourceAnchor : pairs[edgeIndex].targetAnchor;\n anchor.offset = (rank + 1) / (indexes.length + 1);\n });\n }\n}\n\n/** Template/canvas model → grid model, quantizing positions and sizes. */\nexport function asciiDiagramFromTemplateData(\n nodes: readonly DiagramTemplateNode[],\n edges: readonly DiagramTemplateEdge[],\n options: { style?: 'unicode' | 'ascii' } = {},\n): AsciiDiagram {\n const ids = new Set(nodes.map((n) => n.id));\n const outNodes: AsciiDiagramNode[] = nodes.map((n) => {\n const { col, row } = canvasToAsciiCell(n.x, n.y);\n const labelLines = n.label.length > 0 ? n.label.split('\\n') : [];\n const innerW = labelLines.reduce((w, l) => Math.max(w, l.length), 0);\n const wCols =\n typeof n.w === 'number' ? Math.max(3, Math.round(n.w / ASCII_CHAR_W)) : innerW + 4;\n const hRows =\n typeof n.h === 'number' ? Math.max(3, Math.round(n.h / ASCII_CHAR_H)) : labelLines.length + 2;\n return {\n id: n.id,\n label: n.label,\n col,\n row,\n wCols: Math.max(wCols, 3),\n hRows: Math.max(hRows, 3),\n ...(n.container && ids.has(n.container) && n.container !== n.id\n ? { containerId: n.container }\n : {}),\n };\n });\n return {\n nodes: outNodes,\n edges: edges\n .filter((e) => ids.has(e.source) && ids.has(e.target))\n .map((e) => ({\n source: e.source,\n target: e.target,\n ...(e.label ? { label: e.label } : {}),\n directed: e.directed !== false,\n })),\n style: options.style ?? 'unicode',\n warnings: [],\n };\n}\n\n/**\n * Legacy heading-based diagram children → ASCII diagram model. Used to\n * migrate `### Node {#id x= y= connectsTo=}` sections to ASCII fences;\n * positions run through the shared `computeDiagramLayout` so unpinned\n * children get the same grid placement as the legacy renderer.\n */\nexport function asciiDiagramFromBlocks(\n children: readonly Block[],\n options: { style?: 'unicode' | 'ascii' } = {},\n): AsciiDiagram {\n const layout = computeDiagramLayout(children);\n const nodes: DiagramTemplateNode[] = layout.nodes.map((n) => ({\n id: n.id,\n label: n.label,\n x: n.x,\n y: n.y,\n }));\n const edges: DiagramTemplateEdge[] = layout.edges.map((e) => ({\n source: e.source,\n target: e.target,\n ...(e.type ? { label: e.type } : {}),\n }));\n const diagram = asciiDiagramFromTemplateData(nodes, edges, options);\n diagram.warnings.push(...layout.warnings);\n return diagram;\n}\n","/** Mapping from source-grid timeline data to normalized template inputs. */\n\nimport type {\n TimelineTemplateEvent,\n TimelineTemplateLink,\n TimelineTemplateTrack,\n} from '../../schemas/BlockTemplates.js';\nimport type { AsciiTimeline } from './types.js';\n\nexport function asciiTimelineToTemplateData(timeline: AsciiTimeline): {\n tracks: TimelineTemplateTrack[];\n links: TimelineTemplateLink[];\n} {\n const globalStart =\n timeline.tracks.length > 0 ? Math.min(...timeline.tracks.map((track) => track.startColumn)) : 0;\n const globalEnd =\n timeline.tracks.length > 0 ? Math.max(...timeline.tracks.map((track) => track.endColumn)) : 1;\n const span = Math.max(1, globalEnd - globalStart);\n\n const tracks: TimelineTemplateTrack[] = timeline.tracks.map((track) => ({\n id: track.id,\n ...(track.label ? { label: track.label } : {}),\n ...(track.endLabel ? { endLabel: track.endLabel } : {}),\n events: track.events.map(\n (event): TimelineTemplateEvent => ({\n id: event.id,\n label: event.label,\n ...(event.description ? { description: event.description } : {}),\n position: clamp01((event.column - globalStart) / span),\n ...(event.side ? { side: event.side } : {}),\n ...(event.descriptionSide ? { descriptionSide: event.descriptionSide } : {}),\n ...(event.callout === false ? { callout: false } : {}),\n ...(event.marker ? { marker: event.marker } : {}),\n }),\n ),\n }));\n const links: TimelineTemplateLink[] = timeline.links.map((link) => ({ ...link }));\n return { tracks, links };\n}\n\nfunction clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n","/**\n * Mapping between the tree model and the template/layer data model, plus a\n * nested-markdown-list → tree walker (none exists in core — `extractListItems`\n * flattens, losing depth).\n */\n\nimport type { MarkdownBlockNode, MarkdownList, MarkdownListItem } from '../../markdown/types.js';\nimport { extractPlainText } from '../../markdown/utils.js';\nimport type { Tree, TreeNode } from './types.js';\n\n/** JSON-serializable tree item carried on `templateData.items` / a `TreeLayer`. */\nexport interface TreeItem {\n id: string;\n label: string;\n isDir?: boolean;\n comment?: string;\n children: TreeItem[];\n}\n\n/** Tree model → template/layer items (structure-preserving). */\nexport function treeToTemplateData(tree: Tree): { items: TreeItem[] } {\n return { items: tree.roots.map(toItem) };\n}\n\nfunction toItem(node: TreeNode): TreeItem {\n return {\n id: node.id,\n label: node.label,\n ...(node.isDir ? { isDir: true } : {}),\n ...(node.comment ? { comment: node.comment } : {}),\n children: node.children.map(toItem),\n };\n}\n\n/** Template/layer items → tree model (editor write-back / render). */\nexport function treeFromTemplateData(\n items: readonly TreeItem[],\n options: { style?: 'unicode' | 'ascii' } = {},\n): Tree {\n const roots = items.map(fromItem);\n return { roots, style: options.style ?? 'unicode', warnings: [] };\n}\n\nfunction fromItem(item: TreeItem): TreeNode {\n const children = Array.isArray(item.children) ? item.children.map(fromItem) : [];\n return {\n id: typeof item.id === 'string' && item.id ? item.id : 'node',\n label: typeof item.label === 'string' ? item.label : '',\n children,\n isDir: item.isDir === true || children.length > 0,\n ...(item.comment ? { comment: item.comment } : {}),\n };\n}\n\n/**\n * Recursively convert a nested markdown bullet list into a tree. Used by\n * `deriveTemplateInputs` when an author explicitly `{[tree]}`-annotates a\n * block whose body is a nested list rather than a fence.\n */\nexport function treeFromMarkdownList(list: MarkdownList): Tree {\n const usedIds = new Map<string, number>();\n const slugify = (s: string): string =>\n s\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'node';\n const idFor = (label: string): string => {\n const base = slugify(label.replace(/\\/$/, ''));\n const count = usedIds.get(base) ?? 0;\n usedIds.set(base, count + 1);\n return count === 0 ? base : `${base}-${count + 1}`;\n };\n\n const itemToNode = (item: MarkdownListItem): TreeNode => {\n // The item's own label = its first non-list block's plain text.\n const labelNode = item.children.find((c) => c.type !== 'list');\n const label = labelNode ? extractPlainText(labelNode).trim() : '';\n const childLists = item.children.filter((c): c is MarkdownList => c.type === 'list');\n const children: TreeNode[] = [];\n for (const cl of childLists) for (const ci of cl.children) children.push(itemToNode(ci));\n return {\n id: idFor(label),\n label,\n children,\n isDir: label.endsWith('/') || children.length > 0,\n };\n };\n\n return { roots: list.children.map(itemToNode), style: 'unicode', warnings: [] };\n}\n\n/** Find the first top-level markdown list in a block's body, if any. */\nexport function findFirstList(contents: MarkdownBlockNode[] | undefined): MarkdownList | undefined {\n return contents?.find((n): n is MarkdownList => n.type === 'list');\n}\n","/**\n * Template input derivation — build a template's required inputs from a\n * block's heading + markdown body.\n *\n * Used by:\n * - `markdownToDoc`'s content-aware auto template picking, so an\n * auto-picked `quote`/`statHighlight`/`leftFeature` block carries the\n * inputs its template needs through every render path (player, linear\n * view, exports).\n * - `LinearDocView` / editor previews, to render annotated blocks whose\n * authors didn't spell out every template param.\n *\n * Two modes:\n * - strict (default): returns `null` when an essential input can't be\n * derived (no image for a feature block, no table for dataTable…) —\n * auto-picking uses this to fall back to the structural default.\n * - placeholders: returns visible placeholder values instead of failing —\n * preview surfaces use this so a half-authored block still renders.\n */\n\nimport type {\n MarkdownBlockNode,\n MarkdownCodeBlock,\n MarkdownList,\n MarkdownTable,\n} from '../markdown/types.js';\nimport { extractPlainText } from '../markdown/utils.js';\nimport { matchNumberHighlight } from '../recommend/numberHighlight.js';\nimport {\n detectAsciiDiagram,\n isEligibleAsciiFenceLang,\n isExplicitDiagramLang,\n} from './asciiDiagram/detect.js';\nimport { asciiDiagramToTemplateData } from './asciiDiagram/mapping.js';\nimport { detectAsciiTimeline, isEligibleAsciiTimelineFenceLang } from './asciiTimeline/detect.js';\nimport { asciiTimelineToTemplateData } from './asciiTimeline/mapping.js';\nimport { detectTree, isEligibleTreeFenceLang, isExplicitTreeLang } from './treeview/detect.js';\nimport { treeToTemplateData, treeFromMarkdownList, findFirstList } from './treeview/mapping.js';\n\n/** First image discovered in a block's body, with explicit dimensions when present. */\nexport interface FirstImage {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n}\n\n/** Plain text of a block's body contents (excluding the heading). */\nexport function extractBodyPlainText(contents?: MarkdownBlockNode[]): string {\n if (!contents || contents.length === 0) return '';\n return contents\n .map((n) => extractPlainText(n))\n .join('\\n')\n .trim();\n}\n\n/** Extract list items as plain text. */\nexport function extractListItems(contents?: MarkdownBlockNode[]): string[] {\n if (!contents) return [];\n const items: string[] = [];\n for (const node of contents) {\n if (node.type === 'list') {\n for (const item of (node as MarkdownList).children) {\n const text = extractPlainText(item).trim();\n if (text) items.push(text);\n }\n }\n }\n return items;\n}\n\n/** Parse a `width`/`height` HTML attribute to a positive number. */\nfunction parseDim(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined;\n const n = parseFloat(raw);\n return Number.isFinite(n) && n > 0 ? n : undefined;\n}\n\n/**\n * Find images referenced anywhere in block contents — both markdown\n * shorthand `` (type `image`) and raw HTML `<img>` tags\n * (type `htmlBlock`/`htmlInline`). The WYSIWYG editor emits the HTML form\n * whenever a user resizes an image, so missing that path silently breaks\n * every resized image.\n *\n * @param limit Stop after this many images (default: all).\n */\nexport function extractImages(\n contents: MarkdownBlockNode[] | undefined,\n limit = Infinity,\n): FirstImage[] {\n if (!contents || contents.length === 0) return [];\n const found: FirstImage[] = [];\n\n function fromHtml(nodes: unknown[]): void {\n for (const node of nodes) {\n if (found.length >= limit) return;\n if (!node || typeof node !== 'object') continue;\n const n = node as Record<string, unknown>;\n if (n.type === 'htmlElement' && n.tagName === 'img') {\n const attrs = n.attributes as Record<string, string> | undefined;\n if (attrs && typeof attrs.src === 'string' && attrs.src) {\n found.push({\n src: attrs.src,\n alt: typeof attrs.alt === 'string' ? attrs.alt : '',\n width: parseDim(attrs.width),\n height: parseDim(attrs.height),\n });\n }\n }\n if (Array.isArray(n.children)) fromHtml(n.children);\n }\n }\n\n function walk(node: unknown): void {\n if (found.length >= limit) return;\n if (!node || typeof node !== 'object') return;\n const n = node as Record<string, unknown>;\n if (n.type === 'image' && typeof n.url === 'string' && n.url) {\n found.push({ src: n.url, alt: typeof n.alt === 'string' ? n.alt : '' });\n return;\n }\n if ((n.type === 'htmlBlock' || n.type === 'htmlInline') && Array.isArray(n.htmlChildren)) {\n fromHtml(n.htmlChildren);\n }\n if (Array.isArray(n.children)) {\n for (const child of n.children) walk(child);\n }\n }\n\n for (const node of contents) {\n if (found.length >= limit) break;\n walk(node);\n }\n return found;\n}\n\n/** First image in a block's body, or null. */\nexport function extractFirstImage(contents: MarkdownBlockNode[] | undefined): FirstImage | null {\n return extractImages(contents, 1)[0] ?? null;\n}\n\n/** Extract table data (headers, rows, alignment) from block contents. */\nexport function extractTableFromContents(contents?: MarkdownBlockNode[]): {\n headers: string[];\n rows: string[][];\n align?: (('left' | 'right' | 'center') | null)[];\n} | null {\n if (!contents) return null;\n for (const node of contents) {\n if (node.type === 'table') {\n const table = node as MarkdownTable;\n const [headerRow, ...bodyRows] = table.children;\n if (!headerRow) return null;\n const headers = headerRow.children.map((cell) => extractPlainText(cell).trim());\n const rows = bodyRows.map((row) => row.children.map((cell) => extractPlainText(cell).trim()));\n return { headers, rows, align: table.align };\n }\n }\n return null;\n}\n\n/** First blockquote's plain text, or ''. */\nexport function extractBlockquoteText(contents?: MarkdownBlockNode[]): string {\n if (!contents) return '';\n for (const node of contents) {\n if (node.type === 'blockquote') return extractPlainText(node).trim();\n }\n return '';\n}\n\nfunction firstParagraph(\n contents: MarkdownBlockNode[] | undefined,\n): { node: Extract<MarkdownBlockNode, { type: 'paragraph' }>; index: number } | null {\n if (!contents) return null;\n const index = contents.findIndex((node) => node.type === 'paragraph');\n if (index < 0) return null;\n return {\n node: contents[index] as Extract<MarkdownBlockNode, { type: 'paragraph' }>,\n index,\n };\n}\n\n/** A leading bold number is an explicit authoring signal for the hero stat. */\nfunction leadingStrongStat(\n paragraph: Extract<MarkdownBlockNode, { type: 'paragraph' }>,\n): string | null {\n for (const child of paragraph.children) {\n if (child.type === 'text' && child.value.trim() === '') continue;\n if (child.type !== 'strong') return null;\n const text = extractPlainText(child).trim();\n // Explicit bold authoring is intentionally broader than automatic stat\n // recommendation: a small integer such as `**42**` is a valid hero when\n // the author chose statHighlight. Anchor at the beginning so a bold phrase\n // like `**Revenue grew 42%**` does not become oversized wholesale.\n const match = text.match(/^(?:[$€£¥]\\s*)?[+-]?\\d+(?:[.,]\\d+)*(?:\\s?(?:[%‰x×]|[A-Za-z]+))?/);\n return match?.[0].trim() || null;\n }\n return null;\n}\n\nfunction removeStatPhrase(text: string, start: number, end: number): string {\n const before = text.slice(0, start).trim();\n let after = text.slice(end);\n // A dash/colon visually separates inline prose, but is redundant once the\n // stat and description render on separate lines.\n if (!before) after = after.replace(/^\\s*(?:[-–—:]\\s*)?/, '');\n else after = after.trim();\n return [before, after].filter(Boolean).join(' ').trim();\n}\n\nfunction bodyWithoutParagraphStat(\n contents: MarkdownBlockNode[] | undefined,\n paragraphIndex: number,\n paragraphText: string,\n start: number,\n end: number,\n): string {\n if (!contents) return '';\n return contents\n .map((node, index) =>\n index === paragraphIndex\n ? removeStatPhrase(paragraphText, start, end)\n : extractPlainText(node).trim(),\n )\n .filter(Boolean)\n .join('\\n')\n .trim();\n}\n\n/**\n * Map Markdown-authored stat content onto the template's visual roles.\n *\n * A leading bold metric in the body is the strongest signal (`**42%** of\n * teams`), followed by a stat-looking heading for backward compatibility,\n * then an unformatted metric in the first body paragraph (used by automatic\n * templates). Generic content retains the historical heading/body mapping.\n */\nfunction deriveStatHighlightInputs(\n headingText: string,\n contents: MarkdownBlockNode[] | undefined,\n bodyText: string,\n): Record<string, unknown> {\n const paragraph = firstParagraph(contents);\n if (paragraph) {\n const paragraphText = extractPlainText(paragraph.node).trim();\n const strongStat = leadingStrongStat(paragraph.node);\n if (strongStat) {\n const start = paragraphText.indexOf(strongStat);\n const description = bodyWithoutParagraphStat(\n contents,\n paragraph.index,\n paragraphText,\n start,\n start + strongStat.length,\n );\n return {\n stat: strongStat,\n description: description || headingText || strongStat,\n };\n }\n }\n\n const trimmedHeading = headingText.trim();\n const headingStat = matchNumberHighlight(trimmedHeading);\n if (headingStat && headingStat.index === 0 && headingStat.end === trimmedHeading.length) {\n return { stat: headingText, description: bodyText || headingText };\n }\n\n if (paragraph) {\n const paragraphText = extractPlainText(paragraph.node).trim();\n const bodyStat = matchNumberHighlight(paragraphText);\n if (bodyStat) {\n const description = bodyWithoutParagraphStat(\n contents,\n paragraph.index,\n paragraphText,\n bodyStat.index,\n bodyStat.end,\n );\n return {\n stat: bodyStat.value,\n description: description || headingText || bodyStat.value,\n };\n }\n }\n\n return { stat: headingText, description: bodyText || headingText };\n}\n\nexport interface DeriveTemplateInputsOptions {\n /**\n * Return visible placeholder values instead of `null` when an essential\n * input can't be derived (preview surfaces). Default false (strict).\n */\n placeholders?: boolean;\n}\n\n/**\n * Derive a template's inputs from a block's heading text and body nodes.\n * Returns the input fields to merge onto the block, or `null` in strict\n * mode when an essential input is missing.\n */\nexport function deriveTemplateInputs(\n templateName: string,\n headingText: string,\n contents: MarkdownBlockNode[] | undefined,\n options: DeriveTemplateInputsOptions = {},\n): Record<string, unknown> | null {\n const placeholders = options.placeholders === true;\n const bodyText = extractBodyPlainText(contents);\n\n switch (templateName) {\n case 'statHighlight':\n return deriveStatHighlightInputs(headingText, contents, bodyText);\n case 'quote': {\n const quote = extractBlockquoteText(contents) || bodyText || headingText;\n return { quote };\n }\n case 'fullBleedQuote':\n case 'pullQuote': {\n // These templates take `text` (not `quote`).\n const text = extractBlockquoteText(contents) || bodyText || headingText;\n return { text };\n }\n case 'factCard':\n return { fact: headingText, explanation: bodyText || headingText };\n case 'comparisonBar':\n return placeholders\n ? { leftLabel: 'A', leftValue: 60, rightLabel: 'B', rightValue: 40 }\n : null;\n case 'list': {\n const items = extractListItems(contents);\n if (items.length > 0) return { items };\n return placeholders ? { items: ['Item 1', 'Item 2', 'Item 3'] } : null;\n }\n case 'definitionCard':\n return { term: headingText, definition: bodyText || headingText };\n case 'dateEvent':\n return { date: headingText, description: bodyText || headingText };\n case 'dataTable': {\n const tableData = extractTableFromContents(contents);\n if (tableData) return tableData;\n return placeholders ? { headers: ['Column'], rows: [['Data']] } : null;\n }\n case 'imageWithCaption': {\n const img = extractFirstImage(contents);\n if (!img) return placeholders ? { caption: headingText } : null;\n return { imageSrc: img.src, imageAlt: img.alt || headingText, caption: headingText };\n }\n case 'photoGrid': {\n const images = extractImages(contents, 4);\n if (images.length < 2) return placeholders ? {} : null;\n return {\n images: images.map((i) => ({ src: i.src, alt: i.alt })),\n caption: headingText,\n };\n }\n case 'leftFeature':\n case 'rightFeature': {\n const img = extractFirstImage(contents);\n if (!img && !placeholders) return null;\n return {\n imageSrc: img?.src ?? '',\n imageAlt: img?.alt || headingText,\n imageWidth: img?.width,\n imageHeight: img?.height,\n title: headingText,\n body: bodyText,\n };\n }\n case 'diagram': {\n // Nodes/edges from an ASCII-art fence in the body (the fence itself\n // stays in `contents`, untouched, so round-trips are lossless).\n const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');\n const fence =\n fences.length === 1 && isEligibleAsciiFenceLang(fences[0].lang) ? fences[0] : undefined;\n const detection = fence\n ? detectAsciiDiagram(fence.value, { explicit: isExplicitDiagramLang(fence.lang) })\n : undefined;\n if (!detection?.isDiagram || !detection.diagram) return placeholders ? {} : null;\n const { nodes, edges } = asciiDiagramToTemplateData(detection.diagram);\n return { nodes, edges, ...(headingText ? { title: headingText } : {}) };\n }\n case 'timeline': {\n // Tracks/events from a spatial ASCII timeline fence. Calling this case\n // already implies author/template intent, so accept the detector's\n // explicit one-event form even when the fence itself is untagged.\n const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');\n const fence =\n fences.length === 1 && isEligibleAsciiTimelineFenceLang(fences[0].lang)\n ? fences[0]\n : undefined;\n const detection = fence ? detectAsciiTimeline(fence.value, { explicit: true }) : undefined;\n if (!detection?.isTimeline || !detection.timeline) return placeholders ? {} : null;\n const { tracks, links } = asciiTimelineToTemplateData(detection.timeline);\n return { tracks, links, ...(headingText ? { title: headingText } : {}) };\n }\n case 'tree': {\n // Items from an ASCII tree fence, or a nested markdown bullet list when\n // the author explicitly annotates a listed body. The fence/list stays\n // in `contents`, so round-trips are lossless.\n const fences = (contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');\n const fence =\n fences.length === 1 && isEligibleTreeFenceLang(fences[0].lang) ? fences[0] : undefined;\n if (fence) {\n const detection = detectTree(fence.value, { explicit: isExplicitTreeLang(fence.lang) });\n if (detection.isTree && detection.tree) {\n const { items } = treeToTemplateData(detection.tree);\n return { items, ...(headingText ? { title: headingText } : {}) };\n }\n }\n const list = findFirstList(contents);\n if (list) {\n const { items } = treeToTemplateData(treeFromMarkdownList(list));\n if (items.length > 0) return { items, ...(headingText ? { title: headingText } : {}) };\n }\n return placeholders ? {} : null;\n }\n default:\n return placeholders ? {} : null;\n }\n}\n","/**\n * Frontmatter serialization for user-defined custom templates (layouts).\n *\n * Custom template definitions live in the document's YAML frontmatter\n * under the key `squisq-custom-templates`. They're stored as a single\n * **compact JSON** object keyed by template name:\n *\n * ```yaml\n * squisq-custom-templates: {\"hero\":{\"lb\":\"Hero Section\",\"ly\":[{\"ty\":\"text\",…}]}}\n * ```\n *\n * Squisq's frontmatter parser is line-based; a JSON object literal\n * round-trips through it verbatim (no leading quote to strip, single\n * line), so the value is written **unquoted** and stays human-readable\n * and diffable — important for a codebase edited by people and agents.\n *\n * The JSON is kept small by:\n * - keying definitions by `name` (drops the `name` field + array wrapper),\n * - omitting the viewport when it's the 1920×1080 default,\n * - renaming well-known property names to two-letter codes via\n * {@link LONG_TO_SHORT} (e.g. `fontSize` → `fz`).\n *\n * The rename is a generic, recursive, bijective pass: **any property not\n * in the map passes through unchanged**, so the format is lossless even\n * as the Layer schema grows — new fields are simply stored under their\n * full name until (optionally) added to the map.\n *\n * Back-compat: the reader still accepts the historical base64-of-JSON\n * payload and a structured array, so older documents load unchanged.\n * The first save migrates them to the compact form.\n *\n */\n\nimport type { Layer } from '../schemas/Doc.js';\nimport type { CustomTemplateDefinition } from '../schemas/CustomTemplates.js';\nimport { FRONTMATTER_CUSTOM_TEMPLATES_KEY } from '../schemas/CustomTemplates.js';\n\nconst DEFAULT_VIEWPORT = { width: 1920, height: 1080 };\n\n/** Re-export for callers that need the canonical key spelling. */\nexport { FRONTMATTER_CUSTOM_TEMPLATES_KEY };\n\n// ─── Compact key codec ──────────────────────────────────────────────\n\n/**\n * Long → short property-name map. Values must be unique and must not\n * collide with any real key that passes through unmapped (those are\n * 1-char — `x`/`y`/`d`/`id`/`to` — or full words; the codes here are\n * 2-letter combos, so they never clash). A field literally named like a\n * code (e.g. a real `fz` key) would be the one corruption case — none\n * exist in the schema, and the round-trip test guards against it.\n */\nconst LONG_TO_SHORT: Readonly<Record<string, string>> = {\n // definition\n label: 'lb',\n description: 'ds',\n viewport: 'vp',\n layers: 'ly',\n name: 'nm',\n // layer\n type: 'ty',\n position: 'po',\n content: 'ct',\n animation: 'am',\n // position\n width: 'wd',\n height: 'hg',\n anchor: 'an',\n // text\n text: 'tx',\n style: 'sy',\n fontSize: 'fz',\n fontFamily: 'ff',\n fontWeight: 'fw',\n color: 'cl',\n textAlign: 'al',\n verticalAlign: 'vl',\n lineHeight: 'lh',\n shadow: 'sd',\n background: 'bg',\n backgroundOpacity: 'bo',\n backgroundGradient: 'bj',\n borderColor: 'bc',\n borderWidth: 'bw',\n borderStyle: 'bs',\n padding: 'pd',\n maxLines: 'mx',\n // shape / path\n shape: 'sp',\n fill: 'fl',\n fillOpacity: 'fo',\n gradient: 'gr',\n stroke: 'sk',\n strokeWidth: 'sw',\n borderRadius: 'br',\n shapeKind: 'kd',\n dasharray: 'da',\n arrow: 'ar',\n startMarker: 'st',\n endMarker: 'em',\n // image\n src: 'sc',\n alt: 'at',\n fit: 'ft',\n credit: 'cr',\n license: 'lc',\n // gradient\n from: 'fr',\n angle: 'ag',\n};\n\nconst SHORT_TO_LONG: Readonly<Record<string, string>> = Object.fromEntries(\n Object.entries(LONG_TO_SHORT).map(([long, short]) => [short, long]),\n);\n\n/** Recursively rename an object's keys via `map`, leaving unmapped keys. */\nfunction renameKeys(value: unknown, map: Readonly<Record<string, string>>): unknown {\n if (Array.isArray(value)) return value.map((v) => renameKeys(v, map));\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[map[k] ?? k] = renameKeys(v, map);\n }\n return out;\n }\n return value;\n}\n\nfunction isDefaultViewport(v: { width: number; height: number } | undefined): boolean {\n return !v || (v.width === DEFAULT_VIEWPORT.width && v.height === DEFAULT_VIEWPORT.height);\n}\n\n/** UTF-8 safe `atob`. */\nfunction base64ToUtf8(b64: string): string {\n if (typeof globalThis.atob === 'function') {\n const binary = globalThis.atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n return Buffer.from(b64, 'base64').toString('utf-8');\n}\n\n// ─── Definition list read / write ───────────────────────────────────\n\n/**\n * Read the `squisq-custom-templates` frontmatter key and decode it into\n * an array of CustomTemplateDefinitions. Returns undefined when the key\n * is absent or unparseable so callers can omit the field from the Doc.\n *\n * Accepts, in order: the compact JSON object (current), a base64-JSON\n * string (legacy), and an already-structured array/object (in case a\n * richer YAML parser delivers it). Malformed payloads return undefined\n * rather than failing the whole doc load.\n */\nexport function readCustomTemplatesFromFrontmatter(\n frontmatter: Record<string, unknown> | undefined,\n): CustomTemplateDefinition[] | undefined {\n if (!frontmatter) return undefined;\n const candidates = normalizeCandidates(frontmatter[FRONTMATTER_CUSTOM_TEMPLATES_KEY]);\n if (!candidates) return undefined;\n const out: CustomTemplateDefinition[] = [];\n for (const entry of candidates) {\n if (!entry || typeof entry !== 'object') continue;\n const e = entry as Record<string, unknown>;\n if (typeof e.name !== 'string' || typeof e.label !== 'string') continue;\n if (!Array.isArray(e.layers)) continue;\n const def: CustomTemplateDefinition = {\n name: e.name,\n label: e.label,\n viewport: readViewport(e.viewport),\n layers: e.layers as Layer[],\n };\n if (typeof e.description === 'string') def.description = e.description;\n out.push(def);\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * Encode a list of custom template definitions into the compact JSON\n * object described in the module header. Returns undefined when the\n * input list is empty so callers can leave the key off the output.\n */\nexport function writeCustomTemplatesToFrontmatter(\n templates: readonly CustomTemplateDefinition[] | undefined,\n options?: { pretty?: boolean },\n): string | undefined {\n if (!templates || templates.length === 0) return undefined;\n const map: Record<string, Record<string, unknown>> = {};\n for (const def of templates) {\n const entry: Record<string, unknown> = { lb: def.label };\n if (def.description) entry.ds = def.description;\n if (!isDefaultViewport(def.viewport)) entry.vp = def.viewport;\n entry.ly = renameKeys(def.layers, LONG_TO_SHORT);\n map[def.name] = entry;\n }\n // Pretty output is multi-line, so it rides out as a YAML literal block\n // scalar (see `formatBlockScalar` / stringify's frontmatter path) and\n // parses back via `JSON.parse`. Default stays compact (single line) so\n // existing docs and snapshots are byte-unchanged. The compact key codec\n // (LONG_TO_SHORT) is applied in both modes.\n return JSON.stringify(map, null, options?.pretty ? 2 : undefined);\n}\n\nfunction readViewport(raw: unknown): { width: number; height: number } {\n if (raw && typeof raw === 'object') {\n const v = raw as Record<string, unknown>;\n const w = typeof v.width === 'number' ? v.width : DEFAULT_VIEWPORT.width;\n const h = typeof v.height === 'number' ? v.height : DEFAULT_VIEWPORT.height;\n return { width: w, height: h };\n }\n return DEFAULT_VIEWPORT;\n}\n\n/**\n * Expand the compact, name-keyed map into full-keyed definition objects\n * that {@link readCustomTemplatesFromFrontmatter}'s validation loop\n * understands. The `name` comes from the map key.\n */\nfunction expandCompactMap(map: Record<string, unknown>): unknown[] {\n return Object.entries(map).map(([name, raw]) => {\n const e = (raw && typeof raw === 'object' ? raw : {}) as Record<string, unknown>;\n const def: Record<string, unknown> = {\n name,\n label: e.lb,\n viewport: e.vp ?? { ...DEFAULT_VIEWPORT },\n layers: renameKeys(e.ly ?? [], SHORT_TO_LONG),\n };\n if (typeof e.ds === 'string') def.description = e.ds;\n return def;\n });\n}\n\n/** Turn a parsed value into a list of full-keyed definition objects. */\nfunction fromParsed(parsed: unknown): unknown[] | null {\n if (Array.isArray(parsed)) return parsed; // legacy structured array\n if (parsed && typeof parsed === 'object')\n return expandCompactMap(parsed as Record<string, unknown>);\n return null;\n}\n\nfunction tryJson(s: string): unknown | undefined {\n try {\n return JSON.parse(s);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Normalize any supported payload shape into a list of full-keyed\n * definition objects. Returns null when the value is none of them.\n */\nfunction normalizeCandidates(raw: unknown): unknown[] | null {\n if (raw == null) return null;\n if (Array.isArray(raw)) return raw;\n if (typeof raw === 'object') return expandCompactMap(raw as Record<string, unknown>);\n if (typeof raw !== 'string') return null;\n\n // Current format: a JSON object/array literal stored verbatim.\n const direct = tryJson(raw.trim());\n if (direct !== undefined) return fromParsed(direct);\n\n // Legacy format: base64-encoded JSON.\n try {\n const decoded = tryJson(base64ToUtf8(raw));\n if (decoded !== undefined) return fromParsed(decoded);\n } catch {\n // not valid base64 either\n }\n return null;\n}\n","/**\n * Frontmatter serialization for user-defined custom themes.\n *\n * The theme analog of {@link ./customTemplatesFrontmatter.ts}. Custom Theme\n * definitions live in the document's YAML frontmatter under the key\n * `squisq-custom-themes`, stored as a single **compact JSON** object keyed\n * by theme id:\n *\n * ```yaml\n * squisq-custom-themes: {\"my-brand\":{\"schemaVersion\":\"1\",\"id\":\"my-brand\",…}}\n * ```\n *\n * Squisq's frontmatter parser is line-based; a JSON object literal\n * round-trips through it verbatim (single line, no leading quote to strip),\n * so the value is written **unquoted** and stays human-readable and diffable\n * — the same mechanism the custom-templates codec relies on.\n *\n * Only one theme is *active* per doc (selected by id via the `squisq-theme`\n * frontmatter key / `Doc.themeId`), but the payload is a keyed map — parallel\n * to custom templates — so a doc can carry a small catalog and switch between\n * them, and `resolveThemeForDoc` can resolve any of them doc-scoped.\n *\n * Malformed entries are dropped (via `validateTheme`) rather than failing the\n * whole doc load, matching the tolerant behavior of the templates reader.\n */\n\nimport type { Theme } from '../schemas/Theme.js';\nimport { FRONTMATTER_CUSTOM_THEMES_KEY } from '../schemas/Theme.js';\nimport { validateTheme } from '../schemas/themeValidator.js';\n\n/** Re-export for callers that need the canonical key spelling. */\nexport { FRONTMATTER_CUSTOM_THEMES_KEY };\n\n/**\n * Normalize the raw frontmatter value into an array of candidate objects.\n * Accepts, in order: a JSON string (current, from the line-based parser),\n * an already-parsed object map (keyed by id), and an array (in case a richer\n * YAML parser delivers one). Returns undefined when absent/unparseable.\n */\nfunction normalizeCandidates(raw: unknown): unknown[] | undefined {\n if (raw === undefined || raw === null) return undefined;\n let value: unknown = raw;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n try {\n value = JSON.parse(trimmed);\n } catch {\n return undefined;\n }\n }\n if (Array.isArray(value)) return value;\n if (value && typeof value === 'object') {\n return Object.values(value as Record<string, unknown>);\n }\n return undefined;\n}\n\n/**\n * Read the custom themes inlined into a document's frontmatter. Returns\n * undefined when the key is absent or holds no valid theme, so callers can\n * omit the field from the Doc.\n */\nexport function readCustomThemesFromFrontmatter(\n frontmatter: Record<string, unknown> | undefined,\n): Theme[] | undefined {\n if (!frontmatter) return undefined;\n const candidates = normalizeCandidates(frontmatter[FRONTMATTER_CUSTOM_THEMES_KEY]);\n if (!candidates) return undefined;\n const out: Theme[] = [];\n for (const entry of candidates) {\n const result = validateTheme(entry);\n if (result.valid && result.theme) out.push(result.theme);\n }\n return out.length > 0 ? out : undefined;\n}\n\n/**\n * Encode a list of custom themes into the compact JSON object described in\n * the module header (keyed by theme id). Returns undefined when the input is\n * empty so callers can leave the key off the output.\n */\nexport function writeCustomThemesToFrontmatter(\n themes: readonly Theme[] | undefined,\n options?: { pretty?: boolean },\n): string | undefined {\n if (!themes || themes.length === 0) return undefined;\n const map: Record<string, Theme> = {};\n for (const theme of themes) map[theme.id] = theme;\n // Pretty output is multi-line, so it serializes as a YAML literal block\n // scalar (see the markdown stringify frontmatter path) and reads back via\n // `JSON.parse`. Default stays compact (single line) so existing docs and\n // snapshots are byte-unchanged.\n return JSON.stringify(map, null, options?.pretty ? 2 : undefined);\n}\n","/**\n * Structured template data from markdown body content.\n *\n * Attribute strings on a heading annotation are fine for scalar params,\n * but tabular or nested inputs (dataTable rows, map markers, chart data)\n * don't pack well into a single quoted line. This module supplies the two\n * structured channels instead:\n *\n * 1. **Data fences** — a fenced code block whose info string is\n * `json data` or `yaml data`, placed in a heading's body content:\n *\n * ````markdown\n * ## Quarterly numbers {[dataTable]}\n *\n * ```json data\n * { \"headers\": [\"Q\", \"Revenue\"], \"rows\": [[\"Q1\", \"1.2M\"], [\"Q2\", \"1.4M\"]] }\n * ```\n * ````\n *\n * The parsed object lands on `block.templateData` and merges into the\n * template input (after defaults, before `{[…]}` string overrides).\n * The `data` marker keeps ordinary ```json code samples — which should\n * render as code — out of the template input.\n *\n * 2. **GFM tables** — for the `dataTable` template, the first table in the\n * section body supplies `headers` / `rows` / `align` when the author\n * didn't provide them explicitly.\n *\n * YAML support is a documented subset (this package has no YAML\n * dependency): top-level `key: scalar`, `key: [inline, array]`, `key:`\n * followed by an indented `- item` block sequence (scalars or inline\n * arrays), and `key:` followed by *one level* of indented `subkey: scalar`\n * lines (a nested map, e.g. `center:` + indented `lat:` / `lng:`). Deeper\n * nesting, and mixing list items with mapping keys under one key, are\n * rejected with a clear error — use a `json data` fence for those.\n */\n\nimport type {\n MarkdownBlockNode,\n MarkdownCodeBlock,\n MarkdownTable,\n MarkdownTableRow,\n} from '../markdown/types.js';\nimport { extractPlainText } from '../markdown/utils.js';\n\n// ============================================\n// Data fences\n// ============================================\n\n/** Languages accepted for data fences. */\nconst DATA_FENCE_LANGS = new Set(['json', 'yaml', 'yml']);\n\n/**\n * Whether a code block is a structured-data fence: lang `json`/`yaml`/`yml`\n * with the word `data` in the fence meta (` ```json data `).\n */\nexport function isDataFence(node: MarkdownCodeBlock): boolean {\n if (!node.lang || !DATA_FENCE_LANGS.has(node.lang.toLowerCase())) return false;\n const meta = node.meta ?? '';\n return /\\bdata\\b/.test(meta);\n}\n\nexport interface DataFenceParseResult {\n /** Parsed key→value map. Undefined when parsing failed. */\n data?: Record<string, unknown>;\n /** Parse failure description. Undefined when parsing succeeded. */\n error?: string;\n}\n\n/**\n * Parse a data fence's content into a key→value map. JSON fences must\n * contain a top-level object (arrays have no key to merge under); YAML\n * fences are parsed with {@link parseYamlSubset}.\n */\nexport function parseDataFence(node: MarkdownCodeBlock): DataFenceParseResult {\n const lang = node.lang?.toLowerCase();\n if (lang === 'json') {\n try {\n const parsed: unknown = JSON.parse(node.value);\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return { error: 'JSON data fence must contain a top-level object ({\"key\": …})' };\n }\n return { data: parsed as Record<string, unknown> };\n } catch (err: unknown) {\n return { error: `invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n }\n try {\n return { data: parseYamlSubset(node.value) };\n } catch (err: unknown) {\n return { error: `invalid YAML: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\n/**\n * Return a new contents array with the first data fence's code content\n * replaced by `data` (pretty-printed JSON). The fence node keeps its\n * language and `data` marker; only `value` changes. When no data fence\n * exists, a new ` ```json data ` fence is appended instead.\n *\n * Pure: neither `contents` nor its nodes are mutated. This is the write\n * half of the data-fence channel — editors update `block.templateData`\n * and call this to reflect the change back into `block.contents`.\n */\nexport function replaceDataFence(\n contents: MarkdownBlockNode[],\n data: Record<string, unknown>,\n): MarkdownBlockNode[] {\n const value = JSON.stringify(data, null, 2);\n const index = contents.findIndex((node) => node.type === 'code' && isDataFence(node));\n if (index < 0) {\n const fence: MarkdownCodeBlock = { type: 'code', lang: 'json', meta: 'data', value };\n return [...contents, fence];\n }\n const next = [...contents];\n next[index] = { ...(contents[index] as MarkdownCodeBlock), value };\n return next;\n}\n\n// ============================================\n// YAML subset parser\n// ============================================\n\n/** Parse a scalar token: quoted string, boolean, null, number, or string. */\nfunction parseScalar(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed.length >= 2) {\n const q = trimmed[0];\n if ((q === '\"' || q === \"'\") && trimmed.endsWith(q)) {\n return trimmed.slice(1, -1);\n }\n }\n if (trimmed === 'true') return true;\n if (trimmed === 'false') return false;\n if (trimmed === 'null' || trimmed === '~') return null;\n if (trimmed !== '' && !isNaN(Number(trimmed))) return Number(trimmed);\n return trimmed;\n}\n\n/**\n * Split an inline-array interior on top-level commas, respecting quotes.\n */\nfunction splitInlineArray(interior: string): string[] {\n const items: string[] = [];\n let current = '';\n let quote: string | null = null;\n for (const ch of interior) {\n if (quote) {\n current += ch;\n if (ch === quote) quote = null;\n } else if (ch === '\"' || ch === \"'\") {\n quote = ch;\n current += ch;\n } else if (ch === ',') {\n items.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n items.push(current);\n // A trailing comma (or empty interior) leaves an empty final item — drop it.\n return items.map((s) => s.trim()).filter((s) => s !== '');\n}\n\n/** Parse a value that may be an inline array `[a, b]` or a scalar. */\nfunction parseInlineValue(raw: string): unknown {\n const trimmed = raw.trim();\n if (trimmed.startsWith('[') && trimmed.endsWith(']')) {\n return splitInlineArray(trimmed.slice(1, -1)).map(parseScalar);\n }\n return parseScalar(trimmed);\n}\n\n/**\n * Parse the supported YAML subset (see module doc) into a key→value map.\n * Throws an Error with a line-anchored message on anything outside the\n * subset, so callers can surface a precise diagnostic.\n */\nexport function parseYamlSubset(src: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = src.split('\\n');\n\n // Open block under the most recent `key:` line: whether its children are a\n // block sequence (`- …`) or a nested map (`subkey: …`) is decided by the\n // first indented child; `childIndent` pins the one allowed child depth.\n let pendingKey: string | null = null;\n let pendingKind: 'list' | 'map' | null = null;\n let childIndent = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n const indent = line.length - line.trimStart().length;\n\n if (indent > 0) {\n if (!pendingKey) {\n throw new Error(`line ${i + 1}: unexpected indented line without a preceding \"key:\" line`);\n }\n if (childIndent < 0) childIndent = indent;\n if (indent > childIndent) {\n throw new Error(\n `line ${i + 1}: nesting deeper than one level is not supported — use a \\`\\`\\`json data fence for nested input`,\n );\n }\n\n if (trimmed.startsWith('- ')) {\n if (pendingKind === 'map') {\n throw new Error(\n `line ${i + 1}: cannot mix list items and mapping keys under \"${pendingKey}\"`,\n );\n }\n pendingKind = 'list';\n (result[pendingKey] as unknown[]).push(parseInlineValue(trimmed.slice(2)));\n continue;\n }\n\n // Otherwise this is a nested `subkey: value` mapping line.\n if (pendingKind === 'list') {\n throw new Error(\n `line ${i + 1}: cannot mix mapping keys and list items under \"${pendingKey}\"`,\n );\n }\n const subColon = trimmed.indexOf(':');\n if (subColon < 1) {\n throw new Error(`line ${i + 1}: expected \"key: value\"`);\n }\n const subValue = trimmed.slice(subColon + 1).trim();\n if (subValue === '') {\n // A nested `subkey:` opening its own block would be a second level.\n throw new Error(\n `line ${i + 1}: nesting deeper than one level is not supported — use a \\`\\`\\`json data fence for nested input`,\n );\n }\n if (pendingKind !== 'map') {\n pendingKind = 'map';\n result[pendingKey] = {};\n }\n (result[pendingKey] as Record<string, unknown>)[trimmed.slice(0, subColon).trim()] =\n parseInlineValue(subValue);\n continue;\n }\n\n pendingKey = null;\n pendingKind = null;\n childIndent = -1;\n const colonIdx = trimmed.indexOf(':');\n if (colonIdx < 1) {\n throw new Error(`line ${i + 1}: expected \"key: value\"`);\n }\n const key = trimmed.slice(0, colonIdx).trim();\n const rawValue = trimmed.slice(colonIdx + 1).trim();\n\n if (rawValue === '') {\n // `key:` opens a block: an indented `- …` sequence or a `subkey: …`\n // map. Default to an empty list so a `key:` with no children stays\n // back-compatible (`{ key: [] }`); the map branch replaces it wholesale.\n result[key] = [];\n pendingKey = key;\n } else {\n result[key] = parseInlineValue(rawValue);\n }\n }\n\n return result;\n}\n\n// ============================================\n// GFM table extraction\n// ============================================\n\nexport interface ExtractedTableData {\n headers: string[];\n rows: string[][];\n align?: (('left' | 'right' | 'center') | null)[];\n}\n\n/** Find the first GFM table among a block's body contents. */\nexport function findFirstTable(\n contents: MarkdownBlockNode[] | undefined,\n): MarkdownTable | undefined {\n return contents?.find((n): n is MarkdownTable => n.type === 'table');\n}\n\n/**\n * Extract `headers` / `rows` / `align` (the `dataTable` input shape) from a\n * GFM table node. The first row is the header row.\n */\nexport function extractTableData(table: MarkdownTable): ExtractedTableData {\n const toCells = (row: MarkdownTableRow): string[] =>\n row.children.map((cell) => extractPlainText(cell).trim());\n\n const [headerRow, ...bodyRows] = table.children;\n return {\n headers: headerRow ? toCells(headerRow) : [],\n rows: bodyRows.map(toCells),\n ...(table.align && table.align.some((a) => a != null) ? { align: table.align } : {}),\n };\n}\n","/**\n * Standalone-paragraph annotation parser.\n *\n * A paragraph whose entire trimmed text is exactly a `{[…]}` annotation\n * (nothing before or after) is a *standalone annotation*. Two features share\n * this shape:\n *\n * - **Media annotations** (`{[audio …]}` / `{[video …]}`) — lifted into typed\n * {@link import('../schemas/Media.js').MediaClip}s by `mediaAnnotations.ts`.\n * - **Standalone template blocks** (`{[quote]}`, `{[statHighlight …]}`, …) —\n * turned into heading-less {@link import('../schemas/Doc.js').Block}s by\n * `annotationBlocks.ts`.\n *\n * Both call the single parser here so the annotation grammar (quoting,\n * escaping, first-token-is-template) stays identical to the heading form.\n */\n\nimport {\n matchTrailingTemplateAnnotation,\n tokenizeAttrTokens,\n splitKeyValueToken,\n} from '../markdown/attrTokens.js';\nimport type { MarkdownBlockNode } from '../markdown/types.js';\n\n/** The template name + params parsed out of a standalone `{[…]}` paragraph. */\nexport interface ParsedAnnotation {\n /** First bare token, when the annotation leads with one (e.g. `quote`). */\n template?: string;\n /** Remaining `key=value` tokens, unquoted/unescaped. */\n params: Record<string, string>;\n}\n\n/**\n * Parse a paragraph node that is *exactly* a `{[…]}` annotation (nothing\n * before or after). Returns the template + params, or null when the node\n * isn't a standalone annotation (not a paragraph, more than one child, a\n * non-text child such as a resolved inline icon, or trailing text).\n */\nexport function parseStandaloneAnnotation(node: MarkdownBlockNode): ParsedAnnotation | null {\n if (node.type !== 'paragraph') return null;\n const children = node.children ?? [];\n if (children.length !== 1 || children[0].type !== 'text') return null;\n const text = children[0].value.trim();\n const match = matchTrailingTemplateAnnotation(text);\n // index 0 means the whole (trimmed) paragraph is the annotation.\n if (!match || match.index !== 0) return null;\n\n const tokens = tokenizeAttrTokens(match.inner.trim());\n const firstIsParam = tokens.length > 0 && tokens[0].indexOf('=') > 0;\n const template = firstIsParam || tokens.length === 0 ? undefined : tokens[0];\n const startIdx = firstIsParam ? 0 : 1;\n const params: Record<string, string> = {};\n for (let i = startIdx; i < tokens.length; i++) {\n const kv = splitKeyValueToken(tokens[i]);\n if (kv) params[kv.key] = kv.value;\n }\n return { template, params };\n}\n","/**\n * Media-annotation extraction.\n *\n * Lifts standalone body-level media annotations — `{[audio …]}` / `{[video …]}`\n * — out of a block's markdown contents into typed {@link MediaClip}s. A block\n * can hold several clips (unlike the single heading annotation). An annotation\n * flagged `anchor=document` (or `span=document`) becomes a document-spanning\n * clip instead. The annotation grammar is the shared one used for heading\n * annotations, so quoting/escaping behave identically.\n */\n\nimport { parseTimeSeconds } from '../markdown/annotationCoercion.js';\nimport type { MarkdownBlockNode } from '../markdown/types.js';\nimport type { MediaClip } from '../schemas/Media.js';\nimport { parseStandaloneAnnotation, type ParsedAnnotation } from './standaloneAnnotation.js';\n\n/** Annotation template names that produce a timed media clip. */\nconst MEDIA_TEMPLATES = new Set(['audio', 'video', 'media']);\n\n/**\n * Whether a standalone-annotation template name is a media name\n * (`audio`/`video`/`media`). The standalone template-block extractor uses\n * this to leave media annotations to {@link extractMediaFromContents}.\n */\nexport function isMediaAnnotationName(name: string | undefined): boolean {\n return name != null && MEDIA_TEMPLATES.has(name);\n}\n\nfunction time(raw: string | undefined): number | null {\n if (raw == null) return null;\n return parseTimeSeconds(raw);\n}\n\n/** Build a {@link MediaClip} from a parsed media annotation, or null if invalid. */\nfunction toMediaClip(parsed: ParsedAnnotation, id: string): MediaClip | null {\n const { template, params } = parsed;\n if (!template || !MEDIA_TEMPLATES.has(template)) return null;\n const src = params.src;\n if (!src) return null;\n\n const kind: MediaClip['kind'] = template === 'video' ? 'video' : 'audio';\n const anchor: MediaClip['anchor'] =\n params.anchor === 'document' || params.span === 'document' ? 'document' : 'block';\n // `startAt` is canonical; `startTime` is accepted as an alias (it is the\n // heading-attribute spelling, so authors reach for it here too).\n const clip: MediaClip = {\n id,\n src,\n kind,\n startAt: time(params.startAt ?? params.startTime) ?? 0,\n anchor,\n };\n\n const clipStart = time(params.clipStart);\n const clipEnd = time(params.clipEnd);\n if (clipStart != null) clip.clipStart = clipStart;\n if (clipEnd != null) clip.clipEnd = clipEnd;\n // `spillover` or `spillover=true` → true; absent/`false` → omitted.\n if (params.spillover === 'true' || params.spillover === '') clip.spillover = true;\n\n return clip;\n}\n\nexport interface MediaExtraction {\n /** Block-anchored clips (anchor='block'). */\n media: MediaClip[];\n /** Document-spanning clips (anchor='document'). */\n documentMedia: MediaClip[];\n /** Contents with the lifted media-annotation paragraphs removed. */\n remaining: MarkdownBlockNode[];\n}\n\n/**\n * Walk `contents`, lifting every standalone media annotation into a\n * {@link MediaClip}. `makeId(src, index)` produces stable clip ids.\n * When `blockId` is given, each clip records its round-trip `origin` —\n * the owning block, its position in the ORIGINAL contents array, and\n * the annotation paragraph's exact text — so `docToMarkdown` can\n * re-insert it byte-stably.\n */\nexport function extractMediaFromContents(\n contents: MarkdownBlockNode[] | undefined,\n makeId: (src: string, index: number) => string,\n blockId?: string,\n): MediaExtraction {\n const media: MediaClip[] = [];\n const documentMedia: MediaClip[] = [];\n const remaining: MarkdownBlockNode[] = [];\n let index = 0;\n let originalIndex = 0;\n\n for (const node of contents ?? []) {\n const parsed = parseStandaloneAnnotation(node);\n const clip = parsed ? toMediaClip(parsed, '') : null;\n if (parsed && clip) {\n clip.id = makeId(clip.src, index++);\n const line = node.position?.start.line;\n if (line != null) clip.sourceLine = line;\n if (blockId !== undefined) {\n // parseStandaloneAnnotation only matches a paragraph with exactly\n // one text child, so this read is safe when `parsed` is non-null.\n const rawText =\n node.type === 'paragraph' && node.children?.[0]?.type === 'text'\n ? node.children[0].value.trim()\n : undefined;\n clip.origin = {\n blockId,\n index: originalIndex,\n ...(rawText !== undefined ? { raw: rawText } : {}),\n };\n }\n (clip.anchor === 'document' ? documentMedia : media).push(clip);\n } else {\n remaining.push(node);\n }\n originalIndex++;\n }\n\n return { media, documentMedia, remaining };\n}\n","/**\n * Standalone template-annotation block extraction.\n *\n * A paragraph whose entire trimmed text is exactly `{[templateName key=value …]}`\n * — where `templateName` is not a media name (media annotations are extracted\n * first, into typed clips) — becomes a *heading-less template block*. The body\n * nodes that follow it, up to the next heading or the next standalone\n * annotation, become that block's `contents`.\n *\n * This is the block analog of {@link import('./mediaAnnotations.js').extractMediaFromContents}:\n * both walk a block's body `contents` and lift standalone `{[…]}` paragraphs\n * out, sharing the {@link parseStandaloneAnnotation} parser. Runs AFTER media\n * extraction (so media names keep their meaning) and BEFORE structured-data\n * parsing (so `json data` / `yaml data` fences attach to the new blocks).\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type { MarkdownBlockNode } from '../markdown/types.js';\nimport { coerceAnnotationValues, type CoercedBlockMeta } from '../markdown/annotationCoercion.js';\nimport { resolveTemplateName } from './templates/index.js';\nimport { isMediaAnnotationName } from './mediaAnnotations.js';\nimport { parseStandaloneAnnotation, type ParsedAnnotation } from './standaloneAnnotation.js';\n\n/** Configuration for {@link extractTemplateBlocksFromContents}. */\nexport interface StandaloneBlockOptions {\n /** Produce a unique block id for a parsed standalone annotation. */\n makeId: (parsed: ParsedAnnotation) => string;\n /** Initial `duration` for a produced block (the timing pass overrides it). */\n defaultDuration: number;\n}\n\n/** The split produced by {@link extractTemplateBlocksFromContents}. */\nexport interface TemplateBlockExtraction {\n /** Contents before the first standalone template annotation (stay on the\n * containing block). */\n leading: MarkdownBlockNode[];\n /** Heading-less blocks, each carrying the body nodes that followed its\n * annotation up to the next annotation / end of contents. */\n blocks: Block[];\n}\n\n/**\n * Apply coerced block-meta values onto a produced block. Mirrors\n * `markdownToDoc`'s `applyBlockMeta` so a standalone `{[quote duration=8]}`\n * honors the same block-meta keys a heading `{[…]}` annotation would.\n */\nfunction applyBlockMeta(block: Block, m: CoercedBlockMeta): void {\n if (m.x != null) block.x = m.x;\n if (m.y != null) block.y = m.y;\n if (m.startTime != null) block.startTime = m.startTime;\n if (m.duration != null) block.duration = m.duration;\n if (m.connectsTo) block.connectsTo = m.connectsTo;\n if (m.transition) block.transition = m.transition;\n}\n\n/** Build a heading-less block from a parsed standalone template annotation. */\nfunction makeStandaloneBlock(parsed: ParsedAnnotation, options: StandaloneBlockOptions): Block {\n // `parsed.template` is guaranteed defined by the caller's guard.\n const rawTemplate = parsed.template as string;\n const params = parsed.params;\n const hasParams = Object.keys(params).length > 0;\n\n const block: Block = {\n id: options.makeId(parsed),\n startTime: 0,\n duration: options.defaultDuration,\n audioSegment: 0,\n template: resolveTemplateName(rawTemplate),\n standaloneAnnotation: true,\n // Keep the raw (un-resolved) name so validation can report the exact\n // requested name — symmetric with `sourceHeading.templateAnnotation`.\n sourceAnnotation: { template: rawTemplate, ...(hasParams ? { params } : {}) },\n // Only carry a display title when the author supplied one.\n ...(params.title ? { title: params.title } : {}),\n };\n\n if (hasParams) {\n block.templateOverrides = params;\n applyBlockMeta(block, coerceAnnotationValues(params).blockMeta);\n }\n\n return block;\n}\n\n/**\n * Walk `contents`, lifting standalone template-annotation paragraphs into\n * heading-less blocks. Nodes after an annotation (until the next annotation\n * or the end of `contents`) attach to that block. Media annotations are left\n * in place — they are extracted separately, before this runs. `contents` is\n * not mutated; the split is returned.\n */\nexport function extractTemplateBlocksFromContents(\n contents: MarkdownBlockNode[] | undefined,\n options: StandaloneBlockOptions,\n): TemplateBlockExtraction {\n const leading: MarkdownBlockNode[] = [];\n const blocks: Block[] = [];\n let current: Block | null = null;\n\n for (const node of contents ?? []) {\n const parsed = parseStandaloneAnnotation(node);\n const isTemplateAnnotation =\n parsed != null && parsed.template != null && !isMediaAnnotationName(parsed.template);\n\n if (isTemplateAnnotation) {\n const block = makeStandaloneBlock(parsed as ParsedAnnotation, options);\n blocks.push(block);\n current = block;\n } else if (current) {\n (current.contents ??= []).push(node);\n } else {\n leading.push(node);\n }\n }\n\n return { leading, blocks };\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 {\n Doc,\n Block,\n CaptionTrack,\n CaptionPhrase,\n StartBlockConfig,\n DocDiagnostic,\n} from '../schemas/Doc.js';\nimport { readCustomTemplatesFromFrontmatter } from './customTemplatesFrontmatter.js';\nimport { readCustomThemesFromFrontmatter } from './customThemesFrontmatter.js';\nimport type {\n MarkdownDocument,\n MarkdownBlockNode,\n MarkdownCodeBlock,\n MarkdownHeading,\n MarkdownNode,\n HtmlNode,\n} from '../markdown/types.js';\nimport { extractPlainText } from '../markdown/utils.js';\nimport { coerceAnnotationValues, type CoercedBlockMeta } from '../markdown/annotationCoercion.js';\nimport { estimateReadingTime } from '../timing/readingTime.js';\nimport { resolveTemplateName, isContainerTemplate } from './templates/index.js';\nimport { isDataFence, parseDataFence, findFirstTable, extractTableData } from './structuredData.js';\nimport { extractMediaFromContents } from './mediaAnnotations.js';\nimport { extractTemplateBlocksFromContents } from './annotationBlocks.js';\nimport type { ParsedAnnotation } from './standaloneAnnotation.js';\nimport { profileBlockContents, pickAutoTemplate } from '../recommend/templates.js';\nimport { deriveTemplateInputs } from './templateInputs.js';\nimport { isEligibleAsciiFenceLang } from './asciiDiagram/detect.js';\nimport { parseAsciiDiagram } from './asciiDiagram/parse.js';\nimport { asciiDiagramToTemplateData } from './asciiDiagram/mapping.js';\nimport { isEligibleAsciiTimelineFenceLang } from './asciiTimeline/detect.js';\nimport { parseAsciiTimeline } from './asciiTimeline/parse.js';\nimport type { MediaClip } from '../schemas/Media.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 * Timestamp recorded as `captions.generatedAt`. When omitted, the field\n * is left unset so that conversion is fully deterministic — the same\n * markdown always converts to an identical Doc (important for snapshot\n * tests, caching, and agents that verify their output by re-converting).\n */\n captionsGeneratedAt?: string;\n\n /**\n * Content-aware template auto-picking for unannotated headings\n * (default: true). When a heading block carries a strong content signal\n * — a table, images, a blockquote, a list, a stat-looking line — the\n * matching template is applied (with inputs derived from the body)\n * instead of the structural `defaultTemplate`. Explicit `{[template]}`\n * annotations always win. Authors can also disable per document with\n * frontmatter `squisq-auto-templates: false`.\n */\n autoTemplates?: 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. `reserve()` registers an\n * author-pinned `{#id}` so a later heading whose slug matches doesn't\n * collide with it.\n */\nfunction createIdGenerator() {\n const used = new Map<string, number>();\n\n const generate = (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 generate.reserve = (id: string): void => {\n used.set(id, Math.max(used.get(id) ?? 0, 1));\n };\n\n // Slug + dedupe from arbitrary text (used for heading-less standalone\n // annotation blocks, which have no MarkdownHeading to slug from). Shares\n // the same `used` map so a standalone id can't collide with a heading id.\n generate.fromText = (text: string): string => {\n const base = slugify(text);\n const count = used.get(base) ?? 0;\n used.set(base, count + 1);\n return count === 0 ? base : `${base}-${count + 1}`;\n };\n\n return generate;\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 */\n/**\n * Apply coerced block-meta values onto a block's typed fields. Only keys\n * actually present are written, so a later caller (the Pandoc attribute\n * block) can override values supplied by the squiggly `{[…]}` annotation.\n */\nfunction applyBlockMeta(block: Block, m: CoercedBlockMeta): void {\n if (m.x != null) block.x = m.x;\n if (m.y != null) block.y = m.y;\n if (m.startTime != null) block.startTime = m.startTime;\n if (m.duration != null) block.duration = m.duration;\n if (m.connectsTo) block.connectsTo = m.connectsTo;\n if (m.transition) block.transition = m.transition;\n}\n\n/**\n * The block-meta an author pinned on a heading, drawn from either the\n * Pandoc `{key=value}` block or the squiggly `{[key=value]}` annotation\n * (Pandoc wins on conflict — same precedence as {@link makeBlock}). Used by\n * the timing passes to tell \"author pinned this\" from \"derive it\".\n */\nfunction pinnedHeadingMeta(heading: MarkdownHeading | undefined): CoercedBlockMeta {\n if (!heading) return {};\n const fromAnnotation = heading.templateAnnotation?.params\n ? coerceAnnotationValues(heading.templateAnnotation.params).blockMeta\n : {};\n const fromPandoc = heading.attributes?.blockMeta ?? {};\n return { ...fromAnnotation, ...fromPandoc };\n}\n\n/**\n * Pinned block-meta for any block: the heading pins ({@link pinnedHeadingMeta})\n * for heading blocks, or the standalone-annotation params for heading-less\n * standalone blocks. Lets a standalone `{[quote duration=8]}` pin timing the\n * same way a heading annotation would.\n */\nfunction pinnedMeta(block: Block): CoercedBlockMeta {\n if (block.sourceHeading) return pinnedHeadingMeta(block.sourceHeading);\n if (block.sourceAnnotation?.params) {\n return coerceAnnotationValues(block.sourceAnnotation.params).blockMeta;\n }\n return {};\n}\n\n/**\n * Public accessor for {@link pinnedMeta}: the timing/meta values an author\n * pinned on a block (heading `{key=value}` attrs or `{[key=value]}`\n * annotation params). Consumers use this to tell \"author pinned this\"\n * from \"derive it\" — e.g. narration timing never overwrites a pinned\n * `duration=`/`startTime=`.\n */\nexport function getPinnedBlockMeta(block: Block): CoercedBlockMeta {\n return pinnedMeta(block);\n}\n\n/**\n * Rebuild a block list, lifting standalone `{[…]}` template annotations out of\n * each block's body into heading-less sibling blocks (recursing into children\n * first). See {@link extractTemplateBlocksFromContents}.\n */\nfunction expandStandaloneAnnotations(\n blocks: Block[],\n makeId: (parsed: ParsedAnnotation) => string,\n defaultDuration: number,\n): Block[] {\n const out: Block[] = [];\n for (const block of blocks) {\n if (block.children && block.children.length > 0) {\n block.children = expandStandaloneAnnotations(block.children, makeId, defaultDuration);\n }\n const { leading, blocks: produced } = extractTemplateBlocksFromContents(block.contents, {\n makeId,\n defaultDuration,\n });\n if (produced.length > 0) {\n block.contents = leading;\n }\n out.push(block, ...produced);\n }\n return out;\n}\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 idGenerator = options?.generateId ? null : createIdGenerator();\n const generateId = options?.generateId ?? idGenerator!;\n\n let rootBlocks: Block[] = [];\n const diagnostics: DocDiagnostic[] = [];\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 // Pandoc `{#id}` overrides slug-from-heading when present. Pinned ids\n // are reserved in the slug generator so a later un-pinned heading with\n // the same slugified text doesn't collide.\n const pandocId = heading?.attributes?.id;\n const id = pandocId ? pandocId : heading ? generateId(heading, headingIndex++) : 'preamble';\n if (pandocId && idGenerator) {\n idGenerator.reserve(pandocId);\n }\n\n // Use template from annotation if present, otherwise fall back to default.\n // Legacy template ids (e.g. `titleBlock`) are normalized to their canonical\n // short form (`title`) so downstream comparisons can rely on the new names\n // without sprinkling alias resolution everywhere.\n const annotation = heading?.templateAnnotation;\n const rawTemplate = annotation?.template ?? (heading ? defaultTemplate : undefined);\n const template = rawTemplate != null ? resolveTemplateName(rawTemplate) : 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 // {[…]} template params → templateOverrides (template-specific overrides).\n // Known block-meta keys (duration, startTime, x, y, connectsTo) are *also*\n // honored in the squiggly form, so an author — or the timeline editor —\n // can write `{[duration=8]}` instead of the Pandoc `{duration=8}` block.\n // The raw params still flow to `templateOverrides` for round-tripping; the\n // Pandoc attribute block applied below wins when a key appears in both.\n if (annotation?.params) {\n block.templateOverrides = annotation.params;\n applyBlockMeta(block, coerceAnnotationValues(annotation.params).blockMeta);\n }\n\n // Pandoc {#id .class key=value} attributes → block-level fields.\n const attrs = heading?.attributes;\n if (attrs) {\n if (attrs.blockMeta) {\n applyBlockMeta(block, attrs.blockMeta);\n }\n if (attrs.classes && attrs.classes.length > 0) {\n block.classes = attrs.classes;\n }\n if (attrs.metadata && Object.keys(attrs.metadata).length > 0) {\n block.metadata = attrs.metadata;\n }\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 // Lift standalone body-level media annotations (`{[audio …]}` / `{[video …]}`)\n // into typed clips: block-anchored clips ride on `block.media`; clips flagged\n // `anchor=document` collect into the doc-level `documentMedia`. Done before\n // the reading-time pass so annotation text doesn't inflate block durations.\n const documentMedia: MediaClip[] = [];\n for (const block of flattenBlocks(rootBlocks)) {\n const {\n media,\n documentMedia: docMedia,\n remaining,\n } = extractMediaFromContents(\n block.contents,\n (src, i) => `${block.id}-media-${i}-${src.replace(/[^a-zA-Z0-9]+/g, '-')}`,\n block.id,\n );\n if (media.length > 0) block.media = media;\n if (docMedia.length > 0) documentMedia.push(...docMedia);\n if (block.contents) block.contents = remaining;\n }\n\n // A preamble block that held only document-media annotations is now empty —\n // drop it so a doc-spanning narration doesn't leave a phantom 5s block at the\n // top of the timeline. Only the heading-less preamble (rootBlocks[0]) can be\n // emptied this way.\n if (\n rootBlocks.length > 0 &&\n !rootBlocks[0].sourceHeading &&\n (rootBlocks[0].contents?.length ?? 0) === 0 &&\n (rootBlocks[0].children?.length ?? 0) === 0 &&\n !rootBlocks[0].media\n ) {\n rootBlocks.shift();\n }\n\n // Standalone `{[templateName …]}` paragraphs (non-media) become heading-less\n // template blocks; the body after each one, up to the next annotation,\n // becomes its `contents`. Done after media extraction (so media names keep\n // their meaning) and before structured-data parsing (so `json data` fences\n // attach to the produced blocks). Produced blocks are inserted as siblings\n // following the block whose body held the annotation.\n const makeStandaloneId = (parsed: ParsedAnnotation): string => {\n const base = parsed.params.title ?? parsed.template ?? 'block';\n return idGenerator ? idGenerator.fromText(base) : slugify(base);\n };\n rootBlocks = expandStandaloneAnnotations(rootBlocks, makeStandaloneId, defaultDuration);\n // A leading preamble whose entire body was consumed into standalone blocks\n // is now empty — drop it so it doesn't leave a phantom slide.\n if (\n rootBlocks.length > 0 &&\n !rootBlocks[0].sourceHeading &&\n !rootBlocks[0].standaloneAnnotation &&\n (rootBlocks[0].contents?.length ?? 0) === 0 &&\n (rootBlocks[0].children?.length ?? 0) === 0 &&\n !rootBlocks[0].media\n ) {\n rootBlocks.shift();\n }\n\n const allBlocks = flattenBlocks(rootBlocks);\n\n // Structured template data: ```json data / ```yaml data fences in a\n // block's body parse into `templateData`; for dataTable blocks the first\n // GFM table supplies headers/rows when not explicitly provided. Parse\n // failures degrade gracefully (the fence stays visible as code) and are\n // recorded as diagnostics.\n for (const block of allBlocks) {\n applyStructuredData(block, diagnostics);\n }\n\n // Explicitly diagram-annotated blocks whose body is a single eligible\n // ASCII-art fence get nodes/edges derived from it — no detection\n // threshold, the author asked for a diagram. Children-driven diagrams\n // and author `json data` node lists win over the fence.\n for (const block of allBlocks) {\n applyAsciiDiagramData(block, diagnostics);\n applyTimelineData(block, diagnostics);\n applyTreeData(block, diagnostics);\n }\n\n // Content-aware template auto-pick (default on): unannotated heading\n // blocks whose body carries a strong signal get the matching template\n // plus inputs derived from that body. Strict derivation — when the\n // essential input can't be built (e.g. feature without an image src),\n // the block keeps the structural default.\n if ((options?.autoTemplates ?? true) && !frontmatterDisablesAutoTemplates(markdownDoc)) {\n applyAutoTemplates(rootBlocks, resolveTemplateName(defaultTemplate), { featureIndex: 0 });\n }\n\n // Timeline parsing is intentionally tolerant and can retain unresolved\n // branch declarations as warnings. Surface those after auto-template\n // selection so both explicit and auto-derived timeline blocks participate.\n for (const block of allBlocks) collectTimelineWarnings(block, diagnostics);\n\n // Duplicate ids make connections and navigation ambiguous. Generated\n // slugs are already deduped; this catches author-pinned `{#id}` clashes.\n const seenIds = new Map<string, Block>();\n for (const block of allBlocks) {\n if (seenIds.has(block.id)) {\n diagnostics.push({\n severity: 'error',\n code: 'duplicate-id',\n message: `Duplicate block id \"${block.id}\" — later connections and links are ambiguous`,\n blockId: block.id,\n ...lineOf(block),\n });\n } else {\n seenIds.set(block.id, block);\n }\n }\n\n // connectsTo targets must resolve to a block id in this doc.\n for (const block of allBlocks) {\n for (const conn of block.connectsTo ?? []) {\n if (!seenIds.has(conn.target)) {\n diagnostics.push({\n severity: 'warning',\n code: 'unresolved-connection',\n message: `Block \"${block.id}\" connects to unknown target \"${conn.target}\"`,\n blockId: block.id,\n ...lineOf(block),\n });\n }\n }\n }\n\n // Calculate reading-time-based durations and generate captions\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 // Skip blocks that pinned an explicit duration via a heading attribute —\n // author intent wins over reading-time heuristics.\n for (const block of allBlocks) {\n if (pinnedMeta(block).duration != null) continue;\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 // Blocks with an explicit `startTime` attribute keep their pinned value;\n // the running cursor still advances by their duration so following blocks\n // sequence after them.\n let currentTime = 0;\n for (const block of allBlocks) {\n const explicitStart = pinnedMeta(block).startTime;\n if (explicitStart == null) {\n block.startTime = currentTime;\n }\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 // `generatedAt` is only stamped when the caller provides a timestamp —\n // conversion itself never reads the clock, so identical markdown always\n // converts to an identical Doc.\n const captions: CaptionTrack | undefined =\n phrases.length > 0\n ? {\n phrases,\n ...(options?.captionsGeneratedAt ? { generatedAt: options.captionsGeneratedAt } : {}),\n version: 1,\n }\n : undefined;\n\n const customTemplates = readCustomTemplatesFromFrontmatter(markdownDoc.frontmatter);\n const customThemes = readCustomThemesFromFrontmatter(markdownDoc.frontmatter);\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 ...(customTemplates ? { customTemplates } : {}),\n ...(customThemes ? { customThemes } : {}),\n ...(diagnostics.length > 0 ? { diagnostics } : {}),\n ...(documentMedia.length > 0 ? { documentMedia } : {}),\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 * Flatten the block tree into the list of *independently renderable*\n * blocks — like {@link flattenBlocks}, but it does NOT descend into the\n * children of a container template (`diagram`, `drawing`; see\n * `isContainerTemplate`). Those children are consumed by the parent's\n * render (as nodes / shapes), so they must not also surface as their own\n * slides or sections.\n *\n * Use this anywhere a doc is flattened for rendering (slideshow, video,\n * static pages). Use {@link flattenBlocks} when you genuinely need every\n * block regardless of role — validation, timing, duplicate-id checks.\n */\nexport function flattenRenderableBlocks(blocks: Block[]): Block[] {\n const result: Block[] = [];\n for (const block of blocks) {\n result.push(block);\n if (block.children && !isContainerTemplate(block.template)) {\n result.push(...flattenRenderableBlocks(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/** Source line of a block's heading, when position info is available. */\nfunction lineOf(block: Block): { line: number } | Record<string, never> {\n const line = block.sourceHeading?.position?.start.line;\n return line != null ? { line } : {};\n}\n\n/**\n * Populate `block.templateData` from structured body content:\n * 1. Every ```json data / ```yaml data fence in the body merges its parsed\n * object in (later fences override earlier keys).\n * 2. For `dataTable` blocks, the first GFM table supplies headers/rows/align\n * unless the author already provided them via a fence or `{[…]}` params.\n * Parse failures are recorded on `diagnostics` and skip the fence.\n */\nfunction applyStructuredData(block: Block, diagnostics: DocDiagnostic[]): void {\n let data: Record<string, unknown> | undefined;\n\n for (const node of block.contents ?? []) {\n if (node.type !== 'code' || !isDataFence(node)) continue;\n const result = parseDataFence(node);\n if (result.error) {\n diagnostics.push({\n severity: 'error',\n code: 'data-fence-parse',\n message: `Data fence in block \"${block.id}\": ${result.error}`,\n blockId: block.id,\n ...(node.position ? { line: node.position.start.line } : lineOf(block)),\n });\n continue;\n }\n data = { ...data, ...result.data };\n }\n\n if (block.template === 'dataTable') {\n const provided = (key: string) =>\n (data && key in data) || (block.templateOverrides && key in block.templateOverrides);\n if (!provided('headers') && !provided('rows')) {\n const table = findFirstTable(block.contents);\n if (table) {\n data = { ...extractTableData(table), ...data };\n }\n }\n }\n\n if (data && Object.keys(data).length > 0) {\n block.templateData = data;\n }\n}\n\n/**\n * Fill `templateData.nodes`/`edges` for an explicitly `{[diagram]}`-annotated\n * block whose body is exactly one eligible ASCII-art fence. Runs without the\n * detection threshold (explicit annotation = author intent), unconditionally\n * of the autoTemplates switches. The fence stays in `contents`, untouched.\n */\nfunction applyAsciiDiagramData(block: Block, diagnostics: DocDiagnostic[]): void {\n if (resolveTemplateName(block.template ?? '') !== 'diagram') return;\n if (block.children && block.children.length > 0) return; // native children win\n if (block.templateData && 'nodes' in block.templateData) return; // author data wins\n const fences = (block.contents ?? []).filter((n): n is MarkdownCodeBlock => n.type === 'code');\n if (fences.length !== 1 || !isEligibleAsciiFenceLang(fences[0].lang)) return;\n const parsed = parseAsciiDiagram(fences[0].value);\n if (parsed.nodes.length === 0) {\n diagnostics.push({\n severity: 'warning',\n code: 'ascii-diagram-parse',\n message: `Diagram block \"${block.id}\": code fence did not parse as an ASCII diagram`,\n blockId: block.id,\n });\n return;\n }\n const { nodes, edges } = asciiDiagramToTemplateData(parsed);\n block.templateData = { nodes, edges, ...block.templateData };\n}\n\n/**\n * Fill `templateData.items` for an explicitly `{[tree]}`-annotated block\n * whose body is one eligible ASCII tree fence (or a nested list). Runs\n * without the detection threshold (explicit annotation = author intent).\n */\nfunction applyTreeData(block: Block, diagnostics: DocDiagnostic[]): void {\n if (resolveTemplateName(block.template ?? '') !== 'tree') return;\n if (block.templateData && 'items' in block.templateData) return; // author data wins\n const derived = deriveTemplateInputs('tree', block.title ?? '', block.contents);\n if (!derived || !Array.isArray(derived.items) || derived.items.length === 0) {\n diagnostics.push({\n severity: 'warning',\n code: 'tree-parse',\n message: `Tree block \"${block.id}\": body did not parse as a tree`,\n blockId: block.id,\n });\n return;\n }\n block.templateData = { ...derived, ...block.templateData };\n}\n\n/**\n * Fill `templateData.tracks`/`links` for an explicitly `{[timeline]}`-\n * annotated block whose body is one eligible ASCII timeline fence.\n */\nfunction applyTimelineData(block: Block, diagnostics: DocDiagnostic[]): void {\n if (resolveTemplateName(block.template ?? '') !== 'timeline') return;\n if (block.templateData && 'tracks' in block.templateData) return; // author data wins\n const derived = deriveTemplateInputs('timeline', block.title ?? '', block.contents);\n if (!derived || !Array.isArray(derived.tracks) || derived.tracks.length === 0) {\n diagnostics.push({\n severity: 'warning',\n code: 'timeline-parse',\n message: `Timeline block \"${block.id}\": body did not parse as an ASCII timeline`,\n blockId: block.id,\n });\n return;\n }\n block.templateData = { ...derived, ...block.templateData };\n}\n\nfunction collectTimelineWarnings(block: Block, diagnostics: DocDiagnostic[]): void {\n if (resolveTemplateName(block.template ?? '') !== 'timeline') return;\n if (!block.templateData || !('tracks' in block.templateData)) return;\n const fences = (block.contents ?? []).filter(\n (node): node is MarkdownCodeBlock =>\n node.type === 'code' && isEligibleAsciiTimelineFenceLang(node.lang),\n );\n if (fences.length !== 1) return;\n for (const warning of parseAsciiTimeline(fences[0].value).warnings) {\n const unresolved = /^unresolved-link\\((.+)\\)$/.exec(warning);\n diagnostics.push({\n severity: 'warning',\n code: unresolved ? 'timeline-unresolved-link' : 'timeline-parse-warning',\n message: unresolved\n ? `Timeline block \"${block.id}\": unresolved branch ${unresolved[1]}`\n : `Timeline block \"${block.id}\": ${warning}`,\n blockId: block.id,\n });\n }\n}\n\n/** Truthiness of the `squisq-auto-templates` frontmatter kill-switch. */\nfunction frontmatterDisablesAutoTemplates(markdownDoc: MarkdownDocument): boolean {\n const v = markdownDoc.frontmatter?.['squisq-auto-templates'];\n return v === false || v === 'false' || v === 'off' || v === 'no' || v === 0;\n}\n\n/**\n * Walk heading blocks and apply content-aware templates to the ones that\n * still hold the structural default. Children of container templates\n * (diagram/drawing/layout) are consumed by their parent and never\n * re-templated. `state.featureIndex` alternates left/right feature\n * composition across the document.\n */\nfunction applyAutoTemplates(\n blocks: Block[],\n resolvedDefault: string,\n state: { featureIndex: number },\n): void {\n for (const block of blocks) {\n const annotated = !!block.sourceHeading?.templateAnnotation?.template;\n if (block.sourceHeading && !annotated && block.template === resolvedDefault) {\n const profile = profileBlockContents(block.contents ?? []);\n const picked = pickAutoTemplate(profile, state.featureIndex);\n if (picked) {\n const inputs = deriveTemplateInputs(picked, block.title ?? '', block.contents);\n if (inputs) {\n if (picked === 'leftFeature' || picked === 'rightFeature') state.featureIndex += 1;\n block.template = picked;\n block.autoTemplate = true;\n // Author-provided structured data (```json data fences) wins\n // over derived inputs.\n block.templateData = { ...inputs, ...block.templateData };\n }\n }\n }\n if (block.children && block.children.length > 0 && !isContainerTemplate(block.template)) {\n applyAutoTemplates(block.children, resolvedDefault, state);\n }\n }\n}\n\n/**\n * Extract the plain text from a block's body contents (excluding heading text).\n *\n * Exported because the narration script builder and the narration timing\n * resolver must derive the *same* spoken text per block that captions and\n * reading-time use — one source of truth for \"what does this block say\".\n */\nexport function getBlockBodyText(block: Block): string {\n if (!block.contents || block.contents.length === 0) return '';\n // A fence consumed as diagram data must not feed reading-time/captions —\n // 20 lines of box-drawing art would add ~30s of duration and captions\n // that \"read\" border runs aloud.\n const tmpl = resolveTemplateName(block.template ?? '');\n const consumedFence =\n (tmpl === 'diagram' && block.templateData !== undefined && 'nodes' in block.templateData) ||\n (tmpl === 'timeline' && block.templateData !== undefined && 'tracks' in block.templateData) ||\n (tmpl === 'tree' && block.templateData !== undefined && 'items' in block.templateData);\n // Join with newlines to preserve paragraph/list-item boundaries.\n // splitIntoPhrases uses these newlines as natural split points.\n return block.contents\n .filter((node) => !(consumedFence && node.type === 'code'))\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\ninterface ImageRef {\n url: string;\n alt?: string;\n}\n\n/**\n * Walk a parsed HTML sub-tree depth-first for an `<img>` with a `src`.\n * Used to surface images that the WYSIWYG editor serialized as raw HTML\n * (e.g. when an image was resized — markdown's `` shorthand\n * has no width syntax, so resized images round-trip as `<img src width>`).\n */\nfunction findFirstHtmlImage(nodes: HtmlNode[]): ImageRef | undefined {\n for (const node of nodes) {\n if (node.type !== 'htmlElement') continue;\n if (node.tagName === 'img' && node.attributes.src) {\n return { url: node.attributes.src, alt: node.attributes.alt };\n }\n const nested = findFirstHtmlImage(node.children);\n if (nested) return nested;\n }\n return undefined;\n}\n\n/**\n * Walk a MarkdownNode tree depth-first to find the first image reference,\n * whether expressed as a markdown image node or a raw HTML `<img>` tag.\n */\nfunction findFirstImage(node: MarkdownNode): ImageRef | undefined {\n if (node.type === 'image') {\n const img = node as { url: string; alt?: string };\n return { url: img.url, alt: img.alt };\n }\n if (node.type === 'htmlBlock' || node.type === 'htmlInline') {\n const html = node as { htmlChildren?: HtmlNode[] };\n if (html.htmlChildren) {\n const found = findFirstHtmlImage(html.htmlChildren);\n if (found) return found;\n }\n }\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 * Deterministic English-oriented syllable estimation.\n *\n * Approximation limits (accepted by design): ±1 on roughly 15% of\n * English words; systematically wrong on loanwords (\"cafe\", \"naive\"),\n * some vowel-hiatus words (\"create\", \"quiet\"), and non-English text.\n * Every consumer tolerates per-word error — the pacing controller\n * smooths rates and anchors on cumulative sums, and the aligner pays\n * symmetric insert/delete costs — so the estimator only needs to be\n * unbiased on average. Exact outputs are part of the deterministic\n * contract (tests pin a corpus table).\n */\n\nimport { estimateSpokenWordCount } from '../timing/narrationTiming.js';\n\n/** Same boundary-punctuation strip as `countSpokenWords`. */\nconst BOUNDARY_PUNCT = /^[.,!?;:'\"()[\\]{}]+|[.,!?;:'\"()[\\]{}]+$/g;\n\n/** Average syllables per spoken word-equivalent when expanding numbers. */\nconst SYLLABLES_PER_SPOKEN_WORD = 1.4;\n\n/**\n * Estimate the syllable count of a single whitespace-delimited token.\n * Always ≥ 1 for non-empty tokens.\n */\nexport function estimateSyllables(token: string): number {\n const stripped = token.replace(BOUNDARY_PUNCT, '');\n if (!stripped) return 1;\n\n // Numeric tokens: expand via the spoken-word estimator (\"1910\" →\n // \"nineteen ten\" ≈ 2 spoken words × 1.3 × 1.4 ≈ 4 syllables).\n if (/^[-+]?[\\d.,]+$/.test(stripped)) {\n const num = parseFloat(stripped.replace(/,/g, ''));\n if (!Number.isNaN(num) && Number.isFinite(num)) {\n return Math.max(1, Math.round(estimateSpokenWordCount(stripped) * SYLLABLES_PER_SPOKEN_WORD));\n }\n }\n\n // Vowel-less all-caps runs read as initialisms letter by letter\n // (\"HTML\" → aitch-tee-em-el ≈ 4). \"NASA\" has vowels and falls through.\n if (/^[A-Z]{2,5}$/.test(stripped) && !/[AEIOUY]/.test(stripped)) {\n return stripped.length;\n }\n\n // Hyphenated/slashed compounds: sum the parts (\"beam-splitter\" → 3).\n const parts = stripped\n .toLowerCase()\n .split(/[^a-z']+/)\n .filter((p) => p.length > 0);\n if (parts.length === 0) return 1;\n let total = 0;\n for (const part of parts) {\n total += countAlphaSyllables(part.replace(/'/g, ''));\n }\n return Math.max(1, total);\n}\n\n/** Vowel-group heuristic over a lowercase alphabetic word. */\nfunction countAlphaSyllables(word: string): number {\n if (!word) return 0;\n const groups = word.match(/[aeiouy]+/g);\n let count = groups ? groups.length : 0;\n if (count === 0) return 1;\n\n if (count > 1 && /[^aeiouy]e$/.test(word)) {\n // Terminal silent e: \"table\", \"whale\", \"give\".\n count -= 1;\n }\n if (count > 1 && /[^aeiouy]ed$/.test(word) && !/[td]ed$/.test(word)) {\n // Past-tense -ed is silent after most consonants (\"walked\"),\n // syllabic after t/d (\"wanted\", \"loaded\").\n count -= 1;\n }\n if (count > 1 && /[^aeiouy]es$/.test(word) && !/(?:[sxz]|[cs]h)es$/.test(word)) {\n // Plural -es is silent after most consonants (\"makes\"), syllabic\n // after sibilants (\"boxes\", \"riches\").\n count -= 1;\n }\n if (/[^aeiouy]le$/.test(word)) {\n // Syllabic -le after a consonant: \"table\", \"little\" — restores the\n // syllable the silent-e rule removed. Vowel + \"le\" (\"whale\") skips.\n count += 1;\n }\n return Math.max(1, count);\n}\n","/**\n * Teleprompter script model: a Doc flattened into an ordered word-token\n * stream with per-block ranges.\n *\n * `sourceText` is the canonical narration text — it is stored verbatim\n * in the timing sidecar, and every token/block `charOffset` indexes into\n * it. Determinism matters: the same Doc always builds a byte-identical\n * script, because sidecar↔doc matching later compares slices of this\n * exact string.\n */\n\nimport type { Block, Doc } from '../schemas/Doc.js';\nimport { flattenRenderableBlocks, getBlockBodyText } from '../doc/markdownToDoc.js';\nimport { estimateSpokenWordCount } from '../timing/narrationTiming.js';\nimport { estimateSyllables } from './syllables.js';\nimport type { NarrationScript, ScriptBlockRange, ScriptToken, WordTiming } from './types.js';\n\nexport interface BuildScriptOptions {\n /** Include block headings as spoken text (readers usually speak them). Default true. */\n includeTitles?: boolean;\n /** Separator joining block texts inside `sourceText`. Default '\\n\\n'. */\n blockSeparator?: string;\n}\n\n/** Spoken text of one block: optional title line + body plain text. */\nfunction blockSpokenText(block: Block, includeTitles: boolean): string {\n const title = includeTitles && block.title ? block.title.trim() : '';\n const body = getBlockBodyText(block);\n if (title && body) return `${title}\\n${body}`;\n return title || body;\n}\n\n/**\n * Build the narration script for a doc. Blocks with no spoken text\n * (pure-media sections, container-template children) contribute no\n * tokens and no block range.\n */\nexport function buildNarrationScript(doc: Doc, options?: BuildScriptOptions): NarrationScript {\n const includeTitles = options?.includeTitles ?? true;\n const separator = options?.blockSeparator ?? '\\n\\n';\n\n const pieces: Array<{ blockId: string; heading?: string; text: string }> = [];\n for (const block of flattenRenderableBlocks(doc.blocks)) {\n const text = blockSpokenText(block, includeTitles);\n if (!text) continue;\n pieces.push({\n blockId: block.id,\n heading: block.title || undefined,\n text,\n });\n }\n\n let sourceText = '';\n const blocks: ScriptBlockRange[] = [];\n for (let i = 0; i < pieces.length; i++) {\n if (i > 0) sourceText += separator;\n const charStart = sourceText.length;\n sourceText += pieces[i].text;\n blocks.push({\n blockId: pieces[i].blockId,\n ...(pieces[i].heading !== undefined ? { heading: pieces[i].heading } : {}),\n tokenStart: 0,\n tokenEnd: 0,\n charStart,\n charEnd: sourceText.length,\n });\n }\n\n // Tokenize with a single left-to-right scan so charOffsets are exact.\n const tokens: ScriptToken[] = [];\n const tokenRe = /\\S+/g;\n let blockIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = tokenRe.exec(sourceText)) !== null) {\n const charOffset = match.index;\n const charEnd = charOffset + match[0].length;\n while (blockIndex < blocks.length - 1 && charOffset >= blocks[blockIndex].charEnd) {\n blockIndex++;\n }\n // A token with no letters or digits (a standalone em-dash, bullet, …)\n // is punctuation, not a word: it displays but is never spoken.\n const spoken = hasSpokenContent(match[0]);\n tokens.push({\n text: match[0],\n charOffset,\n charEnd,\n blockId: blocks[blockIndex]?.blockId ?? '',\n blockIndex,\n syllables: spoken ? estimateSyllables(match[0]) : 0,\n spokenWordEquiv: spoken ? estimateSpokenWordCount(stripBoundaryPunct(match[0])) : 0,\n pauseAfter: 0,\n spoken,\n });\n }\n\n // Token ranges per block.\n for (const range of blocks) {\n range.tokenStart = tokens.length;\n range.tokenEnd = 0;\n }\n for (let i = 0; i < tokens.length; i++) {\n const range = blocks[tokens[i].blockIndex];\n if (range) {\n if (i < range.tokenStart) range.tokenStart = i;\n range.tokenEnd = i + 1;\n }\n }\n for (const range of blocks) {\n if (range.tokenStart > range.tokenEnd) {\n // No tokens landed in this range (cannot happen for non-empty text,\n // but keep the invariant tokenStart ≤ tokenEnd).\n range.tokenStart = range.tokenEnd;\n }\n }\n\n // Pause classes: block boundary > paragraph break > clause punctuation.\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n const next = tokens[i + 1];\n if (!next || next.blockIndex !== token.blockIndex) {\n token.pauseAfter = 3;\n } else if (sourceText.slice(token.charEnd, next.charOffset).includes('\\n')) {\n // getBlockBodyText joins paragraphs/list items with a single '\\n',\n // so ANY newline in the inter-token gap is a paragraph-class pause.\n token.pauseAfter = 2;\n } else if (endsWithClausePunctuation(token.text)) {\n token.pauseAfter = 1;\n }\n }\n\n const cumulativeSyllables = new Array<number>(tokens.length + 1);\n cumulativeSyllables[0] = 0;\n for (let i = 0; i < tokens.length; i++) {\n cumulativeSyllables[i + 1] = cumulativeSyllables[i] + tokens[i].syllables;\n }\n\n return {\n sourceText,\n tokens,\n blocks,\n totalSyllables: cumulativeSyllables[tokens.length],\n cumulativeSyllables,\n };\n}\n\nconst TRAILING_CLOSERS = /[\"')\\]}»”’]+$/;\n\n/** True when a token carries at least one letter or digit (i.e. is spoken). */\nfunction hasSpokenContent(token: string): boolean {\n return /[\\p{L}\\p{N}]/u.test(token);\n}\n\nfunction stripBoundaryPunct(token: string): string {\n return token.replace(/^[.,!?;:'\"()[\\]{}]+|[.,!?;:'\"()[\\]{}]+$/g, '');\n}\n\n/** Clause/sentence punctuation at the token's end (closing quotes/brackets tolerated). */\nfunction endsWithClausePunctuation(token: string): boolean {\n const bare = token.replace(TRAILING_CLOSERS, '');\n const last = bare.charAt(bare.length - 1);\n if (!last) return false;\n if (last === ',') {\n // Digit-grouping commas never end a token (a trailing comma has no\n // following digit), so any terminal comma is a real pause.\n return true;\n }\n return last === '.' || last === ';' || last === ':' || last === '!' || last === '?';\n}\n\n/** Clamp helper shared by the query functions. */\nfunction clamp(value: number, min: number, max: number): number {\n return value < min ? min : value > max ? max : value;\n}\n\n/**\n * Expected cumulative syllables at a (fractional) word position —\n * linear interpolation over the prefix sums.\n */\nexport function expectedSyllablesAt(script: NarrationScript, wordPos: number): number {\n const n = script.tokens.length;\n if (n === 0) return 0;\n const pos = clamp(wordPos, 0, n);\n const idx = Math.floor(pos);\n if (idx >= n) return script.totalSyllables;\n return script.cumulativeSyllables[idx] + (pos - idx) * script.tokens[idx].syllables;\n}\n\n/**\n * Inverse of {@link expectedSyllablesAt}: the fractional word position at\n * which the script reaches `syllables` cumulative syllables. Used by the\n * pacing controller's hard resync.\n */\nexport function wordPosAtExpectedSyllables(script: NarrationScript, syllables: number): number {\n const n = script.tokens.length;\n if (n === 0) return 0;\n const target = clamp(syllables, 0, script.totalSyllables);\n // Binary search: last index with cumulativeSyllables[idx] <= target.\n let lo = 0;\n let hi = n;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (script.cumulativeSyllables[mid] <= target) lo = mid;\n else hi = mid - 1;\n }\n if (lo >= n) return n;\n const within = target - script.cumulativeSyllables[lo];\n const sylls = script.tokens[lo].syllables;\n return lo + (sylls > 0 ? within / sylls : 0);\n}\n\n/** Index of the token containing (or following) a char offset into sourceText. */\nexport function wordIndexAtChar(script: NarrationScript, charOffset: number): number {\n const tokens = script.tokens;\n if (tokens.length === 0) return 0;\n let lo = 0;\n let hi = tokens.length - 1;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (tokens[mid].charEnd <= charOffset) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n/**\n * Index of the active word at a playback time, given aligned word\n * timings — the last word whose `tSec` ≤ `tSec` (or 0 before the first).\n */\nexport function wordIndexAtTime(words: WordTiming[], tSec: number): number {\n if (words.length === 0) return 0;\n let lo = 0;\n let hi = words.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (words[mid].tSec <= tSec) lo = mid;\n else hi = mid - 1;\n }\n return words[lo].tSec <= tSec ? lo : 0;\n}\n","/**\n * Narration timing sidecar v3 — the extended `<audio>.timing.json`.\n *\n * v1 (the recorder's original shape) is `{ sourceText, duration,\n * bookmarks }` with bookmarks always empty. v3 fills the bookmarks with\n * real per-word timings from the aligner and adds contiguous per-block\n * ranges. `version: 2` is already taken by the consolidated root\n * `timing.json` (`{ version: 2, sections }`), hence v3.\n *\n * Compatibility contract (tested in both directions): v3 is a strict\n * superset of v1, so the legacy `parseTimingJson` gate (requires\n * `sourceText` + `duration`, ignores unknown keys) keeps accepting v3\n * files; {@link parseNarrationTimingJson} accepts v1 files and returns\n * them with empty `blocks`.\n */\n\nimport type { AudioBookmark } from '../schemas/Doc.js';\nimport type { NarrationAlignment, NarrationScript } from './types.js';\n\n/** Narration time range of one doc block at record time. */\nexport interface NarrationTimingBlock {\n /** Doc block id at record time (primary match key; ids can drift on heading edits). */\n blockId?: string;\n /** Block heading at record time (human-readable + fuzzy match key). */\n heading?: string;\n /** Index in renderable-block order at record time. */\n blockIndex: number;\n /** Char range into `sourceText` — the durable content key. */\n charStart: number;\n charEnd: number;\n startSec: number;\n /** Contiguous with the next block's startSec (aligner invariant). */\n endSec: number;\n}\n\nexport interface NarrationTimingJsonV3 {\n version: 3;\n /** EXACTLY the NarrationScript.sourceText of the take. */\n sourceText: string;\n /** Take length in seconds (decoded-PCM length, not the recorder clock). */\n duration: number;\n /** Per-word timings: { id: `word-${i}`, time, charOffset, textFragment }. */\n bookmarks: AudioBookmark[];\n blocks: NarrationTimingBlock[];\n /** Start skew of the companion camera recording, when one exists. */\n cameraOffsetSec?: number;\n /** Provenance of the timing data. */\n generator?: { name: string; method: 'dsp-align'; baseWpm?: number };\n}\n\nexport interface BuildNarrationTimingOptions {\n cameraOffsetSec?: number;\n baseWpm?: number;\n}\n\n/** Build the v3 sidecar payload from a script + its alignment. Pure. */\nexport function buildNarrationTimingJson(\n script: NarrationScript,\n alignment: NarrationAlignment,\n durationSec: number,\n options?: BuildNarrationTimingOptions,\n): NarrationTimingJsonV3 {\n const bookmarks: AudioBookmark[] = alignment.words.map((word) => {\n const token = script.tokens[word.tokenIndex];\n return {\n id: `word-${word.tokenIndex}`,\n time: word.tSec,\n charOffset: token?.charOffset ?? 0,\n textFragment: token?.text ?? '',\n };\n });\n const blocks: NarrationTimingBlock[] = alignment.blocks.map((range) => ({\n ...(range.blockId ? { blockId: range.blockId } : {}),\n ...(range.heading !== undefined ? { heading: range.heading } : {}),\n blockIndex: range.blockIndex,\n charStart: range.charStart,\n charEnd: range.charEnd,\n startSec: range.startSec,\n endSec: range.endSec,\n }));\n return {\n version: 3,\n sourceText: script.sourceText,\n duration: Number.isFinite(durationSec) && durationSec >= 0 ? durationSec : 0,\n bookmarks,\n blocks,\n ...(options?.cameraOffsetSec !== undefined ? { cameraOffsetSec: options.cameraOffsetSec } : {}),\n generator: {\n name: 'squisq-teleprompter',\n method: 'dsp-align',\n ...(options?.baseWpm !== undefined ? { baseWpm: options.baseWpm } : {}),\n },\n };\n}\n\nfunction finiteNonNegative(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n\n/**\n * Tolerant parse: accepts v3, and v1 (`{ sourceText, duration,\n * bookmarks? }`) which comes back with empty `blocks`. Returns null for\n * malformed payloads. Blocks are sorted and clamped monotonic\n * defensively (hand-edited sidecars).\n */\nexport function parseNarrationTimingJson(\n data: ArrayBuffer | Uint8Array | string,\n): NarrationTimingJsonV3 | null {\n try {\n const text =\n typeof data === 'string'\n ? data\n : new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));\n const parsed: unknown = JSON.parse(text);\n if (typeof parsed !== 'object' || parsed === null) return null;\n const raw = parsed as Record<string, unknown>;\n if (typeof raw.sourceText !== 'string' || !finiteNonNegative(raw.duration)) return null;\n\n const bookmarks: AudioBookmark[] = Array.isArray(raw.bookmarks)\n ? (raw.bookmarks as unknown[]).flatMap((b): AudioBookmark[] => {\n if (typeof b !== 'object' || b === null) return [];\n const bookmark = b as Record<string, unknown>;\n if (!finiteNonNegative(bookmark.time) || !finiteNonNegative(bookmark.charOffset)) {\n return [];\n }\n return [\n {\n id: typeof bookmark.id === 'string' ? bookmark.id : `bookmark-${bookmark.charOffset}`,\n time: bookmark.time,\n charOffset: bookmark.charOffset,\n ...(typeof bookmark.textFragment === 'string'\n ? { textFragment: bookmark.textFragment }\n : {}),\n },\n ];\n })\n : [];\n\n let blocks: NarrationTimingBlock[] = Array.isArray(raw.blocks)\n ? (raw.blocks as unknown[]).flatMap((b): NarrationTimingBlock[] => {\n if (typeof b !== 'object' || b === null) return [];\n const block = b as Record<string, unknown>;\n if (\n !finiteNonNegative(block.startSec) ||\n !finiteNonNegative(block.endSec) ||\n !finiteNonNegative(block.charStart) ||\n !finiteNonNegative(block.charEnd)\n ) {\n return [];\n }\n return [\n {\n ...(typeof block.blockId === 'string' ? { blockId: block.blockId } : {}),\n ...(typeof block.heading === 'string' ? { heading: block.heading } : {}),\n blockIndex: finiteNonNegative(block.blockIndex) ? block.blockIndex : 0,\n charStart: block.charStart,\n charEnd: block.charEnd,\n startSec: block.startSec,\n endSec: Math.max(block.startSec, block.endSec),\n },\n ];\n })\n : [];\n\n blocks = blocks.sort((a, b) => a.startSec - b.startSec);\n let cursor = 0;\n for (const block of blocks) {\n if (block.startSec < cursor) block.startSec = cursor;\n if (block.endSec < block.startSec) block.endSec = block.startSec;\n cursor = block.startSec;\n }\n\n return {\n version: 3,\n sourceText: raw.sourceText,\n duration: raw.duration,\n bookmarks,\n blocks,\n ...(finiteNonNegative(raw.cameraOffsetSec) ? { cameraOffsetSec: raw.cameraOffsetSec } : {}),\n ...(typeof raw.generator === 'object' && raw.generator !== null\n ? { generator: raw.generator as NarrationTimingJsonV3['generator'] }\n : {}),\n };\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":["DEFAULT_OPTS","PADDING","numParam","strParam","bodyText","round","emptyHint","clamp01","slugify","bodyText","normalizeCandidates","applyBlockMeta","bodyText","getBlockBodyText","getBlockBodyText","clamp"]}
|