CircleheadsiOS
BodyLog
A skin-tracking app for iPhone. You photograph a place on your body, say what it's about, and the app keeps the record. It never reads your skin, scores it, or tells you what to do — and nothing leaves the phone.
$3/month or $25/year at launch. Native SwiftUI + SwiftData, iOS 17+, zero external dependencies — no image assets; every glyph, badge and figure is a character grid drawn at runtime.
The app
Rebuilt here as live React from the shipping app's own values — the figure is rasterised from its vector anatomy, the logo is its frozen grid, and the colour, type and spacing are the real ones. It works: tap around.
Every tab switches, the + opens capture, the body map picks regions, and the history grid re-colours. Rendered live from the app's own values — not screenshots.
In simple terms
An iPhone app for tracking a visible skin or body condition between doctor visits: acne, eczema, psoriasis, cysts, bruising, physio progress.
It exists because of one question. If you have a chronic condition, the most useful thing your doctor asks is the hardest thing to answer: is it better or worse than last time? Six weeks have gone by, the flare that worried you has faded, and you are reconstructing it from memory in a ten-minute appointment.
You photograph the thing when you notice it, tag where on the body it is, say how it feels, and move on. The whole job of the app is making that thirty-second habit sustainable and handing you the history when it matters.
It never examines your photos, never scores your skin, and never tells you what to do. Nothing leaves the phone: there is no network layer in the app. Not disabled, absent.
The impact. It turns an unanswerable appointment question into a record you can show someone, while holding the line that software with no medical training has no business grading a symptom.
Why it exists
If you have a chronic skin or body condition, the most useful question your doctor asks is the hardest one to answer: is it better or worse than last time? Six weeks have passed, the flare that worried you has faded, and you are reconstructing it from memory in a ten-minute appointment.
BodyLog is the record that answers it. You photograph the thing when you notice it, tag where on the body it is, say how it feels, and move on. The app's only job is to make that thirty-second habit sustainable, and to hand you the history when it matters.
What people track
Deliberately not a dermatology-only tool. Anything visible on the outside of the body, changing slowly enough that memory fails you:
And what you call it is free text you coin — “psoriasis”, “jaw acne”, “hand eczema” — not a fixed menu. Two people with the same diagnosis rarely describe it the same way, and a closed list would make the app argue with them about their own body.
The two routes it is built around: face acne, logged zone by zone on a face diagram, and fold-prone persistent spots — psoriasis and eczema at the inner elbows, backs of knees, neck, scalp, waist — on front and back body diagrams.
What decides arguments
Not style preferences. When a design question comes up, these settle it — and a component is wrong, even if it looks right, when it breaks one.
Activity, never severity.
Every visualisation is keyed to how much you logged. Colouring anything by rating would turn the app into a diagram of how bad you are.
Colour tells things apart; it never ranks them.
A hue means “this is the psoriasis one”. Depth means “more logged here”. Neither ever means “worse”.
Gaps read as gaps.
Days you didn’t log are drawn empty — including in the logo. A mark with no gaps would quietly claim a perfect streak.
On device, full stop.
No network layer exists in the app at all. Not disabled — absent. Adding one would require an explicit written privacy decision first.
Everything is optional.
Save is never disabled. An entry with nothing but a date is a perfectly good entry.
Product voice
Lowercase headings, short sentences, no exclamation, no streak shaming, no medical authority. The one rating vocabulary is flaring · irritated · okay · good · clear — five is the good end on purpose, so the scale reads as progress toward clear rather than a severity score.
The mark is the data
The logo is five weeks of the logging grid. Hue says which thing was tracked, weight says how much, and the empty cells are days nothing was logged. It is the product's own data structure used as its signature — not a metaphor for the record, but a picture of one.
Five by five, gap 24% of a cell, five hues in fixed order, weight 0 as the empty token. A frozen constant rather than generated, so the header mark, the app icon and the splash are byte-identical. Seventeen of twenty-five cells are lit and all five accents appear — both facts are load-bearing. The system otherwise forbids multi-colour; the mark is exempt because there, colour is data rather than decoration.
System specimens
The same components the phone is built from, on their own. The history grid's two readings are the clearest statement of the whole idea in one tap.
How logging works
- Entries like posts, not forms. Optional photo slides with captions, tap-to-select regions on a face / front / back diagram, a 1–5 feel slider, and a free note. Nothing is required — save is never blocked.
- The questions in the order a person thinks them. Where is it showing up → what are you tracking → how does it feel today → what you notice → what you applied → anything else going on. That last one is captioned honestly: the app draws no conclusions from it.
- Shot conditions saved with the photo. Light (window / ring light / overhead / outdoors) and distance (macro / close / arm's length), so future shots can match. Two pictures of the same spot under different light are not a comparison.
- Checkup nudges. When a site you log regularly has gone quiet for three to fourteen days, the home screen offers a pre-filled “quick checkup pic?” card — an offer, never a scold.
- Zoom is time, not tile size. Week / month / all-time changes how the photo timeline is bucketed. Filter to one tracked thing — two progressions interleaved is two stories and neither reads.
Earned by tracking, never by improving
Twenty-six badges across five groups. Every one measures an act of recording — logging, pinning, photographing, describing, writing. None can be earned by a rating going down, and none is lost when a flare gets worse. The app asks people to photograph something they may not enjoy looking at, every day, for months; this is the counterweight, and it only works if it stays honest about what it measures.
The one I'd point at: back again — log again after two weeks away. Deliberately not a streak badge. Missing a fortnight and coming back is the moment most tracking apps make you feel worst; this one gives you something for it. XP is flat by design, so a bad day logged is worth exactly what a good one is.
Photos are health data
Skin photos are among the most sensitive images a person owns, so the storage model was a product decision before it was an engineering one: everything stays on the device. No cloud, no analytics, no network calls.
- Every stored image is downscaled and EXIF/GPS-stripped before it touches disk. Capture dates are read off the original bytes and discarded with them — a dated photo of your own body should not also carry your address.
- Bytes live in
SwiftDataexternal storage — files alongside the store rather than blobs inside it, so a long history stays fast. - The schema has been versioned since V1 and no shipped version is ever edited in place. Four have shipped, each a lightweight migration: V2 added photo capture dates, V3 the tracked condition, V4 the remaining capture questions and shot conditions.
- Body-region identifiers are a stored contract — a shipped one is never renamed. An entry logged before sides existed still parses and still means what it meant; inventing a side for old data would be a lie in a health record.
- Lists show abstract tiles rather than photographs by default, so the app is safe to scroll in public without changing a setting.
From design exploration to a shipping app
It started as a design exploration — a working name, three dashboard variants, and nine screens argued out in the browser before any Swift existed. That stage was for settling questions cheaply: whether the history grid should be one hue or one per condition, whether streaks should exist at all, what a broken streak is allowed to say to you.
That exploration is still the best way to read the user story in one go, so it is kept whole and playable rather than described. Every screen, in the order a person meets them.
What survived became a written system — tokens, the rules above, the frozen mark — and then the real app. The production build is native SwiftUI with SwiftData underneath, and the values on this page are read out of it rather than reconstructed. A few things got better on the way: the figure went from an abstract diagram to real rasterised anatomy with independent left and right limbs, and heat became something clipped by the body's own silhouette so it spreads along a limb instead of stamping a rectangle on it.
A few decisions are still open, and it's worth saying so rather than presenting them as settled: whether the app should force dark rather than follow the system, what a clinic export contains, and whether the multi-colour mark stays multi-colour given the system's own accent rule.
Who built it
A two-person Circleheads build. I did the product: the user story, the whole front end, and the design language — the screen model, the body map, the capture flow, the tracking grid, the copy conventions, and the pixel brand art. The mark, tab icons, badges, figure and sprite are all drawn by one engine, which is why they hold from 14px to 512px with no assets.
Blaise built the back end — how photos are stored, processed and traced through the app: the image pipeline, the SwiftData schema and its migration plan, and the persistence layer underneath the log.
Swift · SwiftUI · SwiftData · iOS 17+ · zero external dependencies
Status
Working build with a real persistent store: photo slides, body-map region picking, the tracking heatmap, checkup nudges, entry detail, spot history, compare, condition detail, the badge shelf and onboarding. Four schema versions shipped. Still to come before release: edit-entry, reminders, more home-metric presets, and the app icon artwork.
Why this one matters to me
It is the same argument as the rest of my work, in a domain where the stakes are personal: the software does not tell you what is happening to your body. It keeps an honest record so that you, and the clinician you trust, can decide. Restraint is the feature — which is why the first onboarding card is called a record, not a verdict.