PitLane Systems

Custom Overlays

Creating your own overlays, the dev workflow, WebSocket data format, and community overlays.

PitLane's overlay system is designed to be extensible. You can create your own overlays using HTML, CSS, and JavaScript (or React), and PitLane will discover, serve, and feed them live race data alongside the built-in overlays.

How overlays work

Every overlay is a web page served by PitLane's built-in server on localhost:9100. Overlays receive live race data over a WebSocket connection and render it however they want. OBS picks them up as browser sources.

The built-in template overlays (leaderboard, lower-third, battle, session-info, ticker) are simple single-file HTML pages — good starting points for your own overlays.

Creating a basic overlay

1. Create a folder

Create a folder in PitLane's overlays directory with your overlay's ID as the folder name. Inside, create an index.html and a manifest.json.

your-overlay/
  index.html
  manifest.json

2. Write the manifest

The manifest.json tells PitLane about your overlay:

{
  "id": "your-overlay",
  "name": "My Custom Overlay",
  "author": "Your Name",
  "version": "1.0",
  "description": "A brief description of what this overlay shows.",
  "tags": ["community"],
  "icon": "Tv",
  "controls": []
}

Required fields:

  • id — unique identifier, must match the folder name
  • name — display name shown in PitLane's overlay panel
  • controls — array of control definitions (can be empty)

Optional fields:

  • author, version, description — metadata shown in the overlay info dialog
  • tags — categorization: "template", "broadcast", or "community"
  • icon — a Lucide icon name for the overlay panel. Available icons: List, LayoutList, User, UserRound, Swords, Info, MessageSquare, Timer, Gauge, Flag, Trophy, Radio, Tv, BarChart3, Map, Layers, Zap, Eye, Activity, Clock

3. Connect to live data

In your index.html, connect to PitLane's WebSocket to receive live race data:

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      margin: 0;
      background: transparent;
      font-family: sans-serif;
      color: white;
    }
  </style>
</head>
<body>
  <div id="overlay"></div>
  <script>
    const ws = new WebSocket('ws://localhost:9100/live');

    ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      // data.cars — array of all cars
      // data.focusedCar — the currently spectated car
      // data.battles — active battles
      // data.events — recent race events
      // data.session — session info (weather, flags, time)
      // data.overlayControls['your-overlay'] — your control values
      render(data);
    };

    function render(data) {
      // Your rendering logic here
    }
  </script>
</body>
</html>

Set background: transparent so your overlay layers cleanly over the game capture in OBS.

4. Add it to PitLane

  1. In PitLane, go to the Overlays panel
  2. Click Add Overlay — PitLane scans for new overlays on the filesystem
  3. Your overlay should appear in the list
  4. Add it to your active set and toggle it on

5. View it in OBS

Add a browser source in OBS pointing to http://localhost:9100/overlay/your-overlay.

Adding controls

Controls let users configure your overlay from PitLane's interface without editing code. Add them to the controls array in your manifest.

Control types

Toggle — on/off switch

{
  "id": "show-gaps",
  "type": "toggle",
  "label": "Show Gaps",
  "placement": "inline",
  "default": true
}

Select — dropdown with predefined options

{
  "id": "sort-mode",
  "type": "select",
  "label": "Sort By",
  "placement": "inline",
  "options": ["position", "gap", "last-lap"],
  "default": "position"
}

Range — numeric slider

{
  "id": "font-size",
  "type": "range",
  "label": "Font Size",
  "placement": "settings",
  "min": 12,
  "max": 32,
  "step": 2,
  "default": 16
}

Color — color picker

{
  "id": "accent-color",
  "type": "color",
  "label": "Accent Color",
  "placement": "settings",
  "default": "#0EA5E9"
}

Text — text input

{
  "id": "header-text",
  "type": "text",
  "label": "Header Text",
  "placement": "settings",
  "default": "Race Standings",
  "maxLength": 50,
  "placeholder": "Enter header text"
}

Button — trigger a momentary action

{
  "id": "reset-animation",
  "type": "button",
  "label": "Reset Animation",
  "placement": "inline",
  "duration": 1000
}

Placement

  • "inline" — shown directly in the overlay's expanded controls in the panel
  • "settings" — shown in the overlay's settings dialog (gear icon)

Reading control values

Control values are included in the WebSocket data:

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  const controls = data.overlayControls['your-overlay'] || {};
  const showGaps = controls['show-gaps'] ?? true;
  const sortMode = controls['sort-mode'] ?? 'position';
};

WebSocket data reference

Every message from the WebSocket includes:

FieldTypeDescription
carsarrayAll cars with position, lap times, speed, pit status, driver info, and more
focusedCarobject or nullDetailed telemetry for the currently spectated car (gear, pedals, RPM, fuel)
battlesarrayActive battles with the two cars involved and the gap between them
eventsarrayRecent race events (overtakes, incidents, pit stops, fastest laps)
sessionobject or nullSession info: weather, flags, time remaining, track length
overlayVisibilityobjectWhether each overlay is toggled on or off
overlayControlsobjectCurrent control values for each overlay, keyed by overlay ID
themeobjectGlobal theme: primaryColor, secondaryColor, panelOpacity
timestampnumberCurrent timestamp

Development workflow

For active development with hot reload:

npm run dev:overlay -- your-overlay

This starts a Vite HMR dev server on port 5174 that proxies to PitLane's overlay server. CSS and JavaScript changes are reflected instantly without refreshing OBS.

This workflow is available if you're developing overlays within the PitLane source tree (e.g., as a React overlay in src/overlays/). For simple HTML overlays, PitLane's overlay server already reads files from disk with no caching — just edit and refresh.

Starting from a template

The 5 template overlays (leaderboard, lower-third, battle, session-info, ticker) are single HTML files designed to be forked. Copy one to a new folder, add a manifest.json, and start modifying.