@bendyline/squisq 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +63 -10
  2. package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
  3. package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
  4. package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
  5. package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
  6. package/dist/chunk-3E5F2XMR.js.map +1 -0
  7. package/dist/chunk-4X3JQXNM.js +35 -0
  8. package/dist/chunk-4X3JQXNM.js.map +1 -0
  9. package/dist/{chunk-P3K7NLHF.js → chunk-5DKBFXPY.js} +31 -121
  10. package/dist/chunk-5DKBFXPY.js.map +1 -0
  11. package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
  12. package/dist/chunk-5J4HKRJF.js.map +1 -0
  13. package/dist/chunk-5UYI3RJB.js +2503 -0
  14. package/dist/chunk-5UYI3RJB.js.map +1 -0
  15. package/dist/{chunk-BEQODJWV.js → chunk-66QO7XFB.js} +11 -291
  16. package/dist/chunk-66QO7XFB.js.map +1 -0
  17. package/dist/{chunk-KKNUBQ6Y.js → chunk-6PJRB2CF.js} +156 -91
  18. package/dist/chunk-6PJRB2CF.js.map +1 -0
  19. package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
  20. package/dist/chunk-AMIR72JP.js.map +1 -0
  21. package/dist/chunk-FVJUUTEM.js +74 -0
  22. package/dist/chunk-FVJUUTEM.js.map +1 -0
  23. package/dist/{chunk-5TYS5V3G.js → chunk-GF3BVNLU.js} +4127 -3538
  24. package/dist/chunk-GF3BVNLU.js.map +1 -0
  25. package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
  26. package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
  27. package/dist/chunk-JOQYPRDZ.js +127 -0
  28. package/dist/chunk-JOQYPRDZ.js.map +1 -0
  29. package/dist/{chunk-A4O7GIWE.js → chunk-LYNJEOAC.js} +10 -73
  30. package/dist/chunk-LYNJEOAC.js.map +1 -0
  31. package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
  32. package/dist/chunk-PXLVXTLW.js.map +1 -0
  33. package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
  34. package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
  35. package/dist/{chunk-T5UK6YOB.js → chunk-QTSJOY54.js} +60 -17
  36. package/dist/chunk-QTSJOY54.js.map +1 -0
  37. package/dist/chunk-QVANWDPH.js +2358 -0
  38. package/dist/chunk-QVANWDPH.js.map +1 -0
  39. package/dist/{chunk-GPLTCSXO.js → chunk-R2GC6RLD.js} +7 -7
  40. package/dist/chunk-R2GC6RLD.js.map +1 -0
  41. package/dist/chunk-R2YZTCLO.js +292 -0
  42. package/dist/chunk-R2YZTCLO.js.map +1 -0
  43. package/dist/chunk-S7A5D7ZJ.js +174 -0
  44. package/dist/chunk-S7A5D7ZJ.js.map +1 -0
  45. package/dist/chunk-T3TI7GSZ.js +884 -0
  46. package/dist/chunk-T3TI7GSZ.js.map +1 -0
  47. package/dist/{chunk-LTN6I7QW.js → chunk-TUWMK62B.js} +55 -4
  48. package/dist/chunk-TUWMK62B.js.map +1 -0
  49. package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
  50. package/dist/chunk-VR7UPJ7C.js.map +1 -0
  51. package/dist/doc/index.d.ts +2334 -5
  52. package/dist/doc/index.js +127 -33
  53. package/dist/generate/index.d.ts +7 -2
  54. package/dist/generate/index.js +1 -1
  55. package/dist/imageEdit/index.d.ts +9 -6
  56. package/dist/imageEdit/index.js +3 -3
  57. package/dist/index.d.ts +12 -10
  58. package/dist/index.js +246 -80
  59. package/dist/jsonForm/index.d.ts +7 -3
  60. package/dist/jsonForm/index.js +9 -4
  61. package/dist/markdown/index.d.ts +6 -70
  62. package/dist/markdown/index.js +13 -9
  63. package/dist/narration/index.d.ts +618 -0
  64. package/dist/narration/index.js +82 -0
  65. package/dist/recommend/index.d.ts +15 -1
  66. package/dist/recommend/index.js +2 -2
  67. package/dist/schemas/index.d.ts +28 -6
  68. package/dist/schemas/index.js +15 -13
  69. package/dist/spatial/index.d.ts +0 -1
  70. package/dist/spatial/index.js +1 -1
  71. package/dist/storage/index.js +1 -1
  72. package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
  73. package/dist/timing/index.js +5 -3
  74. package/dist/transform/index.d.ts +35 -24
  75. package/dist/transform/index.js +9 -10
  76. package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
  77. package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
  78. package/dist/versions/index.d.ts +2 -1
  79. package/dist/versions/index.js +2 -2
  80. package/package.json +6 -6
  81. package/src/__tests__/applyNarrationTiming.test.ts +190 -0
  82. package/src/__tests__/applyRenderStyle.test.ts +3 -3
  83. package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
  84. package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
  85. package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
  86. package/src/__tests__/asciiDiagramParse.test.ts +233 -0
  87. package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
  88. package/src/__tests__/asciiDiagramRender.test.ts +162 -0
  89. package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
  90. package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
  91. package/src/__tests__/asciiTimelineParse.test.ts +205 -0
  92. package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
  93. package/src/__tests__/asciiTimelineRender.test.ts +376 -0
  94. package/src/__tests__/attrTokens.test.ts +5 -0
  95. package/src/__tests__/contentContainer.test.ts +43 -0
  96. package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
  97. package/src/__tests__/dataTable.test.ts +25 -15
  98. package/src/__tests__/diagramBlock.test.ts +3 -3
  99. package/src/__tests__/diagramText.test.ts +26 -0
  100. package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
  101. package/src/__tests__/drawingBlock.test.ts +3 -3
  102. package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
  103. package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
  104. package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
  105. package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
  106. package/src/__tests__/getLayers.test.ts +32 -18
  107. package/src/__tests__/getLayersFallback.test.ts +8 -8
  108. package/src/__tests__/imageEditVersions.test.ts +2 -0
  109. package/src/__tests__/jsonForm.pointer.test.ts +47 -1
  110. package/src/__tests__/layoutBlock.test.ts +3 -3
  111. package/src/__tests__/majorApiTypes.test.ts +18 -0
  112. package/src/__tests__/markdown.test.ts +41 -0
  113. package/src/__tests__/matchFontFamily.test.ts +114 -0
  114. package/src/__tests__/materializeBlockLayers.test.ts +135 -0
  115. package/src/__tests__/materializeTestUtils.ts +17 -0
  116. package/src/__tests__/narrationAlign.test.ts +150 -0
  117. package/src/__tests__/narrationFeatures.test.ts +71 -0
  118. package/src/__tests__/narrationNuclei.test.ts +45 -0
  119. package/src/__tests__/narrationPacing.test.ts +189 -0
  120. package/src/__tests__/narrationScript.test.ts +149 -0
  121. package/src/__tests__/narrationSessionRepro.test.ts +62 -0
  122. package/src/__tests__/narrationSidecar.test.ts +88 -0
  123. package/src/__tests__/narrationSyllables.test.ts +65 -0
  124. package/src/__tests__/narrationTestSignals.ts +167 -0
  125. package/src/__tests__/narrationVad.test.ts +66 -0
  126. package/src/__tests__/resolveDocTheme.test.ts +16 -2
  127. package/src/__tests__/rootExports.test.ts +18 -0
  128. package/src/__tests__/scopedContentContainer.test.ts +20 -0
  129. package/src/__tests__/shapeGeometry.test.ts +12 -0
  130. package/src/__tests__/templateAnnotationParse.test.ts +10 -0
  131. package/src/__tests__/templateInputs.test.ts +69 -0
  132. package/src/__tests__/templateMetadata.test.ts +2 -1
  133. package/src/__tests__/templates.test.ts +143 -17
  134. package/src/__tests__/themeCompile.test.ts +49 -22
  135. package/src/__tests__/transformProvenance.test.ts +160 -0
  136. package/src/__tests__/transformV2.test.ts +40 -14
  137. package/src/__tests__/treeviewBattle.test.ts +76 -0
  138. package/src/__tests__/treeviewDetect.test.ts +168 -0
  139. package/src/__tests__/treeviewParse.test.ts +118 -0
  140. package/src/__tests__/treeviewPipeline.test.ts +183 -0
  141. package/src/__tests__/treeviewRender.test.ts +91 -0
  142. package/src/__tests__/versions.test.ts +44 -0
  143. package/src/doc/applyNarrationTiming.ts +244 -0
  144. package/src/doc/asciiDiagram/chars.ts +210 -0
  145. package/src/doc/asciiDiagram/detect.ts +175 -0
  146. package/src/doc/asciiDiagram/index.ts +38 -0
  147. package/src/doc/asciiDiagram/mapping.ts +225 -0
  148. package/src/doc/asciiDiagram/parse.ts +1095 -0
  149. package/src/doc/asciiDiagram/render.ts +963 -0
  150. package/src/doc/asciiDiagram/repair.ts +400 -0
  151. package/src/doc/asciiDiagram/types.ts +65 -0
  152. package/src/doc/asciiTimeline/detect.ts +138 -0
  153. package/src/doc/asciiTimeline/index.ts +26 -0
  154. package/src/doc/asciiTimeline/mapping.ts +43 -0
  155. package/src/doc/asciiTimeline/parse.ts +870 -0
  156. package/src/doc/asciiTimeline/render.ts +427 -0
  157. package/src/doc/asciiTimeline/types.ts +73 -0
  158. package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
  159. package/src/doc/audioMapping.ts +60 -46
  160. package/src/doc/customTemplatesFrontmatter.ts +0 -41
  161. package/src/doc/docToMarkdown.ts +70 -2
  162. package/src/doc/index.ts +76 -4
  163. package/src/doc/markdownToDoc.ts +135 -1
  164. package/src/doc/materializeBlockLayers.ts +304 -0
  165. package/src/doc/mediaAnnotations.ts +20 -0
  166. package/src/doc/resolveDocTheme.ts +8 -7
  167. package/src/doc/templateInputs.ts +185 -2
  168. package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
  169. package/src/doc/templates/diagramBlock.ts +237 -38
  170. package/src/doc/templates/fallbackBlock.ts +1 -1
  171. package/src/doc/templates/index.ts +134 -279
  172. package/src/doc/templates/inputDescriptors.ts +20 -1
  173. package/src/doc/templates/metadata.ts +10 -0
  174. package/src/doc/templates/persistentLayers.ts +12 -126
  175. package/src/doc/templates/registry.ts +88 -0
  176. package/src/doc/templates/templateNames.ts +22 -0
  177. package/src/doc/templates/timelineBlock.ts +613 -0
  178. package/src/doc/templates/treeBlock.ts +131 -0
  179. package/src/doc/treeview/chars.ts +72 -0
  180. package/src/doc/treeview/detect.ts +145 -0
  181. package/src/doc/treeview/index.ts +30 -0
  182. package/src/doc/treeview/mapping.ts +95 -0
  183. package/src/doc/treeview/parse.ts +201 -0
  184. package/src/doc/treeview/render.ts +41 -0
  185. package/src/doc/treeview/types.ts +43 -0
  186. package/src/doc/utils/applyRenderStyle.ts +2 -9
  187. package/src/doc/utils/diagramText.ts +78 -0
  188. package/src/doc/utils/shapeGeometry.ts +67 -5
  189. package/src/doc/validate.ts +1 -1
  190. package/src/generate/templateMapper.ts +7 -0
  191. package/src/imageEdit/export.ts +6 -5
  192. package/src/imageEdit/versionPaths.ts +13 -26
  193. package/src/imageEdit/versions.ts +21 -100
  194. package/src/index.ts +1 -0
  195. package/src/internal/immutable.ts +58 -0
  196. package/src/jsonForm/index.ts +9 -1
  197. package/src/jsonForm/pointer.ts +68 -23
  198. package/src/markdown/attrTokens.ts +7 -5
  199. package/src/markdown/index.ts +1 -0
  200. package/src/markdown/stringify.ts +4 -9
  201. package/src/markdown/utils.ts +36 -14
  202. package/src/narration/align.ts +514 -0
  203. package/src/narration/features.ts +231 -0
  204. package/src/narration/index.ts +86 -0
  205. package/src/narration/nuclei.ts +118 -0
  206. package/src/narration/pacing.ts +211 -0
  207. package/src/narration/script.ts +239 -0
  208. package/src/narration/session.ts +100 -0
  209. package/src/narration/sidecar.ts +187 -0
  210. package/src/narration/syllables.ts +85 -0
  211. package/src/narration/trace.ts +50 -0
  212. package/src/narration/types.ts +299 -0
  213. package/src/narration/vad.ts +131 -0
  214. package/src/recommend/numberHighlight.ts +25 -0
  215. package/src/recommend/templates.ts +108 -12
  216. package/src/schemas/BlockTemplates.ts +156 -7
  217. package/src/schemas/Doc.ts +72 -9
  218. package/src/schemas/Media.ts +12 -2
  219. package/src/schemas/Theme.ts +45 -25
  220. package/src/schemas/Viewport.ts +2 -2
  221. package/src/schemas/fontStacks.ts +79 -0
  222. package/src/schemas/themeCompile.ts +15 -0
  223. package/src/schemas/themeConstants.ts +2 -0
  224. package/src/schemas/themeLibrary.ts +25 -19
  225. package/src/schemas/themeValidator.ts +1 -1
  226. package/src/spatial/Geohash.ts +0 -3
  227. package/src/storage/ContentContainer.ts +17 -9
  228. package/src/storage/ScopedContentContainer.ts +45 -15
  229. package/src/transform/applyTransform.ts +5 -5
  230. package/src/transform/index.ts +3 -1
  231. package/src/transform/registry.ts +169 -49
  232. package/src/transform/templateSelector.ts +21 -2
  233. package/src/transform/timingAllocator.ts +152 -21
  234. package/src/transform/types.ts +14 -1
  235. package/src/versions/gitignore.ts +34 -0
  236. package/src/versions/index.ts +2 -0
  237. package/src/versions/operations.ts +18 -104
  238. package/src/versions/paths.ts +13 -28
  239. package/src/versions/snapshotStore.ts +202 -0
  240. package/src/versions/types.ts +3 -1
  241. package/dist/chunk-5TYS5V3G.js.map +0 -1
  242. package/dist/chunk-A4O7GIWE.js.map +0 -1
  243. package/dist/chunk-BEQODJWV.js.map +0 -1
  244. package/dist/chunk-DLXZMS5K.js.map +0 -1
  245. package/dist/chunk-GPLTCSXO.js.map +0 -1
  246. package/dist/chunk-HWVFJAAH.js.map +0 -1
  247. package/dist/chunk-IMSCRLLV.js.map +0 -1
  248. package/dist/chunk-JELIRVDP.js +0 -24
  249. package/dist/chunk-JELIRVDP.js.map +0 -1
  250. package/dist/chunk-KKNUBQ6Y.js.map +0 -1
  251. package/dist/chunk-LDQ2HJIX.js.map +0 -1
  252. package/dist/chunk-LTN6I7QW.js.map +0 -1
  253. package/dist/chunk-P3K7NLHF.js.map +0 -1
  254. package/dist/chunk-T5UK6YOB.js.map +0 -1
  255. package/dist/chunk-UY7KGQ5R.js +0 -192
  256. package/dist/chunk-UY7KGQ5R.js.map +0 -1
  257. package/dist/chunk-VLJJHDAC.js +0 -218
  258. package/dist/chunk-VLJJHDAC.js.map +0 -1
  259. package/dist/chunk-VWUFZ6ZG.js.map +0 -1
  260. package/dist/story/index.d.ts +0 -1801
  261. package/dist/story/index.js +0 -279
  262. package/src/doc/getLayers.ts +0 -195
  263. /package/dist/{story → narration}/index.js.map +0 -0
@@ -1,5 +1,2334 @@
1
- export { AccentLayout, AudioSegmentTiming, BASE_INPUT_DESCRIPTORS, CONTAINER_TEMPLATES, ClipBox, ConnectorPort, ConnectorRouting, ConnectorSnapPoint, CoverBlockInput, DEFAULT_LAYOUT, DataFenceParseResult, DeriveTemplateInputsOptions, DiagramEdge, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DocStylePreset, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, ExpandDocBlocksOptions, ExtractedTableData, FirstImage, InputCoercion, LayoutLayerDefaults, LayoutLayersResult, MarkdownToDocOptions, MarkdownValidationResult, PATH_SHAPE_KINDS, RenderContext, RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_ALIASES, TEMPLATE_INPUT_DESCRIPTORS, TEMPLATE_METADATA, TemplateInputDescriptor, TemplateMetadata, TemplateParamFinding, ValidateOptions, adjustY, applyRenderStyleToLayers, buildRegistry, clipEndpoints, clipPoint, coerceTemplateParams, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, decodeLayersFromFrontmatter, definitionCard, deriveTemplateInputs, diagramBlock, docToMarkdown, drawingBlock, encodeLayersForFrontmatter, expandCoverBlock, expandDocBlocks, expandPersistentLayers, expandTemplateBlock, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstTable, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getDocStyleConfig, getLayers, getOverlayOpacity, getPersistentLayersFromTheme, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isContainerTemplate, isDataFence, isShapeName, layoutBlock, leftFeature, lineStyleDasharray, lintTemplateParams, listBlock, mapBlock, markdownToDoc, markerPath, nearestSnapPoint, normalizeShapeKind, parseDataFence, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, replaceDataFence, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, snapEndpoints, snapPoints, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, titleBlock, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter } from '../story/index.js';
2
- export { D as DEFAULT_THEME, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from '../themeLibrary-CehcJhzz.js';
3
- export { z as DocBlock, G as FRONTMATTER_CUSTOM_TEMPLATES_KEY, H as FRONTMATTER_CUSTOM_THEMES_KEY, U as LayoutHints, a5 as PersistentLayerConfig, af as RenderStyle, at as TemplateBlock, au as TemplateContext, az as Theme, aA as ThemeColorPalette, aB as ThemeColorScheme, aE as ThemeStyle, aF as ThemeTypography, aJ as VIEWPORT_PRESETS, aN as ViewportConfig, aO as ViewportOrientation, aP as ViewportPreset, aU as createTemplateContext, a_ as getLayoutHints, b2 as getTwoColumnPositions, b3 as getViewport, b4 as getViewportOrientation, b6 as isTemplateBlock, bb as scaledFontSize } from '../Doc-BBVGq1_9.js';
4
- import '../types-DlAZ7MW4.js';
5
- import '../ContentContainer-BXUlIf18.js';
1
+ import { aw as TemplateBlock, ax as TemplateContext, V as Layer, p as CustomTemplateDefinition, az as TemplateRegistry, aC as Theme, a_ as ViewportConfig, a8 as PersistentLayerConfig, G as DocBlock, a7 as PersistentLayer, aO as TitleBlockInput, al as SectionHeaderInput, ar as StatHighlightInput, ag as QuoteBlockInput, L as FactCardInput, aV as TwoColumnInput, u as DateEventInput, T as ImageWithCaptionInput, Y as LeftFeatureInput, aj as RightFeatureInput, $ as MapBlockInput, aq as StartBlockConfig, O as FullBleedQuoteInput, _ as ListBlockInput, ac as PhotoGridInput, w as DefinitionCardInput, n as ComparisonBarInput, af as PullQuoteInput, aZ as VideoWithCaptionInput, aY as VideoPullQuoteInput, t as DataTableInput, x as DiagramBlockInput, aQ as TreeBlockInput, aK as TimelineBlockInput, B as Block, I as DrawingBlockInput, a3 as MarkerStyle, A as AccentImage, S as ImageTreatment, a as AccentPosition, c as Animation, d as AnimationType, aE as ThemeColorScheme, F as Doc, aF as ThemeRegistry, H as DocDiagnostic, E as DiagramTemplateNode, z as DiagramTemplateEdge, aN as TimelineTemplateTrack, aM as TimelineTemplateLink } from '../Doc-ylqWKDc_.js';
2
+ export { J as FRONTMATTER_CUSTOM_TEMPLATES_KEY, K as FRONTMATTER_CUSTOM_THEMES_KEY, X as LayoutHints, ai as RenderStyle, aD as ThemeColorPalette, aI as ThemeStyle, aJ as ThemeTypography, aW as VIEWPORT_PRESETS, a$ as ViewportOrientation, b0 as ViewportPreset, b5 as createTemplateContext, bc as getLayoutHints, bf as getTwoColumnPositions, bg as getViewport, bh as getViewportOrientation, bj as isTemplateBlock, bm as scaledFontSize } from '../Doc-ylqWKDc_.js';
3
+ import { I as MarkdownNode, $ as TransitionType, _ as TransitionDirection, M as MarkdownBlockNode, q as MarkdownHeading, m as MarkdownDocument, P as MarkdownTable, h as MarkdownCodeBlock, C as MarkdownList } from '../types-BwMPl2CB.js';
4
+ import { C as CoercedBlockMeta } from '../annotationCoercion-Dr_DY9Hx.js';
5
+ import { C as ContentContainer } from '../ContentContainer-BXUlIf18.js';
6
+ export { D as DEFAULT_THEME, g as getAvailableThemes, b as getThemeSummaries, r as resolveTheme } from '../themeLibrary-RjVgLpUi.js';
7
+
8
+ /** Runtime registry composition for built-in and document-scoped templates. */
9
+
10
+ /** Built-in templates keyed by the ids used in document annotations. */
11
+ declare const templateRegistry: TemplateRegistry;
12
+ /** Broad runtime view used after a template name has selected its function. */
13
+ type RuntimeTemplateRegistry = Record<string, (input: TemplateBlock, context: TemplateContext) => Layer[]>;
14
+ /** Merge document-scoped templates without mutating the built-in registry. */
15
+ declare function buildRegistry(custom?: readonly CustomTemplateDefinition[]): RuntimeTemplateRegistry;
16
+
17
+ /**
18
+ * Canonical block-to-layer materialization contract.
19
+ *
20
+ * Timeline scheduling and UI components both delegate here so template
21
+ * lookup, custom templates, ownership, render style, persistent layers,
22
+ * failure policy, and diagnostics cannot drift by render mode.
23
+ */
24
+
25
+ /** How a failed template render is represented in the returned layer graph. */
26
+ type LayerMaterializationFailureMode = 'fallback' | 'empty';
27
+ /** A structured, inspectable explanation for a template render failure. */
28
+ type LayerMaterializationDiagnostic = {
29
+ code: 'unknown-template';
30
+ template: string;
31
+ message: string;
32
+ } | {
33
+ code: 'invalid-template-result';
34
+ template: string;
35
+ message: string;
36
+ receivedType: string;
37
+ } | {
38
+ code: 'template-error';
39
+ template: string;
40
+ message: string;
41
+ cause: unknown;
42
+ };
43
+ /** Identifies which path produced a materialized layer graph. */
44
+ type LayerMaterializationSource = 'authored' | 'template' | 'fallback' | 'empty';
45
+ /**
46
+ * Complete result from {@link materializeBlockLayers}. Failures are data, not
47
+ * console side effects: callers can display, report, or ignore the diagnostic.
48
+ */
49
+ interface BlockLayerMaterialization {
50
+ layers: Layer[];
51
+ source: LayerMaterializationSource;
52
+ diagnostic?: LayerMaterializationDiagnostic;
53
+ }
54
+ /**
55
+ * The single public context for turning a block into renderable layers.
56
+ *
57
+ * Theme persistent layers are inherited by default. Pass
58
+ * `persistentLayers: false` to opt out, or a config to replace the theme's
59
+ * persistent layers wholesale.
60
+ */
61
+ interface MaterializeBlockLayersOptions {
62
+ /** Theme used by templates and render-style post-processing. */
63
+ theme?: Theme;
64
+ /** Target viewport. Defaults to the landscape preset. */
65
+ viewport?: ViewportConfig;
66
+ /** Theme inheritance override for persistent layers. */
67
+ persistentLayers?: PersistentLayerConfig | false;
68
+ /** Zero-based position in the flattened render sequence. */
69
+ blockIndex?: number;
70
+ /** Number of blocks in the flattened render sequence. */
71
+ totalBlocks?: number;
72
+ /** Document-scoped custom templates; built-ins win name collisions. */
73
+ customTemplates?: readonly CustomTemplateDefinition[];
74
+ /** Failed templates render a visible fallback by default. */
75
+ failureMode?: LayerMaterializationFailureMode;
76
+ }
77
+ /**
78
+ * Turn any doc block into an owned, render-ready layer graph.
79
+ *
80
+ * This is the only recommended public materialization entry point.
81
+ */
82
+ declare function materializeBlockLayers(block: DocBlock, options?: MaterializeBlockLayersOptions): BlockLayerMaterialization;
83
+
84
+ /**
85
+ * Canonical, framework-free UI metadata for every built-in block template.
86
+ *
87
+ * This is the single source of truth for the human-readable label and the
88
+ * one-sentence description of each template id in {@link templateRegistry}.
89
+ * The editor's `TemplatePicker` renders its gallery from this map (joining
90
+ * each id with a locally-defined SVG icon, which can't live in this
91
+ * framework-free package), so a template only has to be added here and to
92
+ * `templateRegistry` for it to surface in the editor.
93
+ *
94
+ * `templateMetadata.test.ts` asserts this map and `templateRegistry` stay
95
+ * exactly 1:1 — adding a template to one without the other fails the build.
96
+ *
97
+ * Order matters: pickers iterate this object's insertion order, so it doubles
98
+ * as the canonical gallery order.
99
+ */
100
+ interface TemplateMetadata {
101
+ /** Human-readable label shown in pickers (e.g. "Image with Caption"). */
102
+ label: string;
103
+ /** One-sentence description of when to reach for this template. */
104
+ description: string;
105
+ }
106
+ declare const TEMPLATE_METADATA: Record<string, TemplateMetadata>;
107
+
108
+ /** Resolve a historical template id to its canonical registry key. */
109
+ declare function resolveTemplateName(name: string): string;
110
+ /** Templates that consume their child headings rather than rendering them. */
111
+ declare const CONTAINER_TEMPLATES: ReadonlySet<string>;
112
+ /** True when `name` (or its alias) consumes child blocks. */
113
+ declare function isContainerTemplate(name: string | undefined): boolean;
114
+
115
+ /**
116
+ * Persistent Layers Expansion
117
+ *
118
+ * Expands persistent layer templates (solid backgrounds, gradients, overlays)
119
+ * into raw Layer arrays. These layers are injected into each block based on
120
+ * per-block flags (useBottomLayer, useTopLayer).
121
+ *
122
+ * This is shared code used by both site and efb-app doc renderers.
123
+ *
124
+ * Related Files:
125
+ * - schemas/BlockTemplates.ts - PersistentLayerConfig types
126
+ */
127
+
128
+ /**
129
+ * Expand all persistent layers in a config to raw Layer arrays.
130
+ */
131
+ declare function expandPersistentLayers(layers: PersistentLayer[] | undefined, theme?: Theme): Layer[];
132
+ /**
133
+ * Get persistent layers from a Theme. Returns the theme's baked-in
134
+ * persistentLayers config, or an empty config when the theme has none.
135
+ */
136
+ declare function getPersistentLayersFromTheme(theme: Theme): PersistentLayerConfig;
137
+ /**
138
+ * Resolve the effective persistent-layer config for a doc: the doc's own
139
+ * config wins **wholesale** when present; only docs with no persistent
140
+ * layers inherit the theme's.
141
+ *
142
+ * Doc-wins-wholesale (rather than merging) protects pre-baked documents
143
+ * that carry their own background/branding layers — merging a theme's
144
+ * atmosphere on top of those would double up backgrounds and stack
145
+ * overlays the doc author never saw.
146
+ */
147
+ declare function resolvePersistentLayers(doc: {
148
+ persistentLayers?: PersistentLayerConfig;
149
+ }, theme: Theme): PersistentLayerConfig | undefined;
150
+ /**
151
+ * Compose a block's layers between pre-expanded persistent bottom/top
152
+ * layers, honoring the per-block `useBottomLayer` / `useTopLayer` opt-outs.
153
+ * Shared persistent-layer primitive used by `materializeBlockLayers`.
154
+ */
155
+ declare function wrapWithPersistentLayers(layers: Layer[], block: {
156
+ useBottomLayer?: boolean;
157
+ useTopLayer?: boolean;
158
+ }, bottomLayers: Layer[], topLayers: Layer[]): Layer[];
159
+
160
+ /**
161
+ * Title Block Template
162
+ *
163
+ * Large title with optional subtitle for doc intros.
164
+ * Centered text with fade-in animations, composed as one lockup:
165
+ * accent rule, title, and subtitle are spaced from the title's
166
+ * estimated height instead of fixed slots that collide on wrap.
167
+ * Adapts font sizes and positioning for different viewports.
168
+ *
169
+ * This is shared code used by both site and efb-app doc renderers.
170
+ */
171
+
172
+ declare function titleBlock(input: TitleBlockInput, context: TemplateContext): Layer[];
173
+
174
+ /**
175
+ * Section Header Template
176
+ *
177
+ * Section title card with optional background image.
178
+ * Used to introduce new sections of a story.
179
+ * When an image is provided, displays like a title slide with the image as background.
180
+ * Without an image, falls back to a colored background.
181
+ *
182
+ * This is shared code used by both site and efb-app doc renderers.
183
+ */
184
+
185
+ declare function sectionHeader(input: SectionHeaderInput, context: TemplateContext): Layer[];
186
+
187
+ /**
188
+ * Stat Highlight Template
189
+ *
190
+ * Large statistic/number with description and optional detail.
191
+ * Great for emphasizing key data points.
192
+ * Adapts font sizes and positioning for different viewports.
193
+ *
194
+ * Supports optional accent images that appear as tasteful side/bottom strips.
195
+ *
196
+ * This is shared code used by both site and efb-app doc renderers.
197
+ */
198
+
199
+ declare function statHighlight(input: StatHighlightInput, context: TemplateContext): Layer[];
200
+
201
+ /**
202
+ * Quote Block Template
203
+ *
204
+ * Large centered quote with optional attribution, composed as one
205
+ * vertically-centered lockup: the attribution hangs a fixed distance
206
+ * below the quote's estimated bottom edge instead of being pinned to a
207
+ * far-away layout slot.
208
+ * Adapts font sizes and positioning for different viewports.
209
+ *
210
+ * Supports optional accent images that appear as tasteful side/bottom strips.
211
+ *
212
+ * This is shared code used by both site and efb-app doc renderers.
213
+ */
214
+
215
+ declare function quoteBlock(input: QuoteBlockInput, context: TemplateContext): Layer[];
216
+
217
+ /**
218
+ * Fact Card Template
219
+ *
220
+ * Key fact with explanation and optional source, composed as one
221
+ * vertically-centered lockup: each element is placed relative to the
222
+ * estimated height of the one above it, so short content doesn't leave
223
+ * fixed-slot voids and long content doesn't collide.
224
+ * Adapts font sizes and positioning for different viewports.
225
+ *
226
+ * Supports optional accent images that appear as tasteful side/bottom strips.
227
+ *
228
+ * This is shared code used by both site and efb-app doc renderers.
229
+ */
230
+
231
+ declare function factCard(input: FactCardInput, context: TemplateContext): Layer[];
232
+
233
+ /**
234
+ * Two Column Template
235
+ *
236
+ * Side-by-side comparison of two items.
237
+ * Each column has a label and optional sublabel.
238
+ * Adapts font sizes and positioning for different viewports.
239
+ *
240
+ * Portrait mode: Stacks columns vertically (top/bottom) instead of side-by-side.
241
+ *
242
+ * This is shared code used by both site and efb-app doc renderers.
243
+ */
244
+
245
+ declare function twoColumn(input: TwoColumnInput, context: TemplateContext): Layer[];
246
+
247
+ /**
248
+ * Date Event Template
249
+ *
250
+ * Timeline-style slide with prominent date and description.
251
+ * Supports different moods: neutral, somber, celebratory.
252
+ * Adapts font sizes and positioning for different viewports.
253
+ *
254
+ * Supports optional accent images that appear as tasteful side/bottom strips.
255
+ *
256
+ * This is shared code used by both site and efb-app doc renderers.
257
+ */
258
+
259
+ declare function dateEvent(input: DateEventInput, context: TemplateContext): Layer[];
260
+
261
+ /**
262
+ * Image With Caption Template
263
+ *
264
+ * Full-screen background image with text overlay.
265
+ * Supports Ken Burns animation effects (zoom, pan).
266
+ * Adapts caption positioning and font sizes for different viewports.
267
+ *
268
+ * This is shared code used by both site and efb-app doc renderers.
269
+ */
270
+
271
+ declare function imageWithCaption(input: ImageWithCaptionInput, context: TemplateContext): Layer[];
272
+
273
+ /**
274
+ * Feature Block Templates — `leftFeature` and `rightFeature`
275
+ *
276
+ * Pairs a "feature" image on one side of the block with a title + body
277
+ * paragraph on the other. The two templates are mirror images, so the
278
+ * actual layer-builder lives here once and the per-side template files
279
+ * just call it with a `side` parameter.
280
+ *
281
+ * Used for editorial layouts like product highlights, profile cards,
282
+ * and section intros where a single image deserves to sit next to a
283
+ * short text block rather than behind it (which is what
284
+ * `imageWithCaption` does).
285
+ */
286
+
287
+ declare function leftFeature(input: LeftFeatureInput, context: TemplateContext): Layer[];
288
+ declare function rightFeature(input: RightFeatureInput, context: TemplateContext): Layer[];
289
+
290
+ /**
291
+ * Map Block Template
292
+ *
293
+ * Full-screen geographic map with optional title and caption overlays.
294
+ * Great for establishing geographic context at the start of a doc
295
+ * or when discussing location-specific content.
296
+ * Adapts font sizes and positioning for different viewports.
297
+ *
298
+ * Map tiles are fetched from free/open-source providers.
299
+ * See docs/MAP_TILES.md for available styles and attribution requirements.
300
+ *
301
+ * This is shared code used by both site and efb-app doc renderers.
302
+ */
303
+
304
+ declare function mapBlock(input: MapBlockInput, context: TemplateContext): Layer[];
305
+
306
+ /**
307
+ * Cover Block Template
308
+ *
309
+ * Full-screen hero image with title overlay, shown before playback starts.
310
+ * This is the "poster for the doc, displaying the
311
+ * article's hero image with elegant title treatment.
312
+ *
313
+ * Features:
314
+ * - Full-screen hero image with Ken Burns ambient motion
315
+ * - Gradient overlay for text readability
316
+ * - Large centered title with optional subtitle
317
+ * - No animation delays (shown at rest, not during playback)
318
+ *
319
+ * This is shared code used by both site and efb-app doc renderers.
320
+ */
321
+
322
+ /**
323
+ * Input for coverBlock template - matches StartBlockConfig
324
+ */
325
+ interface CoverBlockInput {
326
+ /** Path to hero image (omit for theme-driven background) */
327
+ heroSrc?: string;
328
+ /** Alt text for the hero image */
329
+ heroAlt?: string;
330
+ /** Title to display over the hero */
331
+ title: string;
332
+ /** Optional subtitle */
333
+ subtitle?: string;
334
+ /** Ambient motion for the hero image */
335
+ ambientMotion?: 'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight';
336
+ /** Photo credit / artist name */
337
+ heroCredit?: string;
338
+ /** License identifier */
339
+ heroLicense?: string;
340
+ /** Per-block override for the theme's photographic image grade. */
341
+ imageTreatment?: 'none' | 'mono' | 'duotone' | 'warm' | 'cool';
342
+ }
343
+ /**
344
+ * Generate cover block layers from StartBlockConfig.
345
+ */
346
+ declare function coverBlock(input: CoverBlockInput, context: TemplateContext): Layer[];
347
+ /**
348
+ * Expand a StartBlockConfig into a renderable Block.
349
+ * This is used by the player to render the cover block at rest.
350
+ */
351
+ declare function expandCoverBlock(config: StartBlockConfig, context: TemplateContext): Layer[];
352
+
353
+ /**
354
+ * Full Bleed Quote Template
355
+ *
356
+ * Short dramatic text filling the viewport like a movie title card.
357
+ * Designed for punchy text under 60 characters. Uses massive font
358
+ * centered on a dark vignette background.
359
+ *
360
+ * This is shared code used by both site and efb-app doc renderers.
361
+ */
362
+
363
+ declare function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateContext): Layer[];
364
+
365
+ /**
366
+ * List Block Template
367
+ *
368
+ * Displays 3-5 items in a numbered vertical list with staggered animations.
369
+ * Good for enumerations like "things to see", "key features", or "tips".
370
+ * Supports optional accent images.
371
+ *
372
+ * This is shared code used by both site and efb-app doc renderers.
373
+ */
374
+
375
+ declare function listBlock(input: ListBlockInput, context: TemplateContext): Layer[];
376
+
377
+ /**
378
+ * Photo Grid Template
379
+ *
380
+ * Displays 2-4 images in a tiled layout for visual variety.
381
+ * Layout adapts based on image count and viewport orientation:
382
+ *
383
+ * Landscape:
384
+ * - 2 images: side-by-side 50/50
385
+ * - 3 images: one large left (60%) + two stacked right
386
+ * - 4 images: 2x2 grid
387
+ *
388
+ * Portrait (9:16): images stack horizontally (top/bottom) instead of
389
+ * side-by-side, giving each image full width on narrow screens.
390
+ *
391
+ * This is shared code used by both site and efb-app doc renderers.
392
+ */
393
+
394
+ declare function photoGrid(input: PhotoGridInput, context: TemplateContext): Layer[];
395
+
396
+ /**
397
+ * Definition Card Template
398
+ *
399
+ * Dictionary-style slide with a large term and its definition.
400
+ * Good for explaining local words, place names, or cultural concepts.
401
+ * Supports optional accent images.
402
+ *
403
+ * This is shared code used by both site and efb-app doc renderers.
404
+ */
405
+
406
+ declare function definitionCard(input: DefinitionCardInput, context: TemplateContext): Layer[];
407
+
408
+ /**
409
+ * Comparison Bar Template
410
+ *
411
+ * Two horizontal bars showing relative numeric values side by side.
412
+ * Bar widths are proportional to the values for immediate visual comparison.
413
+ * Good for population, distance, or measurement comparisons.
414
+ *
415
+ * This is shared code used by both site and efb-app doc renderers.
416
+ */
417
+
418
+ declare function comparisonBar(input: ComparisonBarInput, context: TemplateContext): Layer[];
419
+
420
+ /**
421
+ * Pull Quote Template
422
+ *
423
+ * Quote text over a full-bleed background image with dark overlay.
424
+ * Cinematic alternative to quoteBlock when a high-quality image is available.
425
+ * Combines the visual impact of imageWithCaption with the text focus of quoteBlock.
426
+ *
427
+ * This is shared code used by both site and efb-app doc renderers.
428
+ */
429
+
430
+ declare function pullQuote(input: PullQuoteInput, context: TemplateContext): Layer[];
431
+
432
+ /**
433
+ * Video With Caption Template
434
+ *
435
+ * Full-screen background video clip with text overlay. Mirrors the structure of
436
+ * imageWithCaption but uses a VideoLayer instead of an ImageLayer. The video
437
+ * plays muted — narration audio is the only sound track.
438
+ *
439
+ * Adapts caption positioning and font sizes for different viewports.
440
+ *
441
+ * This is shared code used by both site and efb-app doc renderers.
442
+ *
443
+ * Related Files:
444
+ * - shared/story/templates/imageWithCaption.ts — image equivalent
445
+ * - schemas/StoryScript.ts — VideoLayer type
446
+ * - site/src/components/story/layers/VideoLayer.tsx — rendering component
447
+ */
448
+
449
+ declare function videoWithCaption(input: VideoWithCaptionInput, context: TemplateContext): Layer[];
450
+
451
+ /**
452
+ * Video Pull Quote Template
453
+ *
454
+ * Quote text over a video clip background with dark overlay.
455
+ * Cinematic alternative to pullQuote when a video clip is available.
456
+ * Combines the visual dynamism of live video with the text focus of quoteBlock.
457
+ *
458
+ * The video plays muted — narration audio is the only sound track.
459
+ *
460
+ * This is shared code used by both site and efb-app doc renderers.
461
+ *
462
+ * Related Files:
463
+ * - shared/story/templates/pullQuote.ts — image-based equivalent
464
+ * - schemas/StoryScript.ts — VideoLayer type
465
+ * - site/src/components/story/layers/VideoLayer.tsx — rendering component
466
+ */
467
+
468
+ declare function videoPullQuote(input: VideoPullQuoteInput, context: TemplateContext): Layer[];
469
+
470
+ /**
471
+ * Data Table Template
472
+ *
473
+ * Renders a themed table with header row and data rows.
474
+ * Uses a TableLayer (foreignObject-based HTML table inside SVG)
475
+ * for proper table layout within the viewport.
476
+ *
477
+ * Adapts font sizes for different viewports and uses theme colors
478
+ * for header background, text, borders, and body cells.
479
+ */
480
+
481
+ declare function dataTable(input: DataTableInput, context: TemplateContext): Layer[];
482
+
483
+ /**
484
+ * Diagram block template.
485
+ *
486
+ * Renders a node-and-edge diagram from one of two data sources:
487
+ * 1. Child headings (`context.children`) — the legacy authored form; each
488
+ * child becomes a node positioned by `x`/`y` and connected by
489
+ * `connectsTo` (see `diagramLayout.ts` for auto-placement rules).
490
+ * 2. `input.nodes`/`input.edges` (usually via `templateData`) — the
491
+ * data-driven form derived from an ASCII-art diagram fence. Nodes may
492
+ * carry per-node sizes and a `container` reference; containers draw
493
+ * behind their children as translucent grouping cards.
494
+ *
495
+ * Layout coordinates are author-defined units. The template computes a
496
+ * bounding box of all nodes and scales it to fit the block's viewport
497
+ * with padding, so users don't have to think about absolute pixel ranges.
498
+ */
499
+
500
+ declare function diagramBlock(input: DiagramBlockInput, context: TemplateContext): Layer[];
501
+
502
+ /**
503
+ * Tree Template
504
+ *
505
+ * Renders a hierarchical filesystem-style treeview (folder/file icons +
506
+ * connector rails, collapsible in the live player) from an ASCII tree fence.
507
+ * Emits a single `TreeLayer` (foreignObject HTML, like `dataTable`) plus an
508
+ * optional title + themed background.
509
+ *
510
+ * Data source: `input.items` (a nested `TreeLayerItem[]`), populated from
511
+ * `templateData.items` which the pipeline derives from the tree fence.
512
+ */
513
+
514
+ declare function treeBlock(input: TreeBlockInput, context: TemplateContext): Layer[];
515
+
516
+ /**
517
+ * Timeline Template
518
+ *
519
+ * Renders one or more left-to-right tracks with positioned event markers,
520
+ * callout stems/text, and optional branch links. It deliberately composes
521
+ * existing shape/path/text layers so every current render/export surface can
522
+ * display timelines without a timeline-specific React layer.
523
+ */
524
+
525
+ declare function timelineBlock(input: TimelineBlockInput, context: TemplateContext): Layer[];
526
+
527
+ /**
528
+ * Diagram layout — shared between the read-only SVG render path
529
+ * (`diagramBlock` template) and the interactive editor (React Flow in
530
+ * `@bendyline/squisq-editor-react`). Same children + same options always
531
+ * produce the same node positions and edge list, so previews and the
532
+ * editor stay visually consistent.
533
+ *
534
+ * Layout rules:
535
+ * 1. Children with both `x` and `y` set keep their authored coordinates.
536
+ * 2. Children missing either coordinate are auto-placed in a square-ish
537
+ * grid in declaration order, offset below the bounding box of the
538
+ * explicitly-positioned children.
539
+ * 3. Edges come from each child's `connectsTo`. Targets that don't match
540
+ * any sibling id are dropped (and counted in `warnings`).
541
+ */
542
+
543
+ interface DiagramNodePosition {
544
+ /** Block id (matches `Block.id`). */
545
+ id: string;
546
+ /** Display label (block title or fallback to id). */
547
+ label: string;
548
+ /** Pixel x coordinate (canvas-relative). */
549
+ x: number;
550
+ /** Pixel y coordinate (canvas-relative). */
551
+ y: number;
552
+ /** True when the position came from `x=`/`y=` attributes; false when auto-laid out. */
553
+ pinned: boolean;
554
+ /** Optional `.class` tokens carried over from the heading. */
555
+ classes?: string[];
556
+ }
557
+ interface DiagramEdge {
558
+ /** Synthetic stable edge id. */
559
+ id: string;
560
+ /** Source node id. */
561
+ source: string;
562
+ /** Target node id. */
563
+ target: string;
564
+ /** Connection type from `connectsTo=target:type` (used as edge label). */
565
+ type?: string;
566
+ }
567
+ interface DiagramLayout {
568
+ nodes: DiagramNodePosition[];
569
+ edges: DiagramEdge[];
570
+ warnings: string[];
571
+ }
572
+ interface DiagramLayoutOptions {
573
+ /** Horizontal grid pitch between auto-laid-out nodes. Default: 260 (node width 180 + 80 air). */
574
+ gapX?: number;
575
+ /** Vertical grid pitch between auto-laid-out nodes. Default: 140. */
576
+ gapY?: number;
577
+ /** Padding around the explicit-positions bounding box before the grid starts. Default: 80. */
578
+ gridPad?: number;
579
+ /** Origin x for the grid when no explicit nodes anchor it. Default: 80. */
580
+ gridOriginX?: number;
581
+ /** Origin y for the grid when no explicit nodes anchor it. Default: 80. */
582
+ gridOriginY?: number;
583
+ }
584
+ /**
585
+ * Compute node positions and edges for a diagram from a parent block's
586
+ * children. Pure function — same inputs always produce the same output.
587
+ */
588
+ declare function computeDiagramLayout(children: readonly Block[], options?: DiagramLayoutOptions): DiagramLayout;
589
+
590
+ /**
591
+ * Drawing block template.
592
+ *
593
+ * Renders the parent block's children as free-form shapes on a canvas:
594
+ * - Each child becomes a shape (`rect`/`circle` → ShapeLayer, `line`/
595
+ * `arrow`/`path` → PathLayer, `text` → TextLayer) with its title as a
596
+ * centered label and its body text as an optional sublabel.
597
+ * - `line`/`arrow` children with `from`/`to` (and any child's
598
+ * `connectsTo`) become connectors clipped to the shapes they join.
599
+ *
600
+ * Coordinates from `x`/`y`/`width`/`height` are author-defined units; the
601
+ * template fits the bounding box of all shapes to the viewport with
602
+ * padding (same approach as `diagramBlock`), so authors don't think in
603
+ * absolute pixels.
604
+ */
605
+
606
+ declare function drawingBlock(input: DrawingBlockInput, context: TemplateContext): Layer[];
607
+
608
+ /**
609
+ * shapeGeometry — pure SVG geometry for the drawing/diagram shape vocabulary.
610
+ *
611
+ * Three concerns, all deterministic and dependency-free:
612
+ * - `shapePath(kind, x, y, w, h)` → an SVG path `d` for a named shape inscribed
613
+ * in a bounding box. Returns null for the natively-rendered primitives
614
+ * (rect / circle / line / text / path) so the caller can keep using a
615
+ * `ShapeLayer` for those; everything else becomes a computed `PathLayer`.
616
+ * - `markerPath(style, dir)` → the `<marker>` path for a line end-style, in the
617
+ * standard 0–10 marker viewBox (shared by the SSR `PathLayer` renderer and the
618
+ * editor's edge renderer).
619
+ * - `connectorPath(routing, start, end)` + `snapEndpoints(a, b)` → the line/edge
620
+ * geometry between two shapes (straight / orthogonal / curved), lifted from the
621
+ * diagram template so drawings and diagrams draw identical connectors. The older
622
+ * `clipEndpoints(a, b)` helper remains for free-angle clipping, but rendered
623
+ * connectors use snapped ports so authored lines land on stable attachment points.
624
+ */
625
+
626
+ /** Connector routing styles. */
627
+ type ConnectorRouting = 'straight' | 'orthogonal' | 'curved';
628
+ /**
629
+ * Shape kinds rendered as computed paths (everything except the primitives the
630
+ * renderer draws natively). Used by templates to decide ShapeLayer vs PathLayer.
631
+ */
632
+ declare const PATH_SHAPE_KINDS: Set<string>;
633
+ /**
634
+ * SVG path `d` for a named shape inscribed in `[x, y, w, h]`, or null when the
635
+ * kind is rendered natively (rect / circle / line / text / path / arrow).
636
+ */
637
+ declare function shapePath(kind: string, x: number, y: number, w: number, h: number): string | null;
638
+ /**
639
+ * The `<marker>` path for a line end-style, in the 0–10 marker viewBox.
640
+ * `dir` selects orientation (`end` points along +x; `start` is mirrored).
641
+ * Returns null for `'none'`. `filled` shapes paint with the stroke color;
642
+ * non-filled (`open`) draw as a stroked outline.
643
+ */
644
+ declare function markerPath(style: MarkerStyle, dir: 'start' | 'end'): {
645
+ d: string;
646
+ filled: boolean;
647
+ } | null;
648
+ interface ClipBox {
649
+ cx: number;
650
+ cy: number;
651
+ rx: number;
652
+ ry: number;
653
+ }
654
+ type ConnectorPort = 'top' | 'right' | 'bottom' | 'left' | 'top-left' | 'top-right' | 'bottom-right' | 'bottom-left';
655
+ interface ConnectorSnapPoint {
656
+ port: ConnectorPort;
657
+ x: number;
658
+ y: number;
659
+ }
660
+ interface ConnectorAnchor {
661
+ side: 'top' | 'right' | 'bottom' | 'left';
662
+ offset: number;
663
+ }
664
+ /** Intersection of the center-to-center line with `from`'s bounding box. */
665
+ declare function clipPoint(from: ClipBox, to: ClipBox): {
666
+ x: number;
667
+ y: number;
668
+ };
669
+ /** Clip both endpoints of an edge to the two shapes it joins. */
670
+ declare function clipEndpoints(a: ClipBox, b: ClipBox): {
671
+ start: {
672
+ x: number;
673
+ y: number;
674
+ };
675
+ end: {
676
+ x: number;
677
+ y: number;
678
+ };
679
+ };
680
+ /** The stable connector ports exposed around a shape/card box. */
681
+ declare function snapPoints(box: ClipBox): ConnectorSnapPoint[];
682
+ /** Resolve a normalized authored anchor to a concrete point on a box. */
683
+ declare function anchorPoint(box: ClipBox, anchor: ConnectorAnchor): ConnectorSnapPoint;
684
+ /** Nearest stable connector port on `box` to an arbitrary point. */
685
+ declare function nearestSnapPoint(box: ClipBox, point: {
686
+ x: number;
687
+ y: number;
688
+ }): ConnectorSnapPoint;
689
+ /**
690
+ * Pick the pair of connector ports, one on each box, with the shortest
691
+ * distance between them. This gives stable attachments to side/corner handles
692
+ * instead of arbitrary center-ray intersections.
693
+ */
694
+ declare function snapEndpoints(a: ClipBox, b: ClipBox): {
695
+ start: ConnectorSnapPoint;
696
+ end: ConnectorSnapPoint;
697
+ };
698
+ /** Build the SVG `d` for a connector between two clipped endpoints. */
699
+ declare function connectorPath(routing: ConnectorRouting, start: {
700
+ x: number;
701
+ y: number;
702
+ port?: ConnectorPort;
703
+ }, end: {
704
+ x: number;
705
+ y: number;
706
+ port?: ConnectorPort;
707
+ }): string;
708
+ /** Map a `lineStyle` (solid|dashed|dotted) to an SVG `stroke-dasharray`. */
709
+ declare function lineStyleDasharray(style: string | undefined): string | undefined;
710
+
711
+ /**
712
+ * Drawing layout — shared, pure derivation of shapes + connectors from a
713
+ * drawing block's child headings. Same children always produce the same
714
+ * shapes, so SSR previews, exports, and (eventually) the editor stay
715
+ * visually consistent. Mirrors `diagramLayout.ts` for the richer
716
+ * free-form shape vocabulary.
717
+ *
718
+ * Each child heading is one shape. Its `{[shape …]}` annotation names the
719
+ * primitive (`child.template`) and carries geometry/style as string params
720
+ * (`child.templateOverrides`); `child.id` makes it referenceable;
721
+ * `child.title` is the label.
722
+ *
723
+ * Layout rules (parallel to the diagram):
724
+ * 1. Shapes with both `x` and `y` keep their authored coordinates.
725
+ * 2. Shapes missing either are auto-placed in a square-ish grid below the
726
+ * bounding box of the explicitly-positioned shapes.
727
+ * 3. `line`/`arrow` shapes with `from`/`to` (or any shape's `connectsTo`)
728
+ * become connectors; endpoints that match no sibling id are dropped
729
+ * (and counted in `warnings`).
730
+ */
731
+
732
+ /**
733
+ * The shape kinds a drawing can render. `rect`/`circle`/`line` render as a
734
+ * native `ShapeLayer`; everything else (and `path`/`arrow`) renders as a
735
+ * computed `PathLayer` (see `shapeGeometry.ts`). `text` is a `TextLayer`.
736
+ */
737
+ type DrawingShapeKind = 'rect' | 'circle' | 'line' | 'arrow' | 'path' | 'text' | 'triangle' | 'right-triangle' | 'diamond' | 'pentagon' | 'hexagon' | 'octagon' | 'star' | 'star4' | 'star6' | 'parallelogram' | 'trapezoid' | 'plus' | 'chevron' | 'arrow-right' | 'arrow-left' | 'arrow-up' | 'arrow-down' | 'double-arrow' | 'callout' | 'cylinder' | 'cloud' | 'heart' | 'lightning';
738
+ /**
739
+ * Author-facing shape annotation names accepted on a drawing's children
740
+ * (the `{[…]}` token). Shared with validation so an unknown shape gets a
741
+ * "did you mean" suggestion. Aliases (`rectangle`→rect, `ellipse`→circle)
742
+ * are included.
743
+ */
744
+ declare const SHAPE_NAMES: readonly ["rectangle", "rect", "square", "circle", "ellipse", "oval", "line", "arrow", "path", "text", "triangle", "right-triangle", "diamond", "rhombus", "pentagon", "hexagon", "octagon", "star", "star4", "star6", "parallelogram", "trapezoid", "plus", "cross", "chevron", "arrow-right", "arrow-left", "arrow-up", "arrow-down", "double-arrow", "callout", "speech", "cylinder", "cloud", "heart", "lightning", "bolt"];
745
+ /**
746
+ * Resolve a child's `{[…]}` annotation name to a shape kind, or `null`
747
+ * when it isn't a shape. Case-insensitive.
748
+ */
749
+ declare function normalizeShapeKind(name: string | undefined): DrawingShapeKind | null;
750
+ /** True when `name` is an accepted shape annotation (any alias). */
751
+ declare function isShapeName(name: string | undefined): boolean;
752
+ /** A positioned shape in author-defined units (top-left origin). */
753
+ interface DrawingShape {
754
+ id: string;
755
+ kind: DrawingShapeKind;
756
+ x: number;
757
+ y: number;
758
+ width: number;
759
+ height: number;
760
+ /** True when position came from `x=`/`y=`; false when auto-laid out. */
761
+ pinned: boolean;
762
+ /** Heading text used as the shape's label ('' when none). */
763
+ label: string;
764
+ /** Body text under the heading, used as a sublabel (when present). */
765
+ sublabel?: string;
766
+ /** Text content for `text` shapes (`text=` param, else label, else body). */
767
+ text?: string;
768
+ /** Raw SVG path `d` for `path` shapes. */
769
+ d?: string;
770
+ fill?: string;
771
+ stroke?: string;
772
+ strokeWidth?: number;
773
+ borderRadius?: number;
774
+ dasharray?: string;
775
+ }
776
+ /** A connector joining two shapes by id. */
777
+ interface DrawingConnector {
778
+ id: string;
779
+ kind: 'line' | 'arrow';
780
+ /** Source shape id (resolved to an existing shape). */
781
+ from: string;
782
+ /** Target shape id (resolved to an existing shape). */
783
+ to: string;
784
+ /** Optional midpoint label (heading text, or `connectsTo` type). */
785
+ label?: string;
786
+ stroke?: string;
787
+ strokeWidth?: number;
788
+ dasharray?: string;
789
+ /** End-of-line markers (default: `arrow` kind → filled arrow at `to`). */
790
+ startMarker: MarkerStyle;
791
+ endMarker: MarkerStyle;
792
+ /** How the line is routed between the two shapes. Default: 'straight'. */
793
+ routing: ConnectorRouting;
794
+ }
795
+ interface DrawingLayout {
796
+ shapes: DrawingShape[];
797
+ connectors: DrawingConnector[];
798
+ warnings: string[];
799
+ }
800
+ interface DrawingLayoutOptions {
801
+ /** Horizontal spacing between auto-laid-out shapes. Default: 180. */
802
+ gapX?: number;
803
+ /** Vertical spacing between auto-laid-out shapes. Default: 140. */
804
+ gapY?: number;
805
+ /** Padding below the explicit bounding box before the grid starts. Default: 80. */
806
+ gridPad?: number;
807
+ /** Grid origin when no explicit shapes anchor it. Default: 80, 80. */
808
+ gridOriginX?: number;
809
+ gridOriginY?: number;
810
+ }
811
+ /**
812
+ * Compute shapes + connectors for a drawing from its parent block's
813
+ * children. Pure — same inputs always produce the same output.
814
+ */
815
+ declare function computeDrawingLayout(children: readonly Block[], options?: DrawingLayoutOptions): DrawingLayout;
816
+
817
+ /**
818
+ * Layout block template.
819
+ *
820
+ * Renders the parent block's children as free-form, **absolutely
821
+ * positioned** layers on a canvas (text boxes, shapes, images). Unlike
822
+ * `drawingBlock`, coordinates are used as-is — there is no fit-to-viewport
823
+ * scaling — because a layout is a fixed-canvas composition.
824
+ *
825
+ * Each child is one layer: `### {#id} {[<type> x=.. y=.. …]}`. A text box's
826
+ * content lives in its child body as markdown (see `computeLayoutLayers`).
827
+ * Children render in document order (first child = back-most layer).
828
+ */
829
+
830
+ declare function layoutBlock(input: TemplateBlock, context: TemplateContext): Layer[];
831
+
832
+ interface LayoutLayersResult {
833
+ layers: Layer[];
834
+ warnings: string[];
835
+ }
836
+ interface LayoutLayerDefaults {
837
+ /**
838
+ * Default ink — text color and path/line stroke — used when the author
839
+ * omits `color=`/`stroke=`. `layoutBlock` passes the theme text color so
840
+ * un-styled text stays legible on dark themes; the editor's scene canvas
841
+ * omits it and gets the dark-slate default that suits its fixed light
842
+ * surface.
843
+ */
844
+ ink?: string;
845
+ }
846
+ /** Minimal Block shape this derivation reads (subset of `Block`). */
847
+ interface LayoutChildBlock {
848
+ id: string;
849
+ template?: string;
850
+ templateOverrides?: Record<string, string>;
851
+ title?: string;
852
+ contents?: MarkdownNode[];
853
+ }
854
+ /**
855
+ * Map a layout block's children → positioned layers. Pure: same children
856
+ * always produce the same layers.
857
+ */
858
+ declare function computeLayoutLayers(children: readonly LayoutChildBlock[], _viewport: {
859
+ width: number;
860
+ height: number;
861
+ }, defaults?: LayoutLayerDefaults): LayoutLayersResult;
862
+
863
+ /**
864
+ * Accent Image Utility
865
+ *
866
+ * Creates image layers and layout adjustments for accent images on text-based slides.
867
+ * Accent images are tasteful additions that complement text without overwhelming it.
868
+ *
869
+ * Layout patterns:
870
+ * - left-strip: 35% width vertical strip on left, text area shifted to right 65%
871
+ * - right-strip: 35% width vertical strip on right, text area shifted to left 65%
872
+ * - bottom-strip: 35% height horizontal strip at bottom, text area in upper 65%
873
+ * - corner-inset: Small 25% corner image with gradient vignette
874
+ *
875
+ * This is shared code used by both site and efb-app doc renderers.
876
+ */
877
+
878
+ /**
879
+ * Layout adjustments when an accent image is present.
880
+ * Templates use these values to reposition their text content.
881
+ */
882
+ interface AccentLayout {
883
+ /** X offset for text center (e.g., '64%' for left-strip) */
884
+ textCenterX: string;
885
+ /** Width available for text content */
886
+ textWidth: string;
887
+ /** Y offset adjustment for vertical positioning */
888
+ textYAdjust: number;
889
+ /** Whether to adjust Y positions (for bottom-strip) */
890
+ adjustY: boolean;
891
+ }
892
+ /**
893
+ * Default layout when no accent image is present.
894
+ */
895
+ declare const DEFAULT_LAYOUT: AccentLayout;
896
+ /**
897
+ * Get layout adjustments based on accent position.
898
+ */
899
+ declare function getAccentLayout(position: AccentPosition): AccentLayout;
900
+ /**
901
+ * Create layers for an accent image.
902
+ * Returns the image layer and any overlay/gradient layers needed.
903
+ */
904
+ declare function createAccentLayers(accent: AccentImage, slideId: string, treatment?: ImageTreatment): Layer[];
905
+ /**
906
+ * Adjust a Y position value based on accent layout.
907
+ * Used by templates to shift content when bottom-strip is present.
908
+ */
909
+ declare function adjustY(originalY: string | number, layout: AccentLayout): string;
910
+
911
+ /**
912
+ * Block Template Registry
913
+ *
914
+ * Central registry of all block templates. Provides functions to:
915
+ * - Look up templates by name
916
+ * - Expand template blocks into full Layer arrays
917
+ * - Convert a template-based doc script into a renderable format
918
+ *
919
+ * Supports multiple viewport configurations for different aspect ratios.
920
+ *
921
+ * This is shared code used by both site and efb-app doc renderers.
922
+ */
923
+
924
+ /**
925
+ * Audio segment timing info for aligning blocks with audio.
926
+ */
927
+ interface AudioSegmentTiming {
928
+ /** Start time of this segment in the overall timeline */
929
+ startTime: number;
930
+ /** Duration of this segment */
931
+ duration: number;
932
+ }
933
+ /**
934
+ * Options for expanding doc blocks.
935
+ */
936
+ interface ExpandDocBlocksOptions {
937
+ /** Theme for template rendering (defaults to DEFAULT_THEME) */
938
+ theme?: Theme;
939
+ /** Viewport configuration (defaults to 16:9 landscape) */
940
+ viewport?: ViewportConfig;
941
+ /** Persistent layers for visual consistency across blocks */
942
+ persistentLayers?: PersistentLayerConfig | false;
943
+ /**
944
+ * Audio segment timing information.
945
+ * When provided, blocks are timed relative to their audio segment's start time,
946
+ * ensuring proper synchronization with audio playback.
947
+ */
948
+ audioSegments?: AudioSegmentTiming[];
949
+ /**
950
+ * User-defined custom templates to merge onto the built-in registry
951
+ * before expanding blocks. Typically passed straight from
952
+ * `Doc.customTemplates`. Built-in names take precedence on collision.
953
+ */
954
+ customTemplates?: readonly CustomTemplateDefinition[];
955
+ /** Failed templates render a visible fallback by default. */
956
+ failureMode?: LayerMaterializationFailureMode;
957
+ /** Receives structured template failures without hidden console output. */
958
+ onDiagnostic?: (diagnostic: LayerMaterializationDiagnostic, block: DocBlock, blockIndex: number) => void;
959
+ }
960
+ declare function expandDocBlocks(blocks: DocBlock[], options?: ExpandDocBlocksOptions): Block[];
961
+ /**
962
+ * Get list of available template names.
963
+ */
964
+ declare function getAvailableTemplates(): string[];
965
+ /**
966
+ * Check if a template exists. Accepts both the canonical short id
967
+ * (`title`, `quote`, `map`, `list`) and legacy aliases
968
+ * (`titleBlock`, `quoteBlock`, `mapBlock`, `listBlock`).
969
+ */
970
+ declare function hasTemplate(name: string): boolean;
971
+
972
+ /**
973
+ * Animation Utilities
974
+ *
975
+ * Helper functions for mapping Doc animations to CSS classes and styles.
976
+ * Generates the appropriate animation class names and CSS custom properties
977
+ * for duration, delay, and easing.
978
+ *
979
+ * This is shared code used by both site and efb-app doc renderers.
980
+ */
981
+
982
+ interface AnimationResult {
983
+ /** CSS class name to apply */
984
+ className: string;
985
+ /** Inline styles for CSS custom properties */
986
+ style: Record<string, string>;
987
+ }
988
+ /**
989
+ * Get CSS class and styles for an animation.
990
+ */
991
+ declare function getAnimationStyle(animation: Animation | undefined, _currentTime?: number): AnimationResult;
992
+ /**
993
+ * Get default duration for an animation type.
994
+ */
995
+ declare function getDefaultAnimationDuration(type: AnimationType): number;
996
+ /**
997
+ * Get transition class for slide entry/exit.
998
+ */
999
+ declare function getTransitionClass(type: TransitionType, entering: boolean, direction?: TransitionDirection): string;
1000
+ /**
1001
+ * Calculate animation progress (0-1) based on current time.
1002
+ */
1003
+ declare function getAnimationProgress(animation: Animation, currentTime: number, slideDuration: number): number;
1004
+
1005
+ /**
1006
+ * Theme Utilities
1007
+ *
1008
+ * Template-facing helpers that read from the Theme object on the
1009
+ * TemplateContext. Templates call these instead of hard-coding style
1010
+ * decisions, so the same template code adapts to any theme.
1011
+ */
1012
+
1013
+ /**
1014
+ * Resolve a named color scheme from the theme, with a safe fallback.
1015
+ * Templates call this instead of `COLOR_SCHEMES[name]`.
1016
+ */
1017
+ declare function resolveColorScheme(context: TemplateContext, name: string | undefined): ThemeColorScheme;
1018
+ /**
1019
+ * Get the theme font family for a given role, resolved to a CSS string.
1020
+ * Templates call this to set `fontFamily` on text layers.
1021
+ *
1022
+ * Theme fields are structured `FontFamily` references (`{ stackId }` or
1023
+ * `{ custom: { name, fallback } }`); this helper resolves them to a
1024
+ * CSS font-family string with safe fallbacks.
1025
+ */
1026
+ declare function getThemeFont(context: TemplateContext, role: 'title' | 'body' | 'mono'): string;
1027
+ /**
1028
+ * Calculate a theme-aware scaled font size.
1029
+ * Applies the theme's typography scale multipliers on top of the
1030
+ * viewport-based font scale from LayoutStrategy.
1031
+ *
1032
+ * @param basePx Base font size designed for 1920×1080
1033
+ * @param context Template context (includes fontScale, layout, theme)
1034
+ * @param isTitle Whether this is title text (uses titleScale) or body (bodyScale)
1035
+ */
1036
+ declare function themedFontSize(basePx: number, context: TemplateContext, isTitle?: boolean): number;
1037
+ /**
1038
+ * Scale an animation duration by the theme's animationSpeed multiplier.
1039
+ * A speed of 1.0 returns the base duration unchanged.
1040
+ */
1041
+ declare function scaleAnimationDuration(baseDuration: number, context: TemplateContext): number;
1042
+ /**
1043
+ * Get the theme's default animation type for a layer kind.
1044
+ * Returns `undefined` when the theme doesn't specify one (template picks its own).
1045
+ */
1046
+ declare function getDefaultAnimation(context: TemplateContext, layerType: 'text' | 'image'): AnimationType | undefined;
1047
+ /**
1048
+ * Theme-aware entrance animation for a template layer.
1049
+ *
1050
+ * The theme's `renderStyle.defaultTextAnimation` / `defaultImageAnimation`
1051
+ * overrides the entrance *type*; the template keeps its authored duration,
1052
+ * delay, and stagger. Templates opt in per layer:
1053
+ *
1054
+ * ```ts
1055
+ * animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 })
1056
+ * ```
1057
+ *
1058
+ * `slowZoom` is excluded — it's an ambient treatment handled by the
1059
+ * `applyRenderStyleToLayers` post-pass, not an entrance.
1060
+ */
1061
+ declare function themedEntrance(context: TemplateContext, layerType: 'text' | 'image', fallback: Animation): Animation;
1062
+ /**
1063
+ * Whether the theme defaults to text shadows.
1064
+ * Templates should consult this when choosing `shadow: true/false`.
1065
+ */
1066
+ declare function shouldUseShadow(context: TemplateContext): boolean;
1067
+ /**
1068
+ * Get the theme's overlay opacity for image-backed blocks.
1069
+ */
1070
+ declare function getOverlayOpacity(context: TemplateContext): number;
1071
+ /**
1072
+ * Resolve the effective photographic treatment for a block's imagery.
1073
+ *
1074
+ * Precedence: the block's `imageTreatment` override ('none' opts out, a
1075
+ * type forces that grade) → the theme's `style.imageTreatment` → none.
1076
+ * Duotone tints default to the theme primary. Templates pass the result
1077
+ * straight into `ImageLayer.content.treatment`.
1078
+ */
1079
+ declare function themedImageTreatment(context: TemplateContext, override?: 'none' | 'mono' | 'duotone' | 'warm' | 'cool'): ImageTreatment | undefined;
1080
+ /**
1081
+ * Theme-derived surface gradient for text-first templates.
1082
+ *
1083
+ * Runs from the theme's alternate surface into a slightly deepened
1084
+ * background, staying inside the theme's own hue. Templates must use
1085
+ * this instead of hard-coding a dark endpoint (`#0f1520`, `#1e2030`, …):
1086
+ * hard-coded navy endpoints made light themes render dark panels and
1087
+ * warm themes drift cold halfway down the block.
1088
+ */
1089
+ declare function themedSurfaceGradient(context: TemplateContext, angleDeg?: number): string;
1090
+ /**
1091
+ * Translucent overlay tint derived from the theme background, for text
1092
+ * bands/scrims painted over imagery. Light themes get a light scrim with
1093
+ * dark theme text on top; dark themes get the familiar dark scrim —
1094
+ * `theme.colors.text` stays legible on it by construction.
1095
+ */
1096
+ declare function themedScrim(context: TemplateContext, alpha?: number): string;
1097
+ /**
1098
+ * Read a per-template hint from the theme's renderStyle.
1099
+ * Returns `fallback` when the hint isn't defined.
1100
+ *
1101
+ * @example
1102
+ * ```ts
1103
+ * const entrance = getTemplateHint(context, 'statHighlight', 'entrance', 'subtle');
1104
+ * ```
1105
+ */
1106
+ declare function getTemplateHint<T extends string | number | boolean>(context: TemplateContext, templateName: string, key: string, fallback: T): T;
1107
+
1108
+ /**
1109
+ * Render-style post-pass — applies a theme's mechanical motion defaults to
1110
+ * template-generated layers.
1111
+ *
1112
+ * This is the intent-free half of theme motion (see `themedEntrance` in
1113
+ * [themeUtils.ts](./themeUtils.ts) for the intent-bearing half): it never
1114
+ * decides *what kind* of entrance a layer gets, only
1115
+ *
1116
+ * 1. scales existing animation durations/delays by the theme's
1117
+ * `style.animationSpeed` multiplier (1.4 = calmer/slower, 0.7 = snappier,
1118
+ * 1.0 = no-op), and
1119
+ * 2. gives full-bleed cover imagery with no authored animation a gentle,
1120
+ * deterministic Ken Burns when the theme opts into ambient motion.
1121
+ *
1122
+ * Applied ONLY to template-generated layers — raw authored `block.layers`
1123
+ * are never touched, and an explicit `animation` (including
1124
+ * `{ type: 'none' }`) always wins.
1125
+ */
1126
+
1127
+ /** Whether the theme asks for ambient Ken Burns on otherwise-static imagery. */
1128
+ declare function themeWantsAmbientMotion(theme: Theme): boolean;
1129
+ /**
1130
+ * Apply the theme's mechanical motion defaults to a block's
1131
+ * template-generated layers. Pure: returns new layer objects where a change
1132
+ * applies and the original objects where none does.
1133
+ *
1134
+ * @param layers Template-generated layers (never raw authored layers)
1135
+ * @param block The source block — supplies the ambient-motion seed and duration
1136
+ * @param theme Resolved theme
1137
+ */
1138
+ declare function applyRenderStyleToLayers(layers: Layer[], block: {
1139
+ id: string;
1140
+ duration?: number;
1141
+ }, theme: Theme): Layer[];
1142
+
1143
+ /**
1144
+ * Image treatment → CSS filter derivation.
1145
+ *
1146
+ * Treatments are theme-level photographic grades (see `ImageTreatment` in
1147
+ * [Doc.ts](../../schemas/Doc.ts)). They compile to plain CSS `filter`
1148
+ * functions so the same string works on a foreignObject `<img>`, an SVG
1149
+ * `<image>` element, and in headless frame capture — no SVG filter defs to
1150
+ * coordinate, no renderer-specific code paths.
1151
+ */
1152
+
1153
+ /**
1154
+ * Build the CSS `filter` value for a treatment and/or blur.
1155
+ * Returns `undefined` when there is nothing to apply.
1156
+ */
1157
+ declare function cssFilterForTreatment(treatment?: ImageTreatment, blur?: number): string | undefined;
1158
+
1159
+ /** Text fitting shared by the live diagram canvas and template renderer. */
1160
+ declare const DIAGRAM_LABEL_LINE_HEIGHT = 1.25;
1161
+ declare const DIAGRAM_LABEL_HORIZONTAL_PADDING = 24;
1162
+ declare const DIAGRAM_LABEL_VERTICAL_PADDING = 16;
1163
+ declare const DIAGRAM_LABEL_MIN_FONT_SIZE = 10;
1164
+ interface DiagramLabelFit {
1165
+ fontSize: number;
1166
+ lineCount: number;
1167
+ /** Upward shift that centers the full line group around the node midpoint. */
1168
+ firstLineOffset: number;
1169
+ textWidth: number;
1170
+ }
1171
+ /**
1172
+ * Fit a plain diagram label inside a node card using the same character-width
1173
+ * estimate and word wrapping as React's `TextLayer`.
1174
+ */
1175
+ declare function fitDiagramLabel(text: string, boxWidth: number, boxHeight: number, preferredFontSize: number): DiagramLabelFit;
1176
+
1177
+ /**
1178
+ * Template input derivation — build a template's required inputs from a
1179
+ * block's heading + markdown body.
1180
+ *
1181
+ * Used by:
1182
+ * - `markdownToDoc`'s content-aware auto template picking, so an
1183
+ * auto-picked `quote`/`statHighlight`/`leftFeature` block carries the
1184
+ * inputs its template needs through every render path (player, linear
1185
+ * view, exports).
1186
+ * - `LinearDocView` / editor previews, to render annotated blocks whose
1187
+ * authors didn't spell out every template param.
1188
+ *
1189
+ * Two modes:
1190
+ * - strict (default): returns `null` when an essential input can't be
1191
+ * derived (no image for a feature block, no table for dataTable…) —
1192
+ * auto-picking uses this to fall back to the structural default.
1193
+ * - placeholders: returns visible placeholder values instead of failing —
1194
+ * preview surfaces use this so a half-authored block still renders.
1195
+ */
1196
+
1197
+ /** First image discovered in a block's body, with explicit dimensions when present. */
1198
+ interface FirstImage {
1199
+ src: string;
1200
+ alt: string;
1201
+ width?: number;
1202
+ height?: number;
1203
+ }
1204
+ /** Plain text of a block's body contents (excluding the heading). */
1205
+ declare function extractBodyPlainText(contents?: MarkdownBlockNode[]): string;
1206
+ /** Extract list items as plain text. */
1207
+ declare function extractListItems(contents?: MarkdownBlockNode[]): string[];
1208
+ /**
1209
+ * Find images referenced anywhere in block contents — both markdown
1210
+ * shorthand `![alt](url)` (type `image`) and raw HTML `<img>` tags
1211
+ * (type `htmlBlock`/`htmlInline`). The WYSIWYG editor emits the HTML form
1212
+ * whenever a user resizes an image, so missing that path silently breaks
1213
+ * every resized image.
1214
+ *
1215
+ * @param limit Stop after this many images (default: all).
1216
+ */
1217
+ declare function extractImages(contents: MarkdownBlockNode[] | undefined, limit?: number): FirstImage[];
1218
+ /** First image in a block's body, or null. */
1219
+ declare function extractFirstImage(contents: MarkdownBlockNode[] | undefined): FirstImage | null;
1220
+ /** Extract table data (headers, rows, alignment) from block contents. */
1221
+ declare function extractTableFromContents(contents?: MarkdownBlockNode[]): {
1222
+ headers: string[];
1223
+ rows: string[][];
1224
+ align?: (('left' | 'right' | 'center') | null)[];
1225
+ } | null;
1226
+ /** First blockquote's plain text, or ''. */
1227
+ declare function extractBlockquoteText(contents?: MarkdownBlockNode[]): string;
1228
+ interface DeriveTemplateInputsOptions {
1229
+ /**
1230
+ * Return visible placeholder values instead of `null` when an essential
1231
+ * input can't be derived (preview surfaces). Default false (strict).
1232
+ */
1233
+ placeholders?: boolean;
1234
+ }
1235
+ /**
1236
+ * Derive a template's inputs from a block's heading text and body nodes.
1237
+ * Returns the input fields to merge onto the block, or `null` in strict
1238
+ * mode when an essential input is missing.
1239
+ */
1240
+ declare function deriveTemplateInputs(templateName: string, headingText: string, contents: MarkdownBlockNode[] | undefined, options?: DeriveTemplateInputsOptions): Record<string, unknown> | null;
1241
+
1242
+ /**
1243
+ * Markdown → Doc Conversion
1244
+ *
1245
+ * Converts a MarkdownDocument into a hierarchical Doc whose Block tree
1246
+ * mirrors the heading structure of the markdown. Every heading (H1–H6)
1247
+ * becomes a Block; body content between headings populates `contents`;
1248
+ * sub-headings nest as `children`.
1249
+ *
1250
+ * This enables using BlockTemplates to supply alternate visualizations
1251
+ * for each section of a markdown document.
1252
+ *
1253
+ * @example
1254
+ * ```ts
1255
+ * import { parseMarkdown } from '@bendyline/squisq/markdown';
1256
+ * import { markdownToDoc } from '@bendyline/squisq/doc';
1257
+ *
1258
+ * const md = parseMarkdown('# Intro\n\nHello world\n\n## Details\n\nMore text');
1259
+ * const doc = markdownToDoc(md);
1260
+ * // doc.blocks[0].sourceHeading.depth === 1 ("# Intro")
1261
+ * // doc.blocks[0].contents → [paragraph("Hello world")]
1262
+ * // doc.blocks[0].children[0].sourceHeading.depth === 2 ("## Details")
1263
+ * ```
1264
+ */
1265
+
1266
+ /**
1267
+ * Options for markdownToDoc().
1268
+ */
1269
+ interface MarkdownToDocOptions {
1270
+ /** Article ID for the generated Doc. Default: 'markdown-doc' */
1271
+ articleId?: string;
1272
+ /** Default template name for heading blocks. Default: 'sectionHeader' */
1273
+ defaultTemplate?: string;
1274
+ /** Default duration per block in seconds. Default: 5 */
1275
+ defaultDuration?: number;
1276
+ /** Custom ID generator. Receives the heading node and its index. */
1277
+ generateId?: (heading: MarkdownHeading, index: number) => string;
1278
+ /**
1279
+ * Whether to auto-generate a cover startBlock from the first H1 heading.
1280
+ * When true (default), a StartBlockConfig is created using the first H1's
1281
+ * text as the title. If the document contains an image, the first image
1282
+ * is used as the hero. Set to false to suppress automatic cover generation.
1283
+ */
1284
+ generateCoverBlock?: boolean;
1285
+ /**
1286
+ * Timestamp recorded as `captions.generatedAt`. When omitted, the field
1287
+ * is left unset so that conversion is fully deterministic — the same
1288
+ * markdown always converts to an identical Doc (important for snapshot
1289
+ * tests, caching, and agents that verify their output by re-converting).
1290
+ */
1291
+ captionsGeneratedAt?: string;
1292
+ /**
1293
+ * Content-aware template auto-picking for unannotated headings
1294
+ * (default: true). When a heading block carries a strong content signal
1295
+ * — a table, images, a blockquote, a list, a stat-looking line — the
1296
+ * matching template is applied (with inputs derived from the body)
1297
+ * instead of the structural `defaultTemplate`. Explicit `{[template]}`
1298
+ * annotations always win. Authors can also disable per document with
1299
+ * frontmatter `squisq-auto-templates: false`.
1300
+ */
1301
+ autoTemplates?: boolean;
1302
+ }
1303
+ /**
1304
+ * Public accessor for {@link pinnedMeta}: the timing/meta values an author
1305
+ * pinned on a block (heading `{key=value}` attrs or `{[key=value]}`
1306
+ * annotation params). Consumers use this to tell "author pinned this"
1307
+ * from "derive it" — e.g. narration timing never overwrites a pinned
1308
+ * `duration=`/`startTime=`.
1309
+ */
1310
+ declare function getPinnedBlockMeta(block: Block): CoercedBlockMeta;
1311
+ declare function markdownToDoc(markdownDoc: MarkdownDocument, options?: MarkdownToDocOptions): Doc;
1312
+ /**
1313
+ * Flatten a nested block tree into a depth-first ordered array.
1314
+ * Useful for calculating sequential timing or iterating all blocks.
1315
+ */
1316
+ declare function flattenBlocks(blocks: Block[]): Block[];
1317
+ /**
1318
+ * Flatten the block tree into the list of *independently renderable*
1319
+ * blocks — like {@link flattenBlocks}, but it does NOT descend into the
1320
+ * children of a container template (`diagram`, `drawing`; see
1321
+ * `isContainerTemplate`). Those children are consumed by the parent's
1322
+ * render (as nodes / shapes), so they must not also surface as their own
1323
+ * slides or sections.
1324
+ *
1325
+ * Use this anywhere a doc is flattened for rendering (slideshow, video,
1326
+ * static pages). Use {@link flattenBlocks} when you genuinely need every
1327
+ * block regardless of role — validation, timing, duplicate-id checks.
1328
+ */
1329
+ declare function flattenRenderableBlocks(blocks: Block[]): Block[];
1330
+ /**
1331
+ * Count the total number of blocks in a nested tree (including children at all levels).
1332
+ */
1333
+ declare function countBlocks(blocks: Block[]): number;
1334
+ /**
1335
+ * Get the heading depth for a block. Returns 0 for preamble blocks (no heading).
1336
+ */
1337
+ declare function getBlockDepth(block: Block): number;
1338
+ /**
1339
+ * Extract the plain text from a block's body contents (excluding heading text).
1340
+ *
1341
+ * Exported because the narration script builder and the narration timing
1342
+ * resolver must derive the *same* spoken text per block that captions and
1343
+ * reading-time use — one source of truth for "what does this block say".
1344
+ */
1345
+ declare function getBlockBodyText(block: Block): string;
1346
+
1347
+ /**
1348
+ * Doc → Markdown Conversion
1349
+ *
1350
+ * Converts a Doc with a heading-driven Block hierarchy back into a
1351
+ * MarkdownDocument. This is the reverse of markdownToDoc() and enables
1352
+ * round-tripping: edit a Doc's block tree, then serialize back to markdown.
1353
+ *
1354
+ * **Algorithm:**
1355
+ * Walk the block tree depth-first. For each block:
1356
+ * 1. If it has a `sourceHeading`, emit that heading node
1357
+ * 2. Emit all nodes in `contents`
1358
+ * 3. Recurse into `children`
1359
+ *
1360
+ * @example
1361
+ * ```ts
1362
+ * import { markdownToDoc, docToMarkdown } from '@bendyline/squisq/doc';
1363
+ * import { parseMarkdown, stringifyMarkdown } from '@bendyline/squisq/markdown';
1364
+ *
1365
+ * const md = '# Hello\n\nWorld\n';
1366
+ * const doc = markdownToDoc(parseMarkdown(md));
1367
+ * const roundTripped = stringifyMarkdown(docToMarkdown(doc));
1368
+ * ```
1369
+ */
1370
+
1371
+ /**
1372
+ * Convert a Doc with heading-driven blocks back to a MarkdownDocument.
1373
+ *
1374
+ * Walks the block tree depth-first, emitting heading nodes and contents
1375
+ * in document order. Blocks without a `sourceHeading` (preamble blocks)
1376
+ * emit only their contents.
1377
+ *
1378
+ * If a block has a `template` or `templateOverrides` that aren't already
1379
+ * reflected in the heading's `templateAnnotation`, the annotation is
1380
+ * injected so the round-trip preserves template assignments.
1381
+ *
1382
+ * @param doc - A Doc whose blocks may have `sourceHeading`, `contents`, and `children`
1383
+ * @returns A MarkdownDocument that can be stringified back to markdown
1384
+ */
1385
+ declare function docToMarkdown(doc: Doc): MarkdownDocument;
1386
+
1387
+ /**
1388
+ * Frontmatter serialization for user-defined custom templates (layouts).
1389
+ *
1390
+ * Custom template definitions live in the document's YAML frontmatter
1391
+ * under the key `squisq-custom-templates`. They're stored as a single
1392
+ * **compact JSON** object keyed by template name:
1393
+ *
1394
+ * ```yaml
1395
+ * squisq-custom-templates: {"hero":{"lb":"Hero Section","ly":[{"ty":"text",…}]}}
1396
+ * ```
1397
+ *
1398
+ * Squisq's frontmatter parser is line-based; a JSON object literal
1399
+ * round-trips through it verbatim (no leading quote to strip, single
1400
+ * line), so the value is written **unquoted** and stays human-readable
1401
+ * and diffable — important for a codebase edited by people and agents.
1402
+ *
1403
+ * The JSON is kept small by:
1404
+ * - keying definitions by `name` (drops the `name` field + array wrapper),
1405
+ * - omitting the viewport when it's the 1920×1080 default,
1406
+ * - renaming well-known property names to two-letter codes via
1407
+ * {@link LONG_TO_SHORT} (e.g. `fontSize` → `fz`).
1408
+ *
1409
+ * The rename is a generic, recursive, bijective pass: **any property not
1410
+ * in the map passes through unchanged**, so the format is lossless even
1411
+ * as the Layer schema grows — new fields are simply stored under their
1412
+ * full name until (optionally) added to the map.
1413
+ *
1414
+ * Back-compat: the reader still accepts the historical base64-of-JSON
1415
+ * payload and a structured array, so older documents load unchanged.
1416
+ * The first save migrates them to the compact form.
1417
+ *
1418
+ */
1419
+
1420
+ /**
1421
+ * Read the `squisq-custom-templates` frontmatter key and decode it into
1422
+ * an array of CustomTemplateDefinitions. Returns undefined when the key
1423
+ * is absent or unparseable so callers can omit the field from the Doc.
1424
+ *
1425
+ * Accepts, in order: the compact JSON object (current), a base64-JSON
1426
+ * string (legacy), and an already-structured array/object (in case a
1427
+ * richer YAML parser delivers it). Malformed payloads return undefined
1428
+ * rather than failing the whole doc load.
1429
+ */
1430
+ declare function readCustomTemplatesFromFrontmatter(frontmatter: Record<string, unknown> | undefined): CustomTemplateDefinition[] | undefined;
1431
+ /**
1432
+ * Encode a list of custom template definitions into the compact JSON
1433
+ * object described in the module header. Returns undefined when the
1434
+ * input list is empty so callers can leave the key off the output.
1435
+ */
1436
+ declare function writeCustomTemplatesToFrontmatter(templates: readonly CustomTemplateDefinition[] | undefined, options?: {
1437
+ pretty?: boolean;
1438
+ }): string | undefined;
1439
+
1440
+ /**
1441
+ * Frontmatter serialization for user-defined custom themes.
1442
+ *
1443
+ * The theme analog of {@link ./customTemplatesFrontmatter.ts}. Custom Theme
1444
+ * definitions live in the document's YAML frontmatter under the key
1445
+ * `squisq-custom-themes`, stored as a single **compact JSON** object keyed
1446
+ * by theme id:
1447
+ *
1448
+ * ```yaml
1449
+ * squisq-custom-themes: {"my-brand":{"schemaVersion":"1","id":"my-brand",…}}
1450
+ * ```
1451
+ *
1452
+ * Squisq's frontmatter parser is line-based; a JSON object literal
1453
+ * round-trips through it verbatim (single line, no leading quote to strip),
1454
+ * so the value is written **unquoted** and stays human-readable and diffable
1455
+ * — the same mechanism the custom-templates codec relies on.
1456
+ *
1457
+ * Only one theme is *active* per doc (selected by id via the `squisq-theme`
1458
+ * frontmatter key / `Doc.themeId`), but the payload is a keyed map — parallel
1459
+ * to custom templates — so a doc can carry a small catalog and switch between
1460
+ * them, and `resolveThemeForDoc` can resolve any of them doc-scoped.
1461
+ *
1462
+ * Malformed entries are dropped (via `validateTheme`) rather than failing the
1463
+ * whole doc load, matching the tolerant behavior of the templates reader.
1464
+ */
1465
+
1466
+ /**
1467
+ * Read the custom themes inlined into a document's frontmatter. Returns
1468
+ * undefined when the key is absent or holds no valid theme, so callers can
1469
+ * omit the field from the Doc.
1470
+ */
1471
+ declare function readCustomThemesFromFrontmatter(frontmatter: Record<string, unknown> | undefined): Theme[] | undefined;
1472
+ /**
1473
+ * Encode a list of custom themes into the compact JSON object described in
1474
+ * the module header (keyed by theme id). Returns undefined when the input is
1475
+ * empty so callers can leave the key off the output.
1476
+ */
1477
+ declare function writeCustomThemesToFrontmatter(themes: readonly Theme[] | undefined, options?: {
1478
+ pretty?: boolean;
1479
+ }): string | undefined;
1480
+
1481
+ /**
1482
+ * Doc-scoped theme resolution.
1483
+ *
1484
+ * The theme analog of how `buildRegistry` resolves custom templates: pure and
1485
+ * doc-scoped, with no global state. `resolveThemeForDoc` looks up the active
1486
+ * theme id in the doc's own custom themes first, then falls back to an
1487
+ * optional caller-owned registry, then built-ins via `resolveTheme`.
1488
+ *
1489
+ * It accepts either a squisq `Doc` (which carries a typed `customThemes`
1490
+ * array) or anything with raw `frontmatter` — notably a `MarkdownDocument`,
1491
+ * which is the shape every export pipeline pivots through. In the latter case
1492
+ * the inline themes are decoded from the `squisq-custom-themes` frontmatter
1493
+ * payload. Inline custom themes ship with the doc, exactly like custom
1494
+ * templates; host-level themes can be supplied through an explicit registry.
1495
+ */
1496
+
1497
+ /**
1498
+ * The minimal shape `resolveThemeForDoc` needs. Satisfied by both the squisq
1499
+ * `Doc` (typed `customThemes` + `themeId`) and a `MarkdownDocument` (raw
1500
+ * `frontmatter` carrying the encoded payload).
1501
+ */
1502
+ interface ThemeResolvable {
1503
+ themeId?: string;
1504
+ customThemes?: Theme[];
1505
+ frontmatter?: Record<string, unknown>;
1506
+ }
1507
+ /**
1508
+ * Resolve the Theme a document should render with.
1509
+ *
1510
+ * @param doc - the document (may carry inline custom themes plus a `themeId`
1511
+ * / `squisq-theme` frontmatter selector).
1512
+ * @param explicitId - an id that overrides the doc's own selection (e.g. the
1513
+ * editor's theme dropdown, or an export `--theme` option). When omitted, the
1514
+ * doc's `themeId` / frontmatter theme id is used.
1515
+ * @returns the matching inline custom theme (doc-scoped) when present, else
1516
+ * the caller-registry or built-in theme for that id, else the default theme.
1517
+ */
1518
+ declare function resolveThemeForDoc(doc: ThemeResolvable | null | undefined, explicitId?: string, registry?: ThemeRegistry): Theme;
1519
+
1520
+ /**
1521
+ * Audio Mapping
1522
+ *
1523
+ * Associates audio segments (MP3 files) with document blocks.
1524
+ * Supports two modes:
1525
+ *
1526
+ * 1. **Explicit annotation**: Blocks with `{[audio=filename.mp3]}` in their
1527
+ * heading annotation are directly mapped to that audio file.
1528
+ *
1529
+ * 2. **Auto-matching**: When no annotations exist but the container has MP3s
1530
+ * with `.timing.json` files, matches MP3s to blocks by comparing the
1531
+ * timing.json `sourceText` against block text content (word overlap).
1532
+ * Falls back to filename-based matching (slugified title comparison).
1533
+ */
1534
+
1535
+ /**
1536
+ * Calculate Jaccard similarity between two texts (word overlap).
1537
+ * Returns 0–1 where 1 = identical word sets.
1538
+ */
1539
+ declare function scoreTextSimilarity(a: string, b: string): number;
1540
+ /**
1541
+ * Resolve audio mapping for a Doc using a ContentContainer.
1542
+ *
1543
+ * Tries explicit `{[audio=filename.mp3]}` annotations first,
1544
+ * then falls back to auto-matching by content similarity.
1545
+ *
1546
+ * Returns a new Doc with `audio.segments` populated and blocks
1547
+ * assigned to the correct `audioSegment` indices.
1548
+ *
1549
+ * @param doc - The source Doc (not mutated).
1550
+ * @param container - ContentContainer with narration and timing files.
1551
+ * @returns New Doc with audio segments resolved, or original doc if no matches.
1552
+ */
1553
+ declare function resolveAudioMapping(doc: Doc, container: ContentContainer): Promise<Doc>;
1554
+
1555
+ /**
1556
+ * Apply narration timing from a document-anchored take to a Doc's block
1557
+ * timeline.
1558
+ *
1559
+ * When a doc carries a document-spanning narration clip (a preamble
1560
+ * `{[audio src=… anchor=document]}` → `doc.documentMedia`) whose
1561
+ * `.timing.json` sidecar has per-block ranges (v3, written by the
1562
+ * teleprompter's aligner), the blocks are re-timed so playback and
1563
+ * exports advance in sync with the recorded voice. Runs as step 0 of
1564
+ * `resolveAudioMapping`, so every surface that resolves audio gets it.
1565
+ *
1566
+ * Precedence: author-pinned `duration=`/`startTime=` heading attrs win
1567
+ * over narration ranges (a conflicting pin gets an `info` diagnostic);
1568
+ * narration ranges win over per-block audio-segment mapping and
1569
+ * reading-time estimates.
1570
+ */
1571
+
1572
+ interface NarrationResolution {
1573
+ doc: Doc;
1574
+ /** False → the doc is returned unchanged (no clip / no sidecar / no match). */
1575
+ applied: boolean;
1576
+ /** The narration media path, for callers that bundle assets. */
1577
+ clipSrc?: string;
1578
+ }
1579
+ /**
1580
+ * Find the doc's document-anchored narration clip, load its timing
1581
+ * sidecar, and re-time the blocks from its ranges. Pure with respect to
1582
+ * the input doc — returns a new Doc (or the original when nothing
1583
+ * applies).
1584
+ */
1585
+ declare function applyNarrationTiming(doc: Doc, container: ContentContainer): Promise<NarrationResolution>;
1586
+
1587
+ /**
1588
+ * Structured template data from markdown body content.
1589
+ *
1590
+ * Attribute strings on a heading annotation are fine for scalar params,
1591
+ * but tabular or nested inputs (dataTable rows, map markers, chart data)
1592
+ * don't pack well into a single quoted line. This module supplies the two
1593
+ * structured channels instead:
1594
+ *
1595
+ * 1. **Data fences** — a fenced code block whose info string is
1596
+ * `json data` or `yaml data`, placed in a heading's body content:
1597
+ *
1598
+ * ````markdown
1599
+ * ## Quarterly numbers {[dataTable]}
1600
+ *
1601
+ * ```json data
1602
+ * { "headers": ["Q", "Revenue"], "rows": [["Q1", "1.2M"], ["Q2", "1.4M"]] }
1603
+ * ```
1604
+ * ````
1605
+ *
1606
+ * The parsed object lands on `block.templateData` and merges into the
1607
+ * template input (after defaults, before `{[…]}` string overrides).
1608
+ * The `data` marker keeps ordinary ```json code samples — which should
1609
+ * render as code — out of the template input.
1610
+ *
1611
+ * 2. **GFM tables** — for the `dataTable` template, the first table in the
1612
+ * section body supplies `headers` / `rows` / `align` when the author
1613
+ * didn't provide them explicitly.
1614
+ *
1615
+ * YAML support is a documented subset (this package has no YAML
1616
+ * dependency): top-level `key: scalar`, `key: [inline, array]`, `key:`
1617
+ * followed by an indented `- item` block sequence (scalars or inline
1618
+ * arrays), and `key:` followed by *one level* of indented `subkey: scalar`
1619
+ * lines (a nested map, e.g. `center:` + indented `lat:` / `lng:`). Deeper
1620
+ * nesting, and mixing list items with mapping keys under one key, are
1621
+ * rejected with a clear error — use a `json data` fence for those.
1622
+ */
1623
+
1624
+ /**
1625
+ * Whether a code block is a structured-data fence: lang `json`/`yaml`/`yml`
1626
+ * with the word `data` in the fence meta (` ```json data `).
1627
+ */
1628
+ declare function isDataFence(node: MarkdownCodeBlock): boolean;
1629
+ interface DataFenceParseResult {
1630
+ /** Parsed key→value map. Undefined when parsing failed. */
1631
+ data?: Record<string, unknown>;
1632
+ /** Parse failure description. Undefined when parsing succeeded. */
1633
+ error?: string;
1634
+ }
1635
+ /**
1636
+ * Parse a data fence's content into a key→value map. JSON fences must
1637
+ * contain a top-level object (arrays have no key to merge under); YAML
1638
+ * fences are parsed with {@link parseYamlSubset}.
1639
+ */
1640
+ declare function parseDataFence(node: MarkdownCodeBlock): DataFenceParseResult;
1641
+ /**
1642
+ * Return a new contents array with the first data fence's code content
1643
+ * replaced by `data` (pretty-printed JSON). The fence node keeps its
1644
+ * language and `data` marker; only `value` changes. When no data fence
1645
+ * exists, a new ` ```json data ` fence is appended instead.
1646
+ *
1647
+ * Pure: neither `contents` nor its nodes are mutated. This is the write
1648
+ * half of the data-fence channel — editors update `block.templateData`
1649
+ * and call this to reflect the change back into `block.contents`.
1650
+ */
1651
+ declare function replaceDataFence(contents: MarkdownBlockNode[], data: Record<string, unknown>): MarkdownBlockNode[];
1652
+ /**
1653
+ * Parse the supported YAML subset (see module doc) into a key→value map.
1654
+ * Throws an Error with a line-anchored message on anything outside the
1655
+ * subset, so callers can surface a precise diagnostic.
1656
+ */
1657
+ declare function parseYamlSubset(src: string): Record<string, unknown>;
1658
+ interface ExtractedTableData {
1659
+ headers: string[];
1660
+ rows: string[][];
1661
+ align?: (('left' | 'right' | 'center') | null)[];
1662
+ }
1663
+ /** Find the first GFM table among a block's body contents. */
1664
+ declare function findFirstTable(contents: MarkdownBlockNode[] | undefined): MarkdownTable | undefined;
1665
+ /**
1666
+ * Extract `headers` / `rows` / `align` (the `dataTable` input shape) from a
1667
+ * GFM table node. The first row is the header row.
1668
+ */
1669
+ declare function extractTableData(table: MarkdownTable): ExtractedTableData;
1670
+
1671
+ /**
1672
+ * Markdown document validation.
1673
+ *
1674
+ * `validateMarkdownSource()` gives authors and agents fast, structural
1675
+ * feedback on a squisq markdown document — the same checks the renderer
1676
+ * applies, surfaced as diagnostics instead of degraded slides:
1677
+ *
1678
+ * - unknown template names (with a did-you-mean suggestion)
1679
+ * - unknown drawing shapes, and shape annotations used outside a `{[drawing]}`
1680
+ * - `{[…]}` text that was not recognized as an annotation (bad quoting,
1681
+ * non-heading placement, unknown inline icon)
1682
+ * - malformed heading-attribute values (`x=abc`, bad `startTime`) and
1683
+ * non-numeric drawing-shape geometry
1684
+ * - `connectsTo` / drawing `from`/`to` targets that don't resolve,
1685
+ * duplicate block ids, unparseable data fences (reported by `markdownToDoc`)
1686
+ * - image references missing from the provided asset set (.dbk contents)
1687
+ *
1688
+ * The CLI exposes this as `squisq validate <input>`; agents can also call
1689
+ * it directly and iterate until the diagnostics list is empty.
1690
+ */
1691
+
1692
+ interface ValidateOptions {
1693
+ /**
1694
+ * Known asset paths for image/video reference checks — typically the
1695
+ * file list of a .dbk container or the document's folder. Relative
1696
+ * references not present here produce a `missing-asset` warning.
1697
+ * When omitted, asset checks are skipped.
1698
+ */
1699
+ assets?: ReadonlySet<string> | ((path: string) => boolean);
1700
+ /**
1701
+ * Additional template names to accept beyond the built-in registry and
1702
+ * the document's own `customTemplates` (e.g. app-registered templates).
1703
+ */
1704
+ extraTemplates?: readonly string[];
1705
+ }
1706
+ interface MarkdownValidationResult {
1707
+ /** All findings, in source order where line information exists. */
1708
+ diagnostics: DocDiagnostic[];
1709
+ errorCount: number;
1710
+ warningCount: number;
1711
+ infoCount: number;
1712
+ /** The converted Doc (conversion diagnostics are included above). */
1713
+ doc: Doc;
1714
+ }
1715
+ /**
1716
+ * Validate a squisq markdown source string. Parses, converts (collecting
1717
+ * the conversion's own diagnostics), and runs the structural checks above.
1718
+ */
1719
+ declare function validateMarkdownSource(source: string, options?: ValidateOptions): MarkdownValidationResult;
1720
+ /**
1721
+ * Validate an already-parsed MarkdownDocument. See {@link validateMarkdownSource}.
1722
+ */
1723
+ declare function validateMarkdownDoc(markdownDoc: MarkdownDocument, options?: ValidateOptions): MarkdownValidationResult;
1724
+
1725
+ /**
1726
+ * Fallback Block Rendering
1727
+ *
1728
+ * The graceful-degradation guarantee: a block whose template can't render —
1729
+ * unknown template name, template function threw, or returned a non-array —
1730
+ * still renders its heading and body text as a plain, readable card instead
1731
+ * of a blank slide. A small notice line names the problem so authors (and
1732
+ * agents reviewing screenshots) can see *why* the block degraded.
1733
+ *
1734
+ * This is intentionally not a registered template: it can't be requested by
1735
+ * name, only reached when a requested template fails. See `materializeBlockLayers()`.
1736
+ */
1737
+
1738
+ /**
1739
+ * Render a block's heading + body text as plain layers, with a notice line
1740
+ * describing why the requested template didn't render.
1741
+ *
1742
+ * @param block The block that failed to render via its template.
1743
+ * @param context Template context (theme, viewport).
1744
+ * @param notice Short problem description, e.g. `Unknown template "photGrid"`.
1745
+ */
1746
+ declare function fallbackBlockLayers(block: DocBlock, context: TemplateContext, notice: string): Layer[];
1747
+
1748
+ /**
1749
+ * Template input descriptors — a typed catalog of the inline `{[…]}` params
1750
+ * each built-in template understands, plus the pure coercion + lint logic
1751
+ * that consumes it.
1752
+ *
1753
+ * Two jobs, one source of truth:
1754
+ *
1755
+ * - **Coercion (`coerceTemplateParams`)** turns a flat `key → raw string`
1756
+ * param map (from a `{[name key=value]}` annotation, always strings) into a
1757
+ * partial typed input the template functions can consume directly — e.g.
1758
+ * `center="47.6,-122.3"` → `{ lat: 47.6, lng: -122.3 }`, `zoom=9` → `9`.
1759
+ * This is what makes `{[map center="47.6,-122.3" zoom=9]}` render with no
1760
+ * changes to any template function. Unknown keys ALWAYS pass through
1761
+ * untouched (as strings), so coercion is never lossy; coercion failures are
1762
+ * returned as `warnings` and the raw string is preserved.
1763
+ *
1764
+ * - **Linting (`lintTemplateParams`)** checks a param map against the
1765
+ * descriptors and reports unknown keys (with a did-you-mean suggestion),
1766
+ * values outside a closed enum / that fail coercion, and missing required
1767
+ * inputs. The document validator surfaces these as diagnostics.
1768
+ *
1769
+ * This mirrors the proven block-meta descriptor pattern in
1770
+ * `markdown/annotationCoercion.ts` (`BLOCK_META_KEY_DESCRIPTORS`), extended
1771
+ * from block geometry/timing to per-template content inputs.
1772
+ *
1773
+ * The descriptors are the `{[…]}` counterpart of the template input
1774
+ * interfaces in `schemas/BlockTemplates.ts` — only keys/enums that provably
1775
+ * exist on those interfaces are declared. Keys that can't be meaningfully
1776
+ * expressed as a single inline string (e.g. a `dataTable`'s `rows`) are still
1777
+ * declared with `coerce: 'string'` so they aren't mis-flagged as unknown.
1778
+ */
1779
+ /** How a raw `{[…]}` param string is coerced into a typed input value. */
1780
+ type InputCoercion = 'string' | 'number' | 'boolean' | 'latLng' | 'labeledPair' | 'stringList';
1781
+ /**
1782
+ * Editor/validator-facing description of a single template input key: what it
1783
+ * does, how to coerce its raw string, and either its closed set of valid
1784
+ * values or a free-form format hint. `values`/`valueHint` are mutually
1785
+ * exclusive (a key has a closed enum OR a hint, not both).
1786
+ */
1787
+ interface TemplateInputDescriptor {
1788
+ /** The `{[name key=…]}` param key, matching the template input interface. */
1789
+ key: string;
1790
+ /** One-line description of the input. */
1791
+ description: string;
1792
+ /** Coercion strategy for the raw string (default `'string'`). */
1793
+ coerce?: InputCoercion;
1794
+ /** Closed set of valid values, for keys backed by an enum. */
1795
+ values?: readonly string[];
1796
+ /** Format hint shown when the value is free-form (no closed set). */
1797
+ valueHint?: string;
1798
+ /** When true, the validator warns if the key is absent and can't be derived. */
1799
+ required?: boolean;
1800
+ }
1801
+ /** A single lint finding produced by {@link lintTemplateParams}. */
1802
+ interface TemplateParamFinding {
1803
+ kind: 'unknown-input' | 'invalid-input-value' | 'missing-input';
1804
+ key: string;
1805
+ message: string;
1806
+ /** Did-you-mean candidate (for `unknown-input`). */
1807
+ suggestion?: string;
1808
+ }
1809
+ /**
1810
+ * Inputs shared by every template via `BaseTemplateBlock`. Merged into each
1811
+ * template's known-key set for coercion + lint. Block-level timing/geometry
1812
+ * keys (`duration`, `x`, `y`, …) are NOT here — those stay owned by the
1813
+ * block-meta registry (`KNOWN_BLOCK_META_KEYS`) and are folded into the lint
1814
+ * known-key set separately.
1815
+ */
1816
+ declare const BASE_INPUT_DESCRIPTORS: readonly TemplateInputDescriptor[];
1817
+ /**
1818
+ * Per-template input descriptors, keyed by canonical template id. A template
1819
+ * absent from this map has no descriptors and is exempt from lint (custom
1820
+ * templates and not-yet-described built-ins).
1821
+ */
1822
+ declare const TEMPLATE_INPUT_DESCRIPTORS: Readonly<Record<string, readonly TemplateInputDescriptor[]>>;
1823
+ /**
1824
+ * Coerce a flat `{[…]}` param map into a partial typed template input.
1825
+ *
1826
+ * Known descriptor keys are coerced per their `coerce` strategy; unknown keys
1827
+ * (and `string`-typed keys) pass through unchanged. A coercion failure leaves
1828
+ * the raw string in place and adds a human-readable `warnings` entry — the
1829
+ * output is never lossy. Returns a fresh object; the caller must NOT feed
1830
+ * `templateOverrides` back in — only the ephemeral merged input is coerced.
1831
+ */
1832
+ declare function coerceTemplateParams(template: string | undefined, params: Record<string, string>): {
1833
+ input: Record<string, unknown>;
1834
+ warnings: string[];
1835
+ };
1836
+ /**
1837
+ * Lint a template's `{[…]}` params against its descriptors. Returns findings
1838
+ * for unknown keys, values outside a closed enum / that fail coercion, and
1839
+ * missing required inputs. Templates without descriptors (custom or
1840
+ * not-yet-described built-ins) return `[]`.
1841
+ */
1842
+ declare function lintTemplateParams(template: string, params: Record<string, string>): TemplateParamFinding[];
1843
+
1844
+ /**
1845
+ * Public types for the ASCII diagram codec.
1846
+ *
1847
+ * Coordinates are grid-native: `col`/`row` count character cells from the
1848
+ * top-left of the art (0-based), `wCols`/`hRows` include the borders. The
1849
+ * mapping helpers in `mapping.ts` convert to/from diagram canvas units
1850
+ * via {@link ASCII_CHAR_W} / {@link ASCII_CHAR_H}.
1851
+ */
1852
+ interface AsciiDiagramNode {
1853
+ /**
1854
+ * Stable id: slug of the first label line, deduplicated with `-2`/`-3`
1855
+ * suffixes in reading order. Identical art always re-parses to
1856
+ * identical ids (editor selection and edges resolve by id).
1857
+ */
1858
+ id: string;
1859
+ /** Interior text lines joined with `\n` (trimmed, blank lines dropped). May be `''`. */
1860
+ label: string;
1861
+ /** Left column of the box (0-based, includes the border). */
1862
+ col: number;
1863
+ /** Top row of the box (0-based, includes the border). */
1864
+ row: number;
1865
+ /** Full box width in columns, borders included. */
1866
+ wCols: number;
1867
+ /** Full box height in rows, borders included. */
1868
+ hRows: number;
1869
+ /** Id of the box that strictly contains this one, when nested. */
1870
+ containerId?: string;
1871
+ }
1872
+ interface AsciiDiagramEdge {
1873
+ source: string;
1874
+ target: string;
1875
+ /** Edge label parsed from an embedded horizontal run (`──label──▶`). */
1876
+ label?: string;
1877
+ /** False when the line carried no arrowhead. */
1878
+ directed: boolean;
1879
+ }
1880
+ interface AsciiDiagram {
1881
+ /** Nodes in reading order (row, then col). Containers are ordinary nodes with children pointing at them. */
1882
+ nodes: AsciiDiagramNode[];
1883
+ /** Deduplicated edges, sorted by (source, target, label). */
1884
+ edges: AsciiDiagramEdge[];
1885
+ /** Character vocabulary detected in the source; render emits the same style. */
1886
+ style: 'unicode' | 'ascii';
1887
+ /** Non-fatal parse notes (loose text, dropped labels, ambiguous buses, …). */
1888
+ warnings: string[];
1889
+ }
1890
+ interface AsciiDiagramDetection {
1891
+ isDiagram: boolean;
1892
+ /** Present when `isDiagram` — avoids a second parse in callers. */
1893
+ diagram?: AsciiDiagram;
1894
+ /** Machine-greppable accept/reject reasons, e.g. `too-few-boxes(1)`, `loose-ratio(0.41)`. */
1895
+ reasons: string[];
1896
+ }
1897
+ /**
1898
+ * Canvas pixels per grid column/row. Sized so a typical 12-col × 3-row
1899
+ * ASCII box maps close to the native 180×64 diagram card, and a 60–100
1900
+ * column diagram fits the 1600×900 diagram viewport.
1901
+ */
1902
+ declare const ASCII_CHAR_W = 14;
1903
+ declare const ASCII_CHAR_H = 28;
1904
+
1905
+ /**
1906
+ * ASCII diagram parser: box-and-line art → semantic nodes/edges.
1907
+ *
1908
+ * Pure and deterministic; never throws. Unparseable input degrades to an
1909
+ * empty diagram (plus warnings), never an exception — callers decide what
1910
+ * to do with sparse results (the detector requires ≥2 nodes, for example).
1911
+ *
1912
+ * Pipeline: normalize → char grid → box tracing (corner walks; `+` is
1913
+ * resolved smallest-rectangle-first) → containment tree → labels/ids →
1914
+ * edge extraction (mask box perimeters + leaf interiors, then connected
1915
+ * components of line/arrow cells with label "bridges") → loose text.
1916
+ */
1917
+
1918
+ declare function parseAsciiDiagram(text: string): AsciiDiagram;
1919
+
1920
+ /**
1921
+ * ASCII diagram renderer: semantic nodes/edges → box-and-line art.
1922
+ *
1923
+ * Deterministic (no clock, no randomness; every iteration order is an
1924
+ * explicit sort) and designed as a fixpoint partner for `parse.ts`:
1925
+ *
1926
+ * - `parseAsciiDiagram(renderAsciiDiagram(d))` preserves node ids, labels,
1927
+ * containment, and the edge tuple set of `d`.
1928
+ * - After one normalization cycle the output is byte-stable:
1929
+ * `renderAsciiDiagram(parseAsciiDiagram(renderAsciiDiagram(d))) ===
1930
+ * renderAsciiDiagram(d)`.
1931
+ *
1932
+ * Grid positions come from the nodes; container rects are DERIVED from
1933
+ * their children each render (a container's own col/row are ignored), so
1934
+ * moving children can never orphan them outside their box.
1935
+ */
1936
+
1937
+ interface RenderAsciiDiagramOptions {
1938
+ /** Character vocabulary; defaults to the diagram's own detected style. */
1939
+ style?: 'unicode' | 'ascii';
1940
+ }
1941
+ declare function renderAsciiDiagram(diagram: AsciiDiagram, options?: RenderAsciiDiagramOptions): string;
1942
+
1943
+ /**
1944
+ * ASCII diagram detection: is this fence content a box-and-line diagram?
1945
+ *
1946
+ * False positives are the expensive failure (they hide real code behind a
1947
+ * canvas / template); false negatives just leave a code block alone. Every
1948
+ * rejection path records a machine-greppable reason so the corpus tests
1949
+ * act as the contract for any future threshold tuning.
1950
+ */
1951
+
1952
+ /** Fence languages eligible for diagram detection (plus no language at all). */
1953
+ declare const ASCII_DIAGRAM_FENCE_LANGS: ReadonlySet<string>;
1954
+ declare function isEligibleAsciiFenceLang(lang: string | null | undefined): boolean;
1955
+ /**
1956
+ * True when the fence LANGUAGE is the explicit `diagram` tag — an author-set
1957
+ * "this is a diagram" marker that survives round-trips (the language class
1958
+ * round-trips; fence meta does not). Detection of a tagged fence is lenient
1959
+ * (≥1 box, no lattice rejector) so a degenerate diagram stays a diagram.
1960
+ */
1961
+ declare function isExplicitDiagramLang(lang: string | null | undefined): boolean;
1962
+ interface DetectDiagramOptions {
1963
+ /** The fence is explicitly `diagram`-tagged: accept ≥1 box, skip rejectors. */
1964
+ explicit?: boolean;
1965
+ }
1966
+ declare function detectAsciiDiagram(text: string, opts?: DetectDiagramOptions): AsciiDiagramDetection;
1967
+ /** Convenience gate for pipeline callers: lang allowlist + content detection. */
1968
+ declare function isAsciiDiagramFence(node: MarkdownCodeBlock): boolean;
1969
+
1970
+ /**
1971
+ * ASCII diagram REPAIR — an opt-in, best-effort pass that reconstructs a
1972
+ * clean, well-formed diagram from broken box-and-line art.
1973
+ *
1974
+ * The motivating case: hand-drawn architecture art whose labels overflow
1975
+ * their boxes and shove every following column out of alignment row-to-row
1976
+ * (e.g. a rename widened the labels). Conservative detection correctly
1977
+ * declines such art (`garbled-labels`) so it renders as a faithful code
1978
+ * block — but a user can then ask to "repair" it. This is that repair.
1979
+ *
1980
+ * It is deliberately AGGRESSIVE and lossy — never on the auto-detection path
1981
+ * (a mistake there would hide real code). It is only invoked when the user
1982
+ * explicitly opts in, and the result is a fully editable diagram, so an
1983
+ * imperfect edge or two is fine (the canvas lets the user fix them).
1984
+ *
1985
+ * Pipeline:
1986
+ * 1. Aggressive box tracing (walls may cross edge routing).
1987
+ * 2. Row-band label recovery — the key trick: even when a box's columns are
1988
+ * desynced from its borders, each label ROW is internally consistent, so
1989
+ * its `│…│` segments map to the band's boxes by reading order.
1990
+ * 3. Best-effort edge recovery (facing-border adjacency + arrowhead
1991
+ * direction).
1992
+ * 4. Re-render clean via `renderAsciiDiagram` — the output re-parses cleanly.
1993
+ */
1994
+
1995
+ interface RepairResult {
1996
+ /** The reconstructed diagram model (grid-native coordinates). */
1997
+ diagram: AsciiDiagram;
1998
+ /** Clean, re-rendered box-and-line art — re-parses to `diagram`. */
1999
+ art: string;
2000
+ }
2001
+ /**
2002
+ * True when a fence is a box diagram too broken for clean detection but worth
2003
+ * offering to repair: it has box corners and aggressively traces ≥2 boxes,
2004
+ * yet conservative detection declines it. Clean diagrams (already detected)
2005
+ * and non-box art both return false, so the three states partition cleanly.
2006
+ */
2007
+ declare function isRepairableDiagram(text: string): boolean;
2008
+ /**
2009
+ * Reconstruct a clean diagram from broken art. Returns `null` when fewer than
2010
+ * two boxes can be recovered (nothing worth repairing).
2011
+ */
2012
+ declare function repairAsciiDiagram(text: string): RepairResult | null;
2013
+
2014
+ /**
2015
+ * Mapping between the grid-native ASCII diagram model and the diagram
2016
+ * canvas / template model (canvas units, the same space as `Block.x`/`y`).
2017
+ *
2018
+ * Quantization uses plain `round()` per axis — monotonic and local, so a
2019
+ * small canvas nudge either changes nothing or moves exactly one cell
2020
+ * (cluster-based schemes flap under small moves and churn the art).
2021
+ */
2022
+
2023
+ declare function asciiCellToCanvas(col: number, row: number): {
2024
+ x: number;
2025
+ y: number;
2026
+ };
2027
+ declare function canvasToAsciiCell(x: number, y: number): {
2028
+ col: number;
2029
+ row: number;
2030
+ };
2031
+ /** Grid model → template/canvas model (`templateData.nodes`/`edges`). */
2032
+ declare function asciiDiagramToTemplateData(diagram: AsciiDiagram): {
2033
+ nodes: DiagramTemplateNode[];
2034
+ edges: DiagramTemplateEdge[];
2035
+ };
2036
+ /** Template/canvas model → grid model, quantizing positions and sizes. */
2037
+ declare function asciiDiagramFromTemplateData(nodes: readonly DiagramTemplateNode[], edges: readonly DiagramTemplateEdge[], options?: {
2038
+ style?: 'unicode' | 'ascii';
2039
+ }): AsciiDiagram;
2040
+ /**
2041
+ * Legacy heading-based diagram children → ASCII diagram model. Used to
2042
+ * migrate `### Node {#id x= y= connectsTo=}` sections to ASCII fences;
2043
+ * positions run through the shared `computeDiagramLayout` so unpinned
2044
+ * children get the same grid placement as the legacy renderer.
2045
+ */
2046
+ declare function asciiDiagramFromBlocks(children: readonly Block[], options?: {
2047
+ style?: 'unicode' | 'ascii';
2048
+ }): AsciiDiagram;
2049
+
2050
+ /**
2051
+ * Public model for authored ASCII timelines.
2052
+ *
2053
+ * Source columns and rows are retained so separate tracks share one spatial
2054
+ * scale and pointer callouts can land between authored milestone dots. The
2055
+ * template mapping normalizes columns only at the final rendering boundary.
2056
+ */
2057
+ type AsciiTimelineStyle = 'unicode' | 'ascii';
2058
+ type AsciiTimelineSide = 'above' | 'below';
2059
+ type AsciiTimelineMarker = 'filled' | 'hollow' | 'diamond';
2060
+ interface AsciiTimelineEvent {
2061
+ /** Stable slug id, deduplicated across every track. */
2062
+ id: string;
2063
+ /** Short callout heading. */
2064
+ label: string;
2065
+ /** Optional longer callout/body text. */
2066
+ description?: string;
2067
+ /** Zero-based source-grid column of the event anchor. */
2068
+ column: number;
2069
+ /** Authored/default callout placement around the track. */
2070
+ side?: AsciiTimelineSide;
2071
+ /** Placement for `description` when it differs from the label side. */
2072
+ descriptionSide?: AsciiTimelineSide;
2073
+ /** False renders a cadence/tick point without a text callout. */
2074
+ callout?: boolean;
2075
+ /** Visual point vocabulary inferred from the authored marker. */
2076
+ marker?: AsciiTimelineMarker;
2077
+ }
2078
+ interface AsciiTimelineTrack {
2079
+ /** Stable track id. */
2080
+ id: string;
2081
+ /** Optional label shown to the left of the rendered track. */
2082
+ label?: string;
2083
+ /** Optional axis/end label authored after the terminal arrow. */
2084
+ endLabel?: string;
2085
+ /** Zero-based source row containing this track's horizontal axis. */
2086
+ row: number;
2087
+ /** Inclusive source-grid bounds of the axis. */
2088
+ startColumn: number;
2089
+ endColumn: number;
2090
+ events: AsciiTimelineEvent[];
2091
+ }
2092
+ interface AsciiTimelineLink {
2093
+ /** Source event id. */
2094
+ source: string;
2095
+ /** Target event id. */
2096
+ target: string;
2097
+ /** Optional branch/link label. */
2098
+ label?: string;
2099
+ }
2100
+ interface AsciiTimeline {
2101
+ tracks: AsciiTimelineTrack[];
2102
+ links: AsciiTimelineLink[];
2103
+ /** Source-grid dimensions, shared by every track. */
2104
+ width: number;
2105
+ height: number;
2106
+ style: AsciiTimelineStyle;
2107
+ /** Non-fatal parse notes (unresolved links, unlabeled events, and so on). */
2108
+ warnings: string[];
2109
+ }
2110
+ interface AsciiTimelineDetection {
2111
+ isTimeline: boolean;
2112
+ /** Present on acceptance so callers do not need to parse twice. */
2113
+ timeline?: AsciiTimeline;
2114
+ /** Machine-readable accept/reject reasons. */
2115
+ reasons: string[];
2116
+ }
2117
+
2118
+ /** ASCII timeline parser: horizontal tracks + point/callout art -> model. */
2119
+
2120
+ interface AsciiTimelineStats {
2121
+ axisLines: number;
2122
+ markerCount: number;
2123
+ strongMarkerCount: number;
2124
+ horizontalChars: number;
2125
+ pointerCount: number;
2126
+ branchDeclarations: number;
2127
+ /** True for high-confidence multi-lane flow art with a return edge. */
2128
+ wrappedFlow?: boolean;
2129
+ }
2130
+ declare function parseAsciiTimeline(text: string): AsciiTimeline;
2131
+ declare function parseAsciiTimelineWithStats(text: string): {
2132
+ timeline: AsciiTimeline;
2133
+ stats: AsciiTimelineStats;
2134
+ };
2135
+
2136
+ /**
2137
+ * ASCII timeline renderer: semantic tracks/events -> canonical timeline art.
2138
+ *
2139
+ * The canonical authored form keeps the rail visually continuous and moves
2140
+ * event payloads onto pointer callouts:
2141
+ *
2142
+ * ▲ T28 :: delta 28 {#t28 column=12}
2143
+ * Kernel {#kernel start=8 end=72}: ───●────────────────○────►
2144
+ * ▼ T29 {#t29 column=36}
2145
+ *
2146
+ * Links follow the tracks as declarations. This form is compact, readable in
2147
+ * raw Markdown, and is the exact grammar consumed by `parse.ts`. Rendering is
2148
+ * deterministic and normalizes parser-sensitive text/ids up front, so it is a
2149
+ * byte fixpoint after one render:
2150
+ *
2151
+ * renderAsciiTimeline(parseAsciiTimeline(renderAsciiTimeline(t))) ===
2152
+ * renderAsciiTimeline(t)
2153
+ */
2154
+
2155
+ interface RenderAsciiTimelineOptions {
2156
+ /** Character vocabulary; defaults to the timeline's detected style. */
2157
+ style?: AsciiTimelineStyle;
2158
+ }
2159
+ /** Render a timeline into deterministic, parser-canonical ASCII/Unicode art. */
2160
+ declare function renderAsciiTimeline(timeline: AsciiTimeline, options?: RenderAsciiTimelineOptions): string;
2161
+
2162
+ /** Conservative detection for authored ASCII timeline fences. */
2163
+
2164
+ declare const ASCII_TIMELINE_FENCE_LANGS: ReadonlySet<string>;
2165
+ declare function isEligibleAsciiTimelineFenceLang(lang: string | null | undefined): boolean;
2166
+ declare function isExplicitTimelineLang(lang: string | null | undefined): boolean;
2167
+ interface DetectAsciiTimelineOptions {
2168
+ /** Explicit `timeline` language: allow one-point/ASCII-marker tracks. */
2169
+ explicit?: boolean;
2170
+ }
2171
+ declare function detectAsciiTimeline(text: string, options?: DetectAsciiTimelineOptions): AsciiTimelineDetection;
2172
+ declare function isAsciiTimelineFence(node: MarkdownCodeBlock): boolean;
2173
+
2174
+ /** Mapping from source-grid timeline data to normalized template inputs. */
2175
+
2176
+ declare function asciiTimelineToTemplateData(timeline: AsciiTimeline): {
2177
+ tracks: TimelineTemplateTrack[];
2178
+ links: TimelineTemplateLink[];
2179
+ };
2180
+
2181
+ /**
2182
+ * Conservative parser for two-or-more-lane flow art whose last edge wraps
2183
+ * around the right margin. This dialect is common in AI-authored architecture
2184
+ * notes and sequence sketches:
2185
+ *
2186
+ * CLIENT KERNEL
2187
+ * ────── ──────
2188
+ * input ──► command ────► validate
2189
+ * ├─ invalid → rejected ─┐
2190
+ * surfaced ◄─────────────────────────────────────┘
2191
+ *
2192
+ * It is intentionally strict. Every nonblank row must be a heading,
2193
+ * underline, connector-only row, parenthetical continuation, or prose joined
2194
+ * by an explicit arrow. Accepted art is converted to the ordinary timeline
2195
+ * model, after which the canonical timeline renderer owns the authored form.
2196
+ */
2197
+
2198
+ /** Parse the wrapped-flow dialect, or return null without claiming the art. */
2199
+ declare function parseWrappedFlowTimeline(text: string): AsciiTimeline | null;
2200
+ /** High-confidence predicate used by the editor's lossless rewrite gate. */
2201
+ declare function isWrappedFlowTimelineSource(text: string): boolean;
2202
+
2203
+ /**
2204
+ * Public types for the ASCII treeview codec.
2205
+ *
2206
+ * A tree is a hierarchy of labelled nodes (file trees, dependency trees,
2207
+ * category outlines). Unlike the diagram codec's spatial grid model, the
2208
+ * tree model is a plain nested structure — rendering is a deterministic
2209
+ * tree-walk, so the parse↔render fixpoint is structural and trivially
2210
+ * byte-stable.
2211
+ */
2212
+ interface TreeNode {
2213
+ /**
2214
+ * Stable id: slug of the label, deduplicated with `-2`/`-3` suffixes in
2215
+ * document (depth-first) order. Identical art re-parses to identical ids
2216
+ * (the outline widget's selection resolves by id).
2217
+ */
2218
+ id: string;
2219
+ /** Display label, verbatim (may keep a trailing `/`). */
2220
+ label: string;
2221
+ /** Child nodes (empty for leaves). */
2222
+ children: TreeNode[];
2223
+ /** True when this node reads as a container (trailing `/` or has children). */
2224
+ isDir?: boolean;
2225
+ /** Trailing `# …` / `<-- …` comment, preserved across round-trips. */
2226
+ comment?: string;
2227
+ }
2228
+ interface Tree {
2229
+ /** Top-level nodes (a forest — usually one root for a file tree). */
2230
+ roots: TreeNode[];
2231
+ /** Character vocabulary detected in the source; render emits the same. */
2232
+ style: 'unicode' | 'ascii';
2233
+ /** Non-fatal parse notes (ragged dedents, dropped lines, …). */
2234
+ warnings: string[];
2235
+ }
2236
+ interface TreeDetection {
2237
+ isTree: boolean;
2238
+ /** Present when `isTree` — avoids a second parse in callers. */
2239
+ tree?: Tree;
2240
+ /** Machine-greppable accept/reject reasons. */
2241
+ reasons: string[];
2242
+ }
2243
+
2244
+ /**
2245
+ * ASCII tree parser: file-tree / outline art → nested nodes.
2246
+ *
2247
+ * Pure, deterministic, never throws. Handles the many renditions AI emits:
2248
+ * Unicode connectors (`├── `/`└── `/`│ `), ASCII (`|-- `/`` `-- ``/`+-- `),
2249
+ * bullet-indented (`- `/`* `), and pure indentation. Depth is recovered by
2250
+ * finding where each line's LABEL begins (after any connector/indent
2251
+ * prefix) and running the standard outline indent-stack — this unifies all
2252
+ * renditions and tolerates ragged dedents.
2253
+ */
2254
+
2255
+ declare function parseTree(text: string): Tree;
2256
+
2257
+ /**
2258
+ * ASCII tree renderer: nested nodes → clean tree art.
2259
+ *
2260
+ * A deterministic depth-first walk emitting rail/branch prefixes. The
2261
+ * fixpoint is structural: `parseTree(renderTree(t))` preserves the node
2262
+ * hierarchy + labels + comments, and `renderTree(parseTree(renderTree(t)))`
2263
+ * is byte-identical (idempotent after one normalization cycle). Unlike the
2264
+ * diagram renderer there is no spatial layout, so jitter is impossible.
2265
+ */
2266
+
2267
+ interface RenderTreeOptions {
2268
+ /** Character vocabulary; defaults to the tree's own detected style. */
2269
+ style?: 'unicode' | 'ascii';
2270
+ }
2271
+ declare function renderTree(tree: Tree, options?: RenderTreeOptions): string;
2272
+
2273
+ /**
2274
+ * ASCII tree detection: is this fence content a file-tree / outline?
2275
+ *
2276
+ * The mirror image of the diagram detector. A diagram has ≥2 closed boxes;
2277
+ * a tree has ZERO closed boxes plus connector-branch structure. The two
2278
+ * partition the `├──` glyph space cleanly, so a fence is at most one of
2279
+ * them. Auto-detection is deliberately conservative (requires connector
2280
+ * branches — the unambiguous AI file-tree signal); the parser still handles
2281
+ * pure-indentation renditions for explicitly `{[tree]}`-annotated fences.
2282
+ */
2283
+
2284
+ /** Fence languages eligible for tree detection (plus no language at all). */
2285
+ declare const TREE_FENCE_LANGS: ReadonlySet<string>;
2286
+ declare function isEligibleTreeFenceLang(lang: string | null | undefined): boolean;
2287
+ /**
2288
+ * True when the fence LANGUAGE is the explicit `tree` tag — an author-set
2289
+ * "this is a tree" marker that survives markdown ↔ Tiptap round-trips (the
2290
+ * language class round-trips; fence meta does not). Detection of a tagged
2291
+ * fence is lenient (no connector requirement) so a flattened/degenerate
2292
+ * tree stays a tree.
2293
+ */
2294
+ declare function isExplicitTreeLang(lang: string | null | undefined): boolean;
2295
+ interface DetectTreeOptions {
2296
+ /** The fence is explicitly `tree`-tagged: skip the connector requirement. */
2297
+ explicit?: boolean;
2298
+ }
2299
+ declare function detectTree(text: string, opts?: DetectTreeOptions): TreeDetection;
2300
+ /** Convenience gate for pipeline callers: lang allowlist + content detection. */
2301
+ declare function isTreeFence(node: MarkdownCodeBlock): boolean;
2302
+
2303
+ /**
2304
+ * Mapping between the tree model and the template/layer data model, plus a
2305
+ * nested-markdown-list → tree walker (none exists in core — `extractListItems`
2306
+ * flattens, losing depth).
2307
+ */
2308
+
2309
+ /** JSON-serializable tree item carried on `templateData.items` / a `TreeLayer`. */
2310
+ interface TreeItem {
2311
+ id: string;
2312
+ label: string;
2313
+ isDir?: boolean;
2314
+ comment?: string;
2315
+ children: TreeItem[];
2316
+ }
2317
+ /** Tree model → template/layer items (structure-preserving). */
2318
+ declare function treeToTemplateData(tree: Tree): {
2319
+ items: TreeItem[];
2320
+ };
2321
+ /** Template/layer items → tree model (editor write-back / render). */
2322
+ declare function treeFromTemplateData(items: readonly TreeItem[], options?: {
2323
+ style?: 'unicode' | 'ascii';
2324
+ }): Tree;
2325
+ /**
2326
+ * Recursively convert a nested markdown bullet list into a tree. Used by
2327
+ * `deriveTemplateInputs` when an author explicitly `{[tree]}`-annotates a
2328
+ * block whose body is a nested list rather than a fence.
2329
+ */
2330
+ declare function treeFromMarkdownList(list: MarkdownList): Tree;
2331
+ /** Find the first top-level markdown list in a block's body, if any. */
2332
+ declare function findFirstList(contents: MarkdownBlockNode[] | undefined): MarkdownList | undefined;
2333
+
2334
+ export { ASCII_CHAR_H, ASCII_CHAR_W, ASCII_DIAGRAM_FENCE_LANGS, ASCII_TIMELINE_FENCE_LANGS, type AccentLayout, type AsciiDiagram, type AsciiDiagramDetection, type AsciiDiagramEdge, type AsciiDiagramNode, type AsciiTimeline, type AsciiTimelineDetection, type AsciiTimelineEvent, type AsciiTimelineLink, type AsciiTimelineMarker, type AsciiTimelineSide, type AsciiTimelineStats, type AsciiTimelineStyle, type AsciiTimelineTrack, type AudioSegmentTiming, BASE_INPUT_DESCRIPTORS, type BlockLayerMaterialization, CONTAINER_TEMPLATES, type ClipBox, type ConnectorAnchor, type ConnectorPort, type ConnectorRouting, type ConnectorSnapPoint, type CoverBlockInput, DEFAULT_LAYOUT, DIAGRAM_LABEL_HORIZONTAL_PADDING, DIAGRAM_LABEL_LINE_HEIGHT, DIAGRAM_LABEL_MIN_FONT_SIZE, DIAGRAM_LABEL_VERTICAL_PADDING, type DataFenceParseResult, type DeriveTemplateInputsOptions, type DetectAsciiTimelineOptions, type DiagramEdge, type DiagramLabelFit, type DiagramLayout, type DiagramLayoutOptions, type DiagramNodePosition, DocBlock, type DrawingConnector, type DrawingLayout, type DrawingLayoutOptions, type DrawingShape, type DrawingShapeKind, type ExpandDocBlocksOptions, type ExtractedTableData, type FirstImage, type InputCoercion, type LayerMaterializationDiagnostic, type LayerMaterializationFailureMode, type LayerMaterializationSource, type LayoutLayerDefaults, type LayoutLayersResult, type MarkdownToDocOptions, type MarkdownValidationResult, type MaterializeBlockLayersOptions, type NarrationResolution, PATH_SHAPE_KINDS, PersistentLayerConfig, type RenderAsciiDiagramOptions, type RenderAsciiTimelineOptions, type RenderTreeOptions, type RepairResult, type RuntimeTemplateRegistry, SHAPE_NAMES, TEMPLATE_INPUT_DESCRIPTORS, TEMPLATE_METADATA, TREE_FENCE_LANGS, TemplateBlock, TemplateContext, type TemplateInputDescriptor, type TemplateMetadata, type TemplateParamFinding, Theme, ThemeColorScheme, type Tree, type TreeDetection, type TreeItem, type TreeNode, type ValidateOptions, ViewportConfig, adjustY, anchorPoint, applyNarrationTiming, applyRenderStyleToLayers, asciiCellToCanvas, asciiDiagramFromBlocks, asciiDiagramFromTemplateData, asciiDiagramToTemplateData, asciiTimelineToTemplateData, buildRegistry, canvasToAsciiCell, clipEndpoints, clipPoint, coerceTemplateParams, comparisonBar, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, countBlocks, coverBlock, createAccentLayers, cssFilterForTreatment, dataTable, dateEvent, definitionCard, deriveTemplateInputs, detectAsciiDiagram, detectAsciiTimeline, detectTree, diagramBlock, docToMarkdown, drawingBlock, expandCoverBlock, expandDocBlocks, expandPersistentLayers, extractBlockquoteText, extractBodyPlainText, extractFirstImage, extractImages, extractListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstList, findFirstTable, fitDiagramLabel, flattenBlocks, flattenRenderableBlocks, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockBodyText, getBlockDepth, getDefaultAnimation, getDefaultAnimationDuration, getOverlayOpacity, getPersistentLayersFromTheme, getPinnedBlockMeta, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isAsciiDiagramFence, isAsciiTimelineFence, isContainerTemplate, isDataFence, isEligibleAsciiFenceLang, isEligibleAsciiTimelineFenceLang, isEligibleTreeFenceLang, isExplicitDiagramLang, isExplicitTimelineLang, isExplicitTreeLang, isRepairableDiagram, isShapeName, isTreeFence, isWrappedFlowTimelineSource, layoutBlock, leftFeature, lineStyleDasharray, lintTemplateParams, listBlock, mapBlock, markdownToDoc, markerPath, materializeBlockLayers, nearestSnapPoint, normalizeShapeKind, parseAsciiDiagram, parseAsciiTimeline, parseAsciiTimelineWithStats, parseDataFence, parseTree, parseWrappedFlowTimeline, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, renderAsciiDiagram, renderAsciiTimeline, renderTree, repairAsciiDiagram, replaceDataFence, resolveAudioMapping, resolveColorScheme, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionHeader, shapePath, shouldUseShadow, snapEndpoints, snapPoints, statHighlight, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, timelineBlock, titleBlock, treeBlock, treeFromMarkdownList, treeFromTemplateData, treeToTemplateData, twoColumn, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter };