/ .github / copilot-instructions.md
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)