Initial commit
This commit is contained in:
532
skills/storyboard-manager/SKILL.md
Executable file
532
skills/storyboard-manager/SKILL.md
Executable file
@@ -0,0 +1,532 @@
|
||||
---
|
||||
name: storyboard-manager
|
||||
description: Assist writers with story planning, character development, plot structuring, chapter writing, timeline tracking, and consistency checking. Use this skill when working with creative writing projects organized in folders containing characters, chapters, story planning documents, and summaries. Trigger this skill for tasks like "Help me develop this character," "Write the next chapter," "Check consistency across my story," or "Track the timeline of events."
|
||||
---
|
||||
|
||||
# Storyboard Manager
|
||||
|
||||
## Overview
|
||||
|
||||
The Storyboard Manager skill equips Claude with specialized knowledge and tools for creative writing workflows. It provides frameworks for character development, story structure patterns, automated timeline tracking, and consistency checking across narrative projects. This skill automatically adapts to various storyboard folder structures while maintaining best practices for novel, screenplay, and serialized fiction writing.
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
The skill provides four main capabilities:
|
||||
|
||||
### 1. Character Development & Management
|
||||
Support creating deep, consistent character profiles with backstories, arcs, and relationships.
|
||||
|
||||
### 2. Story Planning & Structure
|
||||
Guide plot development using established frameworks (Three-Act, Hero's Journey, Save the Cat, etc.) and help organize narrative elements.
|
||||
|
||||
### 3. Chapter & Scene Writing
|
||||
Generate chapter content, scene breakdowns, and dialogue that maintains consistency with established characters and plot.
|
||||
|
||||
### 4. Timeline Tracking & Consistency Checking
|
||||
Use automated tools to verify chronological consistency, character continuity, and world-building coherence.
|
||||
|
||||
## Detecting Project Structure
|
||||
|
||||
The Storyboard Manager automatically detects and adapts to various folder organizations. Look for these common directory patterns:
|
||||
|
||||
**Character folders:** `characters/`, `Characters/`, `cast/`, `Cast/`
|
||||
**Chapter folders:** `chapters/`, `Chapters/`, `scenes/`, `Scenes/`, `story/`
|
||||
**Planning folders:** `story-planning/`, `planning/`, `outline/`, `notes/`
|
||||
**Summary files:** `summary.md`, `README.md`, `overview.md`
|
||||
|
||||
When triggered, scan the project root to identify the structure and adjust workflows accordingly. If no standard structure exists, recommend organizing files using the pattern: `characters/`, `chapters/`, `story-planning/`, and `summary.md`.
|
||||
|
||||
## Workflow Decision Tree
|
||||
|
||||
Use this decision tree to determine the appropriate workflow:
|
||||
|
||||
```
|
||||
User Request
|
||||
├─ Character-related? ("develop character," "create backstory," "character arc")
|
||||
│ └─ → Character Development Workflow
|
||||
│
|
||||
├─ Planning/Plot? ("outline story," "plan act 2," "plot structure")
|
||||
│ └─ → Story Planning Workflow
|
||||
│
|
||||
├─ Writing content? ("write chapter," "generate scene," "continue story")
|
||||
│ └─ → Chapter/Scene Writing Workflow
|
||||
│
|
||||
└─ Checking/Analysis? ("check consistency," "track timeline," "find contradictions")
|
||||
├─ Timeline? → Use timeline_tracker.py script
|
||||
└─ Consistency? → Use consistency_checker.py script
|
||||
```
|
||||
|
||||
## Character Development Workflow
|
||||
|
||||
### Step 1: Gather Context
|
||||
|
||||
Before developing a character, read existing character files to understand:
|
||||
- Established naming conventions and profile format
|
||||
- Existing characters and relationships
|
||||
- Story genre and tone
|
||||
- Character archetypes already in use
|
||||
|
||||
Use the Read tool to examine existing character files in the characters directory.
|
||||
|
||||
### Step 2: Access Character Development Framework
|
||||
|
||||
When detailed character guidance is needed, read `references/character_development.md` which contains:
|
||||
- Core character elements (personality, motivation, goals)
|
||||
- Backstory framework (ghost/wound, formative relationships)
|
||||
- Character arc types (positive change, flat, negative)
|
||||
- Relationship dynamics
|
||||
- Voice development techniques
|
||||
- Consistency guidelines
|
||||
|
||||
To efficiently find specific guidance, use Grep to search for relevant sections:
|
||||
```bash
|
||||
# Example: Find guidance on character arcs
|
||||
grep -i "character arc" references/character_development.md
|
||||
```
|
||||
|
||||
### Step 3: Develop Character Profile
|
||||
|
||||
Create or enhance character profiles with these essential elements:
|
||||
|
||||
**Basic Information**
|
||||
- Name, age, role, physical appearance
|
||||
- Key personality traits (both positive and negative)
|
||||
|
||||
**Background**
|
||||
- Origin and formative experiences
|
||||
- Ghost/wound that shapes their behavior
|
||||
- Key relationships and family dynamics
|
||||
|
||||
**Character Arc**
|
||||
- Starting belief or flaw
|
||||
- Want vs. Need (external goal vs. internal growth)
|
||||
- Transformation journey
|
||||
- End state
|
||||
|
||||
**Relationships**
|
||||
- Connections to other characters
|
||||
- Dynamic types (ally, rival, mentor, etc.)
|
||||
- How relationships evolve
|
||||
|
||||
**Unique Elements**
|
||||
- Abilities, skills, or special knowledge
|
||||
- Secrets or hidden aspects
|
||||
- Voice/speech patterns
|
||||
- Character-specific quirks
|
||||
|
||||
### Step 4: Ensure Consistency
|
||||
|
||||
Cross-reference with:
|
||||
- Existing character profiles (avoid redundancy in roles/traits)
|
||||
- Story planning documents (ensure alignment with plot needs)
|
||||
- Summary/overview (match genre and tone)
|
||||
|
||||
### Step 5: Create or Update File
|
||||
|
||||
Write the character profile to `characters/[character-name].md` using markdown format. Match the existing style and structure found in other character files.
|
||||
|
||||
## Story Planning Workflow
|
||||
|
||||
### Step 1: Assess Current Planning State
|
||||
|
||||
Read existing planning documents to understand:
|
||||
- Story concept and premise
|
||||
- Established plot points or outline
|
||||
- Target audience and genre
|
||||
- Themes and central questions
|
||||
- Planned structure (if any)
|
||||
|
||||
Look in folders like `story-planning/`, `outline/`, or files like `summary.md`.
|
||||
|
||||
### Step 2: Access Story Structure Reference
|
||||
|
||||
For detailed structural guidance, read `references/story_structures.md` which includes:
|
||||
- Three-Act Structure
|
||||
- Hero's Journey (Campbell's Monomyth)
|
||||
- Save the Cat Beat Sheet
|
||||
- Character arc templates
|
||||
- Scene structure components
|
||||
- Pacing guidelines by genre
|
||||
- Subplot integration techniques
|
||||
- Genre-specific structures
|
||||
|
||||
Use Grep to find specific frameworks:
|
||||
```bash
|
||||
# Example: Find Three-Act Structure details
|
||||
grep -A 20 "Three-Act Structure" references/story_structures.md
|
||||
```
|
||||
|
||||
### Step 3: Determine Structure Needs
|
||||
|
||||
Based on the user's request and story genre, recommend appropriate frameworks:
|
||||
|
||||
- **Thriller/Mystery**: Three-Act with strong midpoint reversal
|
||||
- **Fantasy/Adventure**: Hero's Journey for quest narratives
|
||||
- **YA/Contemporary**: Save the Cat for tight emotional beats
|
||||
- **Literary Fiction**: Focus on character arc structure
|
||||
- **Romance**: Genre-specific structure with relationship beats
|
||||
|
||||
### Step 4: Develop Planning Document
|
||||
|
||||
Create or enhance planning documents with:
|
||||
|
||||
**Story Overview**
|
||||
- Premise in 2-3 sentences
|
||||
- Genre, target audience, tone
|
||||
- Central themes and questions
|
||||
|
||||
**Plot Structure**
|
||||
- Act/chapter breakdown with key events
|
||||
- Inciting incident and plot points
|
||||
- Midpoint twist or revelation
|
||||
- Climax and resolution
|
||||
|
||||
**Character Arcs**
|
||||
- How each main character transforms
|
||||
- Arc integration with plot beats
|
||||
|
||||
**World-Building Elements** (if applicable)
|
||||
- Setting and locations
|
||||
- Magic systems or technology
|
||||
- Social structures or rules
|
||||
- Historical context
|
||||
|
||||
**Timeline**
|
||||
- Story duration
|
||||
- Key event sequence
|
||||
- Pacing considerations
|
||||
|
||||
### Step 5: Create Planning File
|
||||
|
||||
Write planning documents to `story-planning/[document-name].md`. Use clear hierarchical structure with markdown headers for easy navigation.
|
||||
|
||||
## Chapter & Scene Writing Workflow
|
||||
|
||||
### Step 1: Gather Story Context
|
||||
|
||||
Before writing any content, comprehensively read:
|
||||
|
||||
**Character Files**: All relevant character profiles to understand voices, motivations, arcs
|
||||
**Planning Documents**: Story structure, plot points, current story position
|
||||
**Previous Chapters**: Recent chapters to maintain continuity (read at least 1-2 prior chapters)
|
||||
**Summary**: Overall story premise and themes
|
||||
|
||||
This ensures the new content aligns with established elements.
|
||||
|
||||
### Step 2: Identify Chapter Requirements
|
||||
|
||||
Determine:
|
||||
- **Story Position**: Where does this fit in the overall structure?
|
||||
- **POV Character**: Whose perspective?
|
||||
- **Scene Goal**: What does the POV character want in this scene?
|
||||
- **Conflict**: What opposes their goal?
|
||||
- **Outcome**: How does the scene end? (typically with a complication)
|
||||
- **Character Development**: What arc beats occur here?
|
||||
- **Plot Advancement**: What story questions are raised or answered?
|
||||
|
||||
### Step 3: Structure the Chapter
|
||||
|
||||
Apply scene structure components:
|
||||
|
||||
**Scene (Action)**
|
||||
1. Goal - What the POV character pursues
|
||||
2. Conflict - Opposition encountered
|
||||
3. Disaster - Negative outcome that propels forward
|
||||
|
||||
**Sequel (Reaction)**
|
||||
1. Reaction - Emotional response to disaster
|
||||
2. Dilemma - Processing options
|
||||
3. Decision - Choice leading to next goal
|
||||
|
||||
Alternate between high-tension (action, conflict) and low-tension (reflection, world-building) beats for pacing.
|
||||
|
||||
### Step 4: Write with Character Consistency
|
||||
|
||||
Maintain character voice by referencing:
|
||||
- Established personality traits
|
||||
- Speech patterns and vocabulary
|
||||
- Behavioral patterns (under stress, when happy, decision-making style)
|
||||
- Current position in character arc
|
||||
- Relationships with other characters present
|
||||
|
||||
### Step 5: Integrate Timeline Markers
|
||||
|
||||
Include timeline references to maintain chronological clarity:
|
||||
- Explicit markers: "Day 3," "Two weeks later"
|
||||
- Implicit markers: Time of day, seasonal cues, event references
|
||||
- Format: `**Timeline:** Day 5, Evening` in chapter header or as section break
|
||||
|
||||
### Step 6: Create Chapter File
|
||||
|
||||
Write chapter content to `chapters/chapter-[number].md` or `chapters/[chapter-name].md`. Include:
|
||||
|
||||
**Chapter Header**
|
||||
```markdown
|
||||
# Chapter [Number]: [Optional Title]
|
||||
|
||||
**Timeline:** [When this occurs]
|
||||
**POV:** [Character name]
|
||||
**Location:** [Where this takes place]
|
||||
```
|
||||
|
||||
**Chapter Content**
|
||||
- Scene-by-scene breakdown
|
||||
- Dialogue and action
|
||||
- Character thoughts (for POV character)
|
||||
- Descriptive elements
|
||||
|
||||
### Step 7: Note Continuity Elements
|
||||
|
||||
After writing, document any new information introduced:
|
||||
- Character revelations or development
|
||||
- Plot points or clues
|
||||
- World-building details
|
||||
- Timeline events
|
||||
|
||||
This helps maintain consistency in future chapters.
|
||||
|
||||
## Timeline Tracking
|
||||
|
||||
### When to Use Timeline Tracking
|
||||
|
||||
Invoke the timeline tracker when:
|
||||
- User requests timeline analysis or event sequencing
|
||||
- Checking chronological consistency
|
||||
- Planning event order across chapters
|
||||
- Identifying unmarked time periods
|
||||
|
||||
### Running the Timeline Tracker
|
||||
|
||||
Execute the script from the project root:
|
||||
|
||||
```bash
|
||||
python3 .claude/skills/storyboard-manager/scripts/timeline_tracker.py . --output markdown
|
||||
```
|
||||
|
||||
**Output format options:**
|
||||
- `markdown` - Human-readable report (default)
|
||||
- `json` - Structured data for further processing
|
||||
|
||||
### Understanding Timeline Output
|
||||
|
||||
The script provides:
|
||||
|
||||
**Statistics**
|
||||
- Total events tracked
|
||||
- Total characters appearing
|
||||
- Events per character
|
||||
|
||||
**Timeline View**
|
||||
- Chronological sequence of events
|
||||
- Chapter/scene locations
|
||||
- Characters present in each event
|
||||
- Preview of event content
|
||||
|
||||
**Warnings**
|
||||
- Events without timeline markers
|
||||
- Characters mentioned but not defined in character files
|
||||
|
||||
### Acting on Timeline Results
|
||||
|
||||
After running the tracker:
|
||||
|
||||
1. **Review warnings** - Address missing timeline markers by adding them to chapters
|
||||
2. **Check sequence** - Verify events occur in logical order
|
||||
3. **Identify gaps** - Look for time periods without events
|
||||
4. **Character tracking** - Ensure characters appear consistently with their arc
|
||||
|
||||
Add timeline markers to chapters where missing:
|
||||
```markdown
|
||||
**Timeline:** Day 7, Morning
|
||||
```
|
||||
|
||||
Or use inline markers:
|
||||
```markdown
|
||||
Three days had passed since the incident...
|
||||
```
|
||||
|
||||
## Consistency Checking
|
||||
|
||||
### When to Use Consistency Checking
|
||||
|
||||
Invoke the consistency checker when:
|
||||
- User requests consistency analysis
|
||||
- Before finalizing chapters or acts
|
||||
- After making significant character or plot changes
|
||||
- When tracking contradictions or errors
|
||||
|
||||
### Running the Consistency Checker
|
||||
|
||||
Execute the script from the project root:
|
||||
|
||||
```bash
|
||||
python3 .claude/skills/storyboard-manager/scripts/consistency_checker.py . --output markdown
|
||||
```
|
||||
|
||||
**Output format options:**
|
||||
- `markdown` - Human-readable report with issue details (default)
|
||||
- `json` - Structured data for programmatic analysis
|
||||
|
||||
### Understanding Consistency Output
|
||||
|
||||
The script identifies issues in three severity levels:
|
||||
|
||||
**Critical (🔴)**
|
||||
- Major contradictions requiring immediate attention
|
||||
- Character appearing after death
|
||||
- Fundamental plot contradictions
|
||||
|
||||
**Warning (⚠️)**
|
||||
- Potential inconsistencies to review
|
||||
- Age discrepancies
|
||||
- Physical description contradictions
|
||||
- Relationship conflicts
|
||||
|
||||
**Info (ℹ️)**
|
||||
- Minor issues or variations
|
||||
- Name capitalization inconsistencies
|
||||
- Stylistic variations
|
||||
|
||||
### Acting on Consistency Results
|
||||
|
||||
For each issue reported:
|
||||
|
||||
1. **Read flagged locations** - Review the specific files mentioned
|
||||
2. **Determine truth** - Decide which version is correct (usually character profile is authoritative)
|
||||
3. **Update files** - Fix contradictions using the Edit tool
|
||||
4. **Re-run checker** - Verify fixes resolved the issues
|
||||
|
||||
**Example workflow for character age inconsistency:**
|
||||
```markdown
|
||||
Issue: Age inconsistency for Maya
|
||||
- Profile: 18 years old
|
||||
- Chapter 3: mentions "21-year-old Maya"
|
||||
|
||||
Fix: Edit chapter-3.md to change "21-year-old" to "18-year-old"
|
||||
```
|
||||
|
||||
### Consistency Checking Limitations
|
||||
|
||||
The automated checker catches:
|
||||
- Physical attribute contradictions
|
||||
- Age discrepancies
|
||||
- Name variations
|
||||
- Basic world-building facts
|
||||
|
||||
The checker cannot catch:
|
||||
- Subtle personality inconsistencies
|
||||
- Complex plot logic errors
|
||||
- Thematic contradictions
|
||||
- Nuanced relationship changes
|
||||
|
||||
Manual review is still essential for deep consistency.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Progressive Context Loading
|
||||
|
||||
Don't load all reference files at once. Instead:
|
||||
1. Scan project structure first
|
||||
2. Read only relevant character files for the current task
|
||||
3. Access reference documentation only when specific guidance is needed
|
||||
4. Use Grep to find specific sections in large reference files
|
||||
|
||||
### Maintaining Genre Voice
|
||||
|
||||
Match the story's established tone:
|
||||
- **YA**: Present tense, immediate emotional connection, contemporary language
|
||||
- **Fantasy**: Rich descriptive language, world-building integration
|
||||
- **Thriller**: Short sentences, high tension, sensory details
|
||||
- **Literary**: Complex prose, internal reflection, symbolic elements
|
||||
|
||||
Reference the summary.md to identify target audience and adjust accordingly.
|
||||
|
||||
### Character Arc Integration
|
||||
|
||||
Every chapter should serve character arcs:
|
||||
- Track where each character is in their arc
|
||||
- Show incremental change, not sudden transformation
|
||||
- Use plot events to test character beliefs
|
||||
- Demonstrate growth through choices and behavior
|
||||
|
||||
### Balancing Show vs. Tell
|
||||
|
||||
For narrative writing:
|
||||
- **Show** emotions through actions, dialogue, physical reactions
|
||||
- **Tell** to compress time, provide necessary information efficiently
|
||||
- Use character-filtered description (what would this POV character notice?)
|
||||
|
||||
### Handling Multiple POV
|
||||
|
||||
When stories have multiple perspectives:
|
||||
- Create distinct voices for each POV character
|
||||
- Ensure each POV section advances both that character's arc and the plot
|
||||
- Vary sentence structure and vocabulary by character
|
||||
- Track what each character knows vs. doesn't know
|
||||
|
||||
## Common User Requests & Responses
|
||||
|
||||
### "Help me develop a character backstory"
|
||||
1. Read existing character files for context
|
||||
2. Read the character profile (if exists) to enhance
|
||||
3. Access character_development.md reference for backstory framework
|
||||
4. Create detailed backstory covering: ghost/wound, formative relationships, key history
|
||||
5. Integrate with their character arc and story role
|
||||
|
||||
### "Write the next chapter"
|
||||
1. Read summary.md and story planning documents
|
||||
2. Read all character profiles for characters appearing in chapter
|
||||
3. Read previous 2 chapters for continuity
|
||||
4. Identify chapter position in story structure
|
||||
5. Write chapter with scene/sequel structure
|
||||
6. Include timeline markers and POV/location headers
|
||||
|
||||
### "Outline Act 2"
|
||||
1. Read summary and any existing planning documents
|
||||
2. Access story_structures.md for structural guidance
|
||||
3. Identify act 2 requirements (complications, midpoint, rising tension)
|
||||
4. Create beat-by-beat outline aligned with character arcs
|
||||
5. Note how plot and character arcs intersect
|
||||
|
||||
### "Check my story for consistency"
|
||||
1. Run consistency_checker.py script
|
||||
2. Review output identifying issues
|
||||
3. Read flagged files to understand contradictions
|
||||
4. Recommend specific fixes for each issue
|
||||
5. Offer to make edits if user confirms
|
||||
|
||||
### "Track the timeline of my story"
|
||||
1. Run timeline_tracker.py script
|
||||
2. Review output showing event sequence
|
||||
3. Identify gaps or inconsistencies in chronology
|
||||
4. Recommend adding timeline markers where missing
|
||||
5. Provide timeline summary organized by character or chapter
|
||||
|
||||
### "What structure should I use for my thriller?"
|
||||
1. Access story_structures.md reference
|
||||
2. Recommend Three-Act Structure or Save the Cat
|
||||
3. Explain thriller-specific requirements (escalating tension, ticking clock)
|
||||
4. Provide beat sheet adapted to their story concept
|
||||
5. Offer to create detailed planning document
|
||||
|
||||
## Resources
|
||||
|
||||
### scripts/timeline_tracker.py
|
||||
Python script that analyzes markdown files to extract and organize timeline events. Tracks character appearances, identifies time markers, groups events chronologically, and flags consistency issues.
|
||||
|
||||
**Usage:** Run from project root with `python3 .claude/skills/storyboard-manager/scripts/timeline_tracker.py .`
|
||||
|
||||
### scripts/consistency_checker.py
|
||||
Python script that detects inconsistencies in character details, physical descriptions, ages, names, and world-building facts across all story files. Outputs severity-ranked issues with file locations.
|
||||
|
||||
**Usage:** Run from project root with `python3 .claude/skills/storyboard-manager/scripts/consistency_checker.py .`
|
||||
|
||||
### references/character_development.md
|
||||
Comprehensive framework for creating multi-dimensional characters including core elements, backstory structure, arc types, relationship dynamics, voice development, and consistency guidelines.
|
||||
|
||||
**Load when:** Developing new characters, enhancing existing profiles, resolving character consistency issues, or planning character arcs.
|
||||
|
||||
### references/story_structures.md
|
||||
Detailed reference covering major story structures (Three-Act, Hero's Journey, Save the Cat), character arc templates, scene structure, pacing guidelines, plot development techniques, and genre-specific structures.
|
||||
|
||||
**Load when:** Planning story outline, structuring acts, organizing plot beats, determining pacing, or applying specific narrative frameworks.
|
||||
9
skills/storyboard-manager/index.js
Executable file
9
skills/storyboard-manager/index.js
Executable file
@@ -0,0 +1,9 @@
|
||||
export default async function storyboard_manager(input) {
|
||||
console.log("🧠 Running skill: storyboard-manager");
|
||||
|
||||
// TODO: implement actual logic for this skill
|
||||
return {
|
||||
message: "Skill 'storyboard-manager' executed successfully!",
|
||||
input
|
||||
};
|
||||
}
|
||||
11
skills/storyboard-manager/package.json
Executable file
11
skills/storyboard-manager/package.json
Executable file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@ai-labs-claude-skills/storyboard-manager",
|
||||
"version": "1.0.0",
|
||||
"description": "Claude AI skill: storyboard-manager",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"."
|
||||
],
|
||||
"license": "MIT",
|
||||
"author": "AI Labs"
|
||||
}
|
||||
232
skills/storyboard-manager/references/character_development.md
Executable file
232
skills/storyboard-manager/references/character_development.md
Executable file
@@ -0,0 +1,232 @@
|
||||
# Character Development Reference
|
||||
|
||||
This reference provides frameworks for creating compelling, multi-dimensional characters.
|
||||
|
||||
## Core Character Elements
|
||||
|
||||
### Basic Profile
|
||||
- **Name**: Full name, nicknames, name meaning
|
||||
- **Age**: Chronological and how they present
|
||||
- **Physical Description**: Distinguishing features, style, mannerisms
|
||||
- **Role**: Protagonist, antagonist, supporting, mentor, etc.
|
||||
- **Archetype**: Hero, mentor, trickster, everyman, etc.
|
||||
|
||||
### Personality Dimensions
|
||||
- **Temperament**: Sanguine, choleric, melancholic, phlegmatic
|
||||
- **Traits**: 3-5 defining characteristics (both positive and negative)
|
||||
- **Quirks**: Unique habits or behaviors
|
||||
- **Speech Patterns**: How they talk, vocabulary, accent
|
||||
- **Sense of Humor**: Type and style
|
||||
|
||||
### Motivation & Goals
|
||||
- **External Goal**: What they're trying to achieve (plot-level)
|
||||
- **Internal Goal**: What they're trying to become (character arc)
|
||||
- **Motivation**: Why they want these things
|
||||
- **Stakes**: What happens if they fail
|
||||
- **Misbelief/Lie**: False belief holding them back
|
||||
|
||||
## Character Backstory Framework
|
||||
|
||||
### The Ghost (Past Wound)
|
||||
- **Traumatic Event**: What happened in their past
|
||||
- **Age When It Occurred**: How it shaped their development
|
||||
- **Who Was Involved**: Other characters connected to trauma
|
||||
- **How It Changed Them**: Before and after personality
|
||||
- **Coping Mechanisms**: How they deal with the wound
|
||||
|
||||
### Formative Relationships
|
||||
- **Family Dynamics**: Parents, siblings, family structure
|
||||
- **Key Friendships**: Influences from peers
|
||||
- **Romantic History**: Past relationships and their impact
|
||||
- **Mentors/Role Models**: Who shaped their values
|
||||
- **Enemies/Rivals**: Antagonistic relationships that defined them
|
||||
|
||||
### Life History
|
||||
- **Childhood**: Key events, family situation, early personality
|
||||
- **Adolescence**: Identity formation, major choices, first loves/losses
|
||||
- **Young Adulthood**: Independence, career/path choices, relationships
|
||||
- **Current Situation**: Where story finds them
|
||||
|
||||
## Character Arc Types
|
||||
|
||||
### Positive Change Arc
|
||||
**Structure:**
|
||||
1. Lie they believe
|
||||
2. Want vs. Need established
|
||||
3. First glimpse of truth
|
||||
4. Rejection of truth (return to lie)
|
||||
5. Moment of truth (crisis)
|
||||
6. Choice to embrace truth
|
||||
7. New worldview demonstrated
|
||||
|
||||
**Markers:**
|
||||
- Start: Incomplete, held back by misbelief
|
||||
- Midpoint: Glimpse growth but not ready
|
||||
- Climax: Must choose between lie and truth
|
||||
- End: Transformed, living truth
|
||||
|
||||
### Flat Arc
|
||||
**Structure:**
|
||||
1. Truth known from beginning
|
||||
2. World believes lie
|
||||
3. Character tested on their truth
|
||||
4. Character demonstrates truth
|
||||
5. World begins to change
|
||||
6. Truth proven through action
|
||||
|
||||
**Markers:**
|
||||
- Start: Strong in beliefs
|
||||
- Midpoint: Severely tested
|
||||
- Climax: Greatest test of faith
|
||||
- End: Changed the world, not themselves
|
||||
|
||||
### Negative Arc
|
||||
**Structure:**
|
||||
1. Flaw/weakness established
|
||||
2. Temptation introduced
|
||||
3. Small compromises begin
|
||||
4. Point of no return crossed
|
||||
5. Descent accelerates
|
||||
6. Rejection of redemption
|
||||
7. Tragic conclusion
|
||||
|
||||
**Markers:**
|
||||
- Start: Flawed but sympathetic
|
||||
- Midpoint: Questionable choices
|
||||
- Climax: Beyond redemption
|
||||
- End: Destroyed or becomes villain
|
||||
|
||||
## Relationship Dynamics
|
||||
|
||||
### Character Relationships Matrix
|
||||
For each significant relationship, define:
|
||||
- **Dynamic Type**: Mentor/student, rivals, allies, romance, family
|
||||
- **Conflict Source**: What creates tension
|
||||
- **Common Ground**: What bonds them
|
||||
- **Influence**: How they change each other
|
||||
- **Arc**: How relationship evolves
|
||||
|
||||
### Protagonist-Antagonist Relationship
|
||||
- **Opposition**: How antagonist blocks protagonist's goal
|
||||
- **Mirror/Foil**: How they reflect/contrast each other
|
||||
- **Personal Stakes**: Why this matters beyond plot
|
||||
- **Symmetry**: Similar origins or opposite arc paths
|
||||
- **Respect Level**: Do they understand each other?
|
||||
|
||||
## Character Voice Development
|
||||
|
||||
### Dialogue Markers
|
||||
- **Vocabulary Level**: Formal, casual, slang, technical
|
||||
- **Sentence Structure**: Short and punchy vs. long and flowing
|
||||
- **Favorite Words/Phrases**: Repeated expressions
|
||||
- **Topics They Discuss**: What they talk about most
|
||||
- **What They Avoid**: Topics they don't address
|
||||
- **Lying Tells**: How they behave when dishonest
|
||||
|
||||
### Internal Voice (POV Characters)
|
||||
- **Thought Patterns**: Analytical, emotional, scattered, focused
|
||||
- **Biases**: How they interpret events
|
||||
- **Blind Spots**: What they don't see about themselves
|
||||
- **Metaphors**: Types of comparisons they make
|
||||
- **Narrative Distance**: Close, intimate vs. distant, observational
|
||||
|
||||
## Character Consistency
|
||||
|
||||
### Behavioral Patterns
|
||||
- **Under Stress**: How they react to pressure
|
||||
- **When Happy**: How they express joy
|
||||
- **When Angry**: Explosive, cold, passive-aggressive
|
||||
- **Decision-Making**: Impulsive, analytical, avoidant
|
||||
- **Trust**: Quick or slow to trust others
|
||||
|
||||
### Core Values
|
||||
- **Non-Negotiables**: Lines they won't cross
|
||||
- **Flexible Areas**: Where they compromise
|
||||
- **Value Hierarchy**: Ranking of priorities (family, honor, survival, etc.)
|
||||
- **Values Testing**: Scenes where values conflict
|
||||
|
||||
### Growth Indicators
|
||||
- **Early Story**: How they handle situation type X
|
||||
- **Mid Story**: How handling of X begins to shift
|
||||
- **Late Story**: How they handle X after growth
|
||||
- **Demonstration**: Parallel scenes showing change
|
||||
|
||||
## Character Roles in Ensemble
|
||||
|
||||
### Ensemble Balance
|
||||
- **The Leader**: Drives action, makes decisions
|
||||
- **The Heart**: Emotional center, unifies group
|
||||
- **The Brain**: Strategy, knowledge, analysis
|
||||
- **The Warrior**: Action, protection, physical strength
|
||||
- **The Wildcard**: Unpredictable, challenges norms
|
||||
- **The Conscience**: Moral compass, voice of reason
|
||||
|
||||
### Avoiding Character Redundancy
|
||||
- **Different Wants**: Each character pursuing different goals
|
||||
- **Different Methods**: Varied approaches to problems
|
||||
- **Different Worldviews**: Contrasting perspectives
|
||||
- **Different Skills**: Complementary abilities
|
||||
- **Different Arcs**: Each on unique journey
|
||||
|
||||
## Character Development Questions
|
||||
|
||||
### Surface Level
|
||||
- What do they look like?
|
||||
- How do they dress?
|
||||
- What's their job/role?
|
||||
- Where do they live?
|
||||
|
||||
### Deeper Level
|
||||
- What do they fear most?
|
||||
- What do they desire more than anything?
|
||||
- What's their greatest secret?
|
||||
- What do they lie to themselves about?
|
||||
- What would they sacrifice everything for?
|
||||
|
||||
### Behavioral Level
|
||||
- How do they treat people with less power?
|
||||
- What makes them laugh?
|
||||
- What makes them cry?
|
||||
- When do they lie, and why?
|
||||
- How do they handle failure?
|
||||
|
||||
### Thematic Level
|
||||
- What do they represent in the story?
|
||||
- What question does their arc answer?
|
||||
- How do they embody or challenge the theme?
|
||||
- What truth do they discover?
|
||||
|
||||
## Character Testing Scenarios
|
||||
|
||||
To ensure character depth, test them against:
|
||||
|
||||
1. **Moral Dilemma**: Force choice between two values
|
||||
2. **Loss**: Take away something they depend on
|
||||
3. **Temptation**: Offer something they want vs. need
|
||||
4. **Betrayal**: Test their trust and forgiveness
|
||||
5. **Sacrifice**: Force them to give up something important
|
||||
6. **Revelation**: Expose a truth they've been avoiding
|
||||
7. **Isolation**: Remove their support system
|
||||
8. **Power**: Give them control and see how they use it
|
||||
|
||||
## Red Flags for Weak Characters
|
||||
|
||||
### Avoid:
|
||||
- **Mary Sue/Gary Stu**: Too perfect, no real flaws
|
||||
- **Inconsistent Behavior**: Acts differently for plot convenience
|
||||
- **No Agency**: Things happen to them, they don't drive action
|
||||
- **Single-Note**: Only one personality trait
|
||||
- **No Growth**: Same at end as beginning (unless flat arc)
|
||||
- **Reactive Only**: Never makes proactive choices
|
||||
- **Exposition Puppet**: Exists to explain things
|
||||
- **Token Diversity**: Defined only by identity marker
|
||||
|
||||
### Fix By:
|
||||
- Adding meaningful flaws and consequences
|
||||
- Establishing behavioral patterns and motivations
|
||||
- Giving them goals and plans they actively pursue
|
||||
- Layering contradictory traits and complexity
|
||||
- Planning clear arc with transformation
|
||||
- Creating scenes where they initiate action
|
||||
- Giving them purpose beyond information delivery
|
||||
- Developing full personality, backstory, and individual arc
|
||||
148
skills/storyboard-manager/references/story_structures.md
Executable file
148
skills/storyboard-manager/references/story_structures.md
Executable file
@@ -0,0 +1,148 @@
|
||||
# Story Structure Reference
|
||||
|
||||
This reference provides common story structures and frameworks for planning narratives.
|
||||
|
||||
## Three-Act Structure
|
||||
|
||||
### Act One: Setup (25% of story)
|
||||
- **Hook**: Opening scene that grabs attention
|
||||
- **Inciting Incident**: Event that disrupts the protagonist's normal world
|
||||
- **First Plot Point**: Decision/event that propels protagonist into Act Two (typically at 25% mark)
|
||||
|
||||
### Act Two: Confrontation (50% of story)
|
||||
- **Rising Action**: Series of obstacles and complications
|
||||
- **Midpoint**: Major revelation or reversal (at 50% mark)
|
||||
- **Pinch Points**: Moments that increase pressure on protagonist
|
||||
- **Second Plot Point**: Lowest point/crisis that leads into Act Three (at 75% mark)
|
||||
|
||||
### Act Three: Resolution (25% of story)
|
||||
- **Climax**: Final confrontation or decision
|
||||
- **Falling Action**: Immediate consequences of climax
|
||||
- **Resolution**: New normal/equilibrium established
|
||||
|
||||
## Hero's Journey (Joseph Campbell)
|
||||
|
||||
1. **Ordinary World**: Hero's normal life
|
||||
2. **Call to Adventure**: Challenge or quest presented
|
||||
3. **Refusal of the Call**: Initial hesitation or fear
|
||||
4. **Meeting the Mentor**: Guidance or magical aid
|
||||
5. **Crossing the Threshold**: Commitment to the journey
|
||||
6. **Tests, Allies, and Enemies**: Learning the rules of the new world
|
||||
7. **Approach to the Inmost Cave**: Preparation for major challenge
|
||||
8. **Ordeal**: Greatest fear/challenge faced
|
||||
9. **Reward**: Achievement of goal or new knowledge
|
||||
10. **The Road Back**: Return journey begins
|
||||
11. **Resurrection**: Final test with everything at stake
|
||||
12. **Return with the Elixir**: Hero returns transformed
|
||||
|
||||
## Save the Cat Beat Sheet (Blake Snyder)
|
||||
|
||||
1. **Opening Image**: Snapshot of protagonist's world before change
|
||||
2. **Theme Stated**: Central question or theme introduced
|
||||
3. **Setup**: Establish protagonist's world, flaws, and stakes
|
||||
4. **Catalyst**: Event that starts the story (at 10% mark)
|
||||
5. **Debate**: Internal conflict about whether to act
|
||||
6. **Break into Two**: Protagonist commits to journey (at 20-25% mark)
|
||||
7. **B Story**: Subplot introduced (often romantic or thematic)
|
||||
8. **Fun and Games**: Promise of the premise delivered
|
||||
9. **Midpoint**: False victory or defeat (at 50% mark)
|
||||
10. **Bad Guys Close In**: External and internal pressure increases
|
||||
11. **All Is Lost**: Lowest point (at 75% mark)
|
||||
12. **Dark Night of the Soul**: Protagonist processes loss
|
||||
13. **Break into Three**: Solution discovered (at 80% mark)
|
||||
14. **Finale**: Climax and resolution
|
||||
15. **Final Image**: Parallel to opening showing change
|
||||
|
||||
## Character Arc Templates
|
||||
|
||||
### Positive Change Arc
|
||||
- **Lie Believed**: Character starts believing something false about themselves/world
|
||||
- **Want vs. Need**: What they think they want vs. what they actually need
|
||||
- **Ghost/Wound**: Past trauma influencing present behavior
|
||||
- **Moment of Truth**: Forced to choose between lie and truth
|
||||
- **Resolution**: Embraces truth and grows
|
||||
|
||||
### Flat Arc
|
||||
- **Truth Known**: Character already knows the truth
|
||||
- **World's Lie**: The world around them believes a lie
|
||||
- **Testing**: Character's truth is challenged repeatedly
|
||||
- **Impact**: Character changes the world around them
|
||||
- **Affirmation**: Character's truth proven correct
|
||||
|
||||
### Negative Arc
|
||||
- **Initial Weakness**: Character has a flaw or belief
|
||||
- **Escalation**: Flaw grows worse through choices
|
||||
- **Point of No Return**: Character chooses darkness
|
||||
- **Descent**: Consequences spiral
|
||||
- **Tragic End**: Character destroyed or becomes antagonist
|
||||
|
||||
## Scene Structure
|
||||
|
||||
### Scene Components
|
||||
1. **Goal**: What the POV character wants in this scene
|
||||
2. **Conflict**: Opposition to achieving the goal
|
||||
3. **Disaster**: Outcome (usually negative) that propels to next scene
|
||||
|
||||
### Sequel Components (reaction to scene)
|
||||
1. **Reaction**: Emotional response to disaster
|
||||
2. **Dilemma**: Working through options
|
||||
3. **Decision**: Choice that leads to next goal/scene
|
||||
|
||||
## Pacing Guidelines
|
||||
|
||||
### Chapter Length by Genre
|
||||
- **Thriller/Mystery**: 2,000-3,000 words (faster pace)
|
||||
- **Fantasy/Sci-Fi**: 3,000-5,000 words (world-building needs)
|
||||
- **Romance**: 2,500-4,000 words (emotional beats)
|
||||
- **Literary Fiction**: 2,000-6,000 words (varies widely)
|
||||
- **YA**: 2,000-3,500 words (shorter attention span)
|
||||
|
||||
### Tension Management
|
||||
- **High-tension scenes**: Action, conflict, revelations (shorter, punchier)
|
||||
- **Low-tension scenes**: Character development, world-building (can be longer)
|
||||
- **Rhythm**: Alternate between high and low tension
|
||||
- **Overall trend**: Tension should increase as story progresses
|
||||
|
||||
## Plot Development
|
||||
|
||||
### Conflict Types
|
||||
1. **Character vs. Character**: Antagonist opposition
|
||||
2. **Character vs. Self**: Internal struggle
|
||||
3. **Character vs. Society**: Against norms/systems
|
||||
4. **Character vs. Nature**: Environmental challenges
|
||||
5. **Character vs. Technology**: Man vs. machine
|
||||
6. **Character vs. Fate**: Against destiny/prophecy
|
||||
|
||||
### Subplot Integration
|
||||
- **Mirror subplots**: Reflect main theme differently
|
||||
- **Contrast subplots**: Show opposite approach to theme
|
||||
- **Complication subplots**: Add obstacles to main plot
|
||||
- **Resolution rule**: Resolve minor subplots before climax, major ones during/after
|
||||
|
||||
## Genre-Specific Structures
|
||||
|
||||
### Mystery/Thriller
|
||||
- Introduction of crime/mystery
|
||||
- Investigation and clue discovery
|
||||
- Red herrings and misdirection
|
||||
- Escalating danger
|
||||
- Revelation and confrontation
|
||||
- Resolution and explanation
|
||||
|
||||
### Romance
|
||||
- Meet-cute or introduction
|
||||
- Attraction develops
|
||||
- Barrier/conflict introduced
|
||||
- Relationship deepens despite obstacles
|
||||
- Black moment/breakup
|
||||
- Grand gesture/reconciliation
|
||||
- Happy ending or HEA (Happily Ever After)
|
||||
|
||||
### Fantasy/Sci-Fi
|
||||
- Ordinary world establishment
|
||||
- Introduction to magical/sci-fi elements
|
||||
- Quest or mission defined
|
||||
- Journey and world exploration
|
||||
- Building towards prophesied/anticipated event
|
||||
- Final battle or confrontation
|
||||
- New world order established
|
||||
391
skills/storyboard-manager/scripts/consistency_checker.py
Executable file
391
skills/storyboard-manager/scripts/consistency_checker.py
Executable file
@@ -0,0 +1,391 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Consistency Checker for Storyboard Manager
|
||||
|
||||
This script analyzes markdown files in a storyboard project to detect inconsistencies
|
||||
in character details, plot elements, and world-building across the story.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Set, Tuple, Optional
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class ConsistencyIssue:
|
||||
"""Represents a consistency issue found in the story"""
|
||||
|
||||
def __init__(self, issue_type: str, severity: str, description: str,
|
||||
locations: List[str], details: Dict = None):
|
||||
self.issue_type = issue_type # character, plot, world, timeline
|
||||
self.severity = severity # critical, warning, info
|
||||
self.description = description
|
||||
self.locations = locations
|
||||
self.details = details or {}
|
||||
|
||||
def __repr__(self):
|
||||
return f"ConsistencyIssue({self.severity}: {self.description})"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'type': self.issue_type,
|
||||
'severity': self.severity,
|
||||
'description': self.description,
|
||||
'locations': self.locations,
|
||||
'details': self.details
|
||||
}
|
||||
|
||||
|
||||
class CharacterProfile:
|
||||
"""Stores character information from profile files"""
|
||||
|
||||
def __init__(self, name: str, file_path: str):
|
||||
self.name = name
|
||||
self.file_path = file_path
|
||||
self.attributes = {}
|
||||
self.aliases = []
|
||||
self.relationships = {}
|
||||
|
||||
def add_attribute(self, key: str, value: str):
|
||||
"""Add a character attribute"""
|
||||
self.attributes[key.lower()] = value
|
||||
|
||||
def get_attribute(self, key: str) -> Optional[str]:
|
||||
"""Get a character attribute"""
|
||||
return self.attributes.get(key.lower())
|
||||
|
||||
|
||||
class ConsistencyChecker:
|
||||
"""Main consistency checking class"""
|
||||
|
||||
# Patterns to extract character attributes
|
||||
ATTRIBUTE_PATTERNS = {
|
||||
'age': r'\*\*Age:\*\*\s*(.+?)(?:\n|$)',
|
||||
'appearance': r'\*\*Appearance:\*\*\s*(.+?)(?:\n|$)',
|
||||
'hair': r'(?:hair|Hair)[\s:]+([^,\n]+)',
|
||||
'eyes': r'(?:eyes|Eyes)[\s:]+([^,\n]+)',
|
||||
'height': r'\*\*Height:\*\*\s*(.+?)(?:\n|$)',
|
||||
'role': r'\*\*Role:\*\*\s*(.+?)(?:\n|$)',
|
||||
}
|
||||
|
||||
def __init__(self, project_root: str):
|
||||
self.project_root = Path(project_root)
|
||||
self.characters: Dict[str, CharacterProfile] = {}
|
||||
self.issues: List[ConsistencyIssue] = []
|
||||
self.world_facts: Dict[str, Tuple[str, str]] = {} # fact -> (value, location)
|
||||
|
||||
def scan_directory(self, directory: Path) -> List[Path]:
|
||||
"""Recursively find all markdown files in directory"""
|
||||
md_files = []
|
||||
if not directory.exists():
|
||||
return md_files
|
||||
|
||||
for item in directory.iterdir():
|
||||
if item.is_file() and item.suffix == '.md':
|
||||
md_files.append(item)
|
||||
elif item.is_dir() and not item.name.startswith('.'):
|
||||
md_files.extend(self.scan_directory(item))
|
||||
|
||||
return md_files
|
||||
|
||||
def load_character_profile(self, file_path: Path) -> Optional[CharacterProfile]:
|
||||
"""Load character information from a profile file"""
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
|
||||
# Extract character name from title
|
||||
name_match = re.search(r'^#\s+(.+?)$', content, re.MULTILINE)
|
||||
if not name_match:
|
||||
return None
|
||||
|
||||
name = name_match.group(1).strip()
|
||||
profile = CharacterProfile(name, str(file_path.relative_to(self.project_root)))
|
||||
|
||||
# Extract attributes
|
||||
for attr_name, pattern in self.ATTRIBUTE_PATTERNS.items():
|
||||
match = re.search(pattern, content, re.IGNORECASE)
|
||||
if match:
|
||||
profile.add_attribute(attr_name, match.group(1).strip())
|
||||
|
||||
# Extract aliases/nicknames
|
||||
alias_match = re.search(
|
||||
r'\*\*(?:Nicknames?|Aliases?):\*\*\s*(.+?)(?:\n|$)',
|
||||
content, re.IGNORECASE
|
||||
)
|
||||
if alias_match:
|
||||
aliases = re.split(r'[,;]', alias_match.group(1))
|
||||
profile.aliases = [a.strip() for a in aliases if a.strip()]
|
||||
|
||||
return profile
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read character profile {file_path}: {e}",
|
||||
file=sys.stderr)
|
||||
return None
|
||||
|
||||
def load_all_characters(self):
|
||||
"""Load all character profiles from the project"""
|
||||
char_dirs = ['characters', 'Characters', 'cast', 'Cast']
|
||||
|
||||
for dirname in char_dirs:
|
||||
char_dir = self.project_root / dirname
|
||||
if char_dir.exists():
|
||||
for char_file in self.scan_directory(char_dir):
|
||||
profile = self.load_character_profile(char_file)
|
||||
if profile:
|
||||
self.characters[profile.name] = profile
|
||||
|
||||
def check_character_mentions(self, file_path: Path):
|
||||
"""Check character mentions in content for inconsistencies"""
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
location = str(file_path.relative_to(self.project_root))
|
||||
|
||||
for char_name, profile in self.characters.items():
|
||||
# Check if character is mentioned
|
||||
if not re.search(r'\b' + re.escape(char_name) + r'\b', content, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
# Check for attribute contradictions
|
||||
for attr_name, attr_value in profile.attributes.items():
|
||||
# Look for contradicting descriptions
|
||||
if attr_name == 'age':
|
||||
age_mentions = re.finditer(
|
||||
r'\b' + re.escape(char_name) + r'\b[^.!?]*\b(\d+)[\s-](?:year|yr)',
|
||||
content, re.IGNORECASE
|
||||
)
|
||||
for match in age_mentions:
|
||||
mentioned_age = match.group(1)
|
||||
profile_age = re.search(r'\d+', attr_value)
|
||||
if profile_age and mentioned_age != profile_age.group(0):
|
||||
self.issues.append(ConsistencyIssue(
|
||||
issue_type='character',
|
||||
severity='warning',
|
||||
description=f"Age inconsistency for {char_name}",
|
||||
locations=[location, profile.file_path],
|
||||
details={
|
||||
'character': char_name,
|
||||
'profile_age': attr_value,
|
||||
'mentioned_age': mentioned_age
|
||||
}
|
||||
))
|
||||
|
||||
elif attr_name in ['hair', 'eyes']:
|
||||
# Check for contradicting physical descriptions
|
||||
desc_pattern = rf'\b{re.escape(char_name)}\b[^.!?]*\b({attr_name})\b[^.!?]*'
|
||||
desc_mentions = re.finditer(desc_pattern, content, re.IGNORECASE)
|
||||
for match in desc_mentions:
|
||||
context = match.group(0).lower()
|
||||
# Simple check: if profile says "black hair" but text says "blonde"
|
||||
profile_value_lower = attr_value.lower()
|
||||
if profile_value_lower not in context:
|
||||
# Extract the contradicting description
|
||||
color_pattern = r'\b(black|brown|blonde|red|auburn|white|gray|grey|blue|green|hazel)\b'
|
||||
colors = re.findall(color_pattern, context, re.IGNORECASE)
|
||||
if colors:
|
||||
self.issues.append(ConsistencyIssue(
|
||||
issue_type='character',
|
||||
severity='warning',
|
||||
description=f"{attr_name.capitalize()} color inconsistency for {char_name}",
|
||||
locations=[location, profile.file_path],
|
||||
details={
|
||||
'character': char_name,
|
||||
'profile': attr_value,
|
||||
'context': match.group(0)[:100]
|
||||
}
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Error checking {file_path}: {e}", file=sys.stderr)
|
||||
|
||||
def check_character_relationships(self):
|
||||
"""Check for inconsistent character relationships"""
|
||||
# This is a placeholder for more sophisticated relationship checking
|
||||
# Would analyze relationship declarations in character files and compare
|
||||
# with how relationships are portrayed in chapters
|
||||
|
||||
relationship_keywords = ['friend', 'enemy', 'lover', 'sibling', 'parent', 'child']
|
||||
|
||||
for char_name, profile in self.characters.items():
|
||||
# Extract relationship info from profile
|
||||
# Compare with relationships mentioned in story files
|
||||
# Flag inconsistencies
|
||||
pass
|
||||
|
||||
def check_world_building(self, file_path: Path):
|
||||
"""Check for world-building inconsistencies"""
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
location = str(file_path.relative_to(self.project_root))
|
||||
|
||||
# Look for world-building facts (places, magic systems, technology, etc.)
|
||||
# This is a simplified version - would need more sophisticated pattern matching
|
||||
|
||||
# Example: Check for location descriptions
|
||||
location_pattern = r'\*\*Location:\*\*\s*(.+?)(?:\n|$)'
|
||||
for match in re.finditer(location_pattern, content, re.IGNORECASE):
|
||||
loc_name = match.group(1).strip()
|
||||
|
||||
if loc_name in self.world_facts:
|
||||
# Check if description is consistent
|
||||
prev_value, prev_location = self.world_facts[loc_name]
|
||||
# In a real implementation, would do semantic comparison
|
||||
else:
|
||||
self.world_facts[loc_name] = (match.group(0), location)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Error checking world-building in {file_path}: {e}",
|
||||
file=sys.stderr)
|
||||
|
||||
def check_plot_consistency(self):
|
||||
"""Check for plot inconsistencies"""
|
||||
# Placeholder for plot consistency checking
|
||||
# Would track plot points, events, and check for contradictions
|
||||
|
||||
# Examples to check:
|
||||
# - Events happening out of order
|
||||
# - Characters appearing after their death
|
||||
# - Objects used before acquisition
|
||||
# - Locations visited before discovery
|
||||
pass
|
||||
|
||||
def check_name_variations(self, file_path: Path):
|
||||
"""Check for inconsistent name usage"""
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
location = str(file_path.relative_to(self.project_root))
|
||||
|
||||
# Check if character names are spelled consistently
|
||||
for char_name, profile in self.characters.items():
|
||||
# Look for potential misspellings (Levenshtein distance)
|
||||
# This is simplified - would use actual string distance algorithm
|
||||
|
||||
# Check for variations in capitalization
|
||||
variations = re.findall(
|
||||
r'\b' + re.escape(char_name) + r'\b',
|
||||
content,
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
inconsistent_caps = [v for v in variations if v != char_name]
|
||||
if inconsistent_caps:
|
||||
unique_variations = list(set(inconsistent_caps))
|
||||
if len(unique_variations) > 0:
|
||||
self.issues.append(ConsistencyIssue(
|
||||
issue_type='character',
|
||||
severity='info',
|
||||
description=f"Name capitalization variations for {char_name}",
|
||||
locations=[location],
|
||||
details={
|
||||
'character': char_name,
|
||||
'variations': unique_variations
|
||||
}
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Error checking names in {file_path}: {e}", file=sys.stderr)
|
||||
|
||||
def analyze_project(self) -> Dict:
|
||||
"""Run all consistency checks on the project"""
|
||||
|
||||
# Load character profiles
|
||||
self.load_all_characters()
|
||||
|
||||
# Check all content files
|
||||
content_dirs = ['chapters', 'Chapters', 'scenes', 'Scenes', 'story']
|
||||
content_files = []
|
||||
|
||||
for dirname in content_dirs:
|
||||
content_dir = self.project_root / dirname
|
||||
if content_dir.exists():
|
||||
content_files.extend(self.scan_directory(content_dir))
|
||||
|
||||
# Run checks on each file
|
||||
for content_file in content_files:
|
||||
self.check_character_mentions(content_file)
|
||||
self.check_world_building(content_file)
|
||||
self.check_name_variations(content_file)
|
||||
|
||||
# Run project-wide checks
|
||||
self.check_character_relationships()
|
||||
self.check_plot_consistency()
|
||||
|
||||
# Organize results
|
||||
issues_by_severity = defaultdict(list)
|
||||
for issue in self.issues:
|
||||
issues_by_severity[issue.severity].append(issue.to_dict())
|
||||
|
||||
analysis = {
|
||||
'total_issues': len(self.issues),
|
||||
'critical_issues': len(issues_by_severity['critical']),
|
||||
'warnings': len(issues_by_severity['warning']),
|
||||
'info': len(issues_by_severity['info']),
|
||||
'characters_analyzed': len(self.characters),
|
||||
'issues_by_severity': dict(issues_by_severity),
|
||||
'all_issues': [issue.to_dict() for issue in self.issues]
|
||||
}
|
||||
|
||||
return analysis
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for consistency checker"""
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: consistency_checker.py <project_directory> [--output json|markdown]")
|
||||
sys.exit(1)
|
||||
|
||||
project_dir = sys.argv[1]
|
||||
output_format = 'markdown'
|
||||
|
||||
if len(sys.argv) > 2 and sys.argv[2] == '--output':
|
||||
output_format = sys.argv[3] if len(sys.argv) > 3 else 'markdown'
|
||||
|
||||
checker = ConsistencyChecker(project_dir)
|
||||
analysis = checker.analyze_project()
|
||||
|
||||
if output_format == 'json':
|
||||
print(json.dumps(analysis, indent=2))
|
||||
else:
|
||||
# Markdown output
|
||||
print("# Consistency Analysis\n")
|
||||
print(f"**Total Issues Found:** {analysis['total_issues']}")
|
||||
print(f"- Critical: {analysis['critical_issues']}")
|
||||
print(f"- Warnings: {analysis['warnings']}")
|
||||
print(f"- Info: {analysis['info']}\n")
|
||||
print(f"**Characters Analyzed:** {analysis['characters_analyzed']}\n")
|
||||
|
||||
if analysis['total_issues'] == 0:
|
||||
print("✅ No consistency issues found!\n")
|
||||
else:
|
||||
# Display issues by severity
|
||||
for severity in ['critical', 'warning', 'info']:
|
||||
issues = analysis['issues_by_severity'].get(severity, [])
|
||||
if issues:
|
||||
severity_emoji = {
|
||||
'critical': '🔴',
|
||||
'warning': '⚠️',
|
||||
'info': 'ℹ️'
|
||||
}
|
||||
print(f"\n## {severity_emoji[severity]} {severity.upper()}\n")
|
||||
|
||||
for issue in issues:
|
||||
print(f"### {issue['description']}")
|
||||
print(f"**Type:** {issue['type']}")
|
||||
print(f"**Locations:**")
|
||||
for loc in issue['locations']:
|
||||
print(f"- {loc}")
|
||||
|
||||
if issue['details']:
|
||||
print(f"**Details:**")
|
||||
for key, value in issue['details'].items():
|
||||
print(f"- {key}: {value}")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
352
skills/storyboard-manager/scripts/timeline_tracker.py
Executable file
352
skills/storyboard-manager/scripts/timeline_tracker.py
Executable file
@@ -0,0 +1,352 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Timeline Tracker for Storyboard Manager
|
||||
|
||||
This script analyzes markdown files in a storyboard project to extract and organize
|
||||
timeline events, helping writers maintain chronological consistency.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class TimelineEvent:
|
||||
"""Represents a single event in the story timeline"""
|
||||
|
||||
def __init__(self, content: str, location: str, chapter: str = None,
|
||||
timepoint: str = None, characters: List[str] = None):
|
||||
self.content = content
|
||||
self.location = location # File path where event was found
|
||||
self.chapter = chapter
|
||||
self.timepoint = timepoint # Relative time (e.g., "Day 1", "3 weeks later")
|
||||
self.characters = characters or []
|
||||
|
||||
def __repr__(self):
|
||||
return f"TimelineEvent({self.timepoint}: {self.content[:50]}...)"
|
||||
|
||||
|
||||
class TimelineTracker:
|
||||
"""Main timeline tracking and analysis class"""
|
||||
|
||||
# Patterns to detect time markers in text
|
||||
TIME_PATTERNS = [
|
||||
r'(?:Day|Night)\s+(\d+)', # Day 1, Night 3
|
||||
r'(\d+)\s+(?:days?|weeks?|months?|years?)\s+(?:later|ago|after|before)',
|
||||
r'(?:Morning|Afternoon|Evening|Night)\s+of\s+(?:Day\s+)?(\d+)',
|
||||
r'Chapter\s+(\d+)', # Chapter markers
|
||||
r'\*\*(?:Timeline|Time|When):\*\*\s*(.+?)(?:\n|$)', # Explicit timeline markers
|
||||
r'\*\*Date:\*\*\s*(.+?)(?:\n|$)',
|
||||
]
|
||||
|
||||
# Patterns to detect character mentions
|
||||
CHARACTER_PATTERNS = [
|
||||
r'\*\*Characters?:\*\*\s*(.+?)(?:\n|$)',
|
||||
r'\*\*(?:POV|Perspective):\*\*\s*(.+?)(?:\n|$)',
|
||||
]
|
||||
|
||||
def __init__(self, project_root: str):
|
||||
self.project_root = Path(project_root)
|
||||
self.events: List[TimelineEvent] = []
|
||||
self.characters: set = set()
|
||||
|
||||
def scan_directory(self, directory: Path) -> List[Path]:
|
||||
"""Recursively find all markdown files in directory"""
|
||||
md_files = []
|
||||
if not directory.exists():
|
||||
return md_files
|
||||
|
||||
for item in directory.iterdir():
|
||||
if item.is_file() and item.suffix == '.md':
|
||||
md_files.append(item)
|
||||
elif item.is_dir() and not item.name.startswith('.'):
|
||||
md_files.extend(self.scan_directory(item))
|
||||
|
||||
return md_files
|
||||
|
||||
def extract_characters_from_file(self, file_path: Path) -> List[str]:
|
||||
"""Extract character names from character profile files"""
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
|
||||
# Look for character name in title (# Character Name)
|
||||
name_match = re.search(r'^#\s+(.+?)$', content, re.MULTILINE)
|
||||
if name_match:
|
||||
return [name_match.group(1).strip()]
|
||||
|
||||
# Look for explicit name field
|
||||
name_match = re.search(r'\*\*Name:\*\*\s*(.+?)(?:\n|$)', content)
|
||||
if name_match:
|
||||
return [name_match.group(1).strip()]
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read {file_path}: {e}", file=sys.stderr)
|
||||
|
||||
return []
|
||||
|
||||
def extract_timeline_markers(self, content: str) -> List[Tuple[str, int]]:
|
||||
"""Extract time markers from content, return list of (timepoint, position)"""
|
||||
markers = []
|
||||
|
||||
for pattern in self.TIME_PATTERNS:
|
||||
for match in re.finditer(pattern, content, re.IGNORECASE):
|
||||
timepoint = match.group(1) if match.lastindex else match.group(0)
|
||||
markers.append((timepoint.strip(), match.start()))
|
||||
|
||||
return sorted(markers, key=lambda x: x[1])
|
||||
|
||||
def extract_character_mentions(self, content: str) -> List[str]:
|
||||
"""Extract character names from explicit character markers"""
|
||||
characters = []
|
||||
|
||||
for pattern in self.CHARACTER_PATTERNS:
|
||||
matches = re.finditer(pattern, content, re.IGNORECASE)
|
||||
for match in matches:
|
||||
char_text = match.group(1)
|
||||
# Split by commas, 'and', '&'
|
||||
names = re.split(r'[,&]|\sand\s', char_text)
|
||||
characters.extend([name.strip() for name in names if name.strip()])
|
||||
|
||||
return characters
|
||||
|
||||
def find_character_references(self, content: str, known_characters: set) -> List[str]:
|
||||
"""Find mentions of known characters in content"""
|
||||
found = []
|
||||
for character in known_characters:
|
||||
# Simple word boundary check
|
||||
if re.search(r'\b' + re.escape(character) + r'\b', content, re.IGNORECASE):
|
||||
found.append(character)
|
||||
return found
|
||||
|
||||
def parse_chapter_file(self, file_path: Path) -> List[TimelineEvent]:
|
||||
"""Parse a chapter/scene file for timeline events"""
|
||||
events = []
|
||||
|
||||
try:
|
||||
content = file_path.read_text(encoding='utf-8')
|
||||
|
||||
# Get chapter number/name from filename or title
|
||||
chapter = file_path.stem
|
||||
title_match = re.search(r'^#\s+(.+?)$', content, re.MULTILINE)
|
||||
if title_match:
|
||||
chapter = title_match.group(1).strip()
|
||||
|
||||
# Extract explicit character mentions
|
||||
explicit_chars = self.extract_character_mentions(content)
|
||||
|
||||
# Find timeline markers
|
||||
markers = self.extract_timeline_markers(content)
|
||||
|
||||
# Split content into sections based on markers
|
||||
if markers:
|
||||
sections = []
|
||||
for i, (timepoint, pos) in enumerate(markers):
|
||||
start_pos = pos
|
||||
end_pos = markers[i + 1][1] if i + 1 < len(markers) else len(content)
|
||||
section_content = content[start_pos:end_pos]
|
||||
|
||||
# Find characters in this section
|
||||
section_chars = explicit_chars.copy()
|
||||
section_chars.extend(self.find_character_references(
|
||||
section_content, self.characters))
|
||||
|
||||
event = TimelineEvent(
|
||||
content=section_content[:500], # First 500 chars as preview
|
||||
location=str(file_path.relative_to(self.project_root)),
|
||||
chapter=chapter,
|
||||
timepoint=timepoint,
|
||||
characters=list(set(section_chars))
|
||||
)
|
||||
events.append(event)
|
||||
else:
|
||||
# No explicit markers, treat whole file as one event
|
||||
all_chars = explicit_chars.copy()
|
||||
all_chars.extend(self.find_character_references(content, self.characters))
|
||||
|
||||
event = TimelineEvent(
|
||||
content=content[:500],
|
||||
location=str(file_path.relative_to(self.project_root)),
|
||||
chapter=chapter,
|
||||
timepoint=None,
|
||||
characters=list(set(all_chars))
|
||||
)
|
||||
events.append(event)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Error parsing {file_path}: {e}", file=sys.stderr)
|
||||
|
||||
return events
|
||||
|
||||
def analyze_project(self) -> Dict:
|
||||
"""Analyze entire project and build timeline"""
|
||||
|
||||
# First, find all characters
|
||||
char_dirs = ['characters', 'Characters', 'cast']
|
||||
for dirname in char_dirs:
|
||||
char_dir = self.project_root / dirname
|
||||
if char_dir.exists():
|
||||
for char_file in self.scan_directory(char_dir):
|
||||
names = self.extract_characters_from_file(char_file)
|
||||
self.characters.update(names)
|
||||
|
||||
# Then scan chapters/scenes
|
||||
content_dirs = ['chapters', 'Chapters', 'scenes', 'Scenes', 'story']
|
||||
for dirname in content_dirs:
|
||||
content_dir = self.project_root / dirname
|
||||
if content_dir.exists():
|
||||
for content_file in self.scan_directory(content_dir):
|
||||
events = self.parse_chapter_file(content_file)
|
||||
self.events.extend(events)
|
||||
|
||||
# Build analysis
|
||||
analysis = {
|
||||
'total_events': len(self.events),
|
||||
'total_characters': len(self.characters),
|
||||
'characters': sorted(list(self.characters)),
|
||||
'events_by_timepoint': self._group_events_by_time(),
|
||||
'events_by_character': self._group_events_by_character(),
|
||||
'events_by_chapter': self._group_events_by_chapter(),
|
||||
'timeline': self._build_timeline(),
|
||||
'warnings': self._check_consistency()
|
||||
}
|
||||
|
||||
return analysis
|
||||
|
||||
def _group_events_by_time(self) -> Dict[str, List[Dict]]:
|
||||
"""Group events by their timepoint"""
|
||||
grouped = defaultdict(list)
|
||||
|
||||
for event in self.events:
|
||||
timepoint = event.timepoint or "Unspecified"
|
||||
grouped[timepoint].append({
|
||||
'location': event.location,
|
||||
'chapter': event.chapter,
|
||||
'characters': event.characters,
|
||||
'preview': event.content[:200]
|
||||
})
|
||||
|
||||
return dict(grouped)
|
||||
|
||||
def _group_events_by_character(self) -> Dict[str, List[Dict]]:
|
||||
"""Group events by character appearance"""
|
||||
grouped = defaultdict(list)
|
||||
|
||||
for event in self.events:
|
||||
for character in event.characters:
|
||||
grouped[character].append({
|
||||
'location': event.location,
|
||||
'chapter': event.chapter,
|
||||
'timepoint': event.timepoint,
|
||||
'preview': event.content[:200]
|
||||
})
|
||||
|
||||
return dict(grouped)
|
||||
|
||||
def _group_events_by_chapter(self) -> Dict[str, List[Dict]]:
|
||||
"""Group events by chapter"""
|
||||
grouped = defaultdict(list)
|
||||
|
||||
for event in self.events:
|
||||
chapter = event.chapter or "Unknown"
|
||||
grouped[chapter].append({
|
||||
'location': event.location,
|
||||
'timepoint': event.timepoint,
|
||||
'characters': event.characters,
|
||||
'preview': event.content[:200]
|
||||
})
|
||||
|
||||
return dict(grouped)
|
||||
|
||||
def _build_timeline(self) -> List[Dict]:
|
||||
"""Build chronological timeline of events"""
|
||||
# Sort events by timepoint (this is simplified, real implementation
|
||||
# would need more sophisticated time parsing)
|
||||
timeline = []
|
||||
|
||||
for event in self.events:
|
||||
timeline.append({
|
||||
'timepoint': event.timepoint or "Unknown",
|
||||
'chapter': event.chapter,
|
||||
'location': event.location,
|
||||
'characters': event.characters,
|
||||
'preview': event.content[:200]
|
||||
})
|
||||
|
||||
return timeline
|
||||
|
||||
def _check_consistency(self) -> List[str]:
|
||||
"""Check for potential timeline inconsistencies"""
|
||||
warnings = []
|
||||
|
||||
# Check for events without time markers
|
||||
unmarked_events = [e for e in self.events if not e.timepoint]
|
||||
if unmarked_events:
|
||||
warnings.append(
|
||||
f"Found {len(unmarked_events)} events without timeline markers"
|
||||
)
|
||||
|
||||
# Check for characters appearing in timeline without character files
|
||||
mentioned_chars = set()
|
||||
for event in self.events:
|
||||
mentioned_chars.update(event.characters)
|
||||
|
||||
undefined_chars = mentioned_chars - self.characters
|
||||
if undefined_chars:
|
||||
warnings.append(
|
||||
f"Characters mentioned but not defined: {', '.join(sorted(undefined_chars))}"
|
||||
)
|
||||
|
||||
return warnings
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for timeline tracker"""
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: timeline_tracker.py <project_directory> [--output json|markdown]")
|
||||
sys.exit(1)
|
||||
|
||||
project_dir = sys.argv[1]
|
||||
output_format = 'markdown'
|
||||
|
||||
if len(sys.argv) > 2 and sys.argv[2] == '--output':
|
||||
output_format = sys.argv[3] if len(sys.argv) > 3 else 'markdown'
|
||||
|
||||
tracker = TimelineTracker(project_dir)
|
||||
analysis = tracker.analyze_project()
|
||||
|
||||
if output_format == 'json':
|
||||
print(json.dumps(analysis, indent=2))
|
||||
else:
|
||||
# Markdown output
|
||||
print("# Timeline Analysis\n")
|
||||
print(f"**Total Events:** {analysis['total_events']}")
|
||||
print(f"**Total Characters:** {analysis['total_characters']}\n")
|
||||
|
||||
print("## Characters")
|
||||
for char in analysis['characters']:
|
||||
appearances = len(analysis['events_by_character'].get(char, []))
|
||||
print(f"- {char} ({appearances} appearances)")
|
||||
|
||||
print("\n## Timeline")
|
||||
for event in analysis['timeline']:
|
||||
print(f"\n### {event['timepoint']} - {event['chapter']}")
|
||||
print(f"**Location:** {event['location']}")
|
||||
if event['characters']:
|
||||
print(f"**Characters:** {', '.join(event['characters'])}")
|
||||
print(f"\n{event['preview']}...\n")
|
||||
print("---")
|
||||
|
||||
if analysis['warnings']:
|
||||
print("\n## Warnings")
|
||||
for warning in analysis['warnings']:
|
||||
print(f"- ⚠️ {warning}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user