cover

18 May 2025

Building a Custom Grid UI for Robotics Control

2m16s
robotics
sveltekit
ui-design
ftc

Introduction

When your robotics team is knee-deep in competition chaos, the last thing you need is a clunky control interface. That’s why I rebuilt FTControl Panels a dashboard for FTC (FIRST Tech Challenge) robots - from a button-heavy nightmare into a fluid, grid-based playground. In v0.6.2, we ditched rigid controls for intuitive gestures, letting teams drag, resize, and customize their dashboards like Lego blocks. No external libraries, just pure SvelteKit magic. Let’s break it down!

Core Concepts: Widgets, Groups & Presets

FTControl Panels revolves around three key ideas:

1. Widgets: Modular tools like OpMode controllers, telemetry graphs, or field visualizers.

2. Widget Groups: Tabbed containers holding related widgets (e.g., sensors + graphs).

3. Presets: Saved grid layouts—think "auto mode" vs. "tele-op" dashboards.

Supported widgets include real-time gamepad visualizers, Variable tuning, and even a field map for tracking robot position. Teams can also build custom widgets via plugins.

The Grid Engine: How It Works Under the Hood

Instead of off-the-shelf solutions like GridStack.js, I rolled a custom grid manager. Here’s the blueprint:

- State Management: Each widget group occupies grid squares tracked via UUIDs in a 2D map.

- Collision Checks: The grid validates moves/resizes in real-time.

- Persistent Layouts: Browser storage saves presets using JSON serialization:

Typescript

// Simplified state serialization
toJSON(): Preset {
  return {
    id: this.id,
    groups: this.widgets,
    xSize: this.cellsX, // Grid columns
    ySize: this.cellsY  // Grid rows
  }
}

Gesture-Driven UX: Drag, Drop, and Organize

1. Context Menus (Right-Click Anywhere)

- Create/delete tabs, change widget types, or clone groups.

2. Moving & Resizing

- Drag groups via top handles; resize from bottom-right corners.

3. Tab Management

- Drag tabs between groups or rearrange them like browser tabs.

All interactions use Svelte’s reactive $state and a modular manager system:

Typescript

// Managers handle gestures generically
export abstract class InteractionManager {
  mouseX = $state(0)
  mouseY = $state(0)
  
  abstract onMouseMove(event: MouseEvent): void
  abstract onClick(event: MouseEvent): void
  abstract onKey(event: KeyboardEvent): void
  // ...other events
}

Overcoming Challenges

1. State Sync: Svelte’s stores kept UI reactivity in check—no prop-drilling hell.

2. DOM Hacks: data-* attributes store widget IDs for hover/click targeting:

HTML

<div data-widget-id="sensor-graph-42"></div>

1. Performance: Avoiding full-grid rerenders by updating only moved/resized elements.

Further Reading

- Panels Customization Docs

- FTControl GitHub Repo

Conclusion

FTControl Panels v0.6.2 turns dashboard customization from a chore into a playground. By combining SvelteKit’s reactivity with a gesture-first grid, teams can now build control interfaces that adapt *to them*—not the other way around. Whether you’re tuning PID values mid-match or replaying sensor data, everything stays intuitive and fluid.

Happy Robotics Tinkering! 🚀