← Back to blog

Focus Desk: from a single brief to a working focus workspace

How to quickly conceive, build, and verify a lightweight web demo with a pomodoro timer and task list using Clidex.

Try the demo ↗

Try it first

Open the Focus Desk Demo, write down a small, concrete action to complete today, and click “Start Focus”. Tasks and session counts stay stored locally in your browser.

How I framed the brief

I combined the goal, the primary user journey, and technical constraints into a single prompt:

Create the focus-desk static web demo. Built for individuals who need quiet, distraction-free work. The flow consists of adding tasks, starting a 25-minute focus session, and incrementing completed sessions upon finishing. Use vanilla HTML, CSS, and JavaScript with no backend; persist state with localStorage. Visual style: off-white paper tones, deep ink typography, and neon lime accents, with dark mode and mobile responsiveness. Verify the timer, form submission, reload persistence, and narrow-screen layouts.

This brief directly dictated the layout, palette, and interactions of the demo. I then followed up by asking it to inspect touch targets on smaller viewports, text wrapping, and horizontal overflow before fine-tuning the CSS.

What you will see in action

Type in a specific action like “Proofread draft v3 of contract” and click start to begin a 25-minute focus block. Finishing a session immediately increments today’s rhythm count and advances the progress bar. Completed tasks get crossed out with a strikethrough, dark mode provides a comfortable nighttime interface, and modules stack into a single column on mobile devices.

Start with a small need

This demo intentionally omits user accounts, historical analytics, and OS notifications. It is meant to quickly validate whether pairing tasks with structured focus intervals fits your personal workflow. You can easily adapt the code, tweak the titles, change daily goals, or customize the palette. When writing your brief, clarify who it is for, the shortest user flow, technical boundaries, and how to verify results before testing the page directly.

If you also want to turn ideas into working pages, read our guide on writing a clear brief before your first demo.

Define the experience before picking the stack

I began with the shortest viable user journey: add a task → click start → finish focus block → record completion. Every visual cue and architectural choice served this linear path.

The interface is structured as a single page. On the hero screen, a circular countdown timer sits on the left with an inspiring note on the right; below them lie the task list and session metrics. The timer serves as the focal anchor, immediately followed by the task input, eliminating the need to toggle between sidebars, modal dialogs, or multiple tabs.

Technically, vanilla HTML, CSS, and JavaScript were chosen over heavy frameworks. The priority for this demo is legibility, portability, and zero build overhead: drop the three files onto any static file server and it runs immediately. Application state is equally disciplined, tracking only four variables: seconds, running, tasks, and sessions.

Visual design decisions

The interface employs warm off-white canvas tones, paper-like cards, and neon lime highlights—reminiscent of a physical memo sitting on your desk. Rounded cards delineate independent modules, while crisp 1px borders replace heavy drop shadows to steer clear of generic dashboard aesthetics.

Headings use large display typography with tight letter spacing, creating a calm yet memorable brand presence. Supporting copy relies on muted grays and looser leading to minimize visual noise. Dark mode simply alters CSS color variables without shifting layout geometries, making late-night focus comfortable.

On mobile screens below 700px, the grid collapses into a single column: the timer keeps prime real estate, while note cards and analytics flow naturally below. Touch targets for buttons and form inputs adhere to standard touch sizes, and task text wraps naturally to prevent horizontal scrolling.

How the timer works

The countdown timer relies on seconds as the single source of truth, decrementing each second:

let seconds = 1500;
let running = false;

function tick() {
  seconds -= 1;
  renderTime(seconds);
  if (seconds <= 0) finishSession();
}

Clicking “Start Focus” establishes a setInterval, while clicking again clears the interval and pauses execution. Resetting stops the countdown, restores the clock to 25:00, and switches the button label back to “Start Focus”. When a block reaches zero, the completed session count increments by one and the timer automatically resets for the next round.

I deliberately avoided splitting the timer into an elaborate state machine—the flow only involves start, pause, reset, and complete. A concise data model keeps ongoing tweaks and future extensions straightforward.

Task list and local persistence

Each task object carries only two fields: text and done. Submitting the input trims whitespace and appends the item to the list; toggling the checkbox updates the corresponding index and re-renders the list.

localStorage.tasks = JSON.stringify(tasks);
const tasks = JSON.parse(localStorage.tasks || '[]');

localStorage enables a true serverless, backend-free experience. It is ideal for lightweight local capture on personal machines and proves that state survives browser refreshes. A production-ready app would naturally require cloud account sync, export options, and privacy disclosures, but those were intentionally left out of this first demo.

Turning feedback into rhythm

The stats card tracks completed focus blocks, mapping them onto a four-block daily target bar. This target is not meant as a rigid productivity quota, but rather as subtle, satisfying visual feedback: completing a session immediately updates the UI, reinforcing momentum through visible accumulation.

Progress displays as completed / total, accompanied by crossed-out strikethrough text and lowered contrast in the list. State changes only repaint necessary nodes, avoiding disruptive page reloads or modal alerts that break concentration.

Verification and boundaries

I used npm run build to verify that blog content and static assets build correctly with Astro, ensuring the /en/blog/focus-desk/ route is generated properly. The demo itself requires no dependencies and can be launched directly in any modern browser. Verification covered timer cycles, form submission, checkbox states, theme switching, and data recovery after reloads on both desktop and mobile viewports.

This iteration features three distinct boundaries: the timer relies on the tab remaining open, stats stay scoped to the current browser, and session completion does not trigger audio chimes or system notifications. Each of these can be enhanced independently without interfering with the core user flow.

What comes next

First, introducing short and long break cycles, signaled by dynamic page titles and subtle color shifts. Second, logging historical trends so session counts evolve into an inspectable rhythm over time. Third, adding keyboard shortcuts and desktop notifications so users receive completion alerts even when working in other application windows.

This demo serves best as a fertile starting point: make a single action completely functional, then incrementally expand capabilities based on actual usage. For personal tools, less setup almost always translates to faster execution.