Skip to content
Navigation Fancy Stable

StoryThread

.md

A narrative thread for scroll stories: the page pans sideways through your sections while a dotted line draws itself from node to node, a glowing head rides its tip, nodes light up as it reaches them, and segments can fork and meet again.

Available for Svelte 5, React, and Vue 3.

Preview

Installation

pnpm add fancy-ui-svelte
import { StoryThread } from "fancy-ui-svelte";

Usage

svelte
<script lang="ts">
	import { StoryNode, StoryThread } from "fancy-ui-svelte";

	const chapters = [
		{
			id: "start",
			n: "01",
			title: "Where it starts",
			text: "Scroll down: the page moves sideways and the thread follows.",
			top: "80%",
		},
		{
			id: "craft",
			n: "02",
			title: "Learning the craft",
			text: "Each node lights up as the thread reaches it.",
			top: "56%",
		},
		{
			id: "ship",
			n: "03",
			title: "Shipping it",
			text: "Wheel sideways, drag, or use the arrow keys.",
			top: "86%",
		},
		{
			id: "next",
			n: "04",
			title: "What comes next",
			text: "The end of the thread, so far.",
			top: "62%",
		},
	];
</script>

<div class="bg-background text-foreground h-[420px] w-full overflow-y-auto rounded-xl border">
	<StoryThread layout="horizontal" ariaLabel="A short story">
		{#each chapters as chapter (chapter.id)}
			<section class="relative h-full w-[520px] shrink-0 px-10 py-12">
				<p class="text-muted-foreground font-mono text-xs">( {chapter.n} )</p>
				<h3 class="mt-2 text-2xl font-semibold tracking-tight">{chapter.title}</h3>
				<p class="text-muted-foreground mt-2 max-w-[18rem] text-sm">{chapter.text}</p>
				<StoryNode id={chapter.id} class="absolute right-24" style="top: {chapter.top}" />
			</section>
		{/each}
	</StoryThread>
</div>

Examples

Basic Usage

Scroll inside the box: the sections pan sideways and the thread draws itself from node to node.

Branches

Segments that leave the same node fork, advance together and meet again.

Vertical

The same thread running down a plain stack, dashed.

Props

PropTypeDefaultDescription
layout "auto" | "horizontal" | "vertical""auto"`horizontal` pins a full-height viewport and pans the content sideways as the page scrolls; `vertical` keeps a plain stack with the thread running down it. `auto` is horizontal from 900 × 520 px up.
segments StoryThreadSegment[][]Segments as `{ nodes: string[], color? }`, each through a list of StoryNode ids. Empty draws one segment through every node in document order. Segments that leave the same node draw a fork whose branches advance together.
lead number0.7Where the tip of the thread sits in the viewport, 0..1 along the reading axis.
tension number0.55Curve tension between nodes: 0 draws straight lines, 1 long flat tangents.
dash "dotted" | "dashed" | "solid""dotted"Stroke pattern of the thread.
head booleantrueDraws a glowing dot at the tip of every segment while it is drawing.
sound booleanfalsePlays a soft `tick` each time the thread reaches a node going forward. Only audible once the user has enabled sound.
onReach (id: string) => void-Called with a node's id each time the thread reaches it going forward.
ariaLabel string"Story"Accessible name of the region.
class string-Additional CSS classes on the root.

Slots

SlotDescription
children The story: sections holding `<StoryNode id>` anchors (`variant` `dot` or `ring`). Size the sections yourself; in the horizontal layout they sit side by side at full height.