Felix AnderssonSenior Fullstack Engineer, home

Montevideo

Résumé
All work

04 / 07

LifeUI

A HUD for real life: plan the day in time blocks, run one activity at a time, and close each one with a single honest moment.

Role
Solo: product, design system, frontend and tests
Year
2026
Interface
English and Spanish, light and dark

The story

The story

Not a todo app, not a habit tracker, not a time tracker. You keep a library of repeatable activities, drop them into the day’s time blocks, and run one at a time. Each one ends in a closing ritual: rate it from 0 to 10 and earn tempos. Tempos only go up. No streaks, no penalties, and free time costs nothing.

This year I rebuilt the whole interface from scratch to the standard of a tool like Linear, on top of a domain core that doesn’t know React exists. CI runs typecheck, lint with zero warnings, Jest, the build and Cypress on every push.

In the screenshot
LifeUI Today screen: Read has just started from a quick-start chip, 157 tempos today at 157% of the daily reference, the day plan by time blocks, and a log where Write report was just closed at 9 out of 10 for 78 tempos.LifeUI Today screen: Read has just started from a quick-start chip, 157 tempos today at 157% of the daily reference, the day plan by time blocks, and a log where Write report was just closed at 9 out of 10 for 78 tempos.
  1. Only one activity runs at a time, with its progress against its estimate or timebox.
  2. Tempos today, shown as a share of your reference: an anchor, never a debt.
  3. Quick start for pinned activities. Everything has a shortcut and a command palette.

Engineering

Three things worth a closer look

  1. 01

    A core that doesn’t know React

    Immutable state, subscriptions and managers in plain TypeScript. The UI reaches it through one adapter, and tests drive a real core instead of mocks.

  2. 02

    Versioned persistence

    Every load goes parse, validate, migrate through schema v1, v2 and v3, then sanitize. Legacy fields are archived rather than dropped, and JSON import runs through the same path.

  3. 03

    The preview is the result

    The closing dialog calls the same reward function as the core, so the tempos you see are the tempos you get. The typed i18n layer makes English and Spanish keep exactly the same keys.

  • React 18
  • TypeScript (strict)
  • Vite
  • Tailwind with CSS-variable tokens
  • Radix UI
  • Jest
  • Testing Library
  • Cypress
  • GitHub Actions

More screens from LifeUI

Select a screen to enlarge it

A day in 39 seconds
Closing ritual
Review
Library
On a phone

Build sheet

Stack
React 18, TypeScript (strict), Vite, Tailwind with CSS-variable tokens, Radix UI, Jest, Testing Library, Cypress, GitHub Actions
Scale
  • 158 commits
  • 257 tests (Jest and Cypress)
  • 44 components
  • Light and dark
Typefaces
  • Inter
Palette
#FCFCFD#16161A#5854D6#F59E0B#148054