Wedding QR Code
Table cards that collect every guest's photos, invitations that open your wedding site, registries one scan away — dressed in frame art that belongs on stationery. Pick a frame, match your colors, and download only after your browser has decoded the artwork back to your exact link.
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
Generated at build time by the same engine as the tool above — the floral frame around an untouched code panel. It encodes:
https://example.com/album/ella-and-sam
Version 5 at 37×37 modules, error correction H. Scan it from the screen — it works.
What the wedding preset encodes
Guide: the panel construction behind every framed code, the 5 templates and the recoloring rule are set out in full in Framed codes, explained. This page applies those rules to one preset, with the numbers computed from it.
The wedding preset starts on the Floral frame style with a link as its content. Every preset in the occasion registry fixes three things: the style a page opens on, the payload builder it uses, and the example rendered above. For a wedding that is a floral frame around an untouched code, a link payload, and the fictional album link shown in the worked example — the same registry entry drives the generator, this page, and the test suite, so the three cannot disagree.
A link payload is validated and never rewritten. The builder requires the scheme to be present
— https:// and http:// are the only two it accepts — and the code then
carries exactly the text you typed, character for character. That matters at scan time. A link is
one of the payload types the methodology lists as recognised by Apple's Camera and Google's ML Kit
— links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins — so a phone
that reads the code has something to act on. Bare text is not in that list, which is why a link
needs none of the reveal-link machinery a message keepsake does.
The example link, https://example.com/album/ella-and-sam, is 38 characters long. At error correction
H the encoder chooses version 5: a
37×37-module symbol, 45×45 once the
4-module quiet zone is drawn on every side. Version 5
places its alignment-pattern centers at modules 6 and 30; the three
finder corners carry none, so this symbol has 1 alignment pattern — the smaller inner square a scanner uses to orient a dense code — and it is rendered as a crisp
classic square in every style on this site.
Link length is what sets symbol size. Encode a longer fictional upload link, https://example.com/album/ella-and-sam/upload?event=reception, at the same level and the encoder moves to version 7: 45×45 modules, 53 across with the quiet zone. The framed panel is a fixed size, so a bigger
symbol means smaller modules on the same panel and, as the printing section below works out, a larger
minimum print. The shorter the link, the coarser the code.
The content selector can switch this preset to a message or a contact card. A message brings in the rules the methodology sets out for message keepsakes: a reveal link carries the words in a URL fragment that is stripped before any request is made, so it never reaches a server, a CDN or a log; an offline note writes the words into the code and accepts that an iPhone offers to copy or search bare text while Google Lens runs a web search; in both modes, on a framed keepsake with no caption of your own, the message is printed under the code as the caption. For a link none of those caveats arise, though the caption rule below applies to whatever you print under the code.
Why the floral frame cannot touch the code
A framed code is the one style on this site that decorates nothing inside the code, and the floral composite shows why in the order it is built. The engine draws the frame art first: a rounded border in the primary color and 4 botanical sprigs — each a stem carrying 3 leaves and 2 blossoms — placed at the corners by a transform, with 3 small dots at the top center; those counts are read from the composite's markup when this page is built, not copied from the template's description. Over that it draws an opaque white panel, and into the panel it copies the rendered code, quiet zone included, byte for byte inside a scaled group. Nothing about the sprigs decides whether they stay clear of a module; they are underneath the panel and cannot show through it. The copy is checked at build time: the example's inner render is present verbatim inside the composite — yes.
Read back from the composite rather than assumed: the artwork is 760×880 units, the panel is a 460-unit square whose top-left corner sits at 150,240, and the code with its quiet zone is scaled into a 432-unit box
inside it — 94% of the panel's side, leaving 14 units of the panel's
own padding on each edge. The panel is 61% of the artwork's width. All 5 templates — heart, floral, ring, classic, confetti — put that same panel in that same place and scale the code into the
same box: the example was composed on each of the other 4 when this page was
built and the geometry matched every time. The floral template is the one whose art is sprigs; what
each of the other 4 draws beneath the panel, and the default palette it supplies,
is the difference between them. A wedding code moved to another frame is the same code in the same
panel position, verified the same way — the one mark on the panel that follows the template is its
thin outline, which takes the template's default secondary:
#86efac on floral and, with the same frame color passed, heart #fda4af, ring #eab308, classic #9ca3af, confetti #2563eb
on the others.
A recolor reaches the frame art and never the panel. The preset's frame color is
#15803d, which measures 5.02:1 against white —
a number quoted only to show it is irrelevant. Inside the panel the code keeps the engine's
default colors, measured at 21:1. The primary colors the border and the stems; the
engine's floral defaults supply the secondary for the leaves and the accent for the blossoms
when no other is given, and the secondary also draws the panel's thin outline — on the panel's
edge, 14 units outside the code's box, so it never reaches the quiet zone. Match a
pale stationery palette and the decode margin does not move; the
framed-codes guide walks through why the recolor is
safe by construction rather than by testing.
Inside the panel the anatomy rule is unchanged: finder and alignment patterns stay classic crisp squares, because restyling alignment patterns broke decoding outright in testing. A plain floral frame restyles nothing — the inner render is the engine's plain code. Tick heart-shaped modules inside the frame and the dark data and timing modules are redrawn as hearts spanning 0.97 of their cell — large enough that a scanner's sampling grid still reads each cell as decisively dark — while the finder and alignment modules remain squares. Hearts are where a framed code begins to spend decode margin on decoration, which is why the heart renderer requires a level-H model and rejects anything lower.
Error correction is where a plain frame differs from the other 2 styles. Hearts and halftone redraw modules, so their renderers require a level-H model — roughly 30% recovery — and reject anything lower. A frame leaves the symbol untouched, so the framed composite's own guard accepts level Q as well as H and refuses anything below Q; that is the generator's Smaller code option above. Both answers were computed when this page was built: re-encoded at level Q the example link becomes version 4, 33×33 modules against version 5 at H, and the floral composite accepts it; re-encoded at level M it is refused. The generator starts each preset at H and Smaller code is the opt-in to Q; every worked example on this site is encoded at H, checked across the preset registry at build time: yes. A Q model can never become heart art inside the frame, because the heart renderer rejects it first.
The caption is set below the panel in the frame's primary color; it belongs to the frame, not the code. Two limits apply, and they are different in kind. The composite refuses a caption over 200 characters outright — exercised at build time on 201 characters, it answers: Captions are limited to 200 characters. That ceiling is the composite's own, raised so that a whole message can be printed under the code, and it is the limit that binds on the message-as-caption path — a message keepsake with no caption of your own puts its words there. The second limit: a caption inside the ceiling that needs more than 4 lines is cut at the last line and marked with an ellipsis, so a clipped caption never reads as the whole message. The example's caption, Share your photos with us, is 25 characters and sets on 1 line, read back from the composite at a baseline of 774 units — below the panel's bottom edge at 700.
What verification proves for a framed code — and what it cannot
The badge on this page is earned by the floral composite as a whole, not by the bare code. Verification draws the finished artwork — border, sprigs, panel, code and the caption under it — into a square canvas at each of the engine's 3 raster sizes, 800, 1200, 1600 px, scaled to fit and centered, runs jsQR on the pixels, and compares what it reads to the album link byte for byte: 38 bytes for the example. The composite is taller than it is wide, so its height sets the fit, and the code's share of that height is fixed by the geometry above. At the 3 sizes each module of the example spans 800 px → 8.7 px per module; 1200 px → 13.1 px per module; 1600 px → 17.5 px per module — figures computed from the composite, not measured by a camera.
At least 2 of the 3 rasters must decode to the exact bytes; the badge then names which sizes passed, and anything less shows a warning with the downloads locked. Several sizes rather than one is a response to a measured effect — a render can fail at exactly one raster size and decode at the others — which Decode verification sets out together with the verdict order. As it applies here, one such miss on a floral composite is reported, not hidden, and does not on its own hold back the download. A decode that returns a different link from the one typed outranks a decode that finds nothing, because a wrong address is never safe to print.
What the badge cannot see is the invitation itself. The printer, the paper and the phone that will read the card are outside the loop, and so is the album's destination — the code carries the address exactly, and what that address serves is yours to keep working. The worked example above came out of the same render function at build time, and the engine's test suite runs the decode loop on every occasion example, so a floral preset that stopped scanning would fail the tests rather than reach this page.
Printing and testing a framed wedding code
The methodology's print guidance applies to a table card unchanged, and this page adds nothing to it: print at least 2 × 2 cm for arm's-length scanning, keep the quiet zone uncropped, and scan a test print with a real phone before the day. What the engine contributes is arithmetic — a floor for the code from its module count, and for a framed code the same floor carried out to the panel and to the whole artwork by the geometry read above.
The working minimum module is 0.5 mm. The example is 45 modules across with its quiet zone, so the code itself must print at least 22.5 mm (0.89 in) wide. That floor is for the code, not the panel: the panel holds the code in a box 94% of its side, so a panel printed at 22.5 mm would put each module at 0.470 mm, below the floor. Scaled by the measured geometry, the panel must print at least 24.0 mm wide, or the whole floral artwork 39.6 mm wide. For the longer fictional link above, 53 modules across, the code's floor rises to 26.5 mm and the panel's to 28.2 mm; the box the code is scaled into is the same 432 units for both, which is why a longer link means finer modules on the same panel. Print at whichever is larger, the 2 × 2 cm guidance or the floor for your own code; the readout under the preview states the code's floor for the content you typed. The engine flags a code past 65 modules across as oversized for a tag or a card and asks for shorter content; the example is not oversized and the longer link is not.
The engine's PNG readout describes a square raster at 300 DPI: 512 px prints at 43.3 mm; 1024 px prints at 86.7 mm; 2048 px prints at 173.4 mm. The floral composite is not square, so a preset's pixel count is a side of the artwork, not of the code. Taking it as the artwork's longer side — its 880-unit height, the conservative reading — the code inside comes out as follows: 512 px → code 21.3 mm, which falls short of the 22.5 mm floor; 1024 px → code 42.6 mm, which clears the 22.5 mm floor; 2048 px → code 85.1 mm, which clears the 22.5 mm floor. The SVG download is vector and carries the same verified artwork at any size, so the floors above are the only sizes that bind it.
The 4-module quiet zone is inside the code's box, and the box is inside the panel: between a dark module at the code's edge and the panel's edge there are the quiet zone's 4 modules and then 14 units of panel padding, which at the panel floor of 24.0 mm is 0.7 mm of white. A trim along the frame's border leaves all of it. A cut into the panel spends that padding first and the quiet zone next, and the decoder needs the quiet zone. Keep the panel whole, then make one test print at the final size and scan it with a real phone: it is the only check that includes the card stock, and a verified code that will not scan in print is exactly what the methodology page asks to hear about.
Common misreadings
- Cropping the quiet zone. The 4-module margin is the clear margin around the code the methodology requires: always drawn, never covered by frame art, and removed by any trim that enters the panel.
- Expecting bare text to display. This preset encodes a link, which the recognised payload types include. Switch it to a message and a code containing bare text carries no scheme, so a phone has nothing to act on — the reason the message modes exist, and the reason the message is printed on the keepsake as well.
- Taking the frame color for the code color. The color control recolors the art below the panel. The code stays in the engine's default colors at 21:1, which is why a soft frame palette costs nothing in decode margin.
- Low-contrast heart colors. The gate belongs to the heart renderer, which measures
foreground against background with the WCAG formula and requires 4.5:1; the bare heart-module style is where a stationery palette meets it, because that is the
style that lets you choose the module color. The preset's own heart color,
#881337, measures 9.57:1 on white and clears it. A fictional pale pick,#f9a8d4, measures 1.81:1, and the renderer refuses it with: Artistic styles require at least 4.5:1 contrast (got 1.81:1) — decoration already spends decode margin. - Reading the badge as a print guarantee. The badge reports a decode at screen resolution — 2 of 3 rasters, with the example's modules spanning 8.7 to 17.5 px — and nothing about ink on card stock. The test print at final size is the part of the check that only the person holding the invitation can run.
- Expecting to re-point a printed code. The link is inside the image, so nothing can lapse — and nothing can be edited after printing either. What the address serves can change at any time; the address itself is fixed in the ink.
For the construction behind all 5 frames, read Framed codes, explained; the guides index covers verification, printing and message keepsakes, and the methodology page holds every measured rule in one place.
Wedding code FAQ
What does the wedding preset actually encode?
A link. The preset starts on the Floral frame style with a link as its content; the builder requires the scheme (https:// or http://) and then carries the text exactly as typed, never rewritten. The fictional example link on this page is 38 characters and encodes as version 5, 37×37 modules, at error correction H.
Does the floral frame weaken the code?
No. A framed code is not modified at all: the rendered code, quiet zone included, is nested verbatim on an opaque white panel drawn above the frame art, so the decoration cannot touch a module by construction. Verification then decodes the finished artwork, frame included, before the downloads unlock.
Can I recolor the frame to match our stationery?
Yes. The frame color control recolors the frame art only; the code on the panel stays in the engine's default colors, which measure 21:1, and the frame color never enters the panel. Every recolor is a new render and is verified again like any other.
What happens if I turn on heart-shaped modules inside the frame?
Dark data and timing modules are redrawn as hearts spanning 0.97 of their cell; finder and alignment patterns stay classic squares because restyling them broke decoding in testing. Heart modules require a level-H code and the 4.5:1 contrast gate, and the render still has to pass decode verification before download.
How big must a printed wedding code be?
Print at least 2 × 2 cm for arm's-length scanning, or the engine's floor for your code if that is larger: at 0.5 mm per module the example on this page, 45 modules across with its quiet zone, must print at least 22.5 mm (0.89 in) wide. Keep the quiet zone uncropped and scan a test print with a real phone before the day.
Will the code on a printed invitation still work years later?
Yes. The link is encoded directly into the image — no shortener, no redirect service, nothing that can lapse — so the code itself cannot expire. The trade-off is that a printed code cannot be re-pointed later: keep the destination on a page you control, and change what it shows there.
What does the "Verified scannable" badge prove, and what does it not?
It proves this exact artwork was rasterized at 800, 1200, 1600 pixels, decoded with a real QR decoder at 2 or more of those 3 sizes, and matched your content byte for byte. It cannot see your printer, your paper, or the phone that will do the scanning — that is what the test print is for.
Can the wedding code carry a message instead of a link?
Yes — switch the content from a link to a message. A reveal link then carries the words in the URL fragment, which is stripped before any request is made and never reaches a server, a CDN or a log; an offline note writes the words into the code itself, accepting that an iPhone offers to copy or search bare text and Google Lens runs a web search. In both modes, on a framed keepsake with no caption of your own, the message is printed under the code as the caption, up to 200 characters.
For the question that comes first, see the proposal code; the photo code blends an engagement photo into the code itself; and gift tag codes handle the favor boxes. A year on, the baby reveal code tends to be the sequel.