UI annotations in Svelte.
Stet is a free, MIT-licensed UI annotation library. Add hand-sketched marks to live Svelte interfaces while your existing controls keep their layout, events, and semantics.
Install and make your first mark
The package is @funsaized/stet. These ESM examples use the project’s generated framework templates. Pin your installed version and inspect its capabilities before using newer options.
The Svelte adapter exposes element actions: import circle from @funsaized/stet/svelte and apply use:circle to your button. Action updates follow option changes and destroy the annotation when the element is removed.
<script lang="ts">
// Adapt these sample elements to existing source; retain their semantics and handlers.
import { circle } from "@funsaized/stet/svelte";
import "@funsaized/stet/style.css";
</script>
<button type="button" use:circle={{"seed":42,"description":"Review this action before continuing."}}>Review action</button>
Browse the canonical Svelte templates
Keep marks in step with the interface
These lifecycle templates follow the repository checkout. Placement nudges such as labelOffsetY are unreleased; omit them with published 0.1.0 and check your installed capabilities before adapting the example.
For coordinated marks in Svelte 5, bind:this supplies the target and $effect attaches handles after the DOM update. Return cleanup from the effect. A keyed conditional destination makes replacement explicit while preserving the source control.
<script lang="ts">
// Adapt to existing controls; annotation state never controls their presence.
import { arrow, circle, sticky, type StetHandle } from "@funsaized/stet";
function attachMarks(target: Element, destination: Element | null | undefined, enabled: boolean) {
const handles: StetHandle[] = [];
const destroy = () => { for (const handle of handles.splice(0).reverse()) handle.destroy(); };
try {
if (enabled) {
handles.push(circle(target, { seed: 42, description: "Review this action before continuing." }));
handles.push(sticky(target, { seed: 43, text: "Read the consequences before continuing." }));
if (destination) handles.push(arrow(target, destination, { seed: 44, label: "Consequences are explained here.", labelOffsetY: -12 }));
}
return destroy;
} catch (error) { destroy(); throw error; }
}
import "@funsaized/stet/style.css";
let { enabled = true, destination = 0 }: { enabled?: boolean; destination?: number } = $props();
let target = $state<HTMLButtonElement>();
let to = $state<HTMLParagraphElement>();
$effect(() => {
if (target) return attachMarks(target, to, enabled);
});
</script>
<button bind:this={target} type="submit">Review action</button>
{#if destination > 0}{#key destination}
<p bind:this={to}>Consequences of this action</p>
{/key}{/if}
Ink, layout, and accessible meaning
Import @funsaized/stet/style.css globally. Set --stet-stroke, --stet-fill, and --stet-paper to fit your design. SVG overlays do not occupy layout space or intercept pointer input.
Keep native labels, errors, keyboard focus, and event handlers on your controls. Give meaningful marks a description; color alone cannot explain a finding. Sticky notes and arrow labels supply readable text. Optional ink motion respects reduced-motion preferences.
Stet uses browser DOM APIs. Attach handles after mount, not during server rendering. Resize and scroll tracking cannot cover every transform or top-layer dialog; read placement limits and the full API reference.
Where this fits
Keep tutorial form values in your Svelte state and change only the marks as the reader advances.
Reproduce and annotate a form focus bug · Document an interactive activity inbox · Try all six primitives in the playground
Work with your coding agent
The agent inspects your installed package, validates an annotation plan, and adapts a Svelte template. Plans are authoring artifacts, not a runtime selector engine. Browser verification must still check placement and behavior.
Install project Agent Skills · See the complete visual handoff workflow
Machine-readable capabilities · Annotation plan schema · Full API reference