A binary vector-image format for the web · v0.2 · specification + reference implementation.
▶ Live demo: https://kinti.github.io/svb/demo/ — <img src="*.svb"> rendering in current browsers via a Service Worker.
Spanish project article: https://jquin.net/svb/
SVG is the universal vector format — and its file format has been frozen for two decades. SVB is a compact binary encoding of the same geometry, designed around three properties SVG lacks: size efficiency, verifiable accessibility, and delivery safety. Files render in current browsers through a Service Worker polyfill — no plugin, no browser changes.
- Specification — byte-level, context-free grammar, normative invariants, container ABNF: SPEC.md
- Design model — invariants, threat model, findings ledger: DESIGN.md
- Reference implementation — dependency-free JavaScript: encoder, decoder, CLI (batch mode), validator, fuzzer (src/)
- Conformance vectors — golden
.svbfiles with SHA-256 manifest and byte-exactness tests: vectors/ - Delivery — Service Worker polyfill + comparison page: live demo
- The standard is frozen. SVG 2 died as an abandoned Candidate Recommendation; the working group has been in maintenance mode for years. Structural problems will not be fixed from the inside.
- Text is expensive. Every coordinate costs 3–8 bytes of ASCII; generic transport compression cannot see the geometry it compresses.
- Accessibility is optional in practice.
<title>,<desc>, ARIA inside SVG — almost nobody ships them, and nothing in the format can verify them. - Scripts are a liability. SVG can carry JavaScript — the classic uploaded-logo XSS vector.
SVB addresses each point at the format level:
- Binary encoding — zigzag delta coordinates at configurable fixed-point precision, interned style table, MVT-style command-run packing. Median ×0.277 of the optimized SVG; raw SVB is smaller than svgo+brotli on 100% of the measured corpus.
- A11Y as a first-class chunk — accessible name and description with a fixed grammar, announced by a header flag. Validators can require it; auditors can certify it.
- Safety by construction — no executable chunk type exists; the decoder emits only geometry and escaped text. Bounded reads, declared-count validation, decompression and expansion ceilings are normative (SPEC §12).
- A chunk container built to evolve — unknown chunks are skipped, so repetition, gradients (v0.2) and future progressive rendering or animation ship without breaking anything.
Corpus: 1,087 production SVGs (Feather, Bootstrap Icons, Simple Icons — seed 42), each optimized with svgo multipass before measuring — the comparison is against what a developer would actually ship. Reproducible via benchmark/run.mjs; full data on the benchmark page.
| metric | result |
|---|---|
| Median svb / svg-optimized | ×0.277 |
| Raw SVB smaller than svgo+brotli | 100% of files |
| Median svb+brotli / svgo+brotli | ×0.542 |
| Median size | 467 B → 139 B |
| Mean savings per file | 72.7% (570 B saved) |
| Aggregate bytes saved across the corpus | 73.8% |
Large production-like files (140–580 KB: repetitive maps, schematics, organic curves — the class where naive binary formats typically lose to brotli). v0.2's repetition model (templates + delta-chained instances) and command packing close the gap:
| sample | svb | svg+brotli | ratio |
|---|---|---|---|
| repetitive map, 12k blocks | 1,438 B | 10,040 B | ×0.143 |
| repetitive map, 3k blocks | 948 B | 3,897 B | ×0.233 |
| schematic, 2k instances | 281 B | 4,081 B | ×0.064 |
| organic curves (no repetition) | 66,695 B | 63,190 B | ×1.055 — conceded to v0.3 |
node src/cli.js encode in.svg out.svb
node src/cli.js encode indir/ outdir/ [--strict] # batch: every .svg, per-file warning report
node src/cli.js decode out.svb back.svg
node src/cli.js roundtrip in.svg # encode→decode, writes the decoded SVG
node src/cli.js bench in.svg [more…] # svg/gzip/brotli/svb size table
node src/cli.js validate in.svb [--json] # conformance report + accessibility seal
node src/cli.js fuzz [files…] # deterministic mutation campaign
npm run fuzz:radamsa # 6,000-mutant radamsa campaign (needs radamsa)
npm test # 56 tests (node:test, zero dependencies)Delivery uses a Service Worker: requests for *.svb are decoded (DEFLATE via DecompressionStream, then the reference decoder) and answered as image/svg+xml, so <img src="icon.svb"> works in any current browser — the same "format + runtime" path that carried Lottie and Rive.
Chunk-based container with forward compatibility (unknown chunks are skipped by declared size), zigzag delta coordinates at configurable fixed-point precision, an interned style table, a grammar-fixed A11Y chunk (accessible name and description, verifiable without rendering), linear and radial gradients (objectBoundingBox-u8 or userSpaceOnUse, optional transform), repetition as templates plus delta-chained instances, command-run packing, and reserved chunks for progressive rendering and declarative animation.
Security properties, by design: no executable constructs (removes the uploaded-SVG XSS vector), bounded reads, declared-count validation, decompression and expansion ceilings, zero runtime dependencies. Formal statement: SPEC §12 and DESIGN.md.
- Subset:
g,path,rect,circle,ellipse,line,polyline,polygon, templates/instances, linear and radial gradients. Not yet: text, filters, clip/mask, embedded CSS, pattern fills. - Nothing is dropped silently: every unsupported feature the encoder skips (CSS,
<script>,clipPath/mask/filter/pattern/marker/symbol, container mask/clip/filter attributes) is reported as a warning. - Presentation attributes only (no CSS inheritance from
<style>). - Arc rotations quantized to whole degrees; coordinates to
1/coord_scale(default 1/64). - Organic no-repetition artwork stays ~5% behind svg+brotli — geometry modeling is planned for v0.3.
- Geometry modeling for the organic class (adaptive quantization / curve fitting) — v0.3.
- Entropy stage (grammar-informed codes or rANS) — trigger: measured gap to svg+brotli > 10% after repetition modeling.
<text>and clip/mask — the remaining subset gaps.Validator + "accessible SVB" seal— core shipped in v0.2:svb validateruns 14 conformance and accessibility checks (V-01…V-14, see docs/validator.md) and awards the "SVB accesible" seal. Next: report schema hardening + a11y-toolkit MCP integration.Fuzzing campaign— shipped: deterministic mutator in CI (src/fuzz.js) plus a 6,000-mutant radamsa campaign with 0 malformed outputs, 0 hangs, 0 crashes (see SECURITY.md, reproducible vianpm run fuzz:radamsa).- Rust → WASM port of the hot path.
This repository (spec + reference implementation + conformance suite) is the foundation. Planned next steps: image/svb media type registration with IANA (RFC 6838 expert review), and a W3C Community Group if adoption warrants it. Precedents: TinyVG, Lottie and Rive operate without consortium standardization; adoption decides, and the consortium — if it ever comes — comes after.
Bug reports, hostile files, and feature ideas are all welcome — see CONTRIBUTING.md. The short version: the format is frozen for stability right now, so issues age better than feature PRs; crashes become regression tests.
MIT — © 2026 Jesús Quintana · jquin.net
