Skip to content

Motion and texture

5 min read · Updated 2 Nov 2026

This page belongs to Data App developer guide. It covers the small amount of movement and texture that can give an app character without competing with the data. All of it is optional: choose it when it suits the app’s subject and reader.

An ambient layer is one quiet decorative layer that stays in sight and is never functional: in the header, and where the layout leaves whitespace, behind the page. An app does not need one. If it suits the subject and reader, choose it first, then add nothing else unless the app earns it.

  • Header. The header is sticky, so a decorative layer inside it stays visible while the page scrolls. Use a shader, emitter, aurora or edge light from Navigation.
  • Whitespace. Put one layer behind the whole page, in the gutters and empty areas, and keep every card on a plate above it. Use an aurora, an emitter, or a slow mesh shader.
  • One layer per surface. A moving header and a moving page background together should read as one atmosphere: same palette, similar speed, never competing.

Leave it out when a restrained result is requested, or on a dense operational view where it adds nothing.

  1. Data is the loudest thing on the page. Motion and texture sit behind or beside data, never under a line, bar or number. Put content on a plate (frosted or opaque) above any texture.
  2. Decorative only. Motion never carries information, is not interactive and is hidden from assistive technology. Do not simulate live status.
  3. Low contrast in both themes. Define a texture palette per theme from the page and surface tokens, and check light and dark: a texture that is calm in one is often loud in the other.
  4. Always a designed fallback. Paint a plain gradient from theme tokens first and fade the effect in over it, so no WebGL, reduced motion, a slow device or a load delay still looks intended.
  5. Cost nothing off screen. Mount GPU and canvas effects only while visible and unmount them after. Prefer CSS and SVG for anything that is not a texture.
  6. Calm timing. Interaction under 400 ms with a gentle spring. Ambient loops 4 s or longer. Animate transform and opacity only. Stop loops under reduced motion and show the final frame.
  7. Keep effects off the content. Fade a header layer out before the controls it sits behind, and keep a highlight on a tile’s border, not behind its figures.

Treat navigation motion as two independent pieces and combine one of each. Choose by navigation type; it differs per app.

Navigation type Indicator (what moves) Decorative layer (optional, one)
Top bar Sliding underline, or a pill that follows hover Mesh or grain shader, emitter, or aurora
Side rail Gliding active bar Edge light travelling down the rail; breathing logo mark
Tabs and segmented Sliding underline with sheen, or a resizing thumb None
Drill-down Breadcrumbs cascading in on route change None

Reserve the dithering strip for deep-tech or engineering subjects, where its retro-technical feel fits the data; it reads as noise elsewhere.

Use Options Cost
Behind a KPI row Mesh gradient, grain gradient, warp, or a CSS gradient GPU, or none
Behind a chart Dot grid (static); dithering (deep-tech only) GPU
Tile highlight Conic border, breathing glow none (CSS)

Not recommended: orbiting dots and contour-wave textures, which compete with data, and a pulsing border that shades the inside of a tile.

These are references, not requirements; the CSS and canvas options need no library.

Library Use for Notes
Paper Shaders Mesh, grain, warp, dot grid, dithering backdrops Apache-2.0. Measure the bundle size in your build.
No library (hand-written GLSL) A page or header backdrop Illustrative guidance, not a shipped implementation: a small fragment shader on a full-screen canvas, with glows and faint rings tinted from the theme tokens. Render below full resolution, limit the frame rate, and under reduced motion show a static frame. No dependency to install or version.
Canvas UI Effects on live HTML Needs an experimental browser flag today; do not depend on it in a shipped app.
Better Design Design-guidance MCP for assistants Setup writes assistant configuration and creates a key; read the vendor’s setup guidance first and opt in deliberately.

Small touches that make a first build look finished. Each one stops under reduced motion or is static to begin with.

  • Figures count up once on first load, using requestAnimationFrame and Intl.NumberFormat, and show the final value immediately under reduced motion. Use font-variant-numeric: tabular-nums on every figure so digits do not jitter.
  • Charts reveal, not pop. Fade the chart’s wrapper in with opacity and transform, never the chart host, and gate that transition with prefers-reduced-motion: no-preference. Let the chart grow its bars from their baseline. Run it once, on first paint, never on every filter change. Charts do not read prefers-reduced-motion; read it in your app and send { enabled: false } through setAnimationEnabled to turn off chart animation.
  • Skeletons before data. Show the card’s final frame with a faint shimmer while a query runs, so the layout does not jump. See Loaders.
  • Frosted plates over a backdrop. A translucent card with backdrop-filter: blur() and a hairline border keeps figures legible over a shader; fall back to an opaque surface where it is unsupported.
  • Visible focus. Give every control a :focus-visible ring from the accent token, in both themes.

Build with the logo of the thing being built and use it as the favicon. If none is supplied, use a simple glyph that matches the data’s subject as the favicon and tell the user it is a placeholder. A placeholder does not need a place in the page.

An App Builder app has no HTML file of its own, so add the icon from script, as Account review does.