{"id":42903040,"url":"https://github.com/videlais/story-grammar","last_synced_at":"2026-01-30T15:38:08.437Z","repository":{"id":318109755,"uuid":"1069999155","full_name":"videlais/story-grammar","owner":"videlais","description":"A combintorial grammar for narrative-based projects","archived":false,"fork":false,"pushed_at":"2026-01-01T22:01:26.000Z","size":519,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-18T16:43:45.813Z","etag":null,"topics":["content-generation","narrative","procedural-generation","typescript"],"latest_commit_sha":null,"homepage":"https://videlais.github.io/story-grammar/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/videlais.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-05T03:47:01.000Z","updated_at":"2026-01-01T22:01:24.000Z","dependencies_parsed_at":"2025-10-05T07:21:07.434Z","dependency_job_id":"a777d808-5869-4d62-b81e-478e0f84552a","html_url":"https://github.com/videlais/story-grammar","commit_stats":null,"previous_names":["videlais/story-grammar"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/videlais/story-grammar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videlais%2Fstory-grammar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videlais%2Fstory-grammar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videlais%2Fstory-grammar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videlais%2Fstory-grammar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/videlais","download_url":"https://codeload.github.com/videlais/story-grammar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videlais%2Fstory-grammar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28914906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["content-generation","narrative","procedural-generation","typescript"],"created_at":"2026-01-30T15:38:07.585Z","updated_at":"2026-01-30T15:38:08.431Z","avatar_url":"https://github.com/videlais.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Story Grammar\n\n[![CI](https://github.com/videlais/story-grammar/actions/workflows/ci.yml/badge.svg)](https://github.com/videlais/story-grammar/actions/workflows/ci.yml)\n[![Security Audit](https://github.com/videlais/story-grammar/actions/workflows/security-audit.yml/badge.svg)](https://github.com/videlais/story-grammar/actions/workflows/security-audit.yml)\n[![npm version](https://badge.fury.io/js/story-grammar.svg)](https://badge.fury.io/js/story-grammar)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA combinatorial grammar for generative and narrative-based projects.\n\nThis project is heavily inspired by the great work Kate Compton did and continues to do with [Tracery](https://github.com/galaxykate/tracery).\n\n## Table of Contents\n\n- [Story Grammar](#story-grammar)\n  - [Table of Contents](#table-of-contents)\n  - [Interactive Examples](#interactive-examples)\n  - [Overview](#overview)\n    - [Key Features](#key-features)\n  - [Features](#features)\n  - [Quick Start](#quick-start)\n  - [TypeScript Usage](#typescript-usage)\n  - [Examples](#examples)\n    - [Basic Usage](#basic-usage)\n    - [Complex Nested Variables](#complex-nested-variables)\n    - [Function Rules](#function-rules)\n    - [Weighted Rules](#weighted-rules)\n    - [Conditional Rules](#conditional-rules)\n    - [Sequential Rules](#sequential-rules)\n    - [Range Rules](#range-rules)\n    - [Template Rules](#template-rules)\n    - [Reference Rules](#reference-rules)\n    - [Seeded Randomness](#seeded-randomness)\n    - [Story Generation](#story-generation)\n    - [Error Handling](#error-handling)\n    - [Complexity Analysis](#complexity-analysis)\n    - [Probability Analysis](#probability-analysis)\n  - [Built-in Modifiers](#built-in-modifiers)\n    - [Loading Individual Modifiers](#loading-individual-modifiers)\n    - [Loading All English Modifiers](#loading-all-english-modifiers)\n    - [Basic English Modifiers](#basic-english-modifiers)\n  - [Modifier System](#modifier-system)\n    - [Modifier Features](#modifier-features)\n    - [Adding Custom Modifiers](#adding-custom-modifiers)\n    - [Example with Multiple Modifiers](#example-with-multiple-modifiers)\n    - [Modifier Interface](#modifier-interface)\n    - [Management Methods](#management-methods)\n    - [Priority System](#priority-system)\n  - [Built-in Modifiers Reference](#built-in-modifiers-reference)\n    - [English Articles (`EnglishArticleModifier`)](#english-articles-englisharticlemodifier)\n    - [English Pluralization (`EnglishPluralizationModifier`)](#english-pluralization-englishpluralizationmodifier)\n    - [English Ordinals (`EnglishOrdinalModifier`)](#english-ordinals-englishordinalmodifier)\n    - [English Capitalization (`EnglishCapitalizationModifier`)](#english-capitalization-englishcapitalizationmodifier)\n    - [English Possessives (`EnglishPossessiveModifier`)](#english-possessives-englishpossessivemodifier)\n    - [English Verb Agreement (`EnglishVerbAgreementModifier`)](#english-verb-agreement-englishverbagreementmodifier)\n    - [Punctuation Cleanup (`PunctuationCleanupModifier`)](#punctuation-cleanup-punctuationcleanupmodifier)\n  - [Performance and Utility Features](#performance-and-utility-features)\n    - [Batch Processing](#batch-processing)\n    - [Variation Generation](#variation-generation)\n    - [Performance Monitoring](#performance-monitoring)\n    - [Parser Analysis and Optimization](#parser-analysis-and-optimization)\n  - [Enhanced Error Handling](#enhanced-error-handling)\n    - [Safe Parsing](#safe-parsing)\n    - [Rule Analysis](#rule-analysis)\n    - [Helpful Error Messages](#helpful-error-messages)\n  - [Build and Deployment](#build-and-deployment)\n    - [TypeScript Build](#typescript-build)\n    - [Webpack Bundle](#webpack-bundle)\n    - [Browser Usage](#browser-usage)\n  - [API Reference](#api-reference)\n    - [Parser Class](#parser-class)\n      - [Static Rules](#static-rules)\n      - [Function Rule Methods](#function-rule-methods)\n      - [Weighted Rule Methods](#weighted-rule-methods)\n      - [Conditional Rule Methods](#conditional-rule-methods)\n      - [Sequential Rule Methods](#sequential-rule-methods)\n      - [Range Rule Methods](#range-rule-methods)\n      - [Template Rule Methods](#template-rule-methods)\n      - [Reference Rule Methods](#reference-rule-methods)\n      - [Parsing](#parsing)\n      - [Modifiers](#modifiers)\n      - [Modifier Loading Methods](#modifier-loading-methods)\n      - [Available English Modifiers](#available-english-modifiers)\n      - [Configuration](#configuration)\n    - [Types](#types)\n\n## Interactive Examples\n\nVisit the `docs/` folder for interactive examples demonstrating the Story Grammar library with the new modular modifier API:\n\n- **[Tarot Three-Card Spread](docs/tarot-three-card-spread.html)** - Generate mystical three-card tarot readings with Past • Present • Future spreads using Story Grammar's combinatorial rules. Features a complete 78-card tarot deck, dynamic card combinations and interpretations, and 474,552 possible combinations.\n\n- **[Weapon Loot Table Generator](docs/weapon-loot-generator.html)** - Generate RPG weapon loot with authentic rarity distribution using Story Grammar's weighted rules system. Includes 17 weapon types, realistic drop rates (Common 38.06%, Magic 50%, Rare 10.44%, Unique 1.5%), dynamic stats and special effects by rarity, and a color-coded rarity system with visual effects.\n\n## Overview\n\nThe Story Grammar Parser allows you to create complex, dynamic text generation systems using a simple key-value grammar with variable substitution.\n\n### Key Features\n\n## Features\n\n- **Simple Grammar Definition**: Define rules using key-value pairs\n- **Variable Expansion**: Use `%variable%` syntax for rule expansion\n- **Nested Variables**: Support for deeply nested rule references\n- **Function Rules**: Dynamic rule generation using JavaScript functions\n- **Weighted Rules**: Probability-based selection with custom weights\n- **Conditional Rules**: Context-aware selection based on previous values\n- **Sequential Rules**: Ordered cycling through values with reset capability\n- **Range Rules**: Numeric range generation (integers and floats)\n- **Template Rules**: Structured multi-variable combinations\n- **Reference Rules**: Reuse previously generated values for consistency\n- **Seeded Randomness**: Deterministic results for testing and reproducibility\n- **Modifier System**: Apply text transformations during generation\n- **Circular Reference Detection**: Automatic validation to prevent infinite loops\n- **TypeScript Support**: Full type definitions included\n- **Complexity Analysis**: Calculate the generative potential of rule collections\n- **Probability Analysis**: Determine the likelihood of different outcomes\n- **Zero Dependencies**: Pure TypeScript implementation\n\n## Quick Start\n\n```typescript\nimport { Parser } from 'story-grammar';\n\nconst parser = new Parser();\n\n// Define simple rules\nparser.addRule('flowers', ['roses', 'daisies', 'tulips']);\nparser.addRule('colors', ['red', 'blue', 'yellow']);\n\n// Define complex rules with variables\nparser.addRule('colored_flowers', ['%colors% %flowers%']);\n\n// Generate text\nconst result = parser.parse('I see beautiful %colored_flowers% in the garden.');\nconsole.log(result); // \"I see beautiful red roses in the garden.\"\n```\n\n## TypeScript Usage\n\nStory Grammar includes full TypeScript support with comprehensive type definitions. All interfaces are exported for type-safe development:\n\n```typescript\nimport { \n  Parser, \n  Grammar, \n  FunctionRule, \n  ConditionalRule, \n  Modifier,\n  ParserStats\n} from 'story-grammar';\n\n// Type-safe grammar definition\nconst grammar: Grammar = {\n  protagonist: ['brave knight', 'clever wizard'],\n  action: ['rescued', 'discovered'],\n  treasure: ['ancient scroll', 'magical sword']\n};\n\n// Function rules with proper typing\nconst dynamicRule: FunctionRule = () =\u003e {\n  return ['dynamically generated value'];\n};\n\n// Conditional rules with typed context\nconst contextualRule: ConditionalRule = {\n  conditions: [\n    {\n      if: (context: { [key: string]: string }) =\u003e context.mood === 'happy',\n      then: ['Great!', 'Wonderful!']\n    },\n    {\n      default: ['Okay', 'Sure']\n    }\n  ]\n};\n\n// Custom modifiers with type safety\nconst customModifier: Modifier = {\n  name: 'custom',\n  condition: (text: string) =\u003e text.includes('test'),\n  transform: (text: string) =\u003e text.toUpperCase(),\n  priority: 5\n};\n\nconst parser = new Parser();\nparser.addRules(grammar);\nparser.addFunctionRule('dynamic', dynamicRule);\nparser.addConditionalRule('contextual', contextualRule);\nparser.addModifier(customModifier);\n\n// Type-safe parsing and statistics\nconst result: string = parser.parse('%protagonist% %action% %treasure%');\nconst stats: ParserStats = parser.getStats();\n```\n\nSee [`typescript-usage-example.ts`](./typescript-usage-example.ts) for a complete working example.\n\n## Examples\n\n### Basic Usage\n\n```typescript\nimport { Parser } from 'story-grammar';\n\nconst parser = new Parser();\n\nparser.addRule('flowers', ['roses', 'daisies', 'tulips']);\nparser.addRule('colors', ['red', 'blue', 'pink']);\n\nconst text = 'I see a random %colors% %flowers%.';\nconsole.log(parser.parse(text));\n// Output: \"I see a random blue roses.\" (randomized)\n```\n\n### Complex Nested Variables\n\n```typescript\n### Nested Variables\n\nVariables can reference other variables:\n\n```typescript\nparser.addRule('greeting', ['Hello %name%!', 'Hi there %name%!']);\nparser.addRule('name', ['Alice', 'Bob', 'Charlie']);\nparser.addRule('farewell', ['Goodbye %name%', 'See you later %name%']);\n\nconsole.log(parser.parse('%greeting% %farewell%'));\n// Output: \"Hello Alice! See you later Bob\"\n```\n\n### Function Rules\n\nCreate dynamic rules that generate values at runtime:\n\n```typescript\n// Add a function rule that returns random numbers\nparser.addFunctionRule('randomNumber', () =\u003e {\n    const num = Math.floor(Math.random() * 100) + 1;\n    return [num.toString()];\n});\n\n// Add a function rule for dice rolls\nparser.addFunctionRule('diceRoll', () =\u003e {\n    const roll = Math.floor(Math.random() * 20) + 1;\n    return [`${roll} (d20)`];\n});\n\n// Add a function rule for current time\nparser.addFunctionRule('timestamp', () =\u003e {\n    return [new Date().toLocaleTimeString()];\n});\n\nconsole.log(parser.parse('Player rolls %diceRoll% at %timestamp%'));\n// Output: \"Player rolls 15 (d20) at 3:45:21 PM\"\n\nconsole.log(parser.parse('Random encounter strength: %randomNumber%'));\n// Output: \"Random encounter strength: 73\"\n```\n\nFunction rules are perfect for:\n\n- Random numbers and dice rolls\n- Current date/time values\n- Dynamic calculations\n- External API data (when used with async patterns)\n- Any content that changes each time it's generated\n\n### Weighted Rules\n\nCreate rules where some values are more likely than others using probability weights:\n\n```typescript\n// Equal probability (default behavior)\nparser.addRule('color', ['red', 'green', 'blue']); // Each has 33.33% chance\n\n// Weighted probability - weights must sum to 1.0\nparser.addWeightedRule('rarity', \n  ['common', 'uncommon', 'rare', 'epic', 'legendary'], \n  [0.50, 0.30, 0.15, 0.04, 0.01]\n);\n\n// More realistic treasure distribution\nparser.addWeightedRule('treasure', \n  ['coins', 'jewelry', 'weapon', 'armor', 'artifact'], \n  [0.40, 0.25, 0.20, 0.10, 0.05]\n);\n\nconsole.log(parser.parse('You found %rarity% %treasure%!'));\n// Output: \"You found common coins!\" (most likely)\n// Output: \"You found legendary artifact!\" (very rare - 0.05% chance)\n```\n\nWeighted rules are ideal for:\n\n- Realistic item rarity in games (common items more frequent than legendary)\n- Weather patterns (sunny days more common than storms)\n- Character traits (normal attributes more common than exceptional ones)\n- Any scenario where natural distribution isn't uniform\n\n### Conditional Rules\n\nCreate context-aware rules that select values based on previously generated content:\n\n```typescript\nparser.addRule('character_type', ['warrior', 'mage', 'rogue']);\nparser.addConditionalRule('weapon', {\n  conditions: [\n    {\n      if: (context) =\u003e context.character_type === 'warrior',\n      then: ['sword', 'axe', 'hammer']\n    },\n    {\n      if: (context) =\u003e context.character_type === 'mage', \n      then: ['staff', 'wand', 'orb']\n    },\n    {\n      default: ['dagger', 'bow'] // Fallback for any other case\n    }\n  ]\n});\n\nconsole.log(parser.parse('A %character_type% wielding a %weapon%'));\n// Output: \"A warrior wielding a sword\" (weapon matches character type)\n```\n\n### Sequential Rules\n\nGenerate values in a specific order, with optional cycling:\n\n```typescript\n// Cycling sequence (repeats after end)\nparser.addSequentialRule('day', ['Monday', 'Tuesday', 'Wednesday'], { cycle: true });\n\n// Non-cycling sequence (stops at last value)  \nparser.addSequentialRule('countdown', ['3', '2', '1', 'GO!'], { cycle: false });\n\nconsole.log(parser.parse('%day%')); // Monday\nconsole.log(parser.parse('%day%')); // Tuesday\nconsole.log(parser.parse('%day%')); // Wednesday\nconsole.log(parser.parse('%day%')); // Monday (cycles back)\n\n// Reset a sequential rule to start over\nparser.resetSequentialRule('countdown');\n```\n\n### Range Rules\n\nGenerate numeric values within specified ranges:\n\n```typescript\n// Integer ranges\nparser.addRangeRule('age', { min: 18, max: 65, type: 'integer' });\n\n// Float ranges with custom steps\nparser.addRangeRule('height', { min: 5.0, max: 6.5, step: 0.1, type: 'float' });\n\n// Percentage scores\nparser.addRangeRule('score', { min: 0, max: 100, type: 'integer' });\n\nconsole.log(parser.parse('Character: age %age%, height %height%ft, score %score%'));\n// Output: \"Character: age 34, height 5.7ft, score 87\"\n```\n\n### Template Rules\n\nCreate structured combinations with their own variable sets:\n\n```typescript\nparser.addTemplateRule('npc', {\n  template: '%name% the %adjective% %profession%',\n  variables: {\n    name: ['Aldric', 'Brina', 'Caius'],\n    adjective: ['brave', 'wise', 'cunning'],\n    profession: ['knight', 'merchant', 'scholar']\n  }\n});\n\nconsole.log(parser.parse('Meet %npc%'));\n// Output: \"Meet Brina the cunning merchant\"\n```\n\n### Reference Rules\n\nReuse previously generated values for consistency:\n\n```typescript\nparser.addRule('hero', ['Alice', 'Bob', 'Charlie']);\nparser.addRule('quest', ['rescue the princess', 'slay the dragon']);\n\n// Use @ prefix to reference previously generated values\nconst story = parser.parse(\n  '%hero% begins to %quest%. Later, %@hero% succeeds and %@hero% becomes legendary.',\n  true  // preserveContext = true\n);\n// Output: \"Alice begins to slay the dragon. Later, Alice succeeds and Alice becomes legendary.\"\n```\n\n**Advanced Rule Combinations:**\n\nAll rule types can work together seamlessly:\n\n```typescript\nparser.addConditionalRule('spell_power', {\n  conditions: [\n    { if: (ctx) =\u003e ctx.character_type === 'mage', then: ['devastating', 'reality-bending'] },\n    { default: ['weak', 'fizzling'] }\n  ]\n});\n\nparser.parse('%character_type% %@character_type% casts a %spell_power% spell', true);\n// Output: \"mage mage casts a devastating spell\" (consistent character, appropriate power)\n```\n\n### Seeded Randomness\n\nFor testing and reproducible results, you can seed the random number generator:\n\n```typescript\nconst parser = new Parser();\nparser.addRule('character', ['Alice', 'Bob', 'Charlie']);\nparser.addWeightedRule('rarity', ['common', 'rare'], [0.8, 0.2]);\n\n// Set a seed for deterministic results\nparser.setRandomSeed(12345);\n\nconsole.log(parser.parse('%character% finds %rarity% treasure'));\n// Will always produce the same result with the same seed\n\n// Generate multiple consistent results\nfor (let i = 0; i \u003c 3; i++) {\n  console.log(parser.parse('%character% finds %rarity% treasure'));\n}\n\n// Reset to same seed to reproduce the exact same sequence\nparser.setRandomSeed(12345);\nconsole.log(parser.parse('%character% finds %rarity% treasure')); // Same as first result\n\n// Clear seed to return to true randomness\nparser.clearRandomSeed();\nconsole.log(parser.parse('%character% finds %rarity% treasure')); // Random again\n```\n\n**Note:** Seeded randomness affects the parser's internal random selection for static and weighted rules. Function rules that use `Math.random()` internally will remain random unless you implement seeding within your functions.\n\nSeeded randomness is perfect for:\n\n- Unit testing with predictable outcomes\n- Debugging complex grammar combinations\n- Generating reproducible procedural content\n- Creating consistent examples for documentation\n\n### Story Generation\n\n```typescript\nparser.addRules({\n  characters: ['princess', 'knight', 'dragon', 'wizard'],\n  locations: ['castle', 'forest', 'mountain', 'village'],\n  actions: ['discovered', 'protected', 'explored', 'enchanted'],\n  objects: ['treasure', 'magic sword', 'ancient book', 'crystal'],\n  \n  story_elements: ['%characters%', '%locations%', '%objects%'],\n  story_template: [\n    'The %characters% %actions% a %objects% in the %locations%.',\n    'Once upon a time, a %characters% lived in a %locations%.',\n    'A brave %characters% went to the %locations% seeking %objects%.'\n  ]\n});\n\n// Generate multiple story variations\nfor (let i = 0; i \u003c 3; i++) {\n  console.log(parser.parse('%story_template%'));\n}\n```\n\n### Error Handling\n\n```typescript\n// Handle undefined variables gracefully\nconst result = parser.parse('Unknown %variable% stays unchanged');\nconsole.log(result); // \"Unknown %variable% stays unchanged\"\n\n// Prevent infinite recursion\nparser.addRule('infinite', ['%infinite% loop']);\ntry {\n  parser.parse('This is %infinite%');\n} catch (error) {\n  console.log(error.message); // \"Maximum recursion depth exceeded...\"\n}\n\n// Validate grammar\nconst validation = parser.validate();\nif (!validation.isValid) {\n  console.log('Missing rules:', validation.missingRules);\n  console.log('Circular references:', validation.circularReferences);\n}\n```\n\n### Complexity Analysis\n\nAnalyze the generative potential of your grammar rules:\n\n```typescript\n// Simple complexity calculation\nparser.addRule('colors', ['red', 'blue', 'green']);\nparser.addRule('animals', ['cat', 'dog']);\nparser.addRule('description', ['The %colors% %animals%']);\n\n// Calculate complexity for a specific rule\nconst ruleComplexity = parser.calculateRuleComplexity('description');\nconsole.log(ruleComplexity.complexity); // 6 (3 colors × 2 animals)\nconsole.log(ruleComplexity.variables); // ['colors', 'animals']\nconsole.log(ruleComplexity.ruleType); // 'static'\n\n// Calculate total complexity across all rules\nconst totalComplexity = parser.calculateTotalComplexity();\nconsole.log(totalComplexity.totalComplexity); // 11 (3 + 2 + 6)\nconsole.log(totalComplexity.averageComplexity); // 3.67\nconsole.log(totalComplexity.mostComplexRules[0].ruleName); // 'description'\n```\n\n**Complexity Features:**\n\n- **Individual Rule Analysis**: Calculate how many possible outcomes a single rule can produce\n- **Total Grammar Analysis**: Get comprehensive statistics about your entire grammar\n- **Circular Reference Detection**: Identifies and handles circular dependencies gracefully\n- **Infinite Complexity Detection**: Detects function rules and other infinite-complexity scenarios\n- **Detailed Warnings**: Provides insights about missing rules, depth limits, and potential issues\n\n**Rule Type Complexities:**\n\n- **Static Rules**: Sum of all value possibilities (accounting for nested variables)\n- **Weighted Rules**: Same as static (weights don't affect possibility count)\n- **Range Rules**: `(max - min) / step + 1` possible values\n- **Template Rules**: Product of all template variable possibilities\n- **Sequential Rules**: Number of values in the sequence\n- **Conditional Rules**: Sum of possibilities across all conditions\n- **Function Rules**: Marked as infinite complexity\n\n```typescript\n// Complex nested example\nparser.addRule('adjectives', ['big', 'small']);\nparser.addRule('materials', ['wooden', 'metal', 'glass']);\nparser.addRule('objects', ['%adjectives% %materials% box']);\nparser.addRangeRule('quantity', { min: 1, max: 5, type: 'integer' });\nparser.addTemplateRule('inventory', {\n  template: '%quantity% %objects%',\n  variables: {\n    // uses external rules for objects and quantity\n  }\n});\n\nconst analysis = parser.calculateTotalComplexity();\nconsole.log(`Total possible combinations: ${analysis.totalComplexity}`);\n// Outputs combinations across all interconnected rules\n\n// Detect potential issues\nif (analysis.warnings.length \u003e 0) {\n  console.log('Warnings:', analysis.warnings);\n}\nif (analysis.circularReferences.length \u003e 0) {\n  console.log('Circular references found:', analysis.circularReferences);\n}\n```\n\n### Probability Analysis\n\nAnalyze the probability distribution of your grammar rules to understand outcome likelihood:\n\n```typescript\n// Basic probability analysis\nparser.addWeightedRule('rarity', ['common', 'rare', 'legendary'], [0.7, 0.2, 0.1]);\nparser.addRule('items', ['sword', 'shield']);\nparser.addRule('loot', ['%rarity% %items%']);\n\n// Calculate probability distribution for a rule\nconst analysis = parser.calculateProbabilities('loot');\nconsole.log(`Total possible outcomes: ${analysis.totalOutcomes}`); // 6\nconsole.log(`Entropy (randomness): ${analysis.entropy.toFixed(2)}`); // Measure of uncertainty\n\n// Most probable outcomes\nconsole.log('Most likely outcomes:');\nanalysis.mostProbable.forEach(outcome =\u003e {\n  console.log(`${outcome.outcome}: ${(outcome.probability * 100).toFixed(1)}%`);\n});\n// Output:\n// common sword: 35.0%\n// common shield: 35.0%\n// rare sword: 10.0%\n// rare shield: 10.0%\n// legendary sword: 5.0%\n\n// Least probable outcomes\nconsole.log('Rarest outcomes:');\nanalysis.leastProbable.forEach(outcome =\u003e {\n  console.log(`${outcome.outcome}: ${(outcome.probability * 100).toFixed(1)}%`);\n});\n```\n\n**Quick Access Methods:**\n\n```typescript\n// Get single most/least probable outcomes\nconst mostProbable = parser.getMostProbableOutcome('loot');\nconsole.log(`Most likely: ${mostProbable.outcome} (${(mostProbable.probability * 100).toFixed(1)}%)`);\n\nconst leastProbable = parser.getLeastProbableOutcome('loot');\nconsole.log(`Rarest: ${leastProbable.outcome} (${(leastProbable.probability * 100).toFixed(1)}%)`);\n```\n\n**Probability Features:**\n\n- **Weighted Rule Analysis**: Respects probability weights from weighted rules\n- **Nested Probability Calculation**: Handles complex nested variable dependencies\n- **Entropy Calculation**: Measures the randomness/uncertainty of outcomes\n- **Probability Trees**: Shows the probability chain for complex expansions\n- **Multiple Rule Type Support**: Works with all rule types (static, weighted, range, template, etc.)\n\n**Rule Type Probabilities:**\n\n- **Static Rules**: Equal probability (1/n) for each value\n- **Weighted Rules**: Uses specified probability weights\n- **Range Rules**: Uniform distribution across the range\n- **Template Rules**: Product of component variable probabilities\n- **Conditional Rules**: Assumes equal probability for each condition\n- **Function Rules**: Marked as dynamic (cannot calculate exact probabilities)\n\n**Advanced Probability Analysis:**\n\n```typescript\n// Complex nested probability analysis\nparser.addRule('adjectives', ['big', 'small']);\nparser.addWeightedRule('colors', ['red', 'blue'], [0.7, 0.3]);\nparser.addRule('objects', ['%adjectives% %colors% box']);\n\nconst objectAnalysis = parser.calculateProbabilities('objects');\n\n// Check specific outcome probabilities\nconst bigRedBox = objectAnalysis.outcomes.find(o =\u003e o.outcome === 'big red box');\nconsole.log(`Big red box probability: ${(bigRedBox.probability * 100).toFixed(1)}%`); // 35.0%\n\n// Analyze probability distribution\nif (objectAnalysis.entropy \u003e 1.5) {\n  console.log('High randomness - outcomes are fairly distributed');\n} else {\n  console.log('Low randomness - some outcomes are much more likely');\n}\n\n// Examine probability trees for complex rules\nobjectAnalysis.outcomes.forEach(outcome =\u003e {\n  console.log(`${outcome.outcome}:`);\n  outcome.probabilityTree.forEach(node =\u003e {\n    console.log(`  ${node.ruleName}: ${node.value} (${node.probability})`);\n  });\n});\n```\n\n**Performance Considerations:**\n\n```typescript\n// Control analysis scope for large grammars\nconst limitedAnalysis = parser.calculateProbabilities('complexRule', \n  50,    // maxDepth: prevent deep recursion\n  1000   // maxOutcomes: limit total outcomes calculated\n);\n\nif (limitedAnalysis.warnings.length \u003e 0) {\n  console.log('Analysis warnings:', limitedAnalysis.warnings);\n}\n```\n\n## Built-in Modifiers\n\nThe parser uses a modular modifier system that allows loading language-specific modifiers as needed:\n\n### Loading Individual Modifiers\n\n```typescript\nimport { Parser, EnglishArticleModifier, EnglishPluralizationModifier } from 'story-grammar';\n\nconst parser = new Parser();\n\n// Load specific modifiers\nparser.loadModifier(EnglishArticleModifier);\nparser.loadModifier(EnglishPluralizationModifier);\n\n// Automatically corrects \"a\" to \"an\" before vowel sounds\nparser.addRule('items', ['a elephant', 'a umbrella', 'a house']);\nconsole.log(parser.parse('%items%')); \n// Outputs: \"an elephant\", \"an umbrella\", \"a house\"\n\n// Automatically pluralizes nouns with quantity indicators\nparser.addRule('animals', ['cat', 'dog', 'mouse', 'child']);\nconsole.log(parser.parse('I saw many %animals%')); \n// Outputs: \"I saw many cats\", \"I saw many dogs\", \"I saw many mice\", \"I saw many children\"\n```\n\n### Loading All English Modifiers\n\n```typescript\nimport { Parser, AllEnglishModifiers } from 'story-grammar';\n\nconst parser = new Parser();\n\n// Load all English modifiers at once\nparser.loadModifiers(AllEnglishModifiers);\n\n// Now all English language features are available:\n// - Article correction (a/an)\n// - Pluralization (many cats)\n// - Ordinals (1st, 2nd, 3rd)\n// - Capitalization (sentence starts)\n// - Possessives (John's car)\n// - Verb agreement (he is, they are)\n// - Punctuation cleanup\n```\n\n### Basic English Modifiers\n\n```typescript\nimport { Parser, BasicEnglishModifiers } from 'story-grammar';\n\nconst parser = new Parser();\n\n// Load only core modifiers for performance\nparser.loadModifiers(BasicEnglishModifiers);\n// Includes: articles, pluralization, ordinals\n```\n\n### Namespace Structure (New in v1.0.5)\n\nStory Grammar now organizes modifiers in a clean namespace structure for better organization and future multi-language support:\n\n```typescript\nimport { Parser, Modifiers } from 'story-grammar';\n\nconst parser = new Parser();\n\n// Import from English namespace\nparser.loadModifier(Modifiers.English.ArticleModifier);\nparser.loadModifier(Modifiers.English.PluralizationModifier);\nparser.loadModifier(Modifiers.English.CapitalizationModifier);\n\n// Or load all English modifiers at once\nparser.loadModifiers(Modifiers.English.AllEnglishModifiers);\n\n// Individual imports are also available for convenience\nparser.loadModifier(Modifiers.ArticleModifier);\nparser.loadModifiers(Modifiers.AllEnglishModifiers);\n```\n\n#### Namespace Imports\n\n```typescript\n// Import specific language namespace\nimport { English } from 'story-grammar/modifiers';\n\n// Import all modifiers\nimport { Modifiers } from 'story-grammar';\n\n// Future support for additional languages:\n// import { Spanish, French } from 'story-grammar/modifiers';\n```\n\n#### Available English Modifiers in Namespace\n\n- `Modifiers.English.ArticleModifier` - Handles a/an article correction\n- `Modifiers.English.PluralizationModifier` - Pluralizes nouns with quantity words\n- `Modifiers.English.OrdinalModifier` - Converts numbers to ordinals (1st, 2nd, 3rd)\n- `Modifiers.English.CapitalizationModifier` - Capitalizes sentence starts\n- `Modifiers.English.PossessiveModifier` - Handles possessive forms (John's, cats')\n- `Modifiers.English.VerbAgreementModifier` - Basic subject-verb agreement\n- `Modifiers.English.PunctuationCleanupModifier` - Cleans up spacing around punctuation\n\n**Note**: The original exports remain available for backward compatibility.\n\n## Modifier System\n\nThe Story Grammar parser includes a powerful modifier system that allows you to apply transformations to generated text after variable expansion.\n\n### Modifier Features\n\n- **Conditional Application**: Modifiers only apply when their condition is met\n- **Priority System**: Modifiers are applied in priority order (higher numbers first)\n- **Built-in Article Modifier**: Automatically handles English \"a/an\" articles\n- **Built-in Pluralization Modifier**: Automatically pluralizes nouns with quantity words\n- **Built-in Ordinal Modifier**: Converts cardinal numbers to ordinal format (1st, 2nd, 3rd, etc.)\n- **Chainable**: Multiple modifiers can be applied to the same text\n\n### Adding Custom Modifiers\n\n```typescript\nparser.addModifier({\n  name: 'emphasize',\n  condition: (text: string) =\u003e text.includes('important'),\n  transform: (text: string) =\u003e text.replace(/important/g, 'IMPORTANT'),\n  priority: 5\n});\n```\n\n### Example with Multiple Modifiers\n\nWith the article modifier enabled:\n\n```text\nInput:  \"I found a %adjective% %noun%\"\nRules:  adjective: ['old', 'ancient'], noun: ['apple', 'elephant']\nOutput: \"I found an old apple\" or \"I found an ancient elephant\"\n```\n\n### Modifier Interface\n\n```typescript\ninterface Modifier {\n  name: string;\n  condition: ModifierFunction;\n  transform: ModifierFunction;\n  priority: number;\n}\n```\n\n### Management Methods\n\n- `addModifier(modifier)` - Add a new modifier\n- `removeModifier(name)` - Remove a modifier by name\n- `clearModifiers()` - Remove all modifiers\n- `hasModifier(name)` - Check if a modifier exists\n\n### Priority System\n\nModifiers with higher priority numbers are applied first. This allows you to control the order of transformations. For example:\n\n1. Priority 10: Article correction (a/an)\n2. Priority 9: Pluralization (many/several/three/etc.)\n3. Priority 8: Ordinal conversion (1st/2nd/3rd/etc.)\n4. Priority 7: Capitalization fixes\n5. Priority 1: Punctuation cleanup\n\nThis ensures that language-specific transformations (articles, plurals, ordinals) are handled before stylistic transformations.\n\n## Built-in Modifiers Reference\n\nAll English modifiers are available as separate imports and can be loaded individually or in groups:\n\n```typescript\nimport { \n  EnglishArticleModifier,\n  EnglishPluralizationModifier,\n  EnglishOrdinalModifier,\n  EnglishCapitalizationModifier,\n  EnglishPossessiveModifier,\n  EnglishVerbAgreementModifier,\n  PunctuationCleanupModifier,\n  AllEnglishModifiers,\n  BasicEnglishModifiers\n} from 'story-grammar';\n```\n\n### English Articles (`EnglishArticleModifier`)\n\n- **Priority**: 10\n- **Function**: Converts \"a\" to \"an\" before vowel sounds\n- **Examples**: \"a elephant\" → \"an elephant\", \"a umbrella\" → \"an umbrella\"\n\n### English Pluralization (`EnglishPluralizationModifier`)\n\n- **Priority**: 9\n- **Function**: Pluralizes nouns when quantity indicators are present\n- **Triggers**: \"many\", \"several\", \"multiple\", \"few\", numbers \u003e 1, written numbers\n- **Rules**:\n  - Regular: \"cat\" → \"cats\"\n  - S/X/Z/CH/SH endings: \"box\" → \"boxes\"\n  - Consonant+Y: \"fly\" → \"flies\"\n  - F/FE endings: \"leaf\" → \"leaves\"\n  - Irregular: \"child\" → \"children\", \"mouse\" → \"mice\"\n- **Examples**: \"three cat\" → \"three cats\", \"many child\" → \"many children\"\n\n### English Ordinals (`EnglishOrdinalModifier`)\n\n- **Priority**: 8\n- **Function**: Converts cardinal numbers to ordinal format\n- **Triggers**: Any standalone number (digits)\n- **Rules**:\n  - Numbers ending in 1: \"1\" → \"1st\", \"21\" → \"21st\"\n  - Numbers ending in 2: \"2\" → \"2nd\", \"22\" → \"22nd\"\n  - Numbers ending in 3: \"3\" → \"3rd\", \"33\" → \"33rd\"\n  - Exception - 11, 12, 13: \"11\" → \"11th\", \"112\" → \"112th\"\n  - All others: \"4\" → \"4th\", \"100\" → \"100th\"\n- **Examples**: \"1 place\" → \"1st place\", \"22 floor\" → \"22nd floor\"\n\n### English Capitalization (`EnglishCapitalizationModifier`)\n\n- **Priority**: 7\n- **Function**: Capitalizes words after sentence-ending punctuation\n- **Triggers**: Lowercase letters following periods, exclamation marks, or question marks\n- **Examples**: \"hello. world\" → \"hello. World\", \"what? yes!\" → \"what? Yes!\"\n\n### English Possessives (`EnglishPossessiveModifier`)\n\n- **Priority**: 6\n- **Function**: Handles English possessive forms\n- **Triggers**: \"possessive\" marker and malformed possessives\n- **Rules**:\n  - Regular nouns: \"John possessive\" → \"John's\"\n  - Plural nouns: \"boys possessive\" → \"boys'\"\n  - Fix doubles: \"John's's\" → \"John's\"\n- **Examples**: \"cat possessive toy\" → \"cat's toy\"\n\n### English Verb Agreement (`EnglishVerbAgreementModifier`)\n\n- **Priority**: 5\n- **Function**: Fixes basic subject-verb agreement\n- **Triggers**: Mismatched subjects and verbs (is/are, has/have)\n- **Rules**:\n  - Singular subjects: \"he are\" → \"he is\", \"she have\" → \"she has\"\n  - Plural/quantified subjects: \"they is\" → \"they are\", \"many has\" → \"many have\"\n- **Examples**: \"he are happy\" → \"he is happy\", \"many is here\" → \"many are here\"\n\n### Punctuation Cleanup (`PunctuationCleanupModifier`)\n\n- **Priority**: 1\n- **Function**: Fixes common punctuation and spacing issues\n- **Triggers**: Multiple spaces, incorrect punctuation spacing\n- **Rules**:\n  - Multiple spaces → single space\n  - Space before punctuation → removed\n  - Missing space after punctuation → added\n  - Trim leading/trailing whitespace\n- **Examples**: \"hello  ,  world\" → \"hello, world\"\n\n## Performance and Utility Features\n\n### Batch Processing\n\nProcess multiple texts efficiently with shared context:\n\n```typescript\nconst texts = [\n  'I saw a %animal%',\n  'The %animal% was %color%',\n  'It ran %direction%'\n];\n\nconst results = parser.parseBatch(texts, true); // preserve context\n// Results will use consistent values across all texts\n```\n\n### Variation Generation\n\nGenerate multiple variations for testing or options:\n\n```typescript\n// Generate 5 variations with consistent seed\nconst variations = parser.generateVariations('%greeting% %name%!', 5, 12345);\nconsole.log(variations);\n// [\"Hello Alice!\", \"Hi Bob!\", \"Hey Charlie!\", \"Hello David!\", \"Hi Eve!\"]\n```\n\n### Performance Monitoring\n\nMonitor parsing performance with detailed timing:\n\n```typescript\nconst result = parser.parseWithTiming('%complex_rule%');\nconsole.log(`Total: ${result.timing.totalMs}ms`);\nconsole.log(`Expansion: ${result.timing.expansionMs}ms`);\nconsole.log(`Modifiers: ${result.timing.modifierMs}ms`);\n```\n\n### Parser Analysis and Optimization\n\nAnalyze your parser for optimization opportunities:\n\n```typescript\n// Get statistics\nconst stats = parser.getStats();\nconsole.log(`Total rules: ${stats.totalRules}`);\nconsole.log(`Rule breakdown:`, stats.rulesByType);\n\n// Analyze complexity\nconst analysis = parser.analyzeRules();\nconsole.log(`Most complex rules:`, analysis.mostComplex);\nconsole.log(`Suggestions:`, analysis.suggestions);\n\n// Get optimization recommendations\nconst optimization = parser.optimize();\nif (!optimization.optimized) {\n  console.log('Warnings:', optimization.warnings);\n  console.log('Suggestions:', optimization.suggestions);\n}\n```\n\n## Enhanced Error Handling\n\n### Safe Parsing\n\nParse with automatic error recovery and detailed diagnostics:\n\n```typescript\nconst result = parser.safeParse('%potentially_problematic%', {\n  validateFirst: true,    // Validate rules before parsing\n  maxAttempts: 3,        // Retry with reduced complexity\n  preserveContext: false\n});\n\nif (result.success) {\n  console.log('Result:', result.result);\n  console.log('Attempts needed:', result.attempts);\n} else {\n  console.log('Error:', result.error);\n  if (result.validation) {\n    console.log('Missing rules:', result.validation.missingRules);\n  }\n}\n```\n\n### Rule Analysis\n\nAnalyze individual rules for complexity and issues:\n\n```typescript\n// Analyze specific rule\nconst ruleAnalysis = parser.analyzeRules('complex_rule');\nconsole.log('Complexity score:', ruleAnalysis.ruleDetails?.complexity);\nconsole.log('Variables used:', ruleAnalysis.ruleDetails?.variables);\nconsole.log('Nesting depth:', ruleAnalysis.ruleDetails?.depth);\n```\n\n### Helpful Error Messages\n\nGet detailed error explanations with actionable suggestions:\n\n```typescript\ntry {\n  parser.parse('%problematic_rule%');\n} catch (error) {\n  const helpfulMessage = parser.getHelpfulError(error, {\n    text: '%problematic_rule%',\n    ruleName: 'problematic_rule'\n  });\n  \n  console.log(helpfulMessage);\n  // Includes suggestions, validation issues, and troubleshooting tips\n}\n```\n\n## Build and Deployment\n\n### TypeScript Build\n\nBuild the library for Node.js environments:\n\n```bash\nnpm run build\n```\n\nThis creates:\n\n- **TypeScript declaration files** in the `types/` directory\n- **JavaScript modules** in the `dist/` directory\n\nThe separated structure keeps type definitions cleanly organized from compiled code.\n\n### Webpack Bundle\n\nBuild the library for browser environments:\n\n```bash\n# Production build (minified)\nnpm run build:webpack\n\n# Development build (unminified with source maps)\nnpm run build:webpack:dev\n\n# Build both TypeScript and Webpack\nnpm run build:all\n```\n\nThis creates:\n\n- `dist/story-grammar.bundle.js` - Production browser bundle (minified)\n- `dist/story-grammar.dev.bundle.js` - Development browser bundle  \n- Source maps for debugging\n\n### Browser Usage\n\nInclude the webpack bundle in your HTML:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n    \u003ctitle\u003eStory Grammar Example\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003cscript src=\"dist/story-grammar.bundle.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        // Create parser instance\n        const parser = new StoryGrammar.Parser();\n        \n        // Add rules\n        parser.addRule('colors', ['red', 'blue', 'green']);\n        parser.addRule('animals', ['cat', 'dog', 'bird']);\n        \n        // Add modifiers\n        parser.loadModifier(EnglishArticleModifier);\n        parser.loadModifier(EnglishPluralizationModifier);\n        \n        // Generate text\n        const story = parser.parse('I saw many %colors% %animals%');\n        console.log(story); // \"I saw many red cats\"\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe library is exposed as `StoryGrammar` global object with the `Parser` class available as `StoryGrammar.Parser`.\n\n## API Reference\n\n### Parser Class\n\n#### Static Rules\n\n- `addRule(key: string, values: string[])` - Add a static rule with fixed values\n- `addRules(rules: Grammar)` - Add multiple static rules at once  \n- `removeRule(key: string): boolean` - Remove any rule (static or function)\n- `hasRule(key: string): boolean` - Check if any rule exists (static or function)\n- `clear()` - Clear all rules (static and function)\n- `getGrammar(): Grammar` - Get copy of static rules only\n\n#### Function Rule Methods\n\n- `addFunctionRule(key: string, fn: FunctionRule): void` - Add a dynamic function rule\n- `removeFunctionRule(key: string): boolean` - Remove a function rule\n- `hasFunctionRule(key: string): boolean` - Check if function rule exists\n- `clearFunctionRules(): void` - Clear all function rules\n\n#### Weighted Rule Methods\n\n- `addWeightedRule(key: string, values: string[], weights: number[]): void` - Add a weighted probability rule\n- `removeWeightedRule(key: string): boolean` - Remove a weighted rule\n- `hasWeightedRule(key: string): boolean` - Check if weighted rule exists\n- `clearWeightedRules(): void` - Clear all weighted rules\n\n#### Conditional Rule Methods\n\n- `addConditionalRule(key: string, condition: ConditionalRule): void` - Add a context-aware conditional rule\n- `removeConditionalRule(key: string): boolean` - Remove a conditional rule\n- `hasConditionalRule(key: string): boolean` - Check if conditional rule exists\n- `clearConditionalRules(): void` - Clear all conditional rules\n\n#### Sequential Rule Methods\n\n- `addSequentialRule(key: string, values: string[]): void` - Add a sequential rule that cycles through values\n- `resetSequentialRule(key: string): void` - Reset sequential rule to first value\n- `removeSequentialRule(key: string): boolean` - Remove a sequential rule\n- `hasSequentialRule(key: string): boolean` - Check if sequential rule exists\n- `clearSequentialRules(): void` - Clear all sequential rules\n\n#### Range Rule Methods\n\n- `addRangeRule(key: string, min: number, max: number, isInteger?: boolean): void` - Add a numeric range rule\n- `removeRangeRule(key: string): boolean` - Remove a range rule\n- `hasRangeRule(key: string): boolean` - Check if range rule exists\n- `clearRangeRules(): void` - Clear all range rules\n\n#### Template Rule Methods\n\n- `addTemplateRule(key: string, template: string, slots: string[]): void` - Add a template rule with variable slots\n- `removeTemplateRule(key: string): boolean` - Remove a template rule\n- `hasTemplateRule(key: string): boolean` - Check if template rule exists\n- `clearTemplateRules(): void` - Clear all template rules\n\n#### Reference Rule Methods\n\n- `addReferenceRule(key: string, referenceKey: string): void` - Add a rule that references previously generated values\n- `removeReferenceRule(key: string): boolean` - Remove a reference rule\n- `hasReferenceRule(key: string): boolean` - Check if reference rule exists\n- `clearReferenceRules(): void` - Clear all reference rules\n\n#### Parsing\n\n- `parse(text: string): string` - Parse text and expand all variables\n- `findVariables(text: string): string[]` - Find all variables in text\n- `validate(): ValidationResult` - Validate grammar for missing rules and circular references\n\n#### Modifiers\n\n- `addModifier(modifier: Modifier): void` - Add a text transformation modifier\n- `removeModifier(name: string): boolean` - Remove a modifier\n- `hasModifier(name: string): boolean` - Check if modifier exists\n- `getModifiers(): Modifier[]` - Get all modifiers sorted by priority\n- `clearModifiers(): void` - Clear all modifiers\n\n#### Modifier Loading Methods\n\n- `loadModifier(modifier: Modifier)` - Load a single modifier\n- `loadModifiers(modifiers: Modifier[])` - Load multiple modifiers\n\n#### Available English Modifiers\n\nAll modifiers are available as separate imports:\n\n```typescript\nimport {\n  EnglishArticleModifier,       // Fix a/an articles\n  EnglishPluralizationModifier, // Handle English plurals  \n  EnglishOrdinalModifier,       // Convert to ordinals (1st, 2nd)\n  EnglishCapitalizationModifier,// Capitalize after sentences\n  EnglishPossessiveModifier,    // Handle possessives ('s)\n  EnglishVerbAgreementModifier, // Fix subject-verb agreement\n  PunctuationCleanupModifier,   // Fix spacing/punctuation\n  AllEnglishModifiers,          // All modifiers array\n  BasicEnglishModifiers         // Core modifiers only\n} from 'story-grammar';\n```\n\n#### Configuration\n\n- `setMaxDepth(depth: number): void` - Set maximum recursion depth (default: 100)\n- `getMaxDepth(): number` - Get current maximum recursion depth\n- `setRandomSeed(seed: number): void` - Set random seed for deterministic results\n- `clearRandomSeed(): void` - Clear random seed and return to Math.random()\n- `getRandomSeed(): number | null` - Get current random seed or null\n- `clearAll(): void` - Clear all rules and modifiers\n\n### Types\n\n```typescript\ninterface FunctionRule {\n  (): string[];\n}\n\ninterface WeightedRule {\n  values: string[];\n  weights: number[];\n  cumulativeWeights: number[];\n}\n\ninterface ConditionalRule {\n  (context: Map\u003cstring, string\u003e): string;\n}\n\ninterface SequentialRule {\n  values: string[];\n  currentIndex: number;\n}\n\ninterface RangeRule {\n  min: number;\n  max: number;\n  isInteger: boolean;\n}\n\ninterface TemplateRule {\n  template: string;\n  slots: string[];\n}\n\ninterface ReferenceRule {\n  referenceKey: string;\n}\n\ninterface Grammar {\n  [key: string]: string[];\n}\n\ninterface Modifier {\n  name: string;\n  condition: (text: string, context?: ModifierContext) =\u003e boolean;\n  transform: (text: string, context?: ModifierContext) =\u003e string;\n  priority?: number;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvidelais%2Fstory-grammar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvidelais%2Fstory-grammar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvidelais%2Fstory-grammar/lists"}