Contour typography

Text can become a contour object without ever stopping being text. The architecture is the Body Matter Interaction law: the element absorbs field matter; the visual layer shows what that absorption means; the semantic text remains the source of meaning. This page is the Contour Sink tier — the text/vector form of the sink contract.

The quick form — live text, stroked

For simple typographic outlines, keep the text live and stroke the glyphs. Selectable, accessible, zero tooling:

CSS
.title {
  color: transparent;
  -webkit-text-stroke: 2px currentColor;
  paint-order: stroke fill;
}

The vector form — generated glyph outlines

For true contour behavior the glyphs become vector paths — from any font the author applies to the body. The platform primitive is font-agnostic: Fundamental ships no parser (the zero-dependency rule); you hand contourSvgFor a parsed font — anything matching the ContourFont shape, which opentype.js satisfies directly — and it lays out the element's own text at its computed size, generates the ring SVG, and binds it:

Any font, at runtime
import { load } from 'opentype.js';            // or any parser — you bring the font
import { contourSvgFor } from '@fundamental-engine/platform';

const title = document.querySelector('#hero-title');   // your sink body, YOUR font
const font = await load('/fonts/your-font.woff');      // whatever face the element uses
contourSvgFor(title, font);                            // aria-hidden SVG, bound + mirrored

Prefer zero font work in the browser? Run the same primitive at build time and commit the output — this site does exactly that with its self-hosted face:

Build step
node apps/site/scripts/gen-contours.mjs   # the same primitive at build time — parses the site's face, commits the output

The generated SVG is a representation, never a replacement: it binds to its semantic source with data-field-visual-for, stays aria-hidden, and the platform mirrors the body's live feedback channels onto it (MIRRORED_CHANNELS — density, sink load, the measured metrics):

<h1 id="hero-title" data-body="sink attract" data-absorb="80" data-max="36" data-feedback>
  <span class="sr-only">Contour</span>
</h1>

<svg data-field-visual-for="hero-title" data-field-visual-role="representation"
     aria-hidden="true" focusable="false" viewBox="">
  <path class="ring ring-1" d="" />
  <path class="ring ring-2" d="" />
  <path class="ring ring-3" d="" />
</svg>

Live — the title is a sink; the rings are its readout

The heading below is a real sink attract body on the page field. The outlines are the generated paths. As the body gathers and captures matter, its mirrored --d and --load thicken and brighten the rings — hover and dwell to feed it.

Contour

--d 0.000 · --load 0.000

True offset contours — rings at a mathematically constant distance from the glyph boundary — need polygon offsetting (a Clipper-class pass, best done in the same build step). The rings here are stacked strokes of the one outline: the documented practical form.