bitwrench 2.0.32 → 2.1.1

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 +211 -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 +289 -282
  68. package/dist/bwserve.d.ts +157 -0
  69. package/dist/bwserve.esm.js +290 -283
  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 -161
  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 +59 -26
  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.md CHANGED
@@ -1,67 +1,32 @@
1
1
  # bitwrench.js
2
2
 
3
- [![License](https://img.shields.io/badge/License-BSD%202--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause)
4
- [![NPM version](https://img.shields.io/npm/v/bitwrench.svg?style=flat-square)](https://www.npmjs.com/package/bitwrench)
5
- [![CI](https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg)](https://github.com/deftio/bitwrench/actions/workflows/ci.yml)
6
- [![Coverage](https://img.shields.io/badge/coverage-97.5%25-brightgreen.svg)](https://github.com/deftio/bitwrench)
3
+ [<img class="quikdown-img" src="https://img.shields.io/badge/License-BSD%202--Clause-blue.svg" alt="License" data-qd-alt="License" data-qd-src="https://img.shields.io/badge/License-BSD%202--Clause-blue.svg" data-qd="!">](https://opensource.org/licenses/BSD-2-Clause)
4
+ [<img class="quikdown-img" src="https://img.shields.io/npm/v/bitwrench.svg?style=flat-square" alt="NPM version" data-qd-alt="NPM version" data-qd-src="https://img.shields.io/npm/v/bitwrench.svg?style=flat-square" data-qd="!">](https://www.npmjs.com/package/bitwrench)
5
+ [<img class="quikdown-img" src="https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg" alt="CI" data-qd-alt="CI" data-qd-src="https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg" data-qd="!">](https://github.com/deftio/bitwrench/actions/workflows/ci.yml)
6
+ [<img class="quikdown-img" src="https://img.shields.io/badge/coverage-99.1%25-brightgreen.svg" alt="Coverage" data-qd-alt="Coverage" data-qd-src="https://img.shields.io/badge/coverage-99.1%25-brightgreen.svg" data-qd="!">](https://github.com/deftio/bitwrench)
7
7
 
8
- [![bitwrench](./images/bitwrench-logo-med.png)](https://deftio.github.io/bitwrench/pages/)
8
+ [<img class="quikdown-img" src="./images/bitwrench-logo-med.png" alt="bitwrench" data-qd-alt="bitwrench" data-qd-src="./images/bitwrench-logo-med.png" data-qd="!">](https://deftio.github.io/bitwrench/pages/)
9
9
 
10
- Bitwrench builds UI from plain JavaScript objects -- one format for components, styling, state, and server rendering, with no build step and zero dependencies.
10
+ 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.
11
11
 
12
12
  ```javascript
13
- // Describe UI as a JavaScript object (a "TACO")
13
+ // A "TACO" -- Tag, Attributes, Content, Options
14
14
  var page = {
15
15
  t: 'div', a: { class: 'card' },
16
16
  c: [
17
17
  { t: 'h2', c: 'Hello' },
18
18
  { t: 'p', c: 'UI as native JavaScript objects.' },
19
- bw.makeButton({ text: 'Click me', variant: 'primary', onclick: fn })
19
+ { t: 'button', a: { onclick: function() { alert('clicked'); } }, c: 'Click me' }
20
20
  ]
21
21
  };
22
22
 
23
- bw.DOM('#app', page); // -> live DOM
23
+ bw.mount('#app', page); // -> live DOM
24
24
  bw.html(page); // -> HTML string (Node.js, emails, SSR)
25
25
  ```
26
26
 
27
- Each object has four keys: **t** (tag), **a** (attributes), **c** (content), **o** (options for state/lifecycle). Nest them, loop them, compose them -- it's just JavaScript.
27
+ Each object has four keys: **t** (tag), **a** (attributes, including event handlers like `onclick`), **c** (content -- a string, array, or nested TACO), and **o** (options for state and lifecycle). Nest them, loop them, build them with functions -- they are ordinary JavaScript values.
28
28
 
29
- ### Why bitwrench?
30
-
31
- **One file, everywhere.** 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.
32
-
33
- Structure, styling, state, and server rendering are all handled as JavaScript objects:
34
-
35
- - **No build toolchain** -- works with a `<script>` tag
36
- - **Ready-made components** -- buttons, tables, modals, forms, charts, toasts -- one `make*()` call each, returns a composable TACO
37
- - **CSS from JavaScript** -- `bw.css()` generates stylesheets, `bw.s()` composes inline styles, `bw.loadStyles()` derives a complete design system from 2 seed colors
38
- - **Reactive state** -- `o.state` + `o.render` + `bw.update()` for stateful components; `bw.pub()`/`bw.sub()` for cross-component messaging
39
- - **Dual rendering** -- same object renders to live DOM (`bw.DOM()`) or HTML string (`bw.html()`) for SSR, emails, or static sites
40
- - **Server-driven UI** -- push UI updates from any backend (Python, C, Rust, Go) over SSE via the biwrench bwserve protocol; `client.screenshot()` captures the page back as PNG/JPEG
41
- - **CLI** -- `bwcli` converts Markdown, HTML, and JSON to styled standalone pages
42
- - **Debug tools** -- live client and server debugging with remote incremental inspect, screenshots, and state updates
43
- - **TypeScript** -- full type declarations ship with the package (`dist/bitwrench.d.ts`); see the [TypeScript Usage Guide](docs/bitwrench_typescript_usage.md)
44
- - **Utilities** -- color interpolation, random data, lorem ipsum, cookies, URL params, file I/O
45
-
46
-
47
-
48
- ### Coming from other Frameworks
49
-
50
- Bitwrench uses JavaScript equivalents for most forms of front-end development. Here is a quick mapping (see the [docs](docs/README.md) and [Thinking in Bitwrench](docs/thinking-in-bitwrench.md) for more details).
51
-
52
- | You're using | For | Bitwrench equivalent |
53
- |---|---|---|
54
- | React / Vue / Svelte | Components + reactivity | `{t, a, c, o}` objects + `o.state` + `o.render` |
55
- | JSX / templates | Markup-in-JS | Native JS objects -- no compiler |
56
- | Tailwind / CSS-in-JS | Styling | `bw.css()`, `bw.s()` style composition |
57
- | Sass / PostCSS | CSS generation | `bw.css()` from JS objects (supports @media, @keyframes) |
58
- | ThemeProvider / CSS vars | Theming | `bw.loadStyles()` / `bw.makeStyles()` from 2 seed colors |
59
- | Streamlit / Gradio | Server-driven UI | bwserve SSE -- from any language (Python, Go, C, Rust) |
60
- | Redux / Zustand / Pinia | State management | `o.state` + `bw.update()` + `bw.pub()/sub()` |
61
- | Vite / webpack / Babel | Build tooling | Not needed -- open the HTML file |
62
- | DefinitelyTyped / @types | Type declarations | Ships `dist/bitwrench.d.ts` -- nothing extra to install |
63
-
64
- See the [Framework Translation Table](docs/framework-translation-table.md) for side-by-side code comparisons across 22 operations.
29
+ 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.
65
30
 
66
31
  ## Installation
67
32
 
@@ -85,6 +50,8 @@ Or include directly in a page:
85
50
 
86
51
  ## Getting Started
87
52
 
53
+ A complete page -- no build step, no imports, everything is a plain object:
54
+
88
55
  ```html
89
56
  <!DOCTYPE html>
90
57
  <html lang="en">
@@ -94,21 +61,16 @@ Or include directly in a page:
94
61
  <body>
95
62
  <div id="app"></div>
96
63
  <script>
97
- bw.loadStyles();
64
+ bw.loadStyles(); // structural CSS + design tokens
98
65
 
99
- bw.DOM('#app', {
100
- t: 'div', a: { class: 'bw-container' },
66
+ bw.mount('#app', {
67
+ t: 'div', a: { class: 'bw_container' },
101
68
  c: [
102
69
  { t: 'h1', c: 'My App' },
103
- bw.makeCard({
104
- title: 'Welcome',
105
- content: 'Built with plain JavaScript objects.'
106
- }),
107
- bw.makeButton({
108
- text: 'Click me',
109
- variant: 'primary',
110
- onclick: function() { alert('Hello!'); }
111
- })
70
+ { t: 'p', c: 'Built from plain JavaScript objects.' },
71
+ { t: 'button',
72
+ a: { class: 'bw_btn bw_primary', onclick: function() { alert('Hello!'); } },
73
+ c: 'Click me' }
112
74
  ]
113
75
  });
114
76
  </script>
@@ -116,23 +78,43 @@ Or include directly in a page:
116
78
  </html>
117
79
  ```
118
80
 
119
- ## Adding State
81
+ ## Components
120
82
 
121
- Add `o.state` and `o.render` to any TACO to make it stateful. The render function is called with the DOM element, and state lives on `el._bw_state`. Call `bw.update(el)` to re-render:
83
+ A component is a function that returns a TACO. Bitwrench ships ~50 factory functions (`bw.makeCard()`, `bw.makeTable()`, `bw.makeTabs()`, etc. -- see the [Component Cheat Sheet](docs/component-cheatsheet.md)). Each is a regular function that returns the same `{t, a, c, o}` object you could write by hand. Log the return value and look at it.
84
+
85
+ Your own components work the same way:
86
+
87
+ ```javascript
88
+ function statusChip(label, ok) {
89
+ return { t: 'span', a: { class: 'bw_badge ' + (ok ? 'bw_success' : 'bw_warning') }, c: label };
90
+ }
91
+
92
+ // Built-in and custom components compose identically
93
+ bw.mount('#app', {
94
+ t: 'div', a: { class: 'bw_container' },
95
+ c: [
96
+ bw.makeCard({ title: 'Server', content: 'Build 2.1.0' }),
97
+ statusChip('online', true)
98
+ ]
99
+ });
100
+ ```
101
+
102
+ ## State and Updates
103
+
104
+ Add `o.state` and `o.render` to any TACO to make it stateful. The render function receives `(el, state)`, and you call `bw.refresh(el)` when you want it to re-run:
122
105
 
123
106
  ```javascript
124
107
  var counter = {
125
108
  t: 'div',
126
109
  o: {
127
110
  state: { count: 0 },
128
- render: function(el) {
129
- var s = el._bw_state;
130
- bw.DOM(el, {
111
+ render: function(el, state) {
112
+ bw.mount(el, {
131
113
  t: 'div', c: [
132
- { t: 'h3', c: 'Count: ' + s.count },
114
+ { t: 'h3', c: 'Count: ' + state.count },
133
115
  bw.makeButton({ text: '+1', onclick: function() {
134
- s.count++;
135
- bw.update(el);
116
+ state.count++;
117
+ bw.refresh(el);
136
118
  }})
137
119
  ]
138
120
  });
@@ -140,32 +122,90 @@ var counter = {
140
122
  }
141
123
  };
142
124
 
143
- bw.DOM('#app', counter);
125
+ bw.mount('#app', counter);
144
126
  ```
145
127
 
146
- > **Important: event handlers go in `a: { onclick: fn }`, not in `o.mounted`.** Handlers attached via `addEventListener` in `o.mounted` are silently lost when a component re-renders. Always use `onclick`/`onchange`/etc. inside `a:` -- bitwrench re-attaches them on every render automatically.
128
+ State is also available as `el._bw_state` from outside the render function -- useful for debugging or direct access from event handlers.
129
+
130
+ > Event handlers go in `a: { onclick: fn }`, not in `o.mounted`. Handlers attached via `addEventListener` in `o.mounted` are lost when a component re-renders. Place them in `a:` and bitwrench re-attaches them on every render.
131
+
132
+ 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.
133
+
134
+ The update functions form a cost ladder:
147
135
 
148
- See the [State Management guide](docs/state-management.md) for the full three-level component model.
136
+ | Update verb | Cost | What happens |
137
+ | --- | --- | --- |
138
+ | `el.bw.method()` / slot setters | Surgical | Component updates its own DOM directly |
139
+ | `bw.update(ref, data)` | Dispatch | Calls `el.bw.update(data)` -- never rebuilds |
140
+ | `bw.message(ref, action, data)` | Dispatch | Calls `el.bw[action]()` by selector or UUID |
141
+ | `bw.patch(id, content)` | Targeted | Replaces one element's content |
142
+ | `bw.refresh(ref)` | Full rebuild | Re-runs `o.render`; children are unmounted and rebuilt |
149
143
 
150
- For communication between components, use pub/sub:
144
+ Choosing where you sit on this ladder is the programming model. The full `bw.refresh()` 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.
145
+
146
+ ## Component API
147
+
148
+ 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 (`el._bw_state`), and so does its public API (`el.bw`).
149
+
150
+ **Slots** map CSS selectors to setter/getter pairs. **Handles** define named methods. Both are attached to `el.bw` at mount time:
151
151
 
152
152
  ```javascript
153
- bw.sub('item-added', function(detail) {
154
- console.log('New item:', detail.name);
153
+ var card = bw.mount('#stats', {
154
+ t: 'div', a: { class: 'stats-card' },
155
+ c: [
156
+ { t: 'h3', a: { class: 'card-title' }, c: 'Revenue' },
157
+ { t: 'span', a: { class: 'card-value' }, c: '$50,000' }
158
+ ],
159
+ o: {
160
+ slots: { title: '.card-title', value: '.card-value' },
161
+ handle: {
162
+ update: function(el, data) { el.bw.setValue('$' + data.value.toLocaleString()); }
163
+ }
164
+ }
155
165
  });
156
166
 
157
- bw.pub('item-added', { name: 'Widget' });
167
+ card.bw.setTitle('Profit'); // slot setter -- updates one text node
168
+ card.bw.update({ value: 120000 }); // handle method -- runs your logic
169
+ bw.update(card, { value: 99000 }); // same call, dispatched by element or UUID
170
+ ```
158
171
 
159
- // Wildcard: listen to a group of related topics
160
- bw.sub('item:*', function(detail, topic) {
161
- console.log(topic, detail); // e.g. 'item:added', 'item:removed'
162
- });
172
+ `slots: { title: '.card-title' }` generates `el.bw.setTitle()` and `el.bw.getTitle()` automatically. `handle` methods are attached as-is to `el.bw`. Neither causes a re-render -- they update the DOM directly.
173
+
174
+ Because everything lives on the element, debugging needs no extension: select a component in the browser's Elements panel and type `$0._bw_state` or `$0.bw`.
175
+
176
+ A component's lifecycle is four explicit calls:
177
+
178
+ | Phase | You call | Opt-in hook |
179
+ | --- | --- | --- |
180
+ | Define | a function that returns a TACO | -- |
181
+ | Mount | bw.mount('#app', taco) | o.mounted(el) |
182
+ | Update | el.bw.method() / bw.refresh(el) | -- |
183
+ | Unmount | bw.remove(el) | o.unmount(el) |
184
+
185
+ The [Component Lifecycle Walkthrough](docs/component-lifecycle.md) takes one card through all four phases. The [State Management guide](docs/state-management.md) covers the full component model.
186
+
187
+ ## Cross-Component Communication
188
+
189
+ Components communicate through pub/sub. `bw.sub()` returns an unsubscribe function. Wildcard topics match any suffix after the colon:
190
+
191
+ ```javascript
192
+ bw.sub('item-added', function(detail) { console.log('New:', detail.name); });
193
+ bw.pub('item-added', { name: 'Widget' });
194
+ bw.sub('item:*', function(detail, topic) { /* matches item:added, item:removed, etc. */ });
163
195
  ```
164
196
 
197
+ Pass an element as the third argument to tie the subscription's lifetime to that element -- when the element is removed from the DOM, the subscription is automatically cleaned up:
198
+
199
+ ```javascript
200
+ bw.sub('cart:updated', function(data) {
201
+ el._bw_state.count = data.count;
202
+ bw.refresh(el);
203
+ }, el);
204
+ ```
165
205
 
166
206
  ## CSS from JavaScript
167
207
 
168
- `bw.css()` generates CSS from objects. `bw.s()` composes inline styles from reusable utility objects:
208
+ `bw.css()` generates CSS strings from objects. `bw.injectCSS()` inserts a CSS string into the document as a `<style>` tag. `bw.s()` composes inline styles. `bw.responsive()` generates `@media` rules from a breakpoint map. These are generation functions -- they return strings, so you can use them anywhere:
169
209
 
170
210
  ```javascript
171
211
  // Generate and inject a stylesheet
@@ -173,7 +213,7 @@ bw.injectCSS(bw.css({
173
213
  '.my-card': { padding: '1rem', borderRadius: '8px' }
174
214
  }));
175
215
 
176
- // Compose inline styles from objects
216
+ // Compose inline styles from reusable objects
177
217
  { t: 'div', a: { style: bw.s({ display: 'flex' }, { gap: '1rem' }, { padding: '1rem' }) } }
178
218
 
179
219
  // Responsive breakpoints
@@ -183,9 +223,11 @@ bw.responsive('.hero', {
183
223
  });
184
224
  ```
185
225
 
226
+ Bitwrench does not own your CSS. You can use external stylesheets, Tailwind, or plain CSS alongside any of the above.
227
+
186
228
  ## Theming
187
229
 
188
- `bw.loadStyles()` 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. `bw.toggleStyles()` switches between primary and alternate palettes:
230
+ `bw.loadStyles()` 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. `bw.toggleThemeMode()` switches between primary and alternate palettes:
189
231
 
190
232
  ```javascript
191
233
  bw.loadStyles({
@@ -193,40 +235,33 @@ bw.loadStyles({
193
235
  secondary: '#cc6633'
194
236
  });
195
237
 
196
- bw.toggleStyles(); // switch between primary and alternate palettes
238
+ bw.toggleThemeMode(); // switch to alternate palette
197
239
  ```
198
240
 
241
+ Styles can be scoped to DOM subtrees, so different parts of a page can use different themes. See the [Theming guide](docs/theming.md) for presets, palette structure, and scoping.
199
242
 
200
- ## Core API
243
+ ## Server-Driven UI
201
244
 
202
- | Function | Description |
203
- |---|---|
204
- | `bw.html(obj)` | Convert a TACO to an HTML string |
205
- | `bw.DOM(selector, obj)` | Mount a TACO to a DOM element |
206
- | `bw.mount(selector, obj)` | Like `bw.DOM()` but returns the root element for `el.bw` access |
207
- | `bw.raw(str)` | Mark a string as pre-escaped HTML (no double-escaping) |
208
- | `bw.css(rules)` | Generate CSS from a JS object |
209
- | `bw.s(...objs)` | Compose inline style objects into a style string |
210
- | `bw.responsive(sel, breakpoints)` | Generate `@media` CSS rules from JS |
211
- | `bw.loadStyles(config?)` | Load structural CSS (no args) or generate + apply a theme from seed colors |
212
- | `bw.makeStyles(config)` | Generate a theme from seed colors (returns styles object) |
213
- | `bw.applyStyles(styles)` | Inject a generated styles object's CSS into the document |
214
- | `bw.toggleStyles()` | Switch between primary and alternate palettes |
215
- | `bw.clearStyles()` | Remove injected theme styles |
216
- | `bw.patch(id, content)` | Update a specific element by id or UUID |
217
- | `bw.update(el)` | Re-render via the element's `o.render` function |
218
- | `bw.message(target, action, data)` | Dispatch a method call to a component's `el.bw` handle |
219
- | `bw.pub(topic, detail)` | Publish to subscribers (exact + wildcard matches) |
220
- | `bw.sub(topic, handler, el?)` | Subscribe to topic (supports wildcard `'ns:*'`); returns unsub function |
221
- | `bw.once(topic, handler, el?)` | One-shot subscribe; auto-unsub after first fire |
222
- | `bw.inspect(target, depth)` | Introspect a DOM subtree with bitwrench metadata (state, handles, type) |
223
- | `bw.apply(msg)` | Apply a bwserve protocol message to the DOM |
224
-
225
- See the full [API Reference](https://deftio.github.io/bitwrench/pages/08-api-reference.html) for all functions.
245
+ Because TACOs are plain objects, they serialize as JSON. This means a backend in any language can push UI updates to the browser.
246
+
247
+ Bitwrench includes bwserve, a protocol that sends TACO objects and patches over SSE. Button clicks come back as actions, `client.inspect()` reads DOM state, and `client.screenshot()` captures the live page as a PNG. The browser becomes a display and input device; the application logic lives wherever you want it.
248
+
249
+ Here is a C program on an ESP32 pushing a sensor reading to the browser:
250
+
251
+ ```c
252
+ char msg[96], frame[128];
253
+ BW_PATCH(msg, "office-temp", "23.5");
254
+ BW_SSE_FRAME(frame, msg);
255
+ events.send(frame, NULL, millis()); // the browser updates
256
+ ```
257
+
258
+ The same protocol works from Python, Go, Rust, or a shell script with `curl`. See the [bwserve docs](docs/bwserve.md) for the full protocol, and the [ESP32 tutorial](docs/tutorial-embedded.md) for a complete embedded walkthrough.
259
+
260
+ 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's flash -- no CDN and no internet required.
226
261
 
227
262
  ## CLI
228
263
 
229
- Convert Markdown, HTML, or JSON files to styled standalone pages:
264
+ `bwcli` converts files to styled standalone pages:
230
265
 
231
266
  ```bash
232
267
  # Convert Markdown to a self-contained HTML page
@@ -247,17 +282,66 @@ Flags: `--output/-o`, `--standalone/-s`, `--cdn`, `--theme/-t`, `--css/-c`, `--t
247
282
 
248
283
  ```bash
249
284
  bwcli serve --port 8080 --input-port 9000
250
- curl -X POST http://localhost:9000 -d '{"type":"patch","target":"temp","content":"23.5 C"}'
285
+ curl -X POST http://localhost:9000 -d '{"type":"patch","ref":"temp","content":"23.5 C"}'
251
286
  ```
252
287
 
288
+ ## Coming from Other Frameworks
289
+
290
+ | You're using | For | Bitwrench equivalent |
291
+ | --- | --- | --- |
292
+ | React / Vue / Svelte | Components | {t, a, c, o} objects + o.state + o.render |
293
+ | JSX / templates | Markup-in-JS | Native JS objects -- no compiler |
294
+ | Tailwind / CSS-in-JS | Styling | bw.css(), bw.s() |
295
+ | Sass / PostCSS | CSS generation | bw.css() from JS objects (supports @media, @keyframes) |
296
+ | ThemeProvider / CSS vars | Theming | bw.loadStyles() / bw.makeStyles() from seed colors |
297
+ | Streamlit / Gradio | Server-driven UI | bwserve SSE -- from any language |
298
+ | Redux / Zustand / Pinia | State management | o.state + bw.refresh() + bw.pub()/sub() |
299
+ | Vite / webpack / Babel | Build tooling | Not needed -- open the HTML file |
300
+ | DefinitelyTyped / @types | Type declarations | Ships dist/bitwrench.d.ts |
301
+
302
+ See the [Framework Translation Table](docs/framework-translation-table.md) for side-by-side code comparisons across 22 operations.
303
+
304
+ ## Core API
305
+
306
+ | Function | Description |
307
+ | --- | --- |
308
+ | bw.html(obj) | Convert a TACO to an HTML string |
309
+ | bw.mount(selector, obj) | Mount a TACO into a DOM element; returns the root element |
310
+ | bw.DOM(selector, obj) | Alias of bw.mount() |
311
+ | bw.create(taco) | Create a detached DOM element from a TACO (not inserted into the page) |
312
+ | bw.el(selector, apply?) | Find an element; optionally apply text, TACO, or function to it |
313
+ | bw.$(selector) | querySelectorAll as an array |
314
+ | bw.raw(str) | Mark a string as pre-escaped HTML (no double-escaping) |
315
+ | bw.css(rules) | Generate CSS from a JS object |
316
+ | bw.injectCSS(css, opts?) | Insert a CSS string into the document as a style tag |
317
+ | bw.s(...objs) | Compose inline style objects into a style string |
318
+ | bw.responsive(sel, breakpoints) | Generate @media CSS rules from a breakpoint map |
319
+ | bw.loadStyles(config?) | Structural CSS (no args) or generate + apply a theme from seed colors |
320
+ | bw.makeStyles(config) | Generate a theme from seed colors (returns styles object) |
321
+ | bw.applyStyles(styles) | Inject a generated styles object into the document |
322
+ | bw.toggleThemeMode(scope?) | Switch between primary and alternate palettes |
323
+ | bw.clearStyles() | Remove injected theme styles |
324
+ | bw.patch(id, content) | Update a specific element by id or UUID |
325
+ | bw.refresh(el) | Re-render a stateful component via its o.render function |
326
+ | bw.update(el, data) | Dispatch to el.bw.update(data) |
327
+ | bw.message(target, action, data) | Dispatch to el.bw[action]() by selector or UUID |
328
+ | bw.pub(topic, detail) | Publish to subscribers (exact + wildcard matches) |
329
+ | bw.sub(topic, handler, el?) | Subscribe to a topic (supports wildcard 'ns:*'); returns unsub function |
330
+ | bw.once(topic, handler, el?) | One-shot subscribe; auto-unsub after first fire |
331
+ | bw.remove(el) | Unmount a component (fires o.unmount hook) |
332
+ | bw.inspect(target, depth) | Introspect a DOM subtree with bitwrench metadata |
333
+ | bw.apply(msg) | Apply a bwserve protocol message to the DOM |
334
+
335
+ The update functions (`bw.patch`, `bw.refresh`, `bw.update`, `bw.message`) form a cost ladder -- see [State and Updates](#state-and-updates). Full [API Reference](https://deftio.github.io/bitwrench/pages/08-api-reference.html).
336
+
253
337
  ## Build Formats
254
338
 
255
339
  | Format | File | Use case |
256
- |--------|------|----------|
257
- | UMD | `bitwrench.umd.min.js` | Browsers and Node.js |
258
- | ESM | `bitwrench.esm.min.js` | Modern bundlers (Vite, webpack, etc.) |
259
- | CJS | `bitwrench.cjs.min.js` | Node.js `require()` |
260
- | ES5 | `bitwrench.es5.min.js` | Legacy browsers (IE11) |
340
+ | --- | --- | --- |
341
+ | UMD | bitwrench.umd.min.js | Browsers and Node.js |
342
+ | ESM | bitwrench.esm.min.js | Modern bundlers (Vite, webpack, etc.) |
343
+ | CJS | bitwrench.cjs.min.js | Node.js require() |
344
+ | ES5 | bitwrench.es5.min.js | Legacy browsers (IE11) |
261
345
 
262
346
  All formats include source maps. A separate CSS file (`bitwrench.css`) is also available for use without JavaScript.
263
347
 
@@ -265,13 +349,14 @@ All formats include source maps. A separate CSS file (`bitwrench.css`) is also a
265
349
 
266
350
  **Start here:**
267
351
 
268
- - **[Thinking in Bitwrench](docs/thinking-in-bitwrench.md)** -- the complete guide. Covers TACO, styling (`bw.css`, `bw.s`, `bw.responsive`), composition, events, the three-level component model, bwserve, and common patterns
269
- - **[LLM Guide](docs/llm-bitwrench-guide.md)** -- compact single-file reference with all APIs, patterns, and rules. Designed for AI-assisted development but works as a cheat sheet for anyone
352
+ - **[Thinking in Bitwrench](docs/thinking-in-bitwrench.md)** -- the complete guide: TACO format, styling, composition, events, the component model, bwserve, and common patterns
353
+ - **[LLM Guide](docs/llm-bitwrench-guide.md)** -- compact single-file reference with all APIs, patterns, and rules
270
354
 
271
355
  **Reference guides** (in `docs/`):
272
356
 
273
357
  - [TACO Format](docs/taco-format.md) -- the `{t, a, c, o}` object format
274
- - [State Management](docs/state-management.md) -- three-level component model, stateful TACO, reactive state
358
+ - [Component Lifecycle Walkthrough](docs/component-lifecycle.md) -- one stats card through all four phases
359
+ - [State Management](docs/state-management.md) -- component model, explicit updates, cross-component communication
275
360
  - [Component Library](docs/component-library.md) -- all `make*()` functions with signatures and examples
276
361
  - [Theming](docs/theming.md) -- palette-driven theme generation, presets, design tokens
277
362
  - [CLI](docs/cli.md) -- the `bwcli` command for file conversion and pipe server
@@ -296,7 +381,7 @@ All formats include source maps. A separate CSS file (`bitwrench.css`) is also a
296
381
  **Example apps** (in `examples/`):
297
382
 
298
383
  - [Ember & Oak Coffee Co.](examples/ember-and-oak/) -- full landing page: theme, cart, search, charts, accordion, timeline
299
- - [SunForge Landing Page](examples/landing-page/) -- polished marketing page with zero reactive state, pure BCCL composition
384
+ - [SunForge Landing Page](examples/landing-page/) -- marketing page with zero reactive state, pure BCCL composition
300
385
  - [Todo App](examples/todo-app/) -- stateful TACO with pub/sub
301
386
  - [Metrics Dashboard](examples/dashboard/) -- live stat cards, bar chart, pub/sub, responsive layout
302
387
  - [Signup Wizard](examples/wizard/) -- multi-step form, state transitions, bw.raw()
@@ -307,19 +392,19 @@ All formats include source maps. A separate CSS file (`bitwrench.css`) is also a
307
392
 
308
393
  ## FAQ
309
394
 
310
- **Is this a framework?** -- No. Bitwrench is a library (~40KB gzipped). No lifecycle to learn, no project structure to follow. Import it, call functions, done.
395
+ **Is this a framework?** -- No. It is a library (165KB on disk, 45KB gzipped). No lifecycle ceremony, no project structure. Import it, call functions, done. Lifecycle hooks (`o.mounted`, `o.unmount`) are opt-in.
311
396
 
312
- **How does bitwrench compare to React/Vue?** -- 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.
397
+ **How does bitwrench compare to React/Vue?** -- 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.
313
398
 
314
- **How does CSS work?** -- Bitwrench doesn't own your CSS. Use any external stylesheet, Tailwind, or CSS file you want -- bitwrench doesn't interfere. On top of that, `bw.css()` generates CSS from JS objects (with `@media`, `@keyframes`, pseudo-classes), `bw.s()` composes inline style objects, and `bw.loadStyles()` derives a complete design system from 2 seed colors. You can use all three together or none at all.
399
+ **How does CSS work?** -- Bitwrench does not own your CSS. Use any external stylesheet, Tailwind, or CSS file you want. On top of that, `bw.css()` generates CSS from JS objects (with `@media`, `@keyframes`, pseudo-classes), `bw.s()` composes inline style objects, and `bw.loadStyles()` derives a complete design system from seed colors. Use all three or none.
315
400
 
316
- **What's the difference between `bw.DOM()` and `bw.html()`?** -- Same TACO input, two outputs. `bw.DOM('#app', taco)` mounts live DOM elements in a browser. `bw.html(taco)` 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.
401
+ **What's the difference between `bw.mount()` and `bw.html()`?** -- Same TACO input, two outputs. `bw.mount('#app', taco)` mounts live DOM elements in a browser. `bw.html(taco)` returns an HTML string for Node.js scripts, email generators, static site builds, or anywhere you need markup without a browser. (`bw.DOM()` is an alias for `bw.mount()`.)
317
402
 
318
- **What is bwserve?** -- bwserve lets any server push UI updates to a browser over SSE. The server sends TACO objects as JSON; the browser renders them. It'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 [bwserve docs](docs/bwserve.md).
403
+ **What is bwserve?** -- 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; `client.inspect()` returns DOM state; `client.screenshot()` returns a PNG. Language-agnostic: Python, Go, Rust, C, or a shell script with `curl`. See the [bwserve docs](docs/bwserve.md).
319
404
 
320
- **Can I use bitwrench on embedded devices?** -- 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 [ESP32 tutorial](docs/tutorial-embedded.md).
405
+ **Can I use bitwrench on embedded devices?** -- 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 `embedded_c/`. See the [ESP32 tutorial](docs/tutorial-embedded.md) and the [Pico W example](examples/embedded-pico-w/).
321
406
 
322
- **Can I use it with TypeScript?** -- Yes. Type declarations ship with the package (`dist/bitwrench.d.ts`). TACO objects are plain JSON-compatible objects that TypeScript infers naturally. See the [TypeScript Usage Guide](docs/bitwrench_typescript_usage.md) for import patterns, typed configs, and examples.
407
+ **Can I use it with TypeScript?** -- Yes. Type declarations ship with the package (`dist/bitwrench.d.ts`). See the [TypeScript Usage Guide](docs/bitwrench_typescript_usage.md).
323
408
 
324
409
  **What about accessibility?** -- BCCL components emit semantic HTML with ARIA attributes where applicable. You can add any `aria-*` attribute via `a: { 'aria-label': '...' }`.
325
410
 
@@ -337,4 +422,5 @@ npm run cleanbuild # full production build with SRI hashes
337
422
 
338
423
  ## License
339
424
 
340
- [BSD-2-Clause](./LICENSE.txt) -- (c) M. A. Chatterjee / [deftio](https://github.com/deftio)
425
+ [BSD-2-Clause](./LICENSE.txt) -- (c) M. A. Chatterjee / [deftio](https://github.com/deftio) -- use it in your own projects or commercially.
426
+