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
# 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
.sveltefiles with TypeScript support vialang="ts"in script tags - Main entry:
src/main.tsβ mountssrc/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.sveltewith canonical/variation detection - Server Integration: Services for canonical Piclet lookup and creation
- Piclet Management:
PicletCard.svelte,PicletDetail.sveltewith discovery metadata - Database: IndexedDB with
schema.tsfor local caching + server sync for canonical data
Key Patterns
- State Management: Use
$state()rune for reactive state - TypeScript: All components should use
<script lang="ts"> - Imports: Use ES module imports, components are default exports
- Styling: Component styles are scoped by default, global styles in
src/app.css - Database: Hybrid approach - IndexedDB for local state, server API for canonical Piclets
- 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:
// 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:
// 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/searchwith object keywords - Create Canonical: POST
/api/piclets/canonicalfor new discoveries - Create Variation: POST
/api/piclets/variationwith canonicalId - Activity Feed: GET
/api/activity/recentfor 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
- Image Caption: Joy Caption extracts object type and visual attributes
- Object Extraction: Parse caption for primary object ("pillow", "pyramid", etc.)
- Server Lookup: Search for exact match or close variations
- 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
scanCountper 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 checkto identify TypeScript issues before building - Missing dependencies: Run
npm installif 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
// 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
// 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
$libalias 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)