Skip to content

Gulluth/SIGIL

Repository files navigation

EXPERIMENTAL SOFTWARE

SIGIL is experimental software, and should be treated as such. I am frequently making breaking API changes to tune SIGIL to the way I am expecting it to operate.

You have been warned!

SIGIL

Sigil Is Generative Interpretive Language

A minimalist YAML-based DSL for creating powerful random generators. Perfect for game development, creative writing, worldbuilding, and any application that needs procedural content generation.

What is SIGIL?

SIGIL transforms simple YAML lists into sophisticated random generators with intelligent text processing, automatic content merging, and flexible template syntax. Designed for both browser and Node.js environments.

Installation

npm install @gulluth/sigil

Quick Start

import { SigilEngine } from '@gulluth/sigil';

const engine = new SigilEngine();
await engine.loadData('./data/my-data.yaml');

// Generate content from templates
const result = engine.generate('my_template');
console.log(result);

Core Features

  • YAML-based data structure with automatic list merging
  • Hierarchical organization using dot notation
  • Weighted randomization with custom probabilities
  • Rich template syntax with inline processing
  • Text formatting modifiers for proper grammar
  • Graceful error handling with missing data
  • Browser and Node.js support for flexible deployment

Sigil Reference

SIGIL uses symbolic characters called sigils to define generation behavior. Each sigil has a specific meaning and purpose within templates:

Core Sigils

Sigil Name Purpose Example
[] Reference Sigil Access lists and tables [device] → "scanner"
{} Inline Sigil Inline processing container {red|blue} → "red"
| OR Sigil Choose one option {this|that} → "this"
& AND Sigil Combine multiple selections {red&large} → "redlarge"
^ Weight Sigil Control selection probability laser rifle ^2 → 2x more likely
? Optional Sigil Random inclusion [device?] → may or may not appear
! Exclusion Sigil Filter out items [device!broken] → working devices
* Repetition Sigil Repeat selections [component*3] → 3 components
. Modifier Sigil Apply text transformations [name.capitalize] → "John"

Special Patterns

Pattern Purpose Example
{a} Indefinite articles {a} [item] → "an apple"
{1-10} Number ranges {1-10} → random number 1-10
table.subtable Hierarchical access [shape.triangle] → from triangle subtable

Sigil Combinations

Sigils can be combined for complex behavior:

  • [device*{2-4}?] - Optionally generate 2-4 devices
  • [material!radioactive.capitalize] - Capitalized material, excluding radioactive
  • {[condition]&[device]} - Combine condition and device selections

Sigil Precedence and Evaluation Order

  • AND (&) vs Optional (?): When AND and optional are combined (e.g., {[a]&[b]?}), AND takes precedence. All referenced elements are always included; optionality is ignored in this context.
  • Weights and Repetition: When using both weights and repetition (e.g., [item^2*3]), weights are applied first. Each repetition is an independent draw from the weighted pool.

See the Error Handling Guide for more details and examples.

Complete Syntax Reference

Basic Templates

Reference lists using square brackets:

templates:
  basic_item: "[condition] [device]"

Weighted Lists

Control probability using ^ notation:

devices:
  - laser rifle ^2      # 2x more likely
  - plasma torch        # default weight (1)
  - scanner ^0.5        # half as likely

Hierarchical Selection

Use dot notation for organized data:

shape:
  quadrilateral:
    - square
    - rectangle
  triangle:
    - equilateral
    - isosceles

# Select from subcategory
templates:
  room: "The [shape.quadrilateral] room"

Inline Randomization

OR Selection - Pick one option:

templates:
  greeting: "Hello {there|friend|stranger}"

AND Combination - Combine from two lists:

# Descriptive combinations
templates:
  combo: "A {red&dwarf} object"  # e.g., "A reddwarf object"

# Compound word generation (names, terms)
name_prefixes:
  - Zyx
  - Nex
  - Vor
  - Keth

name_suffixes:
  - on
  - ax
  - prime
  - core

templates:
  survivor_name: "{[name_prefixes]&[name_suffixes]}"  # e.g., "Zyxon", "Nexcore"

Mixed References - Combine lists and inline options:

templates:
  mixed: "A {[color]|[pattern]|striped} design"

Number Ranges - Generate random numbers:

templates:
  quantity: "Found {1-10} coins"
  precise: "Exactly {2.5-7.3} meters"

Advanced Features

Optional Content - Random inclusion using ?:

templates:
  item: "[device] [modification?]"  # Modification may or may not appear

Exclusion Filters - Remove items using !:

templates:
  working_device: "[device!broken]"  # All devices except broken ones

Repetition - Repeat selections using *:

templates:
  treasure: "[component*{2-4}]"  # Generates 2-4 components

Text Formatting

Indefinite Articles - Automatic a/an:

templates:
  description: "{a} [shape]"  # "an octagon" or "a square"

Chained Modifiers (Left-to-Right order)

You can chain multiple modifiers using dot notation, e.g. [table.capitalize.lowercase]. Modifiers are applied in left-to-right order: the leftmost modifier is applied first, and the rightmost is applied last. This matches the order you see in the template and is the most intuitive for users.

Example:

templates:
  fancy_name: "[name.capitalize.lowercase]"
  # This will first capitalize the name, then lowercase the result.

Supported modifiers:

  • capitalize — Capitalize the first letter
  • lowercase — Convert all letters to lowercase
  • pluralForm — Pluralize the word
  • markov — Generate text using Markov chains

Markov Generation - AI-style text from training data:

templates:
  generated_callsign: "[survivor_names&settlements.markov]"

Data Organization

Automatic List Merging

Lists with the same name from different files are automatically combined:

# post-apocalypse.yaml
devices:
  - laser rifle
  - plasma cannon

# Result: All devices available together for genre blending

File Structure

Organize your data across multiple YAML files:

project/
├── data/
│   ├── devices.yaml
│   ├── survivors.yaml
│   └── settlements.yaml
└── generator.js

YAML Structure Approaches

Choose the organizational style that best fits your content complexity.

Flat Structure (Simple Lists)

Perfect for straightforward content:

# simple-data.yaml
entities:
  - radiation mutant ^2
  - scavenger android ^1.5
  - malfunctioning drone

locations:
  - abandoned facility ^2
  - irradiated wasteland
  - underground bunker

templates:
  encounter:
    - "You detect [sounds] echoing from the [locations]"
    - "A [atmosphere] [entities] prowls nearby"

Hierarchical Structure (Organized Categories)

Better for complex, organized content:

# organized-data.yaml
vessel:
  type:
    - transport ^2
    - interceptor
    - cargo hauler ^3
  status:
    - operational
    - damaged ^2
    - derelict ^1.5

templates:
  vessel_description: "A [vessel.status] [vessel.type]"

Error Handling & Reliability

SIGIL is designed with robustness in mind and includes comprehensive error handling:

  • Defensive programming: Attempts to return valid strings even with malformed syntax
  • Graceful degradation: Missing data typically returns placeholder text
  • Recursion limits: Includes protection against circular references
  • Unicode support: Handles emojis, accented characters, and special symbols

Complete Error Handling Guide →

Common Use Cases

  • Game Development: Procedural content, random events, character generation
  • Creative Writing: Plot generators, character traits, world details
  • Tabletop RPGs: Monsters, loot, NPCs, dungeon rooms, random encounters
  • Educational Tools: Quiz questions, example datasets, learning scenarios
  • Testing Data: Realistic mock data generation for applications

API Reference

Quick Reference

import { SigilEngine, loadSigilData } from '@gulluth/sigil';

// Single file
const engine = new SigilEngine();
await engine.loadData('./data/my-data.yaml');

// Multi-file (Node.js)
const data = loadSigilData(['./core.yaml', './expansion.yaml']);
const engine = new SigilEngine(data.lists);

const result = engine.generate('my_template');
console.log(result);

Key Methods:

  • loadData(filePath) - Load single YAML file (Node.js)
  • loadSigilData(filePaths[]) - Load and merge multiple files (Node.js)
  • generate(templateName) - Generate content from template
  • enableDebug(enable) - Toggle debug mode for troubleshooting

📖 Complete API Documentation → (includes browser/Vite examples)

License

MIT License - see LICENSE file for details.

Contributing

Contributions welcome! Please read the contributing guidelines and submit pull requests for any improvements.


SIGIL: Where symbols become worlds

About

A minimalist YAML-based DSL for worldbuilders

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •