API reference
The FieldHandle
Every entry point — createField, mountField, the
FieldField class, the <field-root> element (proxied), and
the React onReady — hands you a FieldHandle. Use it to drive the
field after it mounts.
How you get one
Every entry point returns the same handle — pick the one that matches your stack. With the web component it's also proxied onto the element, so the element is the handle.
import '@field-ui/elements';
// the <field-root> element proxies the entire FieldHandle:
const field = document.querySelector('field-root');
field.setFormation('wells'); import { FieldField } from '@field-ui/react';
// onReady hands you the live handle once the field mounts:
<FieldField onReady={(field) => field.setPalette('heatmap')} /> import { createField } from 'field-ui';
const field = createField(canvas); // ← createField returns the handle
field.setRender('links'); Methods
-
scan() - Re-scan the document for [data-body] bodies after a DOM change.
-
rescan() - Alias of scan().
-
setAccent(hex) - Recolour the travelling accent.
-
setPalette(name | hex[]) - Swap the accent colour template live.
-
setFormation(name) - Switch the global formation.
-
setAttention(on) - Toggle conserved attention live (one finite strength budget).
-
setCausality(on) - Toggle cross-boundary causality live (density spills to neighbours).
-
setHeatmap(on) - Toggle the density heatmap layer live (a glow of where matter pools).
-
setRender(mode) - Switch the render mode: dots / trails / links / metaballs / voronoi / streamlines.
-
threads(list | null) - Wire glowing connector lines between an engaged set, or clear with null.
-
burst(x, y, hex?) - A one-shot shove + heat near a point, optionally tinting the matter.
-
destroy() - Stop the loop and release listeners.
On the element. When you use
<field-root>, these are proxied onto
the element itself — document.querySelector('field-root').setFormation('wells').
A worked example
Drive the field from your own code — recolour it, reshape it, thread engaged elements together, react to events, and clean up:
const field = document.querySelector('field-root');
// recolour + reshape the whole field at runtime
field.setPalette('infrared');
field.setFormation('accretion');
field.setRender('metaballs');
// glowing threads between engaged elements (real Element refs, not selectors)
const a = document.querySelector('#node-a');
const b = document.querySelector('#node-b');
field.threads([{ a, b, color: '#4da3ff' }]);
// a one-shot shove + heat at the cursor
addEventListener('click', (e) => field.burst(e.clientX, e.clientY));
// re-scan after a route change adds or removes [data-body] elements
field.scan();
// release the loop + listeners when you're done
field.destroy(); import { FieldField } from '@field-ui/react';
export function Background() {
// onReady hands you the same handle once the field mounts
return (
<FieldField
onReady={(field) => {
field.setPalette('infrared');
field.setFormation('accretion');
field.setRender('metaballs');
const a = document.querySelector('#node-a');
const b = document.querySelector('#node-b');
field.threads([{ a, b, color: '#4da3ff' }]);
addEventListener('click', (e) => field.burst(e.clientX, e.clientY));
}}
/>
);
} import { createField } from 'field-ui';
const field = createField(canvas); // the handle
// recolour + reshape the whole field at runtime
field.setPalette('infrared');
field.setFormation('accretion');
field.setRender('metaballs');
// glowing threads between engaged elements (real Element refs)
const a = document.querySelector('#node-a');
const b = document.querySelector('#node-b');
field.threads([{ a, b, color: '#4da3ff' }]);
// a one-shot shove + heat at the cursor
addEventListener('click', (e) => field.burst(e.clientX, e.clientY));
field.scan(); // re-scan after the DOM changes
field.destroy(); // release the loop + listeners