STET / VUE

UI annotations in Vue.

Stet is a free, MIT-licensed UI annotation library. Add hand-sketched marks to live Vue 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.

Vue exposes directives such as vStetCircle. Import the directive in script setup and bind options directly to the existing element with v-stet-circle. Vue retains ownership of the element and its event handlers.

Vue / first mark
<script setup lang="ts">
// Adapt these sample elements to existing source; retain their semantics and handlers.
import { vStetCircle } from "@funsaized/stet/vue";
import "@funsaized/stet/style.css";
</script>

<template>
  <button type="button" v-stet-circle='{"seed":42,"description":"Review this action before continuing."}'>Review action</button>
</template>

Browse the canonical Vue 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.

When multiple marks depend on reactive targets, watchPostEffect runs after Vue updates the DOM. Register the returned cleanup with onCleanup so old handles are destroyed before a new binding or destination is attached.

Vue / lifecycle
<script setup lang="ts">
// Adapt to existing controls; annotation state never controls their presence.
import { ref, watchPostEffect } from "vue";
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";

const props = withDefaults(defineProps<{ enabled?: boolean; destination?: number }>(), { enabled: true, destination: 0 });
const target = ref<HTMLButtonElement | null>(null);
const to = ref<HTMLParagraphElement | null>(null);
watchPostEffect(onCleanup => {
  if (target.value) onCleanup(attachMarks(target.value, to.value, props.enabled));
});
</script>
<template>
  <button ref="target" type="submit">Review action</button>
  <p v-if="props.destination > 0" :key="props.destination" ref="to">Consequences of this action</p>
</template>

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

Bind an annotation to a reactive settings control; use post-render effects when a conditional explanation becomes an arrow destination.

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 Vue 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