Integration handbook

Enhance an interface from one application boundary.

Install Formation, Kinetic, or both. Keep your existing HTML and framework components. DYNT adds construction and physical response without replacing application semantics.

2 independent engines9 Formation profiles4 cell geometries3 integration paths
01 · Mental model

One boundary, ordinary HTML, optional behaviors.

DYNT is not a component library and does not require every card, button, or section to import an engine. Initialize an engine against an explicit root, provide a selector, and matching elements inside that boundary become managed surfaces.

Existing applicationRoot + selectorFormationKineticSame semantic HTML
The engines remain independent.

@dynt/formation never imports Kinetic, and @dynt/kinetic never imports Formation. Install only what the interface needs.

PackageOwnsUse it when
@dynt/formationConstruction geometry, viewport travel, reveal, withdrawalSurfaces should visibly form and deconstruct
@dynt/kineticTilt, drift, waves, cell geometry, impact, content responseSurfaces should physically respond to input
@dynt/reactReact mount and cleanup lifecycleYour boundary is owned by a React component
@dynt/web-componentsCustom-element connection lifecycleYou want a declarative framework-neutral host
02 · Installation

Choose the smallest package set.

Formation only

npm install @dynt/formation

Kinetic only

npm install @dynt/kinetic

Both engines

npm install @dynt/formation @dynt/kinetic

React adapter

npm install @dynt/react @dynt/formation
# or @dynt/kinetic

Import the stylesheet belonging to every installed core engine once at the application entry point or shared layout.

import '@dynt/formation/styles.css';
import '@dynt/kinetic/styles.css';
03 · Boundary setup

Start with one root and one selector.

The root may be a Document, DocumentFragment, ShadowRoot, or HTML element. The selector is evaluated only inside that root. Matching the root itself is supported.

const root = document.querySelector('#app');

const kinetic = createKinetic({
  root,
  selector: 'section, article, button, [data-dynt-surface]',
  exclude: '.third-party-widget',
  observe: true
});
1Choose a stable boundary. A layout root or feature shell is better than initializing every component.
2Select meaningful surfaces. Start narrow, then widen the selector after checking ownership.
3Exclude foreign UI. Use data-dynt-ignore or an application-specific exclude selector.
04 · Formation

Construction is a reversible lifecycle.

Formation can send transient lines from viewport edges, acquire targets in sequence, construct permanent geometry, reveal content, and reverse the same choreography during withdrawal.

import { createFormation } from '@dynt/formation';

const formation = createFormation({
  root: document.querySelector('#app'),
  selector: '[data-dynt-surface]',
  profile: 'line-push',
  observe: true,
  viewportFlow: {
    duration: 1160,
    stagger: 110,
    lineLength: 680,
    overrun: 36
  },
  tokens: {
    duration: 380,
    lineColor: '#ffbf00',
    lineWidth: '1px',
    overflow: 14
  }
});

formation.withdraw();
formation.form();

Lifecycle phases

unformedlocatingconstructingenclosedrevealingformedwithdrawingdeconstructing

Subscribe when application logic needs to observe the phase. Do not use fixed timers to guess when construction completed.

const unsubscribe = formation.subscribe(({ element, phase }) => {
  if (phase === 'formed') element.dispatchEvent(new Event('ready'));
});

// Later
unsubscribe();

Built-in profiles

line-push, line-rise, arc-trace, squircle-sweep, chamfer-fold, magnetic-segment, radial-compass, aperture-iris, and elastic-membrane all share the same controller contract.

05 · Directional Tilt

Separate contact response from waves.

Tilt is pointer-position driven. The near side compresses, the opposite side rises, an opposing shadow reinforces depth, and locally owned content can travel through its own bounded channel. Hovering does not create cell geometry.

import { createKinetic } from '@dynt/kinetic';

const tilt = createKinetic({
  root,
  selector: '[data-tilt-surface]',
  effects: {
    tilt: true,
    content: true,
    wave: false,
    drift: false
  },
  motion: {
    maxTilt: 1.35,
    response: 0.18,
    contentTravel: 3
  }
});
Use larger values only for demonstrations.

1.35deg is the restrained preset baseline. Higher values make the mechanism easier to teach but should be validated against real content before production use.

Mark a custom content group with data-dynt-reactor. Kinetic moves the group with CSS translate and leaves the host element's application-owned transform untouched.

06 · Waves and cells

Render cell geometry only while a wave is active.

A click or programmatic impact creates a circular front from the real input location. Coherent turbulence bends the front while speed, thickness, recovery, intensity, and growth remain independently configurable.

const wave = createKinetic({
  root,
  selector: '[data-wave-surface]',
  effects: {
    tilt: false,
    content: true,
    wave: true,
    drift: false
  },
  cells: {
    shape: 'hexagon',
    size: [22, 18, 14],
    colorMode: 'gradient',
    colors: ['#143447', '#1686bd', '#8de1ff']
  },
  flow: {
    speed: 1,
    thickness: 1,
    recovery: 1.1,
    intensity: 1.2,
    turbulence: 0.42,
    multi: true,
    maxWaves: 3,
    maxCells: 420
  }
});
GeometryVisual behaviorUseful for
SquareRegular rectilinear field with configurable gapStructured dashboards and data surfaces
HexagonConnected staggered honeycombContinuous material-like propagation
CircleSeparated radial cellsMaking curved wave fronts easy to read
DiamondConnected interlocked tessellationEmphasizing directional movement

Three-level cell sizing

The size tuple is [section, card, nested]. Nested managed surfaces inherit the next level, capped at level three. The site demonstrations use the finer [22, 18, 14] hierarchy so cells remain precise inside cards.

// One target can override the resolved setting.
element.dataset.dyntCellShape = 'circle';
element.dataset.dyntCellSize = '18';

// Or use CSS.
element.style.setProperty('--dynt-cell-size', '18px');
07 · Combined operation

Compose through shared DOM state, not package imports.

Initialize both engines against the same root and selector. Formation owns construction state. Kinetic observes the Formation phase marker, rests while a target is not formed, and resumes input after formation completes.

const options = {
  root: document.querySelector('#app'),
  selector: '[data-dynt-surface]',
  observe: true
};

const formation = createFormation({
  ...options,
  profile: 'line-push',
  viewportFlow: true
});

const kinetic = createKinetic({
  ...options,
  ...kineticPresets.structural,
  cells: { size: [22, 18, 14] }
});

Destroying either controller leaves the other operational. Shared ownership records prevent duplicate decoration and restore application state only after the final owner releases a target.

08 · Dynamic interfaces

Scroll loading, route changes, and inserted cards are supported.

Set observe: true when matching elements may appear later. Mutation records are batched. New matches are enhanced, removed elements are restored, and targets that become excluded are released.

const kinetic = createKinetic({
  root,
  selector: '[data-dynt-surface]',
  observe: true
});

// Added later by React, a router, or an IntersectionObserver.
root.append(newSurface);

// Optional explicit reconciliation.
const adopted = kinetic.refresh();
Lazy rendering does not require per-component setup.

As long as the new element enters the observed boundary and matches the selector, the existing controller adopts it.

09 · Framework adapters

Thin lifecycle helpers, identical engine behavior.

React

import { useRef } from 'react';
import { useKinetic } from '@dynt/react/kinetic';

export function AppShell() {
  const rootRef = useRef<HTMLElement>(null);

  useKinetic({
    rootRef,
    selector: '[data-dynt-surface]',
    observe: true,
    cells: { size: [22, 18, 14] }
  });

  return <main ref={rootRef}>{/* existing tree */}</main>;
}

Use useFormation from @dynt/react/formation for Formation. Memoize object and array configuration when it should remain stable across renders.

Web Components

import { defineKineticElement } from '@dynt/web-components/kinetic';

defineKineticElement('dynt-kinetic-root', {
  selector: '[data-dynt-surface]',
  observe: true
});
<dynt-kinetic-root>
  <article data-dynt-surface>Existing semantic content</article>
</dynt-kinetic-root>
10 · Themes

Use CSS channels for dark and light surfaces.

Application themes can provide local line, fill, cell, and surface colors. Keep contrast appropriate for both the surrounding UI and transient geometry.

:root {
  --dynt-line-color: #ffbf00;
  --dynt-kinetic-color: #64c6ff;
}

[data-theme='light'] [data-dynt-surface] {
  --dynt-line-color: #8f5d00;
  --dynt-kinetic-color: #0076a8;
}

Controller tokens, selector groups, and target-local data attributes can override the global theme. Target-local configuration has final priority for supported channels.

11 · Operations and cleanup

Pause, update, reconcile, and destroy deliberately.

Controller actionPurpose
refresh()Reconcile current selector matches and return the number newly enhanced
update(...)Change supported configuration without rebuilding managed elements
pause() / resume()Suspend Kinetic input and return surfaces to rest, then resume
impact(target, input)Start a bounded Kinetic response at normalized coordinates
form() / withdraw()Run Formation forward or in reverse for one target or the full set
destroy()Remove owned listeners, observers, layers, timers, frames, styles, and markers
// Route or application boundary teardown.
kinetic.destroy();
formation.destroy();

destroy() is idempotent. Application-owned classes, attributes, inline properties, and priorities are restored exactly after the final controller releases each target.

12 · Accessibility and budgets

Motion remains decoration; semantics stay application-owned.

  • Decoration layers are hidden from assistive technology and never receive pointer events.
  • Links, buttons, inputs, names, values, focus order, and keyboard behavior remain native.
  • prefers-reduced-motion: reduce skips Formation travel and removes Kinetic tilt, drift, and waves while preserving meaningful state.
  • Kinetic uses one controller scheduler, caps active surfaces, limits wave cells, and performs no continuous animation work while idle.
  • Do not use motion or line color as the only indication of required information.

Read the complete accessibility contract and performance budgets.

13 · Troubleshooting

Check the boundary before tuning the effect.

SymptomCheck
A late-rendered section is not enhancedConfirm observe: true, the element is inside root, and it matches selector
A nested card reacts with its parentMake the nested card a managed surface; deepest matching ownership receives input
Cells look too large inside cardsUse a three-level size such as [22, 18, 14] or a target-local size override
Tilt is difficult to noticeVerify effects.tilt, use content response, and test at a temporary demonstration value before selecting a restrained production value
Wave appears on hoverHover should leave the canvas clear; inspect application CSS or confirm the active package version
A third-party widget is decoratedAdd data-dynt-ignore to its boundary or include it in exclude
Motion persists after unmountEnsure the owning boundary calls destroy() or uses the framework lifecycle adapter
Need the typed surface?

Continue to the complete API reference, composition guide, and repository troubleshooting guide.