← Examples
Loose Threads

Notes on code, small apps and things made by hand.

A felt sun with a smiling face on a sunny windowsill next to a cup of tea
Featured

A felt sun for grey mornings

How a plush sun on the windowsill became the icon set for my smart-home dashboard, and why soft things make better buttons.

Continue reading

Reading

Reading slowly, on purpose

12 September 2026

A short book about doing one thing at a time, read one chapter per evening.

Book cover: a moon and stars cut from felt

From the workbench

Sewing a stylesheet from felt

3 October 2026 · Robert · 6 min read

For years every little app I built looked like every other little app. This summer I tried something different: what if the buttons looked like they were cut from wool and sewn on by hand?

It started as a joke on a rainy Sunday. I had photographed a scrap of grey felt for a birthday card, and on a whim I dropped it into a stylesheet as a background on a primary button. It looked ridiculous. It also looked warm, and I couldn't stop smiling at it.

Two kinds of felt

The trick that made it work was to stop treating every surface the same way. Real felt comes in two moods, and so does the stylesheet:

  • Patches are the saturated pieces: buttons, badges and the coloured tiles on my dashboard. They get a soft cut edge and a little shadow.
  • Sheets are the quiet, cream-coloured surfaces: the page, cards and alerts. Flat, calm, and easy to read on.

Keeping those apart is what stops the whole thing from turning into a craft-fair explosion.

Buttons, cards and form controls in the felt look
The first page that looked right: buttons, cards and form fields, all cut from the same sheet.

The seams are real thread

The stitches around each card come from a single photo of a running stitch, cut into a nine-slice frame. A blend mode tints the thread to match whatever it is sewn onto, so it is always a shade lighter on colour and a shade darker on cream.

Make it soft enough that people want to touch it, and plain enough that they still know where to click.

Nothing moves

My one hard rule: switching between the felt look and the clean look must not move a single pixel. Felt only changes colours, textures, shadows and seams, never padding or fonts. In practice that means every felt rule lives in its own cascade layer:

@layer felt {
  :where([data-look="felt"]) .btn-primary {
    background-image: var(--felt);
    background-blend-mode: soft-light;
  }
}

Because the selector is wrapped in :where(), it has no specificity at all, and anything you write yourself wins. Press Ctrl + R with ?look=clean in the address bar and the same page comes back in plain cotton.

What I'd do again

  1. Start with one component and live with it for a week.
  2. Photograph real materials instead of drawing textures.
  3. Check contrast in dark mode before falling in love with a colour.

Earlier posts