libtwee

File Formats Guide

libtwee supports multiple file formats used in the Twine ecosystem. This guide explains each format and how to work with them.

Supported Formats

Format Input Output Description
Twee 3 Latest specification for Twine source files
Twine 2 HTML Compiled playable story format
Twine 2 JSON JSON export format for stories
Twine 2 Archive Collection format for multiple stories
Twine 1 HTML 🟡 Legacy HTML format (partial output support)

Twee 3 Format

Twee 3 is the primary source format for Twine stories. It’s a plain text format that’s human-readable and version control friendly.

Basic Structure

:: StoryTitle
My Adventure Story

:: StoryData
{
  "ifid": "12345678-1234-5678-9ABC-123456789ABC",
  "format": "Harlowe",
  "format-version": "3.3.5",
  "start": "Introduction"
}

:: Introduction
Welcome to my adventure story!

This is where your journey begins.

[[Start the adventure->Forest]]

:: Forest [location outdoor]
You are standing in a dense forest.

The trees tower above you, their leaves rustling in the wind.

* [[Go deeper into the forest->DeepForest]]
* [[Follow the path->Path]]
* [[Turn back->Introduction]]

:: DeepForest [location outdoor hidden]
You venture deeper into the mysterious forest...

Passage Headers

Passages in Twee format follow this pattern:

:: PassageName [tag1 tag2] {"position":"100,200"}

Story Metadata

The StoryData passage contains JSON configuration:

{
  "ifid": "Interactive Fiction ID",
  "format": "Story format name",
  "format-version": "Format version",
  "start": "Starting passage name",
  "tag-colors": {
    "important": "red",
    "optional": "blue"
  },
  "zoom": 1.0
}

Working with Twee

// Parse Twee content
string tweeContent = File.ReadAllText("story.twee");
Story story = Twee.Parse(tweeContent);

// Create Twee from Story object
string tweeOutput = story.ToTwee();
File.WriteAllText("output.twee", tweeOutput);

Twine 2 HTML Format

The compiled HTML format contains both the story data and the story format engine, creating a standalone playable file.

Structure

Twine 2 HTML files contain:

Example HTML Structure

<!DOCTYPE html>
<html>
<head>
    <title>My Story</title>
</head>
<body>
    <tw-storydata name="My Story" startnode="1" 
                  ifid="12345678-1234-5678-9ABC-123456789ABC"
                  format="Harlowe" format-version="3.3.5">
        <tw-passagedata pid="1" name="Start" tags="">
            Welcome to the story!
            
            [[Continue->Next]]
        </tw-passagedata>
        <tw-passagedata pid="2" name="Next" tags="">
            This is the next passage.
        </tw-passagedata>
    </tw-storydata>
    
    <!-- Story format JavaScript would be here -->
</body>
</html>

Working with Twine 2 HTML

// Parse HTML file
string htmlContent = File.ReadAllText("story.html");
Story story = Twine2HTML.Parse(htmlContent);

// Compile story to HTML
string html = story.ToTwine2HTML();
File.WriteAllText("compiled.html", html);

Twine 2 JSON Format

JSON format provides a structured data representation of stories, useful for tool integration and data processing.

JSON Structure

{
  "name": "My Adventure Story",
  "ifid": "12345678-1234-5678-9ABC-123456789ABC",
  "format": "Harlowe",
  "format-version": "3.3.5",
  "start": "Introduction",
  "passages": [
    {
      "name": "Introduction",
      "tags": ["beginning"],
      "text": "Welcome to my adventure!\n\n[[Start->Forest]]",
      "pid": 1
    },
    {
      "name": "Forest",
      "tags": ["location", "outdoor"],
      "text": "You are in a forest.\n\n[[Continue->End]]",
      "pid": 2
    }
  ],
  "creator": "Twine",
  "creator-version": "2.8.1"
}

Working with JSON

// Parse JSON file
string jsonContent = File.ReadAllText("story.json");
Story story = Twine2JSON.Parse(jsonContent);

// Export to JSON
string json = story.ToTwine2JSON();
File.WriteAllText("exported.json", json);

Twine 2 Archive Format

Archive format allows bundling multiple stories into a single HTML file for sharing story collections.

Archive Structure

<tw-library>
    <tw-story name="Story 1" ifid="...">
        <!-- Story 1 data -->
    </tw-story>
    <tw-story name="Story 2" ifid="...">
        <!-- Story 2 data -->
    </tw-story>
</tw-library>

Working with Archives

// Parse archive
string archiveContent = File.ReadAllText("collection.html");
var stories = Twine2Archive.Parse(archiveContent);

// Create archive from multiple stories
var storyList = new List<Story> { story1, story2, story3 };
string archive = Twine2Archive.Create(storyList);
File.WriteAllText("collection.html", archive);

Legacy Twine 1 HTML

libtwee provides parsing support for legacy Twine 1 HTML files, allowing migration to newer formats.

Differences from Twine 2

Migration Example

// Parse legacy Twine 1 HTML
string twine1Html = File.ReadAllText("legacy-story.html");
Story story = Twine1HTML.Parse(twine1Html);

// Convert to modern Twine 2 format
string twine2Html = story.ToTwine2HTML();
File.WriteAllText("modernized-story.html", twine2Html);

Format Conversion Examples

Complete Conversion Workflow

public class StoryConverter
{
    public static void ConvertBetweenFormats(string inputFile, string outputFile)
    {
        Story story = null;
        string extension = Path.GetExtension(inputFile).ToLower();
        
        // Parse input based on file extension
        string content = File.ReadAllText(inputFile);
        
        switch (extension)
        {
            case ".twee":
                story = Twee.Parse(content);
                break;
            case ".html":
                // Try Twine 2 first, fall back to Twine 1
                try
                {
                    story = Twine2HTML.Parse(content);
                }
                catch
                {
                    story = Twine1HTML.Parse(content);
                }
                break;
            case ".json":
                story = Twine2JSON.Parse(content);
                break;
            default:
                throw new ArgumentException($"Unsupported input format: {extension}");
        }
        
        // Generate output based on desired format
        string outputExtension = Path.GetExtension(outputFile).ToLower();
        string output;
        
        switch (outputExtension)
        {
            case ".twee":
                output = story.ToTwee();
                break;
            case ".html":
                output = story.ToTwine2HTML();
                break;
            case ".json":
                output = story.ToTwine2JSON();
                break;
            default:
                throw new ArgumentException($"Unsupported output format: {outputExtension}");
        }
        
        File.WriteAllText(outputFile, output);
        Console.WriteLine($"Converted {inputFile} to {outputFile}");
    }
}

// Usage examples
StoryConverter.ConvertBetweenFormats("story.twee", "story.html");
StoryConverter.ConvertBetweenFormats("story.html", "story.json");
StoryConverter.ConvertBetweenFormats("legacy.html", "modern.twee");

Best Practices

Format Selection

File Organization

project/
├── src/
│   ├── story.twee          # Source files
│   └── chapters/
│       ├── intro.twee
│       └── adventure.twee
├── build/
│   ├── story.html          # Compiled output
│   └── story.json          # Data export
└── assets/
    ├── images/
    └── styles/

Version Control

Twee format is ideal for version control:

# Track source files
git add src/*.twee

# Ignore build artifacts
echo "build/" >> .gitignore
echo "*.html" >> .gitignore