| # CLAUDE.md | |
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | |
| ## Project Overview | |
| This is a Svelte 5 + TypeScript + Vite single-page application for a discovery-based creature collection game called "Pictuary". It uses the latest Svelte 5 with runes syntax (`$state()`, `$derived()`, etc.). | |
| ### Main Features | |
| - **Monster Discovery**: Upload images β AI identifies objects and generates/retrieves canonical "Piclets" | |
| - **Canonical System**: Each real-world object has ONE canonical Piclet, with variations tracked | |
| - **Collection Management**: Track discovered Piclets with metadata (discoverer, rarity, variations) | |
| - **Activity Feed**: Leaderboard showing top discoverers and recent finds | |
| - **Server Integration**: Connects to `../piclets-server/` for canonical Piclet database | |
| ## Essential Commands | |
| ```bash | |
| # Install dependencies | |
| npm install | |
| # Development server with HMR | |
| npm run dev | |
| # Type checking | |
| npm run check | |
| # Production build (outputs to dist/) | |
| npm run build | |
| # Preview production build | |
| npm run preview | |
| # Run tests | |
| npm test | |
| # Run tests with UI | |
| npm run test:ui | |
| ``` | |
| ## Architecture | |
| ### Component Structure | |
| - Components use `.svelte` files with TypeScript support via `lang="ts"` in script tags | |
| - Main entry: `src/main.ts` β mounts `src/App.svelte` | |
| - Reusable components go in `src/lib/` | |
| - Uses Svelte 5 runes syntax (not Svelte 4 syntax) | |
| ### Key Components | |
| - **Pages**: `Scanner.svelte` (discovery), `Pictuary.svelte` (collection), `Activity.svelte` (leaderboard/feed) | |
| - **Monster Discovery**: `PicletGenerator.svelte`, `PicletResult.svelte` with canonical/variation detection | |
| - **Server Integration**: Services for canonical Piclet lookup and creation | |
| - **Piclet Management**: `PicletCard.svelte`, `PicletDetail.svelte` with discovery metadata | |
| - **Database**: IndexedDB with `schema.ts` for local caching + server sync for canonical data | |
| ### Key Patterns | |
| 1. **State Management**: Use `$state()` rune for reactive state | |
| 2. **TypeScript**: All components should use `<script lang="ts">` | |
| 3. **Imports**: Use ES module imports, components are default exports | |
| 4. **Styling**: Component styles are scoped by default, global styles in `src/app.css` | |
| 5. **Database**: Hybrid approach - IndexedDB for local state, server API for canonical Piclets | |
| 6. **Discovery Flow**: Caption β Extract object β Server lookup β Return canonical/variation/new | |
| ### Build Configuration | |
| - Vite handles bundling with `vite.config.ts` | |
| - TypeScript config uses project references (tsconfig.json + tsconfig.app.json) | |
| - Production builds go to `dist/` directory | |
| ## External Dependencies | |
| ### Gradio Client Integration | |
| This project uses Gradio Client for connecting to Hugging Face Spaces. **Important**: Use the CDN-based approach, not npm packages. | |
| **Setup in App.svelte:** | |
| ```javascript | |
| // CDN imports are loaded dynamically | |
| import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; | |
| window.gradioClient = { Client }; | |
| ``` | |
| **Usage in other files:** | |
| ```typescript | |
| // Access via window.gradioClient (types are declared in vite-env.d.ts) | |
| const client = await window.gradioClient.Client.connect("space-name"); | |
| ``` | |
| **Current Gradio Connections:** | |
| - **Flux Image Generation**: `Fraser/flux` | |
| - **Joy Caption**: `fancyfeast/joy-caption-alpha-two` (configured for object identification) | |
| - **Qwen Text Generation**: For generating Piclet concepts from object captions | |
| ### Server Integration | |
| - **Endpoint**: `../piclets-server/` (local development) | |
| - **Canonical Lookup**: POST `/api/piclets/search` with object keywords | |
| - **Create Canonical**: POST `/api/piclets/canonical` for new discoveries | |
| - **Create Variation**: POST `/api/piclets/variation` with canonicalId | |
| - **Activity Feed**: GET `/api/activity/recent` for global discoveries | |
| **Build Notes:** | |
| - DO NOT install Gradio Client via npm (`npm install @gradio/client`) - it causes build failures | |
| - The CDN approach ensures compatibility with Vite bundling | |
| - All Gradio connections should use the established pattern from App.svelte | |
| ### Discovery Architecture | |
| #### Object Identification Flow | |
| 1. **Image Caption**: Joy Caption extracts object type and visual attributes | |
| 2. **Object Extraction**: Parse caption for primary object ("pillow", "pyramid", etc.) | |
| 3. **Server Lookup**: Search for exact match or close variations | |
| 4. **Response Types**: | |
| - **Exact Match**: Return existing canonical Piclet + increment scan count | |
| - **Close Match**: Create variation of canonical + link to parent | |
| - **No Match**: Create new canonical Piclet + register discoverer | |
| #### Rarity Calculation | |
| - Track `scanCount` per canonical Piclet | |
| - Rarity score = 1 / scanCount (lower scan count = higher rarity) | |
| - Display rarity tiers: Common, Uncommon, Rare, Epic, Legendary | |
| ## Troubleshooting | |
| ### Common Build Issues | |
| - **Gradio Client build failures**: Ensure you're NOT using `npm install @gradio/client`. Use CDN imports only. | |
| - **Type errors**: Run `npm run check` to identify TypeScript issues before building | |
| - **Missing dependencies**: Run `npm install` if packages are missing | |
| ### Discovery System Issues | |
| - **Object extraction**: Ensure Joy Caption is set to "Descriptive" mode with focus on object type | |
| - **Server connection**: Verify `../piclets-server/` is running on expected port | |
| - **Variation detection**: Check keyword matching algorithm for false positives | |
| - **Rarity calculation**: Ensure scanCount is properly incremented on each discovery | |
| ### Performance | |
| - **Large image files**: Consider image compression before upload | |
| - **Server latency**: Cache canonical Piclets locally after first fetch | |
| - **Search optimization**: Use keyword indexing for O(1) lookups | |
| - **Activity feed**: Paginate results, cache recent discoveries | |
| ## Implementation Strategy | |
| ### Caption Processing | |
| ```typescript | |
| // Example caption processing for object extraction | |
| const caption = "A velvet blue pillow with golden tassels on a couch"; | |
| const primaryObject = extractObject(caption); // "pillow" | |
| const attributes = extractAttributes(caption); // ["velvet", "blue"] | |
| ``` | |
| ### Server Communication | |
| ```typescript | |
| // Canonical lookup | |
| const result = await fetch('/api/piclets/search', { | |
| method: 'POST', | |
| body: JSON.stringify({ | |
| object: 'pillow', | |
| attributes: ['velvet', 'blue'] | |
| }) | |
| }); | |
| // Response types | |
| interface CanonicalMatch { | |
| type: 'exact' | 'variation' | 'new'; | |
| piclet: PicletInstance; | |
| canonicalId?: string; | |
| discoveredBy?: string; | |
| scanCount: number; | |
| } | |
| ``` | |
| ### Database Schema Updates | |
| - Remove: level, xp, hp, attack, defense, speed, moves, battleStats | |
| - Add: canonicalId, isCanonical, discoveredBy, discoveredAt, scanCount, variations[] | |
| - Keep: typeId, primaryType, tier, imageUrl, description, concept | |
| ## Important Notes | |
| - This is NOT SvelteKit - no routing, SSR, or API routes | |
| - HMR preserves component state (can be toggled in vite.config.ts) | |
| - All paths in imports should be relative or use `$lib` alias for src/lib | |
| - Hybrid storage: IndexedDB for local cache, server for canonical truth | |
| - Object abstraction level is critical - "pillow" not "decorative cushion" | |
| - Variations limited to 2-3 meaningful attributes (material, style, color) |