Latch

Playing

Photos, stamps and recap cards

The gallery, the five stamped-overlay layouts, the session recap card, what the overlay says (and when it says it), and what is stripped on the way out.

On this page

Every photo you put into Latch โ€” a check-in, a verification shot for training โ€” lands in one content-addressed store under your data folder and shows in the Gallery. Voice memos live in the same store but are not gallery tiles: audio has no pixels.

/gallery shows every photo, newest first, with the task it verified if it was one. Each tile has a stamp-layout picker, a download of the stamped version, a ๐Ÿ“ค share button and a ๐Ÿงณ toggle (below).

Stamped photos

A stamped photo is your picture with an overlay of stats, re-encoded as a fresh JPEG. Five layouts, plus auto, which picks by aspect ratio:

Layout Name in the app Shape
bar Hairline one thin line of facts along an edge
hero Collar a bold band with the headline number
badge Tag a compact corner tag
dossier Case File a grid of labelled values
rail Strip a footer strip, suits wide photos

Sizes: 1080, 1600 (default) or 2048 px on the long edge. The default layout and which stats appear are yours to set โ€” see Customise โ†’ Stamps for the full token list (streak, day N, time locked, tasks per week, rank, and about forty others).

The overlay is as-of the shutter

Every value on a stamped photo is computed from the log at the photo's timestamp: the clock as it stood, the streak as it was, the training count up to that moment. A photo from three weeks ago does not wear today's streak. One deliberate exception: an event undone after the photo was taken still appears on that photo's overlay โ€” otherwise every undo would silently recaption every picture already in your gallery.

EXIF and GPS are stripped by construction. The stamped file is rendered from pixels and saved as a new JPEG; there is no metadata to copy. The original stays in your store untouched.

Hidden timer: while a hidden lock is running, no overlay prints the sentence or the time remaining โ€” either one plus the start time would give the end away. Once the lock ends, they return.

Recap cards

Every finished (or in-progress) session has a recap card at /session/<id>/recap.jpg, linked from the Last lock card and the Sessions list. Two shapes: story (1080 ร— 1920, for a phone screen) and square. The card shows the verdict (clean / early / in progress), the headline time, a grid of stats, your rank and level, and a strip of the session's photos.

Which stats sit in the grid is a token list (Settings โ†’ Stamps โ†’ Session recap card). The session's private note is not printed unless you add ?note=1 to the URL โ€” private prose on a share object has to be opt-in.

Share cards

A recap card is about one finished lock. A share card is whatever you point it at โ€” at Share in the nav, or /share.

Pick a kind, a layout, a theme, a shape, and optionally a photo; then download it or hand it to the share sheet, with the post text already written. Every choice lives in the link, so the picture you are looking at, the file you download and the words that go with it are the same card at the same moment โ€” the page pins its clock into all three.

A bare Share page opens on your โ˜… default preset, or on the built-in Daily starter (the Dense layout) when you have none. A link anybody made before 0.14 still means what it says and draws the card it drew โ€” the same pixels outside an event, save where 0.13 cut a value short or the card's moment fell inside a lock that ended later; during an event the stamp is added.

On a phone the page is built for one hand: the preview and the ๐Ÿ“ค Share button stay pinned at the top while the panels โ€” Stats, Post, Look, Photo โ€” sit underneath, and a tap on a stat, a theme or a hashtag changes the card in place, without reloading and without the screen jumping. The address bar follows along, so a reload or a bookmark lands on the same card. With JavaScript off every control is still a plain link that lands back on its own panel.

Three kinds

Is about Its clock
Right now the live state โ€” locked or not, how long, the streak this moment
The last stretch a span: 7, 14, 30 or 90 days, and what happened in it the two ends of the span
One badge one thing you earned, and where things stood then the badge's own moment

The last stretch prints the span's actual dates rather than calling itself "this week". That is deliberate: a card headed THIS WEEK on a Wednesday is a claim about three days wearing the name of a week, which is the same thing badges refuse to do when they wait for a month to end before deciding its winner.

One badge is a record, not a snapshot with a trophy on it. Every number on it is as it stood when the badge was earned โ€” so a card about something you did in August shows August's streak, not today's. The date in the corner is that moment, and the whole card agrees with it. It appears as an option once you have earned a badge.

Themes

Seven palettes, and six of them are the badge metals: Steel, Moss, Sapphire, Amethyst and Gold are the five rarities the badge art uses, and Plate is the cream plate a badge sits on. Midnight is the app's own colours โ€” what every card looked like before themes existed, and still the default.

Badges drawn on a card wear their own metal, so a legendary badge is gold on any theme.

Layouts

Three layouts, and they differ in how much room the clock gets โ€” never in what is true.

Layout What it is Story Square Wide
Poster the big timer โ€” what every card looked like before 0.14 6 stats (3 with a photo) 6 (3) 3
Dense a small timer and the room given to the numbers 12 (9 beside a photo) 9 (6) 6
Check-in the photo fills the card; a glass panel holds the stats 12 8 โ€”

Check-in needs a right now card with a photo, in story or square. Ask for it anywhere else and the card quietly draws as Dense, and the page says so. The Check-in starter (the dashboard's ๐Ÿ“ค button uses it) picks today's photo for you.

A Check-in card has one clock: the shutter. Every number on it โ€” the timer, the streak, the event day โ€” is as it stood when the photo was taken (clamped to when it reached the box, so a camera with a fast clock cannot date a picture into the future), and that moment is printed on the photo itself. Drawn again next week, it is the same card, byte for byte.

Stats

How many fit depends on the layout and the shape (the table above); the page says fits N for the card on screen, from the same arithmetic that draws it. The Stats panel shows twelve slots in the card's own order: tap a slot, then move it earlier or later, or remove it; tap a stat in the catalogue below โ€” each one shows its value right now โ€” to add or drop it. โ†บ default list goes back to the list in Settings โ†’ Stamps & recap; clear means no stats at all. The choice travels in the link and changes no setting; a preset keeps it.

A stat with nothing to say at this moment is left out rather than printed as a zero, so the card lays out what resolved, never what you asked for. A value too long for its cell takes two cells instead of being cut short โ€” "LOCKTOBER ยท DAY 2/31" reads in full. A slot drawn dashed won't fit on this card; a dim one is already on the card โ€” on Dense and Check-in the elapsed time is the big number, the level and rank are in the footer, and a stamp on the card already names the event and the day โ€” so none of those is drawn twice.

What fills the lower half

Never nothing. In order: the photo if you picked one, then the badges โ€” the ones earned in the span on a week card, the rest of your collection on a milestone card, or all of them on a right now card if you ask โ€” and otherwise the events that moved the clock most, which is the same log the numbers above it come from.

A badge's icon is never printed, because the icons are emoji and the card's font has no emoji in it. A badge is drawn instead โ€” the same hexagon-and-metal-ring shape the badge art uses.

The card has two moments in it, and says so

This is the one thing worth understanding about a share card that carries a photograph. The stats describe the card's own moment. The photograph describes whenever its shutter fired โ€” possibly weeks ago. So the card keeps them visibly apart rather than blending them:

The caption is not optional, and it lives inside the image rather than in the card's margin โ€” a card gets cropped, re-shared and screenshotted, and a date that lives in the surrounding chrome survives none of that.

A Check-in card is the exception that proves the rule: it has one moment, the shutter, and prints it on the photo. Nothing on it is from now, so there is nothing to keep apart โ€” which is the only reason it is allowed to fill the card with the picture.

Why a milestone card takes no photograph

Its numbers are already as-of the day the badge was earned. Adding a picture would put a third moment on one card โ€” the badge's, the shutter's, and the reader's assumption that a card they were just handed is about today. Two is already the most anyone can keep straight, so that kind refuses a photo and says so on the page.

The event stamp

When you are in an event โ€” Locktober, or any playset with an [event] โ€” the card carries a drawn postage stamp in the event's own colour: a perforated rim, a padlock, the event's name, the day in big numerals with /31 beside it, and the year. Nothing to set up and nothing for the playset to ship: it is drawn from the event's name, dates and accent, so every event playset gets one.

It sits where its moment is. On a framed photo it is on the photo, and dated by the shutter โ€” a photo from the 2nd says DAY 2 forever, however late you share it. On a Check-in card it is in the header (the shutter is that card's only clock); on a card without a photo it is in the header, as of the card's own moment. No event at that moment means no stamp โ€” never a fallback to "the event running now".

Turn it off for one card under Look โ†’ Event stamp, or with seal=0 in the link.

The stamp reads the playset as it is now

A card re-drawn later asks the playset what the event was. Switch the playset off, remove it, or install a version with different dates, and old cards drawn again lose their stamp or change it. A picture you already shared is a file and does not change.

Post text

Under the card, the Post panel has the words ready: built here, on the box, from the same card โ€” the same moment, and the stats the card actually drew, in its order. No model writes it and nothing is sent anywhere.

Three styles. Pup (the default) has three phrasings that take turns by event day โ€” one of them quotes the playset's own line, so on Locktober's second day it opens Day 2 of 31. It's Locktober, pup. โ€” Stats is the numbers, and Minimal is just the day and the tags. Custom โœŽ opens the template, which you can edit:

Hashtags. An event gives two by default โ€” #Locktober #Locktober2026 โ€” and offers more (#LocktoberDay2, #chastity, #locked, #keyholder, #chastitycage, #pupplay, #petplay) that are never on until you tap them. Add your own; {day}, {days} and {year} inside one fill in from the event. A playset's catalogue tags are never turned into hashtags.

Alt text describes the card for a screen reader (it is written for you and cannot be edited into saying something the picture does not). Content warning is chastity ยท Locktober day 2/31 by default; set your own in the panel. The counters under the text track X (โ‰ˆ280, emoji count double), Bluesky (300) and Mastodon (500, counting the CW).

Sharing it. On an iPhone, ๐Ÿ“ค Share puts the post text on your clipboard and opens the share sheet with the picture, in one tap โ€” pick the app, then paste. (iOS drops the picture if text rides along in the share sheet, which is why the text goes by clipboard.) The picture is prepared before you tap; if you tap before it is ready the page tells you to wait a moment rather than downloading. โง‰ Copy text, Copy alt and Copy CW copy one thing each.

Presets

A preset is a whole look with a name: the stats, the layout, the theme, the shape, the event stamp, the post style, the hashtags, the template and the CW. The row of chips under the preview holds them.

Two built-in starters, Daily and Check-in, sit after your own presets, with a dashed outline; they cannot be renamed, starred or deleted. Presets live in this box's database and ride the full backup. Saving one needs JavaScript; applying one is a link.

Location on photos

Latch can record roughly where a photo was taken and print it on a card or a stamped export. Two separate switches, because they are two different decisions:

Setting Default
Record a coarse location with new photos photo.place_capture on
Print it on an image nothing โ€” every export asks explicitly off

The rounding happens when the photo is saved, not when it is printed. The exact coordinate is never written to disk, so it is not in the database, not in your backups and not in the export bundle โ€” and a card cannot be sharpened back later, by you or by anyone who gets a copy of your data.

How coarse is photo.place_dp:

Grid Reads as
0 ~111 km region
1 ~11 km city
2 ~1.1 km neighbourhood โ€” the default
3 ~110 m street

Where it comes from, in order:

  1. The photo's own EXIF โ€” what the camera recorded, so it stays correct however late you log the photo.
  2. Your browser, but only for a photo you are logging now. A photo backdated to last Tuesday will not take today's position: that would put where you are standing onto a picture taken somewhere else.
  3. A label you type ("the park", "hotel, Chicago"). A typed label replaces the coordinate entirely rather than appearing next to it.

A photo whose camera recorded nothing simply has no location, and the Share page says so instead of offering a switch that would do nothing.

What rounding does and does not buy you

A 1 km cell is a neighbourhood, not a doorway. But the grid is fixed, so every photo taken at home lands in the same cell โ€” and over a long log, the cell you appear in most is home, to within a kilometre. Coarsening limits the blast radius of one image; it is not a disguise. If that matters for a particular card, use a typed label, or leave the location off.

Carrying photos to a new box

๐Ÿงณ means travels with my pup to my next box โ€” not shown to any pack. It is off by default, and it is about one thing only: which photos go into your pup.json when you arrive on your own new box. What a pack sees is a different choice, made on Consent item by item; ticking ๐Ÿงณ shows a photo to nobody.

Sharing

The ๐Ÿ“ค button uses the phone's share sheet (the Web Share API). It needs a secure origin โ€” https://, through your reverse proxy โ€” and a browser that supports it. Anywhere else it downloads the JPEG instead. Nothing in Latch posts anywhere; sharing is you handing a file to another app.

On an iPhone the share sheet gets the picture only, and the share card's post text is already on your clipboard โ€” paste it into the post. (The file in Save to Files is named for the event day, like locktober-2026-day02-20261002-1205-story.jpg.)

For 12 hours after a photo check-in, the dashboard shows ๐Ÿ“ค Share Day N right under the big buttons: one tap opens the Share page with that photo, the Check-in card, the stamp and the text ready. The gallery's ๐Ÿƒ card link does the same for any photo.

Limits and formats

Picking one

Two doors, deliberately different:

That the thumbnail is of the uploaded file matters more than it sounds: a HEIC is converted and a clip becomes a single frame before anything is sent, and the preview shows the result of that, not the thing you tapped. If a preview appears with no picture in it, the file is being sent as-is because this browser could not decode it โ€” the line underneath says so, and the server's refusal will name the real format.

Where the bytes are

<data dir>/media/YYYY/MM/<sha256>.<ext> with thumbnails under media/thumbs/. The export bundle carries originals and thumbnails (Export). Media is not in the SQLite file, so a database-only backup is not a full backup.


This page also ships inside the app, at /guide โ€” so your own instance always serves the guide for the version you are running, with the internet unplugged. Get Latch ยท Something wrong here? Tell me.