The Studio

Design your keepsake below — everything happens in your browser, and every export is checked by actually decoding the artwork first. Signed in, you can save a project and reopen it from My projects for 30 days; downloads are yours forever. For a reveal moment that plays out live on two screens at once, try Live Keepsakes. New to the editor? The guide How the studio composes a keepsake walks through every control, and the notes under the editor explain how to read its verdicts.

Only for your project list — it never appears on the code.

Link details

The link is encoded directly — no shortener, no tracking, and it never expires.

Colors only touch the frame art — the code itself stays black on its white panel, so recoloring can never break scanning.

Fill in the content — your keepsake appears and is verified as you type.

Codes render on light backgrounds for reliable scanning.

What the code contains
 

Exports and saves unlock only after this exact render is decoded back to your content — the decode-verify promise. Everything here is free. Saving uses a free account so your project follows you to any device for 30 days.

How the editor works

The form above is bound to a single description of a project — the editor state. Every change re-reads the form into that state, renders the artwork from it, and decodes the render before any export is enabled. Nothing in that loop is a guess: the rules below are the engine's own rules, and every figure on this page was computed at build time by the same code the editor runs, on fictional inputs. The guide How the studio composes a keepsake walks the controls one by one; this page explains what the editor does with them, where it stops, and how to read what it says back.

One state, read from the form

The state holds a title, an occasion, the payload type and the raw payload text exactly as typed, a frame choice, a 3-colour palette, a caption, a module style, and a photo-woven flag. A fresh project opens as a Wedding occasion with the floral frame, a link payload and classic modules, carrying that frame's suggested palette (#15803d, #86efac, #f472b6). The same shape is what a saved project stores and what a reopened project is rebuilt from, under state version 1. Parsing it is total: corrupt JSON, a foreign shape, an unknown enum value or a future version all read as null, and the editor then simply starts fresh instead of wedging — the fictional string {"version": "not a saved project" reads as null at build time, while a serialized fresh state parses straight back. The photo in photo-woven mode is deliberately not part of the state: photos are processed on-device only and never serialized.

Occasions, suggested templates and palettes

The occasion is a display string stored verbatim. The engine's table pairs each occasion with a suggested template (below); in the editor the frame is yours to pick, and every template stays available for every occasion. Each template carries a suggested palette of 3 hex colours — the engine's paletteForTemplate answers with it for that template, and the table below is that answer for each occasion's suggested template. The colours are yours to change.

Occasion Suggested template Default palette (primary, secondary, accent)
Wedding Floral frame #15803d, #86efac, #f472b6
Memorial Classic frame #1f2937, #9ca3af, #be123c
Anniversary Heart frame #be123c, #fda4af, #fecdd3
Graduation Confetti frame #be123c, #2563eb, #f59e0b
New arrival Heart frame #be123c, #fda4af, #fecdd3
Celebration Confetti frame #be123c, #2563eb, #f59e0b

There are 6 frame choices: the 5 templates plus “no frame”, which composes the bare code without frame art. The composite checks only that each of the 3 colours is a valid hex colour. No contrast rule applies to frame colours, because they never reach a module: the rendered code is nested verbatim inside the composite on an opaque panel drawn above the frame art, so decoration cannot touch the code by construction. For the floral frame around the fictional short link used throughout these notes, the composite is 760 by 880 units, with an opaque panel 460 units on a side; the caption, when present, is drawn under the panel in the primary colour. Captions are limited by the engine: asking it to accept progressively longer captions finds the limit at 80 characters, and one character more is refused with “Captions are limited to 80 characters.” The editor state applies the same limit when a saved project is read back.

Ella & Sam — June 2027
Floral frame, classic modules — a fictional destination, composed at build time

What the code opens, and how large the symbol gets

The code opens either a link or a hidden message shown as text when scanned. Whichever you choose is placed in the symbol exactly as entered, with no shortening, tracking parameters, or redirection added. Every studio style encodes at error-correction level H — the artistic engine's first rule, because decoration spends decode margin and only the ~30% recovery of EC-H leaves enough. The honest trade-off is density. The fictional link https://example.com/our-story encodes at version 4, a 33×33 module symbol that renders as 41×41 modules once the mandatory quiet zone of 4 modules on every side is included. The longer fictional link https://example.com/albums/2027/06/ella-and-sam/guest-uploads?event=reception&view=grid&sort=newest needs version 10 and 57×57 modules: more content at the same correction level means smaller modules at any given print size, which is exactly why very long destinations plus high correction can produce codes that need to be printed larger.

Capacity is counted in encoded bytes: plain ASCII costs one byte per character, emoji or accented characters several. The fictional message Ten years ago today, you said yes… is 34 characters but 36 bytes, because its ellipsis is a multi-byte character, and it encodes at version 5. Empty content is refused with “Enter the content to encode.” and content past the capacity of the largest symbol is refused with “This content is too long for a QR code. Shorten it or lower the error correction level.”

The PNG size menu sets the pixel edge of the download, and the engine reports what that edge means on paper at 300 DPI: 512 px is 1.71 in × 1.71 in (43.3 mm × 43.3 mm) at 300 DPI; 1024 px is 3.41 in × 3.41 in (86.7 mm × 86.7 mm) at 300 DPI; 2048 px is 6.83 in × 6.83 in (173.4 mm × 173.4 mm) at 300 DPI. The SVG download is not sizeless: the renderer writes its own width and height into the file, with a matching viewBox — for the fictional short link as rendered for these notes that is 328 px square for the bare code and 760 by 880 for its framed composite. The print-size readout is computed for a PNG pixel edge only, and it is arithmetic about the file, not a promise about a print: printers, papers, and inks vary, and the methodology's advice stands — test a proof print before a large run.

Module styles: classic squares and hearts

The engine classifies every module of a symbol into one of 4 zones (finder, alignment, timing, data) using the same alignment-pattern positions the encoder used to draw it, so the classifier can never disagree with the symbol. Finder and alignment patterns stay classic squares in every style — the engine's second rule, because restyling alignment patterns breaks decoding outright; timing modules may be styled. With the hearts style each remaining dark module is drawn as a heart spanning 97% of its cell, so a scanner's sampling grid still reads the cell as decisively dark. On the fictional short link, a version-4 symbol with alignment centres at modules 6 and 26, that means 536 dark modules of which 116 stay square and 420 become hearts (18 of those are timing modules).

Contrast is enforced, not merely warned about, for every artistic style: the foreground and background must reach at least 4.5:1 by the WCAG 2.x formula and the code must not be inverted. The classic render on its panel measures 21.00:1; the heart render's default deep-rose foreground measures 9.57:1. A pale fictional foreground is refused with “Artistic styles require at least 4.5:1 contrast (got 1.48:1) — decoration already spends decode margin.” and a light-on-dark pairing with “Artistic styles require dark modules on a light background — inverted codes are rejected.” These are the engine's messages, not paraphrases.

Photo-woven codes

Photo weaving shades a photo into the data cells of the code. Each data cell is split into a small grid of subcells: the outer ring shows the photo quantized to 3 tones at 2 luminance thresholds — dark below 85, light above 175, mid between — while a pure, module-coloured centre square spanning 50% of the cell side is drawn last and is what the decoder treats as authoritative. Finder, alignment and timing cells and the quiet zone stay fully pure, and no logo may be stacked on a photo-woven code — the photo already spends the decode margin.

Density has a hard cap here. Photo weaving is decode-proven only up to version 4, about 34 characters of plain text and fewer with emoji or accents, because denser symbols shrink the authoritative centres below decode viability. The fictional short link, at version 4, is accepted — rendered against a one-pixel stand-in photo at build time it produces a 41×41 module artwork. The long link is refused with “Photo-woven codes need short content — use a short link or pick another style. This content needs a version-10 code; photo weaving is decode-proven only up to version 4 (about 34 characters, fewer with emoji or accents).” The photo itself is processed by JavaScript on your own device and never serialized: a reopened photo-woven project shows its saved artwork and asks for the photo again before re-editing.

Reading the verification verdict

Every render is rasterized at 3 sizes — 800, 1200, 1600 px — and each raster is decoded in your browser and compared byte for byte against what you entered. A single fixed raster can false-negative through sampling resonance: a render that fails at one size can decode cleanly at the sizes either side of it. The badge is therefore earned when at least 2 of the 3 rasters match, and the verdict reports which ones did. The verdicts below were produced at build time by the same combining rule, from a real decode of the fictional short-link symbol:

  • Every raster decodes: “Verified scannable at 800, 1200, 1600 px (3 of 3 rasters) — decoded back to your exact content.”
  • Exactly the minimum decodes: “Verified scannable at 800, 1200 px (2 of 3 rasters) — decoded back to your exact content.”
  • Too few decode: “Cannot verify: this render decoded at only 1 of 3 raster sizes (at least 2 must match). Do not print it — adjust the style (larger size, stronger contrast, shorter content, or a calmer photo) until verification passes.”
  • One raster decodes to different content: “Cannot verify: the render decoded to DIFFERENT content than you entered. Do not print it — this render is not safe to use.”

The order matters. A mismatch anywhere is reported ahead of undecodable rasters, which are reported ahead of rasterization errors, because a render decoding to different content is never safe. Downloads and saves follow the verdict: they unlock on a verified status and stay locked on anything else. What the verdict cannot promise is a print. It says this exact artwork, at these raster sizes, decoded in this browser to your exact content; it does not model paper, ink, glass or lighting — which is why the methodology says to test a proof print.

What saving stores, and how to read the expiry

The preview above, the files you download and the verdict you read are all produced from the editor state by the engine running in this page; nothing is transmitted to render or export them, and a photo you weave in is read into pixels here and never serialized. Saving is the one step that writes anywhere, and the methodology states exactly what it writes: “the saved record contains the project's settings and the composed design — the working photos themselves are not uploaded.” In the editor state those settings are the columns title, occasion, qr_type, payload, style, frame; the store adds the composed artwork and the owner's account reference. Signed out, the editor does everything except save, and if you start designing before creating an account, your in-progress design survives the signup round trip and saves itself once you are in. The guide Composition stays in your browser covers the mechanism.

A saved project is kept for 30 days, and that figure is enforced where the row lives, not on this screen. As the methodology describes it, the save writes an expiry timestamp 30 days ahead, and the database's row-level security policy — the same policy that grants you access to your own projects — requires a row to be unexpired, so an expired project is never returned to any client, and a background purge then removes it. Two things follow for the screens on this site. The remaining-time label on My projects is reading the row's own expiry timestamp, and because the access policy itself requires an unexpired row, no client can show an expired project by ignoring the date — it never receives the row. And nothing about expiry reaches a downloaded file: the PNG or SVG on your device encodes its destination directly and is unaffected by any row disappearing. The full mechanism is in How the 30-day retention works.

Where the studio stops

Three things the editor above cannot tell you, each stated as the methodology states it and expanded in What the studio does not model.

  • Destination longevity. The verdict under the preview is about the symbol: it says the render decoded to the link you typed. Whether the page at the other end will still exist is outside the editor entirely — the studio verifies the format of what you encode, not the future of the service it points to. For the longest-lived keepsakes, point codes at destinations you control.
  • Print-shop colour fidelity. The contrast rule above measures two hex colours, and the print-size readout divides pixels by 300. Neither knows a printer: printers, papers, and inks vary, so test a proof print before a large run.
  • Scan counting or analytics. A downloaded code is a static symbol and cannot report scans, and the editor adds nothing to the link that could — the hint under the link field means what it says: no shortener, no tracking. If you need scan counts, that is a different product.

Common misreadings

  • “Verified” means it will scan from any print. It means this exact artwork decoded at 2 or more of 3 raster sizes in your browser. Printing is outside the verdict; proof it.
  • A bolder caption or palette makes the code denser. Symbol density is set by the content and the fixed correction level only; the caption and colours live in the frame, outside the panel.
  • The 30 days apply to the download or the link. They apply to the saved project row. The downloaded file is independent, and the link is encoded directly — no shortener, no tracking, and it never expires.
  • The photo is stored with the project. The composed design is stored; the working photo is not, which is why a reopened photo-woven project asks for it again.
  • One failed raster means a bad code. One miss is what the 2-of-3 rule exists to absorb. Fewer than 2 matches, or any mismatch, is what blocks the export.

Frequently asked questions

Why are the download and save buttons disabled?

They stay disabled until the render in the preview has been verified: the artwork is rasterized at 800, 1200, 1600 px and decoded in your browser, and at least 2 of those 3 rasters must decode to an exact byte match against what you entered. Until that happens there is nothing the studio is willing to call a keepsake.

How do I read the verification message?

A verified verdict lists the raster sizes that decoded, for example "Verified scannable at 800, 1200, 1600 px (3 of 3 rasters) — decoded back to your exact content." A cannot-verify verdict names the reason: too few rasters decoded, the render decoded to different content, or the artwork could not be rasterized. A mismatch is always reported ahead of the other failures because a render that decodes to the wrong content is never safe to print.

Does recoloring the frame change how the code scans?

No. The frame colors are checked only for being hex colors, and the rendered code is nested verbatim on an opaque panel drawn above the frame art, so decoration cannot touch a module by construction. The frame palette never changes the code's contrast: the classic render measures 21.00:1 and the heart render 9.57:1 whatever the frame colours.

Why does the photo-woven style reject my link?

Photo weaving is decode-proven only up to QR version 4, which fits about 34 plain characters and fewer with emoji or accents. Longer content needs a denser symbol whose pure cell centers shrink below what a decoder can rely on, so the engine refuses rather than producing an unreliable code. The short fictional link on this page encodes at version 4 and is accepted; the long one needs version 10 and is rejected.

What exactly is stored when I click "Save to my studio"?

The saved record contains the project's settings and the composed design — the working photos themselves are not uploaded. In the editor state those settings are title, occasion, qr_type, payload, style, frame, and the store adds the composed artwork and the owner's account reference. A reopened photo-woven project shows its saved artwork and asks for the photo again before re-editing.

What happens to a saved project after 30 days?

Saved projects carry an expiry timestamp set 30 days ahead at save time, and the database's row-level security policy makes expired rows invisible to every client; a background purge then permanently removes expired rows. Anything you downloaded is independent of this — the file on your device keeps encoding its content.

Can the studio tell me whether my link still works, or how often it is scanned?

No. The studio verifies the format of what you encode, not the future of the service it points to, and static codes cannot report scans — no tracking is added to your destination. For the longest-lived keepsakes, point codes at destinations you control.

Do I need an account to use the editor?

No. Signed out, the editor does everything except save. If you start designing before creating an account, your in-progress design survives the signup round trip and saves itself once you are in.

Composition and verification happen in your browser. For the control-by-control walk-through, read How the studio composes a keepsake; the rest of the series is at Guides, and the rules themselves are documented on the methodology page.