Skip to content
TF
All projects
Demo2026

Tideline

Group trip planning built around a vertical timeline that draws the time you have not planned yet.

TypeScriptReact NativeExpoPostgreSQLSupabaseTanStack QueryCloudflare Pages

Group planning happens in a text thread, and a text thread is the worst possible shape for it. Times get restated six times, half the decisions are implicit, and the thing nobody can see is how much unscheduled time is actually left. Calendars do not help, because a calendar draws what you have committed to and leaves the gaps blank.

Tideline draws the gaps. The core screen is one day at a time on a vertical hour grid, blocks sized to how long things really take, and the empty stretches between them rendered as first-class objects you can tap and fill. That inversion is the whole product. It is built accessibility-first for ADHD and autistic users, which in practice means one day on screen at a time, explicit over implicit, and no arithmetic asked of the reader.

The interesting engineering is the layout engine and the timezone discipline around it. Days belong to the event, not to the device, so an activity at 11pm in Reykjavik is Wednesday for everyone looking at it regardless of where they are sitting. Activities that cross midnight are split across both days and flagged. Unplanned time is derived on every render from the confirmed blocks, never stored, and a proposal deliberately does not count as occupying time, because a maybe is not a plan.

The demo is a separate build of the same codebase with no database, no account and no network. The seed lives in memory, so a visitor can add an activity or fill a gap and reloading puts it back. Every date in it is computed at load rather than written down, so it never reads as abandoned.

Details worth knowing

  • 01Pure layout engine with 54 unit tests covering DST boundaries, half-hour and 45-minute timezone offsets, midnight-crossing activities, and gap computation across overlapping blocks.
  • 02Found two row-level security bugs that made creating an event impossible in production: a policy that recursed into its own table, and a SELECT policy that rejected the creator's own INSERT ... RETURNING. Both had been live since the first migration and neither showed up in a typecheck or a build.
  • 03Migrations are rehearsed against a throwaway Postgres in Docker, then against production inside a transaction that is rolled back, because the project has exactly one database and a live page reading it.
  • 04A build-time audit fails the pipeline on any project ref, JWT or access token found in the public demo bundle. It exists because the first demo build shipped a live key, inlined by the bundler from an env file loaded behind the build script's back.
  • 05End-to-end smoke tests drive headless Chrome over the DevTools Protocol with no test dependencies, and run against the built artifact under production routing rules rather than the dev server, which hides the rewrite rules that turn every deep link into a 404.