Overview
The AutoLight V3 WebClient is a modern Next.js 15 web application that provides a comprehensive interface for controlling AutoLight V3 LED systems. The application connects to AutoLight hardware devices via REST API and provides real-time control and monitoring capabilities with an advanced Pattern Builder for LED sequence development.
Key Technologies : Next.js 15, React 19, TypeScript, shadcn/ui, Tailwind CSS 4
Development Commands
Primary Workflow
# Start development server (port 3001)
npm run dev
# Build for production with static export
npm run build
# Start production server (port 3001)
npm run start
# Lint code
npm run lint
# Kill server on port 3001 (Linux/macOS)
npm run kill
Mobile Development (Capacitor)
# Add Android platform
npm run cap:add:android
# Build and sync for Android development
npm run cap:build:android
# Sync project with native platforms
npm run cap:sync
Architecture
Client-Side Rendering Strategy
This application uses full client-side rendering with all major components using the "use client" directive:
Real-time Updates : Immediate response to device state changes
Complex Interactions : Pattern Builder requires client-side state management
Performance : Avoids server-side rendering overhead for real-time UI
Dual Context State Management
Separate contexts for different concerns:
ALSContext
SimulationContext
Device and API State Management Location: /lib/contexts/ALSContext.tsx interface ALSContextType {
// Device State
deviceName : string
deviceSerial : string
deviceCh : number
mode : number
delay : number
// API Configuration
host : string
port : string
protocol : 'http' | 'https'
connectionType : 'ip' | 'dns'
// Settings Management
settingsData : {
themes : 'modern' | 'classic'
colors : 'dark' | 'light'
loader : boolean
}
// Update Methods
updateDeviceName : ( name : string ) => void
updateMode : ( mode : number ) => void
updateDelay : ( delay : number ) => void
updateConnectionConfig : ( config : ConnectionConfig ) => void
}
Features:
localStorage persistence for API configuration
Memoized callbacks with deep equality checks
Optimized updates to prevent unnecessary re-renders
Pattern Builder State Management Location: /lib/contexts/SimulationContext.tsx interface SimulationContextType {
// Pattern Management
frames : LEDFrame []
gridConfig : GridConfig
playbackState : PlaybackState
// Multi-Mode Support
simulationMode : 'visual' | 'cpp' | 'expression' | 'javascript'
// Frame Operations
addFrame : () => void
deleteFrame : ( index : number ) => void
updateFrame : ( index : number , frame : LEDFrame ) => void
// Playback Controls
play : () => void
pause : () => void
reset : () => void
}
Features:
Zustand persistence for session restoration
High-precision timing system
JavaScript engine integration
Real-Time Polling System
useALSPolling Hook - Location: /lib/hooks/useALSPolling.ts
export function useALSPolling () {
const { updateDeviceState , connectionConfig } = useALS ()
useEffect (() => {
const pollDevice = async () => {
try {
// Concurrent API calls using Promise.allSettled
const [ name , serial , ch , mode , delay ] = await Promise . allSettled ([
getDeviceName (),
getDeviceSerial (),
getDeviceChannels (),
getDeviceMode (),
getDeviceDelay ()
])
// Update state with results
updateDeviceState ({ name , serial , ch , mode , delay })
} catch ( error ) {
console . error ( 'Polling error:' , error )
}
}
// Poll every 2 seconds
const interval = setInterval ( pollDevice , 2000 )
pollDevice () // Initial poll
return () => clearInterval ( interval )
}, [ connectionConfig ])
}
Features:
Concurrent API Calls : Promise.allSettled() for 5 endpoints simultaneously
Grace Period Logic : 1-second grace period after local changes
Dynamic Configuration : Updates API config without interrupting polling
Error Resilience : Comprehensive error handling with fallbacks
API Integration
The application communicates with AutoLight V3 hardware via REST endpoints.
Base URL Construction
const baseURL = ` ${ protocol } :// ${ host } : ${ port } /api/v1`
// Example: http://192.168.4.1:8000/api/v1
API Functions
Location: /lib/api/device.ts
Get Device Info
Get Device State
Control Device
export async function getDeviceName () : Promise < string > {
const response = await fetch ( ` ${ baseURL } /data/get/device/name` )
return response . text ()
}
export async function getDeviceSerial () : Promise < string > {
const response = await fetch ( ` ${ baseURL } /data/get/device/serial` )
return response . text ()
}
export async function getDeviceChannels () : Promise < number > {
const response = await fetch ( ` ${ baseURL } /data/get/device/ch` )
return parseInt ( await response . text ())
}
Connection Configuration
Stored in localStorage with migration support:
interface ConnectionConfig {
host : string // '192.168.4.1' or 'als.local'
port : string // '8000'
protocol : 'http' | 'https'
connectionType : 'ip' | 'dns'
}
// Default configuration
const defaultConfig : ConnectionConfig = {
host: '192.168.4.1' ,
port: '8000' ,
protocol: 'http' ,
connectionType: 'ip'
}
Component Architecture
Dual Theme System
Modern Theme
Classic Theme
Card-based interface with drawer components Location: components/ModernTheme.tsx Features:
Card-based layout with shadcn/ui components
Drawer navigation for settings and info
Responsive grid system
Modern UI/UX patterns
< div className = "container mx-auto p-4 space-y-6" >
< MainHeader />
< div className = "grid gap-6 md:grid-cols-2" >
< Card >
< CardHeader >
< CardTitle > LED Control </ CardTitle >
</ CardHeader >
< CardContent >
{ /* Control interface */ }
</ CardContent >
</ Card >
</ div >
</ div >
Section-based layout with alert components Location: components/ClassicTheme.tsx Features:
Section-based layout
Alert-style components
Traditional navigation
Simplified UI
< div className = "container mx-auto p-4 space-y-6" >
< MainHeader />
< section className = "space-y-4" >
< h2 className = "text-2xl font-bold" > LED Control </ h2 >
{ /* Control interface */ }
</ section >
</ div >
Core Components
components/
├── MainPage.tsx # Root component with theme routing
├── ModernTheme.tsx # Card-based interface
├── ClassicTheme.tsx # Section-based layout
├── content/ # Shared UI components
│ ├── MainHeader.tsx # Navigation header
│ ├── Sidebar.tsx # Mobile sidebar navigation
│ ├── ConnectionStatus.tsx # Device connection indicators
│ └── ThemeToggle.tsx # Dark/light mode toggle
├── simulation/ # Pattern Builder components
│ ├── modes/ # 4 simulation modes
│ ├── grid/ # Grid system components
│ ├── config/ # Configuration components
│ └── expression/ # Expression parsing UI
└── ui/ # shadcn/ui components (21 components)
shadcn/ui Integration
The application uses 21 Radix UI components:
Configuration: components.json
{
"$schema" : "https://ui.shadcn.com/schema.json" ,
"style" : "new-york" ,
"rsc" : false ,
"tsx" : true ,
"tailwind" : {
"config" : "tailwind.config.ts" ,
"css" : "app/globals.css" ,
"baseColor" : "neutral" ,
"cssVariables" : true
},
"aliases" : {
"components" : "@/components" ,
"utils" : "@/lib/utils"
}
}
Main Interface Features
Device Control
Mode Selection
Timing Control
Connection Status
16 LED sequence modes (0-15) < Select value = { mode } onValueChange = { updateMode } >
< SelectTrigger >
< SelectValue />
</ SelectTrigger >
< SelectContent >
< SelectItem value = "0" > Mode 0 - OFF </ SelectItem >
< SelectItem value = "1" > Mode 1 - Static ON </ SelectItem >
< SelectItem value = "2" > Mode 2 - Blink All </ SelectItem >
{ /* ... modes 3-15 */ }
</ SelectContent >
</ Select >
30-300ms delay adjustment < Slider
value = { [ delay ] }
onValueChange = { ( value ) => updateDelay ( value [ 0 ]) }
min = { 30 }
max = { 300 }
step = { 10 }
/>
< div className = "text-sm text-muted-foreground" >
{ delay } ms delay
</ div >
Real-time connection monitoring < ConnectionStatus
connected = { isConnected }
deviceName = { deviceName }
deviceSerial = { deviceSerial }
ipAddress = { host }
/>
Indicators:
Connected/Disconnected status
Device name and serial
IP address or DNS
Last update timestamp
Settings Management
Location: /app/settings/page.tsx
Configure API connection:
Host : IP address or DNS name
Port : API port (default 8000)
Protocol : HTTP or HTTPS
Connection Type : IP or DNS
Test Connection : Built-in connectivity test
< ConnectionConfigForm
config = { connectionConfig }
onUpdate = { updateConnectionConfig }
onTest = { testConnection }
/>
Customize appearance:
Theme : Modern or Classic
Color Mode : Dark or Light
Accent Color : Customizable
< ThemeSelector
theme = { theme }
colorMode = { colorMode }
onThemeChange = { updateTheme }
onColorModeChange = { updateColorMode }
/>
Device configuration:
Device Name : Update device name
Channel Count : Display channel configuration
Serial Number : Read-only device serial
< DeviceInfoForm
deviceName = { deviceName }
deviceSerial = { deviceSerial }
deviceCh = { deviceCh }
onNameUpdate = { updateDeviceName }
/>
Pattern Builder Integration
The Pattern Builder is available at /app/simulation/page.tsx and provides desktop-only LED sequence development.
Desktop Only : The Pattern Builder requires a screen width ≥1024px (lg breakpoint). Mobile devices will see an informative message explaining the desktop requirement.
4 Simulation Modes
Visual Pattern
Expression Builder
C++ Simulator
JavaScript Simulator
Interactive grid-based LED pattern creation Component: components/simulation/modes/VisualPatternMode.tsx Features:
Dynamic LED grid (supports up to 64 channels)
Frame-by-frame editing
Timeline visualization
Real-time playback with precise timing
Export to C++ code
< DynamicPatternGrid
channels = { deviceCh }
frame = { currentFrame }
onLEDClick = { toggleLED }
/>
Mathematical expression-based patterns Component: components/simulation/modes/ExpressionBuilderMode.tsx Features:
Expression parser for LED states
Mathematical functions (sin, cos, mod, etc.)
Variable support (t, i, frame)
Live preview
< ExpressionEditor
expression = "sin(t * 0.1 + i) > 0"
variables = { { t: 'time' , i: 'channel' } }
onEvaluate = { evaluateExpression }
/>
C++ code parsing and execution engine Component: components/simulation/modes/CppSimulatorMode.tsx Features:
Parse C++ sequence code
Simulate execution
Validate syntax
Export optimized code
< CppEditor
code = { cppCode }
onParse = { parseCppCode }
onSimulate = { simulateExecution }
/>
High-precision JavaScript engine Component: components/simulation/modes/JavaScriptSimulatorMode.tsx Features:
Arduino compatibility layer
High-precision timing (±1-4% accuracy)
Real-time frame generation
Export to C++/JavaScript
< JavaScriptEditor
code = { jsCode }
engine = { javascriptEngine }
onExecute = { executeJavaScript }
/>
High-Precision Timing System
PrecisionTimer Class - Location: /lib/utils/precisionTimer.ts
class PrecisionTimer {
private targetDelay : number
private callback : () => void
constructor ( delay : number , callback : () => void ) {
this . targetDelay = delay
this . callback = callback
}
start () {
// Hybrid algorithm: setTimeout + requestAnimationFrame
const startTime = performance . now ()
const tick = () => {
const elapsed = performance . now () - startTime
if ( elapsed >= this . targetDelay ) {
this . callback ()
return
}
requestAnimationFrame ( tick )
}
// Initial setTimeout for bulk delay
setTimeout (() => {
requestAnimationFrame ( tick )
}, this . targetDelay - 20 )
}
}
Features:
±1-4% Timing Accuracy : Revolutionary improvement over standard setTimeout
Hybrid Algorithm : Combines setTimeout and requestAnimationFrame
Hardware Compatibility : JavaScript patterns match ESP32 timing exactly
Zero Double-Timing : Eliminates setTimeout + playback conflicts
Configuration Files
Next.js Configuration
next.config.ts
const nextConfig : NextConfig = {
output: 'export' , // Static export mode
trailingSlash: true , // Required for static hosting
basePath: '' , // No base path
images: {
unoptimized: true // Static image optimization
}
}
Tailwind Configuration
tailwind.config.ts
export default {
darkMode: [ 'class' ] ,
content: [
'./pages/**/*.{ts,tsx}' ,
'./components/**/*.{ts,tsx}' ,
'./app/**/*.{ts,tsx}' ,
] ,
theme: {
extend: {
colors: {
border: 'hsl(var(--border))' ,
background: 'hsl(var(--background))' ,
foreground: 'hsl(var(--foreground))' ,
// ... CSS variable-based colors
}
}
} ,
plugins: [ require ( 'tailwindcss-animate' )]
}
Deployment
Static Export Build
# Build for production
npm run build
# Output directory: /out
# Files are static HTML/CSS/JS
# Can be served from any web server
Serving Static Files
Local Development
SD Card (ESP32)
Web Server
npm run start
# Serves on http://localhost:3001
Copy /out contents to SD card root: cp -r out/ * /path/to/sdcard/
AutoLight V3 will serve files from SD card via web server on port 80. Deploy to any static hosting:
Nginx
Apache
GitHub Pages
Netlify
Vercel
server {
listen 80 ;
root /var/www/autolight;
index index.html;
location / {
try_files $ uri $ uri / /index.html;
}
}
Next Steps
Pattern Builder Learn about LED pattern creation tools
REST API Complete API reference for integration
AutoLight V3 Explore firmware architecture
Back to Overview Return to AutoLight overview