bitwrench 2.0.31 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +210 -125
  2. package/dist/bitwrench-bccl.cjs.js +349 -188
  3. package/dist/bitwrench-bccl.cjs.min.js +2 -39
  4. package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
  5. package/dist/bitwrench-bccl.esm.js +349 -188
  6. package/dist/bitwrench-bccl.esm.min.js +2 -39
  7. package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
  8. package/dist/bitwrench-bccl.umd.js +349 -188
  9. package/dist/bitwrench-bccl.umd.min.js +2 -39
  10. package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
  11. package/dist/bitwrench-code-edit.cjs.js +17 -6
  12. package/dist/bitwrench-code-edit.cjs.min.js +2 -20
  13. package/dist/bitwrench-code-edit.es5.js +8 -3
  14. package/dist/bitwrench-code-edit.es5.min.js +2 -19
  15. package/dist/bitwrench-code-edit.esm.js +17 -6
  16. package/dist/bitwrench-code-edit.esm.min.js +2 -19
  17. package/dist/bitwrench-code-edit.umd.js +17 -6
  18. package/dist/bitwrench-code-edit.umd.min.js +2 -19
  19. package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
  20. package/dist/bitwrench-debug.js +1 -1
  21. package/dist/bitwrench-debug.min.js +1 -1
  22. package/dist/bitwrench-lean.cjs.js +2492 -1628
  23. package/dist/bitwrench-lean.cjs.min.js +2 -80
  24. package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
  25. package/dist/bitwrench-lean.es5.js +2740 -1838
  26. package/dist/bitwrench-lean.es5.min.js +2 -49
  27. package/dist/bitwrench-lean.es5.min.js.gz +0 -0
  28. package/dist/bitwrench-lean.esm.js +2492 -1628
  29. package/dist/bitwrench-lean.esm.min.js +2 -80
  30. package/dist/bitwrench-lean.esm.min.js.gz +0 -0
  31. package/dist/bitwrench-lean.umd.js +2492 -1628
  32. package/dist/bitwrench-lean.umd.min.js +2 -80
  33. package/dist/bitwrench-lean.umd.min.js.gz +0 -0
  34. package/dist/bitwrench-util-color.cjs.js +251 -0
  35. package/dist/bitwrench-util-color.cjs.min.js +3 -0
  36. package/dist/bitwrench-util-color.es5.js +256 -0
  37. package/dist/bitwrench-util-color.es5.min.js +3 -0
  38. package/dist/bitwrench-util-color.esm.js +241 -0
  39. package/dist/bitwrench-util-color.esm.min.js +3 -0
  40. package/dist/bitwrench-util-color.umd.js +257 -0
  41. package/dist/bitwrench-util-color.umd.min.js +3 -0
  42. package/dist/bitwrench-util-css.cjs.js +2 -1
  43. package/dist/bitwrench-util-css.cjs.min.js +2 -21
  44. package/dist/bitwrench-util-css.es5.js +2 -1
  45. package/dist/bitwrench-util-css.es5.min.js +2 -20
  46. package/dist/bitwrench-util-css.esm.js +2 -1
  47. package/dist/bitwrench-util-css.esm.min.js +1 -19
  48. package/dist/bitwrench-util-css.umd.js +2 -1
  49. package/dist/bitwrench-util-css.umd.min.js +2 -20
  50. package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
  51. package/dist/bitwrench.cjs.js +2826 -1801
  52. package/dist/bitwrench.cjs.min.js +2 -99
  53. package/dist/bitwrench.cjs.min.js.gz +0 -0
  54. package/dist/bitwrench.css +403 -479
  55. package/dist/bitwrench.d.ts +70 -73
  56. package/dist/bitwrench.es5.js +3106 -2020
  57. package/dist/bitwrench.es5.min.js +2 -67
  58. package/dist/bitwrench.es5.min.js.gz +0 -0
  59. package/dist/bitwrench.esm.js +2826 -1801
  60. package/dist/bitwrench.esm.min.js +2 -99
  61. package/dist/bitwrench.esm.min.js.gz +0 -0
  62. package/dist/bitwrench.min.css +1 -1
  63. package/dist/bitwrench.umd.js +2826 -1801
  64. package/dist/bitwrench.umd.min.js +2 -99
  65. package/dist/bitwrench.umd.min.js.gz +0 -0
  66. package/dist/builds.json +222 -134
  67. package/dist/bwserve.cjs.js +308 -298
  68. package/dist/bwserve.d.ts +157 -0
  69. package/dist/bwserve.esm.js +309 -299
  70. package/dist/sri.json +54 -46
  71. package/docs/README.md +6 -3
  72. package/docs/app-patterns.md +7 -6
  73. package/docs/bitwrench-for-wasm.md +53 -54
  74. package/docs/bitwrench-mcp.md +2 -2
  75. package/docs/bitwrench-northstar-principles.md +406 -0
  76. package/docs/bitwrench-taco-schema-discussion.md +2 -2
  77. package/docs/bitwrench_api.md +191 -106
  78. package/docs/bitwrench_typescript_usage.md +5 -5
  79. package/docs/bw-attach.md +29 -75
  80. package/docs/bwserve.md +200 -168
  81. package/docs/cli.md +36 -12
  82. package/docs/component-cheatsheet.md +2 -2
  83. package/docs/component-library.md +4 -4
  84. package/docs/component-lifecycle.md +234 -0
  85. package/docs/drift-lint.md +268 -0
  86. package/docs/framework-translation-table.md +4 -4
  87. package/docs/llm-bitwrench-guide.md +60 -50
  88. package/docs/routing.md +11 -13
  89. package/docs/state-management.md +110 -109
  90. package/docs/taco-format.md +13 -14
  91. package/docs/theming.md +13 -3
  92. package/docs/thinking-in-bitwrench.md +858 -983
  93. package/docs/tutorial-bwserve.md +37 -36
  94. package/docs/tutorial-embedded.md +10 -21
  95. package/docs/tutorial-website.md +2 -2
  96. package/package.json +38 -7
  97. package/readme.html +262 -160
  98. package/src/bitwrench-bccl-entry.js +2 -2
  99. package/src/bitwrench-bccl.js +346 -185
  100. package/src/bitwrench-code-edit.js +16 -5
  101. package/src/bitwrench-color-utils.js +117 -181
  102. package/src/bitwrench-file-ops.js +2 -2
  103. package/src/bitwrench-lean.js +4 -3
  104. package/src/bitwrench-router.js +5 -2
  105. package/src/bitwrench-styles.js +420 -504
  106. package/src/bitwrench-util-color.js +240 -0
  107. package/src/bitwrench-util-css.js +1 -0
  108. package/src/bitwrench-utils.js +4 -0
  109. package/src/bitwrench.d.ts +70 -73
  110. package/src/bitwrench.h +5 -0
  111. package/src/bitwrench.js +1939 -933
  112. package/src/bwserve/attach.js +0 -1
  113. package/src/bwserve/bwclient.js +172 -32
  114. package/src/bwserve/bwshell.js +0 -4
  115. package/src/bwserve/client.js +59 -220
  116. package/src/bwserve/index.js +78 -42
  117. package/src/bwserve.d.ts +157 -0
  118. package/src/bwserve.h +5 -0
  119. package/src/cli/attach.js +12 -75
  120. package/src/cli/convert.js +2 -2
  121. package/src/cli/serve.js +37 -35
  122. package/src/generate-css.js +1 -1
  123. package/src/mcp/knowledge.js +4 -4
  124. package/src/mcp/live.js +21 -13
  125. package/src/mcp/tools.js +0 -1
  126. package/src/version.js +3 -7
package/readme.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="generator" content="bitwrench v2.0.31">
6
+ <meta name="generator" content="bitwrench v2.1.0">
7
7
  <title>bitwrench.js - README</title>
8
8
  <link rel="icon" type="image/x-icon" href="images/favicon.ico">
9
9
  <script src="dist/bitwrench.umd.min.js"></script>
@@ -69,95 +69,27 @@
69
69
  <div class="demo-content">
70
70
  <div class="readme-body">
71
71
  <h1 class="quikdown-h1">bitwrench.js</h1>
72
- <a class="quikdown-a" href="https://opensource.org/licenses/BSD-2-Clause" rel="noopener noreferrer"><img class="quikdown-img" src="https://img.shields.io/badge/License-BSD%202--Clause-blue.svg" alt="License"></a>
73
- <a class="quikdown-a" href="https://www.npmjs.com/package/bitwrench" rel="noopener noreferrer"><img class="quikdown-img" src="https://img.shields.io/npm/v/bitwrench.svg?style=flat-square" alt="NPM version"></a>
74
- <a class="quikdown-a" href="https://github.com/deftio/bitwrench/actions/workflows/ci.yml" rel="noopener noreferrer"><img class="quikdown-img" src="https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
75
- <a class="quikdown-a" href="https://github.com/deftio/bitwrench" rel="noopener noreferrer"><img class="quikdown-img" src="https://img.shields.io/badge/coverage-97.5%25-brightgreen.svg" alt="Coverage"></a></p><p><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/" rel="noopener noreferrer"><img class="quikdown-img" src="./images/bitwrench-logo-med.png" alt="bitwrench"></a></p><p>Bitwrench builds UI from plain JavaScript objects -- one format for components, styling, state, and server rendering, with no build step and zero dependencies.</p><pre class="quikdown-pre"><code class="language-javascript">// Describe UI as a JavaScript object (a &quot;TACO&quot;)
72
+ <a class="quikdown-a" href="https://opensource.org/licenses/BSD-2-Clause" rel="noopener noreferrer">&lt;img class=&quot;quikdown-img&quot; src=&quot;https://img.shields.io/badge/License-BSD%202--Clause-blue.svg&quot; alt=&quot;License&quot; data-qd-alt=&quot;License&quot; data-qd-src=&quot;https://img.shields.io/badge/License-BSD%202--Clause-blue.svg&quot; data-qd=&quot;!&quot;&gt;</a>
73
+ <a class="quikdown-a" href="https://www.npmjs.com/package/bitwrench" rel="noopener noreferrer">&lt;img class=&quot;quikdown-img&quot; src=&quot;https://img.shields.io/npm/v/bitwrench.svg?style=flat-square&quot; alt=&quot;NPM version&quot; data-qd-alt=&quot;NPM version&quot; data-qd-src=&quot;https://img.shields.io/npm/v/bitwrench.svg?style=flat-square&quot; data-qd=&quot;!&quot;&gt;</a>
74
+ <a class="quikdown-a" href="https://github.com/deftio/bitwrench/actions/workflows/ci.yml" rel="noopener noreferrer">&lt;img class=&quot;quikdown-img&quot; src=&quot;https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg&quot; alt=&quot;CI&quot; data-qd-alt=&quot;CI&quot; data-qd-src=&quot;https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg&quot; data-qd=&quot;!&quot;&gt;</a>
75
+ <a class="quikdown-a" href="https://github.com/deftio/bitwrench" rel="noopener noreferrer">&lt;img class=&quot;quikdown-img&quot; src=&quot;https://img.shields.io/badge/coverage-99.1%25-brightgreen.svg&quot; alt=&quot;Coverage&quot; data-qd-alt=&quot;Coverage&quot; data-qd-src=&quot;https://img.shields.io/badge/coverage-99.1%25-brightgreen.svg&quot; data-qd=&quot;!&quot;&gt;</a></p><p><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/" rel="noopener noreferrer">&lt;img class=&quot;quikdown-img&quot; src=&quot;./images/bitwrench-logo-med.png&quot; alt=&quot;bitwrench&quot; data-qd-alt=&quot;bitwrench&quot; data-qd-src=&quot;./images/bitwrench-logo-med.png&quot; data-qd=&quot;!&quot;&gt;</a></p><p>Bitwrench is a UI library that builds interfaces from plain JavaScript objects -- one format for components, styling, state, and server rendering, with no build step and zero dependencies.</p><pre class="quikdown-pre"><code class="language-javascript">// A &quot;TACO&quot; -- Tag, Attributes, Content, Options
76
76
  var page = {
77
77
  t: &#39;div&#39;, a: { class: &#39;card&#39; },
78
78
  c: [
79
79
  { t: &#39;h2&#39;, c: &#39;Hello&#39; },
80
80
  { t: &#39;p&#39;, c: &#39;UI as native JavaScript objects.&#39; },
81
- bw.makeButton({ text: &#39;Click me&#39;, variant: &#39;primary&#39;, onclick: fn })
81
+ { t: &#39;button&#39;, a: { onclick: function() { alert(&#39;clicked&#39;); } }, c: &#39;Click me&#39; }
82
82
  ]
83
83
  };
84
84
 
85
- bw.DOM(&#39;#app&#39;, page); // -&gt; live DOM
86
- bw.html(page); // -&gt; HTML string (Node.js, emails, SSR)</code></pre><p>Each object has four keys: <strong class="quikdown-strong">t</strong> (tag), <strong class="quikdown-strong">a</strong> (attributes), <strong class="quikdown-strong">c</strong> (content), <strong class="quikdown-strong">o</strong> (options for state/lifecycle). Nest them, loop them, compose them -- it&#39;s just JavaScript.</p><h3 class="quikdown-h3">Why bitwrench?</h3>
87
- <strong class="quikdown-strong">One file, everywhere.</strong> At ~40KB gzipped with zero dependencies, bitwrench runs on anything with a browser -- phones, tablets, Raspberry Pi, even ESP32 microcontrollers. The device serves a single HTML page and pushes data as JSON; bitwrench handles all rendering, styling, and state on the client. No Node.js, no build step, no internet connection required.</p><p>Structure, styling, state, and server rendering are all handled as JavaScript objects:</p><ul class="quikdown-ul">
88
- <li class="quikdown-li"><strong class="quikdown-strong">No build toolchain</strong> -- works with a <code class="quikdown-code">&lt;script&gt;</code> tag</li>
89
- <li class="quikdown-li"><strong class="quikdown-strong">Ready-made components</strong> -- buttons, tables, modals, forms, charts, toasts -- one <code class="quikdown-code">make*()</code> call each, returns a composable TACO</li>
90
- <li class="quikdown-li"><strong class="quikdown-strong">CSS from JavaScript</strong> -- <code class="quikdown-code">bw.css()</code> generates stylesheets, <code class="quikdown-code">bw.s()</code> composes inline styles, <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from 2 seed colors</li>
91
- <li class="quikdown-li"><strong class="quikdown-strong">Reactive state</strong> -- <code class="quikdown-code">o.state</code> + <code class="quikdown-code">o.render</code> + <code class="quikdown-code">bw.update()</code> for stateful components; <code class="quikdown-code">bw.pub()</code>/<code class="quikdown-code">bw.sub()</code> for cross-component messaging</li>
92
- <li class="quikdown-li"><strong class="quikdown-strong">Dual rendering</strong> -- same object renders to live DOM (<code class="quikdown-code">bw.DOM()</code>) or HTML string (<code class="quikdown-code">bw.html()</code>) for SSR, emails, or static sites</li>
93
- <li class="quikdown-li"><strong class="quikdown-strong">Server-driven UI</strong> -- push UI updates from any backend (Python, C, Rust, Go) over SSE via the biwrench bwserve protocol; <code class="quikdown-code">client.screenshot()</code> captures the page back as PNG/JPEG</li>
94
- <li class="quikdown-li"><strong class="quikdown-strong">CLI</strong> -- <code class="quikdown-code">bwcli</code> converts Markdown, HTML, and JSON to styled standalone pages</li>
95
- <li class="quikdown-li"><strong class="quikdown-strong">Debug tools</strong> -- live client and server debugging with remote incremental inspect, screenshots, and state updates</li>
96
- <li class="quikdown-li"><strong class="quikdown-strong">TypeScript</strong> -- full type declarations ship with the package (<code class="quikdown-code">dist/bitwrench.d.ts</code>); see the <a class="quikdown-a" href="docs/bitwrench<em class="quikdown-em">typescript</em>usage.md">TypeScript Usage Guide</a></li>
97
- <li class="quikdown-li"><strong class="quikdown-strong">Utilities</strong> -- color interpolation, random data, lorem ipsum, cookies, URL params, file I/O</li>
98
- </ul><h3 class="quikdown-h3">Coming from other Frameworks</h3>
99
- <p>Bitwrench uses JavaScript equivalents for most forms of front-end development. Here is a quick mapping (see the <a class="quikdown-a" href="docs/README.md">docs</a> and <a class="quikdown-a" href="docs/thinking-in-bitwrench.md">Thinking in Bitwrench</a> for more details).</p><table class="quikdown-table">
100
- <thead class="quikdown-thead">
101
- <tr class="quikdown-tr">
102
- <th class="quikdown-th">You&#39;re using</th>
103
- <th class="quikdown-th">For</th>
104
- <th class="quikdown-th">Bitwrench equivalent</th>
105
- </tr>
106
- </thead>
107
- <tbody class="quikdown-tbody">
108
- <tr class="quikdown-tr">
109
- <td class="quikdown-td">React / Vue / Svelte</td>
110
- <td class="quikdown-td">Components + reactivity</td>
111
- <td class="quikdown-td"><code class="quikdown-code">{t, a, c, o}</code> objects + <code class="quikdown-code">o.state</code> + <code class="quikdown-code">o.render</code></td>
112
- </tr>
113
- <tr class="quikdown-tr">
114
- <td class="quikdown-td">JSX / templates</td>
115
- <td class="quikdown-td">Markup-in-JS</td>
116
- <td class="quikdown-td">Native JS objects -- no compiler</td>
117
- </tr>
118
- <tr class="quikdown-tr">
119
- <td class="quikdown-td">Tailwind / CSS-in-JS</td>
120
- <td class="quikdown-td">Styling</td>
121
- <td class="quikdown-td"><code class="quikdown-code">bw.css()</code>, <code class="quikdown-code">bw.s()</code> style composition</td>
122
- </tr>
123
- <tr class="quikdown-tr">
124
- <td class="quikdown-td">Sass / PostCSS</td>
125
- <td class="quikdown-td">CSS generation</td>
126
- <td class="quikdown-td"><code class="quikdown-code">bw.css()</code> from JS objects (supports @media, @keyframes)</td>
127
- </tr>
128
- <tr class="quikdown-tr">
129
- <td class="quikdown-td">ThemeProvider / CSS vars</td>
130
- <td class="quikdown-td">Theming</td>
131
- <td class="quikdown-td"><code class="quikdown-code">bw.loadStyles()</code> / <code class="quikdown-code">bw.makeStyles()</code> from 2 seed colors</td>
132
- </tr>
133
- <tr class="quikdown-tr">
134
- <td class="quikdown-td">Streamlit / Gradio</td>
135
- <td class="quikdown-td">Server-driven UI</td>
136
- <td class="quikdown-td">bwserve SSE -- from any language (Python, Go, C, Rust)</td>
137
- </tr>
138
- <tr class="quikdown-tr">
139
- <td class="quikdown-td">Redux / Zustand / Pinia</td>
140
- <td class="quikdown-td">State management</td>
141
- <td class="quikdown-td"><code class="quikdown-code">o.state</code> + <code class="quikdown-code">bw.update()</code> + <code class="quikdown-code">bw.pub()/sub()</code></td>
142
- </tr>
143
- <tr class="quikdown-tr">
144
- <td class="quikdown-td">Vite / webpack / Babel</td>
145
- <td class="quikdown-td">Build tooling</td>
146
- <td class="quikdown-td">Not needed -- open the HTML file</td>
147
- </tr>
148
- <tr class="quikdown-tr">
149
- <td class="quikdown-td">DefinitelyTyped / @types</td>
150
- <td class="quikdown-td">Type declarations</td>
151
- <td class="quikdown-td">Ships <code class="quikdown-code">dist/bitwrench.d.ts</code> -- nothing extra to install</td>
152
- </tr>
153
- </tbody>
154
- </table><p>See the <a class="quikdown-a" href="docs/framework-translation-table.md">Framework Translation Table</a> for side-by-side code comparisons across 22 operations.</p><h2 class="quikdown-h2">Installation</h2>
85
+ bw.mount(&#39;#app&#39;, page); // -&gt; live DOM
86
+ bw.html(page); // -&gt; HTML string (Node.js, emails, SSR)</code></pre><p>Each object has four keys: <strong class="quikdown-strong">t</strong> (tag), <strong class="quikdown-strong">a</strong> (attributes, including event handlers like <code class="quikdown-code">onclick</code>), <strong class="quikdown-strong">c</strong> (content -- a string, array, or nested TACO), and <strong class="quikdown-strong">o</strong> (options for state and lifecycle). Nest them, loop them, build them with functions -- they are ordinary JavaScript values.</p><p>A TACO is already a JavaScript object, so there is nothing to compile or transform. This makes bitwrench a good fit for situations where a build pipeline costs more than it buys: dashboards, internal tools, embedded device UIs, server-driven pages, or anything you want to ship as a single HTML file.</p><h2 class="quikdown-h2">Installation</h2>
155
87
  <p><pre class="quikdown-pre"><code class="language-bash">npm install bitwrench</code></pre></p><pre class="quikdown-pre"><code class="language-javascript">// ES module
156
88
  import bw from &#39;bitwrench&#39;;
157
89
 
158
90
  // CommonJS
159
91
  const bw = require(&#39;bitwrench&#39;);</code></pre><p>Or include directly in a page:</p><pre class="quikdown-pre"><code class="language-html">&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bitwrench/dist/bitwrench.umd.min.js&quot;&gt;&lt;/script&gt;</code></pre><h2 class="quikdown-h2">Getting Started</h2>
160
- <p><pre class="quikdown-pre"><code class="language-html">&lt;!DOCTYPE html&gt;
92
+ <p>A complete page -- no build step, no imports, everything is a plain object:</p><pre class="quikdown-pre"><code class="language-html">&lt;!DOCTYPE html&gt;
161
93
  &lt;html lang=&quot;en&quot;&gt;
162
94
  &lt;head&gt;
163
95
  &lt;script src=&quot;https://cdn.jsdelivr.net/npm/bitwrench/dist/bitwrench.umd.min.js&quot;&gt;&lt;/script&gt;
@@ -165,38 +97,44 @@ const bw = require(&#39;bitwrench&#39;);</code></pre><p>Or include directly in a
165
97
  &lt;body&gt;
166
98
  &lt;div id=&quot;app&quot;&gt;&lt;/div&gt;
167
99
  &lt;script&gt;
168
- bw.loadStyles();
100
+ bw.loadStyles(); // structural CSS + design tokens
169
101
 
170
- bw.DOM(&#39;#app&#39;, {
171
- t: &#39;div&#39;, a: { class: &#39;bw-container&#39; },
102
+ bw.mount(&#39;#app&#39;, {
103
+ t: &#39;div&#39;, a: { class: &#39;bw_container&#39; },
172
104
  c: [
173
105
  { t: &#39;h1&#39;, c: &#39;My App&#39; },
174
- bw.makeCard({
175
- title: &#39;Welcome&#39;,
176
- content: &#39;Built with plain JavaScript objects.&#39;
177
- }),
178
- bw.makeButton({
179
- text: &#39;Click me&#39;,
180
- variant: &#39;primary&#39;,
181
- onclick: function() { alert(&#39;Hello!&#39;); }
182
- })
106
+ { t: &#39;p&#39;, c: &#39;Built from plain JavaScript objects.&#39; },
107
+ { t: &#39;button&#39;,
108
+ a: { class: &#39;bw_btn bw_primary&#39;, onclick: function() { alert(&#39;Hello!&#39;); } },
109
+ c: &#39;Click me&#39; }
183
110
  ]
184
111
  });
185
112
  &lt;/script&gt;
186
113
  &lt;/body&gt;
187
- &lt;/html&gt;</code></pre></p><h2 class="quikdown-h2">Adding State</h2>
188
- <p>Add <code class="quikdown-code">o.state</code> and <code class="quikdown-code">o.render</code> to any TACO to make it stateful. The render function is called with the DOM element, and state lives on <code class="quikdown-code">el._bw_state</code>. Call <code class="quikdown-code">bw.update(el)</code> to re-render:</p><pre class="quikdown-pre"><code class="language-javascript">var counter = {
114
+ &lt;/html&gt;</code></pre><h2 class="quikdown-h2">Components</h2>
115
+ <p>A component is a function that returns a TACO. Bitwrench ships ~50 factory functions (<code class="quikdown-code">bw.makeCard()</code>, <code class="quikdown-code">bw.makeTable()</code>, <code class="quikdown-code">bw.makeTabs()</code>, etc. -- see the <a class="quikdown-a" href="docs/component-cheatsheet.md">Component Cheat Sheet</a>). Each is a regular function that returns the same <code class="quikdown-code">{t, a, c, o}</code> object you could write by hand. Log the return value and look at it.</p><p>Your own components work the same way:</p><pre class="quikdown-pre"><code class="language-javascript">function statusChip(label, ok) {
116
+ return { t: &#39;span&#39;, a: { class: &#39;bw_badge &#39; + (ok ? &#39;bw_success&#39; : &#39;bw_warning&#39;) }, c: label };
117
+ }
118
+
119
+ // Built-in and custom components compose identically
120
+ bw.mount(&#39;#app&#39;, {
121
+ t: &#39;div&#39;, a: { class: &#39;bw_container&#39; },
122
+ c: [
123
+ bw.makeCard({ title: &#39;Server&#39;, content: &#39;Build 2.1.0&#39; }),
124
+ statusChip(&#39;online&#39;, true)
125
+ ]
126
+ });</code></pre><h2 class="quikdown-h2">State and Updates</h2>
127
+ <p>Add <code class="quikdown-code">o.state</code> and <code class="quikdown-code">o.render</code> to any TACO to make it stateful. The render function receives <code class="quikdown-code">(el, state)</code>, and you call <code class="quikdown-code">bw.refresh(el)</code> when you want it to re-run:</p><pre class="quikdown-pre"><code class="language-javascript">var counter = {
189
128
  t: &#39;div&#39;,
190
129
  o: {
191
130
  state: { count: 0 },
192
- render: function(el) {
193
- var s = el._bw_state;
194
- bw.DOM(el, {
131
+ render: function(el, state) {
132
+ bw.mount(el, {
195
133
  t: &#39;div&#39;, c: [
196
- { t: &#39;h3&#39;, c: &#39;Count: &#39; + s.count },
134
+ { t: &#39;h3&#39;, c: &#39;Count: &#39; + state.count },
197
135
  bw.makeButton({ text: &#39;+1&#39;, onclick: function() {
198
- s.count++;
199
- bw.update(el);
136
+ state.count++;
137
+ bw.refresh(el);
200
138
  }})
201
139
  ]
202
140
  });
@@ -204,35 +142,184 @@ const bw = require(&#39;bitwrench&#39;);</code></pre><p>Or include directly in a
204
142
  }
205
143
  };
206
144
 
207
- bw.DOM(&#39;#app&#39;, counter);</code></pre><blockquote class="quikdown-blockquote"><strong class="quikdown-strong">Important: event handlers go in <code class="quikdown-code">a: { onclick: fn }</code>, not in <code class="quikdown-code">o.mounted</code>.</strong> Handlers attached via <code class="quikdown-code">addEventListener</code> in <code class="quikdown-code">o.mounted</code> are silently lost when a component re-renders. Always use <code class="quikdown-code">onclick</code>/<code class="quikdown-code">onchange</code>/etc. inside <code class="quikdown-code">a:</code> -- bitwrench re-attaches them on every render automatically.</blockquote><p>See the <a class="quikdown-a" href="docs/state-management.md">State Management guide</a> for the full three-level component model.</p><p>For communication between components, use pub/sub:</p><pre class="quikdown-pre"><code class="language-javascript">bw.sub(&#39;item-added&#39;, function(detail) {
208
- console.log(&#39;New item:&#39;, detail.name);
145
+ bw.mount(&#39;#app&#39;, counter);</code></pre><p>State is also available as <code class="quikdown-code">el._bw_state</code> from outside the render function -- useful for debugging or direct access from event handlers.</p><blockquote class="quikdown-blockquote">Event handlers go in <code class="quikdown-code">a: { onclick: fn }</code>, not in <code class="quikdown-code">o.mounted</code>. Handlers attached via <code class="quikdown-code">addEventListener</code> in <code class="quikdown-code">o.mounted</code> are lost when a component re-renders. Place them in <code class="quikdown-code">a:</code> and bitwrench re-attaches them on every render.</blockquote><p>Bitwrench has no reactivity system. Mutating state does not trigger anything -- the DOM changes only when you call an update function. This is a deliberate trade: you give up automatic re-renders, and in exchange every DOM mutation is a function call you wrote, with a cost you chose.</p><p>The update functions form a cost ladder:</p><table class="quikdown-table">
146
+ <thead class="quikdown-thead">
147
+ <tr class="quikdown-tr">
148
+ <th class="quikdown-th">Update verb</th>
149
+ <th class="quikdown-th">Cost</th>
150
+ <th class="quikdown-th">What happens</th>
151
+ </tr>
152
+ </thead>
153
+ <tbody class="quikdown-tbody">
154
+ <tr class="quikdown-tr">
155
+ <td class="quikdown-td"><code class="quikdown-code">el.bw.method()</code> / slot setters</td>
156
+ <td class="quikdown-td">Surgical</td>
157
+ <td class="quikdown-td">Component updates its own DOM directly</td>
158
+ </tr>
159
+ <tr class="quikdown-tr">
160
+ <td class="quikdown-td"><code class="quikdown-code">bw.update(ref, data)</code></td>
161
+ <td class="quikdown-td">Dispatch</td>
162
+ <td class="quikdown-td">Calls <code class="quikdown-code">el.bw.update(data)</code> -- never rebuilds</td>
163
+ </tr>
164
+ <tr class="quikdown-tr">
165
+ <td class="quikdown-td"><code class="quikdown-code">bw.message(ref, action, data)</code></td>
166
+ <td class="quikdown-td">Dispatch</td>
167
+ <td class="quikdown-td">Calls <code class="quikdown-code">el.bw[action]()</code> by selector or UUID</td>
168
+ </tr>
169
+ <tr class="quikdown-tr">
170
+ <td class="quikdown-td"><code class="quikdown-code">bw.patch(id, content)</code></td>
171
+ <td class="quikdown-td">Targeted</td>
172
+ <td class="quikdown-td">Replaces one element&#39;s content</td>
173
+ </tr>
174
+ <tr class="quikdown-tr">
175
+ <td class="quikdown-td"><code class="quikdown-code">bw.refresh(ref)</code></td>
176
+ <td class="quikdown-td">Full rebuild</td>
177
+ <td class="quikdown-td">Re-runs <code class="quikdown-code">o.render</code>; children are unmounted and rebuilt</td>
178
+ </tr>
179
+ </tbody>
180
+ </table><p>Choosing where you sit on this ladder is the programming model. The full <code class="quikdown-code">bw.refresh()</code> re-render shown above is the simplest but most expensive option. The next section introduces slots and handles, which sit at the top of the ladder.</p><h2 class="quikdown-h2">Component API</h2>
181
+ <p>After mounting, the DOM element is the component. The TACO is consumed at mount time -- there is no virtual DOM and no retained tree. State lives on the element (<code class="quikdown-code">el._bw_state</code>), and so does its public API (<code class="quikdown-code">el.bw</code>).</p><p><strong class="quikdown-strong">Slots</strong> map CSS selectors to setter/getter pairs. <strong class="quikdown-strong">Handles</strong> define named methods. Both are attached to <code class="quikdown-code">el.bw</code> at mount time:</p><pre class="quikdown-pre"><code class="language-javascript">var card = bw.mount(&#39;#stats&#39;, {
182
+ t: &#39;div&#39;, a: { class: &#39;stats-card&#39; },
183
+ c: [
184
+ { t: &#39;h3&#39;, a: { class: &#39;card-title&#39; }, c: &#39;Revenue&#39; },
185
+ { t: &#39;span&#39;, a: { class: &#39;card-value&#39; }, c: &#39;$50,000&#39; }
186
+ ],
187
+ o: {
188
+ slots: { title: &#39;.card-title&#39;, value: &#39;.card-value&#39; },
189
+ handle: {
190
+ update: function(el, data) { el.bw.setValue(&#39;§CB7§#39; + data.value.toLocaleString()); }
191
+ }
192
+ }
209
193
  });
210
194
 
195
+ card.bw.setTitle(&#39;Profit&#39;); // slot setter -- updates one text node
196
+ card.bw.update({ value: 120000 }); // handle method -- runs your logic
197
+ bw.update(card, { value: 99000 }); // same call, dispatched by element or UUID</code></pre><p><code class="quikdown-code">slots: { title: &#39;.card-title&#39; }</code> generates <code class="quikdown-code">el.bw.setTitle()</code> and <code class="quikdown-code">el.bw.getTitle()</code> automatically. <code class="quikdown-code">handle</code> methods are attached as-is to <code class="quikdown-code">el.bw</code>. Neither causes a re-render -- they update the DOM directly.</p><p>Because everything lives on the element, debugging needs no extension: select a component in the browser&#39;s Elements panel and type <code class="quikdown-code">$0._bw_state</code> or <code class="quikdown-code">$0.bw</code>.</p><p>A component&#39;s lifecycle is four explicit calls:</p><table class="quikdown-table">
198
+ <thead class="quikdown-thead">
199
+ <tr class="quikdown-tr">
200
+ <th class="quikdown-th">Phase</th>
201
+ <th class="quikdown-th">You call</th>
202
+ <th class="quikdown-th">Opt-in hook</th>
203
+ </tr>
204
+ </thead>
205
+ <tbody class="quikdown-tbody">
206
+ <tr class="quikdown-tr">
207
+ <td class="quikdown-td">Define</td>
208
+ <td class="quikdown-td">a function that returns a TACO</td>
209
+ <td class="quikdown-td">--</td>
210
+ </tr>
211
+ <tr class="quikdown-tr">
212
+ <td class="quikdown-td">Mount</td>
213
+ <td class="quikdown-td">bw.mount(&#39;#app&#39;, taco)</td>
214
+ <td class="quikdown-td">o.mounted(el)</td>
215
+ </tr>
216
+ <tr class="quikdown-tr">
217
+ <td class="quikdown-td">Update</td>
218
+ <td class="quikdown-td">el.bw.method() / bw.refresh(el)</td>
219
+ <td class="quikdown-td">--</td>
220
+ </tr>
221
+ <tr class="quikdown-tr">
222
+ <td class="quikdown-td">Unmount</td>
223
+ <td class="quikdown-td">bw.remove(el)</td>
224
+ <td class="quikdown-td">o.unmount(el)</td>
225
+ </tr>
226
+ </tbody>
227
+ </table><p>The <a class="quikdown-a" href="docs/component-lifecycle.md">Component Lifecycle Walkthrough</a> takes one card through all four phases. The <a class="quikdown-a" href="docs/state-management.md">State Management guide</a> covers the full component model.</p><h2 class="quikdown-h2">Cross-Component Communication</h2>
228
+ <p>Components communicate through pub/sub. <code class="quikdown-code">bw.sub()</code> returns an unsubscribe function. Wildcard topics match any suffix after the colon:</p><pre class="quikdown-pre"><code class="language-javascript">bw.sub(&#39;item-added&#39;, function(detail) { console.log(&#39;New:&#39;, detail.name); });
211
229
  bw.pub(&#39;item-added&#39;, { name: &#39;Widget&#39; });
212
-
213
- // Wildcard: listen to a group of related topics
214
- bw.sub(&#39;item:*&#39;, function(detail, topic) {
215
- console.log(topic, detail); // e.g. &#39;item:added&#39;, &#39;item:removed&#39;
216
- });</code></pre><h2 class="quikdown-h2">CSS from JavaScript</h2>
217
- <p><code class="quikdown-code">bw.css()</code> generates CSS from objects. <code class="quikdown-code">bw.s()</code> composes inline styles from reusable utility objects:</p><pre class="quikdown-pre"><code class="language-javascript">// Generate and inject a stylesheet
230
+ bw.sub(&#39;item:*&#39;, function(detail, topic) { /* matches item:added, item:removed, etc. */ });</code></pre><p>Pass an element as the third argument to tie the subscription&#39;s lifetime to that element -- when the element is removed from the DOM, the subscription is automatically cleaned up:</p><pre class="quikdown-pre"><code class="language-javascript">bw.sub(&#39;cart:updated&#39;, function(data) {
231
+ el._bw_state.count = data.count;
232
+ bw.refresh(el);
233
+ }, el);</code></pre><h2 class="quikdown-h2">CSS from JavaScript</h2>
234
+ <p><code class="quikdown-code">bw.css()</code> generates CSS strings from objects. <code class="quikdown-code">bw.injectCSS()</code> inserts a CSS string into the document as a <code class="quikdown-code">&lt;style&gt;</code> tag. <code class="quikdown-code">bw.s()</code> composes inline styles. <code class="quikdown-code">bw.responsive()</code> generates <code class="quikdown-code">@media</code> rules from a breakpoint map. These are generation functions -- they return strings, so you can use them anywhere:</p><pre class="quikdown-pre"><code class="language-javascript">// Generate and inject a stylesheet
218
235
  bw.injectCSS(bw.css({
219
236
  &#39;.my-card&#39;: { padding: &#39;1rem&#39;, borderRadius: &#39;8px&#39; }
220
237
  }));
221
238
 
222
- // Compose inline styles from objects
239
+ // Compose inline styles from reusable objects
223
240
  { t: &#39;div&#39;, a: { style: bw.s({ display: &#39;flex&#39; }, { gap: &#39;1rem&#39; }, { padding: &#39;1rem&#39; }) } }
224
241
 
225
242
  // Responsive breakpoints
226
243
  bw.responsive(&#39;.hero&#39;, {
227
244
  base: { fontSize: &#39;1.5rem&#39; },
228
245
  md: { fontSize: &#39;2.5rem&#39; }
229
- });</code></pre><h2 class="quikdown-h2">Theming</h2>
230
- <p><code class="quikdown-code">bw.loadStyles()</code> derives a complete design system -- buttons, alerts, badges, cards, forms, tables, hover states, focus rings -- from two seed colors. Styles can be scoped to DOM subtrees, so different sections of a page can use different themes. <code class="quikdown-code">bw.toggleStyles()</code> switches between primary and alternate palettes:</p><pre class="quikdown-pre"><code class="language-javascript">bw.loadStyles({
246
+ });</code></pre><p>Bitwrench does not own your CSS. You can use external stylesheets, Tailwind, or plain CSS alongside any of the above.</p><h2 class="quikdown-h2">Theming</h2>
247
+ <p><code class="quikdown-code">bw.loadStyles()</code> derives a complete design system -- buttons, alerts, badges, cards, forms, tables, hover states, focus rings -- from two seed colors. Call it with no arguments for structural CSS only, or pass a config to generate a full theme. <code class="quikdown-code">bw.toggleThemeMode()</code> switches between primary and alternate palettes:</p><pre class="quikdown-pre"><code class="language-javascript">bw.loadStyles({
231
248
  primary: &#39;#336699&#39;,
232
249
  secondary: &#39;#cc6633&#39;
233
250
  });
234
251
 
235
- bw.toggleStyles(); // switch between primary and alternate palettes</code></pre><h2 class="quikdown-h2">Core API</h2>
252
+ bw.toggleThemeMode(); // switch to alternate palette</code></pre><p>Styles can be scoped to DOM subtrees, so different parts of a page can use different themes. See the <a class="quikdown-a" href="docs/theming.md">Theming guide</a> for presets, palette structure, and scoping.</p><h2 class="quikdown-h2">Server-Driven UI</h2>
253
+ <p>Because TACOs are plain objects, they serialize as JSON. This means a backend in any language can push UI updates to the browser.</p><p>Bitwrench includes bwserve, a protocol that sends TACO objects and patches over SSE. Button clicks come back as actions, <code class="quikdown-code">client.inspect()</code> reads DOM state, and <code class="quikdown-code">client.screenshot()</code> captures the live page as a PNG. The browser becomes a display and input device; the application logic lives wherever you want it.</p><p>Here is a C program on an ESP32 pushing a sensor reading to the browser:</p><pre class="quikdown-pre"><code class="language-c">char msg[96], frame[128];
254
+ BW_PATCH(msg, &quot;office-temp&quot;, &quot;23.5&quot;);
255
+ BW_SSE_FRAME(frame, msg);
256
+ events.send(frame, NULL, millis()); // the browser updates</code></pre><p>The same protocol works from Python, Go, Rust, or a shell script with <code class="quikdown-code">curl</code>. See the <a class="quikdown-a" href="docs/bwserve.md">bwserve docs</a> for the full protocol, and the <a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 tutorial</a> for a complete embedded walkthrough.</p><p>The library is ~165KB on disk (~45KB gzipped). A lean build without the component library (BCCL) is ~128KB (~35KB gzipped). Both work entirely self-hosted from a microcontroller&#39;s flash -- no CDN and no internet required.</p><h2 class="quikdown-h2">CLI</h2>
257
+ <p><code class="quikdown-code">bwcli</code> converts files to styled standalone pages:</p><pre class="quikdown-pre"><code class="language-bash"># Convert Markdown to a self-contained HTML page
258
+ bwcli README.md -o index.html --standalone
259
+
260
+ # Apply a theme preset
261
+ bwcli doc.md -o doc.html --standalone --theme ocean
262
+
263
+ # Custom colors
264
+ bwcli doc.md -o doc.html --standalone --theme &quot;#336699,#cc6633&quot;</code></pre><p>Flags: <code class="quikdown-code">--output/-o</code>, <code class="quikdown-code">--standalone/-s</code>, <code class="quikdown-code">--cdn</code>, <code class="quikdown-code">--theme/-t</code>, <code class="quikdown-code">--css/-c</code>, <code class="quikdown-code">--title</code>, <code class="quikdown-code">--favicon/-f</code>, <code class="quikdown-code">--highlight</code>, <code class="quikdown-code">--verbose/-v</code></p><h3 class="quikdown-h3">Pipe Server</h3>
265
+ <p><code class="quikdown-code">bwcli serve</code> turns any language into a bwserve backend -- send JSON protocol messages via HTTP POST or stdin, and connected browsers update in real time:</p><pre class="quikdown-pre"><code class="language-bash">bwcli serve --port 8080 --input-port 9000
266
+ curl -X POST http://localhost:9000 -d &#39;{&quot;type&quot;:&quot;patch&quot;,&quot;ref&quot;:&quot;temp&quot;,&quot;content&quot;:&quot;23.5 C&quot;}&#39;</code></pre><h2 class="quikdown-h2">Coming from Other Frameworks</h2>
267
+ <table class="quikdown-table">
268
+ <thead class="quikdown-thead">
269
+ <tr class="quikdown-tr">
270
+ <th class="quikdown-th">You&#39;re using</th>
271
+ <th class="quikdown-th">For</th>
272
+ <th class="quikdown-th">Bitwrench equivalent</th>
273
+ </tr>
274
+ </thead>
275
+ <tbody class="quikdown-tbody">
276
+ <tr class="quikdown-tr">
277
+ <td class="quikdown-td">React / Vue / Svelte</td>
278
+ <td class="quikdown-td">Components</td>
279
+ <td class="quikdown-td">{t, a, c, o} objects + o.state + o.render</td>
280
+ </tr>
281
+ <tr class="quikdown-tr">
282
+ <td class="quikdown-td">JSX / templates</td>
283
+ <td class="quikdown-td">Markup-in-JS</td>
284
+ <td class="quikdown-td">Native JS objects -- no compiler</td>
285
+ </tr>
286
+ <tr class="quikdown-tr">
287
+ <td class="quikdown-td">Tailwind / CSS-in-JS</td>
288
+ <td class="quikdown-td">Styling</td>
289
+ <td class="quikdown-td">bw.css(), bw.s()</td>
290
+ </tr>
291
+ <tr class="quikdown-tr">
292
+ <td class="quikdown-td">Sass / PostCSS</td>
293
+ <td class="quikdown-td">CSS generation</td>
294
+ <td class="quikdown-td">bw.css() from JS objects (supports @media, @keyframes)</td>
295
+ </tr>
296
+ <tr class="quikdown-tr">
297
+ <td class="quikdown-td">ThemeProvider / CSS vars</td>
298
+ <td class="quikdown-td">Theming</td>
299
+ <td class="quikdown-td">bw.loadStyles() / bw.makeStyles() from seed colors</td>
300
+ </tr>
301
+ <tr class="quikdown-tr">
302
+ <td class="quikdown-td">Streamlit / Gradio</td>
303
+ <td class="quikdown-td">Server-driven UI</td>
304
+ <td class="quikdown-td">bwserve SSE -- from any language</td>
305
+ </tr>
306
+ <tr class="quikdown-tr">
307
+ <td class="quikdown-td">Redux / Zustand / Pinia</td>
308
+ <td class="quikdown-td">State management</td>
309
+ <td class="quikdown-td">o.state + bw.refresh() + bw.pub()/sub()</td>
310
+ </tr>
311
+ <tr class="quikdown-tr">
312
+ <td class="quikdown-td">Vite / webpack / Babel</td>
313
+ <td class="quikdown-td">Build tooling</td>
314
+ <td class="quikdown-td">Not needed -- open the HTML file</td>
315
+ </tr>
316
+ <tr class="quikdown-tr">
317
+ <td class="quikdown-td">DefinitelyTyped / @types</td>
318
+ <td class="quikdown-td">Type declarations</td>
319
+ <td class="quikdown-td">Ships dist/bitwrench.d.ts</td>
320
+ </tr>
321
+ </tbody>
322
+ </table><p>See the <a class="quikdown-a" href="docs/framework-translation-table.md">Framework Translation Table</a> for side-by-side code comparisons across 22 operations.</p><h2 class="quikdown-h2">Core API</h2>
236
323
  <table class="quikdown-table">
237
324
  <thead class="quikdown-thead">
238
325
  <tr class="quikdown-tr">
@@ -242,97 +329,111 @@ bw.toggleStyles(); // switch between primary and alternate palettes</code></pre
242
329
  </thead>
243
330
  <tbody class="quikdown-tbody">
244
331
  <tr class="quikdown-tr">
245
- <td class="quikdown-td"><code class="quikdown-code">bw.html(obj)</code></td>
332
+ <td class="quikdown-td">bw.html(obj)</td>
246
333
  <td class="quikdown-td">Convert a TACO to an HTML string</td>
247
334
  </tr>
248
335
  <tr class="quikdown-tr">
249
- <td class="quikdown-td"><code class="quikdown-code">bw.DOM(selector, obj)</code></td>
250
- <td class="quikdown-td">Mount a TACO to a DOM element</td>
336
+ <td class="quikdown-td">bw.mount(selector, obj)</td>
337
+ <td class="quikdown-td">Mount a TACO into a DOM element; returns the root element</td>
338
+ </tr>
339
+ <tr class="quikdown-tr">
340
+ <td class="quikdown-td">bw.DOM(selector, obj)</td>
341
+ <td class="quikdown-td">Alias of bw.mount()</td>
342
+ </tr>
343
+ <tr class="quikdown-tr">
344
+ <td class="quikdown-td">bw.create(taco)</td>
345
+ <td class="quikdown-td">Create a detached DOM element from a TACO (not inserted into the page)</td>
346
+ </tr>
347
+ <tr class="quikdown-tr">
348
+ <td class="quikdown-td">bw.el(selector, apply?)</td>
349
+ <td class="quikdown-td">Find an element; optionally apply text, TACO, or function to it</td>
251
350
  </tr>
252
351
  <tr class="quikdown-tr">
253
- <td class="quikdown-td"><code class="quikdown-code">bw.mount(selector, obj)</code></td>
254
- <td class="quikdown-td">Like <code class="quikdown-code">bw.DOM()</code> but returns the root element for <code class="quikdown-code">el.bw</code> access</td>
352
+ <td class="quikdown-td">bw.$(selector)</td>
353
+ <td class="quikdown-td">querySelectorAll as an array</td>
255
354
  </tr>
256
355
  <tr class="quikdown-tr">
257
- <td class="quikdown-td"><code class="quikdown-code">bw.raw(str)</code></td>
356
+ <td class="quikdown-td">bw.raw(str)</td>
258
357
  <td class="quikdown-td">Mark a string as pre-escaped HTML (no double-escaping)</td>
259
358
  </tr>
260
359
  <tr class="quikdown-tr">
261
- <td class="quikdown-td"><code class="quikdown-code">bw.css(rules)</code></td>
360
+ <td class="quikdown-td">bw.css(rules)</td>
262
361
  <td class="quikdown-td">Generate CSS from a JS object</td>
263
362
  </tr>
264
363
  <tr class="quikdown-tr">
265
- <td class="quikdown-td"><code class="quikdown-code">bw.s(...objs)</code></td>
364
+ <td class="quikdown-td">bw.injectCSS(css, opts?)</td>
365
+ <td class="quikdown-td">Insert a CSS string into the document as a style tag</td>
366
+ </tr>
367
+ <tr class="quikdown-tr">
368
+ <td class="quikdown-td">bw.s(...objs)</td>
266
369
  <td class="quikdown-td">Compose inline style objects into a style string</td>
267
370
  </tr>
268
371
  <tr class="quikdown-tr">
269
- <td class="quikdown-td"><code class="quikdown-code">bw.responsive(sel, breakpoints)</code></td>
270
- <td class="quikdown-td">Generate <code class="quikdown-code">@media</code> CSS rules from JS</td>
372
+ <td class="quikdown-td">bw.responsive(sel, breakpoints)</td>
373
+ <td class="quikdown-td">Generate @media CSS rules from a breakpoint map</td>
271
374
  </tr>
272
375
  <tr class="quikdown-tr">
273
- <td class="quikdown-td"><code class="quikdown-code">bw.loadStyles(config?)</code></td>
274
- <td class="quikdown-td">Load structural CSS (no args) or generate + apply a theme from seed colors</td>
376
+ <td class="quikdown-td">bw.loadStyles(config?)</td>
377
+ <td class="quikdown-td">Structural CSS (no args) or generate + apply a theme from seed colors</td>
275
378
  </tr>
276
379
  <tr class="quikdown-tr">
277
- <td class="quikdown-td"><code class="quikdown-code">bw.makeStyles(config)</code></td>
380
+ <td class="quikdown-td">bw.makeStyles(config)</td>
278
381
  <td class="quikdown-td">Generate a theme from seed colors (returns styles object)</td>
279
382
  </tr>
280
383
  <tr class="quikdown-tr">
281
- <td class="quikdown-td"><code class="quikdown-code">bw.applyStyles(styles)</code></td>
282
- <td class="quikdown-td">Inject a generated styles object&#39;s CSS into the document</td>
384
+ <td class="quikdown-td">bw.applyStyles(styles)</td>
385
+ <td class="quikdown-td">Inject a generated styles object into the document</td>
283
386
  </tr>
284
387
  <tr class="quikdown-tr">
285
- <td class="quikdown-td"><code class="quikdown-code">bw.toggleStyles()</code></td>
388
+ <td class="quikdown-td">bw.toggleThemeMode(scope?)</td>
286
389
  <td class="quikdown-td">Switch between primary and alternate palettes</td>
287
390
  </tr>
288
391
  <tr class="quikdown-tr">
289
- <td class="quikdown-td"><code class="quikdown-code">bw.clearStyles()</code></td>
392
+ <td class="quikdown-td">bw.clearStyles()</td>
290
393
  <td class="quikdown-td">Remove injected theme styles</td>
291
394
  </tr>
292
395
  <tr class="quikdown-tr">
293
- <td class="quikdown-td"><code class="quikdown-code">bw.patch(id, content)</code></td>
396
+ <td class="quikdown-td">bw.patch(id, content)</td>
294
397
  <td class="quikdown-td">Update a specific element by id or UUID</td>
295
398
  </tr>
296
399
  <tr class="quikdown-tr">
297
- <td class="quikdown-td"><code class="quikdown-code">bw.update(el)</code></td>
298
- <td class="quikdown-td">Re-render via the element&#39;s <code class="quikdown-code">o.render</code> function</td>
400
+ <td class="quikdown-td">bw.refresh(el)</td>
401
+ <td class="quikdown-td">Re-render a stateful component via its o.render function</td>
402
+ </tr>
403
+ <tr class="quikdown-tr">
404
+ <td class="quikdown-td">bw.update(el, data)</td>
405
+ <td class="quikdown-td">Dispatch to el.bw.update(data)</td>
299
406
  </tr>
300
407
  <tr class="quikdown-tr">
301
- <td class="quikdown-td"><code class="quikdown-code">bw.message(target, action, data)</code></td>
302
- <td class="quikdown-td">Dispatch a method call to a component&#39;s <code class="quikdown-code">el.bw</code> handle</td>
408
+ <td class="quikdown-td">bw.message(target, action, data)</td>
409
+ <td class="quikdown-td">Dispatch to el.bw[action]() by selector or UUID</td>
303
410
  </tr>
304
411
  <tr class="quikdown-tr">
305
- <td class="quikdown-td"><code class="quikdown-code">bw.pub(topic, detail)</code></td>
412
+ <td class="quikdown-td">bw.pub(topic, detail)</td>
306
413
  <td class="quikdown-td">Publish to subscribers (exact + wildcard matches)</td>
307
414
  </tr>
308
415
  <tr class="quikdown-tr">
309
- <td class="quikdown-td"><code class="quikdown-code">bw.sub(topic, handler, el?)</code></td>
310
- <td class="quikdown-td">Subscribe to topic (supports wildcard <code class="quikdown-code">&#39;ns:*&#39;</code>); returns unsub function</td>
416
+ <td class="quikdown-td">bw.sub(topic, handler, el?)</td>
417
+ <td class="quikdown-td">Subscribe to a topic (supports wildcard &#39;ns:*&#39;); returns unsub function</td>
311
418
  </tr>
312
419
  <tr class="quikdown-tr">
313
- <td class="quikdown-td"><code class="quikdown-code">bw.once(topic, handler, el?)</code></td>
420
+ <td class="quikdown-td">bw.once(topic, handler, el?)</td>
314
421
  <td class="quikdown-td">One-shot subscribe; auto-unsub after first fire</td>
315
422
  </tr>
316
423
  <tr class="quikdown-tr">
317
- <td class="quikdown-td"><code class="quikdown-code">bw.inspect(target, depth)</code></td>
318
- <td class="quikdown-td">Introspect a DOM subtree with bitwrench metadata (state, handles, type)</td>
424
+ <td class="quikdown-td">bw.remove(el)</td>
425
+ <td class="quikdown-td">Unmount a component (fires o.unmount hook)</td>
319
426
  </tr>
320
427
  <tr class="quikdown-tr">
321
- <td class="quikdown-td"><code class="quikdown-code">bw.apply(msg)</code></td>
428
+ <td class="quikdown-td">bw.inspect(target, depth)</td>
429
+ <td class="quikdown-td">Introspect a DOM subtree with bitwrench metadata</td>
430
+ </tr>
431
+ <tr class="quikdown-tr">
432
+ <td class="quikdown-td">bw.apply(msg)</td>
322
433
  <td class="quikdown-td">Apply a bwserve protocol message to the DOM</td>
323
434
  </tr>
324
435
  </tbody>
325
- </table><p>See the full <a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/08-api-reference.html" rel="noopener noreferrer">API Reference</a> for all functions.</p><h2 class="quikdown-h2">CLI</h2>
326
- <p>Convert Markdown, HTML, or JSON files to styled standalone pages:</p><pre class="quikdown-pre"><code class="language-bash"># Convert Markdown to a self-contained HTML page
327
- bwcli README.md -o index.html --standalone
328
-
329
- # Apply a theme preset
330
- bwcli doc.md -o doc.html --standalone --theme ocean
331
-
332
- # Custom colors
333
- bwcli doc.md -o doc.html --standalone --theme &quot;#336699,#cc6633&quot;</code></pre><p>Flags: <code class="quikdown-code">--output/-o</code>, <code class="quikdown-code">--standalone/-s</code>, <code class="quikdown-code">--cdn</code>, <code class="quikdown-code">--theme/-t</code>, <code class="quikdown-code">--css/-c</code>, <code class="quikdown-code">--title</code>, <code class="quikdown-code">--favicon/-f</code>, <code class="quikdown-code">--highlight</code>, <code class="quikdown-code">--verbose/-v</code></p><h3 class="quikdown-h3">Pipe Server</h3>
334
- <p><code class="quikdown-code">bwcli serve</code> turns any language into a bwserve backend -- send JSON protocol messages via HTTP POST or stdin, and connected browsers update in real time:</p><pre class="quikdown-pre"><code class="language-bash">bwcli serve --port 8080 --input-port 9000
335
- curl -X POST http://localhost:9000 -d &#39;{&quot;type&quot;:&quot;patch&quot;,&quot;target&quot;:&quot;temp&quot;,&quot;content&quot;:&quot;23.5 C&quot;}&#39;</code></pre><h2 class="quikdown-h2">Build Formats</h2>
436
+ </table><p>The update functions (<code class="quikdown-code">bw.patch</code>, <code class="quikdown-code">bw.refresh</code>, <code class="quikdown-code">bw.update</code>, <code class="quikdown-code">bw.message</code>) form a cost ladder -- see <a class="quikdown-a" href="#state-and-updates">State and Updates</a>. Full <a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/08-api-reference.html" rel="noopener noreferrer">API Reference</a>.</p><h2 class="quikdown-h2">Build Formats</h2>
336
437
  <table class="quikdown-table">
337
438
  <thead class="quikdown-thead">
338
439
  <tr class="quikdown-tr">
@@ -344,32 +445,33 @@ curl -X POST http://localhost:9000 -d &#39;{&quot;type&quot;:&quot;patch&quot;,&
344
445
  <tbody class="quikdown-tbody">
345
446
  <tr class="quikdown-tr">
346
447
  <td class="quikdown-td">UMD</td>
347
- <td class="quikdown-td"><code class="quikdown-code">bitwrench.umd.min.js</code></td>
448
+ <td class="quikdown-td">bitwrench.umd.min.js</td>
348
449
  <td class="quikdown-td">Browsers and Node.js</td>
349
450
  </tr>
350
451
  <tr class="quikdown-tr">
351
452
  <td class="quikdown-td">ESM</td>
352
- <td class="quikdown-td"><code class="quikdown-code">bitwrench.esm.min.js</code></td>
453
+ <td class="quikdown-td">bitwrench.esm.min.js</td>
353
454
  <td class="quikdown-td">Modern bundlers (Vite, webpack, etc.)</td>
354
455
  </tr>
355
456
  <tr class="quikdown-tr">
356
457
  <td class="quikdown-td">CJS</td>
357
- <td class="quikdown-td"><code class="quikdown-code">bitwrench.cjs.min.js</code></td>
358
- <td class="quikdown-td">Node.js <code class="quikdown-code">require()</code></td>
458
+ <td class="quikdown-td">bitwrench.cjs.min.js</td>
459
+ <td class="quikdown-td">Node.js require()</td>
359
460
  </tr>
360
461
  <tr class="quikdown-tr">
361
462
  <td class="quikdown-td">ES5</td>
362
- <td class="quikdown-td"><code class="quikdown-code">bitwrench.es5.min.js</code></td>
463
+ <td class="quikdown-td">bitwrench.es5.min.js</td>
363
464
  <td class="quikdown-td">Legacy browsers (IE11)</td>
364
465
  </tr>
365
466
  </tbody>
366
467
  </table><p>All formats include source maps. A separate CSS file (<code class="quikdown-code">bitwrench.css</code>) is also available for use without JavaScript.</p><h2 class="quikdown-h2">Documentation</h2>
367
468
  <strong class="quikdown-strong">Start here:</strong></p><ul class="quikdown-ul">
368
- <li class="quikdown-li"><strong class="quikdown-strong"><a class="quikdown-a" href="docs/thinking-in-bitwrench.md">Thinking in Bitwrench</a></strong> -- the complete guide. Covers TACO, styling (<code class="quikdown-code">bw.css</code>, <code class="quikdown-code">bw.s</code>, <code class="quikdown-code">bw.responsive</code>), composition, events, the three-level component model, bwserve, and common patterns</li>
369
- <li class="quikdown-li"><strong class="quikdown-strong"><a class="quikdown-a" href="docs/llm-bitwrench-guide.md">LLM Guide</a></strong> -- compact single-file reference with all APIs, patterns, and rules. Designed for AI-assisted development but works as a cheat sheet for anyone</li>
469
+ <li class="quikdown-li"><strong class="quikdown-strong"><a class="quikdown-a" href="docs/thinking-in-bitwrench.md">Thinking in Bitwrench</a></strong> -- the complete guide: TACO format, styling, composition, events, the component model, bwserve, and common patterns</li>
470
+ <li class="quikdown-li"><strong class="quikdown-strong"><a class="quikdown-a" href="docs/llm-bitwrench-guide.md">LLM Guide</a></strong> -- compact single-file reference with all APIs, patterns, and rules</li>
370
471
  </ul><p><strong class="quikdown-strong">Reference guides</strong> (in <code class="quikdown-code">docs/</code>):</p><ul class="quikdown-ul">
371
472
  <li class="quikdown-li"><a class="quikdown-a" href="docs/taco-format.md">TACO Format</a> -- the <code class="quikdown-code">{t, a, c, o}</code> object format</li>
372
- <li class="quikdown-li"><a class="quikdown-a" href="docs/state-management.md">State Management</a> -- three-level component model, stateful TACO, reactive state</li>
473
+ <li class="quikdown-li"><a class="quikdown-a" href="docs/component-lifecycle.md">Component Lifecycle Walkthrough</a> -- one stats card through all four phases</li>
474
+ <li class="quikdown-li"><a class="quikdown-a" href="docs/state-management.md">State Management</a> -- component model, explicit updates, cross-component communication</li>
373
475
  <li class="quikdown-li"><a class="quikdown-a" href="docs/component-library.md">Component Library</a> -- all <code class="quikdown-code">make*()</code> functions with signatures and examples</li>
374
476
  <li class="quikdown-li"><a class="quikdown-a" href="docs/theming.md">Theming</a> -- palette-driven theme generation, presets, design tokens</li>
375
477
  <li class="quikdown-li"><a class="quikdown-a" href="docs/cli.md">CLI</a> -- the <code class="quikdown-code">bwcli</code> command for file conversion and pipe server</li>
@@ -388,7 +490,7 @@ curl -X POST http://localhost:9000 -d &#39;{&quot;type&quot;:&quot;patch&quot;,&
388
490
  <li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/10-themes.html" rel="noopener noreferrer">Themes</a> -- interactive theme generator with presets and CSS export</li>
389
491
  </ul><p><strong class="quikdown-strong">Example apps</strong> (in <code class="quikdown-code">examples/</code>):</p><ul class="quikdown-ul">
390
492
  <li class="quikdown-li"><a class="quikdown-a" href="examples/ember-and-oak/">Ember &amp; Oak Coffee Co.</a> -- full landing page: theme, cart, search, charts, accordion, timeline</li>
391
- <li class="quikdown-li"><a class="quikdown-a" href="examples/landing-page/">SunForge Landing Page</a> -- polished marketing page with zero reactive state, pure BCCL composition</li>
493
+ <li class="quikdown-li"><a class="quikdown-a" href="examples/landing-page/">SunForge Landing Page</a> -- marketing page with zero reactive state, pure BCCL composition</li>
392
494
  <li class="quikdown-li"><a class="quikdown-a" href="examples/todo-app/">Todo App</a> -- stateful TACO with pub/sub</li>
393
495
  <li class="quikdown-li"><a class="quikdown-a" href="examples/dashboard/">Metrics Dashboard</a> -- live stat cards, bar chart, pub/sub, responsive layout</li>
394
496
  <li class="quikdown-li"><a class="quikdown-a" href="examples/wizard/">Signup Wizard</a> -- multi-step form, state transitions, bw.raw()</li>
@@ -397,7 +499,7 @@ curl -X POST http://localhost:9000 -d &#39;{&quot;type&quot;:&quot;patch&quot;,&
397
499
  <li class="quikdown-li"><a class="quikdown-a" href="examples/client-server/">bwserve Counter</a> -- server-driven UI demo</li>
398
500
  <li class="quikdown-li"><a class="quikdown-a" href="examples/llm-chat/">LLM Chat</a> -- streaming chat via bwserve + Ollama/OpenAI</li>
399
501
  </ul><h2 class="quikdown-h2">FAQ</h2>
400
- <strong class="quikdown-strong">Is this a framework?</strong> -- No. Bitwrench is a library (~40KB gzipped). No lifecycle to learn, no project structure to follow. Import it, call functions, done.</p><p><strong class="quikdown-strong">How does bitwrench compare to React/Vue?</strong> -- They solve different problems at different scales. React and Vue provide a component model, virtual DOM, and ecosystem for large team-built SPAs. Bitwrench provides rendering and state primitives in a single file with no build step, aimed at single-page tools, dashboards, embedded devices, and server-driven UIs. They coexist fine -- use whichever fits the job.</p><p><strong class="quikdown-strong">How does CSS work?</strong> -- Bitwrench doesn&#39;t own your CSS. Use any external stylesheet, Tailwind, or CSS file you want -- bitwrench doesn&#39;t interfere. On top of that, <code class="quikdown-code">bw.css()</code> generates CSS from JS objects (with <code class="quikdown-code">@media</code>, <code class="quikdown-code">@keyframes</code>, pseudo-classes), <code class="quikdown-code">bw.s()</code> composes inline style objects, and <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from 2 seed colors. You can use all three together or none at all.</p><p><strong class="quikdown-strong">What&#39;s the difference between <code class="quikdown-code">bw.DOM()</code> and <code class="quikdown-code">bw.html()</code>?</strong> -- Same TACO input, two outputs. <code class="quikdown-code">bw.DOM(&#39;#app&#39;, taco)</code> mounts live DOM elements in a browser. <code class="quikdown-code">bw.html(taco)</code> returns an HTML string -- use it in Node.js scripts, email generators, static site builds, or anywhere you need markup without a browser. One object format, two rendering modes.</p><p><strong class="quikdown-strong">What is bwserve?</strong> -- bwserve lets any server push UI updates to a browser over SSE. The server sends TACO objects as JSON; the browser renders them. It&#39;s language-agnostic -- the server can be Python, Go, Rust, C, or a shell script. Anything that can write JSON to an HTTP response can drive a bitwrench UI. See the <a class="quikdown-a" href="docs/bwserve.md">bwserve docs</a>.</p><p><strong class="quikdown-strong">Can I use bitwrench on embedded devices?</strong> -- Yes -- this is a primary use case. An ESP32 or Raspberry Pi serves one HTML page with bitwrench loaded, then pushes sensor data as JSON patches over SSE. The device never generates HTML. See the <a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 tutorial</a>.</p><p><strong class="quikdown-strong">Can I use it with TypeScript?</strong> -- Yes. Type declarations ship with the package (<code class="quikdown-code">dist/bitwrench.d.ts</code>). TACO objects are plain JSON-compatible objects that TypeScript infers naturally. See the <a class="quikdown-a" href="docs/bitwrench<em class="quikdown-em">typescript</em>usage.md">TypeScript Usage Guide</a> for import patterns, typed configs, and examples.</p><p><strong class="quikdown-strong">What about accessibility?</strong> -- BCCL components emit semantic HTML with ARIA attributes where applicable. You can add any <code class="quikdown-code">aria-*</code> attribute via <code class="quikdown-code">a: { &#39;aria-label&#39;: &#39;...&#39; }</code>.</p><h2 class="quikdown-h2">Development</h2>
502
+ <strong class="quikdown-strong">Is this a framework?</strong> -- No. It is a library (165KB on disk, 45KB gzipped). No lifecycle ceremony, no project structure. Import it, call functions, done. Lifecycle hooks (<code class="quikdown-code">o.mounted</code>, <code class="quikdown-code">o.unmount</code>) are opt-in.</p><p><strong class="quikdown-strong">How does bitwrench compare to React/Vue?</strong> -- They solve different problems at different scales. React and Vue provide a component model, virtual DOM, and ecosystem for large team-built SPAs. Bitwrench provides rendering and state primitives in a single file with no build step, aimed at single-page tools, dashboards, embedded devices, and server-driven UIs. They coexist fine.</p><p><strong class="quikdown-strong">How does CSS work?</strong> -- Bitwrench does not own your CSS. Use any external stylesheet, Tailwind, or CSS file you want. On top of that, <code class="quikdown-code">bw.css()</code> generates CSS from JS objects (with <code class="quikdown-code">@media</code>, <code class="quikdown-code">@keyframes</code>, pseudo-classes), <code class="quikdown-code">bw.s()</code> composes inline style objects, and <code class="quikdown-code">bw.loadStyles()</code> derives a complete design system from seed colors. Use all three or none.</p><p><strong class="quikdown-strong">What&#39;s the difference between <code class="quikdown-code">bw.mount()</code> and <code class="quikdown-code">bw.html()</code>?</strong> -- Same TACO input, two outputs. <code class="quikdown-code">bw.mount(&#39;#app&#39;, taco)</code> mounts live DOM elements in a browser. <code class="quikdown-code">bw.html(taco)</code> returns an HTML string for Node.js scripts, email generators, static site builds, or anywhere you need markup without a browser. (<code class="quikdown-code">bw.DOM()</code> is an alias for <code class="quikdown-code">bw.mount()</code>.)</p><p><strong class="quikdown-strong">What is bwserve?</strong> -- A protocol that turns the browser into a display and input device for a program running anywhere. The server pushes TACO objects and patches over SSE; button clicks come back as actions; <code class="quikdown-code">client.inspect()</code> returns DOM state; <code class="quikdown-code">client.screenshot()</code> returns a PNG. Language-agnostic: Python, Go, Rust, C, or a shell script with <code class="quikdown-code">curl</code>. See the <a class="quikdown-a" href="docs/bwserve.md">bwserve docs</a>.</p><p><strong class="quikdown-strong">Can I use bitwrench on embedded devices?</strong> -- Yes. The device serves one HTML page plus the library from flash, no CDN required. Build the UI as TACOs in whatever language the device speaks (C, C++, MicroPython), push updates over SSE, and get button presses back the same way. C macros ship in <code class="quikdown-code">embedded_c/</code>. See the <a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 tutorial</a> and the <a class="quikdown-a" href="examples/embedded-pico-w/">Pico W example</a>.</p><p><strong class="quikdown-strong">Can I use it with TypeScript?</strong> -- Yes. Type declarations ship with the package (<code class="quikdown-code">dist/bitwrench.d.ts</code>). See the <a class="quikdown-a" href="docs/bitwrench<em class="quikdown-em">typescript</em>usage.md">TypeScript Usage Guide</a>.</p><p><strong class="quikdown-strong">What about accessibility?</strong> -- BCCL components emit semantic HTML with ARIA attributes where applicable. You can add any <code class="quikdown-code">aria-*</code> attribute via <code class="quikdown-code">a: { &#39;aria-label&#39;: &#39;...&#39; }</code>.</p><h2 class="quikdown-h2">Development</h2>
401
503
  <p><pre class="quikdown-pre"><code class="language-bash">npm install # install dev dependencies
402
504
  npm run build # build all dist formats (UMD, ESM, CJS, ES5)
403
505
  npm test # run unit tests
@@ -405,7 +507,7 @@ npm run test:cli # run CLI tests
405
507
  npm run test:e2e # run Playwright browser tests
406
508
  npm run lint # run ESLint
407
509
  npm run cleanbuild # full production build with SRI hashes</code></pre></p><h2 class="quikdown-h2">License</h2>
408
- <a class="quikdown-a" href="./LICENSE.txt">BSD-2-Clause</a> -- (c) M. A. Chatterjee / <a class="quikdown-a" href="https://github.com/deftio" rel="noopener noreferrer">deftio</a>
510
+ <a class="quikdown-a" href="./LICENSE.txt">BSD-2-Clause</a> -- (c) M. A. Chatterjee / <a class="quikdown-a" href="https://github.com/deftio" rel="noopener noreferrer">deftio</a> -- use it in your own projects or commercially.
409
511
  </p>
410
512
  </div>
411
513
  </div>