Panels
Branded touch surfaces for the people who use the space — built from widgets, or from your own HTML.
A Panel is a screen built for the people who use a space rather than the people who program it. It opens at its own web address, needs no Lightpath login, and shows only what you put on it.
A wall tablet by the door that dims the lights. A phone page a bartender opens to change the scene. A always-on display in the office showing what is playing and whether anything is wrong. All Panels.
Two kinds of Panel
When you create a Panel you choose how it is built, and the choice is permanent.
Widget Panels are assembled from ready-made blocks — a content grid, a palette picker, now-playing, schedule, health. You arrange them, style them, and Lightpath draws them. No code.
Custom Panels are your own HTML, CSS and JavaScript. You get a blank page and the full Panel API. Choose this when the layout you want is not a grid of cards — a floor plan you tap, a room diagram, a branded splash screen.
Opening a Panel
Every Panel has an address of the form /p/name. From the Panels page you can:
- Browser — open it in your normal web browser, exactly as a guest will see it
- New window — open it in its own Lightpath window, sized like a tablet
- Copy URL — copy the address to send to a device
Point a tablet's browser at that address and add it to the home screen. It launches straight back into the Panel, with the Panel's own name and icon.
Who can open it
Set this on the Access tab. Three modes:
| Mode | What happens |
|---|---|
| Open | Loads immediately, no barrier |
| PIN | A number pad, then the Panel opens |
| Login | A real Lightpath sign-in |
What a Panel can do
There is nothing to configure here, on purpose. A device that gets into a Panel can use everything on it — activate content, run controls, and drive playback and the schedule.
It can never author or delete content. A PIN is a shared secret written on a wall, not a personal password, so no Panel hands out the ability to change or remove your looks and scenes.
The reason there is no setting: a Panel that granted less than it displayed would draw a control and then refuse it when pressed, which looks like a broken installation rather than a locked one. What a Panel can do is exactly what you put on it, so put on it only what its audience should have.
Writing a Custom Panel
Creating a Custom Panel scaffolds three files in your project:
projects/your-project/panels/your-panel/
index.html
style.css
script.jsEdit them with any editor. They live in the project folder, so they are backed up and synced with everything else. The Custom tab in the Panel editor has an Open folder button, and a Reload preview button to pick up your changes.
The Panel API
Lightpath injects window.lightpath into your page automatically — there is no
script tag to add and no key to configure.
<button id="warm">Warm evening</button>
<script>
document.getElementById("warm").onclick = () => {
lightpath.applyContent("Warm Evening");
};
</script>Every call is checked on the server, so a Panel can never do more than a Panel is allowed to do, whatever its code asks for. Calls that would author or delete content are refused.
Reading what's happening
| Property | What it holds |
|---|---|
lightpath.state | Live playback: what is on each output, brightness, whether things are running |
lightpath.content | Everything available to activate — looks, scenes, sequences, playlists |
lightpath.outputs | The outputs in this project |
lightpath.theme | This Panel's accent and mode |
lightpath.config | TouchDesigner parameters, by the names shown in the app |
lightpath.devices | Device controls, by the names shown in the app |
lightpath.schedule | What the calendar holds |
lightpath.health | Machine health |
lightpath.alerts | Recent alerts |
These refresh on their own. To react to a change:
const stop = lightpath.on("state", (state) => {
document.body.dataset.playing = state.outputs[0]?.activeLookName ?? "";
});
// stop() when you no longer careon also takes "ready" and "error".
Making something happen
| Call | What it does |
|---|---|
applyContent(name, type?) | Activate a look, scene, sequence or playlist |
applyPalette(name, opts?) | Recolor what is playing — a live override, not a saved edit |
setDimmer(output, 0..1) | Set an output's brightness |
setOutputEnabled(output, bool) | Turn an output on or off |
transport(command, opts?) | pause, resume, stop, toggleLoop, selectTrack |
setAction(name, value?) | Fire an action or set a toggle |
setConfigParameter(key, value) | One TouchDesigner parameter, e.g. "outputs/LEDs/Speed" |
runDeviceControl(key, value?, deviceId?) | One device control, e.g. "Projector/Power". Pass a device's ID to run a group's control on just that device. |
readDeviceControl(key) | Ask a device for a control's current state |
refreshHealth() | Sample machine health now |
Images and video
img.src = lightpath.getThumbnailUrl("Warm Evening", "look");getSourceThumbnailUrl(source) gives the raw pattern image before any palette.
attachStream(el, target) puts live video — an output preview or a camera feed
— into a <video> or a <canvas>, and returns a handle with .stop().
Styling with the Panel's brand
The accent and mode you pick in the editor arrive as CSS variables, so your stylesheet can follow the Panel's branding instead of hard-coding colors:
button {
background: var(--lp-accent);
color: var(--lp-mode-text);
}What your code cannot do
A Custom Panel runs in an isolated frame. It has no access to the Lightpath
app's page, no login token, and no cookies. It cannot make its own network
requests — everything goes through window.lightpath, which applies the Panel's
role to each request.
This is deliberate, and it is what makes it safe to put someone else's HTML on a wall tablet: the worst a mistake in your code can do is the same as what a person holding that tablet could already do.
Pages and groups
Two ways to fit more into a Panel than one screenful, and they work at different scales.
A page is a screen of its own. Add a second page and the Panel grows a nav bar along the bottom, one entry per page, and shows one page at a time. Use pages for things a person is doing separately — lights on one page, music on another.
A group is one tile that holds several widgets, switched by tabs across its top. Everything else on the page stays put. Use a group for a few things that belong in the same spot — a scene picker and a brightness pad in one corner.
Both are built on the Arrange tab, by dragging. Drag a widget onto a group to put it in; drag it back out to give it its own tile again. A group's tab order is the order its widgets appear underneath it, and dragging a group by its handle moves the whole thing, contents included. Deleting a group is not deleting its widgets — they fan back out where the group was. Nor is deleting a page: its contents move to the page above it.
Tablet and phone layouts
A widget Panel has two layouts: one for tablets and wall displays, one for phones. The screen picks between them by width alone. Below 640 pixels wide it gets the phone layout; anything wider gets the tablet layout. A phone turned sideways is wider than that, so it gets the tablet layout.
Phones and tablets want different things. A tablet usually has room for everything on one screen. On a phone it is better to give each widget the full height and spread them across a few pages. So each layout has its own:
- Pages — a tablet layout with one page and a phone layout with four is normal.
- Order — which page each widget is on, and where on it.
- Size — on a tablet, each widget is 1/2 or Full width. On a phone everything is full width, so height is the only size.
- Visibility — the eye on each row in the Arrange list hides that widget on the layout you are editing, and only that one.
Everything else is shared. The widgets themselves and their settings are the same on both, and so are groups: what is grouped with what, and the tab order. Remove a widget and it is gone from both. To take it off just one layout, use the eye instead.
Switch between the two with Tablet and Phone at the top of the Arrange tab. The preview, the Arrange list and the size controls all follow that switch, so what you drag is always what you see. A widget you add appears at the end of the other layout too. Move it where you want it there, or hide it with the eye.
Height
Height is a share of the screen: 1/3, 1/2, 2/3 or Full. Two widgets at 1/2 stacked in a column fill the screen exactly, and so do 1/3 and 2/3. The screen here is the part under the header bar and above the page nav bar.
Some widgets need a minimum height for what you have turned on — a two-row scene picker needs 1/2 — and some have nothing more to show past a certain height. Those sizes are not offered.
If a column adds up to more than one screen, the page scrolls. The preview shows a dashed line where the screen ends, so you can see what a viewer will have to scroll to.
In the editor, the toolbar over the preview lets you check the layout at real device sizes — iPad, iPhone, Pixel, a 1080p wall display — and rotate a tablet between portrait and landscape. Changing the preview size never changes the Panel.

