1 MB for a complete reactive UI framework, CSS toolkit, binary serialisation, schema validation, compression, transport layer (retry/circuit-breaker/cache), OAuth/OIDC auth, session management, crypto, offline-first PWA, routing, charting, graph visualisation, validation, i18n, state machines, animation, drag-and-drop, accessibility, structured logging, JWT handling, 50+ regex patterns, ISO reference data, RBAC, a workflow engine, Markdown renderer, PicoScript 16-opcode ISA compiler + VM, clipboard, file I/O, notifications, pub/sub, undo/redo, IndexedDB, worker pool, forms, geolocation, camera/media, payments, observers, speech, gamepad, sync/CRDTs, URL utilities, capability detection, caching, async pipelines, diagnostics, config management, runtime types, document chains, schema-driven printing, barcode/QR scanning, TOTP authenticator, full-text search, job scheduling, notification inbox, blob lifecycle management, and multi-tenancy. Most people pull in more than that just for a toast notification library.
Modern web development has become absurdly complicated. You need a bundler, a transpiler, a framework, a meta-framework, a state manager, a CSS-in-JS solution, and forty-seven config files before you can render "Hello World". Then you wait for it to compile.
This toolkit takes a different approach: just host some damn files.
BareMetalJsTools is a collection of tiny, zero-dependency vanilla-JS modules that give you reactive UI, REST transport, SPA routing, charts, and a full CSS framework — all as plain <script> tags. No build step. No compile phase. No node_modules black hole. Save your file, refresh your browser, and get on with your life.
Every module follows the same pattern: small, obvious, fast. You can read the source in one sitting. You can understand what it does without a tutorial series. And because there's nothing to build, your deploy is just... serving files. How you serve them matters — cache headers, compression, CDN — but the point is your toolchain stays out of your way.
Extracted from BareMetalWeb and maintained separately so each piece can be reused, evolved, and tested in isolation.
This toolkit doesn't exist in isolation. The same "strip away the nonsense" philosophy runs through the entire stack:
| Project | What it is |
|---|---|
| BareMetalJsTools | This repo. Reactive UI, REST transport, SPA routing, charts, CSS framework — all as plain <script> tags. This is what happens when you apply the philosophy to the browser. |
| BareMetalWeb | The web server and application framework this toolkit was extracted from. A minimal, metadata-driven .NET web host that serves these JS modules and renders server-driven UI — absolute lightning, but it's the only component in the stack that won't run on a tiny RPi Pico 2W. C port incoming. |
| PicoWeb | The hard part is serving your files well. A tiny, fast web server that does exactly that — static files, cache headers, compression, and nothing else. This is what happens when you apply it to the web server. |
| PicoWAL | A write-ahead-log database engine built from scratch. Binary schema cards, Pack-0 wire format, embedded storage — no ORM, no query planner committee meetings. This is what happens when you apply it to the database. |
| picocompress | Block-based LZ compression in pure C and JS (byte-identical output). Integrated into BareMetal.Rest for opt-in wire compression. This is what happens when you apply it to data on the wire. |
| RP2350B_Bitnet | A 1-bit quantised SLM that runs on a Raspberry Pi Pico 2 with 512 KB of RAM. This is what happens when you apply it to machine learning — and refuse to accept that "AI" requires a data centre, or a GPU, or even a proper desktop or laptop computer. |
| PiOS | A bare-metal operating system for the Pi 5. This is what happens when you apply it to the OS itself. Requires Pi 5 for now — but if we can get it small enough, who knows. |
The whole point is the same everywhere: understand what the machine actually needs to do, throw away everything that doesn't serve that goal, and keep the result small enough that one person can hold the entire system in their head.
| Module | What it does | Source | Min | Nearest equivalent for the not-quite-insane |
|---|---|---|---|---|
BareMetal.Styles |
CSS framework. Grid, flex, buttons, forms, tables, cards, modals, alerts, toasts — all with short class names optimised for wire size. Zero JS. | 58 KB | 42 KB | Bootstrap (227 KB), Tailwind (≈300 KB+), Fabric UI (≈350 KB), React (≈140 KB) |
BareMetal.Styles.BootstrapCompatibilityShim |
Drop-in Bootstrap 5 class-name compatibility. Use standard Bootstrap classes (.btn, .card, .row, .col-md-6, etc.) without loading Bootstrap itself. Optional — only needed if migrating from Bootstrap. |
29 KB | 24 KB | Bootstrap 5 (227 KB) — this replaces it at 1/9th the size |
| Themes | Swap the colour palette with a single <link>. ~800 bytes source, ~600 bytes min each. |
Bootswatch (≈8 KB per theme) |
Available themes (src/themes/):
| Theme | Vibe | File |
|---|---|---|
base |
Clean white, soft greys, gentle blue | base.css |
bedlam |
Dark cyberpunk — neon purples & teals | bedlam.css |
wavefunction |
Dark scientific — deep slate & electric indigo | wavefunction.css |
lava |
Fiery dark — molten oranges on volcanic black | lava.css |
candy |
Soft candy pink — pastels & lilacs on warm white | candy.css |
<!-- Load core + optional theme (after core, overrides :root vars) -->
<link href="BareMetalStyles.min.css" rel="stylesheet">
<link href="themes/bedlam.min.css" rel="stylesheet">Bundled fonts (src/fonts/) — load fonts.css for @font-face declarations:
| Font | Type | Size | Use case |
|---|---|---|---|
BareMetalMono |
JetBrains Mono subset | 17 KB | Code, data, terminals |
BareMetalSans |
Inter subset | 14 KB | Clean body text, UI |
BareMetalPixel |
Silkscreen subset | 2.7 KB | Retro, IoT, tiny displays |
Wavefunction-Sans |
Source Sans 3 subset | 27 KB | Versatile modern sans-serif |
Wavefunction-Curly |
Dancing Script subset | 28 KB | Flowing handwriting/calligraphy |
Wavefunction-Serif |
Source Serif 4 subset | 28 KB | Professional typeset (Times-like) |
<!-- Load fonts (optional — themes reference them via --bs-font-sans) -->
<link href="fonts/fonts.min.css" rel="stylesheet">
<link href="BareMetalStyles.min.css" rel="stylesheet">
<link href="themes/wavefunction.min.css" rel="stylesheet">| Module | What it does | Source | Min | Nearest equivalent for the not-quite-insane |
|---|---|---|---|---|
BareMetal.Bind |
Reactive Proxy state + m-* directives. Two-way forms, lists, toasts, chatbot, calendar, Gantt charts, sortable tables, tree views. |
13 KB | 6 KB | Vue.js (≈40 KB min), Alpine.js (≈15 KB), Rivets.js ❤️, Knockout.js ❤️, TinyBind 💕 |
BareMetal.Components |
Widget directives (m-img, m-toast, m-chatbot, m-calendar, m-gantt, m-table, m-tree, m-entity) that extend Bind. | 25 KB | 13 KB | PrimeVue, Vuetify, Material UI (hundreds of KB each) |
BareMetal.ComponentFactories |
create.* helpers and chatEndpoint() auto-wire for REST-backed chatbots. |
2 KB | 1 KB | Hand-rolled boilerplate |
BareMetal.Template |
Schema-driven DOM builder. Hand it metadata, get a form or table back. | 7 KB | 4 KB | Formly (≈80 KB), JSON Forms (≈200 KB) |
BareMetal.Metadata |
Client-side entity schema registry. Inline JSON, server fetch, or PicoWAL binary — declare your entities and render them automatically. | 8 KB | 4 KB | GraphQL schema + codegen toolchain |
BareMetal.Communications |
REST + WebSocket transport. Negotiates WS binary frames → BSO1 → JSON fallback. CSRF, 401-redirect, request multiplexing. | 19 KB | 8 KB | Axios (≈14 KB) + socket.io-client (≈45 KB) |
BareMetal.Launcher |
Hosted terminal/session launcher helpers. API wrapper, tiny store, session cards, idle display, reconnecting WebSocket attach, optional xterm bridge. | 15 KB | 8 KB | React shell + socket.io-client + state library |
BareMetal.Binary |
BSO1 binary wire serialiser. Zero-copy DataView reads, HMAC-SHA256 signing via Web Crypto. |
23 KB | 14 KB | Protocol Buffers JS (≈230 KB), MessagePack (≈25 KB) |
BareMetal.Compress |
Block-based LZ compressor. Byte-identical to the C reference. Opt-in wire compression for Rest. | 19 KB | 8 KB | Brotli.js (≈300 KB), HeatShrink (≈8 KB) |
BareMetal.Rendering |
Glue layer — wires Rest + Bind + Template into an entity lifecycle (createEntity, listEntities). |
4 KB | 1 KB | Custom Redux middleware + React container layer |
BareMetal.Routing |
History-API SPA router. Named segments (:param), catch-all (*), query parsing. |
7 KB | 2 KB | vue-router (≈18 KB), react-router (≈30 KB) |
BareMetal.Charts |
SVG charts — bar, line, sparkline, donut, gauge. Animated, themeable via CSS custom properties. | 16 KB | 8 KB | Chart.js (≈200 KB), D3 (≈250 KB) |
BareMetal.Graph |
Force-directed graph visualiser. Drag, zoom, hover, dynamic add/remove. | 18 KB | 9 KB | D3-force (≈30 KB) + D3-selection (≈20 KB), Cytoscape.js (≈600 KB) |
BareMetal.Auth |
OIDC/OAuth2 PKCE client. Silent refresh, provider presets (Google, Microsoft, GitHub, Apple, Facebook), login/whoami UI components. | 28 KB | 16 KB | oidc-client-ts (≈80 KB), Auth0 SPA SDK (≈60 KB) |
BareMetal.Crypto |
Web Crypto wrapper. AES-256-GCM symmetric, RSA-OAEP hybrid envelope, ECDSA P-256 signing, PBKDF2 key derivation. | 5 KB | 3 KB | Stanford JS Crypto (≈45 KB), tweetnacl (≈7 KB) |
BareMetal.LocalKVStore |
Key-value store abstraction. localStorage, sessionStorage, IndexedDB backends with TTL, namespacing, cross-tab sync. | 14 KB | 7 KB | localForage (≈29 KB), idb-keyval (≈1 KB) |
BareMetal.Progressive |
PWA helper. Service worker registration, install prompts, offline request queue, push notifications, manifest generation. | 10 KB | 5 KB | Workbox (≈60 KB), PWA Builder |
BareMetal.ServiceWorker |
Configurable service worker. CacheFirst, NetworkFirst, StaleWhileRevalidate strategies, precache, background sync. | 7 KB | 4 KB | Workbox SW (≈15 KB) |
BareMetal.Time |
Date/time library. Format, parse, add/subtract, diff, durations, relative time, timezone support, Temporal API bridge. | 12 KB | 7 KB | Day.js (≈7 KB), date-fns (≈75 KB), Moment.js (≈290 KB) |
BareMetal.Validate |
Schema validation. Required, type, min/max, pattern, nested objects, arrays, custom rules, error objects with path+code+message. | 4 KB | 3 KB | Yup (≈40 KB), Joi (≈150 KB), Zod (≈14 KB) |
BareMetal.I18n |
Internationalisation. Locale fallback chains, ICU plural rules via Intl.PluralRules, interpolation, number/date formatting. |
5 KB | 3 KB | i18next (≈40 KB), FormatJS (≈30 KB) |
BareMetal.StateMachine |
Finite state machine. States, transitions, guards, actions, context, subscribe/unsubscribe. | 3 KB | 1 KB | XState (≈50 KB), Robot (≈4 KB) |
BareMetal.Logger |
Structured logging. Levels, transports (console, beacon, custom), batching, safe circular-ref stringify, child loggers. | 5 KB | 3 KB | Winston (≈80 KB), Pino (≈30 KB), loglevel (≈3 KB) |
BareMetal.Animate |
CSS transition/animation helper. Enter/leave, stagger, spring, respects prefers-reduced-motion, timeout fallback. |
8 KB | 4 KB | Framer Motion (≈120 KB), GSAP (≈60 KB), animate.css (≈80 KB) |
BareMetal.TestRunner |
In-browser test runner. describe/it/expect, async, hooks, mocks, grep, bail, retry, TAP + Markdown reporters. | 24 KB | 13 KB | Jest (≈1 MB), Mocha (≈100 KB), uvu (≈6 KB) |
BareMetal.DragDrop |
Pointer-event drag & drop. Sortable lists, drop zones, constraints, touch support, setPointerCapture. |
11 KB | 6 KB | SortableJS (≈40 KB), dnd-kit (≈45 KB), Draggable (≈80 KB) |
BareMetal.A11y |
Accessibility helpers. Focus traps, live regions, skip links, roving tabindex, keyboard navigation, ARIA attribute management. | 9 KB | 5 KB | focus-trap (≈10 KB), ally.js (≈130 KB) |
BareMetal.Expressions |
50+ pre-built regex patterns. Email, phone, URL, postal codes, credit card, UUID, semver, JWT, dates, and more. test(), extract(), detect(), register(). |
25 KB | 17 KB | validator.js (≈60 KB), regex collections scattered across Stack Overflow |
BareMetal.Tokens |
JWT library. Create, sign (HS256/384/512, RS256, ES256), verify, decode, inspect. Fluent builder, PEM/JWK import, key generation via Web Crypto. | 20 KB | 10 KB | jsonwebtoken (≈30 KB + deps), jose (≈100 KB) |
BareMetal.Codes |
Reference data. Countries (250), currencies, languages, timezones, HTTP status codes, MIME types, CSS colours, card types, units. Lazy-parsed compact encoding. | 28 KB | 29 KB | country-data (≈200 KB), i18n-iso-countries (≈100 KB), scattered npm packages |
BareMetal.RBAC |
Client-side role/permission UI hints. Reads JWT from storage/cookie, checks roles, groups, permissions, scopes. DOM attribute processing. UI hints only — enforce server-side. | 19 KB | 9 KB | CASL (≈30 KB), casbin.js (≈50 KB), custom middleware |
BareMetal.Workflow |
Minimal workflow engine. SET/IF/ELSE/FOR/FOREACH/FOREACHP/WEB/LOAD/SAVE/LOG/WAIT/CALL. Registry, JSON serialization, visual designer component. | 23 KB | 12 KB | n8n (massive), Camunda (enterprise), custom state machines |
BareMetal.Markdown |
GFM Markdown-to-HTML renderer. Headings, lists, tables, code blocks, inline formatting, TOC, front matter, custom renderers, sanitize mode. | 18 KB | 11 KB | marked.js (≈39 KB), markdown-it (≈100 KB), showdown (≈70 KB) |
BareMetal.PicoScript |
Real PicoScript 16-opcode ISA: 4-frontend compiler (C/BASIC/Python/English) + deterministic VM + 456 host hooks across 63 namespaces (OS-worker, AI, storage, crypto, UI, capsules). Runs the same bytecode as PIOS bare metal. | 322 KB | — | No equivalent — complete language VM + compiler in one file |
BareMetal.WorkflowPico |
Compiles BareMetal.Workflow step lists to PicoScript (English dialect) — the visual workflow designer becomes a PicoScript frontend that runs on the browser/RP2350/PIOS/C# VM. Adds a "Compile to PicoScript" designer button. |
16 KB | 8 KB | No equivalent — visual workflow → deterministic bytecode |
BareMetal.Report |
Report & form builder. One templated layout engine, two modes: report (read-only table + aggregate footer) and form (read-write inputs + write-back). Visual designer to create/edit templates. Byte-aligned with PicoScript's picolayout. | 18 KB | 10 KB | JasperReports (huge), hand-rolled table/form code |
BareMetal.Clipboard |
Clipboard API wrapper. Read/write text/HTML/images, paste intercept, copy-with-feedback, legacy execCommand fallback. | 8 KB | 7 KB | clipboard.js (≈7 KB) |
BareMetal.Speech |
Web Speech API wrapper. Speech synthesis, recognition sessions, voice commands, dictation, queued utterances. | 8 KB | 6 KB | react-speech-recognition (≈30 KB), annyang (≈13 KB) |
BareMetal.FileIO |
File System Access API + fallbacks. Open/save picker, drag-drop zones, chunked reading, download, format utilities. | 12 KB | 9 KB | FileSaver.js (≈5 KB) + Dropzone (≈95 KB) |
BareMetal.Notify |
Toast/banner queue + Notification API. info/success/warning/error types, progress bars, stacking, auto-dismiss, dark/light themes. | 11 KB | 11 KB | Toastr (≈8 KB), notyf (≈15 KB), react-hot-toast (≈30 KB) |
BareMetal.PubSub |
Event bus. Wildcard topics (*/**), namespaces, sticky/replay, typed channels, request/response, middleware. | 10 KB | 4 KB | EventEmitter3 (≈3 KB), mitt (≈1 KB), postal.js (≈20 KB) |
BareMetal.UndoRedo |
Command pattern undo/redo. Grouping, snapshots, checkpoints, serialization, keyboard binding, event hooks. | 6 KB | 5 KB | Custom implementations — no dominant library |
BareMetal.IDB |
Promise-based IndexedDB. CRUD, indexes, range queries, cursors, transactions, batch ops, KV mode, export/import. | 12 KB | 7 KB | idb (≈5 KB), Dexie (≈80 KB), localForage (≈30 KB) |
BareMetal.Workers |
Inline WebWorker pool + scheduler. debounce/throttle, RAF read/write batching, idle queue, priority task queue, retry/timeout. | 9 KB | 9 KB | workerpool (≈20 KB), comlink (≈5 KB), lodash.debounce (≈1 KB) |
BareMetal.Geo |
Geolocation, Haversine distance, bearing, geohash encode/decode, point-in-polygon, bounding box, tracking, geocoding. | 9 KB | 7 KB | geolib (≈30 KB), Leaflet (≈170 KB) |
BareMetal.Media |
Camera, microphone, screen capture, MediaRecorder, snapshot, PiP, device enumeration, audio analyser. | 11 KB | 8 KB | RecordRTC (≈120 KB), custom implementations |
BareMetal.Pay |
Payment Request API, cart management, Luhn card validation, currency formatting, shipping options. | 11 KB | 8 KB | Custom implementations |
BareMetal.Observe |
Resize/Intersection/Mutation observers, lazy-load, infinite scroll, sticky detection, breakpoints, animate-on-scroll. | 11 KB | 8 KB | lozad (≈2 KB), waypoints (≈8 KB), custom |
BareMetal.Speech |
Web Speech API: synthesis (speak/queue/pause), recognition (listen/dictate/commands), voice listing. | 8 KB | 6 KB | annyang (≈4 KB), custom implementations |
BareMetal.Gamepad |
Gamepad API: polling, deadzone, button/axis events, haptics, combos, profiles (Xbox/PS), normalization. | 11 KB | 8 KB | gamepad.js (≈10 KB), custom |
BareMetal.Forms |
Declarative forms: validation, masks, wizards, repeaters, autosave, conditional fields, JSON→form generation. | 37 KB | 20 KB | Formik (≈45 KB), react-hook-form (≈25 KB) |
BareMetal.Transport |
Retry/backoff, idempotency, request dedup/coalesce, AbortSignal chaining, cache semantics, circuit breaker, rate limiting, priority queue. | 26 KB | 12 KB | axios-retry (≈5 KB), p-queue (≈8 KB), opossum (≈15 KB) |
BareMetal.Errors |
Typed errors: code/category/retryable, causal chains, classify (transient/auth/validation), match routing, serialisation. | 20 KB | 10 KB | Custom implementations |
BareMetal.Schema |
Type-safe schemas: parse→validate→transform, coercion, versioning, migration, Binary module alignment (wireType). | 31 KB | 13 KB | zod (≈60 KB), ajv (≈120 KB), yup (≈40 KB) |
BareMetal.Sync |
Truth reconciliation: diff/patch, merge strategies, conflict resolution, offline queue, CRDTs, vector clocks. | 25 KB | 12 KB | automerge (≈300 KB), yjs (≈60 KB) |
BareMetal.URL |
URL parse/build, query encode/decode, route params, template, join, normalize, slugify, resolve. | 20 KB | 9 KB | qs (≈8 KB), url-pattern (≈4 KB), slugify (≈3 KB) |
BareMetal.Capabilities |
Feature detection, environment profiling, permissions, fallback trees, progressive degradation, capability scoring. | 23 KB | 12 KB | Modernizr (≈25 KB), custom |
BareMetal.Session |
Session lifecycle, token rotation, multi-tab sync (BroadcastChannel), silent re-auth, activity/idle tracking. | 20 KB | 9 KB | Custom implementations |
BareMetal.Cache |
TTL, SWR, stale-if-error, LRU eviction, tag invalidation, tiered (memory+storage), memoize, stats. | 25 KB | 11 KB | lru-cache (≈8 KB), node-cache (≈15 KB) |
BareMetal.Pipeline |
Composable async pipelines, stream transforms (map/filter/reduce/chunk), backpressure, cancellation. | 21 KB | 10 KB | Highland (≈50 KB), RxJS (≈200 KB) |
BareMetal.Diagnostics |
Trace spans, timeline, perf marks/measures/aggregation, counters, gauges, inspection, module auto-hook. | 25 KB | 11 KB | OpenTelemetry (≈200 KB), custom |
BareMetal.Config |
Layered config (defaults/env/runtime/override), schema validation, scoped contexts, freeze, env export/import. | 26 KB | 11 KB | dotenv (≈5 KB), convict (≈30 KB) |
BareMetal.Types |
Runtime type descriptors, registry, contracts, guards, unions/intersections/tuples, reflection, serialize/clone. | 35 KB | 18 KB | io-ts (≈40 KB), runtypes (≈15 KB) |
BareMetal.DocChain |
Document chains/trees: defineType, create, derive (parent→child), transition (lifecycle), lineage, audit trail, graph output. | 18 KB | 8 KB | Custom implementations |
BareMetal.Print |
Schema-driven print: layout primitives (grid/table/barcode/QR), pagination, device abstraction (browser/PDF/thermal). | 22 KB | 10 KB | pdfmake (≈300 KB), jsPDF (≈200 KB) |
BareMetal.Scan |
Semantic ingestion: camera capture → decode (QR/barcode/OCR) → map to schema-typed object. | 19 KB | 9 KB | html5-qrcode (≈100 KB), quagga (≈180 KB) |
BareMetal.Authenticator |
TOTP/HOTP (RFC 6238/4226): setup, verify with drift, QR URI, replay guard, policy-based step-up auth. | 15 KB | 7 KB | otplib (≈25 KB), speakeasy (≈30 KB) |
BareMetal.Search |
Full-text search: inverted index, TF-IDF ranking, facets, fuzzy matching, stemming, highlight. | 28 KB | 15 KB | lunr (≈20 KB), flexsearch (≈30 KB), MiniSearch (≈25 KB) |
BareMetal.Schedule |
Cron parsing, job queue, intervals, retry with backoff, debounce/throttle, named jobs, lifecycle hooks. | 30 KB | 17 KB | node-cron (≈10 KB), agenda (≈80 KB), bull (≈60 KB) |
BareMetal.Inbox |
Persistent notification center: channels, preferences, read/unread, grouping, priority, retention, search. | 18 KB | 10 KB | Custom implementations |
BareMetal.Blob |
File/blob lifecycle: chunked upload, resumable, hash/checksum, encrypt, store adapters, lifecycle policies. | 36 KB | 20 KB | tus-js-client (≈30 KB), uppy (≈200 KB) |
BareMetal.Tenant |
Multi-tenancy: isolation, context propagation, partitioning, hierarchy, limits, feature flags, suspend/activate. | 19 KB | 11 KB | Custom implementations |
| Total | The whole toolkit | ≈1,550 KB | ≈1 MB | ≈6,000+ KB (picking the smaller option from each row) |
graph TB
subgraph "Presentation"
Styles["🎨 Styles<br/><i>Grid · Buttons · Cards<br/>Modals · Toasts · Layout</i>"]
Charts["📊 Charts<br/><i>Bar · Line · Sparkline<br/>Donut · Gauge</i>"]
Graph["🕸️ Graph<br/><i>Force-directed<br/>Drag · Zoom</i>"]
end
subgraph "Reactive Binding"
Bind["⚡ Bind + Components<br/><i>Proxy state · m-* directives</i>"]
Factories["🏭 Factories<br/><i>create.* · chatEndpoint</i>"]
Metadata["📋 Metadata<br/><i>Entity schemas · m-entity</i>"]
end
subgraph "Transport"
Rest["🌐 Communications<br/><i>REST + WebSocket<br/>CSRF · Multiplexing</i>"]
Binary["📦 Binary<br/><i>BSO1 codec · HMAC</i>"]
Compress["🗜️ Compress<br/><i>LZ compression</i>"]
end
subgraph "Orchestration"
Rendering["🔧 Rendering<br/><i>Entity lifecycle</i>"]
Template["📝 Template<br/><i>buildForm · buildTable</i>"]
Routing["🧭 Routing<br/><i>SPA router</i>"]
end
subgraph "Security & Auth"
Auth["🔐 Auth<br/><i>OIDC · PKCE · Providers</i>"]
Crypto["🔑 Crypto<br/><i>AES · RSA · ECDSA</i>"]
end
subgraph "Offline & PWA"
Progressive["📱 Progressive<br/><i>SW reg · Install · Push</i>"]
ServiceWorker["⚙️ ServiceWorker<br/><i>Cache strategies · Sync</i>"]
KVStore["💾 LocalKVStore<br/><i>KV · TTL · IndexedDB</i>"]
Time["🕐 Time<br/><i>Format · Relative · TZ</i>"]
end
subgraph "Dev & Testing"
Validate["✅ Validate<br/><i>Schema · Rules · Errors</i>"]
TestRunner["🧪 TestRunner<br/><i>describe · it · expect</i>"]
Logger["📝 Logger<br/><i>Levels · Transports · Batch</i>"]
end
subgraph "Interaction & UX"
Animate["🎬 Animate<br/><i>Enter/Leave · Spring</i>"]
DragDrop["🖱️ DragDrop<br/><i>Pointer · Sortable · Zones</i>"]
A11y["♿ A11y<br/><i>Focus trap · ARIA · Kbd</i>"]
I18n["🌍 I18n<br/><i>Locale · Plural · Format</i>"]
StateMachine["🔄 StateMachine<br/><i>States · Guards · Context</i>"]
end
Rendering --> Bind
Rendering --> Template
Rendering --> Rest
Metadata --> Template
Metadata -.-> Bind
Metadata -.-> Rest
Rest --> Binary
Rest -.->|opt-in| Compress
Factories -.-> Rest
Bind --> Styles
Auth -.-> Rest
Progressive -.-> Rest
Progressive -.-> KVStore
Progressive --> ServiceWorker
style Bind fill:#0d6efd,color:#fff
style Styles fill:#198754,color:#fff
style Rest fill:#6f42c1,color:#fff
style Charts fill:#fd7e14,color:#fff
style Graph fill:#d63384,color:#fff
style Rendering fill:#495057,color:#fff
style Metadata fill:#20c997,color:#fff
style Auth fill:#dc3545,color:#fff
style Crypto fill:#6610f2,color:#fff
style Progressive fill:#0dcaf0,color:#000
style ServiceWorker fill:#adb5bd,color:#000
style KVStore fill:#ffc107,color:#000
style Time fill:#198754,color:#fff
style Validate fill:#20c997,color:#000
style TestRunner fill:#6c757d,color:#fff
style Logger fill:#adb5bd,color:#000
style Animate fill:#fd7e14,color:#fff
style DragDrop fill:#e83e8c,color:#fff
style A11y fill:#6610f2,color:#fff
style I18n fill:#17a2b8,color:#fff
style StateMachine fill:#495057,color:#fff
<link rel="stylesheet" href="src/BareMetal.Styles.css">
<script src="src/BareMetal.Bind.js"></script>
<script src="src/BareMetal.Components.js"></script>
<!-- add whichever modules you need — order only matters where dependencies exist -->That's it. No install. No config. No waiting.
npm install github:WillEastbury/BareMetalJsToolsconst { state, watch } = BareMetal.Bind.reactive({ name: 'World', items: [] });
document.body.innerHTML = `
<input m-value="name">
<p>Hello, <span m-text="name"></span>!</p>
`;
BareMetal.Bind.bind(document.body, state, watch);
state.name = 'BareMetal'; // UI updates instantlyBareMetal.Routing.on('/users', () => renderList('user'));
BareMetal.Routing.on('/users/:id', ctx => renderDetail('user', ctx.params.id));
BareMetal.Routing.start();BareMetal.Communications.setRoot('/api/');
const customer = BareMetal.Communications.entity('customer');
const all = await customer.list();
await customer.update(42, { name: 'Acme' });<script type="application/bm-meta">
{ "name": "Customer", "schema": { "fields": {
"name": { "type": "text", "label": "Name", "required": true },
"email": { "type": "Email", "label": "Email" }
}}, "layout": { "columns": 2, "fields": ["name", "email"] }}
</script>
<div m-entity="customer" m-mode="form"></div>
<script>
BareMetal.Metadata.scanInline();
// form is auto-rendered and bound — done.
</script>npm install && npm testTests run under Node + jsdom. Each module is loaded in isolation via new Function(...) so globals can be mocked per test.
| Suite | What's covered |
|---|---|
| Bind | reactive(), all m-* directives, dot-paths, formatters, reactive arrays, keyed diffing, transitions, expressions |
| Rest | CRUD, fetch errors, CSRF, FormData |
| Template | buildForm field types, layout, lookup; buildTable cells, callbacks, badges |
| Routing | Pattern matching, params, query parsing, navigate() |
| Rendering | Entity lifecycle, lookup hydration, minibind |
| Compress | Round-trip, profiles, compressBound |
| Metadata | Register, get, scanInline, type normalisation, toTemplateFields |
Web development got complicated for no good reason. Somewhere along the way, "make a web page" turned into "configure a seventeen-stage build pipeline, wait for it to compile, debug the bundler, then discover your CSS got tree-shaken into oblivion."
BareMetalJsTools exists because we think that's insane.
- No build step. Save the file. Refresh the browser. Done.
- No framework tax. No virtual DOM diffing. The browser already has a perfectly good DOM — use it.
- No dependencies. Every module is plain ES2017+ that works in any modern browser, right now.
- Pick what you need. Use one module or all of them. They compose cleanly but don't demand each other.
- Server-driven where it counts. Forms and tables render from metadata — declare your schema, not your markup.
- Wire-efficient. Short class names, binary transport, optional LZ compression. Every byte earns its place.
The hard part isn't the JavaScript. The hard part is serving your files well — cache headers, compression, CDN placement, HTTP/2 push. Focus your energy there, not on configuring webpack.
MIT — see LICENSE.
Extracted from BareMetalWeb and maintained here for independent reuse.