copilot-instructions.md
1 # RadixVerse - AI Coding Agent Instructions 2 3 ## Project Overview 4 **RadixVerse** is an interactive React + TypeScript web application for exploring alternative number systems and bases. It allows users to visualize and convert numbers across 6 distinct mathematical systems (standard, bijective, balanced, clock, sum, balsum) with support for radixes 2-35. 5 6 ## Architecture 7 8 ### Core System: Number Systems (src/utils.ts) 9 The heart of the app is the `Radix` type - a configuration object for each number system that encodes: 10 - Character set mapping (0-9, A-Z, or Unicode symbols like β, π ©) 11 - Low/high value ranges for each system 12 - Conversion functions: `num2str()` (numberβstring), `str2num()` (stringβnumber) 13 14 **Key insight:** Each radix system has different arithmetic rules: 15 - **Standard**: 0 to radix-1 (normal base conversion) 16 - **Bijective**: 1 to radix (no zero; uses only 1 character) 17 - **Balanced**: Negative to positive around zero (e.g., base-3 balanced uses -1,0,1) 18 - **Clock**: Symmetric around zero with negative representation (used for hour-like notation) 19 - **Sum**: Positional system using addition instead of multiplication (powers of r as multipliers) 20 - **Balsum**: Hybrid balanced+sum system 21 22 ### UI Component Hierarchy 23 ``` 24 App (src/app.tsx) 25 βββ Router + useStore (manages radixes, enabled radixes, value from URL params) 26 βββ Header (radix editor) 27 βββ Tabs navigation 28 βββ Route components (Show, Add, Multiply, Convert) 29 βββ Table/Tables (src/components/Table.tsx) 30 βββ renderValue (color coding by HSL hue based on value range) 31 ``` 32 33 **Key pattern:** All route components receive `enabledRadixes` and generate table data locally via `computeProps()` - the app doesn't use global state management. 34 35 ### Data Persistence 36 - **localStorage** keys: `theme`, `chars`, `radixes` 37 - **URL parameters**: `?r=base2&r=base10&value=42&radix=base10` preserves state across sessions 38 - Error handling: JSON parse failures in localStorage fallback silently and trigger error toast 39 40 ## Development Workflows 41 42 ### Build & Serve 43 ```bash 44 npm start # Vite dev server on port 10000 with HMR 45 npm run build # Production build with sourcemaps (vite build) 46 npm run preview # Serve production build on port 10000 47 npm run check # TypeScript type checking (strict mode) 48 npm run lint # ESLint on src/ with styled eslint-plugin 49 npm test # Node native test runner (src/**/*.test.ts) 50 npm run pre-commit # Check + Lint + Test + Build (CI equivalent) 51 ``` 52 53 **Pre-commit hook equivalent:** Use `npm run pre-commit` before pushing. 54 55 ### Quality Standards 56 - **TypeScript**: Strict mode enabled; ESNext target; JSX via React 19 compiler 57 - **Linting**: ESLint 9 with @stylistic/eslint-plugin; Biome parser for CSS with Tailwind directives 58 - **Testing**: Native Node.js test runner (src/**/*.test.ts); example in src/utils.test.ts 59 - **Styling**: TailwindCSS v4 with DaisyUI components; source in src/app.css 60 61 ## Key Conventions 62 63 ### Number Conversion Pattern 64 **Always use BigInt for arithmetic** - the Radix type stores values as `bigint` because JavaScript's `Number` overflows above 2^53. 65 66 ```typescript 67 // β Correct: Handle conversion via Radix methods 68 const num: bigint = 42n; 69 const str = num2str(num, radix); 70 const back: bigint = str2num(str, radix); 71 72 // β Avoid: Direct number operations with large values 73 const val = 999999999999999999; // Loses precision 74 ``` 75 76 ### Component Props Pattern 77 Route components (Add, Multiply, Convert) receive `radixes: Radix[]` and compute derived state locally: 78 79 ```typescript 80 const [ props, setProps ] = useState(computeProps(radix)); 81 useEffect(() => setProps(computeProps(radix, columns, rows)), [ radix, columns, rows ]); 82 ``` 83 84 This avoids prop drilling and keeps table layout computation close to rendering. 85 86 ### Error Handling 87 - **Parser errors**: Catch, log, and call `updateError()` to show toast (10s auto-dismiss) 88 - **Invalid input**: Sanitize via `sanitizeInput()` and throw with `allowedCharaters(radix)` message 89 - **Missing radix in URL**: Throw error with helpful context (currently checked in app.tsx) 90 91 ### localStorage Serialization 92 Only serialize safe fields (name, radix, system, chars, enabled) - omit Maps and computed fields: 93 94 ```typescript 95 const rs = radixes.map(r => ({ 96 name: r.name, 97 radix: Number(r.radix), // BigInt β Number for JSON 98 system: r.system, 99 chars: r.chars, 100 enabled: r.enabled 101 })); 102 ``` 103 104 Deserialization reconstructs Maps via `createRadix()`. 105 106 ## Integration Points 107 108 ### Radix Creation 109 - `createRadixes(chars)` - generates all 35 radixes (radix 2-36) with default enabled set 110 - `createRadix(num, system, chars, enabled, name)` - single radix with validation 111 - **Validation**: System+radix combos have constraints (balanced/sum must be odd, clock even) 112 113 ### Character Sets 114 - Default: 71-char balanced set (`baseBal71`) = -26 to 26 (Unicode symbols) + 0 + 1-9 + A-Z 115 - Custom: Set via `setCharsLS()`, retrieved for Radix creation 116 - **Constraint**: Custom char sets must have odd length and β₯ 71 chars for default radixes 117 118 ### URL State Recovery 119 App.tsx `useEffect` runs once to: 120 1. Detect `?clear-settings` β wipe localStorage 121 2. Parse `?r=...` params β set enabled radixes 122 3. Parse `?radix=...` β set working radix 123 4. Parse `?value=...` β set initial number for conversion 124 125 **Order matters:** Radix must be set before parsing value to avoid "Unknown radix" errors. 126 127 ## Testing & Debugging 128 129 ### Test Utils 130 - `src/utils.test.ts` - examples of num2str, str2num, edge cases 131 - **NaN handling**: `renderValue()` returns empty span for NaN values 132 133 ### Common Issues 134 - **Color encoding**: HSL hue = `(val - low) / space * 300` (maps range to 300Β° color wheel) 135 - **Table dimensions**: `columns = high - low + 1`; `rows = columns + (bijective ? 1 : 0)` 136 - **Overflow**: Use `Number.isNaN()` to detect overflow before rendering 137 138 ## File Reference 139 - [src/utils.ts](../src/utils.ts) - All number system logic, serialization 140 - [src/app.tsx](../src/app.tsx) - Router, URL params, useStore hook 141 - [src/components/Table.tsx](../src/components/Table.tsx) - Rendering logic, color mapping 142 - [src/components/Show.tsx](../src/components/Show.tsx) - Example of `computeProps()` pattern 143 - [vite.config.ts](../vite.config.ts) - PWA plugin, React compiler, Tailwind 144 - [biome.json](../biome.json) - Linter rules (ESNext, no exhaustive deps, allow non-null assertions)