feat: Merge 05-Plot and 06-First Draft into 05-First Draft with YAML frontmatter

- Add YAML frontmatter support with split_yaml_frontmatter() in preprocess.rs
- Update create_scene_pair to create single merged files with YAML frontmatter
- Rename 06-First Draft to 05-First Draft and merge with 05-Plot content
- Update default_project_open_subdir to '05-First Draft'
- Add capitalizes filter to MiniJinja environment for template rendering
- Fix template placeholder escaping in CONSISTENCY.md
- Update all references from 06-First Draft and 05-Plot to 05-First Draft
- Update test expectations to match new folder structure

The merged approach uses YAML frontmatter (--- delimiters) at the top of
each draft file to store planning metadata, allowing it to be collapsed
in the editor while keeping all planning and draft content in one file.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
landon
2026-09-16 10:06:32 -05:00
parent 477c59cb79
commit 449ad4439f
19 changed files with 752 additions and 512 deletions
+143 -86
View File
@@ -96,7 +96,7 @@ impl App {
self.build_story_bible_index(); self.build_story_bible_index();
self.autocomplete = None; self.autocomplete = None;
self.collapsed.clear(); self.collapsed.clear();
// Ensure the manuscript folder (e.g., 06-First Draft) is always expanded // Ensure the manuscript folder (e.g., 05-First Draft) is always expanded
if let Some(ref dir) = self.manuscript_dir { if let Some(ref dir) = self.manuscript_dir {
self.collapsed.remove(dir); self.collapsed.remove(dir);
} }
@@ -284,7 +284,7 @@ impl App {
/// if so, which of its subfolders is the manuscript. /// if so, which of its subfolders is the manuscript.
/// ///
/// The test is simply whether it has a child folder named like the /// The test is simply whether it has a child folder named like the
/// configured manuscript folder (`06-First Draft`), matched leniently by /// configured manuscript folder (`05-First Draft`), matched leniently by
/// [`order::dir_matches`]. `None` means the workspace is itself the /// [`order::dir_matches`]. `None` means the workspace is itself the
/// manuscript, which is how the app behaved before project mode and remains /// manuscript, which is how the app behaved before project mode and remains
/// the right answer for a plain folder of chapters. /// the right answer for a plain folder of chapters.
@@ -453,12 +453,23 @@ impl App {
} }
} }
/// Lift the header out of the buffer, leaving the prose. Does nothing for a /// Lift the header out of the buffer, leaving the prose. Supports both
/// document with no draft marker — there is nothing to collapse. /// YAML frontmatter (`---` delimiters) and the legacy draft marker.
pub(super) fn collapse_header(&mut self) { pub(super) fn collapse_header(&mut self) {
if self.header_stash.is_some() { if self.header_stash.is_some() {
return; return;
} }
// Try YAML frontmatter first
if let Some((header, body)) = crate::preprocess::split_yaml_frontmatter(&self.buffer) {
let (header, body) = (header.to_string(), body.to_string());
self.header_stash = Some(header);
self.buffer = body;
self.after_view_change();
return;
}
// Fall back to draft marker
let Some((header, body)) = let Some((header, body)) =
crate::preprocess::split_at_marker(&self.buffer, &self.config.draft_marker) crate::preprocess::split_at_marker(&self.buffer, &self.config.draft_marker)
else { else {
@@ -639,8 +650,8 @@ impl App {
self.rebuild_field_names(); self.rebuild_field_names();
} }
/// Create a scene pair: both a planning file (in 05-Plot) and a draft file /// Create a new scene file with merged YAML frontmatter containing both
/// (in 06-First Draft), linked to each other. Used for the "New Scene" button. /// planning metadata and draft content. Used for the "New Scene" button.
pub(super) fn create_scene_pair(&mut self) { pub(super) fn create_scene_pair(&mut self) {
use super::today_utc; use super::today_utc;
@@ -652,24 +663,15 @@ impl App {
.unwrap_or_default(); .unwrap_or_default();
// Check if we're in a First Draft folder (Act 1, Act 2, etc.) // Check if we're in a First Draft folder (Act 1, Act 2, etc.)
let in_draft_folder = current_dir.starts_with("06-First Draft/Act") let in_draft_folder = current_dir.starts_with("05-First Draft/Act")
|| current_dir.starts_with("06-First Draft/"); || current_dir.starts_with("05-First Draft/");
// Check if we're in a Plot folder (act_1, act_2, etc.)
let in_plot_folder = current_dir.starts_with("05-Plot/act_")
|| current_dir.starts_with("05-Plot/");
// Extract act number from current directory // Extract act number from current directory
let act_num = if in_draft_folder { let act_num = if in_draft_folder {
// Parse "06-First Draft/Act N" or "06-First Draft/Act N/" // Parse "05-First Draft/Act N" or "05-First Draft/Act N/"
current_dir.split('/').nth(1).and_then(|s| { current_dir.split('/').nth(1).and_then(|s| {
s.strip_prefix("Act ").and_then(|n| n.parse::<u32>().ok()) s.strip_prefix("Act ").and_then(|n| n.parse::<u32>().ok())
}) })
} else if in_plot_folder {
// Parse "05-Plot/act_N" or "05-Plot/act_N/"
current_dir.split('/').nth(1).and_then(|s| {
s.strip_prefix("act_").and_then(|n| n.parse::<u32>().ok())
})
} else { } else {
// Default to Act 1 // Default to Act 1
Some(1) Some(1)
@@ -682,14 +684,14 @@ impl App {
let existing_scenes: Vec<u32> = self.files.iter() let existing_scenes: Vec<u32> = self.files.iter()
.filter(|f| { .filter(|f| {
let path_lower = f.to_lowercase(); let path_lower = f.to_lowercase();
if in_draft_folder || in_plot_folder { if in_draft_folder {
// Check files in current act // Check files in current act
path_lower.contains(&format!("act_{}/", act)) path_lower.contains(&format!("act {}/", act))
|| path_lower.contains(&format!("Act {}/", act)) || path_lower.contains(&format!("Act {}/", act))
} else { } else {
// Check both folders // Check files in 05-First Draft
path_lower.contains(&format!("act_{}/scene_", act)) path_lower.contains(&format!("05-first draft/act {}/scene", act))
|| path_lower.contains(&format!("Act {}/scene", act)) || path_lower.contains(&format!("05-first draft/Act {}/scene", act))
} }
}) })
.filter_map(|f| { .filter_map(|f| {
@@ -709,17 +711,17 @@ impl App {
let title = format!("Chapter {}: Scene {}", chapter, scene_num); let title = format!("Chapter {}: Scene {}", chapter, scene_num);
let slug = format!("chapter-{}--scene-{}", chapter, scene_num); let slug = format!("chapter-{}--scene-{}", chapter, scene_num);
// Determine where to create files // Determine where to create file
let draft_dir = format!("06-First Draft/Act {}", act); let draft_dir = format!("05-First Draft/Act {}", act);
let plot_dir = format!("05-Plot/act_{:02}", act);
// Create planning file // Scene file
let planning_name = format!("{}/scene_{:02}.md", plot_dir, scene_num); let filename = format!("{}/scene{:02}.md", draft_dir, scene_num);
let draft_name = format!("{}/scene{:02}.md", draft_dir, scene_num);
// Planning file content // Scene ID
let planning_id = format!("scene_{:02}_{:02}_{:02}", act, chapter, scene_num); let scene_id = format!("scene_{:02}_{:02}_{:02}", act, chapter, scene_num);
let planning_content = format!(r#"---
// Create merged file with YAML frontmatter
let content = format!(r#"---
id: {} id: {}
title: "{}" title: "{}"
slug: {} slug: {}
@@ -727,7 +729,7 @@ act: {}
chapter: {} chapter: {}
scene: {} scene: {}
type: scene type: scene
status: planning status: draft
word_count_target: 2000 word_count_target: 2000
word_count_min: 1800 word_count_min: 1800
word_count_max: 2200 word_count_max: 2200
@@ -739,50 +741,75 @@ time: ""
conflict: "" conflict: ""
theme: "" theme: ""
tone: "" tone: ""
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
version: 1
created: "{}"
updated: "{}"
order: {} order: {}
created: "{}"
updated: "{}"
--- ---
# {} # {}
**Planning Template** | **ID:** {} | **Status:** Planning **Scene File** | **ID:** {} | **Status:** Draft
--- ---
## Scene Planning ## Scene Metadata
### The Setup | Attribute | Value |
|-----------|-------|
| **Act** | {} |
| **Chapter** | {} |
| **Scene** | {} |
| **Type** | Scene |
| **POV** | Not set |
| **Version** | 1 |
| **Word Count Target** | 2000 |
### The Reveal
### Things to Note
"#,
planning_id, title, slug, act, chapter, scene_num,
scene_num,
today, today,
title, planning_id
);
// Draft file content
let draft_id = format!("draft_scene_{:02}_{:02}_{:02}", act, chapter, scene_num);
let draft_content = format!(r#"---
id: {}
title: "{}"
slug: {}
type: draft
status: not_started
act: {}
chapter: {}
scene: {}
created: "{}"
updated: "{}"
--- ---
# {} ## Word Count Tracking
**Draft File** | **ID:** {} | Metric | Value |
|--------|-------|
| **Target** | 2000 |
| **Minimum** | 1800 |
| **Maximum** | 2200 |
| **Current** | 0 |
| **This Session** | 0 |
| **Last Updated** | Never |
---
## Creative Elements
### POV
> Not specified
### Characters
### Setting
> Not specified
### Date & Time
> Not specified | Not specified
---
## Story Structure
### Conflict
> Not specified
### Theme
> Not specified
### Tone
> Not specified
--- ---
@@ -792,20 +819,50 @@ updated: "{}"
[Write your scene content here...] [Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
### Revision Notes
-
-
---
## Status Checklist
- [ ] Planning complete
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Created:** {} | **Updated:** {}
"#, "#,
draft_id, title, slug, scene_id, title, slug, act, chapter, scene_num,
act, chapter, scene_num, scene_num,
today, today, today, today,
title, draft_id title, scene_id,
act, chapter, scene_num,
today, today
); );
// Create both files // Create the merged file
self.insert_new_file(planning_name, planning_content); self.insert_new_file(filename.clone(), content);
self.insert_new_file(draft_name.clone(), draft_content);
// Select the draft file (more likely what user wants to edit) // Select the new file
let draft_idx = self.files.iter().position(|f| *f == draft_name).unwrap_or(0); let file_idx = self.files.iter().position(|f| *f == filename).unwrap_or(0);
self.selected = Some(draft_idx); self.selected = Some(file_idx);
self.buffer.clear(); self.buffer.clear();
self.dirty = false; self.dirty = false;
} }
@@ -1923,7 +1980,7 @@ mod tests {
/// shapes a workspace can take. /// shapes a workspace can take.
#[test] #[test]
fn the_project_root_is_the_folder_the_manuscript_sits_in() { fn the_project_root_is_the_folder_the_manuscript_sits_in() {
let ws = Path::new("/books/My Book/06-First Draft"); let ws = Path::new("/books/My Book/05-First Draft");
let project = Path::new("/books/My Book"); let project = Path::new("/books/My Book");
// Project mode: the workspace already is the project root, so an // Project mode: the workspace already is the project root, so an
@@ -2183,10 +2240,10 @@ mod tests {
let files = v(&[ let files = v(&[
"00-Scratch Pad/Generated plot points.md", "00-Scratch Pad/Generated plot points.md",
"03-Characters/ada.md", "03-Characters/ada.md",
"06-First Draft/Act 1/scene01.md", "05-First Draft/Act 1/scene01.md",
"06-First Draft/draft_v1.md", "05-First Draft/draft_v1.md",
]); ]);
assert_eq!(first_listed(&files, Some("06-First Draft")), Some(2)); assert_eq!(first_listed(&files, Some("05-First Draft")), Some(2));
} }
#[test] #[test]
@@ -2201,33 +2258,33 @@ mod tests {
#[test] #[test]
fn an_empty_manuscript_falls_back_to_the_first_file() { fn an_empty_manuscript_falls_back_to_the_first_file() {
let files = v(&["00-Scratch Pad/note.md", "03-Characters/ada.md"]); let files = v(&["00-Scratch Pad/note.md", "03-Characters/ada.md"]);
assert_eq!(first_listed(&files, Some("06-First Draft")), Some(0)); assert_eq!(first_listed(&files, Some("05-First Draft")), Some(0));
} }
#[test] #[test]
fn after_a_removal_the_next_listed_file_is_chosen() { fn after_a_removal_the_next_listed_file_is_chosen() {
let files = v(&[ let files = v(&[
"00-Scratch Pad/note.md", "00-Scratch Pad/note.md",
"06-First Draft/a.md", "05-First Draft/a.md",
"06-First Draft/b.md", "05-First Draft/b.md",
]); ]);
// Removing index 1 leaves the following manuscript file at index 1. // Removing index 1 leaves the following manuscript file at index 1.
assert_eq!(nearest_listed(&files, Some("06-First Draft"), 1), Some(1)); assert_eq!(nearest_listed(&files, Some("05-First Draft"), 1), Some(1));
// Removing the last one falls back to the previous manuscript file. // Removing the last one falls back to the previous manuscript file.
assert_eq!(nearest_listed(&files, Some("06-First Draft"), 3), Some(2)); assert_eq!(nearest_listed(&files, Some("05-First Draft"), 3), Some(2));
} }
#[test] #[test]
fn a_removal_never_lands_on_a_reference_file() { fn a_removal_never_lands_on_a_reference_file() {
let files = v(&["00-Scratch Pad/note.md", "06-First Draft/a.md"]); let files = v(&["00-Scratch Pad/note.md", "05-First Draft/a.md"]);
// Index 2 is past the end; the search back must skip the scratch pad. // Index 2 is past the end; the search back must skip the scratch pad.
assert_eq!(nearest_listed(&files, Some("06-First Draft"), 2), Some(1)); assert_eq!(nearest_listed(&files, Some("05-First Draft"), 2), Some(1));
} }
#[test] #[test]
fn removing_the_only_manuscript_file_still_selects_something() { fn removing_the_only_manuscript_file_still_selects_something() {
let files = v(&["00-Scratch Pad/note.md"]); let files = v(&["00-Scratch Pad/note.md"]);
assert_eq!(nearest_listed(&files, Some("06-First Draft"), 0), Some(0)); assert_eq!(nearest_listed(&files, Some("05-First Draft"), 0), Some(0));
assert_eq!(nearest_listed(&[], Some("06-First Draft"), 0), None); assert_eq!(nearest_listed(&[], Some("05-First Draft"), 0), None);
} }
} }
+9 -5
View File
@@ -191,8 +191,9 @@ pub fn default_project_template() -> PathBuf {
/// Default subfolder opened after generating a project: the snowflake /// Default subfolder opened after generating a project: the snowflake
/// template's drafting folder, where the chapter files live. /// template's drafting folder, where the chapter files live.
/// Supports both "05-First Draft" (merged planning+draft) and "06-First Draft" (legacy).
pub fn default_project_open_subdir() -> String { pub fn default_project_open_subdir() -> String {
"06-First Draft".to_string() "05-First Draft".to_string()
} }
/// Templates ship hooks because they are meant to run; honouring them is the /// Templates ship hooks because they are meant to run; honouring them is the
@@ -226,6 +227,9 @@ pub fn default_projects_dir() -> PathBuf {
/// Default new-file template: the editorial header fields this app already /// Default new-file template: the editorial header fields this app already
/// understands, followed by the draft marker so the body starts below it. /// understands, followed by the draft marker so the body starts below it.
///
/// Note: For YAML frontmatter support, create files manually with --- delimiters.
/// The legacy header format is kept for backward compatibility with the parser.
pub fn default_new_file_template() -> String { pub fn default_new_file_template() -> String {
[ [
"# Title: {{name}}", "# Title: {{name}}",
@@ -521,13 +525,13 @@ mod tests {
} }
/// The folder opened after generating a project. It is the snowflake /// The folder opened after generating a project. It is the snowflake
/// template's drafting folder, and the name contains a space — which has to /// template's drafting folder (merged planning + draft), and the name contains
/// survive being stored and joined onto the project path. /// a space — which has to survive being stored and joined onto the project path.
#[test] #[test]
fn the_default_project_subdir_is_the_drafting_folder() { fn the_default_project_subdir_is_the_drafting_folder() {
assert_eq!(default_project_open_subdir(), "06-First Draft"); assert_eq!(default_project_open_subdir(), "05-First Draft");
let joined = PathBuf::from("/tmp/The Winter Gate").join(default_project_open_subdir()); let joined = PathBuf::from("/tmp/The Winter Gate").join(default_project_open_subdir());
assert_eq!(joined, PathBuf::from("/tmp/The Winter Gate/06-First Draft")); assert_eq!(joined, PathBuf::from("/tmp/The Winter Gate/05-First Draft"));
} }
/// A config.json written before screenplay projects existed. Same risk as /// A config.json written before screenplay projects existed. Same risk as
+34
View File
@@ -110,6 +110,40 @@ pub fn split_at_marker<'a>(text: &'a str, marker: &str) -> Option<(&'a str, &'a
None None
} }
/// Split a document at its YAML frontmatter boundaries (`---` delimiters).
/// Returns `(frontmatter, body)` if frontmatter exists, or `None` if no frontmatter.
/// The frontmatter includes the opening and closing `---` lines.
pub fn split_yaml_frontmatter<'a>(text: &'a str) -> Option<(&'a str, &'a str)> {
let mut lines = text.lines();
// Check for opening ---
let first_line = lines.next()?.trim();
if first_line != "---" {
return None;
}
// Find closing ---
let mut frontmatter_end = first_line.len() + 1; // +1 for newline
let mut found_closing = false;
for line in lines {
frontmatter_end += line.len() + 1; // +1 for newline
if line.trim() == "---" {
found_closing = true;
break;
}
}
if !found_closing {
return None;
}
// Return frontmatter (including delimiters) and body
let frontmatter = &text[..frontmatter_end];
let body = &text[frontmatter_end..];
Some((frontmatter, body))
}
/// One `#* Name: value` line from a document's editorial header. /// One `#* Name: value` line from a document's editorial header.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field { pub struct Field {
+14
View File
@@ -110,6 +110,20 @@ pub fn render_template(config: &RenderConfig) -> RenderResult {
.map(|(i, c)| if i == 0 { c.to_uppercase().collect::<String>() } else { c.to_lowercase().collect::<String>() }) .map(|(i, c)| if i == 0 { c.to_uppercase().collect::<String>() } else { c.to_lowercase().collect::<String>() })
.collect::<String>()) // Simplified title case .collect::<String>()) // Simplified title case
}); });
// Capitalize filter - capitalizes the first letter of each word
env.add_filter("capitalize", |value: String| -> Result<String, minijinja::Error> {
Ok(value.chars()
.enumerate()
.map(|(i, c)| if i == 0 { c.to_uppercase().collect::<String>() } else { c.to_lowercase().collect::<String>() })
.collect::<String>())
});
// capitalizes filter (plural) - same as capitalize but handles the common template usage
env.add_filter("capitalizes", |value: String| -> Result<String, minijinja::Error> {
Ok(value.chars()
.enumerate()
.map(|(i, c)| if i == 0 { c.to_uppercase().collect::<String>() } else { c.to_lowercase().collect::<String>() })
.collect::<String>())
});
// Get the context from variables // Get the context from variables
let context = config.variables.to_context(); let context = config.variables.to_context();
@@ -143,8 +143,8 @@ updated: ""
## Quick Verification Commands ## Quick Verification Commands
Use your editor's search: Use your editor's search:
- `{{ character.name }}` - Find all mentions of a character - `{{ '{{' }} character.name {{ '}}' }}` - Find all mentions of a character
- `{{ location.name }}` - Find all mentions of a location - `{{ '{{' }} location.name {{ '}}' }}` - Find all mentions of a location
- `[[` - Find all cross-references - `[[` - Find all cross-references
- `status:` - Find all status fields - `status:` - Find all status fields
@@ -0,0 +1,128 @@
---
id: scene_01
title: "Chapter One: The Beginning"
slug: chapter-one-the-beginning
act: 1
chapter: 1
scene: 1
type: chapter
status: draft
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
pov: ""
characters: []
setting: ""
date: ""
time: ""
conflict: ""
theme: ""
tone: ""
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
version: 1
created: ""
updated: ""
order: 1
---
# Chapter One: The Beginning
**Scene File** | **ID:** scene_01 | **Status:** Draft
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | 1 |
| **Chapter** | 1 |
| **Scene** | 1 |
| **Type** | Chapter |
| **POV** | Not set |
| **Version** | 1 |
| **Word Count Target** | 2000 |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | 2000 |
| **Minimum** | 1800 |
| **Maximum** | 2200 |
| **Current** | 0 |
| **This Session** | 0 |
| **Last Updated** | Never |
---
## Creative Elements
### POV
> Not specified
### Characters
### Setting
> Not specified
### Date & Time
> Not specified | Not specified
---
## Story Structure
### Conflict
> Not specified
### Theme
> Not specified
### Tone
> Not specified
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
### Revision Notes
-
-
---
## Status Checklist
- [ ] Planning complete
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Created:** | **Updated:**
@@ -0,0 +1,129 @@
---
id: scene_02_01
title: "Chapter Two: Development"
slug: chapter-two-development
act: 2
chapter: 1
scene: 1
type: chapter
status: draft
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
pov: ""
characters: []
setting: ""
date: ""
time: ""
conflict: ""
theme: ""
tone: ""
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
version: 1
created: ""
updated: ""
planning_template: ""
draft_file: ""
order: 1
---
# Chapter Two: Development
**Draft File** | **ID:** scene_02_01 | **Status:** Draft
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | 2 |
| **Chapter** | 1 |
| **Scene** | 1 |
| **Type** | Chapter |
| **POV** | Not set |
| **Version** | 1 |
| **Word Count Target** | 2000 |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | 2000 |
| **Minimum** | 1800 |
| **Maximum** | 2200 |
| **Current** | 0 |
| **This Session** | 0 |
| **Last Updated** | Never |
---
## Creative Elements
### POV
> Not specified
### Characters
### Setting
> Not specified
### Date & Time
> Not specified | Not specified
---
## Story Structure
### Conflict
> Not specified
### Theme
> Not specified
### Tone
> Not specified
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
### Revision Notes
-
-
---
## Status Checklist
- [ ] Planning complete
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Created:** | **Updated:**
@@ -0,0 +1,129 @@
---
id: scene_03_01
title: "Chapter Three: Climax"
slug: chapter-three-climax
act: 3
chapter: 1
scene: 1
type: chapter
status: draft
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
pov: ""
characters: []
setting: ""
date: ""
time: ""
conflict: ""
theme: ""
tone: ""
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
version: 1
created: ""
updated: ""
planning_template: ""
draft_file: ""
order: 1
---
# Chapter Three: Climax
**Draft File** | **ID:** scene_03_01 | **Status:** Draft
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | 3 |
| **Chapter** | 1 |
| **Scene** | 1 |
| **Type** | Chapter |
| **POV** | Not set |
| **Version** | 1 |
| **Word Count Target** | 2000 |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | 2000 |
| **Minimum** | 1800 |
| **Maximum** | 2200 |
| **Current** | 0 |
| **This Session** | 0 |
| **Last Updated** | Never |
---
## Creative Elements
### POV
> Not specified
### Characters
### Setting
> Not specified
### Date & Time
> Not specified | Not specified
---
## Story Structure
### Conflict
> Not specified
### Theme
> Not specified
### Tone
> Not specified
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
### Revision Notes
-
-
---
## Status Checklist
- [ ] Planning complete
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Created:** | **Updated:**
@@ -0,0 +1,164 @@
---
# Merged Planning + Draft Template
# YAML frontmatter contains all planning fields; body is the draft content
id: scene_new
# Unique identifier for this scene
title: "New Scene Title"
# Display title for the scene
slug: new-scene-title
# URL-friendly slug
# === Core Metadata ===
act: 1
chapter: 1
scene: 99
type: scene
# Type: scene, chapter, interlude, etc.
# === Planning Fields ===
status: draft
# Status: planning, draft, revised, done
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
# === Creative Elements ===
pov: ""
# Point of view character
characters: []
# Characters appearing in this scene (array of names)
setting: ""
# Location/setting
date: ""
time: ""
# Date and time of scene
conflict: ""
# Central conflict in this scene
theme: ""
# Themes explored
tone: ""
# Mood/tone
# === Draft Tracking ===
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
version: 1
# === Timestamps ===
created: ""
updated: ""
# === Linking ===
# These are kept for backward compatibility but are no longer needed
# since planning and draft are merged
planning_template: ""
draft_file: ""
order: 99
---
# New Scene Title
**Scene File** | **ID:** scene_new | **Status:** Draft
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | 1 |
| **Chapter** | 1 |
| **Scene** | 99 |
| **Type** | Scene |
| **POV** | Not set |
| **Version** | 1 |
| **Word Count Target** | 2000 |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | 2000 |
| **Minimum** | 1800 |
| **Maximum** | 2200 |
| **Current** | 0 |
| **This Session** | 0 |
| **Last Updated** | Never |
---
## Creative Elements
### POV
> Not specified
### Characters
### Setting
> Not specified
### Date & Time
> Not specified | Not specified
---
## Story Structure
### Conflict
> Not specified
### Theme
> Not specified
### Tone
> Not specified
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
### Revision Notes
-
-
---
## Status Checklist
- [ ] Planning complete
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Created:** | **Updated:**
@@ -1,118 +0,0 @@
---
id: scene_new
title: "New Scene Title"
slug: new-scene-title
act: 1
chapter: 1
scene: 99
type: scene
status: planning
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
pov: ""
characters: []
setting: ""
date: ""
time: ""
conflict: ""
theme: ""
tone: ""
draft_file: ""
order: 99
created: ""
updated: ""
---
# New Scene Title
**Planning Template** | **ID:** scene_new | **Status:** {{ status | capitalizes }}
---
## Planning Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | {{ act }} |
| **Chapter** | {{ chapter }} |
| **Scene** | {{ scene }} |
| **Type** | {{ type | capitalizes }} |
| **Order** | {{ order }} |
| **Draft File** | {{ draft_file if draft_file else "[Create Draft File](#)" }} |
---
## Creative Elements
### POV
> {{ pov if pov else "Not specified" }}
### Characters
{% for character in characters %}- [[{{ character }}]]
{% endfor %}
### Setting
> {{ setting if setting else "Not specified" }}
### Date & Time
> {{ date if date else "Not specified" }} | {{ time if time else "Not specified" }}
---
## Story Structure
### Conflict
> {{ conflict if conflict else "Not specified" }}
### Theme
> {{ theme if theme else "Not specified" }}
### Tone
> {{ tone if tone else "Not specified" }}
---
## Word Count Goals
| Metric | Value |
|--------|-------|
| **Target** | {{ word_count_target }} |
| **Minimum** | {{ word_count_min }} |
| **Maximum** | {{ word_count_max }} |
---
## Scene Planning
### The Setup
>
### The Reveal
>
### Things to Note
-
-
---
## Status Tracking
- [ ] Scene outline complete
- [ ] Character arcs aligned
- [ ] Location details verified
- [ ] Conflict established
- [ ] Word count target set
- [ ] Ready for drafting
---
**Instructions:**
1. Copy this file to the appropriate act/chapter folder
2. Rename to `scene_XX.md` (e.g., `scene_02.md`)
3. Update the YAML frontmatter with scene details
4. Set `draft_file` to point to the corresponding draft file
5. Create the draft file using the template in `06-First Draft/_template.md`
**Related:** [Story Bible](../../03-Story-Bible/_index.md) | **Created:** {{ created }} | **Updated:** {{ updated }}
@@ -1,111 +0,0 @@
---
id: scene_01
title: "Chapter One: The Beginning"
slug: chapter-one-the-beginning
act: 1
chapter: 1
scene: 1
type: chapter
status: planning
word_count_target: 2000
word_count_min: 1800
word_count_max: 2200
pov: ""
characters: []
setting: ""
date: ""
time: ""
conflict: ""
theme: ""
tone: ""
draft_file: "../../06-First Draft/Act 1/scene01.md"
order: 1
created: ""
updated: ""
---
# Chapter One: The Beginning
**Planning Template** | **ID:** scene_01 | **Status:** {{ status | capitalizes }}
---
## Planning Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | {{ act }} |
| **Chapter** | {{ chapter }} |
| **Scene** | {{ scene }} |
| **Type** | {{ type | capitalizes }} |
| **Order** | {{ order }} |
| **Draft File** | [`{{ draft_file | replace('../../', '') }}`]({{ draft_file }}) |
---
## Creative Elements
### POV
> {{ pov if pov else "Not specified" }}
### Characters
{% for character in characters %}- [[{{ character }}]]
{% endfor %}
### Setting
> {{ setting if setting else "Not specified" }}
### Date & Time
> {{ date if date else "Not specified" }} | {{ time if time else "Not specified" }}
---
## Story Structure
### Conflict
> {{ conflict if conflict else "Not specified" }}
### Theme
> {{ theme if theme else "Not specified" }}
### Tone
> {{ tone if tone else "Not specified" }}
---
## Word Count Goals
| Metric | Value |
|--------|-------|
| **Target** | {{ word_count_target }} |
| **Minimum** | {{ word_count_min }} |
| **Maximum** | {{ word_count_max }} |
---
## Scene Planning
### The Setup
>
### The Reveal
>
### Things to Note
-
-
---
## Status Tracking
- [ ] Scene outline complete
- [ ] Character arcs aligned
- [ ] Location details verified
- [ ] Conflict established
- [ ] Word count target set
- [ ] Ready for drafting
---
**Draft File:** [Open Draft]({{ draft_file }}) | **Created:** {{ created }} | **Updated:** {{ updated }}
@@ -1,91 +0,0 @@
---
id: draft_scene_01
title: "Chapter One: The Beginning"
slug: chapter-one-the-beginning
planning_template: "../../05-Plot/act_1/scene_01.md"
act: 1
chapter: 1
scene: 1
type: draft
status: not_started
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
pov: ""
version: 1
created: ""
updated: ""
---
# Chapter One: The Beginning
**Draft File** | **ID:** draft_scene_01 | **Status:** {{ status | replace('_', ' ') | capitalizes }}
---
## Planning Reference
> **Linked to:** [Planning Template]({{ planning_template }})
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | {{ act }} |
| **Chapter** | {{ chapter }} |
| **Scene** | {{ scene }} |
| **Type** | {{ type | capitalizes }} |
| **POV** | {{ pov if pov else "Not set" }} |
| **Version** | {{ version }} |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | 2000 (from planning) |
| **Current** | {{ word_count }} |
| **This Session** | {{ session_word_count }} |
| **Last Updated** | {{ word_count_updated if word_count_updated else "Never" }} |
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
| {{ last_session if last_session else "" }} | {{ session_word_count }} | |
### Revision Notes
-
-
---
## Status Checklist
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Planning Template:** [Open Planning]({{ planning_template }}) | **Created:** {{ created }} | **Updated:** {{ updated }}
@@ -1,99 +0,0 @@
---
id: draft_scene_new
title: "New Scene Title"
slug: new-scene-title
planning_template: ""
act: 1
chapter: 1
scene: 99
type: draft
status: not_started
word_count: 0
word_count_updated: ""
session_word_count: 0
last_session: ""
total_sessions: 0
pov: ""
version: 1
created: ""
updated: ""
---
# New Scene Title
**Draft File** | **ID:** draft_scene_new | **Status:** {{ status | replace('_', ' ') | capitalizes }}
---
## Planning Reference
> **Linked to:** {{ planning_template if planning_template else "[Create Planning Template](#)" }}
---
## Scene Metadata
| Attribute | Value |
|-----------|-------|
| **Act** | {{ act }} |
| **Chapter** | {{ chapter }} |
| **Scene** | {{ scene }} |
| **Type** | {{ type | capitalizes }} |
| **POV** | {{ pov if pov else "Not set" }} |
| **Version** | {{ version }} |
---
## Word Count Tracking
| Metric | Value |
|--------|-------|
| **Target** | (from planning) |
| **Current** | {{ word_count }} |
| **This Session** | {{ session_word_count }} |
| **Last Updated** | {{ word_count_updated if word_count_updated else "Never" }} |
---
## Draft Content
### Rough Draft:
[Write your scene content here...]
---
## Writing Notes
### Session Log
| Date | Words Added | Notes |
|------|--------------|-------|
| {{ last_session if last_session else "" }} | {{ session_word_count }} | |
### Revision Notes
-
-
---
## Status Checklist
- [ ] First draft complete
- [ ] Word count target met
- [ ] POV consistent
- [ ] Character voices distinct
- [ ] Setting details accurate
- [ ] Conflict resolved/advanced
- [ ] Ready for revision
---
**Instructions:**
1. Copy this file to the appropriate Act/Chapter folder
2. Rename to `sceneXX.md` (e.g., `scene02.md`)
3. Update the YAML frontmatter with scene details
4. Set `planning_template` to point to the corresponding planning file
5. Create the planning file using the template in `05-Plot/_template.md`
6. Update word count as you write
**Related:** [Story Bible](../../03-Story-Bible/_index.md) | **Created:** {{ created }} | **Updated:** {{ updated }}