Skip to content

abossard/qlcplus

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10,007 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QLC+ Logo

Q Light Controller+

⚠️ EXPERIMENTAL FORK — USE AT YOUR OWN RISK ⚠️

This fork was largely vibe-coded with AI pair-programming. It has NOT been through upstream code review or formal QA. Do NOT submit PRs to upstream from this fork.

For the official QLC+ project, go to: mcallegari/qlcplus

This fork adds an MCP (Model Context Protocol) server that lets AI agents (Copilot, Claude, Cursor, etc.) design and control lighting shows via natural language.

What this fork adds

  • mcp/ directory: Self-contained MCP server — 47 tools, 3 prompts, 230 unit tests
  • Streamable HTTP transport on http://localhost:9696/mcp (auto-starts with app)
  • Function Wizard for QML UI
  • Launchpad controller integration support
  • Audio capture / BPM detection for scripts

Install from DMG (macOS)

Download the latest DMG from Actions artifacts. After mounting the DMG and dragging QLC+ to /Applications:

sudo xattr -cr /Applications/QLC+.app   # clear quarantine (ad-hoc signed)
open /Applications/QLC+.app

Build from source

mkdir build && cd build
cmake -Dqmlui=ON -Dmcp_server=ON ..
make -j$(sysctl -n hw.ncpu)
./qmlui/qlcplus-qml   # MCP auto-starts on port 9696

Disable MCP with --no-mcp, or change port with --mcp-http <port>.

Connect your AI agent

Copilot CLI / VS Code — add to ~/.copilot/mcp.json:

{
  "servers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Claude Code — run:

claude mcp add qlcplus --transport http http://localhost:9696/mcp

Claude Desktop — add to claude_desktop_config.json:

{
  "mcpServers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Cursor — add to .cursor/mcp.json:

{
  "mcpServers": {
    "qlcplus": { "url": "http://localhost:9696/mcp" }
  }
}

Available tools (47)

Category Tools
Query query_fixtures, query_available_fixtures, query_functions, query_fixture_channels, query_palettes, query_universes, query_input_profiles, query_midi_devices, query_osc_status, query_channel_modifiers, query_feedback_profile
Patch patch_fixtures
Functions create_scenes, create_chasers, create_sequences, create_efxs, create_collections, create_rgb_matrices, create_scripts, create_fixture_groups, update_scene_from_dmx, delete_functions
Palettes create_palettes, delete_palettes
Channels configure_channels, read_dmx_values, set_channel_modifiers, convert_degrees_to_dmx, set_grand_master
I/O configure_universes, configure_plugin_params, configure_osc, configure_beat_source, configure_launchpad, set_input_profile, vc_configure_feedback
Virtual Console vc_create_pages, vc_create_widgets, vc_query_pages, vc_query_widgets, vc_update_widgets, vc_delete_widgets, vc_reparent_widgets
VC Input vc_map_inputs, vc_set_key_sequences, vc_detect_overlaps
VC Layout vc_reflow_frame

Prompts: design_dj_show, debug_channel_conflict, setup_launchpad

All tools are batch-based (arrays in, arrays out) and idempotent (upsert by name). See mcp/MCP-ARCHITECTURE.md for full documentation.

Script Engine (JavaScript)

create_scripts accepts raw JavaScript executed by QJSEngine in a dedicated thread. Scripts are validated before saving — syntax errors are rejected with line numbers.

Full Engine API (25 methods)

Function Control:

Method Returns Description
Engine.startFunction(id) bool Start any QLC+ function
Engine.stopFunction(id) bool Stop a running function
Engine.isFunctionRunning(id) bool Check if function is active
Engine.waitFunctionStart(id) bool Block until function starts
Engine.waitFunctionStop(id) bool Block until function stops
Engine.stopOnExit(bool) bool Auto-stop started functions on script exit

Fixture Control:

Method Returns Description
Engine.setFixture(fxID, ch, val) bool Set fixture channel (0-255)
Engine.setFixture(fxID, ch, val, fadeMs) bool Set with fade time
Engine.getChannelValue(universe, ch) int Read live pre-GM DMX value

Timing:

Method Returns Description
Engine.waitTime(ms) bool Pause execution (ms)
Engine.waitTime("2s.500") bool Pause using time string
Engine.random(min, max) int Random integer in [min,max]
Engine.random("1s.0", "5s.0") int Random ms from time strings

BPM & Beat:

Method Returns Description
Engine.setBPM(bpm) bool Set beat generator BPM
Engine.getBPM() int Current BPM (internal/MIDI/audio)
Engine.getBeatDuration() int Beat period in ms
Engine.isBeat() bool True if current tick is on a beat

Audio Input:

Method Returns Description
Engine.getAudioLevel() int Overall volume 0-255
Engine.getAudioFrequency(band, numBands) int Frequency band 0-255 (3=bass/mid/high, 16=detailed)

Envelope (from parent Chaser/Collection):

Method Returns Description
Engine.getOwnID() int This script's function ID
Engine.getElapsed() int Ms since script started
Engine.getEnvelopeDuration() int Allocated duration from parent (ms, 0 if standalone)
Engine.getEnvelopeFadeIn() int Fade-in from parent (ms, 0 if not set)
Engine.getEnvelopeFadeOut() int Fade-out from parent (ms, 0 if not set)

Function Attributes:

Method Returns Description
Engine.getFunctionAttribute(id, idx) float Read function attribute
Engine.setFunctionAttribute(id, idx, val) bool Modify running function attribute
Engine.setFunctionAttribute(id, "Name", val) bool By name (e.g. "Width", "Intensity")

System:

Method Returns Description
Engine.setBlackout(bool) bool Toggle global blackout
Engine.systemCommand("prog args") bool Run external process (detached)
Example patterns
// Candle flicker — Gaussian random, warm colors
function gaussRand(mean, std) {
    var u1 = Math.random(), u2 = Math.random();
    return mean + std * Math.sqrt(-2*Math.log(u1)) * Math.cos(2*Math.PI*u2);
}
for (var tick = 0; tick < 200; tick++) {
    for (var c = 0; c < 6; c++) {
        Engine.setFixture(c, 0, Math.max(100, Math.min(255, Math.round(gaussRand(210, 25)))));
    }
    Engine.waitTime(Engine.random(30, 120));
}

// Envelope-adaptive buildup — reusable across different chaser step durations
var totalMs = Engine.getEnvelopeDuration();
if (totalMs <= 0) totalMs = 5000;
var steps = Math.round(totalMs / 25);
for (var i = 0; i <= steps; i++) {
    Engine.setFixture(0, 0, Math.round(255 * i / steps));
    Engine.waitTime(25);
}

// Audio-reactive — bass drives brightness, mid drives color
for (var tick = 0; tick < 500; tick++) {
    var bass = Engine.getAudioFrequency(0, 3);
    var mid = Engine.getAudioFrequency(1, 3);
    Engine.setFixture(0, 0, bass);
    Engine.setFixture(0, 1, mid);
    Engine.waitTime(25);
}

(Often abbreviated as "QLC+")

Open-source lighting control for DMX, Art-Net, sACN and more.
Designed for live shows, theatre, architectural installations, and venues.

Latest release version badge Release date badge Commits since latest release badge Weekly commit activity badge Build status badge Test coverage badge


Download QLC+ badge Raspberry Pi badge Official store badge

Introduction

QLC+ is powerful and user-friendly software to control lighting. QLC+ supports a huge amount of hardware, runs on Linux, Windows (10+), macOS (10.12+), and Raspberry Pi. Whether you're an experienced lighting professional or just getting started, QLC+ empowers you to take control of your lighting fixtures with ease. The primary goal of this project is to bring QLC+ to the level of available commercial software.

Supported protocols

MIDI OSC HID DMX ArtNet E1.31/S.ACN OS2L

QLC+ on social media

Instagram YouTube Facebook

Support & bug reports

We have a dedicated page to help you find support, please check out SUPPORT.md. To learn about a specific feature of QLC+, take a look at the official documentation. To give feedback, submit new fixtures and get new ideas, go to the forum

Help wanted

Click the badge below to see the currently confirmed issues with QLC+. Perhaps you can find a solution?

Help Wanted

Building QLC+

Compilation guides and platform-specific instructions are available in our GitHub Wiki.

Developers at work

If you're regularly updating QLC+ sources with git pull, you may encounter compiler warnings, errors, or unresolved symbols. We strive to keep the master branch free of critical errors; however, dependencies between objects can sometimes cause issues, requiring a full package recompilation rather than just updating recent changes.

Contributing

Software development

We welcome contributions from the community to help make QLC+ even better. If you're working on something major, start a thread in the Development Forum first. Make sure you read the CONTRIBUTING.md document for more.

Financially

If you're reading this we already appreciate you. If you're just getting started with lighting you have absolutely no obligation to give us money. When QLC+ opens up revenue opportunities for you, we'd be very thankful for your support. GitHub sponsors is the preferred option.

GitHub Sponsors

If you're interested, QLC+ also has an official store where you can purchase clothing, themes, the Raspberry Pi image or one-on-one consultation with an expert.

Thank you!

QLC+ owes its success to the dedication and expertise of numerous individuals who have generously contributed their time and skills. The following list recognizes those whose remarkable contributions have played a pivotal role in building QLC+.

GitHub contributors

QLC+ 5
  • Eric Arnebäck (3D preview features)
  • Santiago Benejam Torres (Catalan translation)
  • Luis García Tornel (Spanish translation)
  • Nils Van Zuijlen, Jérôme Lebleu (French translation)
  • Felix Edelmann, Florian Edelmann (fixture definitions, German translation)
  • Jannis Achstetter (German translation)
  • Dai Suetake (Japanese translation)
  • Hannes Bossuyt (Dutch translation)
  • Aleksandr Gusarov (Russian translation)
  • Vadim Syniuhin (Ukrainian translation)
  • Mateusz Kędzierski + smaks6 (Polish translation)
QLC+ 4
  • Jano Svitok (bugfix, new features and improvements)
  • David Garyga (bugfix, new features and improvements)
  • Lukas Jähn (bugfix, new features)
  • Robert Box (fixtures review)
  • Thomas Achtner (ENTTEC wing improvements)
  • Joep Admiraal (MIDI SysEx init messages, Dutch translation)
  • Florian Euchner (FX5 USB DMX support)
  • Stefan Riemens (new features)
  • Bartosz Grabias (new features)
  • Simon Newton, Peter Newman (OLA plugin)
  • Janosch Frank (webaccess improvements)
  • Karri Kaksonen (DMX USB Eurolite USB DMX512 Pro support)
  • Stefan Krupop (HID DMXControl Projects e.V. Nodle U1 support)
  • Nathan Durnan (RGB scripts, new features)
  • Giorgio Rebecchi (new features)
  • Florian Edelmann (code cleanup, German translation)
  • Heiko Fanieng, Jannis Achstetter (German translation)
  • NiKoyes, Jérôme Lebleu, Olivier Humbert, Nils Van Zuijlen (French translation)
  • Raymond Van Laake (Dutch translation)
  • Luis García Tornel (Spanish translation)
  • Jan Lachman (Czech translation)
  • Nuno Almeida, Carlos Eduardo Porto de Oliveira (Portuguese translation)
  • Santiago Benejam Torres (Catalan translation)
  • Koichiro Saito, Dai Suetake (Japanese translation)
Q Light Controller
  • Stefan Krumm (Bugfixes, new features)
  • Christian Suehs (Bugfixes, new features)
  • Christopher Staite (Bugfixes)
  • Klaus Weidenbach (Bugfixes, German translation)
  • Lutz Hillebrand (uDMX plugin)
  • Matthew Jaggard (Velleman plugin)
  • Ptit Vachon (French translation)


License

GitHub License badge

Licensed under the Apache 2.0 License. See COPYING for details.


Copyright © Heikki Junnila, Massimo Callegari

C++ badge Qt badge CMake badge JavaScript badge

About

Q Light Controller Plus (QLC+) is a free and cross-platform software to control DMX or analog lighting systems like moving heads, dimmers, scanners etc. This project is a fork of the great QLC project written by Heikki Junnila that aims to continue the QLC development and to introduce new features.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • C++ 70.4%
  • QML 14.3%
  • HTML 7.2%
  • JavaScript 3.5%
  • CMake 1.7%
  • C 1.0%
  • Other 1.9%