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,491 @@
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>Plugins - 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" class="active">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">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="../../content/guide/approaches.html">Content</a><span class="separator">›</span><a href="../../content/reference/configuration.html">Reference</a><span class="separator">›</span><span>plugins</span></nav>
139
+ <div class="page-meta">Last updated: 2026-02-12</div>
140
+ <h1 id="plugins">Plugins</h1>
141
+ <p>Kitfly plugins are small, optional add-ons that inject CSS and/or JS into your generated HTML.</p>
142
+ <p>They are designed to stay minimal:</p>
143
+ <ul>
144
+ <li>No build pipeline required</li>
145
+ <li>Offline-friendly when assets are local</li>
146
+ <li>You own the files (standalone sites copy <code>registry/</code> + <code>plugins-dist/</code>)</li>
147
+ </ul>
148
+ <h2 id="enable-a-plugin">Enable a plugin</h2>
149
+ <p>Create <code>kitfly.plugins.yaml</code> in your site root:</p>
150
+ <pre><code class="language-yaml"># yaml-language-server: $schema=./schemas/v0/plugins.schema.json
151
+ plugins:
152
+ - callouts@0.2.0
153
+ </code></pre>
154
+ <p>Canonical plugins are referenced as pinned strings: <code>name@x.y.z</code>.</p>
155
+ <h2 id="registry-assets">Registry + assets</h2>
156
+ <p>Canonical plugins come from a registry file:</p>
157
+ <ul>
158
+ <li>Site registry: <code>registry/plugins.yaml</code> (preferred if present)</li>
159
+ <li>Engine registry: used as a fallback when the site does not include a registry</li>
160
+ </ul>
161
+ <p>Registry entries map a plugin id + version to asset locations (<code>assets.js</code> and/or <code>assets.css</code>) and per-asset checksums (<code>assetSha256</code>).</p>
162
+ <p>For local/offline registries, <code>baseUrl</code> may be an empty string.</p>
163
+ <h2 id="mode-allowlist-modes">Mode allowlist (<code>modes</code>)</h2>
164
+ <p>Registry entries may include an optional <code>modes</code> allowlist to control where a plugin runs:</p>
165
+ <ul>
166
+ <li>Omitted: allowed in <code>docs</code> and <code>slides</code></li>
167
+ <li>Present with values: allowed only in those modes (example: <code>[&quot;slides&quot;]</code>)</li>
168
+ <li>Present but empty (<code>[]</code>): blocked in all modes (quick disable switch)</li>
169
+ </ul>
170
+ <p>Example:</p>
171
+ <pre><code class="language-yaml">plugins:
172
+ slides-widgets:
173
+ version: &quot;0.2.0&quot;
174
+ modes: [&quot;slides&quot;]
175
+ assets:
176
+ js: &quot;plugins-dist/slides-widgets.js&quot;
177
+ assetSha256:
178
+ js: &quot;sha256:...&quot;
179
+ </code></pre>
180
+ <h2 id="integrity-checks">Integrity checks</h2>
181
+ <p>Kitfly verifies every enabled asset against its <code>sha256:&lt;hex&gt;</code> checksum. If a checksum does not match, the build/dev server fails with an integrity error.</p>
182
+ <p>When iterating on a local plugin (for example, editing <code>plugins-dist/slides-visuals.js</code>), you must also update the matching <code>assetSha256</code> in <code>registry/plugins.yaml</code> (or disable the plugin) for Kitfly to load it.</p>
183
+ <h2 id="triple-colon-fence-contract-slides-visuals">Triple-colon fence contract (<code>slides-visuals</code>)</h2>
184
+ <p>The <code>slides-visuals</code> plugin adds a <code>:::</code> block syntax for slides mode (widgets + figures).</p>
185
+ <p>To keep authoring predictable and make errors actionable, Kitfly defines a strict contract for these blocks.
186
+ When <code>slides-visuals</code> is enabled, Kitfly validates blocks before rendering and reports contract violations.</p>
187
+ <h3 id="valid-block-shape">Valid block shape</h3>
188
+ <ul>
189
+ <li>Opening fence: <code>:::&lt;type&gt;</code> <strong>must</strong> start at column 0 and be the only content on the line.</li>
190
+ <li>Closing fence: <code>:::</code> <strong>must</strong> start at column 0 and be the only content on the line.</li>
191
+ <li>No blank lines inside a <code>:::</code> block.</li>
192
+ <li>Content is a narrow YAML subset:<ul>
193
+ <li>Scalar: <code>key: value</code></li>
194
+ <li>List: <code>key:</code> followed by list items<ul>
195
+ <li>List item start: exactly two spaces, then <code>- </code> (example: <code>␠␠- label: Users</code>)</li>
196
+ <li>Continuation lines (object fields): exactly four spaces, then <code>field: value</code></li>
197
+ </ul>
198
+ </li>
199
+ </ul>
200
+ </li>
201
+ </ul>
202
+ <h3 id="supported-types">Supported types</h3>
203
+ <p>Widgets:</p>
204
+ <ul>
205
+ <li><code>kpi</code> (scalar keys: <code>label</code>, <code>value</code>, optional <code>trend</code>)</li>
206
+ <li><code>stat-grid</code> (list key: <code>metrics</code> of <code>{label,value,trend?}</code> objects)</li>
207
+ <li><code>compare</code> (scalar keys: <code>left-title</code>, <code>right-title</code>; list keys: <code>left</code>, <code>right</code> as <strong>strings only</strong>)</li>
208
+ </ul>
209
+ <p>Notes:</p>
210
+ <ul>
211
+ <li><code>compare.left</code> and <code>compare.right</code> items are simple strings (not <code>{label: ..., value: ...}</code> objects).</li>
212
+ <li>If you need multi-field items, use <code>stat-grid</code> / <code>scorecard</code> instead.</li>
213
+ <li>If an item contains a colon (<code>:</code>), quote it as a string.</li>
214
+ </ul>
215
+ <p>Figures:</p>
216
+ <ul>
217
+ <li><code>quadrant-grid</code> (scalar keys: <code>axis-x</code>, <code>axis-y</code>, <code>tl</code>, <code>tr</code>, <code>bl</code>, <code>br</code>)</li>
218
+ <li><code>scorecard</code> (list key: <code>metrics</code> of <code>{label,value,trend?}</code> objects)</li>
219
+ <li><code>comparison-table</code> (list keys: <code>headers</code> (strings), <code>rows</code> (strings))</li>
220
+ <li><code>layer-cake</code> (list key: <code>layers</code> (strings))</li>
221
+ <li><code>pyramid</code> (list key: <code>levels</code> (strings))</li>
222
+ <li><code>funnel</code> (list key: <code>stages</code> (strings))</li>
223
+ </ul>
224
+ <h3 id="example-valid">Example (valid)</h3>
225
+ <pre><code class="language-markdown">:::stat-grid
226
+ metrics:
227
+
228
+ - label: Users
229
+ value: 1,234
230
+ - label: Uptime
231
+ value: 99.95%
232
+ trend: +0.3%
233
+ :::
234
+ </code></pre>
235
+ <h3 id="how-to-know-its-correct">How to know it’s correct</h3>
236
+ <p>When <code>slides-visuals@...</code> is enabled, Kitfly validates your <code>:::</code> blocks before it renders pages.</p>
237
+ <p>You know your fences are valid if:</p>
238
+ <ul>
239
+ <li><code>kitfly dev</code> starts successfully, and pages load normally</li>
240
+ <li><code>kitfly build</code> completes successfully</li>
241
+ <li><code>kitfly bundle</code> completes successfully</li>
242
+ </ul>
243
+ <p>If a block is invalid, Kitfly will fail fast with an error that points to the file and the specific contract rule you violated.</p>
244
+ <h3 id="common-mistakes-and-how-to-fix-them">Common mistakes (and how to fix them)</h3>
245
+ <ul>
246
+ <li><strong>Indented fences</strong>: <code>:::kpi</code> must start at column 0 (no spaces, no list indentation, no blockquote <code>&gt;</code>).</li>
247
+ <li><strong>Blank lines inside the block</strong>: remove empty lines between keys/items.</li>
248
+ <li><strong>Wrong list indentation</strong>:<ul>
249
+ <li>list items must start with exactly two spaces then <code>- </code></li>
250
+ <li>fields under an item must use exactly four spaces</li>
251
+ </ul>
252
+ </li>
253
+ <li><strong>Unknown type</strong>: the opening fence <code>:::&lt;type&gt;</code> must be one of the supported types.</li>
254
+ </ul>
255
+ <h3 id="examples-invalid-fixed">Examples (invalid → fixed)</h3>
256
+ <h4 id="1-indented-fence-invalid">1) Indented fence (invalid)</h4>
257
+ <pre><code class="language-markdown">:::kpi
258
+ label: Users
259
+ value: 1,234
260
+ :::
261
+ </code></pre>
262
+ <p>Fixed:</p>
263
+ <pre><code class="language-markdown">:::kpi
264
+ label: Users
265
+ value: 1,234
266
+ :::
267
+ </code></pre>
268
+ <h4 id="2-blank-line-inside-block-invalid">2) Blank line inside block (invalid)</h4>
269
+ <pre><code class="language-markdown">:::kpi
270
+ label: Users
271
+
272
+ value: 1,234
273
+ :::
274
+ </code></pre>
275
+ <p>Fixed:</p>
276
+ <pre><code class="language-markdown">:::kpi
277
+ label: Users
278
+ value: 1,234
279
+ :::
280
+ </code></pre>
281
+ <h4 id="3-bad-list-indentation-invalid">3) Bad list indentation (invalid)</h4>
282
+ <pre><code class="language-markdown">:::stat-grid
283
+ metrics:
284
+
285
+ - label: Users
286
+ value: 1,234
287
+ :::
288
+ </code></pre>
289
+ <p>Fixed:</p>
290
+ <pre><code class="language-markdown">:::stat-grid
291
+ metrics:
292
+
293
+ - label: Users
294
+ value: 1,234
295
+ :::
296
+ </code></pre>
297
+ <h4 id="4-unknown-type-invalid">4) Unknown type (invalid)</h4>
298
+ <pre><code class="language-markdown">:::stats
299
+ label: Users
300
+ value: 1,234
301
+ :::
302
+ </code></pre>
303
+ <p>Fixed: use a supported type (for example <code>kpi</code>):</p>
304
+ <pre><code class="language-markdown">:::kpi
305
+ label: Users
306
+ value: 1,234
307
+ :::
308
+ </code></pre>
309
+
310
+ </article>
311
+ <aside class="toc"><span class="toc-title">On this page</span><ul><li><a href="#enable-a-plugin">Enable a plugin</a></li><li><a href="#registry-assets">Registry + assets</a></li><li><a href="#integrity-checks">Integrity checks</a></li><li class="toc-h3"><a href="#valid-block-shape">Valid block shape</a></li><li class="toc-h3"><a href="#supported-types">Supported types</a></li><li class="toc-h3"><a href="#example-valid">Example (valid)</a></li><li class="toc-h3"><a href="#how-to-know-its-correct">How to know it’s correct</a></li><li class="toc-h3"><a href="#common-mistakes-and-how-to-fix-them">Common mistakes (and how to fix them)</a></li><li class="toc-h3"><a href="#examples-invalid-fixed">Examples (invalid → fixed)</a></li></ul></aside>
312
+ </main>
313
+ </div>
314
+
315
+ <footer class="site-footer">
316
+ <div class="footer-content">
317
+ <div class="footer-left">
318
+ <span class="footer-version">v0.2.0</span>
319
+ <span class="footer-separator">·</span>
320
+ <span class="footer-commit" title="Commit: 33ccd68">Published 2026-02-15</span>
321
+ </div>
322
+ <div class="footer-center">
323
+ <span class="footer-copyright"><a href="https://3leaps.net" class="footer-link">© 2026 3 Leaps, LLC</a></span>
324
+ <span class="footer-separator">·</span><a href="/" class="footer-link">Kitfly</a>
325
+ </div>
326
+ <div class="footer-right">
327
+ <a href="https://kitfly.dev" class="footer-link">Built with Kitfly</a>
328
+ </div>
329
+ </div>
330
+ </footer>
331
+ <!-- Syntax highlighting - Prism.js -->
332
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1/components/prism-core.min.js"></script>
333
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1/plugins/autoloader/prism-autoloader.min.js"></script>
334
+ <!-- Mermaid diagram support -->
335
+ <script type="module">
336
+ import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
337
+
338
+ function getMermaidTheme() {
339
+ const theme = document.documentElement.getAttribute('data-theme');
340
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
341
+ const isDark = theme === 'dark' || (!theme && prefersDark);
342
+ return isDark ? 'dark' : 'neutral';
343
+ }
344
+
345
+ mermaid.initialize({
346
+ startOnLoad: true,
347
+ theme: getMermaidTheme()
348
+ });
349
+
350
+ // Re-render mermaid diagrams when theme changes
351
+ window.reinitMermaid = async function() {
352
+ mermaid.initialize({ startOnLoad: false, theme: getMermaidTheme() });
353
+ const diagrams = document.querySelectorAll('.mermaid');
354
+ for (const el of diagrams) {
355
+ const code = el.getAttribute('data-mermaid-source');
356
+ if (code) {
357
+ el.innerHTML = code;
358
+ el.removeAttribute('data-processed');
359
+ }
360
+ }
361
+ await mermaid.run({ nodes: diagrams });
362
+ };
363
+ </script>
364
+
365
+ <script>
366
+ function toggleTheme() {
367
+ const html = document.documentElement;
368
+ const current = html.getAttribute('data-theme');
369
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
370
+
371
+ let next;
372
+ if (current === 'dark') {
373
+ next = 'light';
374
+ } else if (current === 'light') {
375
+ next = 'dark';
376
+ } else {
377
+ // No explicit theme set, toggle from system preference
378
+ next = prefersDark ? 'light' : 'dark';
379
+ }
380
+
381
+ html.setAttribute('data-theme', next);
382
+ localStorage.setItem('theme', next);
383
+
384
+ // Switch Prism theme
385
+ const prismLight = document.getElementById('prism-light');
386
+ const prismDark = document.getElementById('prism-dark');
387
+ if (next === 'dark') {
388
+ prismLight?.setAttribute('disabled', '');
389
+ prismDark?.removeAttribute('disabled');
390
+ } else {
391
+ prismLight?.removeAttribute('disabled');
392
+ prismDark?.setAttribute('disabled', '');
393
+ }
394
+
395
+ // Re-render mermaid diagrams with new theme
396
+ if (window.reinitMermaid) {
397
+ window.reinitMermaid();
398
+ }
399
+ }
400
+
401
+ // Slides mode hash routing
402
+ (function initSlidesMode() {
403
+ const shell = document.querySelector('.slides-shell');
404
+ if (!shell) return;
405
+
406
+ const slides = Array.from(document.querySelectorAll('.slide'));
407
+ if (!slides.length) return;
408
+
409
+ const prevBtn = document.querySelector('.slide-prev');
410
+ const nextBtn = document.querySelector('.slide-next');
411
+ const counter = document.querySelector('.slide-counter');
412
+ const progressBar = document.querySelector('.slide-progress-bar');
413
+ const navLinks = Array.from(document.querySelectorAll('.sidebar-nav a[href^="#slide-"]'));
414
+ let current = 0;
415
+
416
+ function setActive(n) {
417
+ current = Math.max(0, Math.min(n, slides.length - 1));
418
+ slides.forEach((slide, idx) => slide.classList.toggle('active', idx === current));
419
+ navLinks.forEach((link) => {
420
+ const active = link.getAttribute('href') === '#' + slides[current].id;
421
+ link.classList.toggle('active', active);
422
+ });
423
+ if (counter) counter.textContent = (current + 1) + ' / ' + slides.length;
424
+ if (progressBar) progressBar.style.width = (((current + 1) / slides.length) * 100) + '%';
425
+ if (prevBtn) prevBtn.disabled = current === 0;
426
+ if (nextBtn) nextBtn.disabled = current === slides.length - 1;
427
+ history.replaceState(null, '', '#' + slides[current].id);
428
+ }
429
+
430
+ function setFromHash() {
431
+ const hash = window.location.hash || '';
432
+ const idx = slides.findIndex((s) => '#' + s.id === hash);
433
+ if (idx >= 0) setActive(idx);
434
+ else setActive(0);
435
+ }
436
+
437
+ prevBtn?.addEventListener('click', () => setActive(current - 1));
438
+ nextBtn?.addEventListener('click', () => setActive(current + 1));
439
+
440
+ document.addEventListener('keydown', (e) => {
441
+ if (e.key === 'ArrowRight' || e.key === ' ') {
442
+ e.preventDefault();
443
+ setActive(current + 1);
444
+ } else if (e.key === 'ArrowLeft') {
445
+ e.preventDefault();
446
+ setActive(current - 1);
447
+ } else if (e.key === 'Home') {
448
+ e.preventDefault();
449
+ setActive(0);
450
+ } else if (e.key === 'End') {
451
+ e.preventDefault();
452
+ setActive(slides.length - 1);
453
+ }
454
+ });
455
+
456
+ window.addEventListener('hashchange', setFromHash);
457
+ setFromHash();
458
+ })();
459
+
460
+ // Copy code button
461
+ document.querySelectorAll('.prose pre code').forEach(block => {
462
+ const button = document.createElement('button');
463
+ button.className = 'copy-button';
464
+ button.textContent = 'Copy';
465
+ button.onclick = async () => {
466
+ await navigator.clipboard.writeText(block.textContent);
467
+ button.textContent = 'Copied!';
468
+ setTimeout(() => button.textContent = 'Copy', 2000);
469
+ };
470
+ block.parentElement.appendChild(button);
471
+ });
472
+
473
+ // Mobile nav toggle
474
+ function toggleNav() {
475
+ document.querySelector('.sidebar').classList.toggle('open');
476
+ }
477
+
478
+ // Close nav when clicking outside on mobile
479
+ document.addEventListener('click', (e) => {
480
+ const sidebar = document.querySelector('.sidebar');
481
+ const toggle = document.querySelector('.nav-toggle');
482
+ if (sidebar.classList.contains('open') &&
483
+ !sidebar.contains(e.target) &&
484
+ !toggle.contains(e.target)) {
485
+ sidebar.classList.remove('open');
486
+ }
487
+ });
488
+ </script>
489
+
490
+ </body>
491
+ </html>