Playground Experiments and short write-ups. Interaction ideas, small tools and side projects, each with the working version and what I learnt building it.
What do I owe people this week?
Claude · 8 lines sent · 1 step · 2.9s
Two things are yours: the revised timeline for the board, and the pricing page copy.
Yours
I'll send the revised timeline to the board
You · Q1 Product Planning
I'll rewrite the pricing page copy
You · Pricing review
Draft the emailPrep me for the pricing check-in
Claude · 12 lines sent · 3 steps · 3.3s
It's tomorrow at 10 with Alice and Sam. Sam owes you the churn model.
OCT 27Pricing check-in
Tue 10:00 · with Alice Moreau, Sam Okafor
S Sam Okafor
2 meetings · 2 open
How did our pricing thinking change?
Claude · 9 lines sent · 2 steps · 2.6s
You started out exploring a third tier and ended up keeping two.
How pricing changed
6 Oct Explore a third tier for teams over 20 seats6 Oct Annual discount stays at 25% for now20 Oct Keep two tiers, Personal and Team20 Oct Cut the annual discount from 25% to 15%What was said about shipping late?
Claude · 2 lines sent · 1 step · 3.0s
It came up in Q1 planning, when the launch moved to March 15.
“Honestly, I'd rather ship two weeks late than ship something we have to apologise for.”
Q1 Product Planning · 25 Oct
Open Q1 planningI turned Muesli's design system into a generative UI one, so Claude can build each chat reply as a layout.
Product Design AI SwiftUI · Oct 2026
Open → → Cursor.swift import AppKit import SwiftUI /// The last few seconds before a break, beside the pointer: a small ink /// disc with the seconds counting down in it. It's there so a break doesn't /// start without warning while you're looking nowhere near the notch. It /// follows the pointer from screen to screen, never takes clicks, and moves /// to the other side of the pointer near a screen's edge. @MainActor final class CursorCountdown: NSObject { static let size: CGFloat = 30 /// From the pointer's hotspot to the dial's centre, clear of the arrow. static let offset: CGFloat = 30 /// Room round the dial for its shadow. static let margin: CGFloat = 10 private let model = CursorModel() private var panel: NSPanel? private var link: CADisplayLink? private var pointer: NSPoint? private var generation = 0 /// Counts down to `until`. func show(until: Date) { // The clock ticks once a second, a fraction early or late; only a // real change moves the bead. if model.shown, abs(until.timeIntervalSince(model.until)) < 1 { return } generation += 1 model.until = until let panel = self.panel ?? makePanel() 0 : 3 2 0 9 8 7 6 Short break Try and look at a church spire Try and look at a crane Try and look at a bird Skip 0:0 8 7 6 5 4 3 2 1 0 Short break Look away for 30 seconds 5 more min 8 7 6 5 4 3 2 1 0
A small break timer for the Mac menu bar. Every 20 minutes it covers the screen for 30 seconds and suggests something to look at out of the window.
SwiftUI Interaction · Oct 2026
Open → → Over a hundred chunky, bold and slightly imperfect icons for my own tools, because most icon sets look the same.
Design Visual Design · Oct 2026
Open → → A small macOS menu bar player for NTS Radio, designed after Dieter Rams.
SwiftUI Interaction · Oct 2026
Open → → A digital business card with a relief of my face that moves when you tilt your phone. It took me three goes to get the relief right.
Dev Design Interaction Motion · Aug 2026
Open → → A tool with five ways of breaking an image down into a grid of marks. I also get into why some dithering methods flicker on video, and which ones I use for motion.
Dev Design Visual Design · Jul 2026
Open → → Rebuilding the trailing text from haha.services. It's basically a queue of points, one for each letter, and most of the work was in the spacing.
Dev Interaction Motion · Jul 2026
Open → → Shadows usually come from a light source that doesn't move, so I tried using the cursor as the light instead.
Dev Design Interaction · Mar 2026
Open → → Hover is either on or off. With proximity, elements change size and colour based on how far away the cursor is. I also look at how much it costs per frame.
Dev Interaction · May 2026
Open → → Water Shader A three.js water shader wired into a headless CMS. Mostly an excuse to see how far I could push a WebGL effect with Claude Code.
Dev Shaders AI · Jan 2026
Translating a picture-book illustrator's energy into a website. A real client, even if he is my dad.
Dev Brand · Jan 2026
Open → → WIP Refract A shader that moves with your voice, so the brand's visuals change in real time as you talk.
Shaders AI Motion Brand
Thoughts on the 'death of the canvas', and why the next design tool needs to hold both the canvas and the prompt.
AI Product Design · Apr 2026
Open → → JoeBot is basically a GPT wrapper, and it'll tell you that if you ask. This is about everything I had to build around it after someone found the first version and drained my OpenAI balance.
Dev Design AI
Open → → More coming soon!
Location
Based in London, working globally.
Back to top