How the studio composes a keepsake

A keepsake project in the Studio is one small record: an occasion, what the code opens, a frame, 3 colors, a caption and a module style. This guide walks through that record field by field: which choices change the QR symbol, which only decorate around it, and where the engine refuses an input rather than quietly accepting it. Every figure on this page is computed at build time by the same code that runs in the editor, on a fictional link and a fictional caption, so the numbers cannot drift from the product. The other guides go deeper on each rule.

A project is one record

The editor state is the single serializable description of a project: what the live editor reads and writes, what the stash holds across a signed-out visitor's signup, what a saved row's columns are built from, and what a reopened project is rebuilt into. Its fields are exactly these: title, occasion, payloadType, payloadValue, frameTemplate, palette, caption, moduleStyle, photoWoven. A fresh project starts as occasion Wedding, a link payload, the floral frame with that template's palette, classic modules and photo-woven mode off. Serialized for the stash, it carries version 1 and reads as:

{"version":1,"title":"","occasion":"Wedding","payloadType":"link","payloadValue":"","frameTemplate":"floral","palette":{"primary":"#15803d","secondary":"#86efac","accent":"#f472b6"},"caption":"","moduleStyle":"classic","photoWoven":false}

Two absences matter. There is no photo field: the photo in photo-woven mode is deliberately not part of the state — processed on-device only, never serialized. And the title is a workspace label — the editor's own hint says it never appears on the code. When a project is saved, the state maps onto these row columns: title, occasion, qr_type, payload, style, frame; the composed design and the owner reference are added by the saving step. The methodology page puts the same fact as a condition: “the saved record contains the project's settings and the composed design — the working photos themselves are not uploaded.” The composition guide shows how to confirm that in a browser's network tab.

Occasions, and the template each one suggests

The studio lists 6 occasions, stored verbatim as display strings. Each maps to a default frame template, but by the engine's own rule it is a suggestion only, applied when you have not chosen a template; every template stays available for every occasion. The occasion never reaches the symbol — it is a label on the project.

Occasion Suggested frame template
Wedding floral
Memorial classic
Anniversary heart
Graduation confetti
New arrival heart
Celebration confetti

What the code opens: a link or a text message

The payload type is link or text, and the payload value is the raw string exactly as typed. By the methodology page's condition, the destination is “placed in the symbol exactly as entered, with no shortening, tracking parameters, or redirection added.” This is the one field that determines the symbol. The fictional link https://example.com/ella-and-sam/album encodes at level H as a version-5 symbol with 37 modules a side; the encoder's default request for the same link comes back at level M, version 3, so the studio's choice costs 8 more modules per side. The studio always composes at H because every artistic style requires it; the error-correction guide covers what that buys and costs on longer destinations.

Frame choices and the opaque panel

The frame choice is one of 6 values: the 5 templates (heart, floral, ring, classic, confetti) or none, the bare code. One rule governs the composite: the rendered QR SVG is nested verbatim on an opaque panel drawn above the frame art, so decoration cannot touch a module by construction. For the fictional link in the floral frame, the composite is 760 by 880 units with a 460-unit panel at (150, 240) — the panel spans 61% of the composite's width, and the code inside it carries its own 4-module quiet zone, which the renderer always draws and cannot disable.

The caption is text drawn on the frame below the panel. Its limit is 80 characters, probed here rather than quoted: the editor state refuses to validate a longer caption, and the composite refuses to draw one, answering: “Captions are limited to 80 characters.” Choosing no frame keeps a palette on the record so a later template switch has colors to start from; the engine's fallback for that case is the heart template's palette.

Ella & Sam — the album
The heart frame with heart modules — a fictional destination, composed at build time

Palettes, measured as if they were module colors

Each template exposes 3 colors — primary, secondary, accent — with a default palette. Recoloring any of them changes only the frame art, the panel's border stroke and the caption around the code — never a module — so a new palette cannot change the symbol. The table shows why that separation is deliberate: each default color is handed to the renderer as if it were the module color on the default background, and the WCAG 2.x ratio the engine computes — not guesses — is reported.

Template primary as module colorsecondary as module coloraccent as module color
heart #be123c — 6.29:1 #fda4af — 1.89:1 (below threshold) #fecdd3 — 1.41:1 (below threshold)
floral #15803d — 5.02:1 #86efac — 1.40:1 (below threshold) #f472b6 — 2.65:1 (below threshold)
ring #a16207 — 4.92:1 #eab308 — 1.92:1 (below threshold) #fde68a — 1.25:1 (below threshold)
classic #1f2937 — 14.68:1 #9ca3af — 2.54:1 (below threshold) #be123c — 6.29:1
confetti #be123c — 6.29:1 #2563eb — 5.17:1 #f59e0b — 2.15:1 (below threshold)

8 of the 15 default colors fall below the engine's 4.5:1 warning threshold. The plain renderer only warns; the artistic engine rejects, so handing the weakest of them, ring accent #fde68a, to the heart-module renderer as a module color returns: “Artistic styles require at least 4.5:1 contrast (got 1.25:1) — decoration already spends decode margin.” The studio sidesteps this by construction: the code is drawn in each renderer's own default, dark on light — classic modules measure 21:1 on white, and the heart-module renderer's own default foreground measures 9.57:1 on white.

Module styles: classic squares or hearts

The module style is classic or hearts. The engine classifies every module as finder, alignment, timing or data. By its second rule, the finder patterns in three corners and the alignment patterns stay classic squares, because restyling alignment patterns breaks decoding outright (spike-proven); timing modules may be styled. In the fictional link's symbol there are 704 dark modules: 99 in the finder corners and 17 in alignment patterns stay classic squares, while 22 timing and 566 data modules — 588 in all — are drawn as hearts spanning 97% of their cell, so a scanner's sampling grid still reads each cell as decisively dark. The heart render for this symbol is 45 modules across, quiet zone included.

Photo-woven mode

Photo-woven mode follows the engine's fourth rule: each data cell is split into a ring of subcells that show the photo quantized to three tones, around a center 50% of the cell wide that stays the pure module color — the part a decoder treats as authoritative. Finder, alignment and timing cells and the quiet zone stay fully pure. Because denser symbols shrink those centers, the engine caps photo-woven codes at version 4 — about 34 ASCII characters. Run against a tiny synthetic swatch at build time, the short fictional message Ella & Sam encodes at version 2 and weaves at 33 modules across; the longer fictional link is refused with the engine's own message: “Photo-woven codes need short content — use a short link or pick another style. This content needs a version-5 code; photo weaving is decode-proven only up to version 4 (about 34 characters, fewer with emoji or accents).” The photo is never part of the saved state — a reopened photo-woven project shows its saved artwork and asks for the photo again before re-editing.

Corrupt input starts fresh, never wedges

Parsing the editor state is total: corrupt JSON, foreign shapes and unknown enum values all read as null, and the editor then starts fresh instead of wedging. Three probes run at build time confirm it — an occasion the studio does not list; text that is not JSON at all; a record written by a future version of the editor — and all 3 read as null, as does a state whose module style is a value the engine does not define. The same validator rebuilds a saved row, so an unreconstructable row is treated the same way.

How to read the editor, and the common misreadings

  • The suggested template is not a lock. Changing the occasion changes the suggestion only; it never overrides a chosen frame or alters the code.
  • The caption and title are outside the symbol. The caption is drawn on the frame; the title stays in your project list. Only the payload is encoded; neither the caption nor the title is in the symbol.
  • Recoloring is decoration. The 3 colors reach the frame art, the panel's border stroke and the caption around the code — never a module; a different module color would be a different style, subject to the contrast rule above.
  • A refusal is information. The engines return messages rather than clamping: a caption over 80 characters, a photo-woven payload above version 4, or a module color below 4.5:1 is named, not silently adjusted.
  • Composing is not verifying. Every artistic render is decoded back in your browser, and anything short of the rule blocks downloading it as a verified keepsake; the verification guide explains the verdicts, and the limits guide explains what no verdict can promise.

Frequently asked questions

Does choosing an occasion change the code itself?

No. The occasion is a label stored on the project and a suggestion for the frame template, applied only when you have not chosen one; every template stays available for every occasion. The symbol is encoded from the payload and the fixed level-H error correction; nothing else on the record reaches it.

Why does the studio compose at error correction level H?

Because every artistic style requires it: the artistic engine rejects a model that is not at level H, since decoration spends decode margin and only the ~30% recovery of EC-H leaves enough. The fictional link in this guide encodes as a version-5 symbol of 37 modules a side at H, against version 3 at the encoder's default level M.

Can recoloring the frame make the code harder to scan?

Not in a framed composite. The 3 palette colors reach the frame art, the panel's border stroke and the caption around the code — never a module: the frame art sits below an opaque panel whose border is stroked in the secondary color, and the rendered code is nested on that panel verbatim, so no palette color ever touches a module. Measured as module colors, 8 of the 15 default palette colors fall below the engine's 4.5:1 threshold. The code itself is drawn in each renderer's own default: classic modules measure 21:1 on white, and the heart-module renderer's own default foreground measures 9.57:1 on white.

What is the caption limit, and where does it apply?

80 characters, enforced twice: the editor state refuses to validate a longer caption, and the framed composite refuses to draw one, answering "Captions are limited to 80 characters." The caption is text on the frame below the panel — it is not part of what the symbol encodes.

Why do the corner squares stay square when I pick heart modules?

The engine classifies every module as finder, alignment, timing or data. By its second rule, the finder patterns in three corners and the alignment patterns stay classic squares, because restyling alignment patterns breaks decoding outright (spike-proven); timing modules may be styled. In the fictional link's symbol, 116 of the 704 dark modules stay classic squares and 588 are drawn as hearts covering 97% of their cell.

Why does photo-woven mode refuse a link that works everywhere else?

Photo weaving replaces each data cell with a three-tone sample of the photo around a pure center 50% of the cell wide — the part a decoder treats as authoritative. Denser symbols shrink it below decode viability, so the engine caps photo-woven codes at version 4 — about 34 ASCII characters. A short message encodes at version 2 and is accepted; the longer fictional link needs version 5 and is refused with the engine's own message.

Where this stops: composition and verification happen in your browser, and the studio verifies the format of what you encode, not the future of the destination it points to. The methodology page documents the encoding standard, the error-correction choice, the 30-day retention mechanism and what is deliberately not modeled.