PolyCSS Morph
@layoutit/polycss-morph is an imperative, framework-agnostic layer for models
whose geometry and paint resources are built ahead of time, then updated
through a stable DOM graph.
npm install @layoutit/polycss-morphUse the regular Polygon[] path when a mesh does not need prepared updates.
Use Morph when a model needs stable DOM elements plus morph targets, semantic
controls, springs, joint skinning, or prepared playback.
Package entries
Section titled “Package entries”The Node and browser dependency graphs are separate:
| Entry | Environment | Purpose |
|---|---|---|
@layoutit/polycss-morph/prepare | Node | Turn glTF/GLB sources into deterministic model packages with CSS triangle plans and browser fallbacks. |
@layoutit/polycss-morph | Browser or shared code | Validate, load, mount, and update prepared models. |
The Node preparer creates static-prepared and morph-regions models. Custom
tooling can create validated joint-skin and prepared-playback models.
Prepare
Section titled “Prepare”import { preparePolyMorphModel } from "@layoutit/polycss-morph/prepare";
await preparePolyMorphModel({ configPath: "./source/prepare.json", outputRoot: "./public/model/package",});Preparation writes resources before manifest.json. Re-running with
check: true verifies the complete existing inventory and bytes without
rewriting them.
Load, mount, update
Section titled “Load, mount, update”import { createPolyMorphDeformationRuntime, loadPolyMorphPackage, mountPolyMorphModel,} from "@layoutit/polycss-morph";
const loaded = await loadPolyMorphPackage("/model/");const mounted = mountPolyMorphModel(host, loaded.model, { resources: loaded.resources,});const deformation = createPolyMorphDeformationRuntime(loaded.model);const frame = deformation.sample({ tick: 0, morphWeights: { "pin-c06-r04-lift": 0.5 },});
mounted.apply({ leaves: frame.leafUpdates });The same imperative API is used from vanilla, React, or Vue applications.
Morph does not ship framework wrappers.
Prepared playback commits explicitly: apply sample.update, then call
runtime.commit(sample) only after mounted.apply(...) succeeds.
If an application already owns a retained DOM graph,
createPolyMorphPreparedDomTarget adopts its source-ordered model, shape, and
leaf elements as indexed write targets. Morph deduplicates requested values and
invalidates the writers at destroy; the application retains DOM teardown
ownership.
Example: Cube to sphere
Section titled “Example: Cube to sphere”This 768-polygon model from the three.js morph-target example exposes two prepared targets. Spherify moves the cube toward a sphere; Swirl applies the source twist target. Both sliders may be combined while the same DOM leaves remain mounted. Drag anywhere on the stage to orbit the model.
Loading model…
The page samples only when a slider changes. Geometry follows the slider directly; releasing it commits the nearest prepared lighting state with at most two ancestor custom-property writes:
const deformation = createPolyMorphDeformationRuntime(model);const mounted = mountPolyMorphModel(host, loaded.model, { resources: loaded.resources,});
function update(spherify: number, twist: number) { const frame = deformation.sample({ tick: tick++, morphWeights: { spherify, twist }, }); mounted.apply({ leaves: frame.leafUpdates });}Morph owns no scheduler. Applications decide whether weights come from direct input, state, an animation sampler, or a spring.
Profiles
Section titled “Profiles”| Profile | Behavior |
|---|---|
static-prepared | Retained rendering with no deformation. |
morph-regions | Sparse morph targets, semantic controls, springs, and clip channels. |
joint-skin | Hierarchical joint transforms and normalized weighted skinning. |
prepared-playback | Source-ordered retained model, shape, transform, visibility, opacity, and image-row changes. |
Runtime behavior
Section titled “Runtime behavior”Mount once, then sample and apply:
- the application owns input and timing;
- Morph owns no animation scheduler;
- leaf elements retain identity until teardown;
- unchanged samples perform no writes;
- sparse samples visit only affected leaves;
- runtime updates do not reconstruct topology or redraw prepared image resources.
Morph chooses the triangle paint path once when it mounts. It uses
corner-shape where available, a larger CSS border triangle in Firefox, and
each leaf’s prepared polygon-sized alpha-atlas slice in WebKit/Safari. Mount
uses the loader’s verified image bytes and revokes their object URLs at
teardown; the browser never refetches, generates, or redraws those pages.
Application ownership
Section titled “Application ownership”Morph owns the prepared model format and sparse DOM updates. Your application owns input, timing, presentation, model-specific preparation, and product behavior.