bitwrench 2.0.22 → 2.0.24

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 (88) hide show
  1. package/LICENSE.txt +1 -1
  2. package/README.md +4 -3
  3. package/bin/bwmcp.js +3 -0
  4. package/dist/bitwrench-bccl.cjs.js +1 -1
  5. package/dist/bitwrench-bccl.cjs.min.js +1 -1
  6. package/dist/bitwrench-bccl.cjs.min.js.gz +0 -0
  7. package/dist/bitwrench-bccl.esm.js +1 -1
  8. package/dist/bitwrench-bccl.esm.min.js +1 -1
  9. package/dist/bitwrench-bccl.esm.min.js.gz +0 -0
  10. package/dist/bitwrench-bccl.umd.js +1 -1
  11. package/dist/bitwrench-bccl.umd.min.js +1 -1
  12. package/dist/bitwrench-bccl.umd.min.js.gz +0 -0
  13. package/dist/bitwrench-code-edit.cjs.js +1 -1
  14. package/dist/bitwrench-code-edit.cjs.min.js +1 -1
  15. package/dist/bitwrench-code-edit.es5.js +1 -1
  16. package/dist/bitwrench-code-edit.es5.min.js +1 -1
  17. package/dist/bitwrench-code-edit.esm.js +1 -1
  18. package/dist/bitwrench-code-edit.esm.min.js +1 -1
  19. package/dist/bitwrench-code-edit.umd.js +1 -1
  20. package/dist/bitwrench-code-edit.umd.min.js +1 -1
  21. package/dist/bitwrench-code-edit.umd.min.js.gz +0 -0
  22. package/dist/bitwrench-debug.js +1 -1
  23. package/dist/bitwrench-debug.min.js +1 -1
  24. package/dist/bitwrench-lean.cjs.js +3 -3
  25. package/dist/bitwrench-lean.cjs.min.js +2 -2
  26. package/dist/bitwrench-lean.cjs.min.js.gz +0 -0
  27. package/dist/bitwrench-lean.es5.js +3 -3
  28. package/dist/bitwrench-lean.es5.min.js +2 -2
  29. package/dist/bitwrench-lean.es5.min.js.gz +0 -0
  30. package/dist/bitwrench-lean.esm.js +3 -3
  31. package/dist/bitwrench-lean.esm.min.js +2 -2
  32. package/dist/bitwrench-lean.esm.min.js.gz +0 -0
  33. package/dist/bitwrench-lean.umd.js +3 -3
  34. package/dist/bitwrench-lean.umd.min.js +2 -2
  35. package/dist/bitwrench-lean.umd.min.js.gz +0 -0
  36. package/dist/bitwrench-util-css.cjs.js +1 -1
  37. package/dist/bitwrench-util-css.cjs.min.js +1 -1
  38. package/dist/bitwrench-util-css.es5.js +1 -1
  39. package/dist/bitwrench-util-css.es5.min.js +1 -1
  40. package/dist/bitwrench-util-css.esm.js +1 -1
  41. package/dist/bitwrench-util-css.esm.min.js +1 -1
  42. package/dist/bitwrench-util-css.umd.js +1 -1
  43. package/dist/bitwrench-util-css.umd.min.js +1 -1
  44. package/dist/bitwrench-util-css.umd.min.js.gz +0 -0
  45. package/dist/bitwrench.cjs.js +3 -3
  46. package/dist/bitwrench.cjs.min.js +2 -2
  47. package/dist/bitwrench.cjs.min.js.gz +0 -0
  48. package/dist/bitwrench.css +1 -1
  49. package/dist/bitwrench.es5.js +3 -3
  50. package/dist/bitwrench.es5.min.js +2 -2
  51. package/dist/bitwrench.es5.min.js.gz +0 -0
  52. package/dist/bitwrench.esm.js +3 -3
  53. package/dist/bitwrench.esm.min.js +2 -2
  54. package/dist/bitwrench.esm.min.js.gz +0 -0
  55. package/dist/bitwrench.umd.js +3 -3
  56. package/dist/bitwrench.umd.min.js +2 -2
  57. package/dist/bitwrench.umd.min.js.gz +0 -0
  58. package/dist/builds.json +65 -65
  59. package/dist/bwserve.cjs.js +2 -2
  60. package/dist/bwserve.esm.js +2 -2
  61. package/dist/sri.json +45 -45
  62. package/docs/README.md +76 -0
  63. package/docs/app-patterns.md +264 -0
  64. package/docs/bitwrench-mcp.md +426 -0
  65. package/docs/bitwrench_api.md +2232 -0
  66. package/docs/bw-attach.md +399 -0
  67. package/docs/bwserve.md +841 -0
  68. package/docs/cli.md +307 -0
  69. package/docs/component-cheatsheet.md +144 -0
  70. package/docs/component-library.md +1099 -0
  71. package/docs/framework-translation-table.md +33 -0
  72. package/docs/llm-bitwrench-guide.md +672 -0
  73. package/docs/routing.md +562 -0
  74. package/docs/state-management.md +767 -0
  75. package/docs/taco-format.md +373 -0
  76. package/docs/theming.md +309 -0
  77. package/docs/thinking-in-bitwrench.md +1457 -0
  78. package/docs/tutorial-bwserve.md +297 -0
  79. package/docs/tutorial-embedded.md +314 -0
  80. package/docs/tutorial-website.md +255 -0
  81. package/package.json +11 -3
  82. package/readme.html +5 -4
  83. package/src/mcp/knowledge.js +231 -0
  84. package/src/mcp/live.js +226 -0
  85. package/src/mcp/server.js +216 -0
  86. package/src/mcp/tools.js +369 -0
  87. package/src/mcp/transport.js +55 -0
  88. package/src/version.js +3 -3
@@ -0,0 +1,373 @@
1
+ # The TACO Format
2
+
3
+ Every UI element in bitwrench is a plain JavaScript object with up to four keys:
4
+
5
+ ```javascript
6
+ {
7
+ t: 'div', // Tag — HTML element name
8
+ a: { class: 'card', id: 'main' }, // Attributes — HTML attributes
9
+ c: 'Hello World', // Content — text, TACO, or array
10
+ o: { state: { count: 0 } } // Options — state, lifecycle, behavior
11
+ }
12
+ ```
13
+
14
+ That's it. **T**ag, **A**ttributes, **C**ontent, **O**ptions — TACO.
15
+
16
+ ## Why plain objects?
17
+
18
+ TACO objects are regular JavaScript. You can store them in variables, pass them to functions, put them in arrays, serialize them to JSON, send them over the network, and generate them on a server. No special syntax, no compiler, no toolchain.
19
+
20
+ ```javascript
21
+ // It's just data — compose with standard JavaScript
22
+ const header = { t: 'h1', c: 'Welcome' };
23
+ const items = data.map(d => ({ t: 'li', c: d.name }));
24
+ const page = { t: 'div', c: [header, { t: 'ul', c: items }] };
25
+ ```
26
+
27
+ > **Coming from React?** A TACO object is analogous to what `React.createElement()` returns — a description of UI, not the UI itself. The difference is that TACO is plain data you write directly, while JSX requires a compiler to produce React elements.
28
+
29
+ > **Coming from Vue?** TACO is similar to Vue's render function `h('div', { class: 'card' }, children)`, but as a data literal rather than a function call. Vue's `<template>` blocks compile down to something similar internally.
30
+
31
+ ## The four keys
32
+
33
+ ### `t` — Tag
34
+
35
+ The HTML element name. Required for rendering.
36
+
37
+ ```javascript
38
+ { t: 'div' } // <div></div>
39
+ { t: 'button' } // <button></button>
40
+ { t: 'input' } // <input>
41
+ { t: 'h1' } // <h1></h1>
42
+ ```
43
+
44
+ ### `a` — Attributes
45
+
46
+ An object of HTML attributes. All standard attributes work, including event handlers.
47
+
48
+ ```javascript
49
+ {
50
+ t: 'button',
51
+ a: {
52
+ class: 'bw-btn bw-btn-primary',
53
+ id: 'save-btn',
54
+ disabled: true,
55
+ onclick: function() { console.log('clicked'); },
56
+ 'data-action': 'save',
57
+ style: 'margin-top: 1rem'
58
+ }
59
+ }
60
+ ```
61
+
62
+ Style can also be an object:
63
+
64
+ ```javascript
65
+ a: { style: { marginTop: '1rem', color: '#333' } }
66
+ ```
67
+
68
+ For composable styles, use `bw.s()` to merge multiple style objects:
69
+
70
+ ```javascript
71
+ a: { style: bw.s({ display: 'flex' }, { alignItems: 'center' }, { gap: '1rem' }, { marginTop: '1rem' }) }
72
+ ```
73
+
74
+ `bw.s()` merges style objects into a style string — it's `Object.assign` for CSS with a string output. See [Thinking in Bitwrench](thinking-in-bitwrench.md) for full coverage.
75
+
76
+ > **Coming from React?** Attribute names use standard HTML casing (`class`, `onclick`, `tabindex`), not React's camelCase (`className`, `onClick`, `tabIndex`).
77
+
78
+ ### `c` — Content
79
+
80
+ The element's content. This can be:
81
+
82
+ - **A string** — rendered as text content (HTML-escaped by default)
83
+ - **A TACO object** — rendered as a child element
84
+ - **An array** — each item rendered in order (strings, TACOs, or nested arrays)
85
+
86
+ ```javascript
87
+ // String content
88
+ { t: 'p', c: 'Hello World' }
89
+
90
+ // Child TACO
91
+ { t: 'div', c: { t: 'span', c: 'nested' } }
92
+
93
+ // Array of children
94
+ { t: 'ul', c: [
95
+ { t: 'li', c: 'First' },
96
+ { t: 'li', c: 'Second' },
97
+ { t: 'li', c: 'Third' }
98
+ ]}
99
+
100
+ // Mixed content
101
+ { t: 'div', c: [
102
+ { t: 'h2', c: 'Title' },
103
+ 'Some paragraph text',
104
+ { t: 'button', c: 'Click me' }
105
+ ]}
106
+ ```
107
+
108
+ #### Content escaping
109
+
110
+ Content is HTML-escaped by default. The text `<script>alert('xss')</script>` renders as literal text, not as a script tag.
111
+
112
+ To include raw HTML, use `bw.raw()` or set `o: { raw: true }`:
113
+
114
+ ```javascript
115
+ // Escaped (safe, default)
116
+ { t: 'div', c: '<b>bold</b>' }
117
+ // Renders: &lt;b&gt;bold&lt;/b&gt;
118
+
119
+ // Raw HTML (opt-in)
120
+ { t: 'div', c: bw.raw('<b>bold</b>') }
121
+ // Renders: <b>bold</b>
122
+
123
+ // Or via options
124
+ { t: 'div', c: '<b>bold</b>', o: { raw: true } }
125
+ ```
126
+
127
+ ### `o` — Options
128
+
129
+ The options key carries state, lifecycle hooks, and component behavior. This is where TACO goes beyond simple HTML description.
130
+
131
+ ```javascript
132
+ {
133
+ t: 'div',
134
+ o: {
135
+ // Component state
136
+ state: { count: 0, items: [] },
137
+
138
+ // Render function (called by bw.update)
139
+ render: function(el) {
140
+ bw.DOM(el, { t: 'span', c: 'Count: ' + el._bw_state.count });
141
+ },
142
+
143
+ // Lifecycle hooks
144
+ mounted: function(el) { console.log('in the DOM'); },
145
+ unmount: function(el) { console.log('being removed'); },
146
+
147
+ // Skip content escaping
148
+ raw: true,
149
+
150
+ // Component handle -- methods exposed on el.bw (v2.0.19+)
151
+ handle: {
152
+ increment: function(el) { el._bw_state.count++; bw.update(el); }
153
+ },
154
+
155
+ // Content slots -- auto-generates el.bw.setX()/getX() (v2.0.19+)
156
+ slots: {
157
+ title: '.my_title',
158
+ content: '.my_body'
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ See [State Management](state-management.md) for detailed coverage of `o.state`, `o.render`, lifecycle hooks, `o.handle`, and `o.slots`.
165
+
166
+ ## Rendering TACO objects
167
+
168
+ TACO objects are data. To produce actual output, pass them to a rendering function:
169
+
170
+ ```javascript
171
+ // Render to HTML string (works in Node.js and browsers)
172
+ const html = bw.html({ t: 'div', c: 'Hello' });
173
+ // '<div>Hello</div>'
174
+
175
+ // Create a live DOM element (browser only)
176
+ const el = bw.createDOM({ t: 'div', c: 'Hello' });
177
+ // HTMLDivElement
178
+
179
+ // Mount into an existing DOM element (browser only)
180
+ bw.DOM('#app', { t: 'div', c: 'Hello' });
181
+ // Replaces contents of #app
182
+ ```
183
+
184
+ `bw.DOM()` cleans up any previous content (running unmount hooks, clearing state) before mounting new content. This prevents memory leaks when re-rendering.
185
+
186
+ ## bw.h() — concise TACO constructor
187
+
188
+ `bw.h()` is a helper that produces TACO objects from positional arguments. It's a convenience — the return value is a plain `{t, a, c, o}` object, identical to what you'd write by hand.
189
+
190
+ ```javascript
191
+ bw.h('div') // { t: 'div' }
192
+ bw.h('p', { class: 'intro' }, 'Hello') // { t: 'p', a: { class: 'intro' }, c: 'Hello' }
193
+ bw.h('span', null, 'text') // { t: 'span', c: 'text' } (null attrs omitted)
194
+ bw.h('div', null, [ // { t: 'div', c: [...] }
195
+ bw.h('li', null, 'one'),
196
+ bw.h('li', null, 'two')
197
+ ])
198
+ ```
199
+
200
+ A common pattern is to alias `bw.h` for compact code:
201
+
202
+ ```javascript
203
+ var h = bw.h;
204
+
205
+ var footer = h('footer', { class: 'bw_bg_dark bw_text_light bw_py_4' }, [
206
+ h('p', null, 'Built with bitwrench.'),
207
+ h('p', null, h('a', { href: '/about' }, 'About'))
208
+ ]);
209
+ ```
210
+
211
+ The output is serializable (assuming no function values), works with `bw.html()`, `bw.DOM()`, `bw.createDOM()`, bwserve, and everywhere else TACO is accepted. Mix `bw.h()` calls freely with `make*()` returns and hand-written TACO — they all produce the same thing.
212
+
213
+ > **When to use `bw.h()` vs. hand-written TACO**: Use `bw.h()` for structural glue — wrapper divs, footers, headings — where the `{t:, a:, c:}` key syntax feels heavy. For complex nodes with `o:` (state, lifecycle), write full TACO — the named keys are clearer.
214
+
215
+ ## Composition patterns
216
+
217
+ Because TACO is just JavaScript, you compose UI with standard language features:
218
+
219
+ ### Variables
220
+
221
+ ```javascript
222
+ const title = { t: 'h1', c: 'Dashboard' };
223
+ const sidebar = { t: 'aside', c: 'Menu' };
224
+ const main = { t: 'main', c: [title, { t: 'p', c: 'Content' }] };
225
+ ```
226
+
227
+ ### Functions
228
+
229
+ ```javascript
230
+ function userCard(user) {
231
+ return {
232
+ t: 'div', a: { class: 'card' },
233
+ c: [
234
+ { t: 'h3', c: user.name },
235
+ { t: 'p', c: user.email }
236
+ ]
237
+ };
238
+ }
239
+
240
+ const cards = users.map(userCard);
241
+ bw.DOM('#list', { t: 'div', c: cards });
242
+ ```
243
+
244
+ ### Conditionals
245
+
246
+ ```javascript
247
+ const content = isLoggedIn
248
+ ? { t: 'div', c: 'Welcome back' }
249
+ : { t: 'div', c: 'Please log in' };
250
+ ```
251
+
252
+ ### Loops
253
+
254
+ ```javascript
255
+ const rows = data.map(item => ({
256
+ t: 'tr', c: [
257
+ { t: 'td', c: item.name },
258
+ { t: 'td', c: String(item.value) }
259
+ ]
260
+ }));
261
+ ```
262
+
263
+ ## TACO and the component library
264
+
265
+ The `make*()` functions in bitwrench's component library return TACO objects:
266
+
267
+ ```javascript
268
+ const card = bw.makeCard({ title: 'Users', content: '1,234' });
269
+ // Returns a TACO object — not HTML, not DOM
270
+
271
+ bw.DOM('#app', card); // Mount it
272
+ const html = bw.html(card); // Or render to string
273
+ ```
274
+
275
+ This means you can compose library components the same way you compose raw TACOs:
276
+
277
+ ```javascript
278
+ bw.DOM('#app', {
279
+ t: 'div', c: [
280
+ bw.makeNavbar({ brand: 'My App', items: [...] }),
281
+ bw.makeContainer({ children: [
282
+ bw.makeCard({ title: 'Stats', content: '42' }),
283
+ bw.makeTable({ data: rows, sortable: true })
284
+ ]})
285
+ ]
286
+ });
287
+ ```
288
+
289
+ See [Component Library](component-library.md) for all available components.
290
+
291
+ ## Custom components without BCCL
292
+
293
+ The `make*()` component library (BCCL) is a convenience, not a requirement. You can write your own component factories that return TACO objects — bitwrench doesn't care where the TACO comes from.
294
+
295
+ ```javascript
296
+ // Your own component factory — no BCCL needed
297
+ function myStatusBadge(status) {
298
+ var colors = { ok: '#4caf50', warn: '#ff9800', error: '#f44336' };
299
+ return {
300
+ t: 'span',
301
+ a: {
302
+ class: 'status-badge',
303
+ style: 'background: ' + (colors[status] || '#999')
304
+ + '; color: #fff; padding: 0.25rem 0.75rem;'
305
+ + ' border-radius: 999px; font-size: 0.8rem;'
306
+ },
307
+ c: status.toUpperCase()
308
+ };
309
+ }
310
+
311
+ bw.DOM('#app', myStatusBadge('ok'));
312
+ ```
313
+
314
+ You can also wrap existing CSS frameworks (Bootstrap, Tailwind, etc.) in TACO objects:
315
+
316
+ ```javascript
317
+ // Bootstrap button as a TACO
318
+ { t: 'button', a: { class: 'btn btn-primary' }, c: 'Save' }
319
+
320
+ // Tailwind card as a TACO
321
+ {
322
+ t: 'div',
323
+ a: { class: 'bg-white rounded-lg shadow-md p-6' },
324
+ c: [
325
+ { t: 'h3', a: { class: 'text-lg font-semibold' }, c: 'Title' },
326
+ { t: 'p', a: { class: 'text-gray-600 mt-2' }, c: 'Content' }
327
+ ]
328
+ }
329
+ ```
330
+
331
+ Bitwrench doesn't care where your CSS classes come from — it just renders the TACO to HTML/DOM. The `make*()` functions use bitwrench's built-in CSS classes (`bw_card`, `bw_btn`, etc.), but that's a choice, not a constraint.
332
+
333
+ To make a custom component reactive, add `o.state` and `o.render`:
334
+
335
+ ```javascript
336
+ bw.DOM('#app', {
337
+ t: 'span',
338
+ o: {
339
+ state: { label: 'OK', color: '#4caf50' },
340
+ render: function(el) {
341
+ var s = el._bw_state;
342
+ bw.DOM(el, {
343
+ t: 'span',
344
+ a: { class: 'status-badge',
345
+ style: 'background:' + s.color + '; color:#fff; padding:0.25rem 0.75rem; border-radius:999px;' },
346
+ c: s.label
347
+ });
348
+ }
349
+ }
350
+ });
351
+
352
+ // Later, update state from outside:
353
+ var el = bw.$('.status-badge')[0].parentElement;
354
+ el._bw_state.label = 'ERROR';
355
+ el._bw_state.color = '#f44336';
356
+ bw.update(el);
357
+ ```
358
+
359
+ ## TACO beyond the browser
360
+
361
+ Because TACO objects are plain data, they work in contexts beyond browser rendering:
362
+
363
+ - **Server-side rendering**: `bw.html(taco)` produces HTML strings in Node.js
364
+ - **Static site generation**: The `bwcli` command converts files to styled HTML pages
365
+ - **Server-driven UI**: A server can push TACO objects to the browser via SSE, and the client renders them with `bw.DOM()`
366
+ - **Serialization**: TACO objects (without function values) can be JSON-serialized and sent over the network
367
+ - **Testing**: TACO objects can be inspected and compared as data without needing a DOM
368
+
369
+ This is a deliberate design choice. The separation between "what to render" (TACO) and "how to render it" (bw.DOM, bw.html) means the same component definition works across all these contexts.
370
+
371
+ ---
372
+
373
+ For a deeper exploration of bitwrench's design philosophy, see [Thinking in Bitwrench](thinking-in-bitwrench.md).
@@ -0,0 +1,309 @@
1
+ # Theming
2
+
3
+ Bitwrench generates CSS at runtime from seed colors. You provide two or three hex colors, and the theme engine derives a complete design system — buttons, cards, alerts, tables, and every other component get consistent, coordinated styling.
4
+
5
+ There is no CSS preprocessor, no build step, and no external stylesheet to manage. The generated CSS is injected into the document as a `<style>` element.
6
+
7
+ ## Quick start
8
+
9
+ ```javascript
10
+ bw.loadStyles({
11
+ primary: '#0077b6',
12
+ secondary: '#90e0ef'
13
+ });
14
+ ```
15
+
16
+ This single call:
17
+
18
+ 1. Derives a full color palette from your two seed colors (9 color families, 8 shades each)
19
+ 2. Generates scoped CSS for all bitwrench components
20
+ 3. Generates an alternate palette (light/dark counterpart)
21
+ 4. Injects both stylesheets into the document
22
+
23
+ Every bitwrench component rendered after this call uses the generated theme.
24
+
25
+ ## Theme presets
26
+
27
+ Bitwrench ships with 12 built-in presets:
28
+
29
+ | Preset | Primary | Secondary | Character |
30
+ |--------|---------|-----------|-----------|
31
+ | `teal` | `#006666` | `#6c757d` | Default, neutral |
32
+ | `ocean` | `#0077b6` | `#90e0ef` | Cool, professional |
33
+ | `sunset` | `#e76f51` | `#264653` | Warm, bold |
34
+ | `forest` | `#2d6a4f` | `#95d5b2` | Natural, calm |
35
+ | `slate` | `#343a40` | `#adb5bd` | Minimal, gray |
36
+ | `rose` | `#e11d48` | `#fda4af` | Vibrant, modern |
37
+ | `indigo` | `#4f46e5` | `#a5b4fc` | Deep, technical |
38
+ | `amber` | `#d97706` | `#fbbf24` | Energetic, warm |
39
+ | `emerald` | `#059669` | `#6ee7b7` | Fresh, growth |
40
+ | `nord` | `#5e81ac` | `#88c0d0` | Muted, Scandinavian |
41
+ | `coral` | `#ef6461` | `#4a7c7e` | Friendly, balanced |
42
+ | `midnight` | `#1e3a5f` | `#7c8db5` | Dark, serious |
43
+
44
+ Use a preset by name:
45
+
46
+ ```javascript
47
+ bw.loadStyles(bw.THEME_PRESETS.ocean);
48
+ ```
49
+
50
+ Or pass the preset colors directly:
51
+
52
+ ```javascript
53
+ bw.loadStyles({
54
+ primary: '#0077b6',
55
+ secondary: '#90e0ef',
56
+ tertiary: '#00b4d8'
57
+ });
58
+ ```
59
+
60
+ ## Configuration options
61
+
62
+ The full config object:
63
+
64
+ ```javascript
65
+ bw.loadStyles({
66
+ // Seed colors (primary and secondary are required)
67
+ primary: '#0077b6', // Brand color
68
+ secondary: '#90e0ef', // Accent color
69
+ tertiary: '#00b4d8', // Third accent (defaults to primary)
70
+
71
+ // Semantic colors (optional — sensible defaults derived from seeds)
72
+ success: '#198754',
73
+ danger: '#dc3545',
74
+ warning: '#b38600',
75
+ info: '#0891b2',
76
+ light: '#f8f9fa',
77
+ dark: '#212529',
78
+
79
+ // Surface colors (optional)
80
+ background: '#ffffff', // Page background
81
+ surface: '#f8f9fa', // Card/panel background
82
+
83
+ // Layout tokens
84
+ spacing: 'normal', // 'compact' | 'normal' | 'spacious'
85
+ radius: 'md', // 'none' | 'sm' | 'md' | 'lg' | 'pill'
86
+
87
+ // Typography
88
+ fontSize: 1.0, // Base font size scale factor
89
+ typeRatio: 'normal', // 'tight' | 'normal' | 'relaxed' | 'dramatic'
90
+
91
+ // Visual depth
92
+ elevation: 'md', // 'flat' | 'sm' | 'md' | 'lg'
93
+ motion: 'standard', // 'reduced' | 'standard' | 'expressive'
94
+
95
+ // Color harmonization (0 to 1)
96
+ harmonize: 0.20, // Shift semantic colors toward primary hue
97
+
98
+ // Injection behavior
99
+ inject: true // Set to false to get CSS without injecting
100
+ });
101
+ ```
102
+
103
+ ### Spacing presets
104
+
105
+ Control padding across all components:
106
+
107
+ | Preset | Button | Card | Alert | Table cell | Input |
108
+ |--------|--------|------|-------|------------|-------|
109
+ | `compact` | 0.25rem 0.75rem | 0.75rem 1rem | 0.5rem 1rem | 0.5rem 0.75rem | 0.25rem 0.75rem |
110
+ | `normal` | 0.5rem 1rem | 1.5rem 1.5rem | 0.75rem 1.5rem | 0.75rem 1rem | 0.5rem 0.75rem |
111
+ | `spacious` | 0.75rem 1.5rem | 2rem 2rem | 1rem 1.5rem | 1rem 1.5rem | 0.75rem 1rem |
112
+
113
+ ### Radius presets
114
+
115
+ Control border-radius across all components:
116
+
117
+ | Preset | Button | Card | Badge | Alert | Input |
118
+ |--------|--------|------|-------|-------|-------|
119
+ | `none` | 0 | 0 | 0 | 0 | 0 |
120
+ | `sm` | 4px | 4px | 0.25rem | 4px | 4px |
121
+ | `md` | 6px | 8px | 0.375rem | 8px | 6px |
122
+ | `lg` | 10px | 12px | 0.5rem | 12px | 10px |
123
+ | `pill` | 50rem | 1rem | 50rem | 1rem | 50rem |
124
+
125
+ ### Type ratio presets
126
+
127
+ Control the modular scale for heading sizes:
128
+
129
+ | Preset | Ratio | Effect |
130
+ |--------|-------|--------|
131
+ | `tight` | 1.2 | Subtle size differences between headings |
132
+ | `normal` | 1.33 | Balanced (minor third scale) |
133
+ | `relaxed` | 1.5 | Pronounced heading hierarchy |
134
+ | `dramatic` | 1.618 | Golden ratio — large headings, compact body |
135
+
136
+ ### Elevation presets
137
+
138
+ Control box-shadow depth:
139
+
140
+ | Preset | Description |
141
+ |--------|-------------|
142
+ | `flat` | No shadows |
143
+ | `sm` | Subtle shadows |
144
+ | `md` | Standard depth (default) |
145
+ | `lg` | Pronounced shadows |
146
+
147
+ ### Motion presets
148
+
149
+ Control transition timing:
150
+
151
+ | Preset | Fast | Normal | Slow | Easing |
152
+ |--------|------|--------|------|--------|
153
+ | `reduced` | 100ms | 150ms | 200ms | ease-out |
154
+ | `standard` | 100ms | 200ms | 300ms | ease-out |
155
+ | `expressive` | 150ms | 300ms | 500ms | cubic-bezier(0.34, 1.56, 0.64, 1) |
156
+
157
+ ## The palette
158
+
159
+ `bw.makeStyles()` returns an object with the full generated palette:
160
+
161
+ ```javascript
162
+ var theme = bw.makeStyles({
163
+ primary: '#0077b6',
164
+ secondary: '#90e0ef'
165
+ });
166
+ bw.applyStyles(theme);
167
+
168
+ // theme.palette contains 9 color families, each with 8 shades:
169
+ theme.palette.primary.base; // '#0077b6' — the seed color
170
+ theme.palette.primary.hover; // darker variant for hover states
171
+ theme.palette.primary.active; // darker still for active/pressed states
172
+ theme.palette.primary.light; // very light tint for backgrounds
173
+ theme.palette.primary.darkText; // dark variant for text
174
+ theme.palette.primary.border; // medium-light for borders
175
+ theme.palette.primary.focus; // semi-transparent for focus rings
176
+ theme.palette.primary.textOn; // '#fff' or '#000' — readable text on base
177
+
178
+ // Same 8 shades available for:
179
+ // secondary, tertiary, success, danger, warning, info, light, dark
180
+
181
+ // Surface colors (raw hex strings):
182
+ theme.palette.background; // '#ffffff'
183
+ theme.palette.surface; // '#f8f9fa'
184
+ ```
185
+
186
+ ### How shade derivation works
187
+
188
+ From a single seed color, `bw.deriveShades()` produces eight coordinated variants:
189
+
190
+ | Shade | Derivation | Purpose |
191
+ |-------|-----------|---------|
192
+ | `base` | The seed color itself | Default button/badge/alert fill |
193
+ | `hover` | 10% darker | Hover state |
194
+ | `active` | 15% darker | Active/pressed state |
195
+ | `light` | 85% tinted with white | Light background (alert bg, card highlight) |
196
+ | `darkText` | 40% darker | Text color for dark-on-light layouts |
197
+ | `border` | 60% tinted with white | Border color |
198
+ | `focus` | 25% opacity of seed | Focus ring |
199
+ | `textOn` | `#fff` or `#000` | Readable text on the base color (WCAG contrast) |
200
+
201
+ ### Color harmonization
202
+
203
+ When `harmonize` is set (default: 0.20), semantic colors (success, danger, warning, info) have their hue shifted slightly toward the primary color. This creates visual cohesion — a forest-themed app's success green will lean toward the forest primary, while an ocean-themed app's success green will lean toward blue.
204
+
205
+ Set `harmonize: 0` for pure, unmodified semantic colors.
206
+
207
+ ## Primary and alternate palettes
208
+
209
+ Every theme has two palettes: primary and alternate. The alternate is derived automatically by inverting the luminance of each seed color.
210
+
211
+ - If your primary palette is light, the alternate will be dark
212
+ - If your primary palette is dark, the alternate will be light
213
+
214
+ ```javascript
215
+ var theme = bw.makeStyles({
216
+ primary: '#0077b6',
217
+ secondary: '#90e0ef'
218
+ });
219
+ bw.applyStyles(theme);
220
+
221
+ theme.isLightPrimary; // false — ocean primary is a dark blue
222
+ theme.alternate.palette; // light-inverted version of ocean
223
+ ```
224
+
225
+ ### Switching between palettes
226
+
227
+ ```javascript
228
+ // Toggle between primary and alternate palettes
229
+ bw.toggleStyles();
230
+ ```
231
+
232
+ The toggle works by adding or removing the CSS class `.bw_theme_alt` on the `<html>` element. Both primary and alternate stylesheets are injected at theme generation time, so switching is instant -- no re-generation needed.
233
+
234
+ ### Clearing a theme
235
+
236
+ ```javascript
237
+ bw.clearStyles();
238
+ ```
239
+
240
+ This removes the injected `<style>` elements and clears the internal theme cache. Call this before generating a new theme with different colors to prevent CSS accumulation.
241
+
242
+ ## Using themes without injection
243
+
244
+ Set `inject: false` to get the CSS without adding it to the document:
245
+
246
+ ```javascript
247
+ var theme = bw.makeStyles({
248
+ primary: '#0077b6',
249
+ secondary: '#90e0ef',
250
+ inject: false
251
+ });
252
+
253
+ // Use the CSS string however you want
254
+ console.log(theme.css); // primary CSS
255
+ console.log(theme.alternate.css); // alternate CSS
256
+
257
+ // Write to a file in Node.js
258
+ fs.writeFileSync('theme.css', theme.css + '\n' + theme.alternate.css);
259
+ ```
260
+
261
+ This is useful for:
262
+
263
+ - Static site generation (write CSS to a file)
264
+ - Server-side rendering (include CSS in the HTML response)
265
+ - Theme export tools (let users download their theme)
266
+
267
+ ## Multiple themes on one page
268
+
269
+ Themes are scoped by CSS class name. You can have multiple themes active simultaneously:
270
+
271
+ ```javascript
272
+ bw.loadStyles({ primary: '#0077b6', secondary: '#90e0ef' });
273
+ bw.loadStyles({ primary: '#e76f51', secondary: '#264653' });
274
+ ```
275
+
276
+ Apply themes to different sections by adding the theme name as a class:
277
+
278
+ ```javascript
279
+ bw.DOM('#header', {
280
+ t: 'div', a: { class: 'ocean' },
281
+ c: bw.makeNavbar({ brand: 'App', dark: true })
282
+ });
283
+
284
+ bw.DOM('#sidebar', {
285
+ t: 'div', a: { class: 'sunset' },
286
+ c: bw.makeCard({ title: 'Sidebar' })
287
+ });
288
+ ```
289
+
290
+ Components inside an `ocean`-classed container use ocean colors; components inside a `sunset`-classed container use sunset colors.
291
+
292
+ ## Color utility functions
293
+
294
+ These functions are available for custom color work:
295
+
296
+ | Function | Description |
297
+ |----------|-------------|
298
+ | `bw.hexToHsl(hex)` | Convert hex to `[h, s, l]` array |
299
+ | `bw.hslToHex([h, s, l])` | Convert HSL array to hex |
300
+ | `bw.adjustLightness(hex, amount)` | Shift lightness by percentage points |
301
+ | `bw.mixColor(hex1, hex2, ratio)` | Linear interpolation between two colors |
302
+ | `bw.relativeLuminance(hex)` | WCAG 2.0 relative luminance (0–1) |
303
+ | `bw.textOnColor(hex)` | Returns `'#fff'` or `'#000'` for readable text |
304
+ | `bw.deriveShades(hex)` | Generate 8 shade variants from one color |
305
+ | `bw.derivePalette(config)` | Generate full palette from seed config |
306
+
307
+ > **Coming from Tailwind?** Bitwrench's shade derivation is similar to Tailwind's color scale (50–900), but generated algorithmically from a single seed rather than hand-tuned. The 8 shades map to specific UI roles (hover, active, focus ring) rather than numeric levels.
308
+
309
+ > **Coming from Bootstrap?** Bitwrench's theme generation replaces Bootstrap's Sass `$theme-colors` map and `tint-color()`/`shade-color()` functions. Instead of a build step with Sass variables, you call `bw.loadStyles()` at runtime.