-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreadme.html
More file actions
528 lines (513 loc) · 41 KB
/
Copy pathreadme.html
File metadata and controls
528 lines (513 loc) · 41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="bitwrench v2.1.3">
<title>bitwrench.js - README</title>
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
<script src="dist/bitwrench.umd.min.js"></script>
<script src="pages/shared-nav.js"></script>
<script src="pages/site.js"></script>
<style>
.quikdown-h1 { font-size:2em;font-weight:600;margin:.67em 0;text-align:left;color:#333 }
.quikdown-h2 { font-size:1.5em;font-weight:600;margin:.83em 0;color:#333 }
.quikdown-h3 { font-size:1.25em;font-weight:600;margin:1em 0;color:#333 }
.quikdown-h4 { font-size:1em;font-weight:600;margin:1.33em 0;color:#333 }
.quikdown-h5 { font-size:.875em;font-weight:600;margin:1.67em 0;color:#333 }
.quikdown-h6 { font-size:.85em;font-weight:600;margin:2em 0;color:#333 }
.quikdown-pre { background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0 }
.quikdown-code { background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace }
.quikdown-blockquote { border-left:4px solid #ddd;margin-left:0;padding-left:1em;color:#333 }
.quikdown-table { border-collapse:collapse;width:100%;margin:1em 0 }
.quikdown-th { border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left }
.quikdown-td { border:1px solid #ddd;padding:8px;text-align:left;color:#333 }
.quikdown-hr { border:none;border-top:1px solid #ddd;margin:1em 0 }
.quikdown-img { max-width:100%;height:auto }
.quikdown-a { color:#06c;text-decoration:underline }
.quikdown-strong { font-weight:bold }
.quikdown-em { font-style:italic }
.quikdown-del { text-decoration:line-through }
.quikdown-ul { margin:.5em 0;padding-left:2em }
.quikdown-ol { margin:.5em 0;padding-left:2em }
.quikdown-li { margin:.25em 0;color:#333 }
.quikdown-task-item { list-style:none }
.quikdown-task-checkbox { margin-right:.5em }
/* README-specific overrides to match pages/ look */
.readme-body {
max-width: 48rem;
margin: 0 auto;
padding: 0;
line-height: 1.6;
}
.readme-body img { max-width: 100%; height: auto; }
.readme-body table { border-collapse: collapse; width: 100%; margin: 1em 0; }
.readme-body th, .readme-body td { border: 1px solid var(--bw_card_border); padding: 0.5em 0.75em; text-align: left; }
.readme-body th { background: var(--bw_teal_bg); font-weight: 600; }
.readme-body h2 { border-bottom: 1px solid var(--bw_card_border); padding-bottom: 0.3em; }
.readme-body a { color: var(--bw_teal); }
.readme-body a:hover { color: var(--bw_teal_dark); }
.readme-body pre { background: var(--bw_code_bg); border-radius: 6px; overflow-x: auto; border: 1px solid rgba(0,0,0,0.1); }
.readme-body pre code { display: block; padding: 1rem; color: var(--bw_code_text); font-family: var(--bw_font_mono); font-size: 0.8125rem; line-height: 1.6; background: transparent; border: none; }
.readme-body code:not(pre code) { background: var(--bw_teal_light); color: var(--bw_teal_dark); padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.85em; font-family: var(--bw_font_mono); }
.readme-body blockquote { border-left: 4px solid var(--bw_teal); margin-left: 0; padding-left: 1em; color: var(--bw_text_secondary); }
</style>
</head>
<body>
<div id="example-nav"></div>
<div class="page-header">
<div class="content-container wide" style="padding-top: 0; padding-bottom: 0;">
<h1>README</h1>
<p class="subtitle">The project README rendered with bitwrench site styling.</p>
</div>
</div>
<div class="content-container">
<div class="demo-section">
<div class="demo-content">
<div class="readme-body">
<h1 class="quikdown-h1">bitwrench.js</h1>
<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" data-qd-alt="License" data-qd-src="https://img.shields.io/badge/License-BSD%202--Clause-blue.svg" data-qd="!"></a>
<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" data-qd-alt="NPM version" data-qd-src="https://img.shields.io/npm/v/bitwrench.svg?style=flat-square" data-qd="!"></a>
<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" data-qd-alt="CI" data-qd-src="https://github.com/deftio/bitwrench/actions/workflows/ci.yml/badge.svg" data-qd="!"></a>
<a class="quikdown-a" href="https://github.com/deftio/bitwrench" rel="noopener noreferrer"><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="!"></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" data-qd-alt="bitwrench" data-qd-src="./images/bitwrench-logo-med.png" data-qd="!"></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 "TACO" -- Tag, Attributes, Content, Options
var page = {
t: 'div', a: { class: 'card' },
c: [
{ t: 'h2', c: 'Hello' },
{ t: 'p', c: 'UI as native JavaScript objects.' },
{ t: 'button', a: { onclick: function() { alert('clicked'); } }, c: 'Click me' }
]
};
bw.mount('#app', page); // -> live DOM
bw.html(page); // -> 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>
<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
import bw from 'bitwrench';
// CommonJS
const bw = require('bitwrench');</code></pre><p>Or include directly in a page:</p><pre class="quikdown-pre"><code class="language-html"><script src="https://cdn.jsdelivr.net/npm/bitwrench/dist/bitwrench.umd.min.js"></script></code></pre><h2 class="quikdown-h2">Getting Started</h2>
<p>A complete page -- no build step, no imports, everything is a plain object:</p><pre class="quikdown-pre"><code class="language-html"><!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.jsdelivr.net/npm/bitwrench/dist/bitwrench.umd.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
bw.loadStyles(); // structural CSS + design tokens
bw.mount('#app', {
t: 'div', a: { class: 'bw_container' },
c: [
{ t: 'h1', c: 'My App' },
{ t: 'p', c: 'Built from plain JavaScript objects.' },
{ t: 'button',
a: { class: 'bw_btn bw_primary', onclick: function() { alert('Hello!'); } },
c: 'Click me' }
]
});
</script>
</body>
</html></code></pre><h2 class="quikdown-h2">Components</h2>
<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) {
return { t: 'span', a: { class: 'bw_badge ' + (ok ? 'bw_success' : 'bw_warning') }, c: label };
}
// Built-in and custom components compose identically
bw.mount('#app', {
t: 'div', a: { class: 'bw_container' },
c: [
bw.makeCard({ title: 'Server', content: 'Build 2.1.0' }),
statusChip('online', true)
]
});</code></pre><h2 class="quikdown-h2">State and Updates</h2>
<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 = {
t: 'div',
o: {
state: { count: 0 },
render: function(el, state) {
bw.mount(el, {
t: 'div', c: [
{ t: 'h3', c: 'Count: ' + state.count },
bw.makeButton({ text: '+1', onclick: function() {
state.count++;
bw.refresh(el);
}})
]
});
}
}
};
bw.mount('#app', 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">
<thead class="quikdown-thead">
<tr class="quikdown-tr">
<th class="quikdown-th">Update verb</th>
<th class="quikdown-th">Cost</th>
<th class="quikdown-th">What happens</th>
</tr>
</thead>
<tbody class="quikdown-tbody">
<tr class="quikdown-tr">
<td class="quikdown-td"><code class="quikdown-code">el.bw.method()</code> / slot setters</td>
<td class="quikdown-td">Surgical</td>
<td class="quikdown-td">Component updates its own DOM directly</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td"><code class="quikdown-code">bw.update(ref, data)</code></td>
<td class="quikdown-td">Dispatch</td>
<td class="quikdown-td">Calls <code class="quikdown-code">el.bw.update(data)</code> -- never rebuilds</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td"><code class="quikdown-code">bw.message(ref, action, data)</code></td>
<td class="quikdown-td">Dispatch</td>
<td class="quikdown-td">Calls <code class="quikdown-code">el.bw[action]()</code> by selector or UUID</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td"><code class="quikdown-code">bw.patch(id, content)</code></td>
<td class="quikdown-td">Targeted</td>
<td class="quikdown-td">Replaces one element's content</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td"><code class="quikdown-code">bw.refresh(ref)</code></td>
<td class="quikdown-td">Full rebuild</td>
<td class="quikdown-td">Re-runs <code class="quikdown-code">o.render</code>; children are unmounted and rebuilt</td>
</tr>
</tbody>
</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>
<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('#stats', {
t: 'div', a: { class: 'stats-card' },
c: [
{ t: 'h3', a: { class: 'card-title' }, c: 'Revenue' },
{ t: 'span', a: { class: 'card-value' }, c: '$50,000' }
],
o: {
slots: { title: '.card-title', value: '.card-value' },
handle: {
update: function(el, data) { el.bw.setValue('§CB7§#39; + data.value.toLocaleString()); }
}
}
});
card.bw.setTitle('Profit'); // slot setter -- updates one text node
card.bw.update({ value: 120000 }); // handle method -- runs your logic
bw.update(card, { value: 99000 }); // same call, dispatched by element or UUID</code></pre><p><code class="quikdown-code">slots: { title: '.card-title' }</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'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's lifecycle is four explicit calls:</p><table class="quikdown-table">
<thead class="quikdown-thead">
<tr class="quikdown-tr">
<th class="quikdown-th">Phase</th>
<th class="quikdown-th">You call</th>
<th class="quikdown-th">Opt-in hook</th>
</tr>
</thead>
<tbody class="quikdown-tbody">
<tr class="quikdown-tr">
<td class="quikdown-td">Define</td>
<td class="quikdown-td">a function that returns a TACO</td>
<td class="quikdown-td">--</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Mount</td>
<td class="quikdown-td">bw.mount('#app', taco)</td>
<td class="quikdown-td">o.mounted(el)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Update</td>
<td class="quikdown-td">el.bw.method() / bw.refresh(el)</td>
<td class="quikdown-td">--</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Unmount</td>
<td class="quikdown-td">bw.remove(el)</td>
<td class="quikdown-td">o.unmount(el)</td>
</tr>
</tbody>
</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>
<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('item-added', function(detail) { console.log('New:', detail.name); });
bw.pub('item-added', { name: 'Widget' });
bw.sub('item:*', function(detail, topic) { /* matches item:added, item:removed, etc. */ });</code></pre><p>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:</p><pre class="quikdown-pre"><code class="language-javascript">bw.sub('cart:updated', function(data) {
el._bw_state.count = data.count;
bw.refresh(el);
}, el);</code></pre><h2 class="quikdown-h2">CSS from JavaScript</h2>
<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"><style></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
bw.injectCSS(bw.css({
'.my-card': { padding: '1rem', borderRadius: '8px' }
}));
// Compose inline styles from reusable objects
{ t: 'div', a: { style: bw.s({ display: 'flex' }, { gap: '1rem' }, { padding: '1rem' }) } }
// Responsive breakpoints
bw.responsive('.hero', {
base: { fontSize: '1.5rem' },
md: { fontSize: '2.5rem' }
});</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>
<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({
primary: '#336699',
secondary: '#cc6633'
});
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>
<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];
BW_PATCH(msg, "office-temp", "23.5");
BW_SSE_FRAME(frame, msg);
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's flash -- no CDN and no internet required.</p><h2 class="quikdown-h2">CLI</h2>
<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
bwcli README.md -o index.html --standalone
# Apply a theme preset
bwcli doc.md -o doc.html --standalone --theme ocean
# Custom colors
bwcli doc.md -o doc.html --standalone --theme "#336699,#cc6633"</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>
<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
curl -X POST http://localhost:9000 -d '{"type":"patch","ref":"temp","content":"23.5 C"}'</code></pre><h3 class="quikdown-h3">Dev Server & Debugging</h3>
<p><code class="quikdown-code">bwcli serve</code> doubles as a dev server with remote debugging. Attach a REPL, inspect DOM state, and capture screenshots -- all from the terminal:</p><pre class="quikdown-pre"><code class="language-bash">bwcli serve --allow-screenshot # start with screenshot support
bw> /inspect #app 2 # DOM tree summary (depth 2)
bw> /screenshot body page.png # full-page capture
bw> /screenshot .my-card card.png # element-level capture
bw> /tree # full DOM tree as JSON</code></pre><p>No browser extensions needed -- <code class="quikdown-code">bwcli serve</code> injects a lightweight client script that handles inspect, screenshot, and live patching over SSE. See <a class="quikdown-a" href="docs/bw-attach.md">bw-attach docs</a> for the full REPL command reference.</p><h2 class="quikdown-h2">Coming from Other Frameworks</h2>
<table class="quikdown-table">
<thead class="quikdown-thead">
<tr class="quikdown-tr">
<th class="quikdown-th">You're using</th>
<th class="quikdown-th">For</th>
<th class="quikdown-th">Bitwrench equivalent</th>
</tr>
</thead>
<tbody class="quikdown-tbody">
<tr class="quikdown-tr">
<td class="quikdown-td">React / Vue / Svelte</td>
<td class="quikdown-td">Components</td>
<td class="quikdown-td">{t, a, c, o} objects + o.state + o.render</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">JSX / templates</td>
<td class="quikdown-td">Markup-in-JS</td>
<td class="quikdown-td">Native JS objects -- no compiler</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Tailwind / CSS-in-JS</td>
<td class="quikdown-td">Styling</td>
<td class="quikdown-td">bw.css(), bw.s()</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Sass / PostCSS</td>
<td class="quikdown-td">CSS generation</td>
<td class="quikdown-td">bw.css() from JS objects (supports @media, @keyframes)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">ThemeProvider / CSS vars</td>
<td class="quikdown-td">Theming</td>
<td class="quikdown-td">bw.loadStyles() / bw.makeStyles() from seed colors</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Streamlit / Gradio</td>
<td class="quikdown-td">Server-driven UI</td>
<td class="quikdown-td">bwserve SSE -- from any language</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Redux / Zustand / Pinia</td>
<td class="quikdown-td">State management</td>
<td class="quikdown-td">o.state + bw.refresh() + bw.pub()/sub()</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">Vite / webpack / Babel</td>
<td class="quikdown-td">Build tooling</td>
<td class="quikdown-td">Not needed -- open the HTML file</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">DefinitelyTyped / @types</td>
<td class="quikdown-td">Type declarations</td>
<td class="quikdown-td">Ships dist/bitwrench.d.ts</td>
</tr>
</tbody>
</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>
<table class="quikdown-table">
<thead class="quikdown-thead">
<tr class="quikdown-tr">
<th class="quikdown-th">Function</th>
<th class="quikdown-th">Description</th>
</tr>
</thead>
<tbody class="quikdown-tbody">
<tr class="quikdown-tr">
<td class="quikdown-td">bw.html(obj)</td>
<td class="quikdown-td">Convert a TACO to an HTML string</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.mount(selector, obj)</td>
<td class="quikdown-td">Mount a TACO into a DOM element; returns the root element</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.DOM(selector, obj)</td>
<td class="quikdown-td">Alias of bw.mount()</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.create(taco)</td>
<td class="quikdown-td">Create a detached DOM element from a TACO (not inserted into the page)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.el(selector, apply?)</td>
<td class="quikdown-td">Find an element; optionally apply text, TACO, or function to it</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.$(selector)</td>
<td class="quikdown-td">querySelectorAll as an array</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.raw(str)</td>
<td class="quikdown-td">Mark a string as pre-escaped HTML (no double-escaping)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.css(rules)</td>
<td class="quikdown-td">Generate CSS from a JS object</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.injectCSS(css, opts?)</td>
<td class="quikdown-td">Insert a CSS string into the document as a style tag</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.s(...objs)</td>
<td class="quikdown-td">Compose inline style objects into a style string</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.responsive(sel, breakpoints)</td>
<td class="quikdown-td">Generate @media CSS rules from a breakpoint map</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.loadStyles(config?)</td>
<td class="quikdown-td">Structural CSS (no args) or generate + apply a theme from seed colors</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.makeStyles(config)</td>
<td class="quikdown-td">Generate a theme from seed colors (returns styles object)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.applyStyles(styles)</td>
<td class="quikdown-td">Inject a generated styles object into the document</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.toggleThemeMode(scope?)</td>
<td class="quikdown-td">Switch between primary and alternate palettes</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.clearStyles()</td>
<td class="quikdown-td">Remove injected theme styles</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.patch(id, content)</td>
<td class="quikdown-td">Update a specific element by id or UUID</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.refresh(el)</td>
<td class="quikdown-td">Re-render a stateful component via its o.render function</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.update(el, data)</td>
<td class="quikdown-td">Dispatch to el.bw.update(data)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.message(target, action, data)</td>
<td class="quikdown-td">Dispatch to el.bw[action]() by selector or UUID</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.pub(topic, detail)</td>
<td class="quikdown-td">Publish to subscribers (exact + wildcard matches)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.sub(topic, handler, el?)</td>
<td class="quikdown-td">Subscribe to a topic (supports wildcard 'ns:*'); returns unsub function</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.once(topic, handler, el?)</td>
<td class="quikdown-td">One-shot subscribe; auto-unsub after first fire</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.remove(el)</td>
<td class="quikdown-td">Unmount a component (fires o.unmount hook)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.inspect(target, depth)</td>
<td class="quikdown-td">Introspect a DOM subtree with bitwrench metadata</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">bw.apply(msg)</td>
<td class="quikdown-td">Apply a bwserve protocol message to the DOM</td>
</tr>
</tbody>
</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>
<table class="quikdown-table">
<thead class="quikdown-thead">
<tr class="quikdown-tr">
<th class="quikdown-th">Format</th>
<th class="quikdown-th">File</th>
<th class="quikdown-th">Use case</th>
</tr>
</thead>
<tbody class="quikdown-tbody">
<tr class="quikdown-tr">
<td class="quikdown-td">UMD</td>
<td class="quikdown-td">bitwrench.umd.min.js</td>
<td class="quikdown-td">Browsers and Node.js</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">ESM</td>
<td class="quikdown-td">bitwrench.esm.min.js</td>
<td class="quikdown-td">Modern bundlers (Vite, webpack, etc.)</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">CJS</td>
<td class="quikdown-td">bitwrench.cjs.min.js</td>
<td class="quikdown-td">Node.js require()</td>
</tr>
<tr class="quikdown-tr">
<td class="quikdown-td">ES5</td>
<td class="quikdown-td">bitwrench.es5.min.js</td>
<td class="quikdown-td">Legacy browsers (IE11)</td>
</tr>
</tbody>
</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>
<strong class="quikdown-strong">Start here:</strong></p><ul class="quikdown-ul">
<li class="quikdown-li"><strong class="quikdown-strong"><a class="quikdown-a" href="docs/quickstart.md">Quick Start</a></strong> -- annotated 100-line tutorial covering the full lifecycle</li>
<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>
<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>
</ul><p><strong class="quikdown-strong">Reference guides</strong> (in <code class="quikdown-code">docs/</code>):</p><ul class="quikdown-ul">
<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>
<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>
<li class="quikdown-li"><a class="quikdown-a" href="docs/state-management.md">State Management</a> -- component model, explicit updates, cross-component communication</li>
<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>
<li class="quikdown-li"><a class="quikdown-a" href="docs/theming.md">Theming</a> -- palette-driven theme generation, presets, design tokens</li>
<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>
<li class="quikdown-li"><a class="quikdown-a" href="docs/bw-attach.md">Dev Server & Attach</a> -- REPL, DOM inspection, and screenshots from the terminal</li>
<li class="quikdown-li"><a class="quikdown-a" href="docs/bwserve.md">bwserve</a> -- server-driven UI protocol (SSE, actions, embedded devices)</li>
</ul><p><strong class="quikdown-strong">Tutorials:</strong></p><ul class="quikdown-ul">
<li class="quikdown-li"><a class="quikdown-a" href="docs/tutorial-website.md">Build a Website</a> -- multi-section landing page from TACO objects</li>
<li class="quikdown-li"><a class="quikdown-a" href="docs/tutorial-bwserve.md">bwserve Dashboard</a> -- Streamlit-style server-push dashboard</li>
<li class="quikdown-li"><a class="quikdown-a" href="docs/tutorial-embedded.md">ESP32 IoT Dashboard</a> -- embedded sensor dashboard with C macros</li>
</ul><p><strong class="quikdown-strong">Interactive demos</strong> (live site):</p><ul class="quikdown-ul">
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/00-quick-start.html" rel="noopener noreferrer">Quick Start</a> -- first steps with <code class="quikdown-code">bw.DOM()</code></li>
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/01-components.html" rel="noopener noreferrer">Components</a> -- all UI components with live demos</li>
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/03-styling.html" rel="noopener noreferrer">Styling & Theming</a> -- CSS generation, <code class="quikdown-code">bw.s()</code>, and theming strategies</li>
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/05-state.html" rel="noopener noreferrer">State & Interactivity</a> -- state patterns and stateful TACO</li>
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/06-tic-tac-toe-tutorial.html" rel="noopener noreferrer">Tic Tac Toe Tutorial</a> -- step-by-step game with state management</li>
<li class="quikdown-li"><a class="quikdown-a" href="https://deftio.github.io/bitwrench/pages/07-framework-comparison.html" rel="noopener noreferrer">Framework Comparison</a> -- bitwrench vs React, Vue, Svelte</li>
<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>
</ul><p><strong class="quikdown-strong">Example apps</strong> (in <code class="quikdown-code">examples/</code>):</p><ul class="quikdown-ul">
<li class="quikdown-li"><a class="quikdown-a" href="examples/ember-and-oak/">Ember & Oak Coffee Co.</a> -- full landing page: theme, cart, search, charts, accordion, timeline</li>
<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>
<li class="quikdown-li"><a class="quikdown-a" href="examples/todo-app/">Todo App</a> -- stateful TACO with pub/sub</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/dashboard/">Metrics Dashboard</a> -- live stat cards, bar chart, pub/sub, responsive layout</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/wizard/">Signup Wizard</a> -- multi-step form, state transitions, bw.raw()</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/live-feed/">Live Feed</a> -- real-time stream, bw.patch(), slide-in animation</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/embedded/">IoT Dashboard</a> -- ESP32-style sensor dashboard with SSE</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/client-server/">bwserve Counter</a> -- server-driven UI demo</li>
<li class="quikdown-li"><a class="quikdown-a" href="examples/llm-chat/">LLM Chat</a> -- streaming chat via bwserve + Ollama/OpenAI</li>
</ul><h2 class="quikdown-h2">FAQ</h2>
<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'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('#app', 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: { 'aria-label': '...' }</code>.</p><h2 class="quikdown-h2">Development</h2>
<p><pre class="quikdown-pre"><code class="language-bash">npm install # install dev dependencies
npm run build # build all dist formats (UMD, ESM, CJS, ES5)
npm test # run unit tests
npm run test:cli # run CLI tests
npm run test:e2e # run Playwright browser tests
npm run lint # run ESLint
npm run cleanbuild # full production build with SRI hashes</code></pre></p><h2 class="quikdown-h2">License</h2>
<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.
<br class="quikdown-br"></p>
</div>
</div>
</div>
</div>
<script>
mountExampleNav('#example-nav', '', 'pages/');
</script>
</body>
</html>