A turn-based roguelite word strategy game built with React, TypeScript, Tailwind CSS, and Framer Motion.
- 4x4 Word Grid: Trace paths orthogonally or diagonally to form words.
- Combat System: Damage based on base damage, word length, and chain multipliers.
- Sophisticated Dark Aesthetic: A premium, high-contrast dark theme with gold accents, serif typography, and cinematic layout.
- Roguelite Loop: Battle waves of enemies, earn gold and keys, and progress through stages.
- Dictionary System: Integrated word validation with a custom Trie-based dictionary.
- Strategic Elements: Energy management, charged tiles (from failed word attempts), and enemy intent telegraphing.
- Trace: Press and drag your finger/mouse across the letters on the grid to form a word.
- Review: Check the word builder at the bottom to see cost and potential damage.
- Confirm: Click confirm to execute the action.
- Survive: Defeat waves to earn rewards and advance.
- State Management: Zustand for global game state.
- UI/UX: Framer Motion for animations and high-contrast fantasy-themed UI.
- Validation: Trie data structure for efficient O(L) word lookups.
Sound effects are critical for adding weight and atmosphere to the "Sophisticated Dark" bookworm aesthetic.
- UI & Clicks:
.wavformat. Keep under 0.3s. (Heavy wooden clicks, snapping stone). - Combat & Magic:
.mp3format. (Deep bass reverbs, shattering glass, slashing winds). - Music:
.oggformat for perfectly seamless looping. (Dark ambient, orchestral hums).
To implement these sounds natively, place them in your public/ directory inside a structure like public/sounds/. Because they are in the public directory, fetch() or new Audio() can safely access them starting from the root URL (/sounds/...).
public/
sounds/
ui/
sfx_tile_click.wav (Heavy wooden/stone knock)
sfx_tile_deselect.wav (Lighter reverse click/pop)
sfx_error_buzz.wav (Dull hollow thud or muted buzz)
sfx_scramble_grid.wav (Shuffling tiles / sliding rocks)
combat/
sfx_cast_spell.mp3 (Building magical hum into sharp swoosh)
sfx_enemy_hit.mp3 (Heavy thud with splash/crumple)
sfx_guard_break.mp3 (Shattering glass/chains for locked tiles)
sfx_buff_trigger.mp3 (High pitched harmonic chime)
sfx_enemy_attack.mp3 (Visceral slash or blunt hit)
sfx_player_hurt.mp3 (Deep bass heartbeat drop)
music/
bgm_archive_ambient.ogg (Looping low atmospheric hum/choir)
You can play these natively via simple functions, or use a hook wrapper like use-sound for built-in sprite mapping, latency optimization, and volume control:
// Example of native web audio implementation:
const playTileClick = () => {
const audio = new Audio('/sounds/ui/sfx_tile_click.wav');
audio.volume = 0.5;
audio.play();
}While the game is styled entirely via code to match the dark aesthetic, there are placeholders for the hero and the enemies. Replacing them with custom or generated art will vastly improve the final product.
- Player Portrait:
300x300pxminimum. Square orientation (.jpg or .webp). Use highly contrasted characters. - Enemy Portraits:
320x320pxminimum. Square orientation (.jpg or .webp). Since they scale up to be larger than the player, high fidelity is important. - Background Splashes:
1200x800pxor1920x1080px. Must be dark, gritty, and atmospheric (e.g., ruined library, dark caverns) as they are blended via dodge/screen CSS filters.
If you have local image assets, place them in the public/ directory (e.g., public/images/) and reference them identically to the audio:
public/
images/
player/
hero_portrait.webp (The central archivist portrait)
enemies/
enemy_scrap_mite.jpg (Floor 1)
enemy_iron_tome.jpg (Floor 2)
enemy_mana_sprite.jpg (Floor 3)
enemy_gargoyle.jpg (Floor 4)
[...etc for floors 5-10]
environments/
bg_archives_ambient.jpg (The primary battle background)
bg_main_menu.jpg (The start menu backdrop)
To use these in code, you would edit src/App.tsx and replace the placeholder src="https://picsum.photos/seed/..." bindings with direct paths:
// Using an environment prop:
<img src="/images/environments/bg_archives_ambient.jpg" className="..." />
// Dynamic mapping via enemy names:
<img src={`/images/enemies/enemy_${currentEnemy?.name.toLowerCase().replace(' ', '_')}.jpg`} className="..." />