@prismer/runtime 2.2.55 → 2.2.63

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 (563) hide show
  1. package/CHANGELOG.md +574 -0
  2. package/apc/skills/releasing-test/SKILL.md +9 -0
  3. package/built-in-skills/agent-coordination/SKILL.md +21 -4
  4. package/built-in-skills/agent-meta/SKILL.md +11 -0
  5. package/built-in-skills/assets/SKILL.md +1 -1
  6. package/built-in-skills/canvas-design/SKILL.md +3 -3
  7. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-OFL.txt +93 -0
  8. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSerif-OFL.txt +93 -0
  9. package/built-in-skills/canvas-design/canvas-fonts/LICENSE-SOURCES.md +16 -0
  10. package/built-in-skills/claim-agent-ownership/SKILL.md +7 -3
  11. package/built-in-skills/claude-api/SKILL.md +1 -1
  12. package/built-in-skills/claude-api/python/claude-api/README.md +2 -2
  13. package/built-in-skills/claude-api/python/claude-api/tool-use.md +9 -5
  14. package/built-in-skills/claude-api/python/managed-agents/README.md +11 -1
  15. package/built-in-skills/claude-api/shared/error-codes.md +4 -4
  16. package/built-in-skills/claude-api/shared/managed-agents-client-patterns.md +4 -2
  17. package/built-in-skills/claude-api/shared/managed-agents-core.md +1 -2
  18. package/built-in-skills/claude-api/shared/managed-agents-events.md +41 -22
  19. package/built-in-skills/claude-api/shared/managed-agents-multiagent.md +5 -3
  20. package/built-in-skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +1 -1
  21. package/built-in-skills/claude-api/shared/managed-agents-tools.md +2 -3
  22. package/built-in-skills/claude-api/shared/model-migration.md +3 -3
  23. package/built-in-skills/claude-api/shared/models.md +1 -1
  24. package/built-in-skills/claude-api/typescript/claude-api/batches.md +1 -1
  25. package/built-in-skills/claude-api/typescript/claude-api/files-api.md +3 -1
  26. package/built-in-skills/claude-api/typescript/claude-api/tool-use.md +8 -2
  27. package/built-in-skills/claude-api/typescript/managed-agents/README.md +8 -2
  28. package/built-in-skills/codebase-design/SKILL.md +15 -1
  29. package/built-in-skills/codebase-design/references/requesting-code-review/GUIDE.md +291 -0
  30. package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE +21 -0
  31. package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE.superpowers +21 -0
  32. package/built-in-skills/codebase-design/references/requesting-code-review/NOTICE.md +37 -0
  33. package/built-in-skills/codebase-design/references/sdlc-review/GUIDE.md +130 -0
  34. package/built-in-skills/codebase-design/references/sdlc-review/LICENSE +21 -0
  35. package/built-in-skills/codebase-design/references/sdlc-review/NOTICE.md +17 -0
  36. package/built-in-skills/codebase-design/references/simplify-code/GUIDE.md +269 -0
  37. package/built-in-skills/codebase-design/references/simplify-code/LICENSE +21 -0
  38. package/built-in-skills/codebase-design/references/simplify-code/NOTICE.md +37 -0
  39. package/built-in-skills/competitor-intelligence/LICENSE +21 -0
  40. package/built-in-skills/competitor-intelligence/NOTICE.md +6 -0
  41. package/built-in-skills/competitor-intelligence/SKILL.md +125 -0
  42. package/built-in-skills/competitor-intelligence/scripts/watch_state.py +160 -0
  43. package/built-in-skills/conversation-compaction/SKILL.md +3 -0
  44. package/built-in-skills/council-creator/SKILL.md +4 -3
  45. package/built-in-skills/diagnosing-bugs/SKILL.md +12 -0
  46. package/built-in-skills/diagnosing-bugs/references/desktop-dom/GUIDE.md +64 -0
  47. package/built-in-skills/diagnosing-bugs/references/desktop-dom/LICENSE +21 -0
  48. package/built-in-skills/diagnosing-bugs/references/desktop-dom/NOTICE.md +17 -0
  49. package/built-in-skills/diagnosing-bugs/references/systematic-debugging/GUIDE.md +410 -0
  50. package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE +21 -0
  51. package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE.superpowers +21 -0
  52. package/built-in-skills/diagnosing-bugs/references/systematic-debugging/NOTICE.md +37 -0
  53. package/built-in-skills/doc-coauthoring/SKILL.md +6 -0
  54. package/built-in-skills/doc-coauthoring/references/humanizer/GUIDE.md +647 -0
  55. package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE +21 -0
  56. package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE.hermes +21 -0
  57. package/built-in-skills/doc-coauthoring/references/humanizer/PROVENANCE.md +7 -0
  58. package/built-in-skills/document-actions/LICENSE +21 -0
  59. package/built-in-skills/document-actions/NOTICE.md +21 -0
  60. package/built-in-skills/document-actions/SKILL.md +46 -0
  61. package/built-in-skills/evidence-citations/LICENSE +21 -0
  62. package/built-in-skills/evidence-citations/NOTICE.md +21 -0
  63. package/built-in-skills/evidence-citations/SKILL.md +46 -0
  64. package/built-in-skills/evidence-citations/references/citation-formats.md +68 -0
  65. package/built-in-skills/evidence-citations/references/grounding-rationale.md +64 -0
  66. package/built-in-skills/evidence-citations/scripts/sources.py +720 -0
  67. package/built-in-skills/frontend-design/SKILL.md +6 -0
  68. package/built-in-skills/frontend-design/references/claude-design/GUIDE.md +650 -0
  69. package/built-in-skills/frontend-design/references/claude-design/LICENSE +21 -0
  70. package/built-in-skills/frontend-design/references/claude-design/LICENSE.hermes +21 -0
  71. package/built-in-skills/frontend-design/references/claude-design/PROVENANCE.md +7 -0
  72. package/built-in-skills/image-generate/SKILL.md +5 -0
  73. package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +24 -3
  74. package/built-in-skills/mcp-builder/reference/evaluation.md +11 -2
  75. package/built-in-skills/mcp-builder/reference/node_mcp_server.md +34 -5
  76. package/built-in-skills/mcp-builder/reference/python_mcp_server.md +6 -2
  77. package/built-in-skills/mcp-builder/scripts/connections.py +1 -1
  78. package/built-in-skills/mcp-builder/scripts/evaluation.py +52 -34
  79. package/built-in-skills/mcp-builder/scripts/requirements.txt +2 -2
  80. package/built-in-skills/meeting-actions/LICENSE +21 -0
  81. package/built-in-skills/meeting-actions/NOTICE.md +21 -0
  82. package/built-in-skills/meeting-actions/SKILL.md +48 -0
  83. package/built-in-skills/memory/SKILL.md +27 -3
  84. package/built-in-skills/memory/references/llm-wiki/GUIDE.md +468 -0
  85. package/built-in-skills/memory/references/llm-wiki/LICENSE +21 -0
  86. package/built-in-skills/memory/references/llm-wiki/NOTICE.md +4 -0
  87. package/built-in-skills/memory/references/llm-wiki/scripts/lint_wiki.py +84 -0
  88. package/built-in-skills/memory/references/llm-wiki/scripts/requirements.txt +1 -0
  89. package/built-in-skills/memory/references/llm-wiki/templates/SCHEMA.md +19 -0
  90. package/built-in-skills/memory/references/llm-wiki/templates/index.md +9 -0
  91. package/built-in-skills/memory/references/llm-wiki/templates/log.md +4 -0
  92. package/built-in-skills/memory-dream/SKILL.md +8 -15
  93. package/built-in-skills/memory-import/SKILL.md +51 -0
  94. package/built-in-skills/office-artifacts/NOTICE.md +15 -0
  95. package/built-in-skills/office-artifacts/SKILL.md +20 -0
  96. package/built-in-skills/office-artifacts/references/RESOURCE-LIMITS.md +44 -0
  97. package/built-in-skills/office-artifacts/references/docx/GUIDE.md +196 -0
  98. package/built-in-skills/office-artifacts/references/docx/LICENSE +21 -0
  99. package/built-in-skills/office-artifacts/references/docx/NOTICE.md +21 -0
  100. package/built-in-skills/office-artifacts/references/docx/references/revisions-and-comments.md +88 -0
  101. package/built-in-skills/office-artifacts/references/docx/scripts/docx_comments.py +292 -0
  102. package/built-in-skills/office-artifacts/references/docx/scripts/docx_common.py +93 -0
  103. package/built-in-skills/office-artifacts/references/docx/scripts/docx_create.py +177 -0
  104. package/built-in-skills/office-artifacts/references/docx/scripts/docx_edit.py +250 -0
  105. package/built-in-skills/office-artifacts/references/docx/scripts/docx_read.py +169 -0
  106. package/built-in-skills/office-artifacts/references/docx/scripts/docx_revisions.py +149 -0
  107. package/built-in-skills/office-artifacts/references/docx/scripts/docx_template.py +70 -0
  108. package/built-in-skills/office-artifacts/references/docx/scripts/docx_validate.py +155 -0
  109. package/built-in-skills/office-artifacts/references/docx/tests/test_docx_skill.py +525 -0
  110. package/built-in-skills/office-artifacts/references/pdf/GUIDE.md +125 -0
  111. package/built-in-skills/office-artifacts/references/pdf/LICENSE +21 -0
  112. package/built-in-skills/office-artifacts/references/pdf/NOTICE.md +21 -0
  113. package/built-in-skills/office-artifacts/references/pdf/references/forms.md +99 -0
  114. package/built-in-skills/office-artifacts/references/pdf/references/nano-pdf-editing.md +40 -0
  115. package/built-in-skills/office-artifacts/references/pdf/references/ocr-extraction.md +165 -0
  116. package/built-in-skills/office-artifacts/references/pdf/scripts/_raster.py +87 -0
  117. package/built-in-skills/office-artifacts/references/pdf/scripts/extract_marker.py +95 -0
  118. package/built-in-skills/office-artifacts/references/pdf/scripts/extract_pymupdf.py +107 -0
  119. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_create.py +153 -0
  120. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_fill_form.py +97 -0
  121. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_form_layout.py +168 -0
  122. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_make_form.py +145 -0
  123. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_merge.py +50 -0
  124. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_meta.py +123 -0
  125. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_page_image.py +101 -0
  126. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_read.py +153 -0
  127. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_secure.py +71 -0
  128. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_split.py +86 -0
  129. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_stamp.py +145 -0
  130. package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_watermark.py +51 -0
  131. package/built-in-skills/office-artifacts/references/pdf/tests/test_pdf_skill.py +414 -0
  132. package/built-in-skills/office-artifacts/references/powerpoint/GUIDE.md +220 -0
  133. package/built-in-skills/office-artifacts/references/powerpoint/LICENSE +21 -0
  134. package/built-in-skills/office-artifacts/references/powerpoint/NOTICE.md +21 -0
  135. package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_create.py +214 -0
  136. package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_edit.py +442 -0
  137. package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_from_template.py +88 -0
  138. package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_read.py +131 -0
  139. package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_render.py +104 -0
  140. package/built-in-skills/office-artifacts/references/powerpoint/tests/test_powerpoint_skill.py +478 -0
  141. package/built-in-skills/office-artifacts/references/xlsx/GUIDE.md +196 -0
  142. package/built-in-skills/office-artifacts/references/xlsx/LICENSE +21 -0
  143. package/built-in-skills/office-artifacts/references/xlsx/NOTICE.md +21 -0
  144. package/built-in-skills/office-artifacts/references/xlsx/references/restructuring.md +74 -0
  145. package/built-in-skills/office-artifacts/references/xlsx/scripts/csv_to_xlsx.py +108 -0
  146. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_create.py +259 -0
  147. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_edit.py +269 -0
  148. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_read.py +160 -0
  149. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_recalc.py +111 -0
  150. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_restructure.py +418 -0
  151. package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_to_csv.py +69 -0
  152. package/built-in-skills/office-artifacts/references/xlsx/tests/test_xlsx_skill.py +542 -0
  153. package/built-in-skills/office-artifacts/tests/test_resource_regressions.py +272 -0
  154. package/built-in-skills/persona-generator/SKILL.md +9 -9
  155. package/built-in-skills/pkf-svg/SKILL.md +5 -0
  156. package/built-in-skills/pkf-svg/references/architecture-diagram/GUIDE.md +148 -0
  157. package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE +21 -0
  158. package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE.hermes +21 -0
  159. package/built-in-skills/pkf-svg/references/architecture-diagram/PROVENANCE.md +7 -0
  160. package/built-in-skills/pkf-svg/references/architecture-diagram/templates/template.html +345 -0
  161. package/built-in-skills/pkf-writing/SKILL.md +36 -14
  162. package/built-in-skills/prismer-airtable/LICENSE +21 -0
  163. package/built-in-skills/prismer-airtable/NOTICE.md +11 -0
  164. package/built-in-skills/prismer-airtable/SKILL.md +248 -0
  165. package/built-in-skills/prismer-airtable/scripts/airtable_client.py +76 -0
  166. package/built-in-skills/prismer-apple-notes/LICENSE +21 -0
  167. package/built-in-skills/prismer-apple-notes/NOTICE.md +17 -0
  168. package/built-in-skills/prismer-apple-notes/SKILL.md +118 -0
  169. package/built-in-skills/prismer-apple-notes/scripts/readiness.py +47 -0
  170. package/built-in-skills/prismer-apple-reminders/LICENSE +21 -0
  171. package/built-in-skills/prismer-apple-reminders/NOTICE.md +17 -0
  172. package/built-in-skills/prismer-apple-reminders/SKILL.md +155 -0
  173. package/built-in-skills/prismer-apple-reminders/scripts/readiness.py +47 -0
  174. package/built-in-skills/prismer-ascii-video/LICENSE +21 -0
  175. package/built-in-skills/prismer-ascii-video/LICENSE.hermes +21 -0
  176. package/built-in-skills/prismer-ascii-video/PROVENANCE.md +7 -0
  177. package/built-in-skills/prismer-ascii-video/README.md +290 -0
  178. package/built-in-skills/prismer-ascii-video/SKILL.md +252 -0
  179. package/built-in-skills/prismer-ascii-video/provenance/category-DESCRIPTION.md +3 -0
  180. package/built-in-skills/prismer-ascii-video/references/architecture.md +807 -0
  181. package/built-in-skills/prismer-ascii-video/references/composition.md +900 -0
  182. package/built-in-skills/prismer-ascii-video/references/effects.md +1877 -0
  183. package/built-in-skills/prismer-ascii-video/references/inputs.md +693 -0
  184. package/built-in-skills/prismer-ascii-video/references/optimization.md +688 -0
  185. package/built-in-skills/prismer-ascii-video/references/scenes.md +1018 -0
  186. package/built-in-skills/prismer-ascii-video/references/shaders.md +1408 -0
  187. package/built-in-skills/prismer-ascii-video/references/troubleshooting.md +360 -0
  188. package/built-in-skills/prismer-baoyu-infographic/LICENSE +21 -0
  189. package/built-in-skills/prismer-baoyu-infographic/LICENSE.hermes +21 -0
  190. package/built-in-skills/prismer-baoyu-infographic/LICENSE.origin +21 -0
  191. package/built-in-skills/prismer-baoyu-infographic/PORT_NOTES.md +37 -0
  192. package/built-in-skills/prismer-baoyu-infographic/PROVENANCE.md +7 -0
  193. package/built-in-skills/prismer-baoyu-infographic/SKILL.md +240 -0
  194. package/built-in-skills/prismer-baoyu-infographic/references/analysis-framework.md +182 -0
  195. package/built-in-skills/prismer-baoyu-infographic/references/base-prompt.md +43 -0
  196. package/built-in-skills/prismer-baoyu-infographic/references/layouts/bento-grid.md +41 -0
  197. package/built-in-skills/prismer-baoyu-infographic/references/layouts/binary-comparison.md +48 -0
  198. package/built-in-skills/prismer-baoyu-infographic/references/layouts/bridge.md +41 -0
  199. package/built-in-skills/prismer-baoyu-infographic/references/layouts/circular-flow.md +41 -0
  200. package/built-in-skills/prismer-baoyu-infographic/references/layouts/comic-strip.md +41 -0
  201. package/built-in-skills/prismer-baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
  202. package/built-in-skills/prismer-baoyu-infographic/references/layouts/dashboard.md +41 -0
  203. package/built-in-skills/prismer-baoyu-infographic/references/layouts/dense-modules.md +72 -0
  204. package/built-in-skills/prismer-baoyu-infographic/references/layouts/funnel.md +41 -0
  205. package/built-in-skills/prismer-baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
  206. package/built-in-skills/prismer-baoyu-infographic/references/layouts/hub-spoke.md +41 -0
  207. package/built-in-skills/prismer-baoyu-infographic/references/layouts/iceberg.md +41 -0
  208. package/built-in-skills/prismer-baoyu-infographic/references/layouts/isometric-map.md +41 -0
  209. package/built-in-skills/prismer-baoyu-infographic/references/layouts/jigsaw.md +41 -0
  210. package/built-in-skills/prismer-baoyu-infographic/references/layouts/linear-progression.md +48 -0
  211. package/built-in-skills/prismer-baoyu-infographic/references/layouts/periodic-table.md +41 -0
  212. package/built-in-skills/prismer-baoyu-infographic/references/layouts/story-mountain.md +41 -0
  213. package/built-in-skills/prismer-baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
  214. package/built-in-skills/prismer-baoyu-infographic/references/layouts/tree-branching.md +41 -0
  215. package/built-in-skills/prismer-baoyu-infographic/references/layouts/venn-diagram.md +41 -0
  216. package/built-in-skills/prismer-baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
  217. package/built-in-skills/prismer-baoyu-infographic/references/structured-content-template.md +244 -0
  218. package/built-in-skills/prismer-baoyu-infographic/references/styles/aged-academia.md +36 -0
  219. package/built-in-skills/prismer-baoyu-infographic/references/styles/bold-graphic.md +36 -0
  220. package/built-in-skills/prismer-baoyu-infographic/references/styles/chalkboard.md +61 -0
  221. package/built-in-skills/prismer-baoyu-infographic/references/styles/claymation.md +29 -0
  222. package/built-in-skills/prismer-baoyu-infographic/references/styles/corporate-memphis.md +29 -0
  223. package/built-in-skills/prismer-baoyu-infographic/references/styles/craft-handmade.md +44 -0
  224. package/built-in-skills/prismer-baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
  225. package/built-in-skills/prismer-baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
  226. package/built-in-skills/prismer-baoyu-infographic/references/styles/ikea-manual.md +29 -0
  227. package/built-in-skills/prismer-baoyu-infographic/references/styles/kawaii.md +29 -0
  228. package/built-in-skills/prismer-baoyu-infographic/references/styles/knolling.md +29 -0
  229. package/built-in-skills/prismer-baoyu-infographic/references/styles/lego-brick.md +29 -0
  230. package/built-in-skills/prismer-baoyu-infographic/references/styles/morandi-journal.md +60 -0
  231. package/built-in-skills/prismer-baoyu-infographic/references/styles/origami.md +29 -0
  232. package/built-in-skills/prismer-baoyu-infographic/references/styles/pixel-art.md +29 -0
  233. package/built-in-skills/prismer-baoyu-infographic/references/styles/pop-laboratory.md +48 -0
  234. package/built-in-skills/prismer-baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
  235. package/built-in-skills/prismer-baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
  236. package/built-in-skills/prismer-baoyu-infographic/references/styles/subway-map.md +29 -0
  237. package/built-in-skills/prismer-baoyu-infographic/references/styles/technical-schematic.md +36 -0
  238. package/built-in-skills/prismer-baoyu-infographic/references/styles/ui-wireframe.md +29 -0
  239. package/built-in-skills/prismer-blocked-page-recovery/LICENSE +21 -0
  240. package/built-in-skills/prismer-blocked-page-recovery/NOTICE.md +17 -0
  241. package/built-in-skills/prismer-blocked-page-recovery/SKILL.md +158 -0
  242. package/built-in-skills/prismer-blocked-page-recovery/scripts/recover_page.py +311 -0
  243. package/built-in-skills/prismer-box/LICENSE +21 -0
  244. package/built-in-skills/prismer-box/NOTICE.md +11 -0
  245. package/built-in-skills/prismer-box/SKILL.md +147 -0
  246. package/built-in-skills/prismer-box/references/bulk-operations.md +43 -0
  247. package/built-in-skills/prismer-box/references/cli-guide.md +133 -0
  248. package/built-in-skills/prismer-box/references/content-workflows.md +86 -0
  249. package/built-in-skills/prismer-box/references/hubs.md +77 -0
  250. package/built-in-skills/prismer-box/references/oauth-setup.md +92 -0
  251. package/built-in-skills/prismer-box/references/rest-api.md +37 -0
  252. package/built-in-skills/prismer-box/references/sdk-development.md +85 -0
  253. package/built-in-skills/prismer-box/references/search-and-ai.md +147 -0
  254. package/built-in-skills/prismer-box/references/troubleshooting.md +33 -0
  255. package/built-in-skills/prismer-box/references/webhooks-and-events.md +43 -0
  256. package/built-in-skills/prismer-codebase-inspection/LICENSE +21 -0
  257. package/built-in-skills/prismer-codebase-inspection/NOTICE.md +17 -0
  258. package/built-in-skills/prismer-codebase-inspection/SKILL.md +141 -0
  259. package/built-in-skills/prismer-computer-use/LICENSE +21 -0
  260. package/built-in-skills/prismer-computer-use/NOTICE.md +17 -0
  261. package/built-in-skills/prismer-computer-use/SKILL.md +372 -0
  262. package/built-in-skills/prismer-design-md/LICENSE +21 -0
  263. package/built-in-skills/prismer-design-md/LICENSE.hermes +21 -0
  264. package/built-in-skills/prismer-design-md/PROVENANCE.md +7 -0
  265. package/built-in-skills/prismer-design-md/SKILL.md +227 -0
  266. package/built-in-skills/prismer-design-md/templates/starter.md +99 -0
  267. package/built-in-skills/prismer-email-inbox-triage/LICENSE +21 -0
  268. package/built-in-skills/prismer-email-inbox-triage/NOTICE.md +11 -0
  269. package/built-in-skills/prismer-email-inbox-triage/SKILL.md +116 -0
  270. package/built-in-skills/prismer-findmy/LICENSE +21 -0
  271. package/built-in-skills/prismer-findmy/NOTICE.md +17 -0
  272. package/built-in-skills/prismer-findmy/SKILL.md +150 -0
  273. package/built-in-skills/prismer-findmy/scripts/readiness.py +47 -0
  274. package/built-in-skills/prismer-gif-search/LICENSE +21 -0
  275. package/built-in-skills/prismer-gif-search/LICENSE.hermes +21 -0
  276. package/built-in-skills/prismer-gif-search/PROVENANCE.md +7 -0
  277. package/built-in-skills/prismer-gif-search/SKILL.md +97 -0
  278. package/built-in-skills/prismer-gif-search/scripts/tenor.py +81 -0
  279. package/built-in-skills/prismer-github/LICENSE +21 -0
  280. package/built-in-skills/prismer-github/NOTICE.md +17 -0
  281. package/built-in-skills/prismer-github/SKILL.md +74 -0
  282. package/built-in-skills/prismer-github/references/auth.md +91 -0
  283. package/built-in-skills/prismer-github/references/ci-troubleshooting.md +193 -0
  284. package/built-in-skills/prismer-github/references/code-review.md +465 -0
  285. package/built-in-skills/prismer-github/references/conventional-commits.md +81 -0
  286. package/built-in-skills/prismer-github/references/github-api-cheatsheet.md +177 -0
  287. package/built-in-skills/prismer-github/references/issue-to-pr.md +74 -0
  288. package/built-in-skills/prismer-github/references/issues.md +336 -0
  289. package/built-in-skills/prismer-github/references/pr-workflow.md +346 -0
  290. package/built-in-skills/prismer-github/references/repo-management.md +484 -0
  291. package/built-in-skills/prismer-github/references/review-output-template.md +84 -0
  292. package/built-in-skills/prismer-github/scripts/ensure-gh.py +132 -0
  293. package/built-in-skills/prismer-github/scripts/gh-env.sh +25 -0
  294. package/built-in-skills/prismer-github/scripts/git-credential-token.py +68 -0
  295. package/built-in-skills/prismer-github/scripts/github-api.py +71 -0
  296. package/built-in-skills/prismer-github/scripts/github-context.py +28 -0
  297. package/built-in-skills/prismer-github/templates/bug-report.md +35 -0
  298. package/built-in-skills/prismer-github/templates/feature-request.md +31 -0
  299. package/built-in-skills/prismer-github/templates/pr-body-bugfix.md +35 -0
  300. package/built-in-skills/prismer-github/templates/pr-body-feature.md +33 -0
  301. package/built-in-skills/prismer-google-workspace/LICENSE +21 -0
  302. package/built-in-skills/prismer-google-workspace/NOTICE.md +11 -0
  303. package/built-in-skills/prismer-google-workspace/SKILL.md +369 -0
  304. package/built-in-skills/prismer-google-workspace/references/daily-brief.md +65 -0
  305. package/built-in-skills/prismer-google-workspace/references/gmail-search-syntax.md +63 -0
  306. package/built-in-skills/prismer-google-workspace/scripts/_hermes_home.py +17 -0
  307. package/built-in-skills/prismer-google-workspace/scripts/_private_state.py +39 -0
  308. package/built-in-skills/prismer-google-workspace/scripts/google_api.py +1339 -0
  309. package/built-in-skills/prismer-google-workspace/scripts/gws_bridge.py +121 -0
  310. package/built-in-skills/prismer-google-workspace/scripts/setup.py +563 -0
  311. package/built-in-skills/prismer-google-workspace/tests/test_productivity_regressions.py +214 -0
  312. package/built-in-skills/prismer-hermes-agent/LICENSE +21 -0
  313. package/built-in-skills/prismer-hermes-agent/NOTICE.md +17 -0
  314. package/built-in-skills/prismer-hermes-agent/SKILL.md +247 -0
  315. package/built-in-skills/prismer-hermes-agent/references/background-systems.md +108 -0
  316. package/built-in-skills/prismer-hermes-agent/references/cli-reference.md +158 -0
  317. package/built-in-skills/prismer-hermes-agent/references/configuration.md +96 -0
  318. package/built-in-skills/prismer-hermes-agent/references/contributor-guide.md +151 -0
  319. package/built-in-skills/prismer-hermes-agent/references/delegate-task-concurrency-diagnosis.md +47 -0
  320. package/built-in-skills/prismer-hermes-agent/references/desktop-plugins.md +215 -0
  321. package/built-in-skills/prismer-hermes-agent/references/native-mcp.md +351 -0
  322. package/built-in-skills/prismer-hermes-agent/references/petdex.md +82 -0
  323. package/built-in-skills/prismer-hermes-agent/references/portal-auth-for-third-party-apps.md +135 -0
  324. package/built-in-skills/prismer-hermes-agent/references/project-context-files.md +55 -0
  325. package/built-in-skills/prismer-hermes-agent/references/providers-and-models.md +81 -0
  326. package/built-in-skills/prismer-hermes-agent/references/security-privacy.md +73 -0
  327. package/built-in-skills/prismer-hermes-agent/references/slash-commands.md +119 -0
  328. package/built-in-skills/prismer-hermes-agent/references/themes.md +134 -0
  329. package/built-in-skills/prismer-hermes-agent/references/troubleshooting.md +87 -0
  330. package/built-in-skills/prismer-hermes-agent/references/tui-widgets.md +144 -0
  331. package/built-in-skills/prismer-hermes-agent/references/webhooks.md +219 -0
  332. package/built-in-skills/prismer-hermes-agent/references/windows-quirks.md +64 -0
  333. package/built-in-skills/prismer-hermes-agent/templates/clock.mjs +51 -0
  334. package/built-in-skills/prismer-hermes-agent/templates/plugin.js +97 -0
  335. package/built-in-skills/prismer-hermes-agent/templates/skin.yaml +49 -0
  336. package/built-in-skills/prismer-himalaya/LICENSE +21 -0
  337. package/built-in-skills/prismer-himalaya/NOTICE.md +11 -0
  338. package/built-in-skills/prismer-himalaya/SKILL.md +340 -0
  339. package/built-in-skills/prismer-himalaya/references/configuration.md +227 -0
  340. package/built-in-skills/prismer-himalaya/references/message-composition.md +206 -0
  341. package/built-in-skills/prismer-himalaya/scripts/compose_draft.py +48 -0
  342. package/built-in-skills/prismer-im-collab/SKILL.md +1 -1
  343. package/built-in-skills/prismer-imessage/LICENSE +21 -0
  344. package/built-in-skills/prismer-imessage/NOTICE.md +17 -0
  345. package/built-in-skills/prismer-imessage/SKILL.md +128 -0
  346. package/built-in-skills/prismer-imessage/scripts/readiness.py +47 -0
  347. package/built-in-skills/prismer-manim-video/LICENSE +21 -0
  348. package/built-in-skills/prismer-manim-video/LICENSE.hermes +21 -0
  349. package/built-in-skills/prismer-manim-video/PROVENANCE.md +7 -0
  350. package/built-in-skills/prismer-manim-video/README.md +23 -0
  351. package/built-in-skills/prismer-manim-video/SKILL.md +279 -0
  352. package/built-in-skills/prismer-manim-video/references/animation-design-thinking.md +161 -0
  353. package/built-in-skills/prismer-manim-video/references/animations.md +282 -0
  354. package/built-in-skills/prismer-manim-video/references/camera-and-3d.md +135 -0
  355. package/built-in-skills/prismer-manim-video/references/decorations.md +202 -0
  356. package/built-in-skills/prismer-manim-video/references/equations.md +216 -0
  357. package/built-in-skills/prismer-manim-video/references/graphs-and-data.md +163 -0
  358. package/built-in-skills/prismer-manim-video/references/mobjects.md +333 -0
  359. package/built-in-skills/prismer-manim-video/references/paper-explainer.md +255 -0
  360. package/built-in-skills/prismer-manim-video/references/production-quality.md +190 -0
  361. package/built-in-skills/prismer-manim-video/references/rendering.md +187 -0
  362. package/built-in-skills/prismer-manim-video/references/scene-planning.md +118 -0
  363. package/built-in-skills/prismer-manim-video/references/troubleshooting.md +135 -0
  364. package/built-in-skills/prismer-manim-video/references/updaters-and-trackers.md +260 -0
  365. package/built-in-skills/prismer-manim-video/references/visual-design.md +124 -0
  366. package/built-in-skills/prismer-manim-video/scripts/setup.sh +15 -0
  367. package/built-in-skills/prismer-maps/LICENSE +21 -0
  368. package/built-in-skills/prismer-maps/NOTICE.md +11 -0
  369. package/built-in-skills/prismer-maps/SKILL.md +240 -0
  370. package/built-in-skills/prismer-maps/scripts/maps_client.py +1324 -0
  371. package/built-in-skills/prismer-node-inspect-debugger/LICENSE +21 -0
  372. package/built-in-skills/prismer-node-inspect-debugger/NOTICE.md +17 -0
  373. package/built-in-skills/prismer-node-inspect-debugger/SKILL.md +347 -0
  374. package/built-in-skills/prismer-notion/LICENSE +21 -0
  375. package/built-in-skills/prismer-notion/NOTICE.md +11 -0
  376. package/built-in-skills/prismer-notion/SKILL.md +495 -0
  377. package/built-in-skills/prismer-notion/references/block-types.md +112 -0
  378. package/built-in-skills/prismer-obsidian/LICENSE +21 -0
  379. package/built-in-skills/prismer-obsidian/LICENSE.hermes +21 -0
  380. package/built-in-skills/prismer-obsidian/PROVENANCE.md +7 -0
  381. package/built-in-skills/prismer-obsidian/SKILL.md +80 -0
  382. package/built-in-skills/prismer-obsidian/provenance/category-DESCRIPTION.md +3 -0
  383. package/built-in-skills/prismer-obsidian/scripts/write_note.py +84 -0
  384. package/built-in-skills/prismer-p5js/LICENSE +21 -0
  385. package/built-in-skills/prismer-p5js/LICENSE.hermes +21 -0
  386. package/built-in-skills/prismer-p5js/PROVENANCE.md +7 -0
  387. package/built-in-skills/prismer-p5js/README.md +64 -0
  388. package/built-in-skills/prismer-p5js/SKILL.md +574 -0
  389. package/built-in-skills/prismer-p5js/references/animation.md +439 -0
  390. package/built-in-skills/prismer-p5js/references/color-systems.md +355 -0
  391. package/built-in-skills/prismer-p5js/references/core-api.md +410 -0
  392. package/built-in-skills/prismer-p5js/references/export-pipeline.md +534 -0
  393. package/built-in-skills/prismer-p5js/references/interaction.md +398 -0
  394. package/built-in-skills/prismer-p5js/references/shapes-and-geometry.md +300 -0
  395. package/built-in-skills/prismer-p5js/references/troubleshooting.md +532 -0
  396. package/built-in-skills/prismer-p5js/references/typography.md +302 -0
  397. package/built-in-skills/prismer-p5js/references/visual-effects.md +905 -0
  398. package/built-in-skills/prismer-p5js/references/webgl-and-3d.md +423 -0
  399. package/built-in-skills/prismer-p5js/scripts/export-frames.js +91 -0
  400. package/built-in-skills/prismer-p5js/scripts/render.sh +113 -0
  401. package/built-in-skills/prismer-p5js/scripts/serve.sh +25 -0
  402. package/built-in-skills/prismer-p5js/scripts/setup.sh +87 -0
  403. package/built-in-skills/prismer-p5js/templates/viewer.html +401 -0
  404. package/built-in-skills/prismer-popular-web-designs/LICENSE +21 -0
  405. package/built-in-skills/prismer-popular-web-designs/LICENSE.hermes +21 -0
  406. package/built-in-skills/prismer-popular-web-designs/LICENSE.origin +21 -0
  407. package/built-in-skills/prismer-popular-web-designs/PROVENANCE.md +7 -0
  408. package/built-in-skills/prismer-popular-web-designs/SKILL.md +218 -0
  409. package/built-in-skills/prismer-popular-web-designs/templates/airbnb.md +259 -0
  410. package/built-in-skills/prismer-popular-web-designs/templates/airtable.md +102 -0
  411. package/built-in-skills/prismer-popular-web-designs/templates/apple.md +326 -0
  412. package/built-in-skills/prismer-popular-web-designs/templates/bmw.md +193 -0
  413. package/built-in-skills/prismer-popular-web-designs/templates/cal.md +272 -0
  414. package/built-in-skills/prismer-popular-web-designs/templates/claude.md +325 -0
  415. package/built-in-skills/prismer-popular-web-designs/templates/clay.md +317 -0
  416. package/built-in-skills/prismer-popular-web-designs/templates/clickhouse.md +294 -0
  417. package/built-in-skills/prismer-popular-web-designs/templates/cohere.md +279 -0
  418. package/built-in-skills/prismer-popular-web-designs/templates/coinbase.md +142 -0
  419. package/built-in-skills/prismer-popular-web-designs/templates/composio.md +320 -0
  420. package/built-in-skills/prismer-popular-web-designs/templates/cursor.md +322 -0
  421. package/built-in-skills/prismer-popular-web-designs/templates/elevenlabs.md +278 -0
  422. package/built-in-skills/prismer-popular-web-designs/templates/expo.md +294 -0
  423. package/built-in-skills/prismer-popular-web-designs/templates/figma.md +233 -0
  424. package/built-in-skills/prismer-popular-web-designs/templates/framer.md +259 -0
  425. package/built-in-skills/prismer-popular-web-designs/templates/hashicorp.md +291 -0
  426. package/built-in-skills/prismer-popular-web-designs/templates/ibm.md +345 -0
  427. package/built-in-skills/prismer-popular-web-designs/templates/intercom.md +159 -0
  428. package/built-in-skills/prismer-popular-web-designs/templates/kraken.md +138 -0
  429. package/built-in-skills/prismer-popular-web-designs/templates/linear.app.md +380 -0
  430. package/built-in-skills/prismer-popular-web-designs/templates/lovable.md +311 -0
  431. package/built-in-skills/prismer-popular-web-designs/templates/minimax.md +270 -0
  432. package/built-in-skills/prismer-popular-web-designs/templates/mintlify.md +339 -0
  433. package/built-in-skills/prismer-popular-web-designs/templates/miro.md +121 -0
  434. package/built-in-skills/prismer-popular-web-designs/templates/mistral.ai.md +274 -0
  435. package/built-in-skills/prismer-popular-web-designs/templates/mongodb.md +279 -0
  436. package/built-in-skills/prismer-popular-web-designs/templates/notion.md +322 -0
  437. package/built-in-skills/prismer-popular-web-designs/templates/nvidia.md +306 -0
  438. package/built-in-skills/prismer-popular-web-designs/templates/ollama.md +280 -0
  439. package/built-in-skills/prismer-popular-web-designs/templates/opencode.ai.md +294 -0
  440. package/built-in-skills/prismer-popular-web-designs/templates/pinterest.md +243 -0
  441. package/built-in-skills/prismer-popular-web-designs/templates/posthog.md +269 -0
  442. package/built-in-skills/prismer-popular-web-designs/templates/raycast.md +281 -0
  443. package/built-in-skills/prismer-popular-web-designs/templates/replicate.md +274 -0
  444. package/built-in-skills/prismer-popular-web-designs/templates/resend.md +316 -0
  445. package/built-in-skills/prismer-popular-web-designs/templates/revolut.md +198 -0
  446. package/built-in-skills/prismer-popular-web-designs/templates/runwayml.md +257 -0
  447. package/built-in-skills/prismer-popular-web-designs/templates/sanity.md +370 -0
  448. package/built-in-skills/prismer-popular-web-designs/templates/sentry.md +275 -0
  449. package/built-in-skills/prismer-popular-web-designs/templates/spacex.md +207 -0
  450. package/built-in-skills/prismer-popular-web-designs/templates/spotify.md +259 -0
  451. package/built-in-skills/prismer-popular-web-designs/templates/stripe.md +335 -0
  452. package/built-in-skills/prismer-popular-web-designs/templates/supabase.md +268 -0
  453. package/built-in-skills/prismer-popular-web-designs/templates/superhuman.md +265 -0
  454. package/built-in-skills/prismer-popular-web-designs/templates/together.ai.md +276 -0
  455. package/built-in-skills/prismer-popular-web-designs/templates/uber.md +308 -0
  456. package/built-in-skills/prismer-popular-web-designs/templates/vercel.md +323 -0
  457. package/built-in-skills/prismer-popular-web-designs/templates/voltagent.md +336 -0
  458. package/built-in-skills/prismer-popular-web-designs/templates/warp.md +266 -0
  459. package/built-in-skills/prismer-popular-web-designs/templates/webflow.md +105 -0
  460. package/built-in-skills/prismer-popular-web-designs/templates/wise.md +186 -0
  461. package/built-in-skills/prismer-popular-web-designs/templates/x.ai.md +270 -0
  462. package/built-in-skills/prismer-popular-web-designs/templates/zapier.md +341 -0
  463. package/built-in-skills/prismer-product-price-monitor/LICENSE +21 -0
  464. package/built-in-skills/prismer-product-price-monitor/NOTICE.md +11 -0
  465. package/built-in-skills/prismer-product-price-monitor/SKILL.md +97 -0
  466. package/built-in-skills/prismer-product-price-monitor/scripts/watch_state.py +116 -0
  467. package/built-in-skills/prismer-python-debugpy/LICENSE +21 -0
  468. package/built-in-skills/prismer-python-debugpy/NOTICE.md +17 -0
  469. package/built-in-skills/prismer-python-debugpy/SKILL.md +377 -0
  470. package/built-in-skills/prismer-python-debugpy/scripts/dap_client.py +68 -0
  471. package/built-in-skills/prismer-songsee/LICENSE +21 -0
  472. package/built-in-skills/prismer-songsee/LICENSE.hermes +21 -0
  473. package/built-in-skills/prismer-songsee/PROVENANCE.md +7 -0
  474. package/built-in-skills/prismer-songsee/SKILL.md +91 -0
  475. package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE +21 -0
  476. package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE.hermes +21 -0
  477. package/built-in-skills/prismer-songwriting-and-ai-music/PROVENANCE.md +7 -0
  478. package/built-in-skills/prismer-songwriting-and-ai-music/SKILL.md +317 -0
  479. package/built-in-skills/prismer-spike/LICENSE +21 -0
  480. package/built-in-skills/prismer-spike/LICENSE.gsd +21 -0
  481. package/built-in-skills/prismer-spike/NOTICE.md +17 -0
  482. package/built-in-skills/prismer-spike/SKILL.md +212 -0
  483. package/built-in-skills/prismer-teams-meeting-pipeline/LICENSE +21 -0
  484. package/built-in-skills/prismer-teams-meeting-pipeline/NOTICE.md +11 -0
  485. package/built-in-skills/prismer-teams-meeting-pipeline/SKILL.md +156 -0
  486. package/built-in-skills/prismer-xurl/LICENSE +21 -0
  487. package/built-in-skills/prismer-xurl/LICENSE.hermes +21 -0
  488. package/built-in-skills/prismer-xurl/PROVENANCE.md +7 -0
  489. package/built-in-skills/prismer-xurl/SKILL.md +444 -0
  490. package/built-in-skills/prismer-xurl/provenance/category-DESCRIPTION.md +3 -0
  491. package/built-in-skills/prismer-youtube-content/LICENSE +21 -0
  492. package/built-in-skills/prismer-youtube-content/LICENSE.hermes +21 -0
  493. package/built-in-skills/prismer-youtube-content/PROVENANCE.md +7 -0
  494. package/built-in-skills/prismer-youtube-content/SKILL.md +86 -0
  495. package/built-in-skills/prismer-youtube-content/provenance/category-DESCRIPTION.md +3 -0
  496. package/built-in-skills/prismer-youtube-content/references/output-formats.md +56 -0
  497. package/built-in-skills/prismer-youtube-content/scripts/fetch_transcript.py +146 -0
  498. package/built-in-skills/research-arxiv/LICENSE +21 -0
  499. package/built-in-skills/research-arxiv/NOTICE.md +4 -0
  500. package/built-in-skills/research-arxiv/SKILL.md +263 -0
  501. package/built-in-skills/research-arxiv/scripts/search_arxiv.py +111 -0
  502. package/built-in-skills/role-builder/SKILL.md +7 -1
  503. package/built-in-skills/role-builder/scripts/author-role.mjs +23 -7
  504. package/built-in-skills/role-builder/scripts/ingest-role.mjs +15 -117
  505. package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +15 -1
  506. package/built-in-skills/role-builder/scripts/operation-harness.mjs +6 -4
  507. package/built-in-skills/skill-creator/LICENSE.prismer +21 -0
  508. package/built-in-skills/skill-creator/NOTICE.md +18 -0
  509. package/built-in-skills/skill-creator/SKILL.md +20 -1
  510. package/built-in-skills/skill-creator/eval-viewer/generate_review.py +20 -31
  511. package/built-in-skills/skill-creator/eval-viewer/viewer.html +35 -23
  512. package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/GUIDE.md +220 -0
  513. package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/LICENSE +21 -0
  514. package/built-in-skills/{skill-authoring/SKILL.md → skill-creator/references/skill-authoring/GUIDE.md} +1 -1
  515. package/built-in-skills/{skill-builder/SKILL.md → skill-creator/references/skill-builder/GUIDE.md} +8 -12
  516. package/built-in-skills/skill-creator/references/skill-builder/scripts/ingest.mjs +93 -0
  517. package/built-in-skills/skill-creator/scripts/aggregate_benchmark.py +3 -2
  518. package/built-in-skills/skill-creator/scripts/import-library.mjs +30 -7
  519. package/built-in-skills/skill-creator/scripts/improve_description.py +14 -16
  520. package/built-in-skills/skill-creator/scripts/package_skill.py +16 -9
  521. package/built-in-skills/skill-creator/scripts/quick_validate.py +22 -5
  522. package/built-in-skills/skill-creator/scripts/run_eval.py +63 -144
  523. package/built-in-skills/skill-creator/scripts/run_loop.py +24 -16
  524. package/built-in-skills/slack-gif-creator/core/gif_builder.py +13 -2
  525. package/built-in-skills/slack-gif-creator/core/validators.py +17 -7
  526. package/built-in-skills/tasks/SKILL.md +2 -2
  527. package/built-in-skills/tdd/SKILL.md +7 -0
  528. package/built-in-skills/tdd/references/test-driven-development/GUIDE.md +356 -0
  529. package/built-in-skills/tdd/references/test-driven-development/LICENSE +21 -0
  530. package/built-in-skills/tdd/references/test-driven-development/LICENSE.superpowers +21 -0
  531. package/built-in-skills/tdd/references/test-driven-development/NOTICE.md +37 -0
  532. package/built-in-skills/team/SKILL.md +1 -1
  533. package/built-in-skills/web-artifacts-builder/SKILL.md +3 -3
  534. package/built-in-skills/web-artifacts-builder/scripts/bundle-artifact.sh +9 -7
  535. package/built-in-skills/web-artifacts-builder/scripts/init-artifact.sh +28 -55
  536. package/built-in-skills/webapp-qa/LICENSE +21 -0
  537. package/built-in-skills/webapp-qa/NOTICE.md +37 -0
  538. package/built-in-skills/webapp-qa/SKILL.md +41 -0
  539. package/built-in-skills/webapp-qa/references/dogfood/GUIDE.md +161 -0
  540. package/built-in-skills/webapp-qa/references/issue-taxonomy.md +109 -0
  541. package/built-in-skills/webapp-qa/templates/dogfood-report-template.md +86 -0
  542. package/built-in-skills/webapp-testing/SKILL.md +9 -2
  543. package/built-in-skills/webapp-testing/examples/console_logging.py +10 -4
  544. package/built-in-skills/webapp-testing/examples/element_discovery.py +11 -4
  545. package/built-in-skills/webapp-testing/examples/static_html_automation.py +14 -9
  546. package/built-in-skills/webapp-testing/scripts/with_server.py +34 -10
  547. package/built-in-skills/weekly-review/LICENSE +21 -0
  548. package/built-in-skills/weekly-review/NOTICE.md +21 -0
  549. package/built-in-skills/weekly-review/SKILL.md +49 -0
  550. package/components/eaas-pi-components.manifest.json +37 -0
  551. package/dist/cli.cjs +7017 -3340
  552. package/dist/cli.js +6631 -2936
  553. package/dist/index.cjs +7863 -3830
  554. package/dist/index.d.cts +459 -5
  555. package/dist/index.d.ts +459 -5
  556. package/dist/index.js +7106 -3064
  557. package/package.json +7 -2
  558. package/plugins/memory/prismer/__init__.py +4 -0
  559. package/plugins/memory/prismer/tool-schemas.generated.json +8 -0
  560. package/built-in-skills/skill-builder/scripts/ingest.mjs +0 -265
  561. package/built-in-skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  562. /package/built-in-skills/{document-generation/SKILL.md → office-artifacts/references/document-generation/GUIDE.md} +0 -0
  563. /package/built-in-skills/{skill-authoring/skill.json → skill-creator/references/skill-authoring/draft-contract.json} +0 -0
@@ -0,0 +1,1408 @@
1
+ # Shader Pipeline & Composable Effects
2
+
3
+ Post-processing effects applied to the pixel canvas (`numpy uint8 array, shape (H,W,3)`) after character rendering and before encoding. Also covers **pixel-level blend modes**, **feedback buffers**, and the **ShaderChain** compositor.
4
+
5
+ > **See also:** composition.md (blend modes, tonemap) · effects.md · scenes.md · architecture.md · optimization.md · troubleshooting.md
6
+ >
7
+ > **Blend modes:** For the 20 pixel blend modes and `blend_canvas()`, see `composition.md`. All blending uses `blend_canvas(base, top, mode, opacity)`.
8
+
9
+ ## Design Philosophy
10
+
11
+ The shader pipeline turns raw ASCII renders into cinematic output. The system is designed for **composability** — every shader, blend mode, and feedback transform is an independent building block. Combining them creates infinite visual variety from a small set of primitives.
12
+
13
+ Choose shaders that reinforce the mood:
14
+ - **Retro terminal**: CRT + scanlines + grain + green/amber tint
15
+ - **Clean modern**: light bloom + subtle vignette only
16
+ - **Glitch art**: heavy chromatic aberration + glitch bands + color wobble + pixel sort
17
+ - **Cinematic**: bloom + vignette + grain + color grade
18
+ - **Dreamy**: heavy bloom + soft focus + color wobble + low contrast
19
+ - **Harsh/industrial**: high contrast + grain + scanlines + no bloom
20
+ - **Psychedelic**: color wobble + chromatic + kaleidoscope mirror + high saturation + feedback with hue shift
21
+ - **Data corruption**: pixel sort + data bend + block glitch + posterize
22
+ - **Recursive/infinite**: feedback buffer with zoom + screen blend + hue shift
23
+
24
+ ---
25
+
26
+ ## Pixel-Level Blend Modes
27
+
28
+ All operate on float32 [0,1] canvases for precision. Use `blend_canvas(base, top, mode, opacity)` which handles uint8 <-> float conversion.
29
+
30
+ ### Available Modes
31
+
32
+ ```python
33
+ BLEND_MODES = {
34
+ "normal": lambda a, b: b,
35
+ "add": lambda a, b: np.clip(a + b, 0, 1),
36
+ "subtract": lambda a, b: np.clip(a - b, 0, 1),
37
+ "multiply": lambda a, b: a * b,
38
+ "screen": lambda a, b: 1 - (1-a)*(1-b),
39
+ "overlay": # 2*a*b if a<0.5, else 1-2*(1-a)*(1-b)
40
+ "softlight": lambda a, b: (1-2*b)*a*a + 2*b*a,
41
+ "hardlight": # like overlay but keyed on b
42
+ "difference": lambda a, b: abs(a - b),
43
+ "exclusion": lambda a, b: a + b - 2*a*b,
44
+ "colordodge": lambda a, b: a / (1-b),
45
+ "colorburn": lambda a, b: 1 - (1-a)/b,
46
+ "linearlight": lambda a, b: a + 2*b - 1,
47
+ "vividlight": # burn if b<0.5, dodge if b>=0.5
48
+ "pin_light": # min(a,2b) if b<0.5, max(a,2b-1) if b>=0.5
49
+ "hard_mix": lambda a, b: 1 if a+b>=1 else 0,
50
+ "lighten": lambda a, b: max(a, b),
51
+ "darken": lambda a, b: min(a, b),
52
+ "grain_extract": lambda a, b: a - b + 0.5,
53
+ "grain_merge": lambda a, b: a + b - 0.5,
54
+ }
55
+ ```
56
+
57
+ ### Usage
58
+
59
+ ```python
60
+ def blend_canvas(base, top, mode="normal", opacity=1.0):
61
+ """Blend two uint8 canvases (H,W,3) using a named blend mode + opacity."""
62
+ af = base.astype(np.float32) / 255.0
63
+ bf = top.astype(np.float32) / 255.0
64
+ result = BLEND_MODES[mode](af, bf)
65
+ if opacity < 1.0:
66
+ result = af * (1-opacity) + result * opacity
67
+ return np.clip(result * 255, 0, 255).astype(np.uint8)
68
+
69
+ # Multi-layer compositing
70
+ result = blend_canvas(base, layer_a, "screen", 0.7)
71
+ result = blend_canvas(result, layer_b, "difference", 0.5)
72
+ result = blend_canvas(result, layer_c, "multiply", 0.3)
73
+ ```
74
+
75
+ ### Creative Combinations
76
+
77
+ - **Feedback + difference** = psychedelic color evolution (each frame XORs with the previous)
78
+ - **Screen + screen** = additive glow stacking
79
+ - **Multiply** on two different effects = only shows where both have brightness (intersection)
80
+ - **Exclusion** between two layers = creates complementary patterns where they differ
81
+ - **Color dodge/burn** = extreme contrast enhancement at overlap zones
82
+ - **Hard mix** = reduces everything to pure black/white/color at intersections
83
+
84
+ ---
85
+
86
+ ## Feedback Buffer
87
+
88
+ Recursive temporal effect: frame N-1 feeds back into frame N with decay and optional spatial transform. Creates trails, echoes, smearing, zoom tunnels, rotation feedback, rainbow trails.
89
+
90
+ ```python
91
+ class FeedbackBuffer:
92
+ def __init__(self):
93
+ self.buf = None # previous frame (float32, 0-1)
94
+
95
+ def apply(self, canvas, decay=0.85, blend="screen", opacity=0.5,
96
+ transform=None, transform_amt=0.02, hue_shift=0.0):
97
+ """Mix current frame with decayed/transformed previous frame.
98
+
99
+ Args:
100
+ canvas: current frame (uint8 H,W,3)
101
+ decay: how fast old frame fades (0=instant, 1=permanent)
102
+ blend: blend mode for mixing feedback
103
+ opacity: strength of feedback mix
104
+ transform: None, "zoom", "shrink", "rotate_cw", "rotate_ccw",
105
+ "shift_up", "shift_down", "mirror_h"
106
+ transform_amt: strength of spatial transform per frame
107
+ hue_shift: rotate hue of feedback buffer each frame (0-1)
108
+ """
109
+ ```
110
+
111
+ ### Feedback Presets
112
+
113
+ ```python
114
+ # Infinite zoom tunnel
115
+ fb_cfg = {"decay": 0.8, "blend": "screen", "opacity": 0.4,
116
+ "transform": "zoom", "transform_amt": 0.015}
117
+
118
+ # Rainbow trails (psychedelic)
119
+ fb_cfg = {"decay": 0.7, "blend": "screen", "opacity": 0.3,
120
+ "transform": "zoom", "transform_amt": 0.01, "hue_shift": 0.02}
121
+
122
+ # Ghostly echo (horror)
123
+ fb_cfg = {"decay": 0.9, "blend": "add", "opacity": 0.15,
124
+ "transform": "shift_up", "transform_amt": 0.01}
125
+
126
+ # Kaleidoscopic recursion
127
+ fb_cfg = {"decay": 0.75, "blend": "screen", "opacity": 0.35,
128
+ "transform": "rotate_cw", "transform_amt": 0.005, "hue_shift": 0.01}
129
+
130
+ # Color evolution (abstract)
131
+ fb_cfg = {"decay": 0.8, "blend": "difference", "opacity": 0.4, "hue_shift": 0.03}
132
+
133
+ # Multiplied depth
134
+ fb_cfg = {"decay": 0.65, "blend": "multiply", "opacity": 0.3, "transform": "mirror_h"}
135
+
136
+ # Rising heat haze
137
+ fb_cfg = {"decay": 0.5, "blend": "add", "opacity": 0.2,
138
+ "transform": "shift_up", "transform_amt": 0.02}
139
+ ```
140
+
141
+ ---
142
+
143
+ ## ShaderChain
144
+
145
+ Composable shader pipeline. Build chains of named shaders with parameters. Order matters — shaders are applied sequentially to the canvas.
146
+
147
+ ```python
148
+ class ShaderChain:
149
+ """Composable shader pipeline.
150
+
151
+ Usage:
152
+ chain = ShaderChain()
153
+ chain.add("bloom", thr=120)
154
+ chain.add("chromatic", amt=5)
155
+ chain.add("kaleidoscope", folds=6)
156
+ chain.add("vignette", s=0.2)
157
+ chain.add("grain", amt=12)
158
+ canvas = chain.apply(canvas, f=features, t=time)
159
+ """
160
+ def __init__(self):
161
+ self.steps = []
162
+
163
+ def add(self, shader_name, **kwargs):
164
+ self.steps.append((shader_name, kwargs))
165
+ return self # chainable
166
+
167
+ def apply(self, canvas, f=None, t=0):
168
+ if f is None: f = {}
169
+ for name, kwargs in self.steps:
170
+ canvas = _apply_shader_step(canvas, name, kwargs, f, t)
171
+ return canvas
172
+ ```
173
+
174
+ ### `_apply_shader_step()` — Full Dispatch Function
175
+
176
+ Routes shader names to implementations. Some shaders have **audio-reactive scaling** — the dispatch function reads `f["bdecay"]` and `f["rms"]` to modulate parameters on the beat.
177
+
178
+ ```python
179
+ def _apply_shader_step(canvas, name, kwargs, f, t):
180
+ """Dispatch a single shader by name with kwargs.
181
+
182
+ Args:
183
+ canvas: uint8 (H,W,3) pixel array
184
+ name: shader key string (e.g. "bloom", "chromatic")
185
+ kwargs: dict of shader parameters
186
+ f: audio features dict (keys: bdecay, rms, sub, etc.)
187
+ t: current time in seconds (float)
188
+ Returns:
189
+ canvas: uint8 (H,W,3) — processed
190
+ """
191
+ bd = f.get("bdecay", 0) # beat decay (0-1, high on beat)
192
+ rms = f.get("rms", 0.3) # audio energy (0-1)
193
+
194
+ # --- Geometry ---
195
+ if name == "crt":
196
+ return sh_crt(canvas, kwargs.get("strength", 0.05))
197
+ elif name == "pixelate":
198
+ return sh_pixelate(canvas, kwargs.get("block", 4))
199
+ elif name == "wave_distort":
200
+ return sh_wave_distort(canvas, t,
201
+ kwargs.get("freq", 0.02), kwargs.get("amp", 8), kwargs.get("axis", "x"))
202
+ elif name == "kaleidoscope":
203
+ return sh_kaleidoscope(canvas.copy(), kwargs.get("folds", 6))
204
+ elif name == "mirror_h":
205
+ return sh_mirror_h(canvas.copy())
206
+ elif name == "mirror_v":
207
+ return sh_mirror_v(canvas.copy())
208
+ elif name == "mirror_quad":
209
+ return sh_mirror_quad(canvas.copy())
210
+ elif name == "mirror_diag":
211
+ return sh_mirror_diag(canvas.copy())
212
+
213
+ # --- Channel ---
214
+ elif name == "chromatic":
215
+ base = kwargs.get("amt", 3)
216
+ return sh_chromatic(canvas, max(1, int(base * (0.4 + bd * 0.8))))
217
+ elif name == "channel_shift":
218
+ return sh_channel_shift(canvas,
219
+ kwargs.get("r", (0,0)), kwargs.get("g", (0,0)), kwargs.get("b", (0,0)))
220
+ elif name == "channel_swap":
221
+ return sh_channel_swap(canvas, kwargs.get("order", (2,1,0)))
222
+ elif name == "rgb_split_radial":
223
+ return sh_rgb_split_radial(canvas, kwargs.get("strength", 5))
224
+
225
+ # --- Color ---
226
+ elif name == "invert":
227
+ return sh_invert(canvas)
228
+ elif name == "posterize":
229
+ return sh_posterize(canvas, kwargs.get("levels", 4))
230
+ elif name == "threshold":
231
+ return sh_threshold(canvas, kwargs.get("thr", 128))
232
+ elif name == "solarize":
233
+ return sh_solarize(canvas, kwargs.get("threshold", 128))
234
+ elif name == "hue_rotate":
235
+ return sh_hue_rotate(canvas, kwargs.get("amount", 0.1))
236
+ elif name == "saturation":
237
+ return sh_saturation(canvas, kwargs.get("factor", 1.5))
238
+ elif name == "color_grade":
239
+ return sh_color_grade(canvas, kwargs.get("tint", (1,1,1)))
240
+ elif name == "color_wobble":
241
+ return sh_color_wobble(canvas, t, kwargs.get("amt", 0.3) * (0.5 + rms * 0.8))
242
+ elif name == "color_ramp":
243
+ return sh_color_ramp(canvas, kwargs.get("ramp", [(0,0,0),(255,255,255)]))
244
+
245
+ # --- Glow / Blur ---
246
+ elif name == "bloom":
247
+ return sh_bloom(canvas, kwargs.get("thr", 130))
248
+ elif name == "edge_glow":
249
+ return sh_edge_glow(canvas, kwargs.get("hue", 0.5))
250
+ elif name == "soft_focus":
251
+ return sh_soft_focus(canvas, kwargs.get("strength", 0.3))
252
+ elif name == "radial_blur":
253
+ return sh_radial_blur(canvas, kwargs.get("strength", 0.03))
254
+
255
+ # --- Noise ---
256
+ elif name == "grain":
257
+ return sh_grain(canvas, int(kwargs.get("amt", 10) * (0.5 + rms * 0.8)))
258
+ elif name == "static":
259
+ return sh_static_noise(canvas, kwargs.get("density", 0.05), kwargs.get("color", True))
260
+
261
+ # --- Lines / Patterns ---
262
+ elif name == "scanlines":
263
+ return sh_scanlines(canvas, kwargs.get("intensity", 0.08), kwargs.get("spacing", 3))
264
+ elif name == "halftone":
265
+ return sh_halftone(canvas, kwargs.get("dot_size", 6))
266
+
267
+ # --- Tone ---
268
+ elif name == "vignette":
269
+ return sh_vignette(canvas, kwargs.get("s", 0.22))
270
+ elif name == "contrast":
271
+ return sh_contrast(canvas, kwargs.get("factor", 1.3))
272
+ elif name == "gamma":
273
+ return sh_gamma(canvas, kwargs.get("gamma", 1.5))
274
+ elif name == "levels":
275
+ return sh_levels(canvas,
276
+ kwargs.get("black", 0), kwargs.get("white", 255), kwargs.get("midtone", 1.0))
277
+ elif name == "brightness":
278
+ return sh_brightness(canvas, kwargs.get("factor", 1.5))
279
+
280
+ # --- Glitch / Data ---
281
+ elif name == "glitch_bands":
282
+ return sh_glitch_bands(canvas, f)
283
+ elif name == "block_glitch":
284
+ return sh_block_glitch(canvas, kwargs.get("n_blocks", 8), kwargs.get("max_size", 40))
285
+ elif name == "pixel_sort":
286
+ return sh_pixel_sort(canvas, kwargs.get("threshold", 100), kwargs.get("direction", "h"))
287
+ elif name == "data_bend":
288
+ return sh_data_bend(canvas, kwargs.get("offset", 1000), kwargs.get("chunk", 500))
289
+
290
+ else:
291
+ return canvas # unknown shader — passthrough
292
+ ```
293
+
294
+ ### Audio-Reactive Shaders
295
+
296
+ Three shaders scale their parameters based on audio features:
297
+
298
+ | Shader | Reactive To | Effect |
299
+ |--------|------------|--------|
300
+ | `chromatic` | `bdecay` | `amt * (0.4 + bdecay * 0.8)` — aberration kicks on beats |
301
+ | `color_wobble` | `rms` | `amt * (0.5 + rms * 0.8)` — wobble intensity follows energy |
302
+ | `grain` | `rms` | `amt * (0.5 + rms * 0.8)` — grain rougher in loud sections |
303
+ | `glitch_bands` | `bdecay`, `sub` | Number of bands and displacement scale with beat energy |
304
+
305
+ To make any shader beat-reactive, scale its parameter in the dispatch: `base_val * (low + bd * range)`.
306
+
307
+ ---
308
+
309
+ ## Full Shader Catalog
310
+
311
+ ### Geometry Shaders
312
+
313
+ | Shader | Key Params | Description |
314
+ |--------|-----------|-------------|
315
+ | `crt` | `strength=0.05` | CRT barrel distortion (cached remap) |
316
+ | `pixelate` | `block=4` | Reduce effective resolution |
317
+ | `wave_distort` | `freq, amp, axis` | Sinusoidal row/column displacement |
318
+ | `kaleidoscope` | `folds=6` | Radial symmetry via polar remapping |
319
+ | `mirror_h` | — | Horizontal mirror |
320
+ | `mirror_v` | — | Vertical mirror |
321
+ | `mirror_quad` | — | 4-fold mirror |
322
+ | `mirror_diag` | — | Diagonal mirror |
323
+
324
+ ### Channel Manipulation
325
+
326
+ | Shader | Key Params | Description |
327
+ |--------|-----------|-------------|
328
+ | `chromatic` | `amt=3` | R/B channel horizontal shift (beat-reactive) |
329
+ | `channel_shift` | `r=(sx,sy), g, b` | Independent per-channel x,y shifting |
330
+ | `channel_swap` | `order=(2,1,0)` | Reorder RGB channels (BGR, GRB, etc.) |
331
+ | `rgb_split_radial` | `strength=5` | Chromatic aberration radiating from center |
332
+
333
+ ### Color Manipulation
334
+
335
+ | Shader | Key Params | Description |
336
+ |--------|-----------|-------------|
337
+ | `invert` | — | Negate all colors |
338
+ | `posterize` | `levels=4` | Reduce color depth to N levels |
339
+ | `threshold` | `thr=128` | Binary black/white |
340
+ | `solarize` | `threshold=128` | Invert pixels above threshold |
341
+ | `hue_rotate` | `amount=0.1` | Rotate all hues by amount (0-1) |
342
+ | `saturation` | `factor=1.5` | Scale saturation (>1=more, <1=less) |
343
+ | `color_grade` | `tint=(r,g,b)` | Per-channel multiplier |
344
+ | `color_wobble` | `amt=0.3` | Time-varying per-channel sine modulation |
345
+ | `color_ramp` | `ramp=[(R,G,B),...]` | Map luminance to custom color gradient |
346
+
347
+ ### Glow / Blur
348
+
349
+ | Shader | Key Params | Description |
350
+ |--------|-----------|-------------|
351
+ | `bloom` | `thr=130` | Bright area glow (4x downsample + box blur) |
352
+ | `edge_glow` | `hue=0.5` | Detect edges, add colored overlay |
353
+ | `soft_focus` | `strength=0.3` | Blend with blurred version |
354
+ | `radial_blur` | `strength=0.03` | Zoom blur from center outward |
355
+
356
+ ### Noise / Grain
357
+
358
+ | Shader | Key Params | Description |
359
+ |--------|-----------|-------------|
360
+ | `grain` | `amt=10` | 2x-downsampled film grain (beat-reactive) |
361
+ | `static` | `density=0.05, color=True` | Random pixel noise (TV static) |
362
+
363
+ ### Lines / Patterns
364
+
365
+ | Shader | Key Params | Description |
366
+ |--------|-----------|-------------|
367
+ | `scanlines` | `intensity=0.08, spacing=3` | Darken every Nth row |
368
+ | `halftone` | `dot_size=6` | Halftone dot pattern overlay |
369
+
370
+ ### Tone
371
+
372
+ | Shader | Key Params | Description |
373
+ |--------|-----------|-------------|
374
+ | `vignette` | `s=0.22` | Edge darkening (cached distance field) |
375
+ | `contrast` | `factor=1.3` | Adjust contrast around midpoint 128 |
376
+ | `gamma` | `gamma=1.5` | Gamma correction (>1=brighter mids) |
377
+ | `levels` | `black, white, midtone` | Levels adjustment (Photoshop-style) |
378
+ | `brightness` | `factor=1.5` | Global brightness multiplier |
379
+
380
+ ### Glitch / Data
381
+
382
+ | Shader | Key Params | Description |
383
+ |--------|-----------|-------------|
384
+ | `glitch_bands` | (uses `f`) | Beat-reactive horizontal row displacement |
385
+ | `block_glitch` | `n_blocks=8, max_size=40` | Random rectangular block displacement |
386
+ | `pixel_sort` | `threshold=100, direction="h"` | Sort pixels by brightness in rows/columns |
387
+ | `data_bend` | `offset, chunk` | Raw byte displacement (datamoshing) |
388
+
389
+ ---
390
+
391
+ ## Shader Implementations
392
+
393
+ Every shader function takes a canvas (`uint8 H,W,3`) and returns a canvas of the same shape. The naming convention is `sh_<name>`. Geometry shaders that build coordinate remap tables should **cache** them since the table only depends on resolution + parameters, not on frame content.
394
+
395
+ ### Helpers
396
+
397
+ Shaders that manipulate hue/saturation need vectorized HSV conversion:
398
+
399
+ ```python
400
+ def rgb2hsv(r, g, b):
401
+ """Vectorized RGB (0-255 uint8) -> HSV (float32 0-1)."""
402
+ rf = r.astype(np.float32) / 255.0
403
+ gf = g.astype(np.float32) / 255.0
404
+ bf = b.astype(np.float32) / 255.0
405
+ cmax = np.maximum(np.maximum(rf, gf), bf)
406
+ cmin = np.minimum(np.minimum(rf, gf), bf)
407
+ delta = cmax - cmin + 1e-10
408
+ h = np.zeros_like(rf)
409
+ m = cmax == rf; h[m] = ((gf[m] - bf[m]) / delta[m]) % 6
410
+ m = cmax == gf; h[m] = (bf[m] - rf[m]) / delta[m] + 2
411
+ m = cmax == bf; h[m] = (rf[m] - gf[m]) / delta[m] + 4
412
+ h = h / 6.0 % 1.0
413
+ s = np.where(cmax > 0, delta / (cmax + 1e-10), 0)
414
+ return h, s, cmax
415
+
416
+ def hsv2rgb(h, s, v):
417
+ """Vectorized HSV->RGB. h,s,v are numpy float32 arrays."""
418
+ h = h % 1.0
419
+ c = v * s; x = c * (1 - np.abs((h * 6) % 2 - 1)); m = v - c
420
+ r = np.zeros_like(h); g = np.zeros_like(h); b = np.zeros_like(h)
421
+ mask = h < 1/6; r[mask]=c[mask]; g[mask]=x[mask]
422
+ mask = (h>=1/6)&(h<2/6); r[mask]=x[mask]; g[mask]=c[mask]
423
+ mask = (h>=2/6)&(h<3/6); g[mask]=c[mask]; b[mask]=x[mask]
424
+ mask = (h>=3/6)&(h<4/6); g[mask]=x[mask]; b[mask]=c[mask]
425
+ mask = (h>=4/6)&(h<5/6); r[mask]=x[mask]; b[mask]=c[mask]
426
+ mask = h >= 5/6; r[mask]=c[mask]; b[mask]=x[mask]
427
+ R = np.clip((r+m)*255, 0, 255).astype(np.uint8)
428
+ G = np.clip((g+m)*255, 0, 255).astype(np.uint8)
429
+ B = np.clip((b+m)*255, 0, 255).astype(np.uint8)
430
+ return R, G, B
431
+
432
+ def mkc(R, G, B, rows, cols):
433
+ """Stack R,G,B uint8 arrays into (rows,cols,3) canvas."""
434
+ o = np.zeros((rows, cols, 3), dtype=np.uint8)
435
+ o[:,:,0] = R; o[:,:,1] = G; o[:,:,2] = B
436
+ return o
437
+ ```
438
+
439
+ ---
440
+
441
+ ### Geometry Shaders
442
+
443
+ #### CRT Barrel Distortion
444
+ Cache the coordinate remap — it never changes per frame:
445
+ ```python
446
+ _crt_cache = {}
447
+ def sh_crt(c, strength=0.05):
448
+ k = (c.shape[0], c.shape[1], round(strength, 3))
449
+ if k not in _crt_cache:
450
+ h, w = c.shape[:2]; cy, cx = h/2, w/2
451
+ Y = np.arange(h, dtype=np.float32)[:, None]
452
+ X = np.arange(w, dtype=np.float32)[None, :]
453
+ ny = (Y - cy) / cy; nx = (X - cx) / cx
454
+ r2 = nx**2 + ny**2
455
+ factor = 1 + strength * r2
456
+ sx = np.clip((nx * factor * cx + cx), 0, w-1).astype(np.int32)
457
+ sy = np.clip((ny * factor * cy + cy), 0, h-1).astype(np.int32)
458
+ _crt_cache[k] = (sy, sx)
459
+ sy, sx = _crt_cache[k]
460
+ return c[sy, sx]
461
+ ```
462
+
463
+ #### Pixelate
464
+ ```python
465
+ def sh_pixelate(c, block=4):
466
+ """Reduce effective resolution."""
467
+ sm = c[::block, ::block]
468
+ return np.repeat(np.repeat(sm, block, axis=0), block, axis=1)[:c.shape[0], :c.shape[1]]
469
+ ```
470
+
471
+ #### Wave Distort
472
+ ```python
473
+ def sh_wave_distort(c, t, freq=0.02, amp=8, axis="x"):
474
+ """Sinusoidal row/column displacement. Uses time t for animation."""
475
+ h, w = c.shape[:2]
476
+ out = c.copy()
477
+ if axis == "x":
478
+ for y in range(h):
479
+ shift = int(amp * math.sin(y * freq + t * 3))
480
+ out[y] = np.roll(c[y], shift, axis=0)
481
+ else:
482
+ for x in range(w):
483
+ shift = int(amp * math.sin(x * freq + t * 3))
484
+ out[:, x] = np.roll(c[:, x], shift, axis=0)
485
+ return out
486
+ ```
487
+
488
+ #### Displacement Map
489
+ ```python
490
+ def sh_displacement_map(c, dx_map, dy_map, strength=10):
491
+ """Displace pixels using float32 displacement maps (same HxW as c).
492
+ dx_map/dy_map: positive = shift right/down."""
493
+ h, w = c.shape[:2]
494
+ Y = np.arange(h)[:, None]; X = np.arange(w)[None, :]
495
+ ny = np.clip((Y + (dy_map * strength).astype(int)), 0, h-1)
496
+ nx = np.clip((X + (dx_map * strength).astype(int)), 0, w-1)
497
+ return c[ny, nx]
498
+ ```
499
+
500
+ #### Kaleidoscope
501
+ ```python
502
+ def sh_kaleidoscope(c, folds=6):
503
+ """Radial symmetry by polar coordinate remapping."""
504
+ h, w = c.shape[:2]; cy, cx = h//2, w//2
505
+ Y = np.arange(h, dtype=np.float32)[:, None] - cy
506
+ X = np.arange(w, dtype=np.float32)[None, :] - cx
507
+ angle = np.arctan2(Y, X)
508
+ dist = np.sqrt(X**2 + Y**2)
509
+ wedge = 2 * np.pi / folds
510
+ folded_angle = np.abs((angle % wedge) - wedge/2)
511
+ ny = np.clip((cy + dist * np.sin(folded_angle)).astype(int), 0, h-1)
512
+ nx = np.clip((cx + dist * np.cos(folded_angle)).astype(int), 0, w-1)
513
+ return c[ny, nx]
514
+ ```
515
+
516
+ #### Mirror Variants
517
+ ```python
518
+ def sh_mirror_h(c):
519
+ """Horizontal mirror — left half reflected to right."""
520
+ w = c.shape[1]; half = w // 2
521
+ c[:, w-half:] = c[:, :half][:, ::-1]
522
+ return c
523
+
524
+ def sh_mirror_v(c):
525
+ """Vertical mirror — top half reflected to bottom."""
526
+ h = c.shape[0]; half = h // 2
527
+ c[h-half:, :] = c[:half, :][::-1, :]
528
+ return c
529
+
530
+ def sh_mirror_quad(c):
531
+ """4-fold mirror — top-left quadrant reflected to all four."""
532
+ return sh_mirror_v(sh_mirror_h(c))
533
+
534
+ def sh_mirror_diag(c):
535
+ """Diagonal mirror — top-left triangle reflected."""
536
+ h, w = c.shape[:2]
537
+ for y in range(h):
538
+ x_cut = int(w * y / h)
539
+ if x_cut > 0 and x_cut < w:
540
+ c[y, x_cut:] = c[y, :x_cut+1][::-1][:w-x_cut]
541
+ return c
542
+ ```
543
+
544
+ > **Note:** Mirror shaders mutate in-place. The dispatch function passes `canvas.copy()` to avoid corrupting the original.
545
+
546
+ ---
547
+
548
+ ### Channel Manipulation Shaders
549
+
550
+ #### Chromatic Aberration
551
+ ```python
552
+ def sh_chromatic(c, amt=3):
553
+ """R/B channel horizontal shift. Beat-reactive in dispatch (amt scaled by bdecay)."""
554
+ if amt < 1: return c
555
+ a = int(amt)
556
+ o = c.copy()
557
+ o[:, a:, 0] = c[:, :-a, 0] # red shifts right
558
+ o[:, :-a, 2] = c[:, a:, 2] # blue shifts left
559
+ return o
560
+ ```
561
+
562
+ #### Channel Shift
563
+ ```python
564
+ def sh_channel_shift(c, r_shift=(0,0), g_shift=(0,0), b_shift=(0,0)):
565
+ """Independent per-channel x,y shifting."""
566
+ o = c.copy()
567
+ for ch_i, (sx, sy) in enumerate([r_shift, g_shift, b_shift]):
568
+ if sx != 0: o[:,:,ch_i] = np.roll(c[:,:,ch_i], sx, axis=1)
569
+ if sy != 0: o[:,:,ch_i] = np.roll(o[:,:,ch_i], sy, axis=0)
570
+ return o
571
+ ```
572
+
573
+ #### Channel Swap
574
+ ```python
575
+ def sh_channel_swap(c, order=(2,1,0)):
576
+ """Reorder RGB channels. (2,1,0)=BGR, (1,0,2)=GRB, etc."""
577
+ return c[:, :, list(order)]
578
+ ```
579
+
580
+ #### RGB Split Radial
581
+ ```python
582
+ def sh_rgb_split_radial(c, strength=5):
583
+ """Chromatic aberration radiating from center — stronger at edges."""
584
+ h, w = c.shape[:2]; cy, cx = h//2, w//2
585
+ Y = np.arange(h, dtype=np.float32)[:, None]
586
+ X = np.arange(w, dtype=np.float32)[None, :]
587
+ dist = np.sqrt((Y-cy)**2 + (X-cx)**2)
588
+ max_dist = np.sqrt(cy**2 + cx**2)
589
+ factor = dist / max_dist * strength
590
+ dy = ((Y-cy) / (dist+1) * factor).astype(int)
591
+ dx = ((X-cx) / (dist+1) * factor).astype(int)
592
+ out = c.copy()
593
+ ry = np.clip(Y.astype(int)+dy, 0, h-1); rx = np.clip(X.astype(int)+dx, 0, w-1)
594
+ out[:,:,0] = c[ry, rx, 0] # red shifts outward
595
+ by = np.clip(Y.astype(int)-dy, 0, h-1); bx = np.clip(X.astype(int)-dx, 0, w-1)
596
+ out[:,:,2] = c[by, bx, 2] # blue shifts inward
597
+ return out
598
+ ```
599
+
600
+ ---
601
+
602
+ ### Color Manipulation Shaders
603
+
604
+ #### Invert
605
+ ```python
606
+ def sh_invert(c):
607
+ return 255 - c
608
+ ```
609
+
610
+ #### Posterize
611
+ ```python
612
+ def sh_posterize(c, levels=4):
613
+ """Reduce color depth to N levels per channel."""
614
+ step = 256.0 / levels
615
+ return (np.floor(c.astype(np.float32) / step) * step).astype(np.uint8)
616
+ ```
617
+
618
+ #### Threshold
619
+ ```python
620
+ def sh_threshold(c, thr=128):
621
+ """Binary black/white at threshold."""
622
+ gray = c.astype(np.float32).mean(axis=2)
623
+ out = np.zeros_like(c); out[gray > thr] = 255
624
+ return out
625
+ ```
626
+
627
+ #### Solarize
628
+ ```python
629
+ def sh_solarize(c, threshold=128):
630
+ """Invert pixels above threshold — classic darkroom effect."""
631
+ o = c.copy(); mask = c > threshold; o[mask] = 255 - c[mask]
632
+ return o
633
+ ```
634
+
635
+ #### Hue Rotate
636
+ ```python
637
+ def sh_hue_rotate(c, amount=0.1):
638
+ """Rotate all hues by amount (0-1)."""
639
+ h, s, v = rgb2hsv(c[:,:,0], c[:,:,1], c[:,:,2])
640
+ h = (h + amount) % 1.0
641
+ R, G, B = hsv2rgb(h, s, v)
642
+ return mkc(R, G, B, c.shape[0], c.shape[1])
643
+ ```
644
+
645
+ #### Saturation
646
+ ```python
647
+ def sh_saturation(c, factor=1.5):
648
+ """Adjust saturation. >1=more saturated, <1=desaturated."""
649
+ h, s, v = rgb2hsv(c[:,:,0], c[:,:,1], c[:,:,2])
650
+ s = np.clip(s * factor, 0, 1)
651
+ R, G, B = hsv2rgb(h, s, v)
652
+ return mkc(R, G, B, c.shape[0], c.shape[1])
653
+ ```
654
+
655
+ #### Color Grade
656
+ ```python
657
+ def sh_color_grade(c, tint):
658
+ """Per-channel multiplier. tint=(r_mul, g_mul, b_mul)."""
659
+ o = c.astype(np.float32)
660
+ o[:,:,0] *= tint[0]; o[:,:,1] *= tint[1]; o[:,:,2] *= tint[2]
661
+ return np.clip(o, 0, 255).astype(np.uint8)
662
+ ```
663
+
664
+ #### Color Wobble
665
+ ```python
666
+ def sh_color_wobble(c, t, amt=0.3):
667
+ """Time-varying per-channel sine modulation. Audio-reactive in dispatch (amt scaled by rms)."""
668
+ o = c.astype(np.float32)
669
+ o[:,:,0] *= 1.0 + amt * math.sin(t * 5.0)
670
+ o[:,:,1] *= 1.0 + amt * math.sin(t * 5.0 + 2.09)
671
+ o[:,:,2] *= 1.0 + amt * math.sin(t * 5.0 + 4.19)
672
+ return np.clip(o, 0, 255).astype(np.uint8)
673
+ ```
674
+
675
+ #### Color Ramp
676
+ ```python
677
+ def sh_color_ramp(c, ramp_colors):
678
+ """Map luminance to a custom color gradient.
679
+ ramp_colors = list of (R,G,B) tuples, evenly spaced from dark to bright."""
680
+ gray = c.astype(np.float32).mean(axis=2) / 255.0
681
+ n = len(ramp_colors)
682
+ idx = np.clip(gray * (n-1), 0, n-1.001)
683
+ lo = np.floor(idx).astype(int); hi = np.minimum(lo+1, n-1)
684
+ frac = idx - lo
685
+ ramp = np.array(ramp_colors, dtype=np.float32)
686
+ out = ramp[lo] * (1-frac[:,:,None]) + ramp[hi] * frac[:,:,None]
687
+ return np.clip(out, 0, 255).astype(np.uint8)
688
+ ```
689
+
690
+ ---
691
+
692
+ ### Glow / Blur Shaders
693
+
694
+ #### Bloom
695
+ ```python
696
+ def sh_bloom(c, thr=130):
697
+ """Bright-area glow: 4x downsample, threshold, 3-pass box blur, screen blend."""
698
+ sm = c[::4, ::4].astype(np.float32)
699
+ br = np.where(sm > thr, sm, 0)
700
+ for _ in range(3):
701
+ p = np.pad(br, ((1,1),(1,1),(0,0)), mode="edge")
702
+ br = (p[:-2,:-2]+p[:-2,1:-1]+p[:-2,2:]+p[1:-1,:-2]+p[1:-1,1:-1]+
703
+ p[1:-1,2:]+p[2:,:-2]+p[2:,1:-1]+p[2:,2:]) / 9.0
704
+ bl = np.repeat(np.repeat(br, 4, axis=0), 4, axis=1)[:c.shape[0], :c.shape[1]]
705
+ return np.clip(c.astype(np.float32) + bl * 0.5, 0, 255).astype(np.uint8)
706
+ ```
707
+
708
+ #### Edge Glow
709
+ ```python
710
+ def sh_edge_glow(c, hue=0.5):
711
+ """Detect edges via gradient, add colored overlay."""
712
+ gray = c.astype(np.float32).mean(axis=2)
713
+ gx = np.abs(gray[:, 2:] - gray[:, :-2])
714
+ gy = np.abs(gray[2:, :] - gray[:-2, :])
715
+ ex = np.zeros_like(gray); ey = np.zeros_like(gray)
716
+ ex[:, 1:-1] = gx; ey[1:-1, :] = gy
717
+ edge = np.clip((ex + ey) / 255 * 2, 0, 1)
718
+ R, G, B = hsv2rgb(np.full_like(edge, hue), np.full_like(edge, 0.8), edge * 0.5)
719
+ out = c.astype(np.int16).copy()
720
+ out[:,:,0] = np.clip(out[:,:,0] + R.astype(np.int16), 0, 255)
721
+ out[:,:,1] = np.clip(out[:,:,1] + G.astype(np.int16), 0, 255)
722
+ out[:,:,2] = np.clip(out[:,:,2] + B.astype(np.int16), 0, 255)
723
+ return out.astype(np.uint8)
724
+ ```
725
+
726
+ #### Soft Focus
727
+ ```python
728
+ def sh_soft_focus(c, strength=0.3):
729
+ """Blend original with 2x-downsampled box blur."""
730
+ sm = c[::2, ::2].astype(np.float32)
731
+ p = np.pad(sm, ((1,1),(1,1),(0,0)), mode="edge")
732
+ bl = (p[:-2,:-2]+p[:-2,1:-1]+p[:-2,2:]+p[1:-1,:-2]+p[1:-1,1:-1]+
733
+ p[1:-1,2:]+p[2:,:-2]+p[2:,1:-1]+p[2:,2:]) / 9.0
734
+ bl = np.repeat(np.repeat(bl, 2, axis=0), 2, axis=1)[:c.shape[0], :c.shape[1]]
735
+ return np.clip(c * (1-strength) + bl * strength, 0, 255).astype(np.uint8)
736
+ ```
737
+
738
+ #### Radial Blur
739
+ ```python
740
+ def sh_radial_blur(c, strength=0.03, center=None):
741
+ """Zoom blur from center — motion blur radiating outward."""
742
+ h, w = c.shape[:2]
743
+ cy, cx = center if center else (h//2, w//2)
744
+ Y = np.arange(h, dtype=np.float32)[:, None]
745
+ X = np.arange(w, dtype=np.float32)[None, :]
746
+ out = c.astype(np.float32)
747
+ for s in [strength, strength*2]:
748
+ dy = (Y - cy) * s; dx = (X - cx) * s
749
+ sy = np.clip((Y + dy).astype(int), 0, h-1)
750
+ sx = np.clip((X + dx).astype(int), 0, w-1)
751
+ out += c[sy, sx].astype(np.float32)
752
+ return np.clip(out / 3, 0, 255).astype(np.uint8)
753
+ ```
754
+
755
+ ---
756
+
757
+ ### Noise / Grain Shaders
758
+
759
+ #### Film Grain
760
+ ```python
761
+ def sh_grain(c, amt=10):
762
+ """2x-downsampled film grain. Audio-reactive in dispatch (amt scaled by rms)."""
763
+ noise = np.random.randint(-amt, amt+1, ((c.shape[0]+1)//2, (c.shape[1]+1)//2, 1), dtype=np.int16)
764
+ noise = np.repeat(np.repeat(noise, 2, axis=0), 2, axis=1)[:c.shape[0], :c.shape[1]]
765
+ return np.clip(c.astype(np.int16) + noise, 0, 255).astype(np.uint8)
766
+ ```
767
+
768
+ #### Static Noise
769
+ ```python
770
+ def sh_static_noise(c, density=0.05, color=True):
771
+ """Random pixel noise overlay (TV static)."""
772
+ mask = np.random.random(((c.shape[0]+1)//2, (c.shape[1]+1)//2)) < density
773
+ mask = np.repeat(np.repeat(mask, 2, axis=0), 2, axis=1)[:c.shape[0], :c.shape[1]]
774
+ out = c.copy()
775
+ if color:
776
+ noise = np.random.randint(0, 256, (c.shape[0], c.shape[1], 3), dtype=np.uint8)
777
+ else:
778
+ v = np.random.randint(0, 256, (c.shape[0], c.shape[1]), dtype=np.uint8)
779
+ noise = np.stack([v, v, v], axis=2)
780
+ out[mask] = noise[mask]
781
+ return out
782
+ ```
783
+
784
+ ---
785
+
786
+ ### Lines / Pattern Shaders
787
+
788
+ #### Scanlines
789
+ ```python
790
+ def sh_scanlines(c, intensity=0.08, spacing=3):
791
+ """Darken every Nth row."""
792
+ m = np.ones(c.shape[0], dtype=np.float32)
793
+ m[::spacing] = 1.0 - intensity
794
+ return np.clip(c * m[:, None, None], 0, 255).astype(np.uint8)
795
+ ```
796
+
797
+ #### Halftone
798
+ ```python
799
+ def sh_halftone(c, dot_size=6):
800
+ """Halftone dot pattern overlay — circular dots sized by local brightness."""
801
+ h, w = c.shape[:2]
802
+ gray = c.astype(np.float32).mean(axis=2) / 255.0
803
+ out = np.zeros_like(c)
804
+ for y in range(0, h, dot_size):
805
+ for x in range(0, w, dot_size):
806
+ block = gray[y:y+dot_size, x:x+dot_size]
807
+ if block.size == 0: continue
808
+ radius = block.mean() * dot_size * 0.5
809
+ cy_b, cx_b = dot_size//2, dot_size//2
810
+ for dy in range(min(dot_size, h-y)):
811
+ for dx in range(min(dot_size, w-x)):
812
+ if math.sqrt((dy-cy_b)**2 + (dx-cx_b)**2) < radius:
813
+ out[y+dy, x+dx] = c[y+dy, x+dx]
814
+ return out
815
+ ```
816
+
817
+ > **Performance note:** Halftone is slow due to Python loops. Acceptable for small resolutions or single test frames. For production, consider a vectorized version using precomputed distance masks.
818
+
819
+ ---
820
+
821
+ ### Tone Shaders
822
+
823
+ #### Vignette
824
+ ```python
825
+ _vig_cache = {}
826
+ def sh_vignette(c, s=0.22):
827
+ """Edge darkening using cached distance field."""
828
+ k = (c.shape[0], c.shape[1], round(s, 2))
829
+ if k not in _vig_cache:
830
+ h, w = c.shape[:2]
831
+ Y = np.linspace(-1, 1, h)[:, None]; X = np.linspace(-1, 1, w)[None, :]
832
+ _vig_cache[k] = np.clip(1.0 - np.sqrt(X**2 + Y**2) * s, 0.15, 1).astype(np.float32)
833
+ return np.clip(c * _vig_cache[k][:,:,None], 0, 255).astype(np.uint8)
834
+ ```
835
+
836
+ #### Reverse Vignette
837
+
838
+ Inverted vignette: darkens the **center** and leaves edges bright. Useful when text is centered over busy backgrounds — creates a natural dark zone for readability without a hard-edged box.
839
+
840
+ Combine with `apply_text_backdrop()` (see composition.md) for per-frame glyph-aware darkening.
841
+
842
+ ```python
843
+ _rvignette_cache = {}
844
+
845
+ def sh_reverse_vignette(c, strength=0.5):
846
+ """Center darkening, edge brightening. Cached."""
847
+ k = ('rv', c.shape[0], c.shape[1], round(strength, 2))
848
+ if k not in _rvignette_cache:
849
+ h, w = c.shape[:2]
850
+ Y = np.linspace(-1, 1, h)[:, None]
851
+ X = np.linspace(-1, 1, w)[None, :]
852
+ d = np.sqrt(X**2 + Y**2)
853
+ # Invert: bright at edges, dark at center
854
+ mask = np.clip(1.0 - (1.0 - d * 0.7) * strength, 0.2, 1.0)
855
+ _rvignette_cache[k] = mask[:, :, np.newaxis].astype(np.float32)
856
+ return np.clip(c.astype(np.float32) * _rvignette_cache[k], 0, 255).astype(np.uint8)
857
+ ```
858
+
859
+ | Param | Default | Effect |
860
+ |-------|---------|--------|
861
+ | `strength` | 0.5 | 0 = no effect, 1.0 = center nearly black |
862
+
863
+ Add to ShaderChain dispatch:
864
+ ```python
865
+ elif name == "reverse_vignette":
866
+ return sh_reverse_vignette(canvas, kwargs.get("strength", 0.5))
867
+ ```
868
+
869
+ #### Contrast
870
+ ```python
871
+ def sh_contrast(c, factor=1.3):
872
+ """Adjust contrast around midpoint 128."""
873
+ return np.clip((c.astype(np.float32) - 128) * factor + 128, 0, 255).astype(np.uint8)
874
+ ```
875
+
876
+ #### Gamma
877
+ ```python
878
+ def sh_gamma(c, gamma=1.5):
879
+ """Gamma correction. >1=brighter mids, <1=darker mids."""
880
+ return np.clip(((c.astype(np.float32)/255.0) ** (1.0/gamma)) * 255, 0, 255).astype(np.uint8)
881
+ ```
882
+
883
+ #### Levels
884
+ ```python
885
+ def sh_levels(c, black=0, white=255, midtone=1.0):
886
+ """Levels adjustment (Photoshop-style). Remap black/white points, apply midtone gamma."""
887
+ o = (c.astype(np.float32) - black) / max(1, white - black)
888
+ o = np.clip(o, 0, 1) ** (1.0 / midtone)
889
+ return (o * 255).astype(np.uint8)
890
+ ```
891
+
892
+ #### Brightness
893
+ ```python
894
+ def sh_brightness(c, factor=1.5):
895
+ """Global brightness multiplier. Prefer tonemap() for scene-level brightness control."""
896
+ return np.clip(c.astype(np.float32) * factor, 0, 255).astype(np.uint8)
897
+ ```
898
+
899
+ ---
900
+
901
+ ### Glitch / Data Shaders
902
+
903
+ #### Glitch Bands
904
+ ```python
905
+ def sh_glitch_bands(c, f):
906
+ """Beat-reactive horizontal row displacement. f = audio features dict.
907
+ Uses f["bdecay"] for intensity and f["sub"] for band height."""
908
+ n = int(3 + f.get("bdecay", 0) * 10)
909
+ out = c.copy()
910
+ for _ in range(n):
911
+ y = random.randint(0, c.shape[0]-1)
912
+ h = random.randint(1, max(2, int(4 + f.get("sub", 0.3) * 12)))
913
+ shift = int((random.random()-0.5) * f.get("bdecay", 0) * 60)
914
+ if shift != 0 and y+h < c.shape[0]:
915
+ out[y:y+h] = np.roll(out[y:y+h], shift, axis=1)
916
+ return out
917
+ ```
918
+
919
+ #### Block Glitch
920
+ ```python
921
+ def sh_block_glitch(c, n_blocks=8, max_size=40):
922
+ """Random rectangular block displacement — copy blocks to random positions."""
923
+ out = c.copy(); h, w = c.shape[:2]
924
+ for _ in range(n_blocks):
925
+ bw = random.randint(10, max_size); bh = random.randint(5, max_size//2)
926
+ sx = random.randint(0, w-bw-1); sy = random.randint(0, h-bh-1)
927
+ dx = random.randint(0, w-bw-1); dy = random.randint(0, h-bh-1)
928
+ out[dy:dy+bh, dx:dx+bw] = c[sy:sy+bh, sx:sx+bw]
929
+ return out
930
+ ```
931
+
932
+ #### Pixel Sort
933
+ ```python
934
+ def sh_pixel_sort(c, threshold=100, direction="h"):
935
+ """Sort pixels by brightness in contiguous bright regions."""
936
+ gray = c.astype(np.float32).mean(axis=2)
937
+ out = c.copy()
938
+ if direction == "h":
939
+ for y in range(0, c.shape[0], 3): # every 3rd row for speed
940
+ row_bright = gray[y]
941
+ mask = row_bright > threshold
942
+ regions = np.diff(np.concatenate([[0], mask.astype(int), [0]]))
943
+ starts = np.where(regions == 1)[0]
944
+ ends = np.where(regions == -1)[0]
945
+ for s, e in zip(starts, ends):
946
+ if e - s > 2:
947
+ indices = np.argsort(gray[y, s:e])
948
+ out[y, s:e] = c[y, s:e][indices]
949
+ else:
950
+ for x in range(0, c.shape[1], 3):
951
+ col_bright = gray[:, x]
952
+ mask = col_bright > threshold
953
+ regions = np.diff(np.concatenate([[0], mask.astype(int), [0]]))
954
+ starts = np.where(regions == 1)[0]
955
+ ends = np.where(regions == -1)[0]
956
+ for s, e in zip(starts, ends):
957
+ if e - s > 2:
958
+ indices = np.argsort(gray[s:e, x])
959
+ out[s:e, x] = c[s:e, x][indices]
960
+ return out
961
+ ```
962
+
963
+ #### Data Bend
964
+ ```python
965
+ def sh_data_bend(c, offset=1000, chunk=500):
966
+ """Treat raw pixel bytes as data, copy a chunk to another offset — datamosh artifacts."""
967
+ flat = c.flatten().copy()
968
+ n = len(flat)
969
+ src = offset % n; dst = (offset + chunk*3) % n
970
+ length = min(chunk, n-src, n-dst)
971
+ if length > 0:
972
+ flat[dst:dst+length] = flat[src:src+length]
973
+ return flat.reshape(c.shape)
974
+ ```
975
+
976
+ ---
977
+
978
+ ## Tint Presets
979
+
980
+ ```python
981
+ TINT_WARM = (1.15, 1.0, 0.85) # golden warmth
982
+ TINT_COOL = (0.85, 0.95, 1.15) # blue cool
983
+ TINT_MATRIX = (0.7, 1.2, 0.7) # green terminal
984
+ TINT_AMBER = (1.2, 0.9, 0.6) # amber monitor
985
+ TINT_SEPIA = (1.2, 1.05, 0.8) # old film
986
+ TINT_NEON_PINK = (1.3, 0.7, 1.1) # cyberpunk pink
987
+ TINT_ICE = (0.8, 1.0, 1.3) # frozen
988
+ TINT_BLOOD = (1.4, 0.7, 0.7) # horror red
989
+ TINT_FOREST = (0.8, 1.15, 0.75) # natural green
990
+ TINT_VOID = (0.85, 0.85, 1.1) # deep space
991
+ TINT_SUNSET = (1.3, 0.85, 0.7) # orange dusk
992
+ ```
993
+
994
+ ---
995
+
996
+ ## Transitions
997
+
998
+ > **Note:** These operate on character-level `(chars, colors)` arrays (v1 interface). In v2, transitions between scenes are typically handled by hard cuts at beat boundaries (see `scenes.md`), or by rendering both scenes to canvases and using `blend_canvas()` with a time-varying opacity. The character-level transitions below are still useful for within-scene effects.
999
+
1000
+ ### Crossfade
1001
+ ```python
1002
+ def tr_crossfade(ch_a, co_a, ch_b, co_b, blend):
1003
+ co = (co_a.astype(np.float32) * (1-blend) + co_b.astype(np.float32) * blend).astype(np.uint8)
1004
+ mask = np.random.random(ch_a.shape) < blend
1005
+ ch = ch_a.copy(); ch[mask] = ch_b[mask]
1006
+ return ch, co
1007
+ ```
1008
+
1009
+ ### v2 Canvas-Level Crossfade
1010
+ ```python
1011
+ def tr_canvas_crossfade(canvas_a, canvas_b, blend):
1012
+ """Smooth pixel crossfade between two canvases."""
1013
+ return np.clip(canvas_a * (1-blend) + canvas_b * blend, 0, 255).astype(np.uint8)
1014
+ ```
1015
+
1016
+ ### Wipe (directional)
1017
+ ```python
1018
+ def tr_wipe(ch_a, co_a, ch_b, co_b, blend, direction="left"):
1019
+ """direction: left, right, up, down, radial, diagonal"""
1020
+ rows, cols = ch_a.shape
1021
+ blend = float(np.clip(blend, 0, 1))
1022
+ rr = np.arange(rows)[:, None]; cc = np.arange(cols)[None, :]
1023
+ if direction == "radial":
1024
+ cx, cy = cols/2, rows/2
1025
+ rr = np.arange(rows)[:, None]; cc = np.arange(cols)[None, :]
1026
+ d = np.sqrt((cc-cx)**2 + (rr-cy)**2)
1027
+ mask = d < blend * np.sqrt(cx**2 + cy**2)
1028
+ elif direction == "left":
1029
+ mask = np.broadcast_to(cc < blend * cols, (rows, cols))
1030
+ elif direction == "right":
1031
+ mask = np.broadcast_to(cc >= (1 - blend) * cols, (rows, cols))
1032
+ elif direction == "up":
1033
+ mask = np.broadcast_to(rr < blend * rows, (rows, cols))
1034
+ elif direction == "down":
1035
+ mask = np.broadcast_to(rr >= (1 - blend) * rows, (rows, cols))
1036
+ elif direction == "diagonal":
1037
+ mask = (rr + cc) < blend * (rows + cols)
1038
+ else:
1039
+ raise ValueError("Unknown wipe direction")
1040
+ if blend == 0: mask = np.zeros((rows, cols), dtype=bool)
1041
+ if blend == 1: mask = np.ones((rows, cols), dtype=bool)
1042
+ ch = ch_a.copy(); co = co_a.copy()
1043
+ ch[mask] = ch_b[mask]; co[mask] = co_b[mask]
1044
+ return ch, co
1045
+ ```
1046
+
1047
+ ### Glitch Cut
1048
+ ```python
1049
+ def tr_glitch_cut(ch_a, co_a, ch_b, co_b, blend):
1050
+ if blend < 0.5: ch, co = ch_a.copy(), co_a.copy()
1051
+ else: ch, co = ch_b.copy(), co_b.copy()
1052
+ if 0.3 < blend < 0.7:
1053
+ intensity = 1.0 - abs(blend - 0.5) * 4
1054
+ for _ in range(int(intensity * 20)):
1055
+ y = random.randint(0, ch.shape[0]-1)
1056
+ shift = int((random.random()-0.5) * 40 * intensity)
1057
+ if shift: ch[y] = np.roll(ch[y], shift); co[y] = np.roll(co[y], shift, axis=0)
1058
+ return ch, co
1059
+ ```
1060
+
1061
+ ---
1062
+
1063
+ ## Output Formats
1064
+
1065
+ ### MP4 (default)
1066
+ ```python
1067
+ cmd = ["ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "rgb24",
1068
+ "-s", f"{W}x{H}", "-r", str(fps), "-i", "pipe:0",
1069
+ "-c:v", "libx264", "-preset", "fast", "-crf", str(crf),
1070
+ "-pix_fmt", "yuv420p", output_path]
1071
+ ```
1072
+
1073
+ ### GIF
1074
+ ```python
1075
+ cmd = ["ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "rgb24",
1076
+ "-s", f"{W}x{H}", "-r", str(fps), "-i", "pipe:0",
1077
+ "-vf", f"fps={fps},scale={W}:{H}:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse",
1078
+ "-loop", "0", output_gif]
1079
+ ```
1080
+
1081
+ ### PNG Sequence
1082
+
1083
+ For frame-accurate editing, compositing in external tools (After Effects, Nuke), or lossless archival:
1084
+
1085
+ ```python
1086
+ import os
1087
+
1088
+ def output_png_sequence(frames, output_dir, W, H, fps, prefix="frame"):
1089
+ """Write frames as numbered PNGs. frames = iterable of uint8 (H,W,3) arrays."""
1090
+ os.makedirs(output_dir, exist_ok=True)
1091
+
1092
+ # Method 1: Direct PIL write (no ffmpeg dependency)
1093
+ from PIL import Image
1094
+ for i, frame in enumerate(frames):
1095
+ img = Image.fromarray(frame)
1096
+ img.save(os.path.join(output_dir, f"{prefix}_{i:06d}.png"))
1097
+
1098
+ # Method 2: ffmpeg pipe (faster for large sequences)
1099
+ cmd = ["ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "rgb24",
1100
+ "-s", f"{W}x{H}", "-r", str(fps), "-i", "pipe:0",
1101
+ os.path.join(output_dir, f"{prefix}_%06d.png")]
1102
+ ```
1103
+
1104
+ Reassemble PNG sequence to video:
1105
+ ```bash
1106
+ ffmpeg -framerate 24 -i frame_%06d.png -c:v libx264 -crf 18 -pix_fmt yuv420p output.mp4
1107
+ ```
1108
+
1109
+ ### Alpha Channel / Transparent Background (RGBA)
1110
+
1111
+ For compositing ASCII art over other video or images. Uses RGBA canvas (4 channels) instead of RGB (3 channels):
1112
+
1113
+ ```python
1114
+ def create_rgba_canvas(H, W):
1115
+ """Transparent canvas — alpha channel starts at 0 (fully transparent)."""
1116
+ return np.zeros((H, W, 4), dtype=np.uint8)
1117
+
1118
+ def render_char_rgba(canvas, row, col, char_img, color_rgb, alpha=255):
1119
+ """Render a character with alpha. char_img = PIL glyph mask (grayscale).
1120
+ Alpha comes from the glyph mask — background stays transparent."""
1121
+ # Straight-alpha source-over; convert before multiplication to avoid uint8 overflow.
1122
+ mask = np.asarray(char_img, dtype=np.float32) / 255.0
1123
+ height, width = mask.shape
1124
+ y0, x0 = row * height, col * width
1125
+ if y0 < 0 or x0 < 0 or y0 + height > canvas.shape[0] or x0 + width > canvas.shape[1]:
1126
+ raise ValueError("Glyph is outside the canvas")
1127
+ tile = canvas[y0:y0+height, x0:x0+width]
1128
+ src_a = mask[..., None] * np.clip(alpha / 255.0, 0, 1)
1129
+ dst_a = tile[..., 3:4].astype(np.float32) / 255.0
1130
+ out_a = src_a + dst_a * (1 - src_a)
1131
+ rgb = (np.asarray(color_rgb, dtype=np.float32) * src_a
1132
+ + tile[..., :3].astype(np.float32) * dst_a * (1 - src_a))
1133
+ rgb = np.divide(rgb, out_a, out=np.zeros_like(rgb), where=out_a > 0)
1134
+ tile[..., :3] = np.clip(np.rint(rgb), 0, 255).astype(np.uint8)
1135
+ tile[..., 3:4] = np.clip(np.rint(out_a * 255), 0, 255).astype(np.uint8)
1136
+
1137
+ def blend_onto_background(rgba_canvas, bg_rgb):
1138
+ """Composite RGBA canvas over a solid or image background."""
1139
+ alpha = rgba_canvas[:, :, 3:4].astype(np.float32) / 255.0
1140
+ fg = rgba_canvas[:, :, :3].astype(np.float32)
1141
+ bg = bg_rgb.astype(np.float32)
1142
+ result = fg * alpha + bg * (1.0 - alpha)
1143
+ return result.astype(np.uint8)
1144
+ ```
1145
+
1146
+ RGBA output via ffmpeg (ProRes 4444 for editing, WebM VP9 for web):
1147
+ ```bash
1148
+ # ProRes 4444 — preserves alpha, widely supported in NLEs
1149
+ ffmpeg -y -f rawvideo -pix_fmt rgba -s {W}x{H} -r {fps} -i pipe:0 \
1150
+ -c:v prores_ks -profile:v 4444 -pix_fmt yuva444p10le output.mov
1151
+
1152
+ # WebM VP9 — alpha support for web/browser compositing
1153
+ ffmpeg -y -f rawvideo -pix_fmt rgba -s {W}x{H} -r {fps} -i pipe:0 \
1154
+ -c:v libvpx-vp9 -pix_fmt yuva420p -crf 30 -b:v 0 output.webm
1155
+
1156
+ # PNG sequence with alpha (lossless)
1157
+ ffmpeg -y -f rawvideo -pix_fmt rgba -s {W}x{H} -r {fps} -i pipe:0 \
1158
+ frame_%06d.png
1159
+ ```
1160
+
1161
+ **Key constraint**: shaders that operate on `(H,W,3)` arrays need adaptation for RGBA. Color-only transforms may preserve alpha; geometric transforms must apply the same coordinate mapping to all four channels. The following wrapper is only for color-only transforms:
1162
+
1163
+ ```python
1164
+ def apply_shader_rgba(canvas_rgba, shader_fn, **kwargs):
1165
+ """Apply an RGB shader to the color channels of an RGBA canvas."""
1166
+ rgb = canvas_rgba[:, :, :3]
1167
+ alpha = canvas_rgba[:, :, 3:4]
1168
+ rgb_out = shader_fn(rgb, **kwargs)
1169
+ return np.concatenate([rgb_out, alpha], axis=2)
1170
+ ```
1171
+
1172
+ ---
1173
+
1174
+ ## Real-Time Terminal Rendering
1175
+
1176
+ Live ASCII display in the terminal using ANSI escape codes. Useful for previewing scenes during development, live performances, and interactive parameter tuning.
1177
+
1178
+ ### ANSI Color Escape Codes
1179
+
1180
+ ```python
1181
+ def rgb_to_ansi(r, g, b):
1182
+ """24-bit true color ANSI escape (supported by most modern terminals)."""
1183
+ return f"\033[38;2;{r};{g};{b}m"
1184
+
1185
+ ANSI_RESET = "\033[0m"
1186
+ ANSI_CLEAR = "\033[2J\033[H" # clear screen + cursor home
1187
+ ANSI_HIDE_CURSOR = "\033[?25l"
1188
+ ANSI_SHOW_CURSOR = "\033[?25h"
1189
+ ```
1190
+
1191
+ ### Frame-to-ANSI Conversion
1192
+
1193
+ ```python
1194
+ def frame_to_ansi(chars, colors):
1195
+ """Convert char+color arrays to a single ANSI string for terminal output.
1196
+
1197
+ Args:
1198
+ chars: (rows, cols) array of single characters
1199
+ colors: (rows, cols, 3) uint8 RGB array
1200
+ Returns:
1201
+ str: ANSI-encoded frame ready for sys.stdout.write()
1202
+ """
1203
+ rows, cols = chars.shape
1204
+ lines = []
1205
+ for r in range(rows):
1206
+ parts = []
1207
+ prev_color = None
1208
+ for c in range(cols):
1209
+ rgb = tuple(colors[r, c])
1210
+ ch = chars[r, c]
1211
+ if ch == " " or rgb == (0, 0, 0):
1212
+ parts.append(" ")
1213
+ else:
1214
+ if rgb != prev_color:
1215
+ parts.append(rgb_to_ansi(*rgb))
1216
+ prev_color = rgb
1217
+ parts.append(ch)
1218
+ parts.append(ANSI_RESET)
1219
+ lines.append("".join(parts))
1220
+ return "\n".join(lines)
1221
+ ```
1222
+
1223
+ ### Optimized: Delta Updates
1224
+
1225
+ Only redraw characters that changed since the last frame. Eliminates redundant terminal writes for static regions:
1226
+
1227
+ ```python
1228
+ def frame_to_ansi_delta(chars, colors, prev_chars, prev_colors):
1229
+ """Emit ANSI escapes only for cells that changed."""
1230
+ rows, cols = chars.shape
1231
+ parts = []
1232
+ for r in range(rows):
1233
+ for c in range(cols):
1234
+ if (chars[r, c] != prev_chars[r, c] or
1235
+ not np.array_equal(colors[r, c], prev_colors[r, c])):
1236
+ parts.append(f"\033[{r+1};{c+1}H") # move cursor
1237
+ rgb = tuple(colors[r, c])
1238
+ parts.append(rgb_to_ansi(*rgb))
1239
+ parts.append(chars[r, c])
1240
+ return "".join(parts)
1241
+ ```
1242
+
1243
+ ### Live Render Loop
1244
+
1245
+ ```python
1246
+ import sys
1247
+ import time
1248
+
1249
+ def render_live(scene_fn, r, fps=24, duration=None):
1250
+ """Render a scene function live in the terminal.
1251
+
1252
+ Args:
1253
+ scene_fn: v2 scene function (r, f, t, S) -> canvas
1254
+ OR v1-style function that populates a grid
1255
+ r: Renderer instance
1256
+ fps: target frame rate
1257
+ duration: seconds to run (None = run until Ctrl+C)
1258
+ """
1259
+ frame_time = 1.0 / fps
1260
+ S = {}
1261
+ f = {} # synthesize features or connect to live audio
1262
+
1263
+ sys.stdout.write(ANSI_HIDE_CURSOR + ANSI_CLEAR)
1264
+ sys.stdout.flush()
1265
+
1266
+ t0 = time.monotonic()
1267
+ frame_count = 0
1268
+ try:
1269
+ while True:
1270
+ t = time.monotonic() - t0
1271
+ if duration and t > duration:
1272
+ break
1273
+
1274
+ # Synthesize features from time (or connect to live audio via pyaudio)
1275
+ f = synthesize_features(t)
1276
+
1277
+ # Render scene — for terminal, use a small grid
1278
+ g = r.get_grid("sm")
1279
+ # Option A: v2 scene → extract chars/colors from canvas (reverse render)
1280
+ # Option B: call effect functions directly for chars/colors
1281
+ canvas = scene_fn(r, f, t, S)
1282
+
1283
+ # For terminal display, render chars+colors directly
1284
+ # (bypassing the pixel canvas — terminal uses character cells)
1285
+ chars, colors = scene_to_terminal(scene_fn, r, f, t, S, g)
1286
+
1287
+ frame_str = ANSI_CLEAR + frame_to_ansi(chars, colors)
1288
+ sys.stdout.write(frame_str)
1289
+ sys.stdout.flush()
1290
+
1291
+ # Frame timing
1292
+ elapsed = time.monotonic() - t0 - (frame_count * frame_time)
1293
+ sleep_time = frame_time - elapsed
1294
+ if sleep_time > 0:
1295
+ time.sleep(sleep_time)
1296
+ frame_count += 1
1297
+ except KeyboardInterrupt:
1298
+ pass
1299
+ finally:
1300
+ sys.stdout.write(ANSI_SHOW_CURSOR + ANSI_RESET + "\n")
1301
+ sys.stdout.flush()
1302
+
1303
+ def scene_to_terminal(scene_fn, r, f, t, S, g):
1304
+ """Run effect functions and return (chars, colors) for terminal display.
1305
+ For terminal mode, skip the pixel canvas and work with character arrays directly."""
1306
+ # Effects that return (chars, colors) work directly
1307
+ # For vf-based effects, render the value field + hue field to chars/colors:
1308
+ val = vf_plasma(g, f, t, S)
1309
+ hue = hf_time_cycle(0.08)(g, f, t, S)
1310
+ mask = val > 0.03
1311
+ chars = val2char(val, mask, PAL_DENSE)
1312
+ R, G, B = hsv2rgb(hue, np.full_like(val, 0.8), val)
1313
+ colors = mkc(R, G, B, g.rows, g.cols)
1314
+ return chars, colors
1315
+ ```
1316
+
1317
+ ### Curses-Based Rendering (More Robust)
1318
+
1319
+ For full-featured terminal UIs with proper resize handling and input:
1320
+
1321
+ ```python
1322
+ import curses
1323
+
1324
+ def render_curses(scene_fn, r, fps=24):
1325
+ """Curses-based live renderer with resize handling and key input."""
1326
+
1327
+ def _main(stdscr):
1328
+ curses.start_color()
1329
+ curses.use_default_colors()
1330
+ curses.curs_set(0) # hide cursor
1331
+ stdscr.nodelay(True) # non-blocking input
1332
+
1333
+ # Initialize color pairs (curses supports 256 colors)
1334
+ # Map RGB to nearest curses color pair
1335
+ color_cache = {}
1336
+ next_pair = [1]
1337
+
1338
+ def get_color_pair(r, g, b):
1339
+ key = (r >> 4, g >> 4, b >> 4) # quantize to reduce pairs
1340
+ if key not in color_cache:
1341
+ if next_pair[0] < curses.COLOR_PAIRS - 1:
1342
+ ci = 16 + (r // 51) * 36 + (g // 51) * 6 + (b // 51) # 6x6x6 cube
1343
+ curses.init_pair(next_pair[0], ci, -1)
1344
+ color_cache[key] = next_pair[0]
1345
+ next_pair[0] += 1
1346
+ else:
1347
+ return 0
1348
+ return curses.color_pair(color_cache[key])
1349
+
1350
+ S = {}
1351
+ f = {}
1352
+ frame_time = 1.0 / fps
1353
+ t0 = time.monotonic()
1354
+
1355
+ while True:
1356
+ t = time.monotonic() - t0
1357
+ f = synthesize_features(t)
1358
+
1359
+ # Adapt grid to terminal size
1360
+ max_y, max_x = stdscr.getmaxyx()
1361
+ g = r.get_grid_for_size(max_x, max_y) # dynamic grid sizing
1362
+
1363
+ chars, colors = scene_to_terminal(scene_fn, r, f, t, S, g)
1364
+ rows, cols = chars.shape
1365
+
1366
+ for row in range(min(rows, max_y - 1)):
1367
+ for col in range(min(cols, max_x - 1)):
1368
+ ch = chars[row, col]
1369
+ rgb = tuple(colors[row, col])
1370
+ try:
1371
+ stdscr.addch(row, col, ch, get_color_pair(*rgb))
1372
+ except curses.error:
1373
+ pass # ignore writes outside terminal bounds
1374
+
1375
+ stdscr.refresh()
1376
+
1377
+ # Handle input
1378
+ key = stdscr.getch()
1379
+ if key == ord('q'):
1380
+ break
1381
+
1382
+ time.sleep(max(0, frame_time - (time.monotonic() - t0 - t)))
1383
+
1384
+ curses.wrapper(_main)
1385
+ ```
1386
+
1387
+ ### Terminal Rendering Constraints
1388
+
1389
+ | Constraint | Value | Notes |
1390
+ |-----------|-------|-------|
1391
+ | Max practical grid | ~200x60 | Depends on terminal size |
1392
+ | Color support | 24-bit (modern), 256 (fallback), 16 (minimal) | Check `$COLORTERM` for truecolor |
1393
+ | Frame rate ceiling | ~30 fps | Terminal I/O is the bottleneck |
1394
+ | Delta updates | 2-5x faster | Only worth it when <30% of cells change per frame |
1395
+ | SSH latency | Kills performance | Local terminals only for real-time |
1396
+
1397
+ **Detect color support:**
1398
+ ```python
1399
+ import os
1400
+ def get_terminal_color_depth():
1401
+ ct = os.environ.get("COLORTERM", "")
1402
+ if ct in ("truecolor", "24bit"):
1403
+ return 24
1404
+ term = os.environ.get("TERM", "")
1405
+ if "256color" in term:
1406
+ return 8 # 256 colors
1407
+ return 4 # 16 colors basic ANSI
1408
+ ```