Skip to content
glyphcss

Fix fluid worker, colour, alignment and reader problems

Start with fluid.stats(): it says which pipeline runs ("worker" or "main"), the encoding, the frame cap, the grid and how many vsyncs were skipped.

console.log(fluid.stats());
// { fps: 60, pipeline: "worker", encoding: "atlas", cols: 144, rows: 66, frames: 812, stalls: 3, stepMs: 3.5, lit: 4210 }

pipeline: "main" means the worker never started or failed.

  • Your bundler did not emit worker.js next to the package’s dist/index.js. Pass a factory: in Vite, import FluidWorker from "@glyphcss/fluid/worker?worker" and worker: () => new FluidWorker().
  • A Content Security Policy blocks workers: allow worker-src for your bundle’s origin (or blob: if your bundler inlines workers).
  • prefers-reduced-motion: reduce is set: reduced motion always runs on the main thread (it draws only settled stills).
  • worker: false was passed.

encoding: "plain" means the atlas font did not load or the browser lacks font-palette (Chrome 101+, Safari 15.4+, Firefox 107+). The fluid then draws real braille in one colour. Check the network panel for the atlas font request and any CSP font-src rule. encoding: "mono" is one colour by choice.

  • The element moved without a resize the fluid could see (an animation, a collapsing sibling, a late image): call fluid.relayout().
  • With glue: "document" the host must be a fixed, viewport-sized layer (position: fixed; inset: 0); the fluid follows the page scroll by whole rows.
  • Web fonts: targets re-measure when document.fonts.ready resolves. A font loaded later by other means needs relayout().
  • The grid shears or columns drift: the <pre> must use the fluid’s own font settings; don’t override its font-family, letter-spacing or line-height from page CSS.

The governor drops to 30 for the session after a 60-frame window with more than 20 % missed vsyncs. That usually means the main-thread pipeline on a slow device (measured: about 20 % misses at a ×4 CPU throttle). Make sure the worker runs, reduce grid.targetCols, or set fps: 30 up front. fpsFallback: false keeps 60 regardless.

  • Use the default look: "plain": real letters, legible at 600 wpm. In look: "glyph" each word is a target the ink has to flow into; at high wpm short words leave before they settle, and long words are drawn smaller (each word is sized to fit the host).
  • Plain letters still scrambling (.:-=): the ink under them has not arrived yet. It pools in a band shared by consecutive words, so this only shows at a sentence start or on a much longer word; lower wpm if it bothers.
  • Give the host room: the letters scale with the host’s width; a host under about 240 px wide makes them small (glyph look: few cells tall). Plain letters need at least 3 rows of height (about 40 px at 416 px wide): the fluid never inks its border rows, so a thinner host has nowhere to pool.
  • Keep the default 52-column grid: denser grids make smaller dots, not sharper letters.
  • Under reduced motion each word is a single settled still, by design.
  • The host has no size: the grid comes from its box (glue: "host"). Give it a width and height.
  • clock: "manual" draws only on fluid.step(dt).
  • The reader’s text is empty or whitespace: the clock has no words and never starts.