plotcoder-board 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,191 @@
1
+ // Type surface for the PlotCoder board kernel (implemented in reducer.js).
2
+ // Authored as plain ESM JS + this declaration so the exact same module runs in
3
+ // the browser (via Vite) and in Node (the MCP server) with no build step.
4
+
5
+ export declare const NOTE_COLORS: readonly ["yellow", "pink", "blue", "green", "orange"];
6
+ export type NoteColor = (typeof NOTE_COLORS)[number];
7
+
8
+ export declare const NOTE_RANKS: readonly ["scene", "beat"];
9
+ export type NoteRank = (typeof NOTE_RANKS)[number];
10
+
11
+ /** What an arrow means: what comes after what, or a setup and its payoff (R30). */
12
+ export declare const ARROW_KINDS: readonly ["follows", "setup"];
13
+ export type ArrowKind = (typeof ARROW_KINDS)[number];
14
+
15
+ /** Length is measured in eighths of a page (D23). */
16
+ export declare const EIGHTHS_PER_PAGE: number;
17
+ export declare const DEFAULT_NOTE_EIGHTHS: number;
18
+ export declare const DEFAULT_TARGET_EIGHTHS: number;
19
+ /** Total estimated length of the board, in eighths. */
20
+ export declare const LINES_PER_PAGE: number;
21
+ /** Eighths the scene's text runs to; 0 when there is no text. */
22
+ export declare function measuredEighths(text: string | undefined): number;
23
+ /** Measured when written, the estimate otherwise. Every reading uses this. */
24
+ export declare function noteEighths(note: BoardNote): number;
25
+ export declare function isMeasured(note: BoardNote): boolean;
26
+ export declare function boardEighths(state: BoardState): number;
27
+ /** Eighths as a breakdown writes them: "1 3/8", "97", "5/8". */
28
+ export declare function formatPages(eighths: number): string;
29
+ /** Eighths as screen time, a page a minute: "17 minutes", "2 hours", "2 h 4 min". */
30
+ export declare function formatMinutes(eighths: number): string;
31
+
32
+ export declare const NOTE_WIDTH: number;
33
+ export declare const NOTE_HEIGHT: number;
34
+
35
+ /**
36
+ * One person in the board's roster (R29, D26). Referenced from cards by id.
37
+ * The record is expected to grow — what they look like, the details a writer
38
+ * pulls up — so it carries an id and timestamps from the start.
39
+ */
40
+ export type CharacterField = "looks" | "voice" | "wants" | "needs" | "notes";
41
+ export declare const CHARACTER_FIELDS: readonly CharacterField[];
42
+
43
+ export type BoardCharacter = {
44
+ id: string;
45
+ name: string;
46
+ /** The person's page (R36): all text, empty until filled. */
47
+ looks: string;
48
+ voice: string;
49
+ wants: string;
50
+ needs: string;
51
+ notes: string;
52
+ createdAt: string;
53
+ updatedAt: string;
54
+ };
55
+
56
+ /** The page fields a person has filled in, in page order. */
57
+ /** The places on a wall in order of first appearance, with card counts. */
58
+ export declare function boardPlaces(state: BoardState): Array<{ name: string; cards: number }>;
59
+ /** True when the card is at this place, spelt any way. */
60
+ export declare function atPlace(note: BoardNote, place: string): boolean;
61
+
62
+ export declare function filledCharacterFields(character: BoardCharacter): CharacterField[];
63
+
64
+ export type BoardNote = {
65
+ id: string;
66
+ headline: string;
67
+ change: string;
68
+ color: NoteColor;
69
+ x: number;
70
+ y: number;
71
+ rotate: number;
72
+ z: number;
73
+ /** A beat is one of the 8-to-15 major turns; everything else is a scene (R20). */
74
+ rank: NoteRank;
75
+ /** Estimated screen time, in eighths of a page (R25). */
76
+ /** The writer's estimate in eighths of a page; null until someone sizes the card, which reads as about a page. */
77
+ lengthEighths: number | null;
78
+ /** Who is in the scene: ids from the roster, in the order they were cast (R29). */
79
+ characterIds: string[];
80
+ /** The corner is folded: this card plants something that must pay off (R31). */
81
+ plants: boolean;
82
+ /** Where the scene happens (R37): a phrase in the writer's words; empty until set. */
83
+ location: string;
84
+ /** The scene's text in Fountain (R23 b): action, cues, dialogue; empty until written. */
85
+ text: string;
86
+ createdAt: string;
87
+ updatedAt: string;
88
+ };
89
+
90
+ export type BoardGroup = {
91
+ id: string;
92
+ title: string;
93
+ noteIds: string[];
94
+ };
95
+
96
+ export type BoardArrow = {
97
+ id: string;
98
+ from: string;
99
+ to: string;
100
+ /** "follows" unless the writer says the tail sets up the head. */
101
+ kind: ArrowKind;
102
+ };
103
+
104
+ export type BoardState = {
105
+ /** The board's central question — what this story is arguing (R19). */
106
+ logline: string;
107
+ /** Target script length in eighths of a page; 120 pages for a feature (R25). */
108
+ targetEighths: number;
109
+ /** The roster: every person in the story, whether or not they are on a card yet (R29). */
110
+ characters: BoardCharacter[];
111
+ notes: BoardNote[];
112
+ groups: BoardGroup[];
113
+ arrows: BoardArrow[];
114
+ /** Locked scene numbers, once a draft has gone out (Roadmap 2, item 8); null until then. */
115
+ lock: import("./numbering").Lock | null;
116
+ /** The revision in progress — a name, a colour, a snapshot — or null. */
117
+ revision: import("./numbering").Revision | null;
118
+ };
119
+
120
+ export type Pose = { id: string; x: number; y: number; rotate: number };
121
+
122
+ export type Command =
123
+ | { type: "set_logline"; logline: string }
124
+ | { type: "set_rank"; ids: string[]; rank: NoteRank }
125
+ | { type: "set_length"; ids: string[]; lengthEighths: number }
126
+ | { type: "set_target"; targetEighths: number }
127
+ | {
128
+ type: "create_note";
129
+ id?: string;
130
+ headline?: string;
131
+ change?: string;
132
+ color?: NoteColor;
133
+ x?: number;
134
+ y?: number;
135
+ rotate?: number;
136
+ rank?: NoteRank;
137
+ lengthEighths?: number;
138
+ characterIds?: string[];
139
+ plants?: boolean;
140
+ location?: string;
141
+ text?: string;
142
+ }
143
+ | { type: "update_note"; id: string; headline?: string; change?: string; location?: string }
144
+ | { type: "move_note"; id: string; x: number; y: number }
145
+ | { type: "nudge_notes"; ids: string[]; dx: number; dy: number }
146
+ | { type: "recolor_notes"; ids: string[]; color: NoteColor }
147
+ | { type: "raise_note"; id: string }
148
+ | { type: "delete_note"; id: string }
149
+ | { type: "apply_poses"; poses: Pose[] }
150
+ | { type: "settle_note"; id: string }
151
+ | { type: "create_group"; title?: string; noteIds: string[] }
152
+ | { type: "ungroup"; id: string }
153
+ | { type: "rename_group"; id: string; title: string }
154
+ | { type: "create_arrow"; from: string; to: string; kind?: ArrowKind }
155
+ | { type: "delete_arrow"; id: string }
156
+ | { type: "set_arrow_kind"; id: string; kind: ArrowKind }
157
+ | { type: "new_board" }
158
+ | { type: "add_character"; name: string; id?: string }
159
+ | { type: "rename_character"; id: string; name: string }
160
+ | { type: "remove_character"; id: string }
161
+ | ({ type: "update_character"; id: string } & Partial<Record<CharacterField, string>>)
162
+ | { type: "set_cast"; ids: string[]; characterIds: string[] }
163
+ | { type: "set_plant"; ids: string[]; plants: boolean }
164
+ | { type: "set_location"; ids: string[]; location: string }
165
+ | { type: "apply_template"; template: string; beats?: Array<{ name: string; prompt: string; at: number }> }
166
+ | { type: "set_text"; id: string; text: string }
167
+ | { type: "lock_numbers"; order?: string[] }
168
+ | { type: "unlock_numbers" }
169
+ | { type: "start_revision"; name: string; color?: string }
170
+ | { type: "end_revision" };
171
+
172
+ export type CommandResult = {
173
+ state: BoardState;
174
+ changed: boolean;
175
+ result?: unknown;
176
+ };
177
+
178
+ export declare function newId(): string;
179
+ export declare function nowIso(): string;
180
+ export declare function emptyState(): BoardState;
181
+ export declare function seedState(now?: string): BoardState;
182
+ export declare function isBoardState(value: unknown): value is BoardState;
183
+ /** Fill in fields added after a board was written. Run at every load boundary. */
184
+ export declare function normalizeState(value: unknown): BoardState;
185
+ /** Beats vs scenes. The app shows this number and passes no judgement (D21). */
186
+ export declare function countRanks(state: BoardState): { beats: number; scenes: number };
187
+ export declare function applyCommand(
188
+ state: BoardState,
189
+ command: Command,
190
+ now?: string,
191
+ ): CommandResult;