Changelog
Core
0.18.0 - 28.04.2026
SVG renderer trail pool is now sized to trailLength at the time of construction instead of a hardcoded cap, which was 200. Before the change, trailLength values above 200 would silently clip in the SVG renderer while the canvas equivalent would have no problem rendering it fully.
Engine.trailLength is now exposed on Engine objects. It reflects the maximum trail capacity set at the time of engine creation.
0.17.3 - 24.04.2026
cyclePos in shared renderer where palette color is retrieved now uses the safe double-modulo form
0.17.0 - 24.04.2026
0.16.0 - 23.04.2026
destroy() now rejects any pending morphTo Promise.
Previously, if a Sarmal instance was destroyed druing a morph, the Promise was never settled.
The rejection is swallowed by the .catch(() => {}) in @sarmal/react’s useSarmal hook. Callers who await morphTo directly should handle the rejection if they call destroy() before the morph completes.
0.15.1 - 19.04.2026
Replaced getBoundingClientRect() approach of getting container size with offsetWidth and offsetHeight.
The getBoundingClientRect() would cause unexpected width/height output, because it would return visually scaled size affected by CSS. So, if one were to apply transform: scale(0.99) to the canvas, but 280px for the actual canvas size, the end result would be 277.2px
The offset values now give the inherent layout box size, unaffected by CSS transforms
0.15.0 - 19.04.2026
palette option is removed. Colors are now unified under trailColor which accepts a single hex string OR an array of hex strings. // Before
const sarmal = createSarmal(canvas, curves.astroid, {
trailStyle: "gradient-animated",
palette: "bard",
});
// After
import { palettes } from "@sarmal/core";
const sarmal = createSarmal(canvas, curves.rose3, {
trailStyle: "gradient-animated",
trailColor: palettes.sunset,
});
setRenderOptions(partial) is added to SarmalInstance. Change colors and trail style on a live instance without destroying and recreating it.
sarmal.setRenderOptions({ trailColor: palettes.sunset });
sarmal.setRenderOptions({ trailStyle: "default", trailColor: "#c0143c" });
sarmal.setRenderOptions({ headColor: "#ffffff" }); // override
sarmal.setRenderOptions({ headColor: null }); // inherited from trail color
Validation rules: The current setup requeires that all colors be 6-digit hex strings. skeletonColor also accepts "transparent". If any field fails validation, then no fields are mutated.
0.14.0 - 18.04.2026
Animated gradients are now supported in SVG renderer
trailStyle and palette options now work in createSarmalSVG with identical behavior to createSarmal. Previously these options were only available in canvas.
const sarmal = createSarmalSVG(container, curves.astroid, {
trailStyle: 'gradient-animated',
palette: 'bard',
});
0.13.0 - 16.04.2026
SarmalInstance methods start() and stop() are renamed to play() and pause() to match similar libraries start()play()stop()pause()
autoStart added: createSarmal and createSarmalSVG now default to autoStart: true, so the animation begins immediately on creation. If you were calling .start() right after creation, you can remove that call. If you want to defer playback, pass autoStart: false.
// Before
const sarmal = createSarmal(canvas, curves.artemis2)
sarmal.start()
// After
const sarmal = createSarmal(canvas, curves.artemis2)
// No call needed here
Deferred start:
const sarmal = createSarmal(canvas, curves.artemis2, { autoStart: false })
// later...
sarmal.play()
A new initialT option lets you seek to a specific position before the first frame, replacing the common pattern of play() then seek(t).
// Start at a specific position
const sarmal = createSarmal(canvas, curves.artemis2, { initialT: Math.PI })
React
0.1.0 - 23.04.2026
@sarmal/react is a new package that provides a React wrapper over @sarmal/core. It exports a <Sarmal> component for drop-in usage and a useSarmal hook for imperative control.
morphTo under the hood import { Sarmal } from "@sarmal/react";
import { curves } from "@sarmal/core";
<Sarmal curve={curves.rose3} />
Peer dependencies: react >= 18 and @sarmal/core. Each source file is marked with "use client" for SSR compatibility.