Proposal QR Code
A code in the ring box, on the last page of a photo book, or taped inside a card: scan it, and your question appears. This tool wraps the code in heart frame art, redraws its modules as hearts, and then proves in your browser that the decoration still scans — before you download anything.
Keepsake print checklist
- Keep the white margin around the code — it is the quiet zone scanners need, not empty space to crop.
- Size for the moment: 2 × 2 cm of code is the floor for cards and tags; photo-woven codes reward 4 cm or more; distant reveals want one tenth of the scanning distance.
- Matte paper over gloss — glare is the most common keepsake scan failure.
- Scan a test print with a real phone before the moment that matters.
A worked example, rendered by the real engine
This artwork was generated at build time by the same engine behind the tool above — heart frame, heart modules, caption and all. It encodes:
https://example.com/will-you
Version 4 at 33×33 modules, error correction H. Point your camera at the screen — it scans.
What the proposal preset encodes
The tool above is the general keepsake generator opened on the proposal preset from the occasion registry. That preset fixes three things before you type anything: the payload type is a link, the starting style is the Heart frame, and heart-shaped modules are switched on inside the frame. The link goes into the code as you enter it, trimmed of surrounding spaces — the engine checks that it is a valid URL whose protocol is http or https — so what a scan returns is your URL, byte for byte. The worked example encodes a fictional address, which the encoder placed in a version 4 symbol of 33 × 33 modules at error correction H; with the mandatory 4-module quiet zone on every side, the printed code is 41 modules across.
A link is the preset's default because of what phones do with one. Apple's Camera and Google's ML Kit both recognise links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins — and no plain-text type. A link is in that list; a code containing bare text carries no scheme, so a phone has nothing to act on. If you would rather the question itself were inside the code, the generator's two message modes exist for exactly that (its third radio option, the inscription, is an offline note folded into the QR alphanumeric set and carries the same display caveat); the Message keepsakes and reveal links guide explains them, and the section below shows what the engine produces for one fictional question.
The heart frame, and the rules it inherits
A framed code is the one style here that does not modify the code at all. The rendered symbol
— quiet zone included — is placed verbatim on an opaque clean panel drawn above the frame art,
so by construction no heart, border or flourish can touch a module. In the worked example the
panel spans 61% of the artwork's width, and all 41 modules of symbol and margin
sit on it. The heart template is one of 5
recolourable vector frames; the preset starts it on #be123c, and changing that
palette changes only the art around the panel, never the code on it; the
Framed codes, explained guide walks through the panel
and every template. The caption under the panel is set from your words — the example's "Will you marry me?" is 18 characters — and it has two limits that fail differently. The
engine's frame refuses a caption longer than 200
characters and renders nothing: a fictional 231-character caption built
for this page is answered, in the engine's words, with Captions are limited to 200 characters.
The caption field
in the tool above takes 80 characters, well inside that limit, and on this preset
— whose payload is a link, so there is no message to print as the caption in its place — that field
is the only route to the caption; the refusal is a rule of the engine, not something the field can
reach. Within the limit a caption is wrapped by words onto at most 4
lines; whatever would need a further line is dropped and the last line ends in an ellipsis, so a
clipped caption never reads as the whole message. The same fictional text cut to
200 characters is accepted, and the frame sets it on 4 lines, the last ending in the ellipsis.
Inside the panel this preset turns on heart-shaped modules, and those obey the heart-module rules exactly as the bare hearts style does — the rules Heart-module codes, explained sets out in full. Each dark module is redrawn as a heart glyph spanning 0.97 of its cell: large enough that a scanner's sampling grid still reads the cell as decisively dark, small enough that neighbouring hearts read as separate shapes. The landmarks are exempt. Of the 1089 cells in the example symbol, 542 are dark; 116 of those belong to the three finder patterns and the single alignment pattern and are drawn as crisp squares, while the remaining 426 — timing and data cells — become hearts. A version 4 symbol places its alignment-pattern centres on rows and columns 6 and 26, minus the three corners the finders occupy. Our testing showed that restyling alignment patterns breaks decoding outright, which is why no style on this site will draw one as a heart.
Two further gates apply because the hearts spend decode margin. First, error correction: every
style that redraws modules — the hearts this preset turns on, and the photo halftone — encodes
at level H (roughly 30% recovery) without exception, and the heart renderer refuses a model
encoded at any lower level. Second, contrast: foreground and background must measure at least 4.5:1 in WCAG contrast, and the engine rejects weaker pairs rather than warning, because
scanners binarize the image and low contrast measurably hurts decoding. The preset's deep
rose, #881337 on white — the colour the worked example's hearts were drawn in, checked
against the example at build time — measures
9.57:1. Hand the same renderer a pale rose such as #fda4af for the hearts
and it answers, in its own words: Artistic styles require at least 4.5:1 contrast (got 1.89:1) — decoration already spends decode margin.
Hand it white hearts on a
#881337 background and the answer is: Artistic styles require dark modules on a light background — inverted codes are rejected.
Those two refusals are
computed on this page by the live engine, not quoted from a manual, so they cannot drift from what
the tool does.
Hiding the question as a message instead
Switching the preset's payload from a link to a message changes what the reader's phone can
do. Faced with bare text, an iPhone offers to copy or search it and Google Lens simply runs a
web search, so the message is the one thing the reader never sees; Samsung phones and
dedicated scanner apps do display it, but a keepsake cannot depend on which phone opens it. So
a message keepsake offers two honest modes. A reveal link encodes a normal URL
to the page at /m/ on this site, with the message carried in the URL's fragment
— the part after the #. Per RFC 3986 a fragment is stripped before a request is
made, so it never reaches our servers, a CDN, or any log; the message is decoded entirely on
the reader's device. An offline note writes the words into the code itself, needing
no connection ever, and accepts the display caveat above. In both modes, on a framed keepsake with
no caption of your own, the message is also printed under the code as the caption, so it can be
read by eye regardless. The generator's third option, the inscription, is an
offline note folded into the QR alphanumeric set — uppercase, like engraving — and it accepts
the same caveat; the guide's
offline-note section
covers it.
Here is the format on a fictional question, computed at build time exactly as the generator
builds it. The message Marry me? Turn around. - J
is 26 of the
300 characters a reveal link accepts. Its fragment is the flag
A — meaning UTF-8 bytes; B marks the raw-deflate
form in the published format — then 42 characters of unpadded uppercase base32, JVQXE4TZEBWWKPZAKR2XE3RAMFZG65LOMQXCALJAJI, then one base32 checksum character,
T, computed over the payload so a truncated or case-mangled link is
reported as altered instead of rendering as gibberish. The full link the code would carry is:
https://KEEPSAKECODES.NET/M/#AJVQXE4TZEBWWKPZAKR2XE3RAMFZG65LOMQXCALJAJIT
Base32 rather than base64 because some scanners change the case of what they read, and base32 survives that; it is also a subset of the QR alphanumeric character set, which encodes at 5.5 bits per character instead of 8. The cost of the detour is symbol size, and the engine makes it visible: the preset's example link encodes at version 4; the fictional question above encodes at version 8 as a reveal link (49 × 49 modules) and at version 4 as an offline note (33 × 33 modules). A larger version means smaller cells at any given print size, which is why the print section below gives a separate floor for the reveal-link form. Every message keepsake can additionally be downloaded as a self-contained HTML file that decodes this format with no network and no website at all — the reveal-links guide covers that file and the rest of the format.
What "Verified scannable" proves — and what it cannot
Rules make failure unlikely; verification makes it visible. After each render, your browser rasterizes the finished artwork — frame, hearts, caption and all — and runs a real QR decoder (jsQR) on the pixels at 3 raster sizes: 800 px, 1200 px, 1600 px. Each decode is compared byte for byte with the content you asked for — on this preset, your URL. The badge is earned when at least 2 of the 3 rasters match, because a single fixed raster can false-negative through sampling resonance: we measured a render that fails at exactly one size and decodes cleanly at the other 2, and one miss must not flip the verdict on its own. Anything short of that shows a clear warning and keeps the downloads locked, so an unverified render cannot leave the page as a finished keepsake. The Decode verification guide sets out the whole loop, including the order in which verdicts are ranked.
The same loop runs in the engine's test suite on every style — at several raster sizes, rotated, and after lossy JPEG re-compression — and the suite decodes every occasion example, including the one at the top of this page, so a preset that stopped scanning could not ship. What the check cannot see is the physical object: your printer, your paper, the light in the room, or the phone that will do the scanning. On-screen verification proves the artwork decodes cleanly at screen resolution; a test print, scanned with a real phone before the moment that matters, proves the rest.
Before the moment: a test print and a link you control
- Print a test first. Scan it with your phone — and, ideally, a friend's phone — before the real print. On-screen verification proves the artwork decodes; a test print proves your printer did it justice. If a verified code will not scan in print, that is exactly the report we want: see the contact page, and confirmed issues are fixed in the engine and locked in with a new test.
- Link to something you control. The URL is encoded directly into the image — there is no shortener, no redirect through our servers, and nothing that can lapse — so the printed code cannot be re-pointed later. A page on your own domain, or a shared album you manage, lets you refresh what the scan opens for anniversaries without changing the printed code.
- Nothing leaves your browser. Encoding, the heart render, the frame composite
and the decode verification all run on your device; the only thing this site ever receives from
a reveal link is a request for the page at
/m/, with the fragment already stripped.
Print sizing for hiding places
The engine's print floor is 0.5 mm per module, quiet zone included — its working minimum module size. For the worked example that is 41 modules across, so the engine says: print at least 20.5 mm (0.81 in) wide. The methodology's working guidance is at least 2 × 2 cm of code for arm's-length scanning. The two are independent minimums, and the larger one governs. For this symbol the engine's floor is the larger of the two, so 20.5 mm governs. A reveal-link version of the question is a bigger symbol — 57 modules across with its quiet zone — and its floor is 28.5 mm (1.12 in), so a message keepsake needs more room than a link keepsake for the same reliability. Both stay within the 65-module width past which a code stops fitting the tags and cards these keepsakes go on. The Printing and scanning a keepsake guide sets out the floor, the download sizes and the test print in full.
- The floor is for the code, not the artwork. It measures the symbol plus its quiet zone, which sits inside the panel: the panel spans 61% of the example artwork's width and keeps a margin of its own inside that, so the code on it — read back from the composite — spans 57%. Size the code to the floor, not the panel: a panel printed 20.5 mm wide would leave the code narrower than that. The heart frame around the panel adds to the printed size of the keepsake and contributes nothing to scannability, so the floor is a measurement of the code on the panel, not of the panel or the whole artwork.
- Never trim the white margin. The 4-module quiet zone is part of the symbol. The frame cannot cover it, because the art is drawn below the panel, but scissors can — cropping it to tighten the design is the classic proposal-eve mistake.
- Scan the test print where the code will be read. The verification badge is a statement about pixels; the print is a statement about ink, light and the phone in hand.
Common misreadings
- Expecting bare text to display. A code containing bare text carries no scheme, so a phone has nothing to act on; an iPhone offers to copy or search it and Google Lens runs a web search. The reveal link exists so that the code carries a link — one of the types those scanners recognise — with the message in its fragment.
- Choosing hearts for colour rather than contrast. The gate is 4.5:1 and it refuses, not warns — #fda4af on white does not render, #881337 on white at 9.57:1 does. Spend colour on the frame, which has no contrast gate because it never touches the code.
- Expecting the corner squares to be hearts. They cannot be. Finder and alignment patterns are drawn as classic squares in every style here; in the example that is 116 cells kept square so the other 426 can be hearts.
- Treating the badge as a print guarantee. It proves the artwork decodes at 800 px, 1200 px, 1600 px on screen, 2 of 3 agreeing. Paper, printer and phone are outside it; the test print is the second half of the check.
- Cropping the quiet zone. 4 modules of margin on every side are part of the symbol the decoder looks for, and the engine always draws them. They are inside the panel, so trimming the frame art is harmless — trimming into the panel is not.
For the rules behind every style, see the methodology; for the message format in full, the Message keepsakes and reveal links guide; and for the rest, all guides.
Proposal code FAQ
Will a decorated heart code really scan?
Yes — and you do not have to take our word for it. After every render, your browser rasterizes the artwork at 3 sizes and runs a real QR decoder on each, comparing the decoded bytes to your exact content. The badge needs at least 2 of those decodes to match, and downloads stay locked until it is earned, so the file you print is one that already decoded correctly.
What should the code open?
Anything with a link: a page you made, a shared photo album, a video, or the song that matters. You can also hide a message instead — a reveal link encodes a normal URL to a page on this site with the message carried in the URL’s fragment, or an offline note keeps the words inside the code so it needs no connection at all. Either way, on a framed keepsake with no caption of your own, the message is printed under the code as the caption too. Point links at pages you control so you can update the content later without reprinting.
Will the code stop working after the proposal?
No. The content is encoded directly into the image — there is no shortener, no redirect through our servers, and no subscription. The code in your ring box will still scan at your silver anniversary.
Why do the three corner squares stay plain?
They are the finder patterns a scanner locks onto, and the smaller inner squares are alignment patterns. Restyling those breaks decoding outright — our testing proved it — so every KeepsakeCodes style keeps them classic and decorates everything else. In the worked example that is 116 dark landmark cells kept square and 426 redrawn as hearts.
Is my proposal plan uploaded anywhere?
No. Encoding, rendering, and the scannability verification all run in your browser. Nothing you type is transmitted, logged, or stored — the surprise stays yours.
Can I change the heart colour to match the ring box?
Within a measured limit. Heart modules must measure at least 4.5:1 WCAG contrast against their background, and the engine rejects a weaker pair rather than warning, because scanners binarize the image and low contrast measurably hurts decoding. The preset’s deep rose, #881337 on white, measures 9.57:1; a pale rose such as #fda4af is refused outright, and light hearts on a dark background are refused too. The frame art has no such limit, because it never touches the code.
How small can the printed code be?
The engine’s floor is 0.5 mm per module, quiet zone included, which for the worked example’s 41-module width means at least 20.5 mm (0.81 in) across. The methodology’s working guidance is at least 2 × 2 cm of code for arm’s-length scanning — take whichever is larger, keep the quiet zone uncropped, and scan a test print with a real phone. The frame around the code adds to the print size and does not count toward it.
Why start on the heart frame instead of bare heart modules?
Because a frame is the one style that leaves the code unmodified: the symbol sits, quiet zone included, on an opaque clean panel drawn above the frame art, so decoration cannot touch a module. The hearts inside the panel still follow the heart-module rules — each spans 0.97 of its cell, the finder and alignment patterns stay crisp squares, and the contrast gate applies — and the caption under the panel puts your words in ink — the caption field above takes up to 80 characters, inside the frame's own limit of 200 — so the card still says what it is for even if a scan fails.
Different occasion? The wedding code follows the yes; a treasure hunt can lead to the ring; the valentine code handles every February in between; and the photo code weaves a picture of the two of you into the code itself.