Valentine QR Code
The Valentine preset starts on the heart-module style and carries a hidden message rather than a link: every dark module outside the scanner's landmarks is redrawn as a heart glyph, and the words ride either inside the code or in a reveal link. This page is that style's measured rules made legible — what the preset encodes, why the hearts stay decodable, how the length of a note sets the size of its hearts, what the verification badge proves, and how to print one. Every number below was computed by the rendering engine when the page was built, and your browser decodes the finished artwork back to your exact words before you can download it.
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
Rendered at build time by the same heart-module engine as the tool above. Point a camera at it — offline is fine — and it reads:
Every love story is beautiful, but ours is my favorite. Happy Valentine’s Day, A.
Version 8 at 49×49 modules, error correction H, hearts at 97% cell coverage.
What the Valentine preset encodes
Read the guide first: Heart-module codes, explained covers the style itself — the coverage constant, the contrast gate and what a heart code cannot carry. This page applies those rules to the Valentine preset; all of the site's guides are at /guides/.
In the occasion registry the Valentine preset starts on the Heart modules style with a hidden-message
payload (content type text), and its default heart colour is #9f1239. Nothing is locked: the style, the payload type and the colour all stay editable in the
generator above. But the preset's choice is the reason this page exists, because a message in
a heart code is governed by rules that a framed link code never has to meet.
The worked example above encodes a fictional note of 81 characters, written for this page and belonging to no one. At error-correction level H it fits a version 8 symbol: 49×49 modules, 2401 cells in all, of which 1263 are dark. Of those, 201 sit inside the three finder patterns or one of the 6 alignment patterns (whose centres lie on the module coordinates 6, 24, 42, in both axes) and are drawn as classic squares; the other 1062 are hearts, 28 of them on the two timing tracks. The guide counts that census zone by zone, so it is not repeated here. What this page adds is how large each of those hearts comes out on paper — which depends on how long the note is.
None of those figures is typed into this page. They are read from the same
renderOccasionExample call that draws the artwork, so if the engine changed, the prose
would change with it or the build would fail — the methodology's "worked examples can't drift" rule
applied to the words as well as the picture.
The measured rules that apply to a heart code
Three of the heart style's rules — maximum error correction wherever a module is redrawn, with hearts holding the line at H; landmarks never decorated; hearts spanning 0.97 of their cell — are the subject of the heart-module guide, measured there against its own worked example, and this page leans on them without restating them. The one rule worked through in full here is the contrast gate, because the heart colour is a setting the Valentine preset leaves editable, and changing it is what brings the gate into play.
Foreground and background must measure at least 4.5:1. The gate is measured, not judged: the engine computes the WCAG 2.x ratio on the actual colours and, below 4.5:1, returns an error rather than a warning, so nothing is rendered, nothing can be verified and nothing can be downloaded. The methodology's reason is that scanners binarise the image and low contrast measurably hurts decoding — and a heart code has already spent decode margin on its hearts. What the formula weighs is relative luminance, so the deciding question for a valentine is not red or pink but how deep the shade is. Four pairs chosen for this page, run through the heart renderer against the worked example's own symbol when the page was built:
-
The preset's own
#9f1239on white measures 8.02:1 and is accepted. -
A pale pink,
#f9a8d4, on white measures 1.81:1 and is rejected. The renderer's exact words: "Artistic styles require at least 4.5:1 contrast (got 1.81:1) — decoration already spends decode margin." -
Rose
#be123chearts on a blush#fce7f3background measure 5.35:1 and are accepted: a tinted background is judged together with the hearts, as a pair. -
White hearts on a rose
#be123cbackground measure 6.29:1 — above the threshold — and are rejected all the same, because the engine also refuses inverted codes: dark modules on a light background only.
How the length of the note sets the size of the hearts
A QR symbol grows in fixed steps called versions. The hearts do not shrink to make room for a longer note; the grid gains cells, and at any given print size each cell, and therefore each heart, is smaller. The encoder picks the lowest version that holds the message at level H, so the trade is direct: more characters, more cells, smaller hearts. The engine encoded 4 fictional notes, all at level H: a one-line note and a paragraph written for this page, the preset's own placeholder, and the worked example above. The last column holds each symbol to one fixed print width — the 1024 px PNG preset, the size the generator above selects by default, printed unscaled at 300 DPI, 86.7 mm across with its quiet zone — and gives the width of a single heart at that size:
| Note | Characters | Version | Modules (with quiet zone) | Minimum print width | Heart width at 86.7 mm |
|---|---|---|---|---|---|
| A one-line note | 19 | 3 | 29×29 (37 across) | 18.5 mm | 2.27 mm |
| The generator’s placeholder | 55 | 6 | 41×41 (49 across) | 24.5 mm | 1.72 mm |
| The worked example above | 81 | 8 | 49×49 (57 across) | 28.5 mm | 1.48 mm |
| A paragraph | 213 | 15 | 77×77 (85 across) | 42.5 mm — flagged oversized | 0.99 mm |
Read down the version column and the step is regular: between the first row and the last, each version adds 4 modules to the side. That figure is not typed into this page — it is derived from the ladder when the page is built, and every row is checked against it, so the table and the sentence cannot disagree. Read down the last column for what the step costs at a fixed print width: the one-line note's hearts are 2.27 mm wide and the paragraph's are 0.99 mm, on cells of 1.02 mm — at or above the engine's working floor of 0.5 mm per module.
The last row also shows the engine's comfort limit at work. Its print-size helper flags any symbol wider than 65 modules, quiet zone included, as oversized for the objects these codes go on, and the paragraph-length note comes out at 85 modules across — flagged. That is a limit on what prints usefully on a card or tag, not on what can be encoded. The reveal link adds a second, separate limit: a reveal message is at most 300 characters before encoding. Accents and emoji are carried as UTF-8 and cost several bytes each, so a note containing them reaches each version step sooner than its character count suggests.
What a phone does with the message
The methodology's finding on what a phone does with bare text is restated here. A QR code containing bare text carries no scheme, so a phone has nothing to act on. 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. 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.
The generator therefore offers the Valentine preset two modes: a reveal link —
a normal URL to the page at
/m/ on this site, with the message in the URL's fragment, which per RFC 3986
is stripped before a request is made and so never reaches our servers, a CDN or any log — and an
offline note, which writes the words straight into the code, needs no
connection ever, and accepts the display caveat above. In either mode, on a framed keepsake
with no caption of your own, the message is printed under the code as the caption — the
frame's caption area holds up to 200 characters on at most 4 lines
— so it can be read by eye regardless. Both qualifiers matter here. The Valentine preset starts
on the bare Heart modules style, which draws the symbol and its quiet zone and nothing else, so on
it the words live in the code alone and the caveat stands unmitigated unless the style is switched
to a frame — the Heart frame with heart modules inside it, say — or the words are printed
separately. The
message-keepsakes guide works the two
modes through in full; what follows is the Valentine preset's own numbers.
The fragment format is published so the codes stay readable by anyone, with or without this
site: #, then one flag character (A for UTF-8 bytes,
B for raw-deflate compressed bytes), then the payload in unpadded uppercase
base32, then one base32 checksum character over the payload. Computed for the fictional one-line
note "Yours, always. — J.", without a compressor:
https://KEEPSAKECODES.NET/M/#ALFXXK4TTFQQGC3DXMF4XGLRA4KAJIICKFYU
That is 65 characters: the scheme, host and path, the #, then a
fragment of 36 characters — the flag A, a base32
body of 34 characters and the checksum
U. Base32 is used rather than base64 because some scanners change
the case of what they read and base32 survives that; its alphabet is also a subset of the QR
alphanumeric character set, which encodes at 5.5 bits per character instead of 8. When a
compressor is available the engine computes both encodings and keeps the shorter, so a long
note may carry the flag B instead.
The reveal link costs density, and the engine can say exactly how much. Encoded at level H, the offline note "Yours, always. — J." is a version 3 symbol of 29×29 modules; its reveal link is version 8 at 49×49. For the worked example above, the offline note is version 8 and the reveal link would be version 13 at 69×69. Choosing the reveal link hands the phone a link instead of bare text, at the price of smaller hearts. 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.
What verification proves — and what it cannot
Rules make failure unlikely; verification makes it visible. After each render, your browser rasterises the finished heart artwork and runs a real QR decoder, jsQR, on the pixels — at 3 raster sizes, 800, 1200, 1600 px, not one. A single fixed raster can false-negative through sampling resonance: a render can fail at exactly one size and decode cleanly at the others. The "Verified scannable" badge is therefore earned when at least 2 of the 3 rasters decode to an exact byte match against your content. Anything else shows a clear warning and keeps the downloads locked, so an unverified heart code cannot leave the page as a finished keepsake.
The comparison is on bytes, not on appearance. When fewer than 2 rasters verify, a render that decoded to different content than you typed is reported as a mismatch ahead of one that did not decode at all, because a code that reads as the wrong words is never safe to use. The engine's test suite runs the identical render–rasterise–decode loop on the heart style at several raster sizes, rotated, and after lossy JPEG recompression, and requires the decoded bytes to match exactly — which is how the 0.97 coverage and the 4.5:1 gate stay pinned.
What it cannot promise: on-screen verification proves the artwork decodes cleanly at screen resolution. It cannot see your printer, your paper or the phone that will do the scanning, and it does not measure any particular printed result. That is what the test print below is for.
Printing and testing a Valentine code
The engine's working minimum is 0.5 mm per module. The worked example is 57 modules across with its quiet zone, and the engine's readout for it at that minimum is "print at least 28.5 mm (1.12 in) wide". The methodology's general guidance holds on top of it: print at least 2 × 2 cm for arm's-length scanning.
The PNG download is rendered at an exact pixel size that spans the whole symbol, quiet zone included, and the engine reports what each of its presets means on paper at 300 DPI. For the worked example's 57 modules, the width of one heart at each preset follows directly:
- 512 px — 1.71 in × 1.71 in (43.3 mm × 43.3 mm) at 300 DPI; each heart 0.74 mm wide
- 1024 px — 3.41 in × 3.41 in (86.7 mm × 86.7 mm) at 300 DPI; each heart 1.48 mm wide
- 2048 px — 6.83 in × 6.83 in (173.4 mm × 173.4 mm) at 300 DPI; each heart 2.95 mm wide
The 512 px size is the engine's smallest preset and is listed because the engine defines it; the generator above exposes the 1024 px and 2048 px sizes. Those are the sizes at which the file prints unscaled; they are not instructions to print that large. Scale the image down to the size the object needs, but not below the floor above. The SVG download is resolution-independent and keeps the heart glyphs as curves at any size.
Two habits separate a verified render from a scannable card. Keep the 4-module quiet zone uncropped: it is part of the symbol, it is always drawn, and a trim that removes it removes something the scanner expects. And scan a test print with a real phone before the moment that matters. If a verified heart code will not scan in print, that is exactly the report we want — see the contact page; confirmed issues are fixed in the engine and locked in with a new test. The full rules are on the methodology page.
Common misreadings
- "The white around the hearts is just margin, so I can crop to them." The quiet zone is 4 modules of blank background on every side, drawn by the engine as part of the symbol. Verification ran on the artwork with it present; a crop that removes it produces an object that was never verified.
- "An offline note will show my words on any phone." It will not. Bare text carries no scheme, so an iPhone offers to copy or search it and Google Lens runs a web search; Samsung phones and dedicated scanner apps do display it. The offline note is the mode for needing no connection, ever; the reveal link is the mode that hands the phone a link instead. On a framed keepsake with no caption of your own the words are printed under the code as the caption, in either mode; on the bare Heart modules style this preset starts on, they are not, so the caveat stands unless the style is switched to a frame or the words are printed separately.
- "A soft pink is more romantic, and it is only a warning." It is not a warning.
The engine rejects any pair under 4.5:1 and will not render;
#f9a8d4on white measured 1.81:1 when this page was built and was rejected. Pick a deeper shade of the same hue — the ratio follows luminance. - "Longer is more heartfelt, and the code will cope." It will encode, up to the symbol's capacity, but each version step adds 4 modules a side and shrinks every heart at a given print size. The paragraph-length note above lands at 85 modules across, which the engine's print helper flags as oversized for a card. The levers are a shorter note or, if the note is a reveal link, carrying it as an offline note instead; coverage and error correction are fixed.
- "The badge means it will scan from the card." It means the artwork decoded at screen resolution, at least 2 of 3 rasters, to your exact bytes. Paper, printer and phone are outside its view; the test print is yours to make.
Valentine code FAQ
How long can the love note be?
Two separate limits apply. A reveal link accepts at most 300 characters, measured before encoding. Independently, the engine’s print helper flags any symbol wider than 65 modules, quiet zone included, as oversized for a card or tag. Measured at level H when this page was built: a note of 19 characters encodes as version 3 (29×29 modules), the worked example of 81 characters as version 8 (49×49), and a paragraph of 213 characters as version 15 (77×77) — 85 modules across with its quiet zone, past the comfortable limit. Fewer characters mean fewer, larger cells, and so larger hearts at any given print size.
Is the message private?
It is not encrypted: anyone who scans the code can decode it, and on a framed keepsake with no caption of your own the message is printed under the code as the caption, where it can be read by eye. The Valentine preset starts on the bare Heart modules style, which draws the symbol and its quiet zone and nothing else, so there the words are in the code alone unless the style is switched to a frame. What the reveal-link mode does guarantee is that the words never reach this site. They travel in the URL fragment after the #, which per RFC 3986 is stripped before a request is made, so the message never reaches our servers, a CDN or any log and is decoded entirely on the reader’s device. An offline note never leaves the code at all.
Why hearts instead of squares — does it still scan?
Each dark module outside the landmarks is redrawn as a heart spanning 0.97 of its cell — 97% — a coverage this engine decode-verified and pins with its tests. The three finder squares and the alignment patterns stay classic squares because restyling alignment patterns broke decoding outright in testing. Your browser then rasterises the finished artwork at 800, 1200, 1600 px, decodes each raster with jsQR and compares the bytes to your exact message; downloads unlock only when at least 2 of the 3 rasters match.
Can I use pale pink hearts on a white background?
Only if the pair measures at least 4.5:1 in WCAG contrast; the engine rejects weaker pairs rather than warning. Measured at build time: the preset’s #9f1239 on white is 8.02:1 and is accepted; a pale pink such as #f9a8d4 on white measures 1.81:1 and is rejected. The ratio is computed from relative luminance, not hue, so a deeper shade of the same pink passes where the pale one fails.
Reveal link or offline note — which should the valentine use?
Both carry the same words. On a framed keepsake with no caption of your own the message is printed under the code as the caption, in either mode; the Valentine preset starts on the bare Heart modules style, which prints nothing but the symbol, so the words appear on paper only if the style is switched to a frame — the Heart frame with heart modules inside it, say — or they are printed separately. A QR code containing bare text carries no scheme, so a phone has nothing to act on: Apple’s Camera and Google’s ML Kit recognise links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins, and no plain-text type. Faced with an offline note, an iPhone offers to copy or search it and Google Lens runs a web search; Samsung phones and dedicated scanner apps do display it. A reveal link encodes a normal URL to a page on this site with the message in the fragment, so the phone is handed a link rather than bare text — at a cost in density. For the worked example the offline note is a version 8 symbol and its reveal link would be version 13. The offline note needs no connection, ever, and accepts the display caveat.
Can I tint the background as well as the hearts?
Yes, within the same gate: the engine measures the pair, not the hearts alone. #be123c hearts on a blush #fce7f3 background measure 5.35:1 and are accepted. Light hearts on a dark background are a different matter: white hearts on #be123c measure 6.29:1, well above the threshold, and are still rejected, because the engine refuses inverted codes outright — dark modules on a light background only.
How big does a heart code need to be printed?
The engine’s working minimum is 0.5 mm per module. The worked example is 57 modules across with its quiet zone, so its floor is 28.5 mm; the methodology’s general guidance is at least 2 × 2 cm for arm’s-length scanning. At 300 DPI the largest PNG preset, 2048 px, prints at 6.83 in × 6.83 in (173.4 mm × 173.4 mm) at 300 DPI. Whatever the size, keep the 4-module quiet zone uncropped and scan a test print with a real phone before the moment that matters.
What does the “Verified scannable” badge not cover?
It proves the artwork decodes cleanly at screen resolution and to your exact bytes. It cannot see your printer, your paper or the phone that will do the scanning, so it cannot guarantee a particular printed result. If a verified heart code will not scan in print, that is exactly the report we want — see the contact page; confirmed issues are fixed in the engine and locked in with a new test.
If this valentine comes with a question, the proposal code adds the heart frame around the hearts. Prefer a picture of the two of you inside the code? That is the photo keepsake code. And a gift tag code ties a second message to the chocolates.