Displaces every point of a host with a GPU kernel you write inline in WGSL — the escape hatch for any per-point deformation the built-in point-constraints don't cover.
JavaScript API:
CustomWGSLPointConstraint
This is the fully-programmable member of the PointConstraint family: like
every point-constraint it runs a GPU kernel over all of a host's points at once (a
mesh, a spline, or a sk-cloner). What is unique here is that you supply
the kernel body: the engine owns the scaffold (world-space sampling, the
field-weight range, per-target buffer I/O) and calls your computeDisplacement()
for each point, plus an optional computeGradient() when the result should also
recompute normals.
Key attributes. wgsl holds the kernel source — at minimum a
computeDisplacement(worldXZ) function returning a world-space offset. Its tunable
parameters come from sk-wgsl-uniform elements attached to it, read inside
the kernel through generated skUniform_<name>() accessors, so each is independently
animatable. affects-normals turns on the computeGradient() path so shading and
cloner orientation follow the deformed surface. max-displacement reports the
kernel's worst-case travel so bounds stay correct. It is the per-point cousin of
sk-compute-node, which produces whole output buffers that
compute-buffer sources consume by reference.
Related. For a ready-made wave there is
sk-ocean-displacement-point-constraint; for field-weighted
translate/scale/rotate there is sk-simple-point-constraint. Its single-node
CPU analogue is sk-field-constraint.
Serve these docs to run the live example.
WebGPU needs a secure context — open this page via grunt serve
rather than double-clicking the file. The Markup tab works from disk.
<!-- A custom GPU displacement kernel: `wgsl` provides computeDisplacement()
(plus computeGradient() so normals follow the surface), and the
<sk-wgsl-uniform> children feed its parameters. This one is a travelling
sine wave whose amplitude and wavelength you can read off the moving
surface. -->
<sk-scene>
<sk-directional-light p="35deg" h="25deg" intensity="1.0"></sk-directional-light>
<sk-ambient-light intensity="0.4"></sk-ambient-light>
<sk-plain-material id="mat" base-color="#3a6ea5"></sk-plain-material>
<!-- A finely subdivided plane so the wave reads smoothly. -->
<sk-plane width="20" height="20" width-segments="128" height-segments="128">
<sk-surface-paint material="#mat" cull-mode="none"></sk-surface-paint>
<sk-custom-wgsl-point-constraint affects-normals="true" max-displacement="4"
wgsl="fn computeDisplacement(worldXZ: vec2<f32>) -> vec3<f32> { let k = 2.0 * PI / max(skUniform_wavelength(), 1e-6); let phase = skUniform_speed() * modUniforms.time; return vec3<f32>(0.0, skUniform_amplitude() * sin(k * worldXZ.x + phase), 0.0); } fn computeGradient(worldXZ: vec2<f32>) -> vec2<f32> { let k = 2.0 * PI / max(skUniform_wavelength(), 1e-6); let phase = skUniform_speed() * modUniforms.time; return vec2<f32>(skUniform_amplitude() * k * cos(k * worldXZ.x + phase), 0.0); }">
<sk-wgsl-uniform name="amplitude" value="2"></sk-wgsl-uniform>
<sk-wgsl-uniform name="wavelength" value="8"></sk-wgsl-uniform>
<sk-wgsl-uniform name="speed" value="0.002"></sk-wgsl-uniform>
</sk-custom-wgsl-point-constraint>
</sk-plane>
</sk-scene>
| Attribute | Type | Default | Description |
|---|---|---|---|
id |
<id> |
— | The element's unique identifier — the standard HTML global id attribute. |
wgsl |
<string> |
"" |
Inline WGSL implementing the displacement-kernel contract. |
src |
<string> |
— | URL of an external .wgsl file providing the displacement kernel, |
affects-normals |
<boolean> |
false |
The AUTHORED affects-normals value, independent of show. alias for affectsNormalsConfig |
max-displacement |
<number> |
0 |
Analytic upper-bound displacement magnitude (world units), used to |
time-dependent |
<boolean> |
false |
Whether the kernel must be re-dispatched every frame. |
show |
<boolean> |
true |
Whether the constraint is active. |
field-weight-rangeanimatable |
<field-weight-range> ([<number>, <number>]) |
— | The [lo, hi] range the field weight maps onto. |
Standard DOM event-handler content attributes — the value is JavaScript run when the event fires. They behave exactly as on any HTML element.
onload, onerror