Getting started
Your first field
Eight short steps from npm install to a headline that gains weight and glow as
the field pools around it. Every step is runnable on its own — paste, save, watch.
1. Install
Pick the entry point for your stack. The rest of this tutorial uses the web component.
npm i @field-ui/elements npm i @field-ui/react npm i @field-ui/vanilla 2. Drop the field
One field lives behind your whole page. Register the element and drop a single
<field-root> — it mounts a fixed, full-viewport canvas and starts the
engine. Nothing reacts yet; there are no bodies.
<script type="module">
import '@field-ui/elements';
</script>
<!-- one field, behind everything -->
<field-root accent="#4da3ff"></field-root> import { FieldField } from '@field-ui/react';
export default function App() {
return (
<>
<FieldField accent="#4da3ff" />
{/* your app */}
</>
);
} import { mountField } from '@field-ui/vanilla';
// creates + manages a fixed full-viewport canvas, returns the handle
const field = mountField({ accent: '#4da3ff' }); 3. Add your first body
A body is any element with data-body. Mark your headline an
attract body and the field starts pulling matter toward it. Move the element and
the force moves with it — the engine re-reads its box every frame.
<h1 data-body="attract" data-strength="0.9" data-range="320">
field-ui
</h1> field.scan() once from onReady to pick them up.
// bodies are plain elements anywhere in your tree
<h1 data-body="attract" data-strength="0.9" data-range="320">
field-ui
</h1>
// React renders bodies after the field mounts — rescan once they're in:
<FieldField accent="#4da3ff" onReady={(field) => field.scan()} /> 4. Make the type react
This is the payoff. Add data-feedback and the field writes the density it
gathered back to your element as the --d custom property (∈ [0, 1], low-pass
filtered so it eases). Drive weight and glow from it — the word grows where matter collects.
<h1 data-body="attract" data-range="320" data-feedback>field-ui</h1>
<style>
h1 {
--d: 0; /* the engine eases this in, density ∈ [0,1] */
font-variation-settings: 'wght' calc(380 + var(--d) * 420);
text-shadow: 0 0 calc(var(--d) * 36px) rgba(77, 163, 255, var(--d));
}
</style> --d only enhances it; particles never assemble into letterforms.
5. Compose another force
Forces compose, space-separated. Add swirl and your headline now both pulls and
spins the matter around it. Each force reads only the attributes it uses —
swirl takes data-spin; attract ignores it.
<h1
data-body="attract swirl"
data-strength="0.9"
data-range="320"
data-spin="1"
data-feedback
>field-ui</h1> 6. Gate it on a condition
A force can act only when a condition holds, via data-when. Mark an
element data-hot so hover and keyboard focus set its engaged state, then gate the
force on active — it swirls only while the link is engaged.
<a data-hot data-body="swirl" data-when="active" data-spin="1" data-range="220">
hover me
</a> 7. Drive it from code
Every entry point hands you a FieldHandle. With the web component it's proxied onto the element, so you can reshape the field and react to events:
const field = document.querySelector('field-root');
// a global bias on every particle
field.setFormation('wells');
// a one-shot shove + heat at the cursor
document.addEventListener('click', (e) => field.burst(e.clientX, e.clientY));