Measure the real task

A page can load quickly and still feel slow when a person opens a menu, types into a search field, or submits a form. Initial loading is one part of the experience. The rest is a conversation between the user and a busy browser.

Start with the critical user journeys: find a service, inspect the product, read an article, send an enquiry. Define what immediate feedback looks like at each step. A button that shows a pending state promptly can communicate progress even while the server does slower work.

Interaction to Next Paint measures responsiveness across qualifying interactions. Treat it as a useful signal, then investigate the actual user task and device conditions behind the number. A synthetic lab run and field measurements answer different questions; neither should be mistaken for a universal guarantee.

Account for main-thread work

Rendering, event handlers, JavaScript evaluation, style recalculation, and layout compete for the main thread. Adding an animation does not just add download weight. It adds recurring work while the visitor is trying to interact.

For a decorative particle scene, our design budget is explicit: cap pixel ratio, reduce particle count on small screens, stop when the scene leaves the viewport, stop when the document is hidden, and respect reduced-motion preferences. Avoid moving thousands of DOM nodes. A single canvas is a better representation for thousands of decorative particles.

// A scheduler sketch, not a complete renderer.
let frame = 0;
let visible = true;
let paused = false;

function tick(now) {
  frame = 0;
  if (!visible || paused || document.hidden) return;
  renderScene(now);
  frame = requestAnimationFrame(tick);
}

function resume() {
  if (!frame && visible && !paused && !document.hidden) {
    frame = requestAnimationFrame(tick);
  }
}

This code needs lifecycle cleanup and visibility listeners in a real implementation. It also needs a static fallback when graphics initialization fails. The product’s content and contact paths should work independently of the renderer.

Ship less work

Rendering meaningful HTML on the server or at build time lets a browser show useful content before client scripts finish. A marketing page does not necessarily need a client-side application router, a global state store, or hydration for paragraphs and links.

Keep the interactive enhancement separate. Load the 3D renderer only where the scene exists. Reserve dimensions for imagery so the layout stays stable. Host the font files you need and avoid loading an entire family for one tiny label. These choices remove work before any micro-optimization begins.

A smaller bundle does not automatically mean better responsiveness. Parsing a compact script that performs expensive synchronous work can still block input. Inspect execution, style, and layout costs in a performance trace, then fix the largest relevant contributor.

Instrument with purpose

The PerformanceObserver API can expose supported performance entry types. Detect capabilities before observing them. Do not assume every browser produces the same entries.

const supported = PerformanceObserver.supportedEntryTypes;
if (supported.includes('longtask')) {
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      recordTiming({ type: 'longtask', ms: entry.duration });
    }
  });
  observer.observe({ type: 'longtask', buffered: true });
}

recordTiming represents your own privacy-conscious measurement pipeline. Send bounded timing data, not form contents or arbitrary DOM text. Long-task observation helps find blocking work, but it is not an INP implementation. Use a maintained Web Vitals implementation if you need the full metric, including its lifecycle rules.

Test the experience

Check a midrange phone, a narrow viewport, keyboard navigation, slow network conditions, and reduced motion. Test the page with scripts disabled. Submit an invalid form, simulate a server failure, and verify that a visitor can recover without losing their draft.

Use a performance budget as a decision tool: what work is necessary for the user’s task, and what is the cost of the decoration? Keep visual richness where it helps the experience. Remove recurring work where it competes with the user.

The goal is an interface that remains useful under imperfect conditions. Scores help diagnose it; the visitor’s ability to finish the task is the result.

Working on a problem like this?

We help teams turn architecture decisions into working software.

Talk to the studio