Composition stays in your browser

The methodology page makes a short, exact claim: framing, captions, styling and any photos you work with during composition are processed by JavaScript on your own device, and nothing you type or place on the canvas is transmitted in order to render a preview or produce a download. This guide turns that sentence into mechanism: which steps run where, what a saved record does and does not contain, the one hosted exception, and how to confirm the claim yourself. Every figure below is computed at build time by the engines that run in the editor, on fictional inputs.

What “in your browser” means here

The site is static and has no server that could receive the working photos, and nothing you type or place on the canvas is transmitted in order to render a preview or produce a download. The QR renderer and the artistic engine each describe themselves in their own source as “pure and network-free”: they take your content and settings as values and return markup, and the renderer names its one impure surface — drawing onto a canvas the caller supplies. The verifier's combining rule, which decides from the per-raster outcomes whether the badge is earned, is pure as well; its rasterizing step is the browser-only part, which draws the render to a canvas and reads the pixels back for decoding. That is why the editor needs JavaScript: the constraint that makes it necessary is the one that keeps composition on your device.

What is processed on the device

Take a fictional project: a table card whose code opens https://example.com/our-album, framed in the floral template with the caption “Mia & Jonah — 2027”.

Encoding

The engine encodes the link exactly as typed into a standard QR symbol at error-correction level H. For this fictional link that is a version-4 symbol of 33 × 33 modules; with the quiet zone of 4 modules the renderer always adds on each side, the drawn grid is 41 × 41. Nothing is shortened, tracked or redirected: the destination is placed in the symbol exactly as entered. The error-correction guide explains why the level is fixed at H for every artistic style.

Frame art, caption and palette

The framed composite is assembled from that rendered code: frame art below an opaque panel, the code SVG nested verbatim on top, the caption beneath. For the fictional card the composite is 760 × 880 units with a 460-unit code panel, and the whole composed design is one piece of SVG markup 10,282 characters long — the string the preview displays, the SVG download writes, and, if you save, the “composed design” the methodology page says a saved record contains. The composition guide walks through the templates and palettes.

Photo weaving

The halftone engine takes an RGBA pixel buffer — what a browser produces when it draws an image onto a canvas and reads the pixels back — together with the encoded model, and returns SVG markup. The photo enters as pixels and leaves as paths; it is never attached to anything as a file. In the build-time example, a fictional 48 × 48-pixel grey gradient stands in for a photograph: that buffer is 9,216 bytes of pixel data, and weaving it into a code for the fictional short link https://example.com/mia (a version-3 symbol) produced 156,987 characters of markup in which each data cell keeps a pure code-coloured centre spanning 50% of its side. The engine's limit is enforced there too: photo-woven codes are decode-proven only up to version 4, so a longer fictional link (https://example.com/albums/2027/06/the-whole-weekend-in-photos, a version-7 symbol) is rejected before anything is drawn: “Photo-woven codes need short content — use a short link or pick another style. This content needs a version-7 code; photo weaving is decode-proven only up to version 4 (about 34 characters, fewer with emoji or accents).”

Verification happens on the device too

“Verified scannable” is not a server's opinion. The verifier rasterizes your render in the browser at 800, 1200, 1600 px, decodes each raster with a real QR decoder and compares the decoded bytes with the content you entered; the badge is earned only when at least 2 of those 3 rasters match exactly, and downloads stay disabled until it is. The verification guide covers the rule and each verdict.

Downloads are produced on the device

An SVG download writes the composed markup to a file. A PNG download rasterises the composed design and saves that bitmap. The print-size readout belongs to a narrower case. The methodology page states that “The shared QR core carries a print-size readout for a square PNG”, with fixed arithmetic — inches are pixels divided by 300 — and the features page says what that square covers: “The readout is defined for a square PNG, so for a bare code exported at a preset those figures describe the whole image, quiet zone included”. A bare code is square by construction; a framed or captioned composite is not — the fictional floral card is 760 × 880 units, taller than it is wide — so the square readout describes the bare code, not that composite; the composite's file is measured by its own pixel dimensions. The engine defines 3 export presets, and the readout for each square export follows.

PNG preset Readout for a square export at 300 DPI
512 px 1.71 in × 1.71 in (43.3 mm × 43.3 mm) at 300 DPI
1,024 px 3.41 in × 3.41 in (86.7 mm × 86.7 mm) at 300 DPI
2,048 px 6.83 in × 6.83 in (173.4 mm × 173.4 mm) at 300 DPI

Neither download transmits what you typed or placed on the canvas, and the file is, in the methodology page's words, “independent of all of this” — of a saved project, an account or the retention window.

What a saved project contains

Saving is the one step for a static keepsake that is meant to transmit, and the methodology page states what travels: “the saved record contains the project's settings and the composed design — the working photos themselves are not uploaded”. The settings are the editor state, a small, fully enumerable object; for the fictional table-card project the engine's mapping from state to record columns produces 6 fields — title, occasion, qr_type, payload, style, frame — and this is the whole of it:

{
  "title": "Table cards",
  "occasion": "Wedding",
  "qr_type": "link",
  "payload": {
    "type": "link",
    "value": "https://example.com/our-album"
  },
  "style": {
    "moduleStyle": "classic",
    "photoWoven": false
  },
  "frame": {
    "template": "floral",
    "palette": {
      "primary": "#15803d",
      "secondary": "#86efac",
      "accent": "#f472b6"
    },
    "caption": "Mia & Jonah — 2027"
  }
}

The store adds the composed design (the SVG markup above) and the owner's id when it writes the row; the features page lists what an account stores in the same terms — content, design settings and the composed artwork, plus your email and sign-in credentials. Note what the record has no field for: pixels. As far as the photo is concerned, a photo-woven project differs by a single boolean: serialising a fictional photo-woven state yields a 286-character string containing "photoWoven":true and no image data, and the engine's own note is the rule — photos are processed on-device only and never serialised, so a reopened photo-woven project shows its saved artwork and asks for the photo again before re-editing.

The studio page states the same rule for the signed-out case: if you start designing before creating an account, “your in-progress design survives the signup round trip and saves itself once you are in” — and the engine note above still holds there, since photos are never serialised. Parsing serialised state is total: not a project at all parses as null, as does a record stamped with version 2 rather than 1, so the editor starts fresh instead of wedging. Once saved, the record is subject to the retention rule the methodology page describes — an expiry timestamp set 30 days ahead at save time, enforced by the database's row-level security policy — which the retention guide walks through.

The one hosted exception: Live Keepsakes

Live Keepsakes are the part of the Studio that is deliberately not a downloadable file: the message is hosted in the database so a recipient's scan can open it, as the features page states. Two things stay in the browser even there. The photo a sender places on their own screen is never uploaded. And the anonymous read path returns only occasion, message and style through a parser written as an allowlist: handing it a fictional row with the fields id, user_id, title, occasion, message, style, expires_at yields an object with exactly occasion, message, style, because the code has no line that copies the sender id or the private label. The Live Keepsakes guide walks both screens' state machines.

How to check this in a network panel

If your browser has a developer panel that lists network requests, the check is:

  1. Open the editor with the panel showing, let the page finish loading, then clear the list — the page's own assets load at this point and are not what you are checking.
  2. Compose with fictional content: type a link, switch frames, recolour, add a caption, tick photo-woven and choose a photo, watching the preview and badge update.
  3. Read the list. You are checking for an absence: no request whose payload carries the text you typed, and none whose size matches the photo file you chose. Any request that does appear can be opened and inspected for your content.
  4. Press a download button: the file arrives without a request carrying your design.
  5. Press save — or, if you started designing before creating an account, let the design save itself once you are in, as the studio page describes. That is the step that should produce a request carrying settings and composed design, in a size you can compare with your photo's.

Common misreadings

  • “In your browser” describes composition, not a promise that nothing is ever stored. Saving stores settings and composed design by your choice; Live Keepsakes host the message by design.
  • A saved photo-woven project does not contain the photo. It holds the composed artwork and a flag; keep the original if you intend to re-edit.
  • Verification is about a destination's format, not its future. 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. The limits guide collects what is not modelled.
  • On-device verification is about the render, not the print. Printers, papers and inks vary; test a proof print before a large run.
  • Downloads do not depend on the saved record. A file on your device is independent of the account and the project row.

Frequently asked questions

Is my photo uploaded when I make a photo-woven code?

No. The photo becomes pixel data on your device and the engine turns it into SVG markup there; nothing on the canvas is transmitted to render a preview or produce a download. A saved project holds settings and composed design, with photo-woven as a true/false flag, and a reopened photo-woven project asks for the photo again.

Does saving a project send my design somewhere?

Yes — saving is the one deliberate transmission for a static keepsake: the record contains the project settings and the composed design, exactly as the methodology page states, and carries an expiry timestamp set 30 days ahead at save time. The downloaded file is independent of all of this.

Why does the editor need JavaScript?

Because composition runs on your device. The site is static: no server renders a preview or a download for you, so without JavaScript nothing can draw or verify the code.

Does the decode verification happen on a server?

No. Each render is rasterized in your browser at 800, 1200, 1600 px and decoded there with a real QR decoder; the "Verified scannable" badge requires at least 2 of those 3 rasters to decode to an exact byte match.

Is a Live Keepsake message also kept in my browser?

No — Live Keepsakes are the stated exception: the message is hosted in the database so a recipient can open it; any photo on the sender's own screen is never uploaded, and the anonymous read path returns only occasion, message and style through an allowlist parser.

How can I check this myself?

Open the editor in a desktop browser with its developer panel showing, let the page load, clear the panel, then compose — type content, change frames, add a photo. No request should appear carrying your text or an upload the size of your photo; pressing save — or, if you started designing before creating an account, the save that runs itself once you are in — is the step that should produce a request carrying settings and composed design.

A note on scope: every figure on this page was computed at build time by the engines that run in the editor, on fictional inputs. Composition and verification happen in your browser. See the methodology page for the full statement of what is processed on your device, how retention is enforced, and what the studio does not model, and Guides for the rest of the series.