Skip to main content

Overview

The Pattern Builder is an advanced LED sequence development tool integrated into the AutoLight Web Client. It provides desktop-only pattern creation with 4 distinct simulation modes, high-precision timing, and C++ code generation for seamless integration with AutoLight V3 firmware.
Desktop Only: The Pattern Builder requires a screen width ≥1024px (lg breakpoint). This is due to the complexity of the Monaco editor, frame timeline, and grid controls which require substantial screen real estate for an optimal development experience.

4 Simulation Modes

The Pattern Builder provides comprehensive LED sequence development through four complementary approaches:

Visual Pattern

Interactive grid-based LED pattern creation with frame-by-frame editing

Expression Builder

Mathematical expression-based patterns with live preview

C++ Simulator

C++ code parsing and execution engine with validation

JavaScript Simulator

High-precision JavaScript engine with Arduino compatibility

Visual Pattern Mode

Overview

Interactive grid-based LED pattern creation with frame-by-frame editing, timeline visualization, and real-time playback. Component: components/simulation/modes/VisualPatternMode.tsx

Features

Adaptive grid supporting up to 64 channels
<DynamicPatternGrid
  channels={deviceCh}        // Auto-adapts to device channel count
  frame={currentFrame}       // Current frame state
  onLEDClick={toggleLED}     // LED click handler
  gridLayout="auto"          // Auto-calculate optimal layout
/>
Features:
  • Automatic grid layout calculation
  • Responsive cell sizing
  • Visual LED state (ON/OFF)
  • Click to toggle individual LEDs
  • Multi-select support
  • Copy/paste frame data

Grid Layout System

Automatic grid layout calculation based on channel count:
function calculateGridLayout(channels: number): GridLayout {
  // Auto-calculate optimal rows/columns
  if (channels <= 8) {
    return { rows: 1, cols: channels }  // Single row
  } else if (channels <= 16) {
    return { rows: 2, cols: channels / 2 }  // 2 rows
  } else if (channels <= 32) {
    return { rows: 4, cols: channels / 4 }  // 4 rows
  } else {
    return { rows: 8, cols: channels / 8 }  // 8 rows (max 64 channels)
  }
}
1

Configure Grid

Set channel count to match your device (e.g., 12 channels)
<GridConfig channels={12} />
2

Create Frame 1

Click all LEDs ON in the grid
Frame 1: [1,1,1,1,1,1,1,1,1,1,1,1]
3

Add Frame 2

Click “Add Frame” and set all LEDs OFF
Frame 2: [0,0,0,0,0,0,0,0,0,0,0,0]
4

Set Timing

Configure frame delay (e.g., 100ms)
<Slider value={100} min={30} max={300} />
5

Test Playback

Click Play to preview the blinking patternAll LEDs will blink ON/OFF at 100ms intervals
6

Generate Code

Export to C++ for use in BaseChannelSequence.cpp
void BaseChannel::taskSequenceCustomBlink() {
    for (int i = 0; i < 10; i++) {
        // Frame 1: All ON
        on();
        sleep(100);
        
        // Frame 2: All OFF
        off();
        sleep(100);
    }
}

Expression Builder Mode

Overview

Mathematical expression-based pattern generation with real-time evaluation and live preview. Component: components/simulation/modes/ExpressionBuilderMode.tsx

Expression System

Expression syntax and variablesAvailable variables:
  • t - Time in milliseconds
  • i - Channel index (0 to channels-1)
  • frame - Current frame number
  • ch - Total channel count
Supported functions:
  • Math: sin(), cos(), tan(), abs(), floor(), ceil(), round()
  • Logic: &&, ||, !, >, <, ==, !=
  • Operators: +, -, *, /, %, ^
Example:
sin(t * 0.1 + i) > 0  // Wave pattern

Example: Creating a Wave Pattern

<ExpressionEditor>
  <Input 
    value="sin((t * 0.05) + (i * 0.8)) > 0"
    onChange={updateExpression}
  />
  
  <div className="preview">
    {/* Live visualization of wave propagating across LEDs */}
  </div>
  
  <Button onClick={exportToFrames}>
    Convert to Frames
  </Button>
  
  <Button onClick={exportToCpp}>
    Generate C++ Code
  </Button>
</ExpressionEditor>

C++ Simulator Mode

Overview

C++ code parsing and execution engine with syntax validation and simulation capabilities. Component: components/simulation/modes/CppSimulatorMode.tsx

Features

Parse existing C++ sequence code from BaseChannelSequence.cpp
void BaseChannel::taskSequence2BlinkAll() {
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 15; ++j) {
            // Turn all channels ON
            for (int k = 0; k < pin_size_; k++) {
                set(pin_ptr_[k], HIGH);
            }
            sleep(delay_time_);
            
            // Turn all channels OFF
            for (int k = 0; k < pin_size_; k++) {
                set(pin_ptr_[k], LOW);
            }
            sleep(delay_time_);
        }
        sleep(500);
    }
    off();
}
Simulate C++ code execution to generate frame dataFeatures:
  • Parse function calls: set(), on(), off(), sleep()
  • Track channel states
  • Generate timing information
  • Validate syntax
  • Export frame data
Validate C++ code for common errorsChecks:
  • Function syntax
  • Variable declarations
  • Loop structures
  • Array bounds
  • Timing constraints
  • AutoLight API usage
Optimize C++ code for performanceOptimizations:
  • Remove redundant operations
  • Combine sequential sets
  • Minimize sleep calls
  • Reduce loop iterations
  • Suggest improvements

JavaScript Simulator Mode

Overview

High-precision JavaScript engine with Arduino compatibility layer and exact ESP32 timing matching. Component: components/simulation/modes/JavaScriptSimulatorMode.tsx

High-Precision Timing System

PrecisionTimer Class - Location: /lib/utils/precisionTimer.ts
class PrecisionTimer {
  private targetDelay: number
  private callback: () => void
  private running: boolean = false
  
  constructor(delay: number, callback: () => void) {
    this.targetDelay = delay
    this.callback = callback
  }
  
  start(): void {
    this.running = true
    const startTime = performance.now()
    
    const tick = () => {
      if (!this.running) return
      
      const elapsed = performance.now() - startTime
      
      if (elapsed >= this.targetDelay) {
        this.callback()
        return
      }
      
      // Continue ticking
      requestAnimationFrame(tick)
    }
    
    // Hybrid approach: setTimeout for bulk delay + RAF for precision
    const bulkDelay = Math.max(0, this.targetDelay - 20)
    setTimeout(() => {
      if (this.running) {
        requestAnimationFrame(tick)
      }
    }, bulkDelay)
  }
  
  stop(): void {
    this.running = false
  }
}
Features:
  • ±1-4% Timing Accuracy: Revolutionary improvement over standard setTimeout (±10-30%)
  • Hybrid Algorithm: Combines setTimeout (bulk delay) and requestAnimationFrame (precision)
  • Hardware Compatibility: JavaScript patterns match ESP32 deployment timing exactly
  • Zero Double-Timing: Eliminates setTimeout + playback context timing conflicts

Arduino Compatibility Layer

JavaScript Engine - Location: /lib/simulation/javascriptEngine.ts
class ArduinoAPI {
  constructor(channelCount) {
    this.channels = new Array(channelCount).fill(0)
    this.frames = []
  }
  
  // Arduino-compatible functions
  set(channel, state) {
    this.channels[channel] = state ? 1 : 0
  }
  
  on() {
    this.channels.fill(1)
  }
  
  off() {
    this.channels.fill(0)
  }
  
  sleep(ms) {
    // Capture current frame with delay
    this.frames.push({
      channels: [...this.channels],
      delay: ms
    })
  }
  
  // Helper functions
  HIGH = 1
  LOW = 0
}

Example: JavaScript Pattern

function pattern() {
  for (let i = 0; i < 10; i++) {
    on()
    sleep(100)
    off()
    sleep(100)
  }
}

Code Generation

C++ Export Formats

Uses BaseChannel direct control functions
void BaseChannel::taskSequenceCustom() {
    // Generated pattern with BaseChannel API
    
    // Frame 1
    on();
    sleep(100);
    
    // Frame 2
    off();
    sleep(100);
    
    // Frame 3
    set(0, HIGH);
    set(1, HIGH);
    set(2, HIGH);
    sleep(50);
    
    // Repeat...
}
Functions:
  • on() - Turn all channels ON
  • off() - Turn all channels OFF
  • set(channel, state) - Set individual channel
  • sleep(ms) - Delay in milliseconds

Integration with BaseChannelSequence.cpp

1

Generate Code

Use Pattern Builder to create your sequence and generate C++ code
2

Copy Function

Copy the generated function to your clipboard
3

Add to BaseChannelSequence.cpp

Open Firmware/Core/Channel/BaseChannel/BaseChannelSequence.cppAdd your function at the end:
void BaseChannel::taskSequence16CustomPattern() {
    // Your generated code here
}
4

Declare in Header

Add declaration to BaseChannel.h:
void taskSequence16CustomPattern();
5

Update Sequence Router

Add to sequence routing logic:
case 16:
    taskSequence16CustomPattern();
    break;
6

Build and Upload

pio run --target upload

Desktop-Only Design

Responsive Requirements

The Pattern Builder requires substantial screen real estate:
<div className="hidden lg:block">
  {/* Pattern Builder - Desktop Only */}
  <PatternBuilder />
</div>

<div className="lg:hidden">
  {/* Mobile Warning */}
  <Alert>
    <Info className="h-4 w-4" />
    <AlertTitle>Desktop Required</AlertTitle>
    <AlertDescription>
      The Pattern Builder requires a screen width of at least 1024px.
      Please use a desktop or laptop computer for pattern development.
    </AlertDescription>
  </Alert>
</div>

Why Desktop-Only?

The Monaco code editor (used in C++/JavaScript modes) requires:
  • Minimum width: 600px for usable editing
  • Syntax highlighting panel
  • Line numbers and minimap
  • Error indicators and tooltips
Frame timeline visualization needs:
  • Minimum 800px for comfortable scrolling
  • Thumbnail previews (64x64px each)
  • Frame controls and labels
  • Drag-and-drop interaction area
Dynamic LED grid requires:
  • Minimum 400px for 64-channel display
  • Touch targets must be ≥44px for accessibility
  • Labels and state indicators
  • Multi-select interaction area
Multiple control panels need:
  • Pattern controls: 300px
  • Grid configuration: 250px
  • Export options: 200px
  • Settings panel: 250px
Total: ~1000px minimum width

Next Steps

Web Client

Learn about the Next.js web interface

REST API

API reference for device control

AutoLight V3

Firmware architecture details

Back to Overview

Return to AutoLight overview

Build docs developers (and LLMs) love