
Scene Sequencing
- 4 installs
- 8 repo stars
- Updated January 16, 2026
- jwynia/the-kepler-testimonies
Control pacing and accumulation using scene-sequel rhythm based on Dwight Swain.
About
Structures scenes and controls pacing using goal-conflict-disaster patterns. Use when individual scenes work but don't accumulate or when pacing feels off.
- Scene-sequel rhythm
- Pacing control
Scene Sequencing by the numbers
- 4 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #2,331 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jwynia/the-kepler-testimonies --skill scene-sequencingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 8 |
| Last updated | January 16, 2026 |
| Repository | jwynia/the-kepler-testimonies ↗ |
What it does
Control pacing and accumulation using scene-sequel rhythm based on Dwight Swain.
Files
Scene Sequencing: Pacing Skill
You help writers structure scenes and control narrative pacing using the scene-sequel rhythm.
Core Principle
The fundamental unit of pacing is not the scene alone, but the scene-sequel pair. Scenes create tension; sequels process it. The alternation creates peaks and valleys that make stories readable.
Scene Structure: Goal → Conflict → Disaster
Goal
What does the POV character want in this scene?
- Specific and concrete
- Achievable within the scene
- Connected to larger story goals
- Clear to reader within first beats
Conflict
Opposition to the goal that escalates within the scene.
- Another character with different agenda
- Environmental obstacle or time pressure
- Internal resistance (fear, doubt, values)
Static conflict is boring. Each beat should make the goal harder.
Disaster
Scene ends with one of these outcomes (in order of narrative power): 1. Yes, but... — Goal achieved, new problem created (strongest) 2. No, and furthermore... — Goal failed, situation worse 3. No — Goal failed, must try again 4. Yes — Goal achieved cleanly (use sparingly—kills tension)
Sequel Structure: Reaction → Dilemma → Decision
Reaction
Emotional response to disaster. Lets reader:
- Process what happened
- Connect with character's emotional state
- Breathe between high-tension scenes
Can be brief (a sentence) or extended (pages).
Dilemma
Character faces choice with no good options. Previous disaster has:
- Closed some paths
- Revealed new information
- Created competing priorities
Dilemma must feel genuinely difficult.
Decision
Character commits to action, which becomes the goal of the next scene.
Pacing Control
The ratio of scene to sequel controls tempo:
| More Scene | More Sequel |
|---|---|
| Fast-paced | Slow-paced |
| Action-heavy | Reflective |
| Thriller feel | Literary feel |
| Reader breathless | Reader contemplative |
Key technique: Compress or expand sequels to control tempo. Scenes run at natural length; sequels are your pacing lever.
Scene-Level Diagnostic
Missing Goal
"What does the character want here?"
- If you can't answer clearly, scene lacks direction
- Fix: Establish goal in first paragraph
Static Conflict
"Does the opposition escalate?"
- If conflict stays at same level, scene feels flat
- Fix: Each beat makes goal harder to achieve
Weak Disaster
"Is the outcome too clean?"
- "Yes" endings without complications drain tension
- Fix: Add a "but" or "and furthermore"
Missing Sequel
"Did we process the previous scene?"
- Scene-to-scene jumps without sequels exhaust readers
- Fix: Even brief reaction paragraph helps
Too Much Sequel
"Are we wallowing in reaction?"
- Extended introspection without action stalls momentum
- Fix: Compress to essential beats, move to decision
Writing Modes in Scenes
| Mode | Best For | Common In |
|---|---|---|
| Action | Scene conflict | Scenes |
| Dialogue | Character interaction | Scenes |
| Description | Setting, slowing pace | Scene openings, Sequels |
| Introspection | Processing events | Sequels |
| Summarization | Time compression | Between scenes |
Mode should match function. Action in sequels feels rushed. Introspection in action kills momentum.
What You Do
1. Ask about the goal — What does character want in this scene? 2. Check escalation — Does conflict intensify? 3. Examine the disaster — Is it too clean? 4. Find the sequel — Is there processing time? 5. Map the ratio — More scene or more sequel? Does that match intent? 6. Trace the chain — Does decision lead to next scene's goal?
What You Don't Do
- Prescribe specific scene lengths
- Enforce rigid templates
- Demand sequel after every scene (pacing varies)
- Choose what should happen in scenes
Example Interaction
Writer: "The middle of my story feels exhausting but also slow somehow."
Your approach: 1. Ask: "Walk me through a typical chapter—what happens?" 2. Check for relentless scenes: "Is there processing time between action sequences?" 3. Check for scene goals: "In the last scene you wrote, what did the character want?" 4. Probe disaster quality: "How did that scene end? Did they get what they wanted?" 5. If clean victories: "That might be draining tension. What 'but' could you add?" 6. If missing sequels: "Adding even a paragraph of reaction before the next scene helps readers catch up"
Anti-Patterns to Watch
The Relentless Scene
Pure action with no processing time. Reader becomes numb. Fix: Insert sequel beats even in fast-paced stories.
The Wallowing Sequel
Pages of introspection without decision. Reader loses patience. Fix: Dilemma must lead to decision; decision to action.
The Arbitrary Disaster
Outcome disconnected from scene events. Fix: Disaster should be logical consequence of conflict.
The Clean Victory
Character achieves goal without complications. Fix: Add a "but" or set up new problem.
Goal Drift
Scene starts with one goal, achieves different goal. Fix: If goal changes, make shift explicit and motivated.
Available Tools
analyze-scene.ts
Analyzes scene text for structure elements. Use when you need quick diagnostic on a specific scene.
# Analyze a scene file
deno run --allow-read scripts/analyze-scene.ts scene.txt
# Analyze text directly
deno run --allow-read scripts/analyze-scene.ts --text "She needed to find the key..."
# Get JSON output for further processing
deno run --allow-read scripts/analyze-scene.ts scene.txt --jsonWhat it detects:
- Goal indicators (want, need, trying to)
- Conflict indicators (but, blocked, obstacle)
- Disaster indicators (failed, worse, trapped)
- Reaction indicators (felt, emotion, shock)
- Dilemma indicators (choice, either, what if)
- Decision indicators (decided, will, plan)
Output includes:
- Scene/sequel ratio assessment
- Pacing classification (action-heavy, balanced, reflective)
- Missing element warnings
- Specific recommendations
When to use:
- Quick diagnostic on a draft scene
- Identifying why a scene feels off
- Checking pacing across multiple scenes
- Getting specific recommendations before deeper analysis
Output Persistence
This skill writes primary output to files so work persists across sessions.
Output Discovery
Before doing any other work:
1. Check for context/output-config.md in the project 2. If found, look for this skill's entry 3. If not found or no entry for this skill, ask the user first:
- "Where should I save output from this scene-sequencing session?"
- Suggest:
explorations/pacing/or a sensible location for this project
4. Store the user's preference:
- In
context/output-config.mdif context network exists - In
.scene-sequencing-output.mdat project root otherwise
Primary Output
For this skill, persist:
- Pacing diagnosis - scene/sequel balance, rhythm issues
- Scene analysis - goal, conflict, disaster for each scene
- Sequel analysis - reaction, dilemma, decision elements
- Recommendations - specific interventions for pacing issues
Conversation vs. File
| Goes to File | Stays in Conversation |
|---|---|
| Scene-by-scene breakdown | Discussion of specific scenes |
| Pacing diagnosis | Clarifying questions |
| Recommended interventions | Writer's structural decisions |
| Scene/sequel ratio assessment | Real-time feedback |
File Naming
Pattern: {story}-pacing-{date}.md Example: novel-chapter5-pacing-2025-01-15.md
#!/usr/bin/env -S deno run --allow-read
/**
* Scene Structure Analyzer
*
* Analyzes a scene or chapter for scene-sequel structure elements.
* Outputs a diagnostic report identifying:
* - Whether goal/conflict/disaster are present
* - Whether sequel elements (reaction/dilemma/decision) appear
* - Pacing indicators
* - Potential issues
*
* Usage:
* deno run --allow-read analyze-scene.ts <file>
* deno run --allow-read analyze-scene.ts --text "scene text here"
* cat scene.txt | deno run --allow-read analyze-scene.ts --stdin
*/
interface SceneAnalysis {
wordCount: number;
paragraphCount: number;
dialogueRatio: number;
// Scene elements detected
goalIndicators: string[];
conflictIndicators: string[];
disasterIndicators: string[];
// Sequel elements detected
reactionIndicators: string[];
dilemmaIndicators: string[];
decisionIndicators: string[];
// Pacing analysis
estimatedSceneRatio: number; // 0-1, higher = more scene, lower = more sequel
pacingAssessment: "action-heavy" | "balanced" | "reflective";
// Issues detected
issues: string[];
// Recommendations
recommendations: string[];
}
// Patterns that suggest scene elements
const GOAL_PATTERNS = [
/\b(want|wanted|wants|need|needed|needs|must|had to|have to|trying to|attempted to|goal|objective|mission)\b/gi,
/\b(determined to|resolved to|set out to|aimed to|intended to)\b/gi,
/\b(find|get|reach|escape|stop|save|discover|learn|prove)\b/gi,
];
const CONFLICT_PATTERNS = [
/\b(but|however|although|despite|yet|still|unfortunately)\b/gi,
/\b(blocked|stopped|prevented|refused|denied|resisted|fought|struggled)\b/gi,
/\b(problem|obstacle|challenge|difficulty|trouble|threat|danger)\b/gi,
/\b(against|versus|confronted|opposed|clashed)\b/gi,
];
const DISASTER_PATTERNS = [
/\b(failed|lost|fell|collapsed|shattered|ruined|destroyed)\b/gi,
/\b(worse|terrible|horrible|devastating|catastrophic)\b/gi,
/\b(trapped|caught|discovered|exposed|betrayed)\b/gi,
/\b(too late|no way|impossible|hopeless)\b/gi,
/\b(and then|but then|suddenly|without warning)\b/gi,
];
const REACTION_PATTERNS = [
/\b(felt|feeling|emotion|heart|stomach|chest|tears)\b/gi,
/\b(shock|horror|despair|grief|anger|fear|relief)\b/gi,
/\b(couldn't believe|couldn't think|mind raced|thoughts)\b/gi,
/\b(sat|stood|stared|gazed|looked)\s+(there|still|frozen|numb)/gi,
];
const DILEMMA_PATTERNS = [
/\b(choice|decision|option|alternative|either|or)\b/gi,
/\b(could|should|might|what if|if only)\b/gi,
/\b(on one hand|on the other|weighing|considering)\b/gi,
/\b(no good options|impossible choice|between)\b/gi,
];
const DECISION_PATTERNS = [
/\b(decided|decision|chose|choice|resolved|determined)\b/gi,
/\b(would|going to|had to|must|will)\b/gi,
/\b(plan|strategy|next step|only way|one thing)\b/gi,
/\b(stood up|got up|turned|headed|set off|began)\b/gi,
];
function countMatches(text: string, patterns: RegExp[]): string[] {
const matches: string[] = [];
for (const pattern of patterns) {
const found = text.match(pattern);
if (found) {
matches.push(...found.slice(0, 3)); // Limit to 3 examples per pattern
}
}
return [...new Set(matches)].slice(0, 5); // Dedupe and limit total
}
function calculateDialogueRatio(text: string): number {
// Simple heuristic: count quoted text vs total
const quotes = text.match(/"[^"]+"/g) || [];
const quotedChars = quotes.join("").length;
return quotedChars / text.length;
}
function analyzeScene(text: string): SceneAnalysis {
const words = text.split(/\s+/).filter(w => w.length > 0);
const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim().length > 0);
const goalIndicators = countMatches(text, GOAL_PATTERNS);
const conflictIndicators = countMatches(text, CONFLICT_PATTERNS);
const disasterIndicators = countMatches(text, DISASTER_PATTERNS);
const reactionIndicators = countMatches(text, REACTION_PATTERNS);
const dilemmaIndicators = countMatches(text, DILEMMA_PATTERNS);
const decisionIndicators = countMatches(text, DECISION_PATTERNS);
// Calculate scene vs sequel ratio
const sceneScore = goalIndicators.length + conflictIndicators.length + disasterIndicators.length;
const sequelScore = reactionIndicators.length + dilemmaIndicators.length + decisionIndicators.length;
const totalScore = sceneScore + sequelScore || 1;
const sceneRatio = sceneScore / totalScore;
let pacingAssessment: "action-heavy" | "balanced" | "reflective";
if (sceneRatio > 0.65) {
pacingAssessment = "action-heavy";
} else if (sceneRatio < 0.35) {
pacingAssessment = "reflective";
} else {
pacingAssessment = "balanced";
}
// Detect issues
const issues: string[] = [];
const recommendations: string[] = [];
if (goalIndicators.length === 0) {
issues.push("No clear goal detected in opening");
recommendations.push("Establish what the POV character wants in the first paragraph");
}
if (conflictIndicators.length === 0) {
issues.push("No conflict indicators detected");
recommendations.push("Add opposition that escalates—what blocks the character?");
}
if (disasterIndicators.length === 0 && sceneScore > 0) {
issues.push("Scene may end too cleanly (no disaster detected)");
recommendations.push("Consider adding 'but' or 'and furthermore' to the outcome");
}
if (sceneRatio > 0.8) {
issues.push("Very action-heavy—may exhaust reader");
recommendations.push("Add sequel beats (reaction time) before next scene");
}
if (sceneRatio < 0.2 && words.length > 500) {
issues.push("Extended reflection without action");
recommendations.push("Move toward a decision that leads to the next scene's goal");
}
if (reactionIndicators.length > 0 && decisionIndicators.length === 0) {
issues.push("Reaction without decision—sequel may be incomplete");
recommendations.push("Sequel should end with commitment to action");
}
return {
wordCount: words.length,
paragraphCount: paragraphs.length,
dialogueRatio: calculateDialogueRatio(text),
goalIndicators,
conflictIndicators,
disasterIndicators,
reactionIndicators,
dilemmaIndicators,
decisionIndicators,
estimatedSceneRatio: sceneRatio,
pacingAssessment,
issues,
recommendations,
};
}
function formatReport(analysis: SceneAnalysis): string {
const lines: string[] = [];
lines.push("# Scene Structure Analysis\n");
lines.push("## Overview");
lines.push(`- Words: ${analysis.wordCount}`);
lines.push(`- Paragraphs: ${analysis.paragraphCount}`);
lines.push(`- Dialogue ratio: ${(analysis.dialogueRatio * 100).toFixed(1)}%`);
lines.push(`- Pacing: ${analysis.pacingAssessment}`);
lines.push(`- Scene/Sequel ratio: ${(analysis.estimatedSceneRatio * 100).toFixed(0)}% scene\n`);
lines.push("## Scene Elements (Goal → Conflict → Disaster)");
lines.push(`- Goal indicators: ${analysis.goalIndicators.length > 0 ? analysis.goalIndicators.join(", ") : "⚠ None detected"}`);
lines.push(`- Conflict indicators: ${analysis.conflictIndicators.length > 0 ? analysis.conflictIndicators.join(", ") : "⚠ None detected"}`);
lines.push(`- Disaster indicators: ${analysis.disasterIndicators.length > 0 ? analysis.disasterIndicators.join(", ") : "⚠ None detected"}\n`);
lines.push("## Sequel Elements (Reaction → Dilemma → Decision)");
lines.push(`- Reaction indicators: ${analysis.reactionIndicators.length > 0 ? analysis.reactionIndicators.join(", ") : "None detected"}`);
lines.push(`- Dilemma indicators: ${analysis.dilemmaIndicators.length > 0 ? analysis.dilemmaIndicators.join(", ") : "None detected"}`);
lines.push(`- Decision indicators: ${analysis.decisionIndicators.length > 0 ? analysis.decisionIndicators.join(", ") : "None detected"}\n`);
if (analysis.issues.length > 0) {
lines.push("## Issues Detected");
for (const issue of analysis.issues) {
lines.push(`- ⚠ ${issue}`);
}
lines.push("");
}
if (analysis.recommendations.length > 0) {
lines.push("## Recommendations");
for (const rec of analysis.recommendations) {
lines.push(`- ${rec}`);
}
lines.push("");
}
if (analysis.issues.length === 0) {
lines.push("## Assessment");
lines.push("✓ Scene structure appears complete. Verify manually that:\n - Goal is clear in opening\n - Conflict escalates\n - Disaster creates pressure for sequel\n");
}
return lines.join("\n");
}
async function main() {
const args = Deno.args;
let text = "";
if (args.includes("--help") || args.includes("-h")) {
console.log(`Scene Structure Analyzer
Usage:
deno run --allow-read analyze-scene.ts <file>
deno run --allow-read analyze-scene.ts --text "scene text"
cat scene.txt | deno run analyze-scene.ts --stdin
Options:
--json Output as JSON instead of formatted report
--help Show this help message
`);
Deno.exit(0);
}
const jsonOutput = args.includes("--json");
if (args.includes("--stdin")) {
const decoder = new TextDecoder();
const input = await Deno.readAll(Deno.stdin);
text = decoder.decode(input);
} else if (args.includes("--text")) {
const textIndex = args.indexOf("--text");
text = args[textIndex + 1] || "";
} else {
// Assume first non-flag arg is a file
const file = args.find(a => !a.startsWith("--"));
if (file) {
text = await Deno.readTextFile(file);
} else {
console.error("Error: No input provided. Use --help for usage.");
Deno.exit(1);
}
}
if (!text.trim()) {
console.error("Error: Empty input");
Deno.exit(1);
}
const analysis = analyzeScene(text);
if (jsonOutput) {
console.log(JSON.stringify(analysis, null, 2));
} else {
console.log(formatReport(analysis));
}
}
main();