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

@writewhisker/export

v0.1.0

Published

Export system for Whisker - JSON, HTML, Markdown, Twine, EPUB, and Static Site exporters

Readme

@writewhisker/export

Export Whisker stories to multiple formats (HTML, Markdown, Twine, and more).

Installation

npm install @writewhisker/export

Features

  • HTML Standalone - Self-contained HTML files with embedded player
  • HTML Template - Customizable HTML with themes (default, dark, minimal, classic)
  • Markdown - Documentation-friendly format for version control
  • Twine 2 JSON - Export to Twine format for compatibility

Quick Start

Programmatic API

import { StandaloneExporter, TemplateExporter, MarkdownExporter, TwineExporter } from '@writewhisker/export';
import { readFile, writeFile } from 'fs/promises';

// Load your story
const storyJson = await readFile('story.json', 'utf-8');
const story = JSON.parse(storyJson);

// Export as standalone HTML
const standaloneExporter = new StandaloneExporter();
const html = await standaloneExporter.export(story, {
  minify: true,
  includeMetadata: true
});
await writeFile('story.html', html);

// Export with custom theme
const templateExporter = new TemplateExporter();
const themed = await templateExporter.export(story, {
  theme: 'dark',
  customCSS: '.passage { font-family: Georgia; }'
});
await writeFile('story-dark.html', themed);

// Export as Markdown
const markdownExporter = new MarkdownExporter();
const markdown = await markdownExporter.export(story);
await writeFile('story.md', markdown);

// Export to Twine 2 format
const twineExporter = new TwineExporter();
const twine = await twineExporter.export(story, {
  storyFormat: 'sugarcube' // or 'harlowe', 'snowman', 'chapbook'
});
await writeFile('story-twine.json', twine);

CLI Usage

# Install globally
npm install -g @writewhisker/export

# Export as standalone HTML
whisker-export export story.json -f html-standalone -o story.html

# Export with dark theme
whisker-export export story.json -f html-template -t dark -o story.html

# Export as Markdown
whisker-export export story.json -f markdown -o story.md

# Export to Twine 2 (SugarCube format)
whisker-export export story.json -f twine --twine-format sugarcube -o story.json

# Minify HTML output
whisker-export export story.json -f html-standalone --minify -o story.min.html

# Use custom CSS
whisker-export export story.json -f html-template --css custom.css -o story.html

# List available formats
whisker-export list-formats

Export Formats

HTML Standalone

Self-contained HTML file with embedded player. Perfect for distribution.

const exporter = new StandaloneExporter();
const html = await exporter.export(story, {
  minify: false,           // Minify HTML/CSS/JS
  includeMetadata: true,   // Include story metadata
  customCSS: undefined     // Optional custom CSS
});

Features:

  • Embedded JavaScript player
  • All CSS inline
  • No external dependencies
  • Works offline
  • Single file distribution

HTML Template

Customizable HTML with theme support.

const exporter = new TemplateExporter();
const html = await exporter.export(story, {
  theme: 'dark',           // default, dark, minimal, classic
  customCSS: '.passage { font-size: 18px; }',
  includeMetadata: true
});

Available Themes:

  • default - Clean, modern theme
  • dark - Dark mode with high contrast
  • minimal - Minimalist, distraction-free
  • classic - Book-style with serif fonts

Markdown

Documentation format for version control and collaboration.

const exporter = new MarkdownExporter();
const markdown = await exporter.export(story, {
  includeMetadata: true,
  includePassageIds: false,
  includeScripts: true,
  includeChoiceLogic: true
});

Output Structure:

  • Table of contents
  • Metadata section
  • Variables table
  • All passages with:
    • Title and content
    • Tags and scripts
    • Choices with conditions

Use Cases:

  • Version control (Git-friendly)
  • Documentation
  • Collaboration and review
  • Story structure analysis

Twine 2 JSON

Export to Twine-compatible format.

const exporter = new TwineExporter();
const json = await exporter.export(story, {
  storyFormat: 'sugarcube'  // harlowe, sugarcube, snowman, chapbook
});

Story Formats:

  • harlowe - Twine 2 default (Harlowe 3.x)
  • sugarcube - SugarCube 2.x
  • snowman - Minimal JS format
  • chapbook - Modern, declarative format

Conversion Details:

  • Whisker passages → Twine passages
  • Whisker choices → Twine links
  • Variables preserved (format-specific syntax)
  • Conditions → Format-appropriate syntax
  • Generates valid IFID

CLI Reference

Export Command

whisker-export export <input> [options]

Options:

  • -f, --format <format> - Export format (default: html-standalone)
    • html-standalone - Self-contained HTML
    • html-template - Themed HTML
    • markdown - Markdown documentation
    • twine - Twine 2 JSON
  • -o, --output <file> - Output file path
  • -t, --theme <theme> - Theme for template export (default: default)
    • default, dark, minimal, classic
  • --minify - Minify output (HTML only)
  • --no-metadata - Exclude metadata from export
  • --css <file> - Custom CSS file (template export only)
  • --twine-format <format> - Twine story format (default: harlowe)
    • harlowe, sugarcube, snowman, chapbook

List Formats Command

whisker-export list-formats

Shows all available export formats, themes, and Twine formats.

API Reference

Exporter Interface

All exporters implement this interface:

interface Exporter {
  export(story: StoryData, options?: ExportOptions): Promise<string>;
}

interface ExportOptions {
  minify?: boolean;
  includeMetadata?: boolean;
  customCSS?: string;
}

StandaloneExporter

class StandaloneExporter implements Exporter {
  export(story: StoryData, options?: ExportOptions): Promise<string>;
}

TemplateExporter

interface TemplateExportOptions extends ExportOptions {
  theme?: 'default' | 'dark' | 'minimal' | 'classic';
  template?: string;  // Custom Handlebars template
  helpers?: Record<string, HandlebarsHelperDelegate>;
  templateData?: Record<string, any>;
}

class TemplateExporter implements Exporter {
  export(story: StoryData, options?: TemplateExportOptions): Promise<string>;
}

MarkdownExporter

interface MarkdownExportOptions extends ExportOptions {
  includePassageIds?: boolean;
  includeScripts?: boolean;
  includeChoiceLogic?: boolean;
}

class MarkdownExporter implements Exporter {
  export(story: StoryData, options?: MarkdownExportOptions): Promise<string>;
}

TwineExporter

interface TwineExportOptions extends ExportOptions {
  storyFormat?: 'harlowe' | 'sugarcube' | 'snowman' | 'chapbook';
}

class TwineExporter implements Exporter {
  export(story: StoryData, options?: TwineExportOptions): Promise<string>;
}

Examples

Batch Export

Export a story to all formats:

import { StandaloneExporter, TemplateExporter, MarkdownExporter, TwineExporter } from '@writewhisker/export';

async function exportAll(story: StoryData, baseName: string) {
  // HTML Standalone
  const standaloneExporter = new StandaloneExporter();
  await writeFile(
    `${baseName}.html`,
    await standaloneExporter.export(story, { minify: true })
  );

  // HTML with each theme
  const templateExporter = new TemplateExporter();
  for (const theme of ['default', 'dark', 'minimal', 'classic']) {
    await writeFile(
      `${baseName}-${theme}.html`,
      await templateExporter.export(story, { theme })
    );
  }

  // Markdown
  const markdownExporter = new MarkdownExporter();
  await writeFile(
    `${baseName}.md`,
    await markdownExporter.export(story)
  );

  // Twine formats
  const twineExporter = new TwineExporter();
  for (const format of ['harlowe', 'sugarcube', 'snowman', 'chapbook']) {
    await writeFile(
      `${baseName}-${format}.json`,
      await twineExporter.export(story, { storyFormat: format })
    );
  }
}

Custom Theme

Create a custom theme:

const customCSS = `
  body {
    font-family: 'Courier New', monospace;
    background: #000;
    color: #0f0;
  }
  .passage {
    border: 1px solid #0f0;
    padding: 20px;
  }
  .choice {
    color: #0ff;
    text-decoration: none;
  }
  .choice:hover {
    text-shadow: 0 0 10px #0ff;
  }
`;

const exporter = new TemplateExporter();
const html = await exporter.export(story, {
  theme: 'dark',
  customCSS
});

Publishing Pipeline

Automated publishing workflow:

#!/bin/bash

# Export for web
whisker-export export story.json -f html-standalone -o dist/index.html --minify

# Export for documentation
whisker-export export story.json -f markdown -o docs/story.md

# Export for Twine users
whisker-export export story.json -f twine --twine-format sugarcube -o exports/story-twine.json

# Create themed versions
whisker-export export story.json -f html-template -t dark -o dist/dark.html
whisker-export export story.json -f html-template -t minimal -o dist/minimal.html

License

AGPL-3.0