You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/components/qr-code
dev 34f8087fe8
fix(eidos): QrCode size tokens use literal var names (recipe contract)
4 months ago
..
README.md fix(eidos): QrCode logo visibility + demo content presets 4 months ago
context.ts feat(eidos): add QrCode — themeable QR with own zero-dep encoder 4 months ago
index.ts feat(eidos): add QrCode — themeable QR with own zero-dep encoder 4 months ago
qr-code-download-trigger.svelte feat(eidos): add QrCode — themeable QR with own zero-dep encoder 4 months ago
qr-code.css fix(eidos): QrCode logo visibility + demo content presets 4 months ago
qr-code.svelte fix(eidos): QrCode size tokens use literal var names (recipe contract) 4 months ago
types.ts feat(eidos): add QrCode — themeable QR with own zero-dep encoder 4 months ago

README.md

QrCode

Themeable, accessible QR code — own zero-dependency encoder, framework 4-layer rigor, richer than the references it learns from.

Design proposal (approved 2026-06-12). This README is both the design record and the component doc.

Why a new one (vs the references)

Capability ark-ui (zag + uqr) qr-code-styling react-qr-code QrCode (ours)
Parts / anatomy ✅ Root·Frame·Pattern·Overlay·Download ❌ imperative ❌ single comp ✅
Encoder uqr dep qr-code-generator dep qr.js dep own, zero-dep ($libs/qr)
Error correction L/M/Q/H ✅ ✅ ✅ ✅
Themeable colour (tokens) ❌ currentColor only ✅ free fg/bg props ✅ via tokens + color
Cell shapes (square/rounded/dots) ❌ ✅ ❌ ✅
Logo overlay ✅ ✅ partial ✅ + auto quiet-zone + auto-boost ECC
Download PNG/SVG ✅ ✅ manual ✅ DownloadTrigger = <Button>
role=img + label a11y partial ❌ ❌ ✅
Framework morfo/recipe rigor n/a n/a n/a ✅

Takeaway: ark has the best structure but is visually flat and pulls an encoder dependency; qr-code-styling is visually rich but imperative, dependency- heavy, no a11y. Ours keeps ark's clean anatomy + API, owns the encoder (the QR algorithm is the open ISO/IEC 18004 standard — no npm dep), and adds themeable colour, cell shapes, a scannable logo overlay and real a11y.

Encoder — $libs/qr (own, zero-dep)

encode(value, { errorCorrection, minVersion?, maxVersion? }) → { matrix: boolean[][], reserved: boolean[][], size, version, errorCorrection }. A from-scratch QR encoder (segment analysis → Reed-Solomon ECC over GF(256) → matrix layout → mask selection over all 8 masks by penalty), pure and zero-dependency, living in $libs alongside the other pure helpers. The algorithm follows the public QR standard; uqr/nayuki are correctness references only, never imported. Unit-tested against known vectors + structural invariants; the demo harness round-trips encode→decode through jsQR (versions 1–24, all ECC, all modes, all four cell shapes).

reserved[y][x] marks the function modules (finders, timing, alignment, format/version info) — the eidos layer keeps those square even when cellShape is rounded/dots, so the scanner's grid-lock pattern stays intact and every shape remains scannable. Only the data modules take the decorative shape.

Scannability (verified)

  • Function patterns stay square for all cell shapes (reserved mask) — what qr-code-styling does, and the reason rounded/dots still decode.
  • Logo auto-boosts ECC to H and clears a central ~24% region so the lost modules fall within the error-correction budget.
  • Fixed-tone default colours (dark-on-light) — a QR can't invert in dark mode and stay scannable, so the default fg/bg are theme-independent; theming is opt-in via color/background (you own the contrast).
  • Quiet zone is in modules, not pixels — margin measures the quiet zone in QR modules (spec minimum 4 — ISO/IEC 18004), the canonical unit: it scales with the symbol so the clear ring stays proportional at any rendered size, which is what guarantees scannability. There is deliberately no pixel margin prop. For fixed pixel spacing in a layout, pad the container in CSS using the QR's background colour — the symbol's quiet zone stays canonical in modules.
  • Export bakes resolved colours — a serialized SVG loses the document's CSS custom properties, so DownloadTrigger resolves getComputedStyle fills into the clone before writing PNG/SVG.
  • Logo in exports — SVG export is lossless (the logo is XML and travels with it). PNG export omits the logo: browsers do not rasterize <foreignObject> content when an SVG is drawn to a canvas via <img> (a Chromium limitation, not a taint — the QR itself rasterizes fine). The cleared centre region stays, but the overlay is dropped. Use SVG to keep the logo. (A future PNG path could composite a raster logo directly onto the canvas; deferred — the logo slot is an arbitrary snippet, not a URL.)

Anatomy (parts)

<QrCode value="https://…">          ← Frame  (svg, role="img", aria-label)
  └ Pattern                          ← the <path> matrix (decorative)
  └ Overlay                          ← centred logo slot (optional)
<QrCode.DownloadTrigger>             ← <Button> → PNG / SVG (optional)

morfo scope: ['eidos'] (+ optional sema for a commit-download tap cue). No soma — a QR is a pure display (like Avatar / Image): value → matrix in a $derived, rendered to SVG. Download is imperative via $adom.

API (root)

Prop Type Default
value string '' data to encode (bindable)
size ResponsiveProp<number | Size> 'md' rendered box size
errorCorrection 'L' | 'M' | 'Q' | 'H' 'M' redundancy (auto-boosted to H when a logo is present)
color AffirmativeColorRole | string currentColor/token module colour
background string token / transparent quiet-zone + module background
cellShape 'square' | 'rounded' | 'dots' 'square' module shape
margin number 4 quiet zone in modules, not pixels (spec min 4 — see Scannability)
logo Snippet — centred overlay; clears the centre + boosts ECC to H
alt string value accessible name for the Frame

DownloadTrigger props: format: 'png' \| 'svg' (default 'png'), filename (default 'qrcode') + all <Button> props (variant, size, color, …). It renders the framework <Button> and calls the root's colour-baking export via context.

Compound: <QrCode> + .DownloadTrigger. The logo is the logo snippet prop (not a subcomponent); the morfo's Overlay/Pattern parts are render internals.

v1 scope (approved)

square/rounded/dots cell shapes · themeable colour · logo Overlay with auto quiet-zone + auto-ECC-boost · download PNG + SVG · role=img + label.

Deferred to v2: gradient fills, per-corner (finder) styling — the marketing-grade flourishes of qr-code-styling.

Layers

  • $libs/qr — own encoder + tests.
  • morfo qr-code.ts — Frame / Pattern / Overlay / DownloadTrigger contract.
  • eidos qr-code/ — wrapper + recipe (--qr-code-* tokens) + SVG render from the matrix.
  • demo web/routes/uix/components/qr-code/ + nav entry.

Powered by TurnKey Linux.