npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

yarn-spinner-runner-ts

v0.1.5-c

Published

TypeScript parser, compiler, and runtime for Yarn Spinner 3.x with React adapter [NPM package](https://www.npmjs.com/package/yarn-spinner-runner-ts)

Downloads

207

Readme

yarn-spinner-runner-ts

TypeScript parser, compiler, and runtime for Yarn Spinner 3.x with React adapter.

References

  • Old JS parser: bondage.js (Yarn 2.x) — GitHub
  • Official compiler (C#): YarnSpinner.Compiler — GitHub
  • Existing dialogue runner API: YarnBound — GitHub

Features

  • ✅ Full Yarn Spinner 3.x syntax support
  • ✅ Parser for .yarn files → AST
  • ✅ Compiler: AST → Intermediate Representation (IR)
  • ✅ Runtime with YarnRunner class
  • ✅ React hook: useYarnRunner()
  • ✅ React components: <DialogueView />, <DialogueScene />, <DialogueExample />
  • ✅ Typing animation with configurable speeds, cursor styles, and auto-advance controls
  • ✅ Markup parsing with HTML formatting tags and CSS-ready spans
  • ✅ Expression evaluator for conditions
  • ✅ Command system with built-in handlers (<<set>>, <<declare>>, etc.)
  • ✅ Scene system with backgrounds and actor images (with configurable portrait cross-fades)
  • ✅ Custom CSS styling via &css{} attributes
  • ✅ Built-in functions (visited, random, min, max, etc.)
  • ✅ Support for:
    • Lines with speakers
    • Options with indented bodies
    • Inline option conditions via [if expression]
    • <<if>>/<<elseif>>/<<else>>/<<endif>> blocks
    • <<once>>...<<endonce>> blocks
    • <<jump NodeName>> commands
    • <<detour NodeName>> commands
    • Variables and expressions
    • Enums (<<enum>> blocks)
    • Smart variables (<<declare $var = expr>>)
    • Node groups with when: conditions
    • Tags and metadata on nodes, lines, and options
    • Custom commands

Installation

npm install
npm run build

Quick Start

Basic Usage

import { parseYarn, compile, YarnRunner } from "yarn-spinner-runner-ts";

const yarnText = `
title: Start
---
Narrator: Hello!
-> Option 1
    Narrator: You chose option 1.
-> Option 2
    Narrator: You chose option 2.
===
`;

const ast = parseYarn(yarnText);
const program = compile(ast);
const runner = new YarnRunner(program, {
  startAt: "Start",
  variables: { score: 10 },
  functions: {
    add: (a: number, b: number) => a + b,
  },
  handleCommand: (cmd, parsed) => {
    console.log("Command:", cmd);
  },
  onStoryEnd: ({ variables, storyEnd }) => {
    console.log("Story ended!", storyEnd);
    console.log("Final variables:", variables);
  },
});

// Get current result
console.log(runner.currentResult); // TextResult, OptionsResult, or CommandResult

// Advance dialogue
runner.advance(); // Continue text
runner.advance(0); // Choose option 0

Variables passed from your host app can be provided as score or $score; the runner normalizes keys so either style works.

Inline conditional options

You can add a per-option condition by appending [if expression] to the option text. The expression is evaluated when the option list is emitted; options whose expression evaluates to false are dropped before the runner shows them.

title: Hub
---
<<declare $hasBadge = false>>
-> Ask about the badge [if $hasBadge]
    Narrator: You flash the badge.
-> Offer a bribe
    Narrator: You slide some eddies across the table.
===

Once some branch executes <<set $hasBadge = true>>, the badge option automatically appears alongside the other entries, without extra <<if>> blocks.

Arithmetic assignments

<<set>> accepts both to and = aliases and evaluates the expression on the right-hand side, so you can modify variables inline—operator precedence and parentheses all work the same way they do in Yarn Spinner:

<<set $reputation = $reputation - 25 >>
<<set $score = ($score + 10) / 2>>
Narrator: Current street cred: {$reputation}, score: {$score}

React Usage

import { parseYarn, compile, useYarnRunner, DialogueView } from "yarn-spinner-runner-ts";
import { parseScenes } from "yarn-spinner-runner-ts";
import type { SceneCollection } from "yarn-spinner-runner-ts";

function MyDialogue() {
  const [program] = useState(() => {
    const ast = parseYarn(yarnText);
    return compile(ast);
  });

  const [scenes] = useState<SceneCollection>(() => {
    return parseScenes(sceneYamlText);
  });

  const { result, advance } = useYarnRunner(program, {
    startAt: "Start",
    variables: { score: 10 },
  });

  return (
    <DialogueView 
      result={result} 
      onAdvance={advance}
      scenes={scenes}
    />
  );
}

Full Example Component

import { DialogueExample } from "yarn-spinner-runner-ts";

function App() {
  return <DialogueExample />;
}

Typing Animation

Set enableTypingAnimation on DialogueView to enable the TypingText component for typewriter-style delivery. Tweak props like typingSpeed, showTypingCursor, cursorCharacter, autoAdvanceAfterTyping, autoAdvanceDelay, and pauseBeforeAdvance to fine-tune behaviour, and see Typing Animation (React) for details.

Browser Demo

Run the interactive browser demo:

npm run demo

This starts a Vite dev server with a live Yarn script editor and dialogue system.

API Reference

Parser

  • parseYarn(text: string): YarnDocument — Parse Yarn script text into AST

Compiler

  • compile(doc: YarnDocument, opts?: CompileOptions): IRProgram — Compile AST to IR

Runtime

  • YarnRunner(program: IRProgram, options: RunnerOptions) — Dialogue runner class
    • currentResult: RuntimeResult | null — Current dialogue state
    • advance(optionIndex?: number): void — Advance dialogue
    • getVariable(name: string): unknown — Get variable value
    • setVariable(name: string, value: unknown): void — Set variable value
    • getVariables(): Readonly<Record<string, unknown>> — Get all variables
    • onStoryEnd?: (payload: { variables: Readonly<Record<string, unknown>>; storyEnd: true }) => void — Handler called when story reaches its end, providing final variable state

React Components

  • useYarnRunner(program: IRProgram, options: RunnerOptions) — React hook
    • Returns: { result: RuntimeResult | null, advance: (optionIndex?: number) => void, runner: YarnRunner }
  • <DialogueView result={...} onAdvance={...} scenes={...} /> — Ready-to-use dialogue component
  • <DialogueScene sceneName={...} speaker={...} scenes={...} actorTransitionDuration={...} /> — Scene background, actor display, and portrait transitions — Scene background and actor display
  • <DialogueExample /> — Full example with editor

Scene System

  • parseScenes(input: string | Record<string, unknown>): SceneCollection — Parse YAML scene configuration
  • SceneCollection — Type for scene configuration
  • SceneConfig — Type for individual scene config
  • ActorConfig — Type for actor configuration

See Scene and Actor Setup Guide for detailed documentation.

Expression Evaluator

  • ExpressionEvaluator(variables, functions, enums?) — Safe expression evaluator
    • Supports: ===, !==, <, >, <=, >=, &&, ||, !
    • Operator aliases: eq/is, neq, gt, lt, lte, gte, and, or, not, xor
    • Function calls: functionName(arg1, arg2)
    • Variables, numbers, strings, booleans
    • Enum support with shorthand (MyEnum.Case)

Commands

  • CommandHandler — Command handler registry
    • Built-in: <<set variable = value>>, <<declare $var = expr>>
    • Register custom handlers: handler.register("mycommand", (args) => { ... })
  • parseCommand(content: string): ParsedCommand — Parse command string

Built-in Functions

The runtime includes these built-in functions:

  • visited(nodeName) — Check if a node was visited
  • visited_count(nodeName) — Get visit count for a node
  • random() — Random float 0-1
  • random_range(min, max) — Random integer in range
  • dice(sides) — Roll a die
  • min(a, b), max(a, b) — Min/max values
  • round(n), round_places(n, places) — Rounding
  • floor(n), ceil(n) — Floor/ceiling
  • inc(n), dec(n) — Increment/decrement
  • decimal(n) — Convert to decimal
  • int(n) — Convert to integer
  • string(n), number(n), bool(n) — Type conversions

Example Yarn Script

title: Start
tags: #introduction #tutorial
---
Narrator: Welcome!
<<set score = 10>>
<<if score >= 10>>
    Narrator: High score!
<<else>>
    Narrator: Low score.
<<endif>>

<<declare $randomName = random_range(1, 3) == 1 ? "Alice" : "Bob">>
Narrator: Your name is {$randomName}.

-> Ask about features
    Player: What can this do?
    Narrator: Lots of things!
-> Ask about commands
    Player: Tell me about commands.
    Narrator: Commands modify state.

<<once>>
    Narrator: This only shows once!
<<endonce>>

<<jump NextNode>>
===

title: NextNode
scene: scene1
---
Narrator: You've arrived at the next scene!
===

CSS Styling

You can apply custom CSS styles to nodes and options using the &css{} attribute:

title: StyledNode
&css{background-color: #ff0000; color: white;}
---
Narrator: This node has a red background.

-> Option 1 &css{background-color: blue;}
    Narrator: You chose the blue option.
===

Styles are merged with default styles, with custom styles taking precedence.

See CSS Attribute Documentation for details.

Scene Configuration

Configure scenes and actors using YAML:

scenes:
  scene1:
    background: https://example.com/background1.jpg
    actors:
      special_npc:
        image: https://example.com/special-npc.png

actors:
  Narrator: https://example.com/narrator.png
  Player: https://example.com/player.png

Use scenes in Yarn nodes:

title: MyNode
scene: scene1
---
Narrator: This scene uses scene1's background and actors.
===

See Scene and Actor Setup Guide for complete documentation.

Project Structure

yarn-spinner/
├── src/
│   ├── model/          # AST types
│   ├── parse/          # Lexer and parser
│   ├── compile/        # Compiler (AST → IR)
│   ├── runtime/        # Runtime execution
│   ├── scene/          # Scene system
│   ├── react/          # React components
│   └── tests/          # Test files
├── examples/
│   ├── yarn/           # Example Yarn scripts
│   ├── browser/        # Browser demo (Vite)
│   └── scenes/         # Scene configuration examples
├── docs/               # Documentation
└── dist/               # Compiled output

Development

npm run build     # Build TypeScript
npm run dev       # Watch mode
npm run lint      # Run ESLint
npm test          # Run tests
npm run demo      # Start browser demo
npm run demo:build # Build browser demo

Testing

Tests are located in src/tests/ and cover:

  • Basic dialogue flow
  • Options and branching
  • Variables and flow control
  • Commands (<<set>>, <<declare>>, etc.)
  • <<once>> blocks
  • <<jump>> and <<detour>>
  • Full featured Yarn scripts

Run tests:

npm test

Documentation

Additional documentation is available in the docs/ folder:

License

MIT