The static class property singleton pattern doesn't survive HMR
when module boundaries get crossed. New dials would register with
a fresh registry instance while DialsOverlay stayed subscribed to
the old one.
Fix: Store the singleton on `window.__NITESHIFT_DIALS_REGISTRY__`
so it persists across module re-evaluations during hot reload.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Introduces a complete design dials system that allows designers and PMs
to adjust UI parameters at runtime without code changes.
**Dials SDK (`packages/dials/`):**
- useDynamicColor: Color values with design system integration
- useDynamicSpacing: Spacing/padding/margin controls
- useDynamicVariant: Discrete choice selections
- useDynamicBoolean: Toggle/feature flag controls
- useDynamicNumber: Numeric values with min/max/step
- DialsOverlay: Compact Leva-inspired UI (Ctrl+D to toggle)
- DialsProvider: React context for dial state management
- Design manifest integration for design system tokens
**App Integration:**
- Added DialsProvider to app Providers
- Example dials on WebsitePage (metrics bar, panels, navigation)
- MetricCard component with adjustable typography dials
- TypeScript manifest at src/config/niteshift-manifest.ts
**Documentation:**
- Comprehensive CLAUDE.md section on dials usage
- Best practices for preserving original appearance
- Examples for all dial types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>