Media & effects
Morphing Blob
Fluid spring-physics blob with cursor interaction
detent-morphing-blob
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-cinematic
- Group
- Media & effects
Content sits above the decoration.
5.1 KB gzip for the class module
Variants
A decorative blob: it is aria-hidden="true" with role="presentation" and
pointer-events: none, so the paragraph layered above it stays clickable. Move the pointer across the
preview to see the shape lean towards it with the pinned spring physics (stiffness 45,
damping 9, cursor-strength 0.35). The row records no events.
Ten anchors, tighter variance, demo palette.
With prefers-reduced-motion: reduce the blob freezes in its deterministic resting shape and schedules
no animation frame. The palette in this tile is demonstration data; colors is property-only plain data,
never an attribute.
Recorded states
hoverrecorded state; no setterdisabledrecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/morphing-blob/define.js';
// or register it yourself
import { DetentMorphingBlob } from '/components/morphing-blob/morphing-blob.js';
Attributes
base-radiuscursor-followcursor-smoothnesscursor-strengthdampingheightpointsspeedstiffnessvariancewidth
Properties
colors
Slots
No slots are recorded for this component.
Events
No events are recorded for this component.
Example
Runnable example: site/examples/morphing-blob.ts. The snippet below is generated from the catalogued attributes.
<detent-morphing-blob
base-radius="120"
cursor-follow
cursor-smoothness="0.08"
cursor-strength="0.35"
damping="9"
height="400"
points="8"
speed="0.7"
stiffness="45"
variance="28"
width="400"
></detent-morphing-blob>
Property-only values
const element = document.querySelector('detent-morphing-blob');
if (element !== null) {
// colors: [string, string]
element.colors = undefined;
}
Source
The pinned upstream source for this row:
src/components/ui/MorphingBlob.tsxsha256 ef2a74f65508…
Native files
The native module and its artifacts:
src/components/morphing-blob/morphing-blob.tssrc/components/morphing-blob/styles.csssrc/components/morphing-blob/define.tsdocs/components/morphing-blob.mdsite/examples/morphing-blob.tstests/browser/morphing-blob.spec.tsevidence/components/morphing-blob.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
base-radius | baseRadius | number | 120 | Kebab-case attribute; camelCase property. |
cursor-follow | cursorFollow | boolean | true | Presence semantics: present means true, absent means false. |
cursor-smoothness | cursorSmoothness | number | 0.08 | Kebab-case attribute; camelCase property. |
cursor-strength | cursorStrength | number | 0.35 | Kebab-case attribute; camelCase property. |
damping | damping | number | 9 | Kebab-case attribute; camelCase property. |
height | height | number | 400 | Kebab-case attribute; camelCase property. |
points | points | number | 8 | Kebab-case attribute; camelCase property. |
speed | speed | number | 0.7 | Kebab-case attribute; camelCase property. |
stiffness | stiffness | number | 45 | Kebab-case attribute; camelCase property. |
variance | variance | number | 28 | Kebab-case attribute; camelCase property. |
width | width | number | 400 | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
colors | [string, string] | ['#7C3AED', '#06B6D4'] | Property-only: assign from script; not accepted as an attribute. |
Events
No custom events are recorded for this component.
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- className is replaced by host class/style plus the documented parts (svg, gradient, path) and custom properties (--detent-morphing-blob-blur, -opacity, -shape).
- The per-anchor integrator is kept instead of the shared spring helper because stiffness and damping are public attributes whose defaults (45/9) differ from every shared token; PC-10.1 permits rAF for interactive physics and the choice is recorded for review.
- Seeded random targets replace Math.random, so the shape sequence is deterministic and identical for identically configured instances.
- points and the other geometry attributes rebuild the anchor ring, where upstream initialised it once and left a stale ring after a runtime change.
- Retarget cadence is driven by accumulated frame time instead of a separate setInterval, so pausing leaves no timer.
- aria-hidden and role=presentation moved onto the host as well as the SVG, so the whole element is hidden from assistive technology.
- The blob pauses while offscreen through an IntersectionObserver the source did not have (PC-10.6).
What it does
A decorative SVG blob that morphs continuously with spring physics and follows the pointer.
Upstream behaviour
- Spring-physics anchor points with Catmull-Rom smoothing for a fluid, organic shape
- Smooth cursor-follow interaction with configurable strength and responsiveness
- Imperative per-frame path updates for smooth animation without unnecessary React re-renders
- Independently configurable SVG width and height
- Customizable point count, radius, variance, speed, stiffness, and damping
- Configurable gradient start and end colors
- Automatically respects the prefers-reduced-motion accessibility preference
- Pointer-events disabled by default so the decorative blob never blocks foreground interactions
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- className is replaced by host class/style plus the documented parts (svg, gradient, path) and custom properties (--detent-morphing-blob-blur, -opacity, -shape).
- The per-anchor integrator is kept instead of the shared spring helper because stiffness and damping are public attributes whose defaults (45/9) differ from every shared token; PC-10.1 permits rAF for interactive physics and the choice is recorded for review.
- Seeded random targets replace Math.random, so the shape sequence is deterministic and identical for identically configured instances.
- points and the other geometry attributes rebuild the anchor ring, where upstream initialised it once and left a stale ring after a runtime change.
- Retarget cadence is driven by accumulated frame time instead of a separate setInterval, so pausing leaves no timer.
- aria-hidden and role=presentation moved onto the host as well as the SVG, so the whole element is hidden from assistive technology.
- The blob pauses while offscreen through an IntersectionObserver the source did not have (PC-10.6).