Skip to content

Commit b52c2a4

Browse files
committed
updates: add story settings links
1 parent 0b9ab12 commit b52c2a4

7 files changed

Lines changed: 168 additions & 23 deletions

File tree

SPECIFICATION.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ For open-source adopters, this creates a shared on-ramp: communities can exchang
9393
```
9494

9595

96+
## Story Settings
97+
98+
NCP supports optional reusable story-level Settings for places or environments that recur across Moments. `story.settings[]` defines the shared setting once, while each Moment keeps its own free-text `setting` and may optionally reference the shared entry with `setting_id`.
99+
100+
This avoids repeating the same place details across multiple Moments without making every producer model setting identity. Producers that only need free-text Moment settings can omit `story.settings[]` and `setting_id`.
101+
102+
```json
103+
"settings": [
104+
{
105+
"id": "setting_precinct_archive",
106+
"name": "Precinct Archive",
107+
"description": "A dimly lit archive room where old case files preserve institutional memory."
108+
}
109+
]
110+
```
111+
96112
## Narrative: Structuring Subtext & Storytelling
97113

98114
A single story may contain one or more narratives (e.g., _The Empire Strikes Back_ has the Luke/Yoda Storyform and the Han/Leia Storyform, _Barbie_ has the Barbie/Ken Storyform and the Barbie/Gloria Storyform). Most stories, however, exhibit a single central narrative (e.g., _Anora_, _Anatomy of a Fall_, etc.).
@@ -414,6 +430,7 @@ Organizational narrative units—such as Acts, Scenes, Sequences, Chapters, and
414430
"summary": "Infiltrating the neon-lit heart of a dystopian metropolis, Alex plunges into a shadowy realm teeming with digital outlaws.",
415431
"synopsis": "Freshly arrived in the neon chaos of Neo-Tokyo, Alex is swiftly ensnared in a perilous game played by cyber-criminals, underground syndicates, and relentless AI-driven enforcers.",
416432
"setting": "The pulsating streets of Neo-Tokyo, where holographic ads blend with the shadowy back alleys controlled by syndicate bosses.",
433+
"setting_id": "setting_neo_tokyo_streets",
417434
"timing": "Late night, just hours after Alex's first unsettling discovery upon arriving in the city.",
418435
"imperatives": "- Establish the dark, chaotic atmosphere of Neo-Tokyo\n- Introduce key threats: cyber-criminals and AI enforcers\n- Show Alex's initial vulnerabilities and resourcefulness",
419436
"audience_experiential_pov": "third_person_limited",

docs/narrative-context-protocol-schema.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ Quick heuristic:
104104
- If it is an event chain or conflict progression, put it in `plot`.
105105
- If it is a framing/experience contract with the audience, put it in `genre`.
106106

107+
## Story Settings
108+
109+
`story.settings[]` is an optional story-level glossary for reusable places or environments. Each setting requires an `id` and `name`, with an optional `description`. Moments may keep their local free-text `setting` prose while also pointing at a shared setting with `setting_id`.
110+
111+
Use this when multiple Moments occur in the same place and producers want a stable reference instead of repeating or string-matching setting descriptions.
112+
113+
```json
114+
"settings": [
115+
{
116+
"id": "setting_precinct_archive",
117+
"name": "Precinct Archive",
118+
"description": "A dimly lit archive room where old case files preserve institutional memory."
119+
}
120+
]
121+
```
122+
107123
## Narrative Layers
108124

109125
Each item in `story.narratives[]` is a Dramatica storyform: a single, complete argument structure within the story, expressed through `subtext` and `storytelling` layers.
@@ -290,7 +306,9 @@ Required keys per item:
290306

291307
Optional keys:
292308

293-
- `id`, `act`, `order`, `maximum_steps`, `fabric`, `audience_experiential_pov`
309+
- `id`, `setting_id`, `act`, `order`, `maximum_steps`, `fabric`, `audience_experiential_pov`
310+
311+
`setting` remains the Moment-specific free-text description. `setting_id` may reference a `story.settings[]` entry when the Moment occurs in a reusable story-level setting.
294312

295313
`storybeats` inside a moment is an ordered reference list:
296314

examples/example-story.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
"genre": "Mystery Thriller",
77
"logline": "A hardened detective uncovers clues linking a cold case to his own haunting history.",
88
"created_at": "2025-12-01T12:34:56Z",
9+
"settings": [
10+
{
11+
"id": "setting_precinct_archive",
12+
"name": "Precinct Archive",
13+
"description": "A dimly lit archive room where old case files preserve institutional memory and unresolved history."
14+
}
15+
],
916
"ideation": {
1017
"character": [
1118
{
@@ -149,6 +156,7 @@
149156
"summary": "The inciting discovery",
150157
"synopsis": "John uncovers an old case file that hints at deeper connections to his own past.",
151158
"setting": "A dimly lit precinct archive room.",
159+
"setting_id": "setting_precinct_archive",
152160
"timing": "Late night, after hours.",
153161
"imperatives": "Investigate the link before the evidence disappears.",
154162
"storybeats": [

examples/story-settings.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"schema_version": "1.3.0",
3+
"story": {
4+
"id": "story_settings_demo",
5+
"title": "Shared Settings Demo",
6+
"logline": "A detective returns to the same archive twice and discovers that the room itself carries meaning.",
7+
"created_at": "2026-05-12T20:10:00Z",
8+
"settings": [
9+
{
10+
"id": "setting_precinct_archive",
11+
"name": "Precinct Archive",
12+
"description": "A dim archive room where unresolved cases gather institutional dust."
13+
}
14+
],
15+
"narratives": [
16+
{
17+
"id": "narrative_settings_demo",
18+
"title": "Central Narrative",
19+
"subtext": {
20+
"perspectives": [],
21+
"players": [],
22+
"dynamics": [],
23+
"storypoints": [],
24+
"storybeats": []
25+
},
26+
"storytelling": {
27+
"overviews": [],
28+
"moments": [
29+
{
30+
"id": "moment_archive_return",
31+
"summary": "The detective returns to the archive.",
32+
"synopsis": "A second visit to the archive reframes the old evidence as a personal warning.",
33+
"setting": "The same archive room, now colder and less familiar.",
34+
"setting_id": "setting_precinct_archive",
35+
"timing": "After midnight.",
36+
"imperatives": "Show that the shared place has taken on new meaning.",
37+
"storybeats": []
38+
}
39+
]
40+
}
41+
}
42+
]
43+
}
44+
}

schema/ncp-schema.json

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,31 @@
2929
"description": "ISO-8601 UTC timestamp (e.g., 2025-12-01T12:34:56Z).",
3030
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
3131
},
32+
"settings": {
33+
"type": "array",
34+
"description": "Optional story-level setting glossary. Each entry is a stable, referenceable place or environment that Moments may identify with setting_id while retaining free-text setting prose.",
35+
"items": {
36+
"type": "object",
37+
"properties": {
38+
"id": {
39+
"$ref": "#/$defs/setting_id"
40+
},
41+
"name": {
42+
"type": "string",
43+
"description": "Short human-readable setting name."
44+
},
45+
"description": {
46+
"type": "string",
47+
"description": "Optional longer setting description."
48+
}
49+
},
50+
"required": [
51+
"id",
52+
"name"
53+
],
54+
"additionalProperties": false
55+
}
56+
},
3257
"ideation": {
3358
"type": "object",
3459
"description": "Optional pre-narrative ideation threads for exploratory and beginner workflows.",
@@ -90,17 +115,17 @@
90115
"subtext": {
91116
"type": "object",
92117
"properties": {
93-
"perspectives": {
94-
"type": "array",
95-
"items": {
96-
"type": "object",
97-
"properties": {
98-
"id": {
99-
"$ref": "#/$defs/perspective_id"
100-
},
101-
"author_structural_pov": {
102-
"type": "string",
103-
"enum": [
118+
"perspectives": {
119+
"type": "array",
120+
"items": {
121+
"type": "object",
122+
"properties": {
123+
"id": {
124+
"$ref": "#/$defs/perspective_id"
125+
},
126+
"author_structural_pov": {
127+
"type": "string",
128+
"enum": [
104129
"i",
105130
"you",
106131
"we",
@@ -348,17 +373,17 @@
348373
"type": "array",
349374
"items": {
350375
"type": "object",
351-
"properties": {
352-
"id": {
353-
"$ref": "#/$defs/stable_id"
354-
},
355-
"appreciation": {
356-
"type": "string",
357-
"description": "Optional derived structural label, typically throughline + scope + sequence (for example, Objective Story Signpost 1)."
358-
},
359-
"scope": {
360-
"type": "string",
361-
"enum": [
376+
"properties": {
377+
"id": {
378+
"$ref": "#/$defs/stable_id"
379+
},
380+
"appreciation": {
381+
"type": "string",
382+
"description": "Optional derived structural label, typically throughline + scope + sequence (for example, Objective Story Signpost 1)."
383+
},
384+
"scope": {
385+
"type": "string",
386+
"enum": [
362387
"signpost",
363388
"progression",
364389
"event"
@@ -515,6 +540,10 @@
515540
"setting": {
516541
"type": "string"
517542
},
543+
"setting_id": {
544+
"$ref": "#/$defs/setting_id",
545+
"description": "Optional reference to a story.settings[] entry for this Moment. Use with setting to avoid repeating shared place details while preserving the Moment-specific setting prose."
546+
},
518547
"timing": {
519548
"type": "string"
520549
},
@@ -661,6 +690,10 @@
661690
"type": "string",
662691
"description": "Opaque identifier for an overview. Plain UUIDs are fine; type prefixes are not required."
663692
},
693+
"setting_id": {
694+
"type": "string",
695+
"description": "Opaque identifier for a story-level setting. Plain UUIDs are fine; setting_ prefixes are optional."
696+
},
664697
"perspective_link": {
665698
"type": "object",
666699
"properties": {

schema/ncp-schema.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ properties:
2222
type: string
2323
description: ISO-8601 UTC timestamp (e.g., 2025-12-01T12:34:56Z).
2424
pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
25+
settings:
26+
type: array
27+
description: Optional story-level setting glossary. Each entry is a stable, referenceable place or environment that Moments may identify with setting_id while retaining free-text setting prose.
28+
items:
29+
type: object
30+
properties:
31+
id:
32+
"$ref": "#/$defs/setting_id"
33+
name:
34+
type: string
35+
description: Short human-readable setting name.
36+
description:
37+
type: string
38+
description: Optional longer setting description.
39+
required:
40+
- id
41+
- name
42+
additionalProperties: false
2543
ideation:
2644
type: object
2745
description: Optional pre-narrative ideation threads for exploratory and beginner workflows.
@@ -368,6 +386,9 @@ properties:
368386
type: string
369387
setting:
370388
type: string
389+
setting_id:
390+
"$ref": "#/$defs/setting_id"
391+
description: Optional reference to a story.settings[] entry for this Moment. Use with setting to avoid repeating shared place details while preserving the Moment-specific setting prose.
371392
timing:
372393
type: string
373394
imperatives:
@@ -468,6 +489,9 @@ additionalProperties: false
468489
overview_id:
469490
type: string
470491
description: Opaque identifier for an overview. Plain UUIDs are fine; type prefixes are not required.
492+
setting_id:
493+
type: string
494+
description: Opaque identifier for a story-level setting. Plain UUIDs are fine; setting_ prefixes are optional.
471495
perspective_link:
472496
type: object
473497
properties:

tests/validate-schema.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const validate = ajv.compile(schema);
99

1010
const validFixtures = [
1111
'../examples/example-story.json',
12+
'../examples/story-settings.json',
1213
'../examples/ideation-beginner.json',
1314
'../examples/anora.json',
1415
'../examples/the-shawshank-redemption.json',

0 commit comments

Comments
 (0)