@kids-games/core 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.
Files changed (73) hide show
  1. package/dist/celebrations/confetti.d.ts +18 -0
  2. package/dist/celebrations/confetti.d.ts.map +1 -0
  3. package/dist/celebrations/confetti.js +35 -0
  4. package/dist/celebrations/confetti.js.map +1 -0
  5. package/dist/celebrations/index.d.ts +3 -0
  6. package/dist/celebrations/index.d.ts.map +1 -0
  7. package/dist/celebrations/index.js +3 -0
  8. package/dist/celebrations/index.js.map +1 -0
  9. package/dist/celebrations/types.d.ts +13 -0
  10. package/dist/celebrations/types.d.ts.map +1 -0
  11. package/dist/celebrations/types.js +21 -0
  12. package/dist/celebrations/types.js.map +1 -0
  13. package/dist/components/CelebrationOverlay.d.ts +20 -0
  14. package/dist/components/CelebrationOverlay.d.ts.map +1 -0
  15. package/dist/components/CelebrationOverlay.js +92 -0
  16. package/dist/components/CelebrationOverlay.js.map +1 -0
  17. package/dist/components/MuteButton.d.ts +14 -0
  18. package/dist/components/MuteButton.d.ts.map +1 -0
  19. package/dist/components/MuteButton.js +16 -0
  20. package/dist/components/MuteButton.js.map +1 -0
  21. package/dist/components/PersonaPicker.d.ts +17 -0
  22. package/dist/components/PersonaPicker.d.ts.map +1 -0
  23. package/dist/components/PersonaPicker.js +62 -0
  24. package/dist/components/PersonaPicker.js.map +1 -0
  25. package/dist/components/index.d.ts +4 -0
  26. package/dist/components/index.d.ts.map +1 -0
  27. package/dist/components/index.js +4 -0
  28. package/dist/components/index.js.map +1 -0
  29. package/dist/sfx/index.d.ts +2 -0
  30. package/dist/sfx/index.d.ts.map +1 -0
  31. package/dist/sfx/index.js +2 -0
  32. package/dist/sfx/index.js.map +1 -0
  33. package/dist/sfx/synth.d.ts +18 -0
  34. package/dist/sfx/synth.d.ts.map +1 -0
  35. package/dist/sfx/synth.js +97 -0
  36. package/dist/sfx/synth.js.map +1 -0
  37. package/dist/tokens/colors.d.ts +51 -0
  38. package/dist/tokens/colors.d.ts.map +1 -0
  39. package/dist/tokens/colors.js +51 -0
  40. package/dist/tokens/colors.js.map +1 -0
  41. package/dist/tokens/index.d.ts +3 -0
  42. package/dist/tokens/index.d.ts.map +1 -0
  43. package/dist/tokens/index.js +3 -0
  44. package/dist/tokens/index.js.map +1 -0
  45. package/dist/tokens/spacing.d.ts +55 -0
  46. package/dist/tokens/spacing.d.ts.map +1 -0
  47. package/dist/tokens/spacing.js +55 -0
  48. package/dist/tokens/spacing.js.map +1 -0
  49. package/dist/voice/hooks.d.ts +52 -0
  50. package/dist/voice/hooks.d.ts.map +1 -0
  51. package/dist/voice/hooks.js +91 -0
  52. package/dist/voice/hooks.js.map +1 -0
  53. package/dist/voice/index.d.ts +6 -0
  54. package/dist/voice/index.d.ts.map +1 -0
  55. package/dist/voice/index.js +5 -0
  56. package/dist/voice/index.js.map +1 -0
  57. package/dist/voice/personas.d.ts +7 -0
  58. package/dist/voice/personas.d.ts.map +1 -0
  59. package/dist/voice/personas.js +143 -0
  60. package/dist/voice/personas.js.map +1 -0
  61. package/dist/voice/player.d.ts +54 -0
  62. package/dist/voice/player.d.ts.map +1 -0
  63. package/dist/voice/player.js +224 -0
  64. package/dist/voice/player.js.map +1 -0
  65. package/dist/voice/provider.d.ts +35 -0
  66. package/dist/voice/provider.d.ts.map +1 -0
  67. package/dist/voice/provider.js +82 -0
  68. package/dist/voice/provider.js.map +1 -0
  69. package/dist/voice/types.d.ts +52 -0
  70. package/dist/voice/types.d.ts.map +1 -0
  71. package/dist/voice/types.js +2 -0
  72. package/dist/voice/types.js.map +1 -0
  73. package/package.json +51 -0
@@ -0,0 +1,224 @@
1
+ "use client";
2
+ import { PERSONAS } from "./personas";
3
+ /**
4
+ * AudioPlayer — plays pre-generated .mp3 files from public/audio/.
5
+ * No runtime API calls. All audio is static files served by the app.
6
+ */
7
+ export class AudioPlayer {
8
+ audioElement = null;
9
+ audioContext = null;
10
+ muted = false;
11
+ volume = 1.0;
12
+ cancelFlag = false;
13
+ audioBasePath;
14
+ storagePrefix;
15
+ unlocked = false;
16
+ cachedVoices = [];
17
+ constructor(storagePrefix, audioBasePath) {
18
+ this.storagePrefix = storagePrefix;
19
+ this.audioBasePath = audioBasePath;
20
+ if (typeof window !== "undefined") {
21
+ this.muted = localStorage.getItem(`${storagePrefix}-muted`) === "true";
22
+ const savedVolume = localStorage.getItem(`${storagePrefix}-volume`);
23
+ if (savedVolume)
24
+ this.volume = parseFloat(savedVolume);
25
+ // Pre-cache voices for Chrome (fires async) and other browsers
26
+ if (window.speechSynthesis) {
27
+ this.cachedVoices = window.speechSynthesis.getVoices();
28
+ window.speechSynthesis.addEventListener("voiceschanged", () => {
29
+ this.cachedVoices = window.speechSynthesis.getVoices();
30
+ });
31
+ }
32
+ }
33
+ }
34
+ /** Must be called from a user interaction to unlock audio on mobile browsers */
35
+ unlock() {
36
+ if (this.unlocked)
37
+ return;
38
+ try {
39
+ // Create and resume AudioContext to unlock Web Audio
40
+ const ctx = this.getAudioContext();
41
+ if (ctx.state === "suspended") {
42
+ ctx.resume();
43
+ }
44
+ // Create a silent audio element to unlock HTMLAudioElement playback
45
+ const el = this.getAudioElement();
46
+ el.src = "data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA//tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAACAAABhgC7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7//////////////////////////////////////////////////////////////////8AAAAATGF2YzU4LjEzAAAAAAAAAAAAAAAAJAAAAAAAAAAAAYYoRwMHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
47
+ el.play().catch(() => { });
48
+ el.pause();
49
+ this.unlocked = true;
50
+ }
51
+ catch {
52
+ // Silently fail — will retry on next interaction
53
+ }
54
+ }
55
+ getAudioElement() {
56
+ if (!this.audioElement) {
57
+ this.audioElement = new Audio();
58
+ this.audioElement.preload = "auto";
59
+ }
60
+ return this.audioElement;
61
+ }
62
+ getAudioContext() {
63
+ if (!this.audioContext) {
64
+ this.audioContext = new (window.AudioContext ||
65
+ window.webkitAudioContext)();
66
+ }
67
+ if (this.audioContext.state === "suspended") {
68
+ this.audioContext.resume();
69
+ }
70
+ return this.audioContext;
71
+ }
72
+ /** Get the Web Audio context for SFX synthesis */
73
+ getContext() {
74
+ return this.getAudioContext();
75
+ }
76
+ /**
77
+ * Play a pre-generated phrase by ID.
78
+ * Resolves to the audio file at: {audioBasePath}/{personaId}/{phraseId}.mp3
79
+ */
80
+ async playPhrase(phraseId, personaId) {
81
+ if (this.muted)
82
+ return;
83
+ this.cancelFlag = false;
84
+ const url = `${this.audioBasePath}/${personaId}/${phraseId}.mp3`;
85
+ return this.playAudioFile(url);
86
+ }
87
+ /**
88
+ * Play a sequence of phrases with pauses between them.
89
+ * Useful for Letter Land's "A... ah... Apple" pattern.
90
+ */
91
+ async playSequence(phrases, pauseMs = 400) {
92
+ this.cancelFlag = false;
93
+ for (let i = 0; i < phrases.length; i++) {
94
+ if (this.cancelFlag || this.muted)
95
+ break;
96
+ await this.playPhrase(phrases[i].id, phrases[i].persona);
97
+ if (i < phrases.length - 1 && !this.cancelFlag) {
98
+ await this.pause(pauseMs);
99
+ }
100
+ }
101
+ }
102
+ /** Play an audio file by URL */
103
+ playAudioFile(url) {
104
+ return new Promise((resolve) => {
105
+ if (this.muted || typeof window === "undefined") {
106
+ resolve();
107
+ return;
108
+ }
109
+ const audio = this.getAudioElement();
110
+ // Cancel any in-progress playback
111
+ audio.pause();
112
+ audio.currentTime = 0;
113
+ audio.src = url;
114
+ audio.volume = this.volume;
115
+ const cleanup = () => {
116
+ audio.removeEventListener("ended", onEnd);
117
+ audio.removeEventListener("error", onError);
118
+ };
119
+ const onEnd = () => {
120
+ cleanup();
121
+ resolve();
122
+ };
123
+ const onError = () => {
124
+ cleanup();
125
+ if (process.env.NODE_ENV !== "production") {
126
+ console.warn(`[kids-audio] Failed to play: ${url}`);
127
+ }
128
+ resolve();
129
+ };
130
+ audio.addEventListener("ended", onEnd);
131
+ audio.addEventListener("error", onError);
132
+ audio.play().catch(() => {
133
+ cleanup();
134
+ resolve();
135
+ });
136
+ });
137
+ }
138
+ /** Fallback: speak text using Web Speech API with persona voice settings */
139
+ async speakDynamic(text, personaId) {
140
+ if (this.muted || typeof window === "undefined" || !window.speechSynthesis) {
141
+ return;
142
+ }
143
+ const persona = PERSONAS[personaId];
144
+ return new Promise((resolve) => {
145
+ window.speechSynthesis.cancel();
146
+ const utterance = new SpeechSynthesisUtterance(text);
147
+ utterance.rate = persona.fallback.rate;
148
+ utterance.pitch = persona.fallback.pitch;
149
+ utterance.volume = this.volume;
150
+ // Use cached voices (handles Chrome's async voice loading)
151
+ const voices = this.cachedVoices.length > 0
152
+ ? this.cachedVoices
153
+ : window.speechSynthesis.getVoices();
154
+ if (persona.fallback.preferFemale) {
155
+ const preferred = voices.find((v) => v.lang.startsWith("en") && v.name.includes("Female")) ||
156
+ voices.find((v) => v.lang.startsWith("en"));
157
+ if (preferred)
158
+ utterance.voice = preferred;
159
+ }
160
+ else {
161
+ const preferred = voices.find((v) => v.lang.startsWith("en"));
162
+ if (preferred)
163
+ utterance.voice = preferred;
164
+ }
165
+ utterance.onend = () => resolve();
166
+ utterance.onerror = () => resolve();
167
+ window.speechSynthesis.speak(utterance);
168
+ });
169
+ }
170
+ /** Cancel any in-progress audio playback */
171
+ cancel() {
172
+ this.cancelFlag = true;
173
+ // Stop audio element
174
+ if (this.audioElement) {
175
+ this.audioElement.pause();
176
+ this.audioElement.currentTime = 0;
177
+ }
178
+ // Stop speech synthesis (for speakDynamic fallback)
179
+ if (typeof window !== "undefined" && window.speechSynthesis) {
180
+ window.speechSynthesis.cancel();
181
+ }
182
+ }
183
+ /** Set muted state */
184
+ setMuted(muted) {
185
+ this.muted = muted;
186
+ if (typeof window !== "undefined") {
187
+ localStorage.setItem(`${this.storagePrefix}-muted`, String(muted));
188
+ }
189
+ if (muted) {
190
+ this.cancel();
191
+ }
192
+ }
193
+ /** Get muted state */
194
+ isMuted() {
195
+ return this.muted;
196
+ }
197
+ /** Set volume (0.0 to 1.0) */
198
+ setVolume(vol) {
199
+ this.volume = Math.max(0, Math.min(1, vol));
200
+ if (typeof window !== "undefined") {
201
+ localStorage.setItem(`${this.storagePrefix}-volume`, String(this.volume));
202
+ }
203
+ if (this.audioElement) {
204
+ this.audioElement.volume = this.volume;
205
+ }
206
+ }
207
+ /** Get volume */
208
+ getVolume() {
209
+ return this.volume;
210
+ }
211
+ pause(ms) {
212
+ return new Promise((resolve) => setTimeout(resolve, ms));
213
+ }
214
+ /** Clean up resources */
215
+ destroy() {
216
+ this.cancel();
217
+ if (this.audioContext) {
218
+ this.audioContext.close();
219
+ this.audioContext = null;
220
+ }
221
+ this.audioElement = null;
222
+ }
223
+ }
224
+ //# sourceMappingURL=player.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player.js","sourceRoot":"","sources":["../../voice/player.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type ReactNode } from "react";
2
+ import { AudioPlayer } from "./player";
3
+ import type { PersonaId, AudioProviderConfig } from "./types";
4
+ export interface KidsAudioContextType {
5
+ /** Play a pre-generated phrase by ID */
6
+ playPhrase: (phraseId: string, personaId: PersonaId) => Promise<void>;
7
+ /** Play a sequence of phrases with pauses */
8
+ playSequence: (phrases: Array<{
9
+ id: string;
10
+ persona: PersonaId;
11
+ }>, pauseMs?: number) => Promise<void>;
12
+ /** Fallback: speak dynamic text via Web Speech API */
13
+ speakDynamic: (text: string, personaId: PersonaId) => Promise<void>;
14
+ /** Cancel all audio playback */
15
+ cancel: () => void;
16
+ /** Current mute state */
17
+ muted: boolean;
18
+ /** Toggle or set mute */
19
+ setMuted: (muted: boolean) => void;
20
+ /** Toggle mute */
21
+ toggleMute: () => void;
22
+ /** Current volume (0-1) */
23
+ volume: number;
24
+ /** Set volume (0-1) */
25
+ setVolume: (vol: number) => void;
26
+ /** Get the underlying AudioPlayer (for SFX access) */
27
+ player: AudioPlayer | null;
28
+ }
29
+ export declare const KidsAudioContext: import("react").Context<KidsAudioContextType>;
30
+ interface KidsAudioProviderProps extends AudioProviderConfig {
31
+ children: ReactNode;
32
+ }
33
+ export declare function KidsAudioProvider({ children, storagePrefix, audioBasePath, }: KidsAudioProviderProps): import("react/jsx-runtime").JSX.Element;
34
+ export {};
35
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../voice/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAoB,MAAM,SAAS,CAAC;AAGhF,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,6CAA6C;IAC7C,YAAY,EAAE,CACZ,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,SAAS,CAAA;KAAE,CAAC,EAClD,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,sDAAsD;IACtD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,gCAAgC;IAChC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,yBAAyB;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,yBAAyB;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,kBAAkB;IAClB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,sDAAsD;IACtD,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,+CAW3B,CAAC;AAEH,UAAU,sBAAuB,SAAQ,mBAAmB;IAC1D,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,aAAa,EACb,aAAa,GACd,EAAE,sBAAsB,2CA+FxB"}
@@ -0,0 +1,82 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useCallback, useEffect, useRef, useState, } from "react";
4
+ import { AudioPlayer } from "./player";
5
+ export const KidsAudioContext = createContext({
6
+ playPhrase: async () => { },
7
+ playSequence: async () => { },
8
+ speakDynamic: async () => { },
9
+ cancel: () => { },
10
+ muted: false,
11
+ setMuted: () => { },
12
+ toggleMute: () => { },
13
+ volume: 1,
14
+ setVolume: () => { },
15
+ player: null,
16
+ });
17
+ export function KidsAudioProvider({ children, storagePrefix, audioBasePath, }) {
18
+ const playerRef = useRef(null);
19
+ const [muted, setMutedState] = useState(false);
20
+ const [volume, setVolumeState] = useState(1);
21
+ // Initialize player
22
+ useEffect(() => {
23
+ const player = new AudioPlayer(storagePrefix, audioBasePath);
24
+ playerRef.current = player;
25
+ setMutedState(player.isMuted());
26
+ setVolumeState(player.getVolume());
27
+ return () => {
28
+ player.destroy();
29
+ playerRef.current = null;
30
+ };
31
+ }, [storagePrefix, audioBasePath]);
32
+ // Unlock audio on first user interaction
33
+ useEffect(() => {
34
+ const handleInteraction = () => {
35
+ playerRef.current?.unlock();
36
+ };
37
+ document.addEventListener("pointerdown", handleInteraction, { once: true });
38
+ document.addEventListener("keydown", handleInteraction, { once: true });
39
+ return () => {
40
+ document.removeEventListener("pointerdown", handleInteraction);
41
+ document.removeEventListener("keydown", handleInteraction);
42
+ };
43
+ }, []);
44
+ const playPhrase = useCallback(async (phraseId, personaId) => {
45
+ await playerRef.current?.playPhrase(phraseId, personaId);
46
+ }, []);
47
+ const playSequence = useCallback(async (phrases, pauseMs) => {
48
+ await playerRef.current?.playSequence(phrases, pauseMs);
49
+ }, []);
50
+ const speakDynamic = useCallback(async (text, personaId) => {
51
+ await playerRef.current?.speakDynamic(text, personaId);
52
+ }, []);
53
+ const cancel = useCallback(() => {
54
+ playerRef.current?.cancel();
55
+ }, []);
56
+ const setMuted = useCallback((value) => {
57
+ playerRef.current?.setMuted(value);
58
+ setMutedState(value);
59
+ }, []);
60
+ const toggleMute = useCallback(() => {
61
+ const next = !playerRef.current?.isMuted();
62
+ playerRef.current?.setMuted(next);
63
+ setMutedState(next);
64
+ }, []);
65
+ const setVolume = useCallback((vol) => {
66
+ playerRef.current?.setVolume(vol);
67
+ setVolumeState(vol);
68
+ }, []);
69
+ return (_jsx(KidsAudioContext.Provider, { value: {
70
+ playPhrase,
71
+ playSequence,
72
+ speakDynamic,
73
+ cancel,
74
+ muted,
75
+ setMuted,
76
+ toggleMute,
77
+ volume,
78
+ setVolume,
79
+ player: playerRef.current,
80
+ }, children: children }));
81
+ }
82
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../voice/provider.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /** OpenAI TTS voice identifiers */
2
+ export type OpenAIVoice = "shimmer" | "nova" | "fable" | "echo" | "alloy" | "onyx";
3
+ /** Persona identifiers */
4
+ export type PersonaId = "sunny" | "bloop" | "maple" | "fizz" | "pip";
5
+ /** Persona definition */
6
+ export interface Persona {
7
+ id: PersonaId;
8
+ name: string;
9
+ role: string;
10
+ description: string;
11
+ openaiVoice: OpenAIVoice;
12
+ speed: number;
13
+ /** Fallback settings for Web Speech API */
14
+ fallback: {
15
+ rate: number;
16
+ pitch: number;
17
+ preferFemale: boolean;
18
+ };
19
+ celebrationPhrases: string[];
20
+ encouragementPhrases: string[];
21
+ tryAgainPhrases: string[];
22
+ }
23
+ /** A single line in a game's voice script */
24
+ export interface VoiceScriptLine {
25
+ id: string;
26
+ text: string;
27
+ persona: PersonaId;
28
+ trigger: string;
29
+ }
30
+ /** A game's complete voice script */
31
+ export interface VoiceScript {
32
+ game: string;
33
+ personas: PersonaId[];
34
+ lines: VoiceScriptLine[];
35
+ }
36
+ /** Audio playback state */
37
+ export interface AudioState {
38
+ muted: boolean;
39
+ volume: number;
40
+ currentPersona: PersonaId | null;
41
+ isPlaying: boolean;
42
+ }
43
+ /** Configuration for the audio provider */
44
+ export interface AudioProviderConfig {
45
+ /** localStorage key prefix for this game (e.g., "count-along") */
46
+ storagePrefix: string;
47
+ /** Base path for audio files (e.g., "/audio" or "/count-along/audio") */
48
+ audioBasePath: string;
49
+ }
50
+ /** Celebration intensity levels */
51
+ export type CelebrationLevel = "small" | "medium" | "big";
52
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../voice/types.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEnF,0BAA0B;AAC1B,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAErE,yBAAyB;AACzB,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,mCAAmC;AACnC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../voice/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@kids-games/core",
3
+ "version": "0.1.0",
4
+ "description": "Shared framework for Kids Corner games — voice personas, audio playback, celebrations, UI components, and design tokens",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/mattatencio/kids-games-core"
10
+ },
11
+ "exports": {
12
+ "./voice": {
13
+ "types": "./dist/voice/index.d.ts",
14
+ "import": "./dist/voice/index.js"
15
+ },
16
+ "./sfx": {
17
+ "types": "./dist/sfx/index.d.ts",
18
+ "import": "./dist/sfx/index.js"
19
+ },
20
+ "./components": {
21
+ "types": "./dist/components/index.d.ts",
22
+ "import": "./dist/components/index.js"
23
+ },
24
+ "./celebrations": {
25
+ "types": "./dist/celebrations/index.d.ts",
26
+ "import": "./dist/celebrations/index.js"
27
+ },
28
+ "./tokens": {
29
+ "types": "./dist/tokens/index.d.ts",
30
+ "import": "./dist/tokens/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist/"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "prepublishOnly": "npm run build",
39
+ "generate-audio": "tsx scripts/generate-audio.ts"
40
+ },
41
+ "peerDependencies": {
42
+ "react": "^19.0.0",
43
+ "react-dom": "^19.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "openai": "^4.80.0",
47
+ "tsx": "^4.19.0",
48
+ "typescript": "^5.7.0",
49
+ "@types/react": "^19.0.0"
50
+ }
51
+ }