Story Continuation
Spectator can continue stories by appending new beats while preserving the full narrative context — character states, summaries, and world state carry forward.
Basic Continuation
Generate an initial story, then continue it with new beats:
const engine = new Engine({ provider: 'anthropic' })
// Generate the initial story
const story = await engine.generate({
characters: [
Character.create({ name: 'Kira', traits: ['brave', 'curious'] }),
Character.create({ name: 'Vorn', traits: ['mysterious', 'wise'] }),
],
plot: {
beats: [
{ name: 'The Meeting', type: 'setup' },
{ name: 'The Journey Begins', type: 'inciting-incident' },
],
},
instructions: 'Set in a fantasy world with ancient ruins',
})
console.log(story.toMarkdown())Now continue with new beats:
const continued = await engine.continue(story, {
beats: [
{ name: 'The Discovery', type: 'rising-action' },
{ name: 'The Confrontation', type: 'climax' },
],
instructions: 'Raise the stakes dramatically',
})Accessing New Scenes
The continued story includes all scenes — both original and new. To get only the new scenes:
const newScenes = continued.scenes.slice(story.sceneCount)
for (const scene of newScenes) {
console.log(`--- ${scene.beat?.name ?? 'Scene'} ---`)
console.log(scene.text)
}Character State Evolution
Character states evolve across continuations. The engine tracks emotional states, goals, and internal conflicts:
if (continued.characterStates) {
for (const state of continued.characterStates) {
console.log(`${state.characterName}: ${state.emotionalState}`)
if (state.internalConflict) {
console.log(` Conflict: ${state.internalConflict}`)
}
}
}ContinueInput
The second argument to continue() is optional:
interface ContinueInput {
beats?: BeatInput[] // New beats to generate (defaults to a single generic beat)
instructions?: string // Additional guidance for this continuation
}If you omit beats, the engine generates a single scene with a generic beat.
Streaming Continuation
Continuation supports both streaming modes:
Scene-level
for await (const scene of engine.continueStream(story, {
beats: [{ name: 'The Aftermath', type: 'falling-action' }],
})) {
console.log(scene.text)
}Token-level
const stream = engine.continueStreamText(story, {
beats: [{ name: 'The Aftermath', type: 'falling-action' }],
})
for await (const event of stream) {
if (event.type === 'text-delta') {
process.stdout.write(event.text)
}
}How Context is Preserved
When continuing a story, the engine:
- Extracts scene summaries from all previous scenes
- Reads the last scene's character states
- Passes this context to the LLM alongside the new beats
- Generates new scenes that build on the existing narrative
This means characters remember what happened, emotional arcs carry forward, and the narrative stays consistent.