Designed QR codes
A QR code is a block like any other: what it holds and how it looks are props, so the AI (in the app or over MCP) and a person in HQ make the same thing. Nothing is on by default: a space has QR codes only where someone adds a qr block, turns on qr on web.share, or uses invites.code.
What it holds #
One of:
| Prop | Encodes |
|---|---|
value | Any text or full link, up to 600 characters. Wi-Fi: WIFI:T:WPA;S:<name>;P:<password>;; |
page | A link that opens that page of the space in Zvessa |
link: "space" | A link that opens the space itself (/s/<id>) |
link: "web" (+ optional page) | The space's public web address (Public links kit); hides while the space isn't on the web |
link: "invite" | The viewer's own invite link (needs /referrals/codes); each person sees their own |
Other props: label (words printed under the code, inside the design), title, size (96-360, default 220), actions (Share / Copy link / Print buttons, default on), and the button words share, copy, print.
How it looks: design #
Every setting is optional. A look is a preset of the others; anything set alongside it wins.
| Look | Dots | Corners | Paper |
|---|---|---|---|
classic (default) | square | square | square |
rounded | soft | round | rounded |
round | round (joined like pills) | round | rounded |
dots | dot | circle | rounded |
circle | dot | circle | a round badge, like Apple's, with a ring of dots |
dots: square, soft, round, dot, diamond.eyes(the three corner squares): square, round, circle, leaf.shape: square, rounded, circle.fill: the circle's ring of dots (default on).- Colours are style values, like everywhere else: a role (
accent,text…),#hex, ormix()/alpha()/contrast().ink(default the style'sqrInk, else black),paper(defaultqrPaper, else white),eyeInk,border, and agradient(linearorradial) frominktoink2atangle. logoin the middle:zvessa(the app's spiral),initial(a letter, default the space's first), orimage(logoImage, an https address). A logo raises error correction to H.caption(up to 60 characters),ecc(L, M, Q, H; default M, H with a logo),margin(2-6 modules).
It always scans. Ink is kept dark and paper light with at least 4:1 contrast; when a style or a design asks for something cameras can't read (light ink, dark paper), the colours are made darker or lighter and the AI's tools say so. The circle's decorative dots stay two modules clear of the code. tests/qr.test.ts draws every look, dot, corner, logo and gradient exactly as the app does and reads it back with ZXing.
Sharing, saving, printing #
On phones, Share saves the code as a 1024 px PNG and opens the share sheet, which also offers Save Image (Photos) and Print. On the web, Share shares the PNG file where the browser can, or downloads it; Print prints the code alone, centred, 12 cm wide. Copy link shows for links.
No new native package: drawing is react-native-svg (already in the app), the picture is its toDataURL, and sharing is expo-sharing and expo-file-system. A logo image from another site may be left out of a saved picture (browsers don't load outside pictures into SVG images). If printing straight from the app (no share sheet) is wanted later, that's expo-print, which needs a new EAS build.
Where else #
invites.codetakes the samedesign.web.sharetakesqr: trueand adesign: the address as a code, in the app and on the web page.- Public web pages draw
qrblocks inline as SVG (no script, no request);link: "invite"stays in the app.
Tools (AI and MCP) #
preview_qr(scope read): what a code would encode, its version, error correction and any colour fixes;svg: truereturns the SVG file. Changes nothing.make_qr(scope propose, needs manage): proposes adding aqrblock to a page; a person approves it, and it can be undone.
Code #
convex/kits/qr/encode.ts: the QR maker (byte mode, levels L/M/Q/H, versions 1-40). Pure code.convex/kits/qr/design.ts: designs → shapes → SVG; colour fixes; checks.convex/kits/qr/blocks.ts,tools.ts,run.ts,qr.ts: the block, the tools, the tools' runner, the space's context for them.src/kits/qr/QrCode.tsx(drawing, share, print),src/kits/qr/QrBlocks.tsx(theqrblock).convex/kits/invites/qr.tsremains for older imports.