Skip to content

Project Structure

Understanding the structure of an Encounters story project is essential for creating and organizing your content.

Directory Overview

your-story-project/
├── src/                   # Source files for your story
│   ├── assets/           # Media files (images, audio, video)
│   ├── contacts/         # Contact definitions
│   ├── conversations/    # Conversation configurations
│   ├── gallery/          # Gallery item definitions
│   ├── ink/             # Ink script files
│   ├── news/            # News articles (markdown)
│   └── notes/           # Notes/clues (markdown)
├── scripts/              # Build and publish scripts
│   ├── build-story.cjs  # Compiles and packages your story
│   └── publish-story.cjs # Uploads to Encounters server
├── dist/                 # Build output (generated)
├── .env                  # Environment variables (not committed)
├── .env.example         # Template for environment variables
└── package.json         # Node.js dependencies and scripts

Contacts Directory

Contact files define the characters in your story. Each contact is a JSON file in src/contacts/.

Contact File Format

Example: src/contacts/alex.json

json
{
  "id": "alex",
  "name": "Alex Thompson",
  "avatar": "alex-avatar.jpg",
  "phoneNumber": "+44 7700 900124"
}

Fields:

  • id - Unique identifier (must match filename without .json)
  • name - Character's display name
  • avatar - Filename of avatar image in src/assets/
  • phoneNumber - Character's phone number (optional, for display)

Naming Convention

Use lowercase, hyphenated IDs (e.g., alex, family-group) for consistency.

Automatic Contact Unlocking

Contacts are automatically unlocked when a conversation containing that contact is unlocked. For example, if you unlock a conversation with #unlockConversation:alex, the contact "alex" will automatically appear in the player's contact list. You only need to use #unlockContact: if you want to unlock a contact separately from any conversation.

Conversations Directory

Conversation files link contacts to Ink scripts. Located in src/conversations/.

Conversation File Format

Individual Conversation: src/conversations/alex.json

json
{
  "id": "alex",
  "name": "Alex Thompson",
  "type": "individual",
  "contacts": ["alex"],
  "inkFile": "alex.ink",
  "initial": true
}

Group Conversation: src/conversations/family-group.json

json
{
  "id": "family-group",
  "name": "Family",
  "type": "group",
  "contacts": ["mum", "dad", "sister"],
  "inkFile": "family-group.ink",
  "initial": false
}

Fields:

  • id - Unique identifier (must match filename)
  • name - Conversation display name
  • type - Either "individual" or "group"
  • contacts - Array of contact IDs participating in this conversation
  • inkFile - Name of the Ink script file (in src/ink/)
  • initial - Whether this conversation starts immediately when the story begins

Ink Directory

Contains your narrative scripts written in Ink. Each .ink file corresponds to a conversation.

Example: src/ink/alex.ink

ink
// Variables
VAR police_contacted = false
VAR alex_knows_player = false

-> start

== start ==
Hey Sarah, have you seen my keys? #initial #read
Sarah? You were supposed to meet me an hour ago. #initial
-> conversation_choices

== conversation_choices ==
* [Hi, I found Sarah's phone]
  -> found_phone_response
* [Where was Sarah last seen?]
  -> last_seen_response
-> END

See the Ink Scripting Guide for detailed information.

Assets Directory

Store all media files in src/assets/:

  • Avatars - Character profile images (e.g., alex-avatar.jpg)
  • Story Images - Images referenced in messages
  • Audio Files - Voice messages, recordings (e.g., message.wav)
  • Video Files - Video clips, footage (e.g., footage.mp4)
  • Thumbnail - Story cover image (thumbnail.jpg)

Supported Formats:

  • Images: .jpg, .jpeg, .png, .gif, .webp
  • Audio: .wav, .mp3, .ogg, .m4a
  • Video: .mp4, .webm, .mov
  • Recommended avatar size: 200x200px to 500x500px
  • Recommended thumbnail size: 1200x630px

File References

When referencing assets in Ink scripts or JSON files, use just the filename (e.g., "alex-avatar.jpg"), not the full path.

News Directory

News articles are written in Markdown and appear in the in-game news feed. Located in src/news/.

Quick Overview

Each .md file in the news directory represents one news article with metadata tags at the top:

markdown
#initial
#title:Local Woman Reported Missing
#source:City News Network
#image:news-photo.jpg
#publishedAt:2025-10-22T10:00:00Z

**BREAKING**: A local woman has been reported missing...

Key Features

  • Markdown formatting - Full support for headings, lists, images, links, etc.
  • Metadata tags - Control title, source, images, and publication date
  • Initial unlock - Use #initial tag for articles available from the start
  • Timed unlocking - Unlock articles via Ink with #unlockNews:article-id[:delay]
  • State tracking - Check if articles are unlocked or read with external functions

Learn More

See the complete News System Guide for detailed documentation, examples, and best practices.

Notes Directory

Notes are written in Markdown and appear in the in-game notes app. Located in src/notes/.

Quick Overview

Each .md file in the notes directory represents one note with metadata tags at the top:

markdown
#initial
#title:Welcome to Your Notes

# Welcome to Your Notes

This is your personal notes app. Important information will appear here as you progress...

Key Features

  • Markdown formatting - Full support for headings, lists, tables, code blocks, etc.
  • Metadata tags - Control title and initial unlock status
  • Initial unlock - Use #initial tag for notes available from the start
  • Timed unlocking - Unlock notes via Ink with #unlockNote:note-id[:delay]
  • State tracking - Check if notes are unlocked or read with external functions

Common Use Cases

  • Clues and evidence - Important details players need to remember
  • Locations - Addresses, coordinates, access codes
  • Character information - Backgrounds, relationships, profiles
  • Timeline tracking - Sequence of events
  • Puzzle solutions - Codes, passwords, hints

Learn More

See the complete Notes System Guide for detailed documentation, examples, and best practices.

Gallery items (photos and videos) are defined in JSON files. Located in src/gallery/.

Quick Overview

Each .json file defines one gallery item with fields for type, asset, caption, and more:

json
{
  "type": "image",
  "asset": "crime-scene.jpg",
  "caption": "Evidence found at the warehouse",
  "takenAt": "2025-10-22T15:30:00Z",
  "initial": false
}

Key Features

  • Media types - Support for images and videos
  • Captions - Add descriptive text to provide context
  • Timestamps - Use takenAt to create a timeline of events
  • Initial unlock - Use "initial": true for items available from the start
  • Unlock via Ink - Use #gallery:item-id to unlock during gameplay
  • Dual display - Items appear in conversations and the gallery app

Common Use Cases

  • Evidence photos - Crime scenes, clues, documents
  • Security footage - CCTV, recordings, video evidence
  • Personal photos - Character selfies, group photos
  • Timeline creation - Visual sequence of events

Learn More

See the complete Gallery System Guide for detailed documentation, JSON field reference, and best practices.

Scripts Directory

build-story.cjs

Compiles your story:

  1. Finds all .ink files
  2. Compiles them to JSON using inkjs or inklecate
  3. Copies assets to build directory
  4. Generates manifest files
  5. Creates dist/story-build.zip

Usage:

bash
npm run build:story

Watch Mode:

bash
npm run build:story -- --watch

publish-story.cjs

Uploads your built story to an Encounters server:

  1. Runs the build script
  2. Reads credentials from .env
  3. Uploads story-build.zip via API

Usage:

bash
npm run publish:story

Environment Variables

The .env file stores your publishing credentials. Create it by copying .env.example:

bash
cp .env.example .env

Then fill in your details:

env
BASE_URL=https://encounters.andyh.app
STORY_ID=your-story-uuid-here
API_KEY=your-api-key-here

Getting Your Credentials

Story ID:

  1. Go to Stories Management
  2. Create your story
  3. Copy the UUID from the URL after creation

API Key:

  1. Go to Manage Passport Tokens
  2. Create a new token
  3. Copy the API key immediately (you won't see it again!)

Security

Never commit .env to version control! It contains sensitive API keys. Always add .env to your .gitignore file.

Build Output

After running npm run build:story, the dist/ directory contains:

dist/
└── story-build.zip       # Packaged story ready for upload

The zip file contains:

  • Compiled Ink scripts (.json)
  • All assets
  • Contact and conversation definitions
  • Story metadata
  • Manifest files

Visual Studio Code with Ink Extension

For the best development experience, use Visual Studio Code with the Ink extension:

Installation:

  1. Download Visual Studio Code (free)
  2. Install and open VS Code
  3. Open Extensions (Ctrl+Shift+X / Cmd+Shift+X)
  4. Search for "Ink" by inkle
  5. Click Install

Benefits:

  • Syntax highlighting for .ink files
  • Error detection as you type
  • Auto-completion for Ink keywords
  • File navigation - jump to knot definitions
  • Integrated terminal - run build commands without leaving the editor

Opening Your Project:

  1. Open VS Code
  2. File → Open Folder
  3. Select your story project folder
  4. All files will appear in the sidebar

Useful VS Code Features:

  • Explorer (left sidebar) - Browse all project files
  • Search (Ctrl+Shift+F / Cmd+Shift+F) - Find text across all files
  • Terminal (Ctrl+`` / Cmd+``) - Run npm run build:story directly in VS Code
  • Split view - Edit multiple files side-by-side

Best Practices

Organization

  • One contact per file - Keep contact definitions separate
  • Match IDs to filenames - alex.json should have "id": "alex"
  • Group related conversations - Use clear naming for group chats

Naming Conventions

  • IDs: lowercase-with-hyphens (e.g., family-group)
  • Display Names: Proper Case (e.g., "Alex Thompson")
  • Files: Match the ID (e.g., alex.json, alex.ink)

Asset Management

  • Optimize images - Compress before adding to reduce file size
  • Consistent naming - Use descriptive names (e.g., alex-avatar.jpg)
  • Organize by type - Consider subdirectories for large projects
  • Test media files - Ensure audio/video files play correctly before publishing

Content Organization

  • News articles - Use realistic news writing style, include publication dates
  • Notes - Keep concise and scannable, format important info clearly
  • Gallery items - Add descriptive captions, organize by story progression
  • Initial content - Mark welcome/tutorial content with #initial tag

Version Control

Add to .gitignore:

.env
node_modules/
dist/

Next Steps

Released under the MIT License.