@kids-games/core
v1.0.0
Published
Shared framework for Kids Corner games — voice personas, audio playback, celebrations, UI components, and design tokens
Readme
@kids-games/core
Shared framework for Kids Corner educational games (ages 2-6). Provides voice personas with pre-generated TTS audio, sound effects, celebration animations, reusable React components, and design tokens.
Installation
npm install @kids-games/corePeer dependencies (install if not already present):
npm install react@^19 react-dom@^19Modules
The package is split into five independently importable modules:
| Module | Import | Description |
|--------|--------|-------------|
| Voice | @kids-games/core/voice | Persona system, audio playback, React provider & hooks |
| SFX | @kids-games/core/sfx | Synthesized sound effects via Web Audio API |
| Celebrations | @kids-games/core/celebrations | Confetti particle system with physics |
| Components | @kids-games/core/components | Ready-to-use React UI components |
| Tokens | @kids-games/core/tokens | Design tokens (colors, spacing, touch targets) |
Voice
Five kid-friendly personas, each mapped to an OpenAI TTS voice with a Web Speech API fallback:
| Persona | Voice | Character | |---------|-------|-----------| | Sunny | shimmer | Warm, encouraging guide | | Bloop | fable | Silly, playful buddy | | Maple | nova | Calm, nurturing mentor | | Fizz | echo | Energetic, excited hype | | Pip | alloy | Gentle, curious explorer |
Provider setup
Wrap your app (or game layout) with KidsAudioProvider:
import { KidsAudioProvider } from "@kids-games/core/voice";
export default function Layout({ children }) {
return (
<KidsAudioProvider storagePrefix="color-mixer" audioBasePath="/audio">
{children}
</KidsAudioProvider>
);
}Hooks
import { useVoice, usePersona, useSoundEffects, useCelebrate } from "@kids-games/core/voice";
function GameScreen() {
const { playPhrase, muted, toggleMute } = useVoice();
const persona = usePersona("sunny");
const { playCorrect, playIncorrect } = useSoundEffects();
const celebrate = useCelebrate("sunny");
const handleAnswer = (correct: boolean) => {
if (correct) {
playCorrect();
celebrate("big");
playPhrase("well-done", "sunny");
} else {
playIncorrect();
playPhrase("try-again", "sunny");
}
};
return <button onClick={() => handleAnswer(true)}>Answer</button>;
}Persona data
import { PERSONAS, getPersona, getRandomPhrase } from "@kids-games/core/voice";
const sunny = getPersona("sunny");
// { name: "Sunny", openaiVoice: "shimmer", ... }
const phrase = getRandomPhrase("sunny", "celebration");
// Random celebration phrase from Sunny's poolSFX
Synthesized sound effects using the Web Audio API. No audio files needed.
import { playTap, playPop, playCorrect, playIncorrect, playWhoosh, playCelebrationChime } from "@kids-games/core/sfx";
// All functions take an AudioContext
const ctx = new AudioContext();
playTap(ctx);
playPop(ctx);
playCorrect(ctx);
playIncorrect(ctx);
playWhoosh(ctx);
playCelebrationChime(ctx);When using with the voice module, get the context from the provider:
const { getContext } = useVoice();
playTap(getContext());Celebrations
Confetti particle system with three intensity levels.
import { createConfettiBurst, tickConfetti } from "@kids-games/core/celebrations";
import { CELEBRATION_CONFIGS } from "@kids-games/core/celebrations";
import type { CelebrationLevel } from "@kids-games/core/components";
// Create particles
const config = CELEBRATION_CONFIGS["big"]; // small | medium | big
let particles = createConfettiBurst(config.particleCount);
// Animation loop
function animate() {
particles = tickConfetti(particles);
// render particles...
if (particles.length > 0) requestAnimationFrame(animate);
}
animate();Or use the ready-made component (see Components below).
Components
CelebrationOverlay
Full-screen confetti overlay with auto-dismiss.
import { CelebrationOverlay } from "@kids-games/core/components";
<CelebrationOverlay
level="big" // "small" | "medium" | "big" | null
text="Great job!" // optional overlay text
onComplete={() => setLevel(null)}
/>MuteButton
Floating mute/unmute toggle. Requires KidsAudioProvider as an ancestor.
import { MuteButton } from "@kids-games/core/components";
<MuteButton size={48} className="custom-class" />PersonaPicker
Tappable persona cards with localStorage persistence.
import { PersonaPicker } from "@kids-games/core/components";
<PersonaPicker
availablePersonas={["sunny", "bloop", "maple"]}
onSelect={(id) => setActivePersona(id)}
storageKey="my-game-persona"
/>Tokens
Design tokens optimized for children ages 2-6.
Colors
import { COLORS } from "@kids-games/core/tokens";
COLORS.primary.red // "#FF6B6B"
COLORS.background.warm // "#FFF8E7"
COLORS.feedback.success // "#4CAF50"
COLORS.persona.sunny // "#FFD93D"Spacing
import { SPACING } from "@kids-games/core/tokens";
SPACING.touchTarget.min // 48 (WCAG minimum)
SPACING.touchTarget.recommended // 56 (toddler-friendly)
SPACING.touchTarget.large // 64 (primary actions)
SPACING.padding.md // 16
SPACING.gap.comfortable // 16
SPACING.radius.lg // 16
SPACING.fontSize.lg // 24Generating Voice Audio
Each game defines its dialogue in a voice-script.json file. The generation script converts these to MP3 files using the OpenAI TTS API.
1. Create a voice script
{
"lines": [
{ "id": "welcome", "text": "Welcome to Color Mixer!", "persona": "sunny" },
{ "id": "try-again", "text": "Oops, let's try that again!", "persona": "bloop" },
{ "id": "well-done", "text": "Amazing job, you did it!", "persona": "sunny" }
]
}Save this as voice-script.json in your game's root directory.
2. Generate audio files
OPENAI_API_KEY=sk-... npx tsx node_modules/@kids-games/core/scripts/generate-audio.ts ./Or from the monorepo root:
OPENAI_API_KEY=sk-... npx tsx _core/scripts/generate-audio.ts ./my-game/This creates public/audio/<persona>/<id>.mp3 files. Use --force to regenerate existing files.
3. Reference in your provider
<KidsAudioProvider storagePrefix="my-game" audioBasePath="/audio">The player resolves audio as {audioBasePath}/{persona}/{phraseId}.mp3.
TypeScript
All exports are fully typed. Key types:
import type {
PersonaId, // "sunny" | "bloop" | "maple" | "fizz" | "pip"
Persona, // Full persona config object
CelebrationLevel // "small" | "medium" | "big"
} from "@kids-games/core/voice";