inkhaven 1.6.21

Inkhaven — TUI literary work editor for Typst books
# Tutorial 67 — The Planning Board: diagnose your structure

*Inkhaven 1.3.2+*

Most planning tools help you *organize* — corkboards, index cards, outlines.
What none of them do well is help you **diagnose**: *"something's wrong with
my middle but I can't see it."* The Planning Board turns that vague unease
into a specific, located, objective finding.

Structure is a third axis alongside the **Timeline** (*when* things happen)
and **Threads** (*whether each arc pays off*): the acts, beats, and turning
points — the shape of the rise and fall. It works on a draft you already
have; you don't plan from a blank page.

## 1. Lay a framework over the book

Pick a story-structure framework and scaffold its beats into the
**Planning** system book:

```sh
inkhaven plan init --framework save_the_cat
# three_act (default) | save_the_cat | story_circle | hero_journey | seven_point
```

Each beat becomes an HJSON paragraph in the Planning book — open one in the
editor and it reads like a Thread:

```hjson
{
  framework:       "save_the_cat"
  beat:            "Midpoint"
  act:             2
  target_position: 0.50
  mapped_chapter:  null        // ← set this to a chapter slug
  threads:         []          // ← arc slugs this beat advances
  status:          "planned"
}
```

## 2. Find the slugs, then map a beat

A beat maps to a chapter by the chapter's **slug**, and to arcs by their
**thread slugs**. You don't have to guess them — **`inkhaven plan check`
prints both lists at the bottom of its report**, so the loop is *init →
check → map → check again*:

```
CHAPTER SLUGS (set `mapped_chapter:` to one of these)
  the-wharf            0%
  the-letter          12%
  the-reveal          48%
  the-long-night      71%
  …
THREAD SLUGS (add to a beat's `threads:` list)
  the-inheritance
  the-lighthouse-secret
```

These are the **bare** slugs — the title lowercased and hyphenated, with
**no** leading `NN-` number. (That `01-`/`02-` prefix you see on the folder
names under `books/…/` only orders the files on disk; it is *not* part of
the slug.) Threads come from the **Threads** book — add an arc with
`inkhaven thread add "The Inheritance"` and its slug is `the-inheritance`.

Now open the beat in the editor — it's a paragraph under **Planning** in
the tree (`Planning ▸ Midpoint`) — and fill the two fields, copying the
slugs from the lists above:

```hjson
{
  framework:       "save_the_cat"
  beat:            "Midpoint"
  act:             2
  target_position: 0.50
  mapped_chapter:  "the-reveal"          // ← was null
  threads:         ["the-inheritance"]   // ← was []
  status:          "drafted"
}
```

Save with `Ctrl+S`. One chapter can host several beats, and a beat can
carry several threads (`["the-inheritance", "the-lighthouse-secret"]`).
Re-run `plan check` and the beat resolves:

```
✓ Midpoint          act 2  target  50%  → the-reveal (48%, -2%)  ↪ the-inheritance
```

(Prefer the editor, but the same edit works from any text editor on the
beat's `.typ` file under `books/planning/` — inkhaven reloads it.)

**Or skip the hand-edit entirely.** `plan map` does the write-back for you,
straight from the slugs `plan check` just printed:

```sh
inkhaven plan map Midpoint --chapter the-reveal --threads the-inheritance
inkhaven plan unmap "All Is Lost"     # clears mapped_chapter back to null
```

The beat is matched by name, slug, or beat-number; the mapping lands in its
Planning-book HJSON exactly as the hand-edit would. This is the same
primitive the interactive outline (§4) uses.

## 3. Check the structure

```sh
inkhaven plan check                 # or --json / --drift 15 / --book-name "My Novel"
```

```
plan check · My Novel · Save the Cat · 24 chapter(s)

BEATS
  ✓ Catalyst          act 1  target  10%  → the-letter (12%, +2%)
  ⚠ Midpoint          act 2  target  50%  → the-reveal (64%, +14%)  ↪ the-inheritance
  ✗ All Is Lost       act 2  target  75%  (unmapped)

PACING (act word-share)
  Act 1   expected  20%   actual  30%   ⚠ long
  Act 2   expected  60%   actual  45%   ⚠ short

3 finding(s):
  ⚠ gap: `All Is Lost` is unmapped
  ⚠ drift: `Midpoint` lands at 64% (target 50%, +14%)
  ⚠ pacing: Act 1 is 30% of words (expected 20%, long)

CHAPTER SLUGS (set `mapped_chapter:` to one of these)
  the-wharf            0%
  the-letter          12%
  …
THREAD SLUGS (add to a beat's `threads:` list)
  the-inheritance
```

Three diagnoses, none of them AI:

- **Coverage** — which beats have a home, which are gaps (``).
- **Position drift** — a beat lands far from where the framework expects it
  (your Midpoint is two-thirds in, not half).
- **Pacing** — each act's *word share* vs. the framework's shape. "Act 1 is
  30% of your words" is the objective version of "the opening drags."

These are factual, not verdicts — prompts to think.

## 4. See it at a glance

In the editor, **`Ctrl+V Shift+K`** (K for sKeleton) opens the structure
outline: every beat as a position bar — `|` is where the framework wants
it, `●` where it actually lands — colour-coded on-target / drift / gap,
with the act pacing below. `↪N` marks beats that advance threads.

The outline is **interactive** — you map without leaving it:

- `↑↓` browse beats; the selected beat's intention shows under the bar.
- **`m`** opens a chapter picker and maps the selected beat to your choice
  (the write-back from §2, no HJSON editing).
- **`t`** links threads to the beat (Space toggles each on/off).
- **`s`** cycles the beat's status (planned → drafted → done).
- **`Enter`** opens the beat's mapped chapter in the editor.
- **`a`** streams the AI analysis into the AI pane (§5).
- **`v`** flips to the scene board (§7).

So the tighten-the-structure loop — *see the drift, map the beat, watch it
snap to target* — never leaves this one view.

### The tension curve

Beneath the position bars the outline draws two block-ramp sparklines
(`▁`..`█`), aligned to the same axis so a beat's `●` sits over its cell:

- **expected** — the framework's intended *intensity* (calm open, peak in
  the back half — the canonical rise and fall).
- **actual** — how much narrative tension your draft actually carries at
  each point, measured deterministically as **open-obligation density**:
  every question you raise but haven't paid off keeps the line high.

Where expected is high but actual is low, the beat is flagged **flat** — the
objective version of "the midpoint sags." `plan check` prints the same
read as a TENSION section:

```
TENSION (expected vs actual intensity)
  Midpoint            expected  65%  actual  33% ⚠ flat
  Climax              expected 100%  actual 100%
```

The actual line needs the open/resolved data: run **`inkhaven tension
scan`** (the 1.2.19 AI pass that tags each chapter's introduced/resolved
tensions) and/or link your **Threads** so the Board can see which arcs are
open where. Without either, you still get the expected shape, with a hint.

**A second opinion.** The actual line is deterministic — it counts *open
obligations*. For an independent reading, run **`inkhaven plan tension
rate`**: an AI pass that rates each chapter's felt intensity 0–100 and
caches it. `plan check` then adds an `ai` column and the overlay a third
sparkline, so you compare three readings:

```
TENSION (expected vs actual vs ai intensity)
  Midpoint            expected  65%  actual  33%  ai  35% ⚠ flat
  Climax              expected 100%  actual 100%  ai  95%
```

When *both* actual and ai land low where the framework wants a peak — as at
the Midpoint above — that's two independent signals agreeing the middle
sags. The deterministic curve stays the default; the `ai` line is opt-in and
absent until you rate.

## 5. Ask the AI

For the qualitative read, over the book digest:

```sh
inkhaven plan analyze               # builds the digest if needed
```

It maps each beat to the best-fitting chapter and names the problems —
*"your 'bad guys close in' stretch is doing the work of a midpoint; the
real midpoint is missing."* From the outline view, **`a`** streams the same
analysis into the AI pane. Its prompt resolves through the usual three
tiers (a `plan-analyze` paragraph in your Prompts book → `prompts.hjson` →
built-in), so the editorial voice is tunable. To keep an analysis you like,
press **`L`** in the AI pane — it files the response as a *Structural
Analysis* paragraph in the Planning book, next to your beats.

## 6. Start from nothing (plan-first)

The sections above diagnose an existing draft. You can also run the Board
the other way — skeleton first, prose later. Give a framework a one-line
premise and let it write the beat sheet:

```sh
inkhaven plan init --framework save_the_cat
inkhaven plan scaffold --premise "A lighthouse keeper's daughter inherits a
  debt that can only be paid by the secret her father drowned to keep."
```

`scaffold` writes a concrete **intention** into every beat — what actually
happens there in *this* story, not the generic beat description — which the
outline then shows under each bar. Add `--chapters` to materialize a
**chapter shell** per beat, named from the beat and pre-linked via
`mapped_chapter`:

```sh
inkhaven plan scaffold --premise "…" --chapters
```

That's opt-in and guarded — it refuses to run once the book has chapters,
so it can't clobber a draft. The result is a mapped beat sheet and a
chapter scaffold you can start writing into, with `plan check` already
green because every beat has a home.

## 7. Scene cards (a finer grain than beats)

Beats are chapter-scale. **Scene cards** work one level down — each scene's
**goal → conflict → disaster** (Swain's model: the POV character wants
something, something opposes it, and the scene *turns* on a disaster that
ends it worse or changed):

```sh
inkhaven plan scene add "Mara confronts the harbourmaster" \
    --chapter the-wharf \
    --goal "get the manifest" \
    --conflict "he stonewalls" \
    --disaster "he names her father as the debtor"

inkhaven plan scene list      # grouped by chapter, with G/C/D marks
```

The deterministic check is the **turn**: a scene that states a goal but has
no disaster *doesn't turn* — it's flagged `⚠ no turn`, in `plan scene list`
and folded into `plan check`. `plan scene set <title> --disaster "…"` fills
it in; `plan scene remove <title>` drops the card. Cards live under a
**Scenes** chapter in the Planning book.

In the outline (`Ctrl+V Shift+K`), press **`v`** for the scene board: every
card grouped by chapter with its G/C/D marks and turn flag, the selected one
expanding its full goal/conflict/disaster spine. And `plan analyze` reads
the cards too — it'll name the scenes that don't turn and suggest the turn
they're missing.

**Don't type it from scratch.** The prose already implies the
goal/conflict/disaster, so let the AI propose them:

```sh
inkhaven plan scene scaffold --chapter the-wharf   # one chapter
inkhaven plan scene scaffold --all                 # every cardless chapter
```

In the scene board, **`g`** regenerates the selected card from its chapter's
prose — the proposal streams into the AI pane, and **`L`** files it back
into the card (the same lift you use for the structural analysis).

### Sequels: the reactive half

Swain's structure alternates **scenes** (proactive: goal → conflict →
disaster) with **sequels** (reactive: **reaction → dilemma → decision**).
The disaster lands; the character reels, weighs bad options, and *decides* —
which sets the next scene's goal. Model the reactive beats too:

```sh
inkhaven plan sequel add "Mara reels" --chapter the-wharf \
    --reaction "she's gutted" \
    --dilemma "pay the debt or expose her father" \
    --decision "pay it quietly and hunt the truth"

inkhaven plan sequel list      # or `plan scene list` for both, kind-tagged
```

The weak-card check flips for sequels: one that reaches a **dilemma** but
never **decides** stalls the story (`⚠ no decision`). And once you're using
sequels, two scenes back-to-back flag the first's **unprocessed disaster** —
a skipped sequel. The `v` board shows both kinds, tagged.

## Threads do narrative work

Listing a beat's `threads` connects structure to arcs: `plan check` shows
them (`↪`), flags a reference to a thread that doesn't exist, and — once
you're using thread-links — nudges you about mapped beats that advance no
tracked thread. A beat that moves the plot forward but pays off no arc is
worth a second look.

## Where to go next

- The submission path once the structure holds:
  [Tutorial 66]66-submission-package.md.
- Every chord: [`../KEYBINDING.md`]../KEYBINDING.md.
- The design: [PLANNING-1 plan]../PROPOSALS/PLANNING-1_PLAN.md.