kitfly 0.1.2 → 0.2.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 (194) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +63 -16
  3. package/VERSION +1 -1
  4. package/dist/_raw/content/deployment/preflight.md +134 -0
  5. package/dist/_raw/content/deployment/recipes/aws-s3.md +128 -0
  6. package/dist/_raw/content/deployment/recipes/cloudflare-pages.md +73 -0
  7. package/dist/_raw/content/deployment/recipes/cloudflare-r2.md +156 -0
  8. package/dist/_raw/content/deployment/recipes/fly-io.md +57 -0
  9. package/dist/_raw/content/deployment/recipes/github-pages.md +112 -0
  10. package/dist/_raw/content/deployment/recipes/netlify.md +99 -0
  11. package/dist/_raw/content/deployment/recipes/vercel.md +88 -0
  12. package/dist/_raw/content/deployment/secrets-and-env-vars.md +75 -0
  13. package/dist/_raw/content/deployment.md +128 -0
  14. package/dist/_raw/content/guide/approaches.md +182 -0
  15. package/dist/_raw/content/guide/features.md +121 -0
  16. package/dist/_raw/content/guide/getting-started.md +112 -0
  17. package/dist/_raw/content/guide/kitfly-overview.md +209 -0
  18. package/dist/_raw/content/reference/configuration.md +259 -0
  19. package/dist/_raw/content/reference/design-catalog.md +167 -0
  20. package/dist/_raw/content/reference/environment-variables.md +66 -0
  21. package/dist/_raw/content/reference/glossary.md +92 -0
  22. package/dist/_raw/content/reference/key-concepts.md +118 -0
  23. package/dist/_raw/content/reference/plugins.md +220 -0
  24. package/dist/_raw/content/reference/structure.md +166 -0
  25. package/dist/_raw/content/reference.md +19 -0
  26. package/dist/_raw/content/templates/crucible.md +192 -0
  27. package/dist/_raw/content/templates/handbook.md +83 -0
  28. package/dist/_raw/content/templates/minimal.md +138 -0
  29. package/dist/_raw/content/templates/overview.md +187 -0
  30. package/dist/_raw/content/templates/pipeline.md +151 -0
  31. package/dist/_raw/content/templates/productbook.md +187 -0
  32. package/dist/_raw/content/templates/runbook.md +193 -0
  33. package/dist/_raw/content/templates/servicebook.md +163 -0
  34. package/dist/_raw/docs/decisions/ADR-0001-minimalist-site-code.md +118 -0
  35. package/dist/_raw/docs/decisions/ADR-0002-ai-accessibility.md +153 -0
  36. package/dist/_raw/docs/decisions/ADR-0003-single-file-bundle.md +93 -0
  37. package/dist/_raw/docs/decisions/ADR-0004-bun-runtime.md +98 -0
  38. package/dist/_raw/docs/decisions/ADR-0005-plugin-contract-and-distribution.md +110 -0
  39. package/dist/_raw/docs/decisions/DDR-0001-viewport-locked-layout.md +111 -0
  40. package/dist/_raw/docs/decisions/DDR-0002-theme-system.md +131 -0
  41. package/dist/_raw/docs/decisions/DDR-0003-bounded-logo-slot.md +106 -0
  42. package/dist/_raw/docs/decisions/DDR-0004-slides-rendering-model.md +113 -0
  43. package/dist/_raw/docs/decisions/DDR-0005-deterministic-layout-boundary.md +107 -0
  44. package/dist/_raw/docs/userguide/cli/build.md +85 -0
  45. package/dist/_raw/docs/userguide/cli/bundle.md +81 -0
  46. package/dist/_raw/docs/userguide/cli/dev.md +92 -0
  47. package/dist/_raw/docs/userguide/cli/init.md +116 -0
  48. package/dist/_raw/docs/userguide/cli/servers.md +69 -0
  49. package/dist/_raw/docs/userguide/cli/stop.md +76 -0
  50. package/dist/_raw/docs/userguide/cli/update.md +78 -0
  51. package/dist/_raw/docs/userguide/cli/version.md +65 -0
  52. package/dist/_raw/docs/userguide/cli.md +34 -0
  53. package/dist/_raw/docs/userguide/sharing.md +94 -0
  54. package/dist/_raw/schemas/plugin-schemas-notes.md +71 -0
  55. package/dist/_raw/schemas.md +42 -0
  56. package/dist/assets/brand/kitfly-favicon-32.png +0 -0
  57. package/dist/assets/brand/kitfly-icon-64.png +0 -0
  58. package/dist/assets/brand/kitfly-logo-128.png +0 -0
  59. package/dist/assets/brand/kitfly-logo-512.png +0 -0
  60. package/dist/assets/brand/kitfly-logo.svg +12132 -0
  61. package/dist/assets/brand/kitfly-neon-128.png +0 -0
  62. package/dist/assets/brand/kitfly-neon-192.png +0 -0
  63. package/dist/assets/brand/kitfly-neon-256.png +0 -0
  64. package/dist/assets/brand/kitfly-neon.png +0 -0
  65. package/dist/assets/brand/palette.md +75 -0
  66. package/dist/content/deployment/index.html +11 -0
  67. package/dist/content/deployment/preflight.html +418 -0
  68. package/dist/content/deployment/recipes/aws-s3.html +421 -0
  69. package/dist/content/deployment/recipes/cloudflare-pages.html +372 -0
  70. package/dist/content/deployment/recipes/cloudflare-r2.html +443 -0
  71. package/dist/content/deployment/recipes/fly-io.html +356 -0
  72. package/dist/content/deployment/recipes/github-pages.html +414 -0
  73. package/dist/content/deployment/recipes/index.html +11 -0
  74. package/dist/content/deployment/recipes/netlify.html +394 -0
  75. package/dist/content/deployment/recipes/vercel.html +382 -0
  76. package/dist/content/deployment/secrets-and-env-vars.html +380 -0
  77. package/dist/content/deployment.html +426 -0
  78. package/dist/content/guide/approaches.html +501 -0
  79. package/dist/content/guide/features.html +436 -0
  80. package/dist/content/guide/getting-started.html +403 -0
  81. package/dist/content/guide/index.html +11 -0
  82. package/dist/content/guide/kitfly-overview.html +544 -0
  83. package/dist/content/index.html +11 -0
  84. package/dist/content/reference/configuration.html +580 -0
  85. package/dist/content/reference/design-catalog.html +449 -0
  86. package/dist/content/reference/environment-variables.html +367 -0
  87. package/dist/content/reference/glossary.html +368 -0
  88. package/dist/content/reference/index.html +11 -0
  89. package/dist/content/reference/key-concepts.html +399 -0
  90. package/dist/content/reference/plugins.html +491 -0
  91. package/dist/content/reference/structure.html +463 -0
  92. package/dist/content/reference.html +334 -0
  93. package/dist/content/templates/crucible.html +546 -0
  94. package/dist/content/templates/handbook.html +405 -0
  95. package/dist/content/templates/index.html +11 -0
  96. package/dist/content/templates/minimal.html +447 -0
  97. package/dist/content/templates/overview.html +558 -0
  98. package/dist/content/templates/pipeline.html +494 -0
  99. package/dist/content/templates/productbook.html +540 -0
  100. package/dist/content/templates/runbook.html +543 -0
  101. package/dist/content/templates/servicebook.html +523 -0
  102. package/dist/content-index.json +540 -0
  103. package/dist/docs/decisions/ADR-0001-minimalist-site-code.html +491 -0
  104. package/dist/docs/decisions/ADR-0002-ai-accessibility.html +434 -0
  105. package/dist/docs/decisions/ADR-0003-single-file-bundle.html +412 -0
  106. package/dist/docs/decisions/ADR-0004-bun-runtime.html +409 -0
  107. package/dist/docs/decisions/ADR-0005-plugin-contract-and-distribution.html +402 -0
  108. package/dist/docs/decisions/DDR-0001-viewport-locked-layout.html +459 -0
  109. package/dist/docs/decisions/DDR-0002-theme-system.html +452 -0
  110. package/dist/docs/decisions/DDR-0003-bounded-logo-slot.html +423 -0
  111. package/dist/docs/decisions/DDR-0004-slides-rendering-model.html +399 -0
  112. package/dist/docs/decisions/DDR-0005-deterministic-layout-boundary.html +422 -0
  113. package/dist/docs/decisions/index.html +11 -0
  114. package/dist/docs/userguide/cli/build.html +408 -0
  115. package/dist/docs/userguide/cli/bundle.html +419 -0
  116. package/dist/docs/userguide/cli/dev.html +428 -0
  117. package/dist/docs/userguide/cli/index.html +11 -0
  118. package/dist/docs/userguide/cli/init.html +436 -0
  119. package/dist/docs/userguide/cli/servers.html +393 -0
  120. package/dist/docs/userguide/cli/stop.html +408 -0
  121. package/dist/docs/userguide/cli/update.html +406 -0
  122. package/dist/docs/userguide/cli/version.html +406 -0
  123. package/dist/docs/userguide/cli.html +386 -0
  124. package/dist/docs/userguide/index.html +11 -0
  125. package/dist/docs/userguide/sharing.html +465 -0
  126. package/dist/index.html +387 -0
  127. package/dist/llms.txt +18 -0
  128. package/dist/provenance.json +7 -0
  129. package/dist/schemas/index.html +11 -0
  130. package/dist/schemas/plugin-registry.schema.html +327 -0
  131. package/dist/schemas/plugin-schemas-notes.html +364 -0
  132. package/dist/schemas/plugin.schema.html +327 -0
  133. package/dist/schemas/plugins.schema.html +327 -0
  134. package/dist/schemas/v0/common.schema.html +386 -0
  135. package/dist/schemas/v0/index.html +11 -0
  136. package/dist/schemas/v0/plugin-registry.schema.html +547 -0
  137. package/dist/schemas/v0/plugin.schema.html +497 -0
  138. package/dist/schemas/v0/plugins.schema.html +406 -0
  139. package/dist/schemas/v0/site.schema.html +541 -0
  140. package/dist/schemas/v0/theme.schema.html +615 -0
  141. package/dist/schemas.html +351 -0
  142. package/dist/styles.css +1262 -0
  143. package/package.json +4 -2
  144. package/plugins-dist/callouts.css +32 -0
  145. package/plugins-dist/callouts.js +46 -0
  146. package/plugins-dist/slides-visuals.css +224 -0
  147. package/plugins-dist/slides-visuals.js +598 -0
  148. package/registry/plugins.yaml +35 -0
  149. package/schemas/README.md +10 -0
  150. package/schemas/plugin-registry.schema.json +5 -0
  151. package/schemas/plugin-schemas-notes.md +71 -0
  152. package/schemas/plugin.schema.json +5 -0
  153. package/schemas/plugins.schema.json +5 -0
  154. package/schemas/v0/common.schema.json +64 -0
  155. package/schemas/v0/plugin-registry.schema.json +225 -0
  156. package/schemas/v0/plugin.schema.json +175 -0
  157. package/schemas/v0/plugins.schema.json +84 -0
  158. package/schemas/v0/site.schema.json +56 -9
  159. package/schemas/v0/theme.schema.json +105 -22
  160. package/scripts/build.ts +155 -3
  161. package/scripts/bundle.ts +258 -95
  162. package/scripts/dev.ts +203 -1
  163. package/src/__tests__/build.test.ts +158 -1
  164. package/src/__tests__/bundle.test.ts +31 -0
  165. package/src/__tests__/cli.test.ts +14 -3
  166. package/src/__tests__/fixtures/fences/slides-visuals/invalid/bad-list-indent.md +5 -0
  167. package/src/__tests__/fixtures/fences/slides-visuals/invalid/blank-line.md +5 -0
  168. package/src/__tests__/fixtures/fences/slides-visuals/invalid/compare-object-items.md +9 -0
  169. package/src/__tests__/fixtures/fences/slides-visuals/invalid/indented-fence.md +4 -0
  170. package/src/__tests__/fixtures/fences/slides-visuals/invalid/stat-grid-missing-fields.md +5 -0
  171. package/src/__tests__/fixtures/fences/slides-visuals/invalid/unknown-type.md +3 -0
  172. package/src/__tests__/fixtures/fences/slides-visuals/valid/compare.md +10 -0
  173. package/src/__tests__/fixtures/fences/slides-visuals/valid/comparison-table.md +14 -0
  174. package/src/__tests__/fixtures/fences/slides-visuals/valid/funnel.md +7 -0
  175. package/src/__tests__/fixtures/fences/slides-visuals/valid/kpi.md +5 -0
  176. package/src/__tests__/fixtures/fences/slides-visuals/valid/layer-cake.md +6 -0
  177. package/src/__tests__/fixtures/fences/slides-visuals/valid/pyramid.md +6 -0
  178. package/src/__tests__/fixtures/fences/slides-visuals/valid/quadrant-grid.md +8 -0
  179. package/src/__tests__/fixtures/fences/slides-visuals/valid/scorecard.md +13 -0
  180. package/src/__tests__/fixtures/fences/slides-visuals/valid/stat-grid.md +8 -0
  181. package/src/__tests__/init.test.ts +35 -0
  182. package/src/__tests__/plugin-loader.test.ts +221 -0
  183. package/src/__tests__/shared.test.ts +428 -0
  184. package/src/__tests__/slides-visuals-fence-contract.test.ts +28 -0
  185. package/src/__tests__/slides-visuals-runtime-regressions.bun.test.ts +114 -0
  186. package/src/__tests__/styles.test.ts +35 -0
  187. package/src/cli.ts +9 -4
  188. package/src/plugin-loader.ts +245 -0
  189. package/src/shared.ts +614 -7
  190. package/src/site/styles.css +331 -0
  191. package/src/site/template.html +66 -5
  192. package/src/templates/deck.ts +186 -0
  193. package/src/templates/driver.ts +11 -1
  194. package/src/templates/minimal.ts +1 -0
@@ -0,0 +1,422 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DDR-0005: Deterministic Layout Boundary - Kitfly Docs</title>
7
+ <link rel="icon" type="image/png" sizes="32x32" href="../../assets/brand/kitfly-favicon-32.png">
8
+ <link rel="icon" type="image/png" sizes="64x64" href="../../assets/brand/kitfly-neon-256.png">
9
+ <link rel="stylesheet" href="../../styles.css">
10
+ <style id="kitfly-theme">
11
+ :root { --color-bg: #ffffff;
12
+ --color-bg-sidebar: #f5f7f8;
13
+ --color-text: #374151;
14
+ --color-text-muted: #6b7280;
15
+ --color-border: #e5e7eb;
16
+ --color-link: #007182;
17
+ --color-link-hover: #0a6172;
18
+ --color-accent: #152F46;
19
+ --color-code-bg: #f5f7f8;
20
+ --color-logo: #152F46;
21
+ --sidebar-width: 280px;
22
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
23
+ --font-headings: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
24
+ --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
25
+ html { font-size: 16px; }
26
+ @media (prefers-color-scheme: dark) {
27
+ :root:not([data-theme="light"]) { --color-bg: #0d1117;
28
+ --color-bg-sidebar: #152F46;
29
+ --color-text: #e5e7eb;
30
+ --color-text-muted: #9ca3af;
31
+ --color-border: #374151;
32
+ --color-link: #709EA6;
33
+ --color-link-hover: #8fb5bc;
34
+ --color-accent: #f9fafb;
35
+ --color-code-bg: #152F46;
36
+ --color-logo: #f9fafb; }
37
+ }
38
+ [data-theme="dark"] { --color-bg: #0d1117;
39
+ --color-bg-sidebar: #152F46;
40
+ --color-text: #e5e7eb;
41
+ --color-text-muted: #9ca3af;
42
+ --color-border: #374151;
43
+ --color-link: #709EA6;
44
+ --color-link-hover: #8fb5bc;
45
+ --color-accent: #f9fafb;
46
+ --color-code-bg: #152F46;
47
+ --color-logo: #f9fafb; }
48
+ [data-theme="light"] { --color-bg: #ffffff;
49
+ --color-bg-sidebar: #f5f7f8;
50
+ --color-text: #374151;
51
+ --color-text-muted: #6b7280;
52
+ --color-border: #e5e7eb;
53
+ --color-link: #007182;
54
+ --color-link-hover: #0a6172;
55
+ --color-accent: #152F46;
56
+ --color-code-bg: #f5f7f8;
57
+ --color-logo: #152F46;
58
+ --sidebar-width: 280px;
59
+ --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
60
+ --font-headings: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
61
+ --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
62
+ </style>
63
+ <!-- Syntax highlighting - Prism.js -->
64
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1/themes/prism.min.css" id="prism-light">
65
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1/themes/prism-okaidia.min.css" id="prism-dark" disabled>
66
+
67
+ <script>
68
+ // Apply saved theme immediately to prevent flash
69
+ (function() {
70
+ const saved = localStorage.getItem('theme');
71
+ if (saved) {
72
+ document.documentElement.setAttribute('data-theme', saved);
73
+ }
74
+ // Set Prism theme based on saved or system preference
75
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
76
+ const isDark = saved === 'dark' || (!saved && prefersDark);
77
+ if (isDark) {
78
+ document.getElementById('prism-light')?.setAttribute('disabled', '');
79
+ document.getElementById('prism-dark')?.removeAttribute('disabled');
80
+ }
81
+ })();
82
+ </script>
83
+ </head>
84
+ <body class="mode-docs">
85
+ <div class="mobile-header">
86
+ <button class="nav-toggle" onclick="toggleNav()" aria-label="Toggle navigation">
87
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
88
+ <path d="M3 12h18M3 6h18M3 18h18"/>
89
+ </svg>
90
+ </button>
91
+ <a href="../../" class="mobile-logo" title="Home" data-initial="K">
92
+ <img src="../../assets/brand/kitfly-neon-256.png" alt="Kitfly" class="logo-img logo-icon" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
93
+ </a>
94
+ <button class="mobile-theme-toggle" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
95
+ <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
96
+ <circle cx="12" cy="12" r="5"/>
97
+ <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
98
+ </svg>
99
+ <svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
100
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
101
+ </svg>
102
+ </button>
103
+ </div>
104
+ <div class="layout">
105
+ <nav class="sidebar">
106
+ <div class="sidebar-header">
107
+ <div class="logo logo-icon">
108
+ <a href="/" class="logo-icon" data-initial="K">
109
+ <img src="../../assets/brand/kitfly-neon-256.png" alt="Kitfly" class="logo-img" onerror="this.onerror=null;this.style.display='none';this.parentElement.classList.add('logo-fallback')"/>
110
+ </a>
111
+ <span class="logo-text">
112
+ <a href="/" class="brand">Kitfly</a>
113
+ <a href="../../" class="product">Kitfly Docs</a>
114
+ </span>
115
+ </div>
116
+ <div class="header-tools">
117
+ <button class="theme-toggle" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
118
+ <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
119
+ <circle cx="12" cy="12" r="5"/>
120
+ <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
121
+ </svg>
122
+ <svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
123
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
124
+ </svg>
125
+ </button>
126
+ <div class="sidebar-meta">
127
+ <span class="meta-version">v0.2.0</span>
128
+ <span class="meta-branch">HEAD</span>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ <div class="sidebar-nav">
133
+ <ul><li><a href="../../index.html" class="nav-home">Home</a></li><li><span class="nav-section">Guide</span><ul><li><a href="../../content/guide/approaches.html">approaches</a></li><li><a href="../../content/guide/features.html">features</a></li><li><a href="../../content/guide/getting-started.html">getting-started</a></li><li><a href="../../content/guide/kitfly-overview.html">kitfly-overview</a></li></ul></li><li><span class="nav-section">Templates</span><ul><li><a href="../../content/templates/crucible.html">crucible</a></li><li><a href="../../content/templates/handbook.html">handbook</a></li><li><a href="../../content/templates/minimal.html">minimal</a></li><li><a href="../../content/templates/overview.html">overview</a></li><li><a href="../../content/templates/pipeline.html">pipeline</a></li><li><a href="../../content/templates/productbook.html">productbook</a></li><li><a href="../../content/templates/runbook.html">runbook</a></li><li><a href="../../content/templates/servicebook.html">servicebook</a></li></ul></li><li><a href="../../content/reference.html" class="nav-section">Reference</a><ul><li><a href="../../content/reference/configuration.html">configuration</a></li><li><a href="../../content/reference/design-catalog.html">design-catalog</a></li><li><a href="../../content/reference/environment-variables.html">environment-variables</a></li><li><a href="../../content/reference/glossary.html">glossary</a></li><li><a href="../../content/reference/key-concepts.html">key-concepts</a></li><li><a href="../../content/reference/plugins.html">plugins</a></li><li><a href="../../content/reference/structure.html">structure</a></li></ul></li><li><a href="../../content/deployment.html" class="nav-section">Deployment</a><ul><li><a href="../../content/deployment/preflight.html">preflight</a></li><li><details><summary class="nav-group">recipes</summary><ul><li><a href="../../content/deployment/recipes/aws-s3.html">aws-s3</a></li><li><a href="../../content/deployment/recipes/cloudflare-pages.html">cloudflare-pages</a></li><li><a href="../../content/deployment/recipes/cloudflare-r2.html">cloudflare-r2</a></li><li><a href="../../content/deployment/recipes/fly-io.html">fly-io</a></li><li><a href="../../content/deployment/recipes/github-pages.html">github-pages</a></li><li><a href="../../content/deployment/recipes/netlify.html">netlify</a></li><li><a href="../../content/deployment/recipes/vercel.html">vercel</a></li></ul></details></li><li><a href="../../content/deployment/secrets-and-env-vars.html">secrets-and-env-vars</a></li></ul></li><li><span class="nav-section">User Guide</span><ul><li><details><summary class="nav-group"><a href="../../docs/userguide/cli.html">cli</a></summary><ul><li><a href="../../docs/userguide/cli/build.html">build</a></li><li><a href="../../docs/userguide/cli/bundle.html">bundle</a></li><li><a href="../../docs/userguide/cli/dev.html">dev</a></li><li><a href="../../docs/userguide/cli/init.html">init</a></li><li><a href="../../docs/userguide/cli/servers.html">servers</a></li><li><a href="../../docs/userguide/cli/stop.html">stop</a></li><li><a href="../../docs/userguide/cli/update.html">update</a></li><li><a href="../../docs/userguide/cli/version.html">version</a></li></ul></details></li><li><a href="../../docs/userguide/sharing.html">sharing</a></li></ul></li><li><span class="nav-section">Decisions</span><ul><li><a href="../../docs/decisions/ADR-0001-minimalist-site-code.html">ADR-0001-minimalist-site-code</a></li><li><a href="../../docs/decisions/ADR-0002-ai-accessibility.html">ADR-0002-ai-accessibility</a></li><li><a href="../../docs/decisions/ADR-0003-single-file-bundle.html">ADR-0003-single-file-bundle</a></li><li><a href="../../docs/decisions/ADR-0004-bun-runtime.html">ADR-0004-bun-runtime</a></li><li><a href="../../docs/decisions/ADR-0005-plugin-contract-and-distribution.html">ADR-0005-plugin-contract-and-distribution</a></li><li><a href="../../docs/decisions/DDR-0001-viewport-locked-layout.html">DDR-0001-viewport-locked-layout</a></li><li><a href="../../docs/decisions/DDR-0002-theme-system.html">DDR-0002-theme-system</a></li><li><a href="../../docs/decisions/DDR-0003-bounded-logo-slot.html">DDR-0003-bounded-logo-slot</a></li><li><a href="../../docs/decisions/DDR-0004-slides-rendering-model.html">DDR-0004-slides-rendering-model</a></li><li><a href="../../docs/decisions/DDR-0005-deterministic-layout-boundary.html" class="active">DDR-0005-deterministic-layout-boundary</a></li></ul></li><li><a href="../../schemas.html" class="nav-section">Schemas</a><ul><li><a href="../../schemas/plugin-registry.schema.html">plugin-registry.schema</a></li><li><a href="../../schemas/plugin-schemas-notes.html">plugin-schemas-notes</a></li><li><a href="../../schemas/plugin.schema.html">plugin.schema</a></li><li><a href="../../schemas/plugins.schema.html">plugins.schema</a></li><li><details><summary class="nav-group">v0</summary><ul><li><a href="../../schemas/v0/common.schema.html">common.schema</a></li><li><a href="../../schemas/v0/plugin-registry.schema.html">plugin-registry.schema</a></li><li><a href="../../schemas/v0/plugin.schema.html">plugin.schema</a></li><li><a href="../../schemas/v0/plugins.schema.html">plugins.schema</a></li><li><a href="../../schemas/v0/site.schema.html">site.schema</a></li><li><a href="../../schemas/v0/theme.schema.html">theme.schema</a></li></ul></details></li></ul></li></ul>
134
+ </div>
135
+ </nav>
136
+ <main class="content">
137
+ <article class="prose">
138
+ <nav class="breadcrumbs"><a href="../../docs/userguide/cli/build.html">Docs</a><span class="separator">›</span><a href="../../docs/decisions/ADR-0001-minimalist-site-code.html">Decisions</a><span class="separator">›</span><span>DDR-0005-deterministic-layout-boundary</span></nav>
139
+
140
+ <h1 id="ddr-0005-deterministic-layout-boundary">DDR-0005: Deterministic Layout Boundary</h1>
141
+ <h2 id="status">Status</h2>
142
+ <p>Proposed</p>
143
+ <h2 id="context">Context</h2>
144
+ <p>Kitfly generates slidesites — fixed-aspect pages that are not “infinite scroll” documents. A key use case is AI agents generating presentation-quality slides, including infographic-style layouts with shapes, connectors, and composed visual patterns. (If content is long, it may scroll <em>within</em> the slide frame; the page layout remains slide-like.)</p>
145
+ <p>Kitfly is not trying to recreate diagram engines like Mermaid or PlantUML. Those tools compute layout from relationships, which is powerful but hard to control precisely in slide composition and hard for agents to predict.</p>
146
+ <p>We need to decide how far to push CSS-based shapes and figures before delegating to diagram engines. The risk on one side is rebuilding a diagram engine inside CSS; the risk on the other is forcing all visual compositions through tools whose auto-layout is difficult for agents to control precisely.</p>
147
+ <h3 id="observed-problems">Observed Problems</h3>
148
+ <ol>
149
+ <li><strong>Mermaid/PlantUML alignment</strong> — Auto-layout engines optimize for their own constraints. Achieving pixel-precise placement within a slide&#39;s visual design is unreliable. Agents cannot predict where nodes will land.</li>
150
+ <li><strong>Agent reasoning</strong> — AI agents generate better results when they can specify placement explicitly (&quot;put X at grid position 2,1&quot;) rather than describing relationships and hoping the layout engine produces the desired visual.</li>
151
+ <li><strong>Scope creep</strong> — Without a clear boundary, CSS primitives could grow into a general-purpose diagramming system, duplicating work better handled by existing engines.</li>
152
+ </ol>
153
+ <h2 id="decision">Decision</h2>
154
+ <p><strong>Kitfly will maintain two distinct tiers of visual building blocks, separated by a deterministic layout boundary.</strong></p>
155
+ <h3 id="tier-1-shapes-primitives">Tier 1: Shapes (Primitives)</h3>
156
+ <p>Atomic visual elements (shapes, connectors, text treatments, decorators) with <strong>no internal layout logic</strong>. The author or agent specifies position explicitly. These are analogous to icons in an icon library.</p>
157
+ <p>Examples: box, circle, diamond, chevron, block-arrow, line-connector, callout, badge.</p>
158
+ <h3 id="tier-2-figures-deterministic-infographic-patterns">Tier 2: Figures (Deterministic Infographic Patterns)</h3>
159
+ <p>Parameterized layout templates built from primitives. The figure owns its <strong>internal arrangement</strong> via a deterministic algorithm (CSS Grid, flexbox, trigonometric placement). The agent fills named slots; the figure handles spacing, sizing, and connector routing within its bounding box.</p>
160
+ <p>Examples: cycle-wheel, quadrant-grid, layer-cake, funnel, hub-spoke, horizontal-flow, timeline.</p>
161
+ <h3 id="the-boundary-rule">The Boundary Rule</h3>
162
+ <blockquote>
163
+ <p><strong>If you can name the pieces and where they go (explicit positions or slots), it is a figure. If layout must be computed from relationships between a variable set of nodes, it is a diagram engine.</strong></p>
164
+ </blockquote>
165
+ <table>
166
+ <thead>
167
+ <tr>
168
+ <th>Criterion</th>
169
+ <th>Primitives / Figures</th>
170
+ <th>Diagramming Engine</th>
171
+ </tr>
172
+ </thead>
173
+ <tbody><tr>
174
+ <td>Agent knows element count</td>
175
+ <td>Yes</td>
176
+ <td>Maybe not</td>
177
+ </tr>
178
+ <tr>
179
+ <td>Agent controls placement</td>
180
+ <td>Yes (explicit or via slots)</td>
181
+ <td>No (engine decides)</td>
182
+ </tr>
183
+ <tr>
184
+ <td>Adding a node requires recalculating others</td>
185
+ <td>No</td>
186
+ <td>Yes</td>
187
+ </tr>
188
+ <tr>
189
+ <td>Relationships determine layout</td>
190
+ <td>No</td>
191
+ <td>Yes</td>
192
+ </tr>
193
+ <tr>
194
+ <td>Topology is fixed per figure type</td>
195
+ <td>Yes</td>
196
+ <td>No</td>
197
+ </tr>
198
+ </tbody></table>
199
+ <h3 id="diagramming-engine-integration">Diagramming Engine Integration</h3>
200
+ <p>For compositions that cross the boundary (flowcharts with variable branching, org charts, dependency graphs, state machines), kitfly&#39;s <strong>plugin model</strong> will wrap diagramming engines with a constrained contract:</p>
201
+ <ul>
202
+ <li>The plugin renders into a <strong>declared bounding box</strong> within the slide grid.</li>
203
+ <li>The plugin accepts a <strong>kitfly theme</strong> (colors, fonts, stroke styles) for visual consistency.</li>
204
+ <li>Internal layout is fully delegated to the engine.</li>
205
+ <li>The agent does not attempt to micro-position nodes within the engine&#39;s output.</li>
206
+ </ul>
207
+ <h2 id="consequences">Consequences</h2>
208
+ <h3 id="implementation-notes-m11">Implementation Notes (M1.1)</h3>
209
+ <ul>
210
+ <li>Core ships <strong>shape primitives</strong> as <code>.block</code> modifiers (for example <code>circle</code>, <code>diamond</code>, <code>chevron</code>, <code>block-arrow</code>) with deterministic CSS-only behavior.</li>
211
+ <li>Simple directional flows use existing <code>block-flow</code> glyph arrows plus directional shapes; general connector routing remains deferred to plugin/engine phases.</li>
212
+ <li>This keeps Tier 1 in core without crossing into layout-engine responsibilities.</li>
213
+ </ul>
214
+ <h3 id="benefits">Benefits</h3>
215
+ <ol>
216
+ <li><strong>Agent reliability</strong> — Agents produce consistent, predictable visual output for common infographic patterns that are deterministic layouts.</li>
217
+ <li><strong>Clear plugin contract</strong> — Diagramming engines are scoped to a bounding box with theme passthrough, avoiding the &quot;Mermaid vs. slide layout&quot; fight.</li>
218
+ <li><strong>No engine rebuild</strong> — We explicitly stop before reimplementing graph layout, edge routing, or constraint solving in CSS.</li>
219
+ <li><strong>Catalog-driven authoring</strong> — The figure catalog acts as a vocabulary. Agents pick a pattern and fill slots, similar to choosing an icon from a set.</li>
220
+ </ol>
221
+ <h3 id="trade-offs">Trade-offs</h3>
222
+ <ol>
223
+ <li><strong>Figure library maintenance</strong> — Each new infographic pattern requires a new figure implementation. This is intentional — it&#39;s the cost of deterministic quality.</li>
224
+ <li><strong>Boundary edge cases</strong> — Some compositions (e.g., a flow diagram with exactly 2 branch points) could go either way. Default to figures when topology is fixed and small; to engines when variable.</li>
225
+ <li><strong>Two rendering paths</strong> — Slides mixing figures and engine-rendered diagrams have two rendering subsystems. The plugin model must ensure visual coherence (shared theme tokens).</li>
226
+ </ol>
227
+ <h2 id="alternatives-considered">Alternatives Considered</h2>
228
+ <h3 id="a-css-only-no-diagramming-engines">A. CSS-only, no diagramming engines</h3>
229
+ <p>Rejected. Connector routing and auto-layout for arbitrary graphs is a solved problem in existing engines. Rebuilding it in CSS is high effort, low quality.</p>
230
+ <h3 id="b-diagramming-engine-only-mermaidplantuml-for-everything">B. Diagramming engine-only (Mermaid/PlantUML for everything)</h3>
231
+ <p>Rejected. Agents cannot control output placement precisely enough for slide-quality layouts. Simple compositions (4-box grid, layer cake) become unnecessarily complex in diagram DSLs.</p>
232
+ <h3 id="c-canvassvg-drawing-api-exposed-to-agents">C. Canvas/SVG drawing API exposed to agents</h3>
233
+ <p>Rejected for primary use. Too low-level — agents generating raw SVG coordinates produce inconsistent results. However, primitives may use inline SVG internally (especially for connectors), hidden behind the primitive&#39;s API.</p>
234
+ <h2 id="references">References</h2>
235
+ <ul>
236
+ <li><a href="../../content/reference/design-catalog.md">Design Catalog: Shapes and Figures</a></li>
237
+ <li><a href="ADR-0005-plugin-contract-and-distribution.md">ADR-0005: Plugin Contract and Distribution Strategy</a></li>
238
+ <li><a href="DDR-0004-slides-rendering-model.md">DDR-0004: Slides Rendering Model</a></li>
239
+ </ul>
240
+
241
+ </article>
242
+ <aside class="toc"><span class="toc-title">On this page</span><ul><li><a href="#status">Status</a></li><li><a href="#context">Context</a></li><li class="toc-h3"><a href="#observed-problems">Observed Problems</a></li><li><a href="#decision">Decision</a></li><li class="toc-h3"><a href="#tier-1-shapes-primitives">Tier 1: Shapes (Primitives)</a></li><li class="toc-h3"><a href="#tier-2-figures-deterministic-infographic-patterns">Tier 2: Figures (Deterministic Infographic Patterns)</a></li><li class="toc-h3"><a href="#the-boundary-rule">The Boundary Rule</a></li><li class="toc-h3"><a href="#diagramming-engine-integration">Diagramming Engine Integration</a></li><li><a href="#consequences">Consequences</a></li><li class="toc-h3"><a href="#implementation-notes-m11">Implementation Notes (M1.1)</a></li><li class="toc-h3"><a href="#benefits">Benefits</a></li><li class="toc-h3"><a href="#trade-offs">Trade-offs</a></li><li><a href="#alternatives-considered">Alternatives Considered</a></li><li class="toc-h3"><a href="#a-css-only-no-diagramming-engines">A. CSS-only, no diagramming engines</a></li><li class="toc-h3"><a href="#b-diagramming-engine-only-mermaidplantuml-for-everything">B. Diagramming engine-only (Mermaid/PlantUML for everything)</a></li><li class="toc-h3"><a href="#c-canvassvg-drawing-api-exposed-to-agents">C. Canvas/SVG drawing API exposed to agents</a></li><li><a href="#references">References</a></li></ul></aside>
243
+ </main>
244
+ </div>
245
+
246
+ <footer class="site-footer">
247
+ <div class="footer-content">
248
+ <div class="footer-left">
249
+ <span class="footer-version">v0.2.0</span>
250
+ <span class="footer-separator">·</span>
251
+ <span class="footer-commit" title="Commit: 33ccd68">Published 2026-02-15</span>
252
+ </div>
253
+ <div class="footer-center">
254
+ <span class="footer-copyright"><a href="https://3leaps.net" class="footer-link">© 2026 3 Leaps, LLC</a></span>
255
+ <span class="footer-separator">·</span><a href="/" class="footer-link">Kitfly</a>
256
+ </div>
257
+ <div class="footer-right">
258
+ <a href="https://kitfly.dev" class="footer-link">Built with Kitfly</a>
259
+ </div>
260
+ </div>
261
+ </footer>
262
+ <!-- Syntax highlighting - Prism.js -->
263
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1/components/prism-core.min.js"></script>
264
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1/plugins/autoloader/prism-autoloader.min.js"></script>
265
+ <!-- Mermaid diagram support -->
266
+ <script type="module">
267
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
268
+
269
+ function getMermaidTheme() {
270
+ const theme = document.documentElement.getAttribute('data-theme');
271
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
272
+ const isDark = theme === 'dark' || (!theme && prefersDark);
273
+ return isDark ? 'dark' : 'neutral';
274
+ }
275
+
276
+ mermaid.initialize({
277
+ startOnLoad: true,
278
+ theme: getMermaidTheme()
279
+ });
280
+
281
+ // Re-render mermaid diagrams when theme changes
282
+ window.reinitMermaid = async function() {
283
+ mermaid.initialize({ startOnLoad: false, theme: getMermaidTheme() });
284
+ const diagrams = document.querySelectorAll('.mermaid');
285
+ for (const el of diagrams) {
286
+ const code = el.getAttribute('data-mermaid-source');
287
+ if (code) {
288
+ el.innerHTML = code;
289
+ el.removeAttribute('data-processed');
290
+ }
291
+ }
292
+ await mermaid.run({ nodes: diagrams });
293
+ };
294
+ </script>
295
+
296
+ <script>
297
+ function toggleTheme() {
298
+ const html = document.documentElement;
299
+ const current = html.getAttribute('data-theme');
300
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
301
+
302
+ let next;
303
+ if (current === 'dark') {
304
+ next = 'light';
305
+ } else if (current === 'light') {
306
+ next = 'dark';
307
+ } else {
308
+ // No explicit theme set, toggle from system preference
309
+ next = prefersDark ? 'light' : 'dark';
310
+ }
311
+
312
+ html.setAttribute('data-theme', next);
313
+ localStorage.setItem('theme', next);
314
+
315
+ // Switch Prism theme
316
+ const prismLight = document.getElementById('prism-light');
317
+ const prismDark = document.getElementById('prism-dark');
318
+ if (next === 'dark') {
319
+ prismLight?.setAttribute('disabled', '');
320
+ prismDark?.removeAttribute('disabled');
321
+ } else {
322
+ prismLight?.removeAttribute('disabled');
323
+ prismDark?.setAttribute('disabled', '');
324
+ }
325
+
326
+ // Re-render mermaid diagrams with new theme
327
+ if (window.reinitMermaid) {
328
+ window.reinitMermaid();
329
+ }
330
+ }
331
+
332
+ // Slides mode hash routing
333
+ (function initSlidesMode() {
334
+ const shell = document.querySelector('.slides-shell');
335
+ if (!shell) return;
336
+
337
+ const slides = Array.from(document.querySelectorAll('.slide'));
338
+ if (!slides.length) return;
339
+
340
+ const prevBtn = document.querySelector('.slide-prev');
341
+ const nextBtn = document.querySelector('.slide-next');
342
+ const counter = document.querySelector('.slide-counter');
343
+ const progressBar = document.querySelector('.slide-progress-bar');
344
+ const navLinks = Array.from(document.querySelectorAll('.sidebar-nav a[href^="#slide-"]'));
345
+ let current = 0;
346
+
347
+ function setActive(n) {
348
+ current = Math.max(0, Math.min(n, slides.length - 1));
349
+ slides.forEach((slide, idx) => slide.classList.toggle('active', idx === current));
350
+ navLinks.forEach((link) => {
351
+ const active = link.getAttribute('href') === '#' + slides[current].id;
352
+ link.classList.toggle('active', active);
353
+ });
354
+ if (counter) counter.textContent = (current + 1) + ' / ' + slides.length;
355
+ if (progressBar) progressBar.style.width = (((current + 1) / slides.length) * 100) + '%';
356
+ if (prevBtn) prevBtn.disabled = current === 0;
357
+ if (nextBtn) nextBtn.disabled = current === slides.length - 1;
358
+ history.replaceState(null, '', '#' + slides[current].id);
359
+ }
360
+
361
+ function setFromHash() {
362
+ const hash = window.location.hash || '';
363
+ const idx = slides.findIndex((s) => '#' + s.id === hash);
364
+ if (idx >= 0) setActive(idx);
365
+ else setActive(0);
366
+ }
367
+
368
+ prevBtn?.addEventListener('click', () => setActive(current - 1));
369
+ nextBtn?.addEventListener('click', () => setActive(current + 1));
370
+
371
+ document.addEventListener('keydown', (e) => {
372
+ if (e.key === 'ArrowRight' || e.key === ' ') {
373
+ e.preventDefault();
374
+ setActive(current + 1);
375
+ } else if (e.key === 'ArrowLeft') {
376
+ e.preventDefault();
377
+ setActive(current - 1);
378
+ } else if (e.key === 'Home') {
379
+ e.preventDefault();
380
+ setActive(0);
381
+ } else if (e.key === 'End') {
382
+ e.preventDefault();
383
+ setActive(slides.length - 1);
384
+ }
385
+ });
386
+
387
+ window.addEventListener('hashchange', setFromHash);
388
+ setFromHash();
389
+ })();
390
+
391
+ // Copy code button
392
+ document.querySelectorAll('.prose pre code').forEach(block => {
393
+ const button = document.createElement('button');
394
+ button.className = 'copy-button';
395
+ button.textContent = 'Copy';
396
+ button.onclick = async () => {
397
+ await navigator.clipboard.writeText(block.textContent);
398
+ button.textContent = 'Copied!';
399
+ setTimeout(() => button.textContent = 'Copy', 2000);
400
+ };
401
+ block.parentElement.appendChild(button);
402
+ });
403
+
404
+ // Mobile nav toggle
405
+ function toggleNav() {
406
+ document.querySelector('.sidebar').classList.toggle('open');
407
+ }
408
+
409
+ // Close nav when clicking outside on mobile
410
+ document.addEventListener('click', (e) => {
411
+ const sidebar = document.querySelector('.sidebar');
412
+ const toggle = document.querySelector('.nav-toggle');
413
+ if (sidebar.classList.contains('open') &&
414
+ !sidebar.contains(e.target) &&
415
+ !toggle.contains(e.target)) {
416
+ sidebar.classList.remove('open');
417
+ }
418
+ });
419
+ </script>
420
+
421
+ </body>
422
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta http-equiv="refresh" content="0; url=./DDR-0005-deterministic-layout-boundary.html">
6
+ <title>Redirecting...</title>
7
+ </head>
8
+ <body>
9
+ <p>Redirecting to <a href="./DDR-0005-deterministic-layout-boundary.html">DDR-0005-deterministic-layout-boundary</a>...</p>
10
+ </body>
11
+ </html>