stream_weaver 0.3.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 (381) hide show
  1. checksums.yaml +7 -0
  2. data/.beads/.gitignore +77 -0
  3. data/.beads/README.md +81 -0
  4. data/.beads/config.yaml +54 -0
  5. data/.beads/metadata.json +7 -0
  6. data/.rspec +3 -0
  7. data/AGENTS.md +91 -0
  8. data/CHANGELOG.md +294 -0
  9. data/CLAUDE.md +67 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +565 -0
  12. data/Rakefile +13 -0
  13. data/assets/streamweaver-hero.jpg +0 -0
  14. data/bench/baselines/ledger.rb +58 -0
  15. data/bench/baselines/warroom.rb +51 -0
  16. data/bench/fixtures/ledger.rb +76 -0
  17. data/bench/fixtures/warroom.rb +60 -0
  18. data/bench/results/6daf8b8.md +102 -0
  19. data/bench/results/c8d749b.md +102 -0
  20. data/bench/results/eb06ab9.md +102 -0
  21. data/bench/run.rb +151 -0
  22. data/bench/support.rb +84 -0
  23. data/copy_this/dto_run_sample_run_7631.html +220 -0
  24. data/docs/SERVICE_MODE.md +302 -0
  25. data/docs/architecture/how_streamweaver_works.md +772 -0
  26. data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
  27. data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
  28. data/docs/canvas-ipc-session-summary.md +127 -0
  29. data/docs/canvas-panel-workflow.md +172 -0
  30. data/docs/canvas-read.md +147 -0
  31. data/docs/canvas-roadmap.md +275 -0
  32. data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
  33. data/docs/claude-code-companion-skill-spec.md +567 -0
  34. data/docs/components_reference.md +1223 -0
  35. data/docs/crud-patterns.md +265 -0
  36. data/docs/endpoints.md +122 -0
  37. data/docs/for_llms.md +1 -0
  38. data/docs/form-patterns.md +165 -0
  39. data/docs/frontend-only.md +169 -0
  40. data/docs/html-artifact-audit.md +238 -0
  41. data/docs/ideas/2025-01-01-as-a-service.md +203 -0
  42. data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
  43. data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
  44. data/docs/ideas/dhh-review-future-refactors.md +142 -0
  45. data/docs/opal-jamstack.md +47 -0
  46. data/docs/opal-npm-direction.md +184 -0
  47. data/docs/opal-spike-findings.md +194 -0
  48. data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
  49. data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
  50. data/docs/plans/2026-01-02-charts-design.md +288 -0
  51. data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
  52. data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
  53. data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
  54. data/docs/plans/canvas-claude-project-design.md +238 -0
  55. data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
  56. data/docs/plans/org-doc-preview-surfaces.md +293 -0
  57. data/docs/plans/shadcn-polish-plan.md +417 -0
  58. data/docs/porting-artifacts.md +252 -0
  59. data/docs/reference/agent-skills-comparison.md +369 -0
  60. data/docs/reference/travel-state-prd.artifact.html +780 -0
  61. data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
  62. data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
  63. data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
  64. data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
  65. data/docs/research/frontend-only-matrix.md +278 -0
  66. data/docs/research/streamweaver-way-spike-findings.md +529 -0
  67. data/docs/resource-dsl.md +342 -0
  68. data/docs/routing.md +302 -0
  69. data/docs/ruby-ui-comparison.md +319 -0
  70. data/docs/shared-dsl-fragments.md +356 -0
  71. data/docs/streamweaver-for-ai-agents.md +401 -0
  72. data/docs/streamweaver-frontend-vision.md +123 -0
  73. data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
  74. data/docs/streamweaver_canvas/save_example.rb +9 -0
  75. data/docs/templates.md +213 -0
  76. data/docs/testing.md +155 -0
  77. data/docs/theming-hooks.md +281 -0
  78. data/docs/tutorials/the-streamweaver-way.md +882 -0
  79. data/docs/university/capability-inventory.md +137 -0
  80. data/docs/university/dependency-survey.md +114 -0
  81. data/docs/university/design-spec.md +217 -0
  82. data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
  83. data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
  84. data/docs/university/mockups/course-list-dark.png +0 -0
  85. data/docs/university/mockups/course-list-light.png +0 -0
  86. data/docs/university/mockups/course_canvas_mockup.rb +741 -0
  87. data/docs/university/mockups/step-screen-dark.png +0 -0
  88. data/docs/university/mockups/step-screen-light.png +0 -0
  89. data/docs/university/roadmap.md +72 -0
  90. data/docs/university/send-to-coworker.md +77 -0
  91. data/docs/university/worker-session-mining.md +109 -0
  92. data/docs/visual/browser-rendering-spike.md +173 -0
  93. data/docs/visual/builder-visual-plan-analysis.md +378 -0
  94. data/docs/visual/sw-plan-format-exploration.md +511 -0
  95. data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
  96. data/docs/visual-skills/PROGRESS.md +60 -0
  97. data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
  98. data/docs/visual-skills/analysis/components.md +317 -0
  99. data/docs/visual-skills/analysis/overlap.md +360 -0
  100. data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
  101. data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
  102. data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
  103. data/docs/visual-skills/analysis/visual-explainer.md +964 -0
  104. data/docs/visual-skills/blog/blog-series-outline.md +39 -0
  105. data/docs/visual-skills/blog/token-efficiency.md +73 -0
  106. data/docs/visual-skills/design/architecture.md +1725 -0
  107. data/docs/visual-skills/design/codex-review.md +340 -0
  108. data/docs/visual-skills/design/dhh-review.md +209 -0
  109. data/docs/visual-skills/design/evolution.md +100 -0
  110. data/docs/visual-skills/design/gemini-review.md +55 -0
  111. data/docs/visual-skills/design/review-synthesis.md +149 -0
  112. data/docs/visual-skills/implementation/STATE.md +22 -0
  113. data/docs/visual-skills/implementation/plan.md +347 -0
  114. data/docs/visual-skills/implementation/spike-findings.md +237 -0
  115. data/docs/visual-skills/implementation/tasks.md +702 -0
  116. data/docs/visual-skills/lessons-learned/process.md +145 -0
  117. data/examples/README.md +96 -0
  118. data/examples/advanced/all_components.rb +177 -0
  119. data/examples/advanced/examples_browser.rb +394 -0
  120. data/examples/advanced/teachables_browser.rb +261 -0
  121. data/examples/advanced/theme_tweaker.rb +366 -0
  122. data/examples/advanced/tutorial.rb +1528 -0
  123. data/examples/agentic/agentic_form.rb +30 -0
  124. data/examples/agentic/agentic_form_autoclose.rb +30 -0
  125. data/examples/agentic/cultivation_tracker.rb +69 -0
  126. data/examples/basic/hello_world.rb +22 -0
  127. data/examples/basic/opal_tabs_table.rb +44 -0
  128. data/examples/basic/todo_list.rb +39 -0
  129. data/examples/button_loading_test.rb +36 -0
  130. data/examples/canvas/mermaid_canvas_demo.sh +151 -0
  131. data/examples/charts/bar_chart_demo.rb +57 -0
  132. data/examples/charts/line_chart_demo.rb +73 -0
  133. data/examples/charts/pie_area_demo.rb +87 -0
  134. data/examples/charts/stacked_bar_chart_demo.rb +69 -0
  135. data/examples/claude_code/README.md +85 -0
  136. data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
  137. data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
  138. data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
  139. data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
  140. data/examples/claude_code/codebreaker/README.md +213 -0
  141. data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
  142. data/examples/claude_code/tutorial/README.md +102 -0
  143. data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
  144. data/examples/claude_code/verification_flow/README.md +126 -0
  145. data/examples/components/annotated_code_demo.rb +54 -0
  146. data/examples/components/callout_demo.rb +33 -0
  147. data/examples/components/checkbox_group_demo.rb +46 -0
  148. data/examples/components/design_review.css +468 -0
  149. data/examples/components/design_review_demo.rb +44 -0
  150. data/examples/components/design_review_dsl.rb +300 -0
  151. data/examples/components/diff_block_demo.rb +112 -0
  152. data/examples/components/events_demo.rb +184 -0
  153. data/examples/components/form_demo.rb +62 -0
  154. data/examples/components/lesson_demo.rb +53 -0
  155. data/examples/components/markdown_demo.rb +110 -0
  156. data/examples/components/mermaid_demo.rb +166 -0
  157. data/examples/components/pareto_set.rb +64 -0
  158. data/examples/components/prd_demo.rb +21 -0
  159. data/examples/components/prd_dsl.rb +385 -0
  160. data/examples/components/quiz_demo.rb +47 -0
  161. data/examples/components/run_viewer_demo.rb +100 -0
  162. data/examples/components/score_and_collapsible_demo.rb +82 -0
  163. data/examples/components/select_stale_value_smoke_test.rb +39 -0
  164. data/examples/components/table_demo.rb +247 -0
  165. data/examples/components/timer_with_state_demo.rb +58 -0
  166. data/examples/components/todo_due_dates.rb +63 -0
  167. data/examples/components/uat_gaps_demo.rb +112 -0
  168. data/examples/dashboard/feed_simulator.rb +60 -0
  169. data/examples/dashboard/live_dashboard.rb +80 -0
  170. data/examples/dashboard_components.rb +108 -0
  171. data/examples/deferred_fragments_demo.rb +62 -0
  172. data/examples/generate_more_spike/README.md +63 -0
  173. data/examples/generate_more_spike/app.rb +441 -0
  174. data/examples/git_health.sh +401 -0
  175. data/examples/layout/layout_components_demo.rb +174 -0
  176. data/examples/layout/modal_demo.rb +215 -0
  177. data/examples/layout/navigation_demo.rb +227 -0
  178. data/examples/layout/route_tabs_demo.rb +52 -0
  179. data/examples/layout/routing_demo.rb +52 -0
  180. data/examples/layout/scroll_box_demo.rb +154 -0
  181. data/examples/lazy_fragments_demo.rb +151 -0
  182. data/examples/my_todos/README.md +29 -0
  183. data/examples/my_todos/my_todos.rb +312 -0
  184. data/examples/my_todos/store.rb +86 -0
  185. data/examples/opal/reactive_demo.rb +62 -0
  186. data/examples/opal/scenarios/s1_counter.rb +15 -0
  187. data/examples/opal/scenarios/s2_search_filter.rb +17 -0
  188. data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
  189. data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
  190. data/examples/opal/scenarios/s5_watch.rb +39 -0
  191. data/examples/opal/scenarios/s6_on_start.rb +20 -0
  192. data/examples/opal/scenarios/s7_wizard.rb +33 -0
  193. data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
  194. data/examples/opal/scenarios/s9_dashboard.rb +27 -0
  195. data/examples/operations_dashboard_demo.rb +167 -0
  196. data/examples/panel_demo.sh +447 -0
  197. data/examples/parity/assets/tyrion_slice.css +86 -0
  198. data/examples/parity/rivet_people_slice.rb +182 -0
  199. data/examples/parity/tyrion_components.css +777 -0
  200. data/examples/parity/tyrion_warroom_components.rb +414 -0
  201. data/examples/parity/tyrion_warroom_slice.rb +549 -0
  202. data/examples/puma_dev/README.md +124 -0
  203. data/examples/puma_dev/config.ru +34 -0
  204. data/examples/puma_dev/standalone_app.rb +34 -0
  205. data/examples/scaffolding/blog.rb +49 -0
  206. data/examples/scaffolding/utf_lite.rb +105 -0
  207. data/examples/styling/feedback_demo.rb +229 -0
  208. data/examples/styling/style_showcase.rb +172 -0
  209. data/examples/styling/theme_demo.rb +508 -0
  210. data/examples/timer_health_checker.rb +111 -0
  211. data/examples/timer_showcase.rb +131 -0
  212. data/examples/tutorials/render_markdown.rb +112 -0
  213. data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
  214. data/examples/tutorials/tutorial_content.rb +1082 -0
  215. data/examples/visual_skills/design_deck_demo.rb +314 -0
  216. data/examples/visual_skills/explainer_demo.rb +499 -0
  217. data/exe/streamweaver +9 -0
  218. data/gsd/ROADMAP-1.0.md +167 -0
  219. data/gsd/STATE.md +13 -0
  220. data/gsd/research/market-positioning-research.md +139 -0
  221. data/gsd/research/production-patterns-research.md +270 -0
  222. data/gsd/research/repo-audit-1.0.md +274 -0
  223. data/lib/stream_weaver/action_token.rb +58 -0
  224. data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
  225. data/lib/stream_weaver/adapter/base.rb +591 -0
  226. data/lib/stream_weaver/adapter/opal.rb +334 -0
  227. data/lib/stream_weaver/adapter/static.rb +1118 -0
  228. data/lib/stream_weaver/admin.rb +176 -0
  229. data/lib/stream_weaver/app.rb +1821 -0
  230. data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
  231. data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
  232. data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
  233. data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
  234. data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
  235. data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
  236. data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
  237. data/lib/stream_weaver/canvas/bridge.rb +239 -0
  238. data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
  239. data/lib/stream_weaver/canvas/client.rb +298 -0
  240. data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
  241. data/lib/stream_weaver/canvas/doc_store.rb +252 -0
  242. data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
  243. data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
  244. data/lib/stream_weaver/canvas/gist_store.rb +135 -0
  245. data/lib/stream_weaver/canvas/helpers.rb +109 -0
  246. data/lib/stream_weaver/canvas/history.rb +90 -0
  247. data/lib/stream_weaver/canvas/protocol.rb +86 -0
  248. data/lib/stream_weaver/canvas/reader.rb +853 -0
  249. data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
  250. data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
  251. data/lib/stream_weaver/canvas/session.rb +132 -0
  252. data/lib/stream_weaver/cli.rb +3235 -0
  253. data/lib/stream_weaver/component_assets.rb +70 -0
  254. data/lib/stream_weaver/component_registry.rb +67 -0
  255. data/lib/stream_weaver/component_renderer.rb +48 -0
  256. data/lib/stream_weaver/components/annotated_code.rb +53 -0
  257. data/lib/stream_weaver/components/api_endpoint.rb +42 -0
  258. data/lib/stream_weaver/components/callout.rb +59 -0
  259. data/lib/stream_weaver/components/chart.rb +84 -0
  260. data/lib/stream_weaver/components/code_block.rb +77 -0
  261. data/lib/stream_weaver/components/comparison.rb +39 -0
  262. data/lib/stream_weaver/components/decision.rb +38 -0
  263. data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
  264. data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
  265. data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
  266. data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
  267. data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
  268. data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
  269. data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
  270. data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
  271. data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
  272. data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
  273. data/lib/stream_weaver/components/diff_block.rb +125 -0
  274. data/lib/stream_weaver/components/doc_header.rb +57 -0
  275. data/lib/stream_weaver/components/image_block.rb +70 -0
  276. data/lib/stream_weaver/components/implementation_map.rb +33 -0
  277. data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
  278. data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
  279. data/lib/stream_weaver/components/mermaid.rb +79 -0
  280. data/lib/stream_weaver/components/pipeline.rb +63 -0
  281. data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
  282. data/lib/stream_weaver/components/slide_container.rb +141 -0
  283. data/lib/stream_weaver/components/timeline_event.rb +58 -0
  284. data/lib/stream_weaver/components/wireframe.rb +29 -0
  285. data/lib/stream_weaver/components/wireframe_block.rb +34 -0
  286. data/lib/stream_weaver/components.rb +2711 -0
  287. data/lib/stream_weaver/css.rb +230 -0
  288. data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
  289. data/lib/stream_weaver/display_dsl.rb +1004 -0
  290. data/lib/stream_weaver/export/html_exporter.rb +478 -0
  291. data/lib/stream_weaver/feed.rb +34 -0
  292. data/lib/stream_weaver/feed_builder.rb +31 -0
  293. data/lib/stream_weaver/fonts.rb +33 -0
  294. data/lib/stream_weaver/interaction_runner.rb +487 -0
  295. data/lib/stream_weaver/iterm.rb +460 -0
  296. data/lib/stream_weaver/layout_registry.rb +92 -0
  297. data/lib/stream_weaver/opal/bridge.rb +52 -0
  298. data/lib/stream_weaver/opal/builder.rb +193 -0
  299. data/lib/stream_weaver/opal/env.rb +29 -0
  300. data/lib/stream_weaver/opal/reactive_state.rb +75 -0
  301. data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
  302. data/lib/stream_weaver/opal/renderer.rb +77 -0
  303. data/lib/stream_weaver/opal/runtime.rb +250 -0
  304. data/lib/stream_weaver/opal/shell.rb +145 -0
  305. data/lib/stream_weaver/opal/string_bridge.rb +50 -0
  306. data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
  307. data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
  308. data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
  309. data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
  310. data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
  311. data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
  312. data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
  313. data/lib/stream_weaver/opal_entry.rb +136 -0
  314. data/lib/stream_weaver/org/inline.rb +95 -0
  315. data/lib/stream_weaver/org/reader.rb +561 -0
  316. data/lib/stream_weaver/org/recording_context.rb +86 -0
  317. data/lib/stream_weaver/org/source_splitter.rb +63 -0
  318. data/lib/stream_weaver/org/writer.rb +300 -0
  319. data/lib/stream_weaver/page_shell.rb +530 -0
  320. data/lib/stream_weaver/portfile.rb +79 -0
  321. data/lib/stream_weaver/pushable.rb +42 -0
  322. data/lib/stream_weaver/resource/default_views.rb +111 -0
  323. data/lib/stream_weaver/resource/field_input.rb +25 -0
  324. data/lib/stream_weaver/resource/state_keys.rb +16 -0
  325. data/lib/stream_weaver/resource/store.rb +18 -0
  326. data/lib/stream_weaver/resource.rb +104 -0
  327. data/lib/stream_weaver/server.rb +1471 -0
  328. data/lib/stream_weaver/service.rb +1240 -0
  329. data/lib/stream_weaver/service_client.rb +104 -0
  330. data/lib/stream_weaver/session_store.rb +186 -0
  331. data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
  332. data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
  333. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
  334. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
  335. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
  336. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
  337. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
  338. data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
  339. data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
  340. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
  341. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
  342. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
  343. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
  344. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
  345. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
  346. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
  347. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
  348. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
  349. data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
  350. data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
  351. data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
  352. data/lib/stream_weaver/streamer.rb +63 -0
  353. data/lib/stream_weaver/templates/choices.rb +149 -0
  354. data/lib/stream_weaver/templates/code.rb +157 -0
  355. data/lib/stream_weaver/templates/confirm.rb +110 -0
  356. data/lib/stream_weaver/templates/diff.rb +195 -0
  357. data/lib/stream_weaver/templates/info.rb +142 -0
  358. data/lib/stream_weaver/templates/table.rb +169 -0
  359. data/lib/stream_weaver/templates/wizard.rb +271 -0
  360. data/lib/stream_weaver/theme/auto_mode.rb +116 -0
  361. data/lib/stream_weaver/theme/presets.rb +555 -0
  362. data/lib/stream_weaver/theme.rb +639 -0
  363. data/lib/stream_weaver/university/canvas.rb +924 -0
  364. data/lib/stream_weaver/university/course.rb +699 -0
  365. data/lib/stream_weaver/university/demos/counter.rb +33 -0
  366. data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
  367. data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
  368. data/lib/stream_weaver/university/demos.rb +50 -0
  369. data/lib/stream_weaver/university/listener.rb +467 -0
  370. data/lib/stream_weaver/university/progress.rb +201 -0
  371. data/lib/stream_weaver/university/runner.rb +138 -0
  372. data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
  373. data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
  374. data/lib/stream_weaver/utils.rb +31 -0
  375. data/lib/stream_weaver/version.rb +5 -0
  376. data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
  377. data/lib/stream_weaver/views.rb +3940 -0
  378. data/lib/stream_weaver.rb +122 -0
  379. data/llms.txt +1269 -0
  380. data/sig/stream_weaver.rbs +4 -0
  381. metadata +598 -0
@@ -0,0 +1,1102 @@
1
+ # pi-design-deck Comprehensive Analysis
2
+
3
+ *Analysis date: 2026-03-12*
4
+ *Source: /Users/fkchang/work/rstreamlit/pi-design-deck/ (v0.3.2)*
5
+ *Purpose: Port feasibility analysis for StreamWeaver*
6
+
7
+ ---
8
+
9
+ ## 1. Core Intent
10
+
11
+ ### Problem Solved
12
+ When an AI coding agent needs to present visual design/architecture decisions to a user, text descriptions are inadequate. The user needs to **see** the options side-by-side -- rendered UI mockups, architecture diagrams, syntax-highlighted code, images -- and make explicit selections that become an "implementation contract."
13
+
14
+ ### Target User
15
+ A developer working with the Pi coding agent (analogous to Claude Code) who needs to make multi-dimensional design decisions before implementation begins.
16
+
17
+ ### Workflow
18
+ 1. User asks the agent about design/architecture options (or uses `/deck`, `/deck-plan`, `/deck-discover` slash commands)
19
+ 2. Agent analyzes codebase, generates a JSON deck config with slides and options
20
+ 3. Agent calls `design_deck` tool with the JSON -- a local HTTP server starts, browser opens
21
+ 4. User navigates slides, selects one option per slide
22
+ 5. Optionally requests more options via "Generate N options" button -- agent generates and pushes via SSE
23
+ 6. User submits -- selections returned as `{ slideId: "selected label" }` map
24
+ 7. Agent uses selections as implementation contract
25
+
26
+ ---
27
+
28
+ ## 2. Feature Inventory
29
+
30
+ ### 2.1 Slide Types and Options
31
+
32
+ **DeckConfig structure:**
33
+ ```
34
+ {
35
+ title?: string,
36
+ slides: DeckSlide[]
37
+ }
38
+ ```
39
+
40
+ **DeckSlide:**
41
+ - `id: string` (unique, "summary" is reserved)
42
+ - `title: string`
43
+ - `context?: string` (displayed below title as framing text)
44
+ - `columns?: 1 | 2 | 3 | 4` (grid override; auto-detected if omitted)
45
+ - `options: DeckOption[]` (at least 1)
46
+
47
+ **DeckOption:**
48
+ - `label: string` (required, non-empty)
49
+ - `description?: string` (shown on hover as title attribute)
50
+ - `aside?: string` (explanatory text below preview, supports `\n` line breaks)
51
+ - `recommended?: boolean` (shows "Recommended" badge)
52
+ - Exactly one of:
53
+ - `previewHtml: string` (raw HTML injected via innerHTML)
54
+ - `previewBlocks: PreviewBlock[]` (typed block array, at least 1)
55
+
56
+ ### 2.2 Preview Block Types
57
+
58
+ 1. **HTML block**: `{ type: "html", content: "<div>...</div>" }` -- raw HTML snippet
59
+ 2. **Mermaid block**: `{ type: "mermaid", content: "graph LR\n A-->B", theme?: { primaryColor: "#ff0000" } }` -- renders via Mermaid.js CDN, optional per-block theme variable overrides
60
+ 3. **Code block**: `{ type: "code", code: "const x = 1;", lang: "ts" }` -- Prism.js syntax highlighting with autoloader for language support
61
+ 4. **Image block**: `{ type: "image", src: "/absolute/path.png", alt: "description", caption?: "optional" }` -- served from temp directory via `/assets/` endpoint
62
+
63
+ ### 2.3 The Generate-More Loop
64
+
65
+ **Trigger:** User clicks "Generate N options" button on any slide.
66
+
67
+ **Client-side flow:**
68
+ 1. User optionally types instructions in prompt input, selects count (1-3) from dropdown
69
+ 2. Click sends POST `/generate-more` with `{ slideId, prompt?, model?, thinking?, count }`
70
+ 3. Client shows skeleton placeholder(s) with shimmer animation in the options grid
71
+ 4. Button enters loading state ("Generating...")
72
+
73
+ **Server-side flow:**
74
+ 1. Server validates request, sets `pendingGenerate` with 90-second timeout
75
+ 2. Calls `callbacks.onGenerateMore(slideId, prompt, model, thinking, count)`
76
+ 3. This resolves the Promise blocking the tool, returning structured prompt text to the agent
77
+
78
+ **Agent-side flow:**
79
+ 1. Tool returns with `status: "generate-more"` and a text prompt instructing the agent:
80
+ - Which slide needs options, how many
81
+ - What options already exist (labels + descriptions)
82
+ - Whether to use a specific model (via `deck_generate` tool)
83
+ - The format hint (previewBlocks or previewHtml)
84
+ - The exact tool call to make: `design_deck({ action: "add-options", slideId, options: "[...]" })`
85
+ 2. Agent generates options and calls `design_deck({ action: "add-options", ... })`
86
+ 3. Server pushes each option via SSE `new-option` event
87
+ 4. Client receives, removes skeleton, renders new option card with entry animation
88
+ 5. `add-options` call blocks until next user action
89
+
90
+ **Regenerate-all flow:**
91
+ - "Regenerate all" button replaces all options on a slide
92
+ - Uses `action: "replace-options"`
93
+ - Shows overlay with skeleton placeholders covering existing options
94
+ - SSE event: `replace-options` with full replacement array
95
+
96
+ **Single option (non-blocking):**
97
+ - `action: "add-option"` pushes one option and returns immediately (for parallel calls)
98
+
99
+ **Error handling:**
100
+ - 90-second generation timeout on server
101
+ - 30-second per-option timeout on client
102
+ - SSE events: `generate-failed`, `regenerate-failed`
103
+ - JSON parse errors return actionable messages
104
+ - Invalid option structure returns specific validation errors
105
+ - `cancelGenerate()` clears pending state and sends failure event
106
+
107
+ ### 2.4 Selection/Submission Flow
108
+
109
+ **Selection:**
110
+ - Click option card or press number key (1-9)
111
+ - Stores in `selections[slideId] = label`
112
+ - Visual: radio button fills, checkmark appears (with pop animation), border highlights
113
+ - Persisted to localStorage keyed by sessionId
114
+ - Each option has a "Your notes (optional)" textarea
115
+
116
+ **Summary slide:**
117
+ - Auto-generated as last slide (id: "summary")
118
+ - Shows grid of summary cards with slide title, selected option label, preview thumbnail, aside text, and notes
119
+ - "Additional instructions" textarea for final notes
120
+ - Submit button enabled only when all slides have selections
121
+ - Shows "Still need: X, Y" message for incomplete selections
122
+
123
+ **Submit:**
124
+ - POST `/submit` with `{ selections, notes, finalNotes }`
125
+ - Auto-saves snapshot with `-submitted` suffix
126
+ - Clears localStorage
127
+ - Shows close overlay: "Selections sent to agent. You can close this tab."
128
+ - Auto-closes tab after 800ms
129
+ - Tool resolves with `{ status: "completed", selections, notes?, finalNotes? }`
130
+
131
+ ### 2.5 Save/Load/Export Snapshots
132
+
133
+ **Manual save (Cmd+S):**
134
+ - POST `/save` with current selections and notes
135
+ - Saves to `~/.pi/deck-snapshots/{title}-{project}-{branch}-{date}-{time}/deck.json`
136
+ - Shows toast notification with path
137
+ - Tracks dirty state ("Unsaved changes" / "Saved at HH:MM")
138
+
139
+ **Auto-save on submit:** Enabled by default (`autoSaveOnSubmit: true`)
140
+
141
+ **Auto-save on cancel:** If selections exist when cancelling, saved with `-cancelled` suffix
142
+
143
+ **Snapshot structure:**
144
+ ```
145
+ {title}-{project}-{branch}-{date}-{time}[-submitted|-cancelled]/
146
+ deck.json # { config, selections, savedAt, id, status, modifiedAt, notes, finalNotes, savedFrom }
147
+ images/ # Copied image assets with relative paths
148
+ ```
149
+
150
+ **List saved decks:** `design_deck({ action: "list" })` -- returns array of `{ id, title, savedAt, modifiedAt, status, cwd, branch, slideCount }`
151
+
152
+ **Open saved deck:** `design_deck({ action: "open", deckId: "..." })` -- reopens with selections and notes restored
153
+
154
+ **Export:** `design_deck({ action: "export", deckId: "...", format: "html" })` -- generates standalone HTML with:
155
+ - Embedded CSS (all 4 CSS files)
156
+ - Inlined base64 images
157
+ - Mermaid CDN for diagrams
158
+ - Google Fonts link
159
+ - All slides visible simultaneously (no navigation)
160
+ - Meta chips showing deck ID, status, timestamps, cwd, branch
161
+ - Selected options highlighted with "Selected" badge
162
+
163
+ ### 2.6 Keyboard Shortcuts
164
+
165
+ | Key | Action |
166
+ |-----|--------|
167
+ | Left/Right arrows | Navigate slides (or if focused on option, move between options) |
168
+ | Up/Down arrows | Move between options within a slide |
169
+ | 1-9 | Quick-select option by number |
170
+ | Space | Select focused option |
171
+ | Enter | Select focused option, or advance to next slide, or submit on summary |
172
+ | Escape | Cancel (shows confirmation bar if selections exist; second Escape confirms) |
173
+ | Cmd+S / Ctrl+S | Save snapshot |
174
+ | Cmd+Shift+L | Toggle theme (configurable hotkey) |
175
+
176
+ ### 2.7 Theme Support
177
+
178
+ **Three modes:** `dark` (default), `light`, `auto` (follows OS `prefers-color-scheme`)
179
+
180
+ **Implementation:**
181
+ - CSS custom properties on `:root` and `[data-theme="light"]`
182
+ - `data-theme` attribute on `<html>`
183
+ - `colorScheme` CSS property set
184
+ - `<meta name="theme-color">` updated
185
+ - Theme override stored in localStorage (`pi-deck-theme-override`)
186
+ - Configurable hotkey parsed from string like `"mod+shift+l"` (mod = Cmd on Mac, Ctrl otherwise)
187
+ - Auto mode listens for `matchMedia` changes
188
+
189
+ **Preview palette themes (for previewHtml):**
190
+ - `midnight-rose`, `slate-jade`, `warm-copper`, `ocean-cyan`
191
+ - Font themes: `albert`, `jakarta`, `grotesk`
192
+ - Applied via `data-theme` and `data-fonts` attributes on `.preview` elements
193
+
194
+ ### 2.8 Model Selector
195
+
196
+ **Visibility:** Shown when 2+ models available in the agent's model registry
197
+
198
+ **UI:** Model bar below header with:
199
+ - Provider filter pills (Current, anthropic, google, etc.)
200
+ - Model list with selectable items showing model name and "current" tag
201
+ - "Default" checkbox to save selection to settings
202
+ - Thinking level pills (off, low, medium, high, xhigh) -- only for reasoning models when using current model
203
+
204
+ **Model override flow:**
205
+ 1. User selects a non-current model
206
+ 2. Generate-more prompt includes instruction to use `deck_generate` tool
207
+ 3. `deck_generate` spawns headless `pi` CLI with `--provider` and `--model` flags
208
+ 4. Agent parses output as options JSON
209
+
210
+ **Persistence:** Default model saved to `~/.pi/agent/settings.json` under `designDeck.generateModel`
211
+
212
+ ### 2.9 Accessibility Features
213
+
214
+ - `role="radiogroup"` on options container
215
+ - `role="radio"` + `aria-checked` on option cards
216
+ - `aria-label` on radiogroups, inputs, model list
217
+ - `aria-pressed` on layout toggle buttons
218
+ - `aria-live="polite"` on summary description and save status
219
+ - `focus-visible` outlines on interactive elements
220
+ - Heading focus on slide change (`h2.focus()`)
221
+ - `tabIndex` management (interactive elements inside previews set to -1)
222
+ - `prefers-reduced-motion` media query disables animations
223
+
224
+ ### 2.10 Error Handling / Edge Cases
225
+
226
+ - **Single option per slide:** Valid (columns auto-set to 1)
227
+ - **Many options:** Grid rebalances; cols-4 supported
228
+ - **Cancel with selections:** Auto-saves with `-cancelled` suffix, confirmation bar shown
229
+ - **Browser disconnection:** Heartbeat watchdog (5s interval, 60s grace period) triggers stale cancel
230
+ - **Agent disconnection:** Idle timer (5 minutes) after generate-more closes deck
231
+ - **Abort signal:** Agent abort closes deck immediately
232
+ - **Duplicate slide IDs:** Rejected during validation
233
+ - **Reserved ID "summary":** Rejected during validation
234
+ - **Body size limit:** 15MB max (BodyTooLargeError)
235
+ - **Session token validation:** All endpoints require valid session token
236
+ - **JSON parse errors:** Descriptive error messages with snippet of bad input
237
+ - **Concurrent decks:** Only one active deck allowed
238
+ - **Path traversal:** `resolveDeckFilePath` validates deckId has no slashes or `..`
239
+ - **Tab close:** `beforeunload` sends cancel beacon via `navigator.sendBeacon`
240
+ - **Double submit:** `isSubmitting` flag prevents re-entry
241
+
242
+ ---
243
+
244
+ ## 3. Architecture & Implementation
245
+
246
+ ### 3.1 Server Architecture
247
+
248
+ **HTTP server (Node.js `http`):**
249
+ - Binds to `127.0.0.1` on specified port (default: random/0)
250
+ - Token-based auth via `?session=UUID` query param (GET) or `token` body field (POST)
251
+ - No CORS (localhost only)
252
+
253
+ **Endpoints:**
254
+ | Method | Path | Purpose |
255
+ |--------|------|---------|
256
+ | GET | `/` | Serve deck HTML (template with inlined data) |
257
+ | GET | `/deck.css` | Concatenated CSS (4 files) |
258
+ | GET | `/deck.js` | Concatenated JS (4 files) |
259
+ | GET | `/assets/{file}` | Serve image assets from temp dir |
260
+ | GET | `/events` | SSE stream |
261
+ | GET | `/health` | Health check |
262
+ | GET | `/models` | Available models |
263
+ | POST | `/heartbeat` | Keep-alive ping |
264
+ | POST | `/submit` | Submit selections |
265
+ | POST | `/save` | Save snapshot |
266
+ | POST | `/cancel` | Cancel deck |
267
+ | POST | `/generate-more` | Request new options |
268
+ | POST | `/regenerate-slide` | Request replacement options |
269
+ | POST | `/save-model-default` | Save default model |
270
+
271
+ **SSE events:**
272
+ - `new-option` -- `{ slideId, option }` (new option generated)
273
+ - `replace-options` -- `{ slideId, options }` (regenerated options)
274
+ - `generate-failed` -- `{ slideId, reason? }`
275
+ - `regenerate-failed` -- `{ slideId, reason? }`
276
+ - `deck-close` -- `{ reason }` (submitted, user, stale, aborted, closed)
277
+
278
+ ### 3.2 Client-Side State Management
279
+
280
+ **Global state in `deck-core.js`:**
281
+ - `slides[]` -- mutable copy of config slides (options can be appended)
282
+ - `selections{}` -- slideId -> label map
283
+ - `optionNotes{}` -- slideId -> { label, notes }
284
+ - `finalNotes` -- string
285
+ - `current` -- current slide index
286
+ - `isClosed`, `isSubmitting`, `isDirty`
287
+ - `pendingGenerate` -- Map of slideId -> pending generation state
288
+ - `selectedModel`, `selectedThinking`
289
+
290
+ **Persistence:**
291
+ - Selections + notes saved to localStorage keyed by `pi-deck-{sessionId}`
292
+ - Layout preference saved to localStorage (`pi-deck-layout`)
293
+ - Theme override saved to localStorage (`pi-deck-theme-override`)
294
+
295
+ **JS module structure (concatenated in order):**
296
+ 1. `deck-core.js` -- state, config, DOM refs, utilities, theme, layout toggle, selection persistence
297
+ 2. `deck-render.js` -- mermaid rendering, code blocks, preview blocks, option cards, slide rendering, summary
298
+ 3. `deck-interact.js` -- selection logic, navigation, keyboard handling, model bar
299
+ 4. `deck-session.js` -- network (postJson), save/snapshot, session lifecycle, generate-more, SSE, init
300
+
301
+ ### 3.3 Agent-Tool Communication
302
+
303
+ The tool uses a Promise-based blocking pattern:
304
+
305
+ 1. `design_deck()` starts server, opens browser, returns `blockOnDeck()` (Promise)
306
+ 2. Promise resolves when user submits, cancels, or clicks generate-more
307
+ 3. For generate-more: Promise resolves with structured prompt, agent processes, calls `add-options`
308
+ 4. `add-options` pushes options via SSE and returns `blockOnDeck()` again
309
+ 5. Cycle repeats until submit or cancel
310
+
311
+ **Module-level state:**
312
+ - `activeDeckServer` -- handle + current resolve callback
313
+ - `pendingDeckResult` -- for results that arrive when no resolve is waiting
314
+ - `activeDeckIdleTimer` -- 5-minute idle timer
315
+ - `restoreDeckThinking` -- function to restore thinking level on cleanup
316
+
317
+ ### 3.4 Tool Parameter API
318
+
319
+ ```typescript
320
+ DeckParams = {
321
+ slides?: string, // JSON string or file path
322
+ action?: "add-option" | "add-options" | "replace-options" | "list" | "open" | "export",
323
+ slideId?: string, // target slide for option actions
324
+ option?: string, // JSON string of single option (add-option)
325
+ options?: string, // JSON array string (add-options, replace-options)
326
+ deckId?: string, // saved deck folder name (open, export)
327
+ format?: string, // export format ("html")
328
+ }
329
+ ```
330
+
331
+ ### 3.5 Persistent Server Across Re-invocations
332
+
333
+ The server persists because:
334
+ 1. `activeDeckServer` is module-level state (survives across tool calls)
335
+ 2. First call creates server, subsequent `add-options`/`add-option` calls interact with same server
336
+ 3. Server closes only on: submit, cancel, stale heartbeat, idle timeout, abort, or session shutdown
337
+ 4. Browser stays open -- SSE reconnects automatically if needed
338
+
339
+ ### 3.6 Asset Serving
340
+
341
+ - Image blocks reference absolute file paths on disk
342
+ - Server copies images to temp dir (`mkdtempSync`)
343
+ - Served via `/assets/{uuid}{ext}` with appropriate MIME types
344
+ - Supported: png, jpg/jpeg, gif, webp, svg, avif
345
+ - Cleanup: temp dir removed on server close (`rmSync`)
346
+ - Snapshots copy images to `images/` subdirectory with relative paths
347
+
348
+ ### 3.7 Settings System
349
+
350
+ **File:** `~/.pi/agent/settings.json` under `designDeck` key
351
+
352
+ ```typescript
353
+ interface DesignDeckSettings {
354
+ port?: number; // Server port (0 = random)
355
+ browser?: string; // Browser app name
356
+ theme?: {
357
+ mode?: "auto" | "light" | "dark";
358
+ toggleHotkey?: string; // e.g., "mod+shift+l"
359
+ };
360
+ snapshotDir?: string; // Snapshot directory (~ expansion)
361
+ autoSaveOnSubmit?: boolean; // Default: true
362
+ generateModel?: string; // Default model for generation
363
+ }
364
+ ```
365
+
366
+ **Migration:** Auto-migrates `interview.deckGenerateModel` to `designDeck.generateModel`.
367
+
368
+ ---
369
+
370
+ ## 4. UI/UX Patterns
371
+
372
+ ### 4.1 Layout System
373
+
374
+ **Grid columns auto-detection (`optionCountClass`):**
375
+ - 1 option: 1 column
376
+ - 2 or 4 options: 2 columns
377
+ - 3+ options: 3 columns
378
+ - Per-slide `columns` override
379
+ - Global layout toggle (1/2/3/4 buttons in footer) overrides everything via `data-layout` attribute
380
+ - Layout persisted in localStorage
381
+
382
+ **Responsive breakpoints:**
383
+ - <1200px: 3-col grid collapses to 2
384
+ - <900px: 2-col and 3-col collapse to 1; slide padding reduces; save status hidden
385
+
386
+ **CSS Grid subgrid:** Options use `grid-row: span 3` with subgrid for header/preview/footer alignment
387
+
388
+ ### 4.2 Animations
389
+
390
+ - **Slide transition:** opacity + translateY (0.35s ease)
391
+ - **Check mark pop:** scale 0->1 (0.35s cubic-bezier overshoot)
392
+ - **Option entry (generated):** opacity + scale(0.92) + translateY(8px) + blur(6px) (0.5s)
393
+ - **Regenerated options:** translateY(12px) + scale(0.96) with staggered delays (0.05s per item)
394
+ - **Skeleton shimmer:** linear-gradient background-position animation (1.5s infinite)
395
+ - **Regen overlay fade-in:** 0.3s ease-out
396
+ - **Progress bar:** width transition (0.4s cubic-bezier)
397
+ - **Loading overlay:** fade-out (0.25s)
398
+ - **Toast notification:** translateY(8px) -> 0 (0.3s)
399
+ - **Confirm bar:** translateY(-100%) -> 0 (0.25s)
400
+ - **Reduced motion:** All animations disabled via `prefers-reduced-motion`
401
+
402
+ ### 4.3 Navigation Patterns
403
+
404
+ - Linear slide progression (Back/Next buttons)
405
+ - Progress bar showing position
406
+ - Arrow keys for slide navigation (left/right) and option focus (up/down within radiogroup)
407
+ - Summary as final slide
408
+ - Back disabled on first slide; Next disabled on summary
409
+
410
+ ### 4.4 Selection Patterns
411
+
412
+ - Radio-button metaphor (one selection per slide)
413
+ - Visual: radio indicator, accent border, checkmark badge, header background change
414
+ - Number keys for quick selection (1-9)
415
+ - Click anywhere on option card
416
+ - Selection state tracked independently from focus
417
+
418
+ ### 4.5 Summary Slide Behavior
419
+
420
+ - Auto-populated from current selections
421
+ - Shows preview thumbnail (first block only: code snippet 3 lines, image 80px, mermaid miniature, or HTML preview)
422
+ - Shows aside text (truncated to 120 chars)
423
+ - Shows user notes per option
424
+ - Final notes textarea
425
+ - Submit button: disabled until all selections made, shows "Still need: X, Y"
426
+ - After submit: button changes to "Submitted" with green background
427
+
428
+ ### 4.6 Confirmation Dialogs
429
+
430
+ **Cancel confirmation bar:**
431
+ - Fixed at top of viewport, slides down
432
+ - Shows: "Cancel deck? Selections will be lost."
433
+ - Two buttons: "Cancel" (red) and "Keep Going"
434
+ - Auto-hides after 5 seconds
435
+ - First Escape shows bar; second Escape (or click Cancel) confirms
436
+
437
+ **Close overlay:**
438
+ - Fixed full-screen overlay with blur backdrop
439
+ - Color-coded: green (submitted), amber (cancelled), red (stale/aborted/closed)
440
+ - Messages: "Selections sent to agent", "Deck cancelled", "Session ended -- lost connection", "Session was ended by the agent", "Session was closed"
441
+ - Auto-closes tab after 800ms for submit/cancel
442
+
443
+ ---
444
+
445
+ ## 5. Gherkin/Cucumber Scenarios
446
+
447
+ ### Feature: Creating a New Deck
448
+
449
+ ```gherkin
450
+ Feature: Deck Creation
451
+ As a developer using an AI agent
452
+ I want to view visual design options in a browser
453
+ So that I can make informed implementation decisions
454
+
455
+ Scenario: Start a new deck with previewHtml options
456
+ Given the agent has generated a deck config with 3 slides
457
+ And each slide has 2-4 options with previewHtml
458
+ When the agent calls design_deck with the slides JSON
459
+ Then a local HTTP server starts on a random port
460
+ And the browser opens to the deck URL with a session token
461
+ And the deck displays the first slide with options in a grid
462
+ And a progress bar shows 1/4 (including summary)
463
+
464
+ Scenario: Start a new deck with previewBlocks options
465
+ Given a deck config with code, mermaid, and image blocks
466
+ When the agent calls design_deck with the slides JSON
467
+ Then code blocks render with Prism.js syntax highlighting
468
+ And mermaid blocks render as SVG diagrams
469
+ And image blocks display from the temp assets directory
470
+ And blocks stack vertically within each option card
471
+
472
+ Scenario: Deck with per-slide column override
473
+ Given a slide with columns set to 1
474
+ When the deck renders that slide
475
+ Then options display in a single-column layout
476
+ And other slides use auto-detected column counts
477
+
478
+ Scenario: Deck with context text
479
+ Given a slide with a context property
480
+ When the deck renders that slide
481
+ Then the context text appears below the slide title
482
+ And it is styled as secondary text with max-width 640px
483
+
484
+ Scenario: Deck rejects invalid config
485
+ Given a deck config with a slide ID of "summary"
486
+ When the agent calls design_deck
487
+ Then it throws an error: '"summary" is reserved'
488
+
489
+ Scenario: Deck rejects duplicate slide IDs
490
+ Given a deck config with two slides both having id "arch"
491
+ When the agent calls design_deck
492
+ Then it throws an error about duplicate slide ids
493
+
494
+ Scenario: Deck rejects option with both previewHtml and previewBlocks
495
+ Given an option that has both previewHtml and previewBlocks
496
+ When the agent calls design_deck
497
+ Then it throws an error: "must have either previewHtml or previewBlocks, not both"
498
+
499
+ Scenario: Deck rejects option with neither preview type
500
+ Given an option that has neither previewHtml nor previewBlocks
501
+ When the agent calls design_deck
502
+ Then it throws an error about requiring non-empty preview
503
+
504
+ Scenario: Only one deck active at a time
505
+ Given a design deck is already active
506
+ When the agent calls design_deck with new slides
507
+ Then it returns an error: "A design deck is already active"
508
+
509
+ Scenario: Deck requires interactive mode
510
+ Given the agent is running in headless/RPC mode
511
+ When the agent calls design_deck (not list or export)
512
+ Then it throws an error about requiring interactive mode
513
+ ```
514
+
515
+ ### Feature: Navigating Slides
516
+
517
+ ```gherkin
518
+ Feature: Slide Navigation
519
+ As a user viewing a design deck
520
+ I want to navigate between slides
521
+ So that I can review all decision points
522
+
523
+ Scenario: Navigate forward with button
524
+ Given the deck is showing slide 1 of 3
525
+ When I click the "Next" button
526
+ Then slide 2 becomes active with a fade transition
527
+ And the progress bar updates to 2/4
528
+ And the heading of slide 2 receives focus
529
+
530
+ Scenario: Navigate backward with button
531
+ Given the deck is showing slide 2 of 3
532
+ When I click the "Back" button
533
+ Then slide 1 becomes active
534
+ And the Back button becomes disabled
535
+
536
+ Scenario: Navigate with arrow keys
537
+ Given the deck is showing slide 1
538
+ And no option card is focused
539
+ When I press the Right arrow key
540
+ Then slide 2 becomes active
541
+
542
+ Scenario: Arrow keys within radiogroup
543
+ Given an option card has focus
544
+ When I press the Down arrow key
545
+ Then focus moves to the next option card
546
+ And the slide does not change
547
+
548
+ Scenario: Navigate to summary slide
549
+ Given the deck is showing the last regular slide
550
+ When I click "Next"
551
+ Then the summary slide appears
552
+ And the "Next" button shows "Done" and is disabled
553
+
554
+ Scenario: Back button disabled on first slide
555
+ Given the deck is showing slide 1
556
+ Then the "Back" button is disabled
557
+ ```
558
+
559
+ ### Feature: Selecting Options
560
+
561
+ ```gherkin
562
+ Feature: Option Selection
563
+ As a user viewing a design deck
564
+ I want to select one option per slide
565
+ So that my choices are communicated to the agent
566
+
567
+ Scenario: Select by clicking
568
+ Given slide 1 has 3 options
569
+ When I click option "Microservices"
570
+ Then option "Microservices" shows as selected
571
+ And a checkmark badge appears with a pop animation
572
+ And the radio indicator fills with accent color
573
+ And selections are saved to localStorage
574
+
575
+ Scenario: Select by number key
576
+ Given slide 1 has 3 options
577
+ When I press the "2" key
578
+ Then the second option becomes selected
579
+
580
+ Scenario: Select by Space key
581
+ Given an option card has focus
582
+ When I press Space
583
+ Then that option becomes selected
584
+
585
+ Scenario: Change selection
586
+ Given option "Monolith" is selected on slide 1
587
+ When I click option "Microservices"
588
+ Then "Microservices" becomes selected
589
+ And "Monolith" is deselected
590
+ And dirty state is marked
591
+
592
+ Scenario: Selection persists across page reload
593
+ Given I have selected options on slides 1 and 2
594
+ When I reload the page
595
+ Then my previous selections are restored from localStorage
596
+
597
+ Scenario: Add notes to selected option
598
+ Given option "Microservices" is selected
599
+ When I type "Use event sourcing" in the notes textarea
600
+ Then the notes are saved to localStorage
601
+ And dirty state is marked
602
+ And notes appear in the summary slide
603
+
604
+ Scenario: Recommended badge display
605
+ Given an option has recommended: true
606
+ And it is not selected
607
+ Then a "Recommended" badge appears in the header
608
+
609
+ Scenario: Aside text display
610
+ Given an option has aside text with newlines
611
+ Then the aside text renders below the preview
612
+ And newline characters render as line breaks
613
+ ```
614
+
615
+ ### Feature: Generate-More Flow
616
+
617
+ ```gherkin
618
+ Feature: Generate More Options
619
+ As a user who wants additional design options
620
+ I want to request AI-generated alternatives
621
+ So that I have more choices to consider
622
+
623
+ Scenario: Generate one additional option
624
+ Given the deck is showing a slide with 2 options
625
+ When I click "Generate" with count set to 1
626
+ Then a skeleton placeholder with shimmer animation appears
627
+ And the button shows "Generating..." with a spinner
628
+ And the prompt input is disabled
629
+ And the agent receives a generate-more instruction
630
+ When the agent pushes a new option via add-options
631
+ Then the skeleton is replaced with the new option card
632
+ And the card has an entry animation (scale + blur)
633
+ And a "Generated" badge appears on the option
634
+ And the grid rebalances for the new option count
635
+
636
+ Scenario: Generate multiple options at once
637
+ Given the deck is showing a slide with 2 options
638
+ When I select count "3" and click "Generate"
639
+ Then 3 skeleton placeholders appear
640
+ And the agent receives count=3 in the instruction
641
+ When the agent pushes 3 options via add-options
642
+ Then skeletons are removed one by one as options arrive
643
+
644
+ Scenario: Generate with custom prompt
645
+ Given I type "make it more minimal" in the prompt input
646
+ When I click "Generate"
647
+ Then the prompt text is included in the agent instruction
648
+ And the prompt input is cleared
649
+
650
+ Scenario: Generate with Enter key in prompt
651
+ Given focus is in the prompt input
652
+ When I press Enter
653
+ Then generation is triggered (same as clicking Generate)
654
+
655
+ Scenario: Generation timeout
656
+ Given I clicked "Generate"
657
+ And 30 seconds pass without receiving an option
658
+ Then a toast shows "Generation timed out -- try again"
659
+ And the generate button is restored
660
+ And skeletons are removed
661
+
662
+ Scenario: Generation failure
663
+ Given the agent encounters an error generating options
664
+ Then a "generate-failed" SSE event is sent
665
+ And a toast shows "Generation failed"
666
+ And the button is restored
667
+
668
+ Scenario: Regenerate all options
669
+ Given the slide has 3 options
670
+ When I click "Regenerate all"
671
+ Then a skeleton overlay covers the existing options grid
672
+ And a centered spinner with "Regenerating options..." text appears
673
+ And the agent receives a regenerate-slide instruction
674
+ When the agent pushes 3 replacement options via replace-options
675
+ Then the overlay is removed
676
+ And new options appear with staggered entry animations
677
+ And the previous selection for this slide is cleared
678
+
679
+ Scenario: Concurrent generation prevented
680
+ Given a generation is already in progress
681
+ When I try to click "Generate" or "Regenerate all"
682
+ Then the buttons are disabled and nothing happens
683
+ ```
684
+
685
+ ### Feature: Model Selection for Generation
686
+
687
+ ```gherkin
688
+ Feature: Model Selector
689
+ As a user who wants control over option generation
690
+ I want to choose which AI model generates new options
691
+ So that I can get options from different model capabilities
692
+
693
+ Scenario: Model bar appears with multiple models
694
+ Given the agent has 3+ models available
695
+ When the deck loads
696
+ Then a model bar appears below the header
697
+ And "Current" pill is active by default
698
+ And provider pills are shown (anthropic, google, etc.)
699
+
700
+ Scenario: Select a model from a provider
701
+ Given the model bar is visible
702
+ When I click the "google" provider pill
703
+ Then a model list appears with Google models
704
+ When I click "gemini-3.1-pro"
705
+ Then the model is selected and shown in the label
706
+ And subsequent generate-more requests use this model
707
+
708
+ Scenario: Save model as default
709
+ Given a model is selected
710
+ When I check the "Default" checkbox
711
+ Then the model is saved to settings.json
712
+ And future decks pre-select this model
713
+
714
+ Scenario: Thinking level adjustment
715
+ Given the current model supports reasoning
716
+ And no override model is selected
717
+ Then thinking level pills appear (off, low, medium, high)
718
+ When I click "high"
719
+ Then the thinking level is included in generate requests
720
+
721
+ Scenario: Model bar hidden with fewer than 2 models
722
+ Given the agent has only 1 model available
723
+ When the deck loads
724
+ Then no model bar appears
725
+ ```
726
+
727
+ ### Feature: Save/Load/Export
728
+
729
+ ```gherkin
730
+ Feature: Save and Load Decks
731
+ As a user who wants to preserve my design decisions
732
+ I want to save, load, and export deck snapshots
733
+ So that I can resume work or share decisions
734
+
735
+ Scenario: Manual save with Cmd+S
736
+ Given I have selections on 2 slides
737
+ When I press Cmd+S
738
+ Then a POST /save request is sent
739
+ And a snapshot is saved to the snapshots directory
740
+ And a toast shows "Saved to ~/.pi/deck-snapshots/..."
741
+ And the save status shows "Saved at HH:MM"
742
+
743
+ Scenario: Auto-save on submit
744
+ Given autoSaveOnSubmit is true (default)
745
+ When I submit the deck
746
+ Then a snapshot is saved with "-submitted" suffix
747
+ And image assets are copied to an images/ subdirectory
748
+
749
+ Scenario: Auto-save on cancel with selections
750
+ Given I have selected options
751
+ When I cancel the deck
752
+ Then a snapshot is saved with "-cancelled" suffix
753
+
754
+ Scenario: List saved decks
755
+ Given there are 3 saved decks
756
+ When the agent calls design_deck({ action: "list" })
757
+ Then it returns an array of deck metadata
758
+ And each entry has id, title, savedAt, status, slideCount
759
+
760
+ Scenario: Open a saved deck
761
+ Given a deck "api-design-myapp-main-submitted" exists
762
+ When the agent calls design_deck({ action: "open", deckId: "..." })
763
+ Then the deck opens with selections pre-populated
764
+ And notes are restored
765
+ And image paths are resolved relative to the snapshot
766
+
767
+ Scenario: Export as standalone HTML
768
+ Given a submitted deck exists
769
+ When the agent calls design_deck({ action: "export", deckId: "...", format: "html" })
770
+ Then an export.html file is written next to deck.json
771
+ And it contains embedded CSS, inlined images, and meta chips
772
+ And all slides are visible simultaneously (no navigation)
773
+
774
+ Scenario: Dirty state tracking
775
+ Given I make a selection
776
+ Then save status shows "Unsaved changes"
777
+ And the Save button gets a warning style
778
+ When I save
779
+ Then status shows "Saved at HH:MM"
780
+ And the Save button returns to normal
781
+ ```
782
+
783
+ ### Feature: Keyboard Navigation
784
+
785
+ ```gherkin
786
+ Feature: Keyboard Navigation
787
+ As a user who prefers keyboard interaction
788
+ I want full keyboard support
789
+ So that I can navigate and select efficiently
790
+
791
+ Scenario: Quick select by number
792
+ Given slide 1 has 4 options
793
+ When I press "3"
794
+ Then the third option is selected
795
+
796
+ Scenario: Enter advances to next slide
797
+ Given I am on slide 1
798
+ And no option or button has focus
799
+ When I press Enter
800
+ Then slide 2 becomes active
801
+
802
+ Scenario: Enter on summary submits
803
+ Given I am on the summary slide
804
+ And all selections are made
805
+ When I press Enter
806
+ Then the deck is submitted
807
+
808
+ Scenario: Escape shows confirmation then cancels
809
+ Given I have selections
810
+ When I press Escape
811
+ Then the confirmation bar appears
812
+ When I press Escape again
813
+ Then the deck is cancelled
814
+
815
+ Scenario: Escape with no selections cancels immediately
816
+ Given I have no selections
817
+ When I press Escape
818
+ Then the deck is cancelled immediately
819
+
820
+ Scenario: Arrow navigation between options
821
+ Given an option card has focus
822
+ When I press ArrowDown
823
+ Then focus moves to the next option
824
+ When I press ArrowUp
825
+ Then focus moves to the previous option
826
+ And wrapping occurs at boundaries
827
+ ```
828
+
829
+ ### Feature: Theme Switching
830
+
831
+ ```gherkin
832
+ Feature: Theme Switching
833
+ As a user with theme preferences
834
+ I want to toggle between light and dark themes
835
+ So that the deck matches my environment
836
+
837
+ Scenario: Default dark theme
838
+ Given no theme override exists
839
+ And theme mode is "dark" (default)
840
+ When the deck loads
841
+ Then the page uses dark theme variables
842
+ And meta theme-color is #18181e
843
+
844
+ Scenario: Toggle to light theme
845
+ Given the deck is in dark theme
846
+ When I press Cmd+Shift+L
847
+ Then the page switches to light theme
848
+ And meta theme-color is #f8f8f8
849
+ And the override is saved to localStorage
850
+
851
+ Scenario: Auto theme follows OS
852
+ Given theme mode is "auto"
853
+ And OS is in light mode
854
+ When the deck loads
855
+ Then light theme is applied
856
+ When OS switches to dark mode
857
+ Then dark theme is applied
858
+
859
+ Scenario: Theme shortcut label in footer
860
+ Given a theme toggle hotkey is configured
861
+ Then the footer shows the hotkey combination
862
+ ```
863
+
864
+ ### Feature: Error Cases
865
+
866
+ ```gherkin
867
+ Feature: Error Handling
868
+ As a user of the design deck
869
+ I want graceful error handling
870
+ So that I don't lose my work
871
+
872
+ Scenario: Browser loses connection
873
+ Given the deck is open
874
+ When the browser stops sending heartbeats
875
+ And 60 seconds pass
876
+ Then the server detects stale connection
877
+ And the deck is cancelled with reason "stale"
878
+ And any pending generations are cleared
879
+
880
+ Scenario: Agent idle timeout
881
+ Given the agent received a generate-more request
882
+ And 5 minutes pass without the agent responding
883
+ Then the deck is closed with reason "idle-timeout"
884
+
885
+ Scenario: Agent aborts the deck
886
+ Given the deck is open
887
+ When the agent receives an abort signal
888
+ Then the deck is closed with reason "aborted"
889
+ And a close overlay shows "Session was ended by the agent"
890
+
891
+ Scenario: Invalid JSON in add-options
892
+ Given the agent calls add-options with malformed JSON
893
+ Then the tool returns an error with the parse message
894
+ And a snippet of the bad JSON is shown
895
+ And pending generation is cancelled
896
+
897
+ Scenario: Invalid option structure
898
+ Given the agent calls add-option with an option missing a label
899
+ Then the tool returns a validation error
900
+ And specifies what is required
901
+
902
+ Scenario: Tab closed by user
903
+ Given the deck is open with selections
904
+ When the user closes the browser tab
905
+ Then a cancel beacon is sent via navigator.sendBeacon
906
+ And selections are included for auto-save
907
+ ```
908
+
909
+ ---
910
+
911
+ ## 6. Example Runs
912
+
913
+ ### Minimal Deck Config
914
+ ```json
915
+ {
916
+ "slides": [{
917
+ "id": "s1",
918
+ "title": "Pick one",
919
+ "options": [
920
+ { "label": "A", "previewHtml": "<div>A</div>" },
921
+ { "label": "B", "previewHtml": "<div>B</div>" }
922
+ ]
923
+ }]
924
+ }
925
+ ```
926
+
927
+ ### Architecture Comparison Deck (from SKILL.md)
928
+ ```json
929
+ {
930
+ "title": "Architecture Direction",
931
+ "slides": [{
932
+ "id": "arch",
933
+ "title": "System Architecture",
934
+ "context": "Choose the high-level architecture for the backend.",
935
+ "columns": 2,
936
+ "options": [
937
+ {
938
+ "label": "Monolith",
939
+ "description": "Single deployable, shared database",
940
+ "aside": "Simpler to deploy and debug. Good starting point.\nWatch for coupling as the codebase grows.",
941
+ "previewBlocks": [
942
+ { "type": "mermaid", "content": "graph TD\n Client-->API\n API-->DB" },
943
+ { "type": "code", "code": "app.listen(3000)", "lang": "ts" }
944
+ ]
945
+ },
946
+ {
947
+ "label": "Microservices",
948
+ "description": "Event-driven, independently deployable",
949
+ "aside": "Independent scaling and deployment per service.\nRequires service mesh, distributed tracing, and eventual consistency patterns.",
950
+ "previewBlocks": [
951
+ { "type": "mermaid", "content": "graph LR\n Gateway-->Auth\n Gateway-->Orders\n Gateway-->Inventory" },
952
+ { "type": "code", "code": "bus.publish('order.created', payload)", "lang": "ts" }
953
+ ],
954
+ "recommended": true
955
+ }
956
+ ]
957
+ }]
958
+ }
959
+ ```
960
+
961
+ ### Saved Deck Structure (deck.json)
962
+ ```json
963
+ {
964
+ "config": { "title": "API Design", "slides": [...] },
965
+ "selections": { "auth": "JWT + Refresh Tokens", "db": "PostgreSQL" },
966
+ "savedAt": "2026-03-01T10:30:45.000Z",
967
+ "id": "api-design-myapp-main-2026-03-01-103045-submitted",
968
+ "status": "submitted",
969
+ "modifiedAt": "2026-03-01T10:30:45.000Z",
970
+ "notes": { "auth": "Use short-lived tokens" },
971
+ "finalNotes": "Prioritize security over convenience",
972
+ "savedFrom": { "cwd": "~/work/myapp", "branch": "main", "sessionId": "uuid" }
973
+ }
974
+ ```
975
+
976
+ ### Generate-More Prompt (what agent receives)
977
+ ```
978
+ The design deck is still open and waiting for your response.
979
+
980
+ User clicked "Generate 2 options" for slide "System Architecture".
981
+ Context: Choose the high-level architecture for the backend.
982
+
983
+ Existing options:
984
+ - Monolith: Single deployable, shared database -- Simpler to deploy and debug.
985
+ - Microservices: Event-driven, independently deployable -- Independent scaling and deployment per service.
986
+
987
+ YOU MUST generate 2 distinctive additional options and call design_deck with add-options (one call with all options in an array). Do not skip this step or decide the user has enough options -- they explicitly requested 2 more.
988
+
989
+ design_deck({"action":"add-options","slideId":"arch","options":"[{"label":"Option label","description":"Short rationale","aside":"Explanatory notes below the preview","previewBlocks":[{"type":"code","code":"...","lang":"ts"}],"recommended":false}, ...]"})
990
+
991
+ The options field must be a JSON string containing an array of 2 option objects.
992
+ Each option needs: label, optional description, optional aside, optional recommended, and either previewHtml or previewBlocks.
993
+ Use previewBlocks (array of typed blocks: html, mermaid, code, image) to match the existing options.
994
+
995
+ Make each option distinctive -- they should represent genuinely different approaches.
996
+ ```
997
+
998
+ ---
999
+
1000
+ ## 7. Token Cost Analysis
1001
+
1002
+ ### Current Approach: Token Usage per Interaction
1003
+
1004
+ **Initial deck creation (agent generates slides JSON):**
1005
+ - Tool description + parameters schema: ~500 tokens
1006
+ - Slides JSON for a 3-slide deck with 2-3 options each: ~2,000-8,000 tokens
1007
+ - previewHtml options: 500-2,000 tokens per option (raw HTML with inline styles)
1008
+ - previewBlocks with code: 200-500 tokens per option
1009
+ - previewBlocks with mermaid: 100-300 tokens per option
1010
+ - Total initial call: ~2,500-8,500 tokens output
1011
+
1012
+ **Generate-more loop (per round):**
1013
+ - Prompt returned to agent: ~300-500 tokens (structured instructions)
1014
+ - Agent generates 1-3 new options: ~500-3,000 tokens output per option
1015
+ - `add-options` call: ~500-3,000 tokens (JSON string of options)
1016
+ - Total per generate-more round: ~1,300-6,500 tokens
1017
+
1018
+ **Completion (submit):**
1019
+ - Result text: ~100-200 tokens
1020
+ - Selection map: ~50-100 tokens
1021
+
1022
+ **Typical 3-slide interaction with 1 generate-more:**
1023
+ - Initial: ~5,000 tokens
1024
+ - Generate-more: ~3,000 tokens
1025
+ - Completion: ~200 tokens
1026
+ - **Total: ~8,200 tokens** (output only; input context window cost depends on conversation)
1027
+
1028
+ ### StreamWeaver DSL Approach: Estimated Token Savings
1029
+
1030
+ With a StreamWeaver DSL, the agent would not generate raw HTML or construct complex JSON. Instead:
1031
+
1032
+ **DSL-based approach:**
1033
+ ```ruby
1034
+ design_deck "Architecture Direction" do
1035
+ slide "arch", "System Architecture", context: "Choose the backend architecture" do
1036
+ option "Monolith", recommended: false,
1037
+ aside: "Simpler to deploy and debug" do
1038
+ mermaid "graph TD\n Client-->API\n API-->DB"
1039
+ code "app.listen(3000)", lang: "ts"
1040
+ end
1041
+ option "Microservices", recommended: true,
1042
+ aside: "Independent scaling per service" do
1043
+ mermaid "graph LR\n Gateway-->Auth\n Gateway-->Orders"
1044
+ code "bus.publish('order.created', payload)", lang: "ts"
1045
+ end
1046
+ end
1047
+ end
1048
+ ```
1049
+
1050
+ **Token comparison:**
1051
+ - DSL blocks: ~60-70% of equivalent JSON token count (no structural boilerplate, no escaping)
1052
+ - previewHtml savings: DSL components (if StreamWeaver provides them) could reduce UI mockup tokens by 50-80%
1053
+ - Generate-more: StreamWeaver's reactive model might eliminate the SSE push pattern entirely if the server can render new options directly
1054
+
1055
+ **Estimated savings:**
1056
+ - Initial deck creation: 30-50% token reduction
1057
+ - Generate-more: 20-40% reduction (still need option content)
1058
+ - **Overall: ~30-45% token reduction** for a typical interaction
1059
+
1060
+ **Key insight:** The biggest token cost is in previewHtml (raw HTML with inline styles for UI mockups). A DSL with pre-built UI component primitives would provide the largest savings here. previewBlocks (code, mermaid) are already relatively compact and would see smaller savings.
1061
+
1062
+ ### Additional Considerations
1063
+
1064
+ - StreamWeaver's server-side rendering eliminates the need to send HTML/CSS to the client
1065
+ - Alpine.js reactivity in StreamWeaver could handle the generate-more loop without SSE
1066
+ - The persistent server pattern maps well to StreamWeaver's architecture
1067
+ - Selection state management could leverage StreamWeaver's existing state primitives
1068
+ - The skill/prompt system is agent-framework-specific and wouldn't port directly
1069
+
1070
+ ---
1071
+
1072
+ ## 8. Key Architectural Decisions for StreamWeaver Port
1073
+
1074
+ ### What Maps Directly
1075
+ - Multi-slide navigation with options grid
1076
+ - Preview block types (code, mermaid, image, HTML)
1077
+ - Selection tracking and summary slide
1078
+ - Save/load snapshots
1079
+ - Theme support (StreamWeaver already has theme-aware CSS)
1080
+ - Keyboard shortcuts
1081
+ - Layout toggle
1082
+
1083
+ ### What Needs Rearchitecting
1084
+ - **SSE push for generate-more:** StreamWeaver's Alpine.js reactivity with polling or WebSocket could replace this
1085
+ - **Agent communication protocol:** The Promise-based blocking pattern is Pi-specific; StreamWeaver would use its own tool/callback mechanism
1086
+ - **Module-level singleton state:** StreamWeaver's class-based approach is different
1087
+ - **Asset serving:** StreamWeaver already has Rack-based serving
1088
+ - **Client JS:** Would be replaced by StreamWeaver's component system + Alpine.js
1089
+
1090
+ ### What Can Be Dropped
1091
+ - Pi-specific: `model-runner.ts` (headless pi spawner), Pi extension API integration
1092
+ - `generate-prompts.ts` (prompt building for Pi agent)
1093
+ - `server-utils.ts` session registry (StreamWeaver has its own session management)
1094
+ - Export HTML (could be added later as a separate feature)
1095
+
1096
+ ### Unique Value to Preserve
1097
+ - The generate-more loop concept (user requests more AI options during an active session)
1098
+ - Skeleton shimmer placeholders during generation
1099
+ - The summary slide pattern with preview thumbnails
1100
+ - Notes per option + final notes
1101
+ - Auto-save behavior (submit saves, cancel with selections saves)
1102
+ - Confirmation dialog on cancel with existing selections