@kawaijs/runtime 0.1.10 → 0.1.12

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.
package/dist/save.d.ts CHANGED
@@ -1,12 +1,34 @@
1
- import type { Snapshot } from './state.js';
1
+ import type { StoryPackage } from '@kawaijs/ast';
2
+ import type { DialogueHistoryEntry } from './history.js';
3
+ import { type Snapshot, type StoryState } from './state.js';
4
+ export declare const CURRENT_SAVE_SCHEMA_VERSION = 2;
2
5
  export interface SaveSlot {
6
+ readonly schemaVersion?: number;
7
+ readonly storyHash?: string;
3
8
  readonly id: string;
4
9
  readonly name: string;
5
10
  readonly timestamp: number;
6
11
  readonly snapshot: Snapshot;
7
12
  readonly previewText?: string;
8
13
  readonly screenshotUrl?: string;
14
+ /** Persisted dialogue backlog (schema v2+). */
15
+ readonly historyEntries?: readonly DialogueHistoryEntry[];
9
16
  }
17
+ export type LoadFailureReason = 'not_found' | 'corrupt' | 'incompatible_schema' | 'incompatible_story';
18
+ export interface LoadResult {
19
+ readonly success: boolean;
20
+ readonly slot?: SaveSlot;
21
+ readonly reason?: LoadFailureReason;
22
+ }
23
+ export declare function fnv1a(str: string): string;
24
+ export declare function computeStoryHash(story: StoryPackage): string;
25
+ /** Explicit v1 → v2: add historyEntries (empty if missing). */
26
+ export declare function migrateSaveV1ToV2(slot: SaveSlot): SaveSlot;
27
+ /**
28
+ * Migrate / normalize a parsed save slot to the current schema.
29
+ * Returns null if the slot cannot be recovered.
30
+ */
31
+ export declare function migrateSaveSlot(raw: unknown): SaveSlot | null;
10
32
  export interface StorageAdapter {
11
33
  getItem(key: string): string | null | Promise<string | null>;
12
34
  setItem(key: string, value: string): void | Promise<void>;
@@ -27,9 +49,11 @@ export declare class SaveManager {
27
49
  private readonly storage;
28
50
  private readonly storagePrefix;
29
51
  constructor(storage?: StorageAdapter, storagePrefix?: string);
30
- saveSlot(slotId: string, snapshot: Snapshot, previewText?: string): Promise<SaveSlot>;
31
- loadSlot(slotId: string): Promise<SaveSlot | null>;
52
+ saveSlot(slotId: string, snapshot: Snapshot, previewText?: string, storyHash?: string, historyEntries?: readonly DialogueHistoryEntry[]): Promise<SaveSlot>;
53
+ loadSlot(slotId: string, expectedStoryHash?: string): Promise<LoadResult>;
32
54
  deleteSlot(slotId: string): Promise<void>;
33
- listSlots(totalSlots?: number): Promise<(SaveSlot | null)[]>;
55
+ listSlots(totalSlots?: number, expectedStoryHash?: string): Promise<(SaveSlot | null)[]>;
34
56
  }
57
+ /** @internal helper for tests */
58
+ export type { StoryState };
35
59
  //# sourceMappingURL=save.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,KAAK,CAA6B;IAEnC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAInC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIzC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAGrC;AAED,qBAAa,mBAAoB,YAAW,cAAc;IACjD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKnC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAIrC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAE3B,OAAO,CAAC,EAAE,cAAc,EAAE,aAAa,SAAkB;IAKxD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAcrF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAYlD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,SAAS,CAAC,UAAU,SAAI,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;CAQrE"}
1
+ {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"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"}
package/dist/save.js CHANGED
@@ -1,3 +1,106 @@
1
+ import { normalizeStoryState } from './state.js';
2
+ export const CURRENT_SAVE_SCHEMA_VERSION = 2;
3
+ export function fnv1a(str) {
4
+ let hash = 0x811c9dc5;
5
+ for (let i = 0; i < str.length; i++) {
6
+ hash ^= str.charCodeAt(i);
7
+ hash = Math.imul(hash, 0x01000193);
8
+ }
9
+ return (hash >>> 0).toString(16).padStart(8, '0');
10
+ }
11
+ export function computeStoryHash(story) {
12
+ const sortedLabels = Object.keys(story.labels ?? {}).sort();
13
+ const parts = [];
14
+ parts.push(`start:${story.meta?.startLabel ?? 'start'}`);
15
+ for (const label of sortedLabels) {
16
+ parts.push(`label:${label}`);
17
+ const instructions = story.labels[label] ?? [];
18
+ for (const inst of instructions) {
19
+ const { loc: _, ...rest } = inst;
20
+ parts.push(JSON.stringify(rest));
21
+ }
22
+ }
23
+ return fnv1a(parts.join('\n'));
24
+ }
25
+ function normalizeHistoryEntries(raw) {
26
+ if (!Array.isArray(raw))
27
+ return [];
28
+ const out = [];
29
+ for (const item of raw) {
30
+ if (!item || typeof item !== 'object')
31
+ continue;
32
+ const e = item;
33
+ if (typeof e['text'] !== 'string')
34
+ continue;
35
+ out.push({
36
+ id: typeof e['id'] === 'string' ? e['id'] : `hist_${out.length}`,
37
+ speaker: typeof e['speaker'] === 'string' ? e['speaker'] : undefined,
38
+ speakerDisplayName: typeof e['speakerDisplayName'] === 'string' ? e['speakerDisplayName'] : undefined,
39
+ text: e['text'],
40
+ timestamp: typeof e['timestamp'] === 'number' ? e['timestamp'] : 0
41
+ });
42
+ }
43
+ return out;
44
+ }
45
+ /** Explicit v1 → v2: add historyEntries (empty if missing). */
46
+ export function migrateSaveV1ToV2(slot) {
47
+ return {
48
+ ...slot,
49
+ schemaVersion: 2,
50
+ historyEntries: slot.historyEntries ? [...slot.historyEntries] : [],
51
+ snapshot: {
52
+ ...slot.snapshot,
53
+ historyLength: typeof slot.snapshot.historyLength === 'number'
54
+ ? slot.snapshot.historyLength
55
+ : (slot.historyEntries?.length ?? 0)
56
+ }
57
+ };
58
+ }
59
+ /**
60
+ * Migrate / normalize a parsed save slot to the current schema.
61
+ * Returns null if the slot cannot be recovered.
62
+ */
63
+ export function migrateSaveSlot(raw) {
64
+ if (!raw || typeof raw !== 'object')
65
+ return null;
66
+ const slot = raw;
67
+ const snapshotRaw = slot['snapshot'];
68
+ if (!snapshotRaw || typeof snapshotRaw !== 'object')
69
+ return null;
70
+ const snap = snapshotRaw;
71
+ const normalizedState = normalizeStoryState(snap['state']);
72
+ if (!normalizedState)
73
+ return null;
74
+ const id = typeof slot['id'] === 'string' ? slot['id'] : 'unknown';
75
+ const timestamp = typeof slot['timestamp'] === 'number' ? slot['timestamp'] : Date.now();
76
+ const rawVersion = typeof slot['schemaVersion'] === 'number' ? slot['schemaVersion'] : 1;
77
+ let migrated = {
78
+ schemaVersion: rawVersion,
79
+ storyHash: typeof slot['storyHash'] === 'string' ? slot['storyHash'] : undefined,
80
+ id,
81
+ name: typeof slot['name'] === 'string' ? slot['name'] : `Slot ${id}`,
82
+ timestamp,
83
+ snapshot: {
84
+ id: typeof snap['id'] === 'string' ? snap['id'] : `snap_${timestamp}`,
85
+ timestamp: typeof snap['timestamp'] === 'number' ? snap['timestamp'] : timestamp,
86
+ state: normalizedState,
87
+ historyLength: typeof snap['historyLength'] === 'number' ? snap['historyLength'] : undefined
88
+ },
89
+ previewText: typeof slot['previewText'] === 'string' ? slot['previewText'] : undefined,
90
+ screenshotUrl: typeof slot['screenshotUrl'] === 'string' ? slot['screenshotUrl'] : undefined,
91
+ historyEntries: normalizeHistoryEntries(slot['historyEntries'])
92
+ };
93
+ if (migrated.schemaVersion === undefined || migrated.schemaVersion < 2) {
94
+ migrated = migrateSaveV1ToV2(migrated);
95
+ }
96
+ else {
97
+ migrated = {
98
+ ...migrated,
99
+ schemaVersion: CURRENT_SAVE_SCHEMA_VERSION
100
+ };
101
+ }
102
+ return migrated;
103
+ }
1
104
  export class MemoryStorageAdapter {
2
105
  store = new Map();
3
106
  getItem(key) {
@@ -34,39 +137,57 @@ export class SaveManager {
34
137
  this.storage = storage ?? (typeof localStorage !== 'undefined' ? new LocalStorageAdapter() : new MemoryStorageAdapter());
35
138
  this.storagePrefix = storagePrefix;
36
139
  }
37
- async saveSlot(slotId, snapshot, previewText) {
140
+ async saveSlot(slotId, snapshot, previewText, storyHash = '', historyEntries = []) {
38
141
  const slot = {
142
+ schemaVersion: CURRENT_SAVE_SCHEMA_VERSION,
143
+ storyHash,
39
144
  id: slotId,
40
145
  name: `Slot ${slotId}`,
41
146
  timestamp: Date.now(),
42
147
  snapshot,
43
- previewText
148
+ previewText,
149
+ historyEntries: [...historyEntries]
44
150
  };
45
151
  const key = `${this.storagePrefix}${slotId}`;
46
152
  await this.storage.setItem(key, JSON.stringify(slot));
47
153
  return slot;
48
154
  }
49
- async loadSlot(slotId) {
155
+ async loadSlot(slotId, expectedStoryHash) {
50
156
  const key = `${this.storagePrefix}${slotId}`;
51
157
  const raw = await this.storage.getItem(key);
52
158
  if (!raw)
53
- return null;
159
+ return { success: false, reason: 'not_found' };
54
160
  try {
55
- return JSON.parse(raw);
161
+ const parsed = JSON.parse(raw);
162
+ const slot = migrateSaveSlot(parsed);
163
+ if (!slot) {
164
+ return { success: false, reason: 'corrupt' };
165
+ }
166
+ const rawObj = parsed;
167
+ if (typeof rawObj['schemaVersion'] === 'number' && rawObj['schemaVersion'] > CURRENT_SAVE_SCHEMA_VERSION) {
168
+ return { success: false, reason: 'incompatible_schema', slot };
169
+ }
170
+ // When a story hash is expected, require a matching hash (reject missing hashes).
171
+ if (expectedStoryHash) {
172
+ if (!slot.storyHash || slot.storyHash !== expectedStoryHash) {
173
+ return { success: false, reason: 'incompatible_story', slot };
174
+ }
175
+ }
176
+ return { success: true, slot };
56
177
  }
57
178
  catch {
58
- return null;
179
+ return { success: false, reason: 'corrupt' };
59
180
  }
60
181
  }
61
182
  async deleteSlot(slotId) {
62
183
  const key = `${this.storagePrefix}${slotId}`;
63
184
  await this.storage.removeItem(key);
64
185
  }
65
- async listSlots(totalSlots = 6) {
186
+ async listSlots(totalSlots = 6, expectedStoryHash) {
66
187
  const slots = [];
67
188
  for (let i = 1; i <= totalSlots; i++) {
68
- const slot = await this.loadSlot(String(i));
69
- slots.push(slot);
189
+ const res = await this.loadSlot(String(i), expectedStoryHash);
190
+ slots.push(res.success && res.slot ? res.slot : null);
70
191
  }
71
192
  return slots;
72
193
  }
package/dist/save.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"save.js","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"save.js","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"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"}
package/dist/state.d.ts CHANGED
@@ -1,7 +1,22 @@
1
- import type { ChoiceOption } from '@kawaijs/ast';
1
+ import type { ChoiceOption, HotspotOption } from '@kawaijs/ast';
2
2
  export interface CharacterState {
3
3
  readonly expression?: string;
4
4
  readonly position?: string;
5
+ readonly transition?: string;
6
+ readonly layer?: string;
7
+ readonly z?: number;
8
+ readonly cssAnimation?: {
9
+ readonly name: string;
10
+ readonly durationMs?: number;
11
+ /** Bumps so the same animation can re-trigger. */
12
+ readonly token?: number;
13
+ };
14
+ }
15
+ export interface AchievementState {
16
+ readonly id: string;
17
+ readonly title?: string;
18
+ readonly description?: string;
19
+ readonly unlockedAt: number;
5
20
  }
6
21
  export interface DialogueState {
7
22
  readonly speaker?: string;
@@ -9,10 +24,19 @@ export interface DialogueState {
9
24
  readonly speakerColor?: string;
10
25
  readonly text: string;
11
26
  }
27
+ export interface VfxState {
28
+ readonly effect: 'rain' | 'snow' | 'sakura' | 'fog' | 'tint' | 'stop';
29
+ readonly intensity?: number | string;
30
+ readonly color?: string;
31
+ }
12
32
  export interface VisualState {
13
33
  readonly background: string | null;
14
34
  readonly transition: string | null;
15
35
  readonly characters: Record<string, CharacterState>;
36
+ readonly vfx: VfxState | null;
37
+ readonly activeCG: string | null;
38
+ /** Default layer name applied to subsequent shows without an explicit layer. */
39
+ readonly defaultLayer: string | null;
16
40
  }
17
41
  export interface AudioState {
18
42
  readonly music: string | null;
@@ -31,6 +55,29 @@ export interface StoryState {
31
55
  readonly audio: AudioState;
32
56
  readonly dialogue: DialogueState | null;
33
57
  readonly choices: readonly ChoiceOption[] | null;
58
+ /** Clickable stage/CG regions waiting for a player pick. */
59
+ readonly hotspots: readonly HotspotOption[] | null;
60
+ /** CSS theme token applied on the player root (`data-kawa-theme`). */
61
+ readonly theme: string | null;
62
+ /** Named style tokens keyed by UI target (dialogue, stage, root, choices). */
63
+ readonly styleClasses: Readonly<Record<string, string>>;
64
+ readonly unlockedCGs: Record<string, boolean>;
65
+ /** Unlocked achievements / exportable flags. */
66
+ readonly achievements: Readonly<Record<string, AchievementState>>;
67
+ /** Active language code for `{t:key}` string tables. */
68
+ readonly lang: string | null;
69
+ /**
70
+ * When set, the presentation layer should auto-advance after this many ms.
71
+ * Click/keyboard advance may skip the remaining delay.
72
+ */
73
+ readonly pendingPauseMs: number | null;
74
+ /** Text prompt waiting for the player (`input` directive). */
75
+ readonly pendingInput: {
76
+ readonly variable: string;
77
+ readonly prompt: string;
78
+ } | null;
79
+ /** When false, the dialogue window should be hidden (`window hide`). */
80
+ readonly windowVisible: boolean;
34
81
  readonly isWaitingForInput: boolean;
35
82
  readonly isFinished: boolean;
36
83
  }
@@ -38,7 +85,14 @@ export interface Snapshot {
38
85
  readonly id: string;
39
86
  readonly timestamp: number;
40
87
  readonly state: StoryState;
88
+ /** Dialogue history length at snapshot time — used to trim backlog on rollback. */
89
+ readonly historyLength?: number;
41
90
  }
42
91
  export declare function createInitialState(startLabel?: string): StoryState;
92
+ /**
93
+ * Normalize a partially-shaped / older save state into a full StoryState.
94
+ * Returns null when the payload is too corrupt to recover.
95
+ */
96
+ export declare function normalizeStoryState(raw: unknown): StoryState | null;
43
97
  export declare function cloneState(state: StoryState): StoryState;
44
98
  //# sourceMappingURL=state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,wBAAgB,kBAAkB,CAAC,UAAU,SAAU,GAAG,UAAU,CAoBnE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAmBxD"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,YAAY,CAAC,EAAE;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC7B,kDAAkD;QAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gFAAgF;IAChF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAAC;IACjD,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAAC;IACnD,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAClE,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACrF,wEAAwE;IACxE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,kBAAkB,CAAC,UAAU,SAAU,GAAG,UAAU,CAgCnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAgFnE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAqCxD"}
package/dist/state.js CHANGED
@@ -3,11 +3,14 @@ export function createInitialState(startLabel = 'start') {
3
3
  currentLabel: startLabel,
4
4
  instructionPointer: 0,
5
5
  callStack: [],
6
- variables: {},
6
+ variables: Object.create(null),
7
7
  visual: {
8
8
  background: null,
9
9
  transition: null,
10
- characters: {}
10
+ characters: {},
11
+ vfx: null,
12
+ activeCG: null,
13
+ defaultLayer: null
11
14
  },
12
15
  audio: {
13
16
  music: null,
@@ -15,24 +18,126 @@ export function createInitialState(startLabel = 'start') {
15
18
  },
16
19
  dialogue: null,
17
20
  choices: null,
21
+ hotspots: null,
22
+ theme: null,
23
+ styleClasses: Object.create(null),
24
+ unlockedCGs: Object.create(null),
25
+ achievements: Object.create(null),
26
+ lang: null,
27
+ pendingPauseMs: null,
28
+ pendingInput: null,
29
+ windowVisible: true,
18
30
  isWaitingForInput: false,
19
31
  isFinished: false
20
32
  };
21
33
  }
34
+ /**
35
+ * Normalize a partially-shaped / older save state into a full StoryState.
36
+ * Returns null when the payload is too corrupt to recover.
37
+ */
38
+ export function normalizeStoryState(raw) {
39
+ if (!raw || typeof raw !== 'object')
40
+ return null;
41
+ const s = raw;
42
+ if (typeof s['currentLabel'] !== 'string' || typeof s['instructionPointer'] !== 'number') {
43
+ return null;
44
+ }
45
+ const base = createInitialState(s['currentLabel']);
46
+ const visualRaw = (s['visual'] && typeof s['visual'] === 'object' ? s['visual'] : {});
47
+ const audioRaw = (s['audio'] && typeof s['audio'] === 'object' ? s['audio'] : {});
48
+ const dialogueRaw = s['dialogue'] && typeof s['dialogue'] === 'object' ? s['dialogue'] : null;
49
+ const callStack = Array.isArray(s['callStack'])
50
+ ? s['callStack']
51
+ .filter((f) => !!f && typeof f === 'object')
52
+ .map(f => ({
53
+ returnLabel: typeof f['returnLabel'] === 'string' ? f['returnLabel'] : base.currentLabel,
54
+ returnPointer: typeof f['returnPointer'] === 'number' ? f['returnPointer'] : 0
55
+ }))
56
+ : [];
57
+ const charactersRaw = visualRaw['characters'] && typeof visualRaw['characters'] === 'object'
58
+ ? visualRaw['characters']
59
+ : {};
60
+ return {
61
+ currentLabel: s['currentLabel'],
62
+ instructionPointer: s['instructionPointer'],
63
+ callStack,
64
+ variables: s['variables'] && typeof s['variables'] === 'object'
65
+ ? Object.assign(Object.create(null), s['variables'])
66
+ : Object.create(null),
67
+ visual: {
68
+ background: typeof visualRaw['background'] === 'string' ? visualRaw['background'] : null,
69
+ transition: typeof visualRaw['transition'] === 'string' ? visualRaw['transition'] : null,
70
+ characters: { ...charactersRaw },
71
+ vfx: visualRaw['vfx'] ?? null,
72
+ activeCG: typeof visualRaw['activeCG'] === 'string' ? visualRaw['activeCG'] : null,
73
+ defaultLayer: typeof visualRaw['defaultLayer'] === 'string' ? visualRaw['defaultLayer'] : null
74
+ },
75
+ audio: {
76
+ music: typeof audioRaw['music'] === 'string' ? audioRaw['music'] : null,
77
+ voice: typeof audioRaw['voice'] === 'string' ? audioRaw['voice'] : null
78
+ },
79
+ dialogue: dialogueRaw && typeof dialogueRaw['text'] === 'string'
80
+ ? {
81
+ speaker: typeof dialogueRaw['speaker'] === 'string' ? dialogueRaw['speaker'] : undefined,
82
+ speakerDisplayName: typeof dialogueRaw['speakerDisplayName'] === 'string'
83
+ ? dialogueRaw['speakerDisplayName']
84
+ : undefined,
85
+ speakerColor: typeof dialogueRaw['speakerColor'] === 'string' ? dialogueRaw['speakerColor'] : undefined,
86
+ text: dialogueRaw['text']
87
+ }
88
+ : null,
89
+ choices: Array.isArray(s['choices']) ? s['choices'] : null,
90
+ hotspots: null, // never restore mid-hotspot from saves
91
+ theme: typeof s['theme'] === 'string' ? s['theme'] : null,
92
+ styleClasses: s['styleClasses'] && typeof s['styleClasses'] === 'object'
93
+ ? Object.assign(Object.create(null), s['styleClasses'])
94
+ : Object.create(null),
95
+ unlockedCGs: s['unlockedCGs'] && typeof s['unlockedCGs'] === 'object'
96
+ ? Object.assign(Object.create(null), s['unlockedCGs'])
97
+ : Object.create(null),
98
+ achievements: s['achievements'] && typeof s['achievements'] === 'object'
99
+ ? Object.assign(Object.create(null), s['achievements'])
100
+ : Object.create(null),
101
+ lang: typeof s['lang'] === 'string' ? s['lang'] : null,
102
+ pendingPauseMs: typeof s['pendingPauseMs'] === 'number' ? s['pendingPauseMs'] : null,
103
+ pendingInput: null, // never restore mid-prompt from saves
104
+ windowVisible: s['windowVisible'] === false ? false : true,
105
+ isWaitingForInput: Boolean(s['isWaitingForInput']),
106
+ isFinished: Boolean(s['isFinished'])
107
+ };
108
+ }
22
109
  export function cloneState(state) {
23
110
  return {
24
111
  currentLabel: state.currentLabel,
25
112
  instructionPointer: state.instructionPointer,
26
113
  callStack: state.callStack.map(frame => ({ ...frame })),
27
- variables: { ...state.variables },
114
+ variables: Object.assign(Object.create(null), state.variables),
28
115
  visual: {
29
116
  background: state.visual.background,
30
117
  transition: state.visual.transition,
31
- characters: Object.fromEntries(Object.entries(state.visual.characters).map(([k, v]) => [k, { ...v }]))
118
+ vfx: state.visual.vfx ? { ...state.visual.vfx } : null,
119
+ activeCG: state.visual.activeCG,
120
+ defaultLayer: state.visual.defaultLayer,
121
+ characters: Object.fromEntries(Object.entries(state.visual.characters).map(([k, v]) => [
122
+ k,
123
+ {
124
+ ...v,
125
+ cssAnimation: v.cssAnimation ? { ...v.cssAnimation } : undefined
126
+ }
127
+ ]))
32
128
  },
33
129
  audio: { ...state.audio },
34
130
  dialogue: state.dialogue ? { ...state.dialogue } : null,
35
131
  choices: state.choices ? state.choices.map(c => ({ ...c })) : null,
132
+ hotspots: state.hotspots ? state.hotspots.map(h => ({ ...h })) : null,
133
+ theme: state.theme,
134
+ styleClasses: Object.assign(Object.create(null), state.styleClasses),
135
+ unlockedCGs: Object.assign(Object.create(null), state.unlockedCGs),
136
+ achievements: Object.assign(Object.create(null), state.achievements),
137
+ lang: state.lang,
138
+ pendingPauseMs: state.pendingPauseMs ?? null,
139
+ pendingInput: state.pendingInput ? { ...state.pendingInput } : null,
140
+ windowVisible: state.windowVisible !== false,
36
141
  isWaitingForInput: state.isWaitingForInput,
37
142
  isFinished: state.isFinished
38
143
  };
package/dist/state.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAiDA,MAAM,UAAU,kBAAkB,CAAC,UAAU,GAAG,OAAO;IACrD,OAAO;QACL,YAAY,EAAE,UAAU;QACxB,kBAAkB,EAAE,CAAC;QACrB,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,MAAM,EAAE;YACN,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,EAAE;SACf;QACD,KAAK,EAAE;YACL,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI;SACZ;QACD,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,IAAI;QACb,iBAAiB,EAAE,KAAK;QACxB,UAAU,EAAE,KAAK;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,kBAAkB,EAAE,KAAK,CAAC,kBAAkB;QAC5C,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QACvD,SAAS,EAAE,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE;QACjC,MAAM,EAAE;YACN,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;YACnC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;YACnC,UAAU,EAAE,MAAM,CAAC,WAAW,CAC5B,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CACvE;SACF;QACD,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE;QACzB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI;QACvD,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;QAClE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
package/dist/vm.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { StoryPackage } from '@kawaijs/ast';
2
- import { type StoryState } from './state.js';
2
+ import { type AchievementState, type StoryState } from './state.js';
3
3
  import { HistoryManager } from './history.js';
4
- import { SaveManager } from './save.js';
4
+ import { SaveManager, type SaveSlot, type LoadResult } from './save.js';
5
5
  export interface AudioEvent {
6
6
  readonly action: 'play' | 'stop';
7
7
  readonly channel: 'music' | 'sound' | 'voice';
@@ -9,32 +9,74 @@ export interface AudioEvent {
9
9
  readonly fade?: number;
10
10
  readonly loop?: boolean;
11
11
  }
12
+ export interface CameraEvent {
13
+ readonly action: 'shake' | 'vpunch' | 'hpunch' | 'flash';
14
+ readonly duration?: number;
15
+ }
12
16
  export type StateChangeListener = (state: StoryState) => void;
13
17
  export type AudioEventListener = (event: AudioEvent) => void;
18
+ export type CameraEventListener = (event: CameraEvent) => void;
19
+ export type TickListener = (deltaMs: number, totalTimeMs: number) => void;
20
+ export type ErrorListener = (error: Error) => void;
21
+ export interface VMOptions {
22
+ readonly saveManager?: SaveManager;
23
+ readonly maxSnapshots?: number;
24
+ readonly maxCallDepth?: number;
25
+ /** Hard cap on instructions executed in a single burst (prevents infinite jump loops). */
26
+ readonly maxInstructionsPerBurst?: number;
27
+ }
14
28
  export declare class StoryVM {
29
+ readonly storyHash: string;
15
30
  private readonly story;
16
31
  private state;
17
32
  private snapshotStack;
18
33
  private readonly historyManager;
19
34
  private readonly saveManager;
35
+ private readonly maxSnapshots;
36
+ private readonly maxCallDepth;
37
+ private readonly maxInstructionsPerBurst;
20
38
  private stateChangeListeners;
21
39
  private audioEventListeners;
40
+ private cameraEventListeners;
41
+ private errorListeners;
42
+ private tickListeners;
43
+ private executionTrace;
44
+ private virtualTimeMs;
22
45
  private isExecuting;
23
- constructor(story: StoryPackage, saveManager?: SaveManager);
46
+ constructor(story: StoryPackage, saveManagerOrOptions?: SaveManager | VMOptions);
24
47
  getState(): StoryState;
48
+ getStory(): StoryPackage;
25
49
  getHistoryManager(): HistoryManager;
26
50
  getSaveManager(): SaveManager;
51
+ getExecutionTrace(): readonly string[];
52
+ clearExecutionTrace(): void;
53
+ private recordTrace;
54
+ getVirtualTime(): number;
55
+ tick(deltaMs: number): void;
56
+ onTick(listener: TickListener): () => void;
27
57
  onStateChange(listener: StateChangeListener): () => void;
28
58
  onAudioEvent(listener: AudioEventListener): () => void;
29
- start(): void;
59
+ onCameraEvent(listener: CameraEventListener): () => void;
60
+ onError(listener: ErrorListener): () => void;
61
+ private emitCameraEvent;
62
+ private emitError;
63
+ start(atLabel?: string): void;
30
64
  /**
31
65
  * Advances the story to the next dialogue, choice, or scene event.
32
66
  */
33
67
  next(): void;
68
+ /**
69
+ * Completes a pending `input` prompt and continues the story.
70
+ */
71
+ submitInput(value: string): void;
34
72
  /**
35
73
  * Selects an option from the current choice menu.
36
74
  */
37
75
  choose(choiceIndex: number): void;
76
+ /**
77
+ * Selects a clickable hotspot and jumps to its target label.
78
+ */
79
+ selectHotspot(id: string): void;
38
80
  /**
39
81
  * Jumps directly to a label.
40
82
  */
@@ -44,13 +86,36 @@ export declare class StoryVM {
44
86
  */
45
87
  rollback(): boolean;
46
88
  canRollback(): boolean;
47
- save(slotId: string): Promise<void>;
48
- load(slotId: string): Promise<boolean>;
89
+ save(slotId: string): Promise<SaveSlot>;
90
+ load(slotId: string, validateStoryHash?: boolean): Promise<boolean>;
91
+ loadWithDetails(slotId: string, validateStoryHash?: boolean): Promise<LoadResult>;
92
+ /**
93
+ * Restore from an in-memory SaveSlot (continue-links, imported saves).
94
+ * Validates storyHash when present on the slot.
95
+ */
96
+ loadFromSlot(slot: SaveSlot, validateStoryHash?: boolean): LoadResult;
97
+ private applyLoadedSlot;
98
+ /**
99
+ * Emit stop/play audio events so the presentation layer matches restored state
100
+ * after load or rollback (snapshots store track ids but not live Audio elements).
101
+ */
102
+ private resyncAudio;
49
103
  private executeUntilWaiting;
50
104
  private executeInstruction;
51
105
  private captureSnapshot;
52
106
  private recordSnapshot;
53
107
  private notifyStateChanged;
54
108
  private emitAudioEvent;
109
+ private persistAchievement;
110
+ /** Merge locally persisted achievements into the current state (call after start/load). */
111
+ hydrateAchievements(): void;
112
+ /** Export achievements as a plain JSON-serializable object (itch / analytics). */
113
+ exportAchievementsJson(): {
114
+ storyHash: string;
115
+ exportedAt: number;
116
+ achievements: AchievementState[];
117
+ };
118
+ /** Set active language for `{t:key}` lookups (also used by `?lang=`). */
119
+ setLang(code: string): void;
55
120
  }
56
121
  //# sourceMappingURL=vm.d.ts.map