Guides
The TypeScript wrapper
@fundamental-engine/vanilla is the framework-free door — a typed FieldField
class for plain TypeScript apps, with no custom element to register and no framework
dependency. It wraps the same zero-dependency engine the web component and React adapter do.
Install
npm i @fundamental-engine/vanilla The FieldField class
new FieldField() builds a fixed, full-viewport canvas behind your page and
starts the engine on it. It takes every FieldOptions value,
implements the full FieldHandle surface, and exposes the
canvas it runs on. Importing the package has no side effects — it never
registers a custom element.
import { FieldField } from '@fundamental-engine/vanilla';
// builds + manages a fixed full-viewport canvas, starts the engine
const field = new FieldField({ accent: '#4da3ff', render: 'dots' });
field.setFormation('wells');
field.burst(window.innerWidth / 2, 200);
// …later
field.destroy(); // stops the loop AND removes the managed canvas Drive a canvas you own
Pass your own <canvas> and the field never creates or removes one —
destroy() only stops the engine. Use this when you place and size the canvas
yourself.
import { FieldField } from '@fundamental-engine/vanilla';
// drive a <canvas> you place and size yourself — nothing is created or removed,
// and destroy() only stops the engine.
const field = new FieldField({ canvas: myCanvas, density: 1.2 }); mountField — the factory form
Prefer a plain function over a class? mountField() returns the bare
FieldHandle; its destroy() also removes the
canvas it made. @fundamental-engine/vanilla also re-exports a browser-wired createField (it injects browserHost() for you) for when you own the
canvas. The lowest-level engine entry is @fundamental-engine/core's createField
with an explicit host — see the core engine guide.
import { mountField, createField } from '@fundamental-engine/vanilla';
// the plain factory form — same managed canvas, returns the bare FieldHandle
const field = mountField({ render: 'trails' });
// or own the canvas entirely — this createField is browser-wired (host injected for you).
// The lowest-level engine entry is @fundamental-engine/core's createField with an explicit host.
const own = createField(document.querySelector('canvas'), { accent: '#2dd4bf' }); FORCES,
FORMATIONS, CONDITIONS, PALETTE) and the engine
contracts are re-exported, so a force picker or legend needs no second install.
These are the unguarded doors
Every entry in this package — FieldField, mountField,
createField — starts the engine at full cost and leaves it there.
<field-root> self-throttles: under sustained frame overrun its runtime
applies an adaptive quality tier automatically (capping the effective DPR, dropping the
heatmap), and it skips all draw work while the element is hidden. The vanilla doors wire
none of that — a full-viewport canvas here runs unthrottled, and a heavy one starves
the host page's own transitions and timers.
import { createField, FieldField } from '@fundamental-engine/vanilla';
// full-viewport canvas → cap the DPR (the dominant fill-rate lever; default ceiling 2)
const field = createField(canvas, { render: 'dots', dprCap: 1 });
// component-scale → contain the field, so the canvas only covers what needs it
const card = new FieldField({ bounds: document.querySelector('.card') });
// hidden or scrolled away → skip all draw work (signals stay live)
field.setVisible(false); dprCap, contain it with
bounds, or prefer <field-root> — and for the automatic
throttle on this path (the same QualityGovernor the element uses, wired by
hand), see createField is the unguarded
path in the performance guide.