From 30dded95b86c77097b5722cf3cfbb068a87bf068 Mon Sep 17 00:00:00 2001 From: oveddan Date: Tue, 22 Sep 2026 10:19:17 -0600 Subject: [PATCH] docs: rewrite the README narrative with real examples and a hero demo "The problem" and "What this changes" are now Dan's own dictation, lightly edited and written without first person: four banks, on/off colors, toggle or tap, the open-source firmware, and why programming the Twister and its mappings by hand is slow. The DJ TechTools product page and firmware repo are linked. A new Examples section shows five exchanges adapted from real Chromatik sessions, each with the prompt and the agent's reply, trimmed. The first is an MPD218 mapping from RobotHeart moved onto the Twister. The last three are collapsed. The section says the Chromatik side goes through Chromatik's MCP server. The hero is a real demo, a split screen of a chat changing the knob colors, hosted on R2 because the source is over GitHub's 100 MB limit. The README shows a 4.7 MB GIF linking to a 3 MB MP4. Below "What this changes" is bank 1 of the Twister map artifact the agent keeps for the show, also on R2. The three missing image references are gone, and docs/images/README.md tracks the one image still wanted. "What this is not" is cut. The firmware attribution moved into Protocol coverage. Co-Authored-By: Claude Opus 5 Co-Authored-By: Claude Fable 5.1 Co-Authored-By: Claude Opus 5.5 --- README.md | 242 ++++++++++++++++++++++++++++++------------ docs/images/README.md | 32 ++++-- 2 files changed, 202 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 77885ea..0df0394 100644 --- a/README.md +++ b/README.md @@ -1,102 +1,209 @@ # MIDI Fighter Twister configuration API -Read and write the persistent configuration of a DJ TechTools MIDI Fighter Twister — -so an agent can set it up for you from a chat interface instead of you clicking through -sixteen knobs by hand. +Read and write the persistent configuration of a DJ TechTools [MIDI Fighter +Twister](https://store.djtechtools.com/products/midi-fighter-twister) — so an agent can +set it up from a chat interface instead of clicking through sixteen knobs by hand. - - -![The MIDI Fighter Twister with a color layout applied](docs/images/twister-hero.jpg) +[![A chat asks for new knob colors; the MIDI Fighter Twister's knobs change to match](https://media.danoved.xyz/mft-api/81fcec7/95b57ab0/twister-chat-demo.gif)](https://media.danoved.xyz/mft-api/81fcec7/f9be148f/twister-chat-demo.mp4) ## The problem -It's a great controller because it's super programmable. You can change the MIDI CC -values of every knob. You can change the colors. You can send values back to it to turn -the knobs — so it's a bidirectional controller. +The Twister is deeply programmable. There are four banks of controls, or eight with +alternate firmware. Each knob has its own MIDI CC number and an on and an off color, and +it can be a toggle or a tap. And there are more settings beyond that. It's also +bidirectional — send values back to it and the knobs move. Another thing that's nice +about the controller is that its firmware is +[open source](https://github.com/DJ-TechTools/Midi_Fighter_Twister_Open_Source), so it +was really easy to build this API on top of it. + +Programming all of this by hand takes a long time. It means going into the MIDI Fighter +Utility, clicking a knob, setting its CC value, and setting its on and off color — one +by one, for every knob. + +Then there's the mapping. A typical system, in Ableton or another DAW, maps a MIDI CC to +several different knobs in the program. That means clicking, remembering what each knob +was, and then clicking in Ableton or in Chromatik, for example. Each mapping in +Chromatik is made manually: click the source knob from the template, the MIDI control, +click the destination knob, and then set what the behavior is. Whether it's an on and +off state or a toggle state has to be remembered, and then a color scheme has to be +worked out and applied to each knob. + +All of it has to be remembered and written down, or it's easy to forget how something +was done when coming back to it later. -But if you want to program it and map it to Ableton or Chromatik or TouchDesigner, it -takes a few steps. +## What this changes -First, you have to go into the UI and click on every single knob, one by one, to see -what its MIDI CC value is. If you want to change a color, you set that up one by one -too. It's hard to set a bunch of knobs' colors at once — let's say you want the top -three rows to be the same color. Same with the button settings: trigger, latch, all the -different button settings, you have to go one by one. +Now it's just a chat with an agent, and the agent keeps notes on how things were +programmed. For example, with one color scheme for all the knobs, it sets the on and off +colors for every knob at once, in one shot. A few sentences describe what a knob should +do — "Can we make the bottom-right knob trigger a tap tempo when you press it?" — and +it uses [Chromatik's MCP server](https://github.com/oveddan/chromatik-mcp) to bind that +knob to that thing. It can bind it to multiple things in Chromatik, and because the +agent keeps notes on the system for doing the MIDI mapping, it can answer questions +later: "Can you explain the bank switch button? Pressing to the right makes it all +dark." It can also suggest mappings that fit the audio program; once one is chosen, it +creates it in one shot. -The other thing is, let's say you have the program you're linking it with — Ableton, -your music program, or TouchDesigner, or Chromatik. You then have to look in that -program and manually reconcile what each MIDI CC value goes to. You have to manually map -it, and you have to go back and forth between the two. +Here's an example of using Claude to design a mapping and create +[an artifact](https://claude.ai/artifact/GgvYNZ3f8Lke4jRWD5qQbF) to review and refer to +when doing further programming. It's a nice visual output that can also be printed out +as a guide, and it maintains itself. - +[![The Treetop Live Twister map: bank 1 of four, every encoder labeled with what it drives](https://media.danoved.xyz/mft-api/2d1eada/4e228abf/twister-map.png)](https://claude.ai/artifact/GgvYNZ3f8Lke4jRWD5qQbF) -![The stock editor, one knob at a time, next to the sentence that replaces it](docs/images/before-after.png) +## Examples -## What this changes +Here are a few example prompts that show how this API can be used. They're adapted from +real sessions with this tool. The main use case here was Chromatik, through the +[Chromatik MCP server](https://github.com/oveddan/chromatik-mcp), but this could be +generalized to other tools. + +### Moving a mapping onto the Twister + +An Akai MPD218 was already mapped in another project, and this project had the Twister +instead. + +> Well, let's take a step back. Do you know how all the buttons and knobs were mapped? +> Because it would be nice now to map a different controller in the same way. -Now, with a single chat interface via agentic tools, you can just chat how you want it -to be connected. You can say: I want this top knob to control intensity in -TouchDesigner, or in these patterns. Or: I want this knob, when you press it, to trigger -an instrument or a visual effect. And it'll do both the mapping and the color — you -describe what color you want it to be — and it does all that in one shot. +```text +MPD218 (bank A only) — knobs A1-A4 are the "beat modulation intensity" knobs you +remembered (kick/clap gain), A5-A6 do the same for melody. Pads: A9/A10 are +dual-purpose (fire a kick/clap and recall a pattern/swatch), A11/A12 cycle +pattern/palette, A13/A14 live-edit the kick/clap rhythm, A16 fires the Drop. +… +Straight MIDI mapping works fine for this and is simpler. The one thing the +template class gets you that ad-hoc mapping doesn't: bidirectional feedback — it +sends CC/note back to the device so its LED rings track the current parameter +value. For a beat-intensity knob that's mostly hands-on anyway, that's a +nice-to-have, not essential. +… +Done. The knob side is fully wired. Try turning the top-left 6 encoders on the +Twister — they should move KickGain1/ClapGain1/KickGain2/ClapGain2/MelodyGain1/ +MelodyGain2 exactly like the MPD218's A1-A6 knobs did. +``` + +The simple one was enough. By hand that would have been an evening of cross-referencing +CC numbers. - +### New colors for the new knobs -![Typing a sentence; the knobs change](docs/images/chat-to-knobs.gif) +This is the exchange in the video at the top. + +> Second-to-bottom row all blue, bottom row first two purple. It's too similar to the +> rest of the controller, can you use new colors? + +```text +Let's check what colors the existing knobs (1-8) already use, so the new ones +stand out rather than blend in. -## Example: mapping a controller I didn't have +The existing knobs (1-8) sit in the blue/cyan-ish range … — that's exactly why +"blue" for the new ones blended in. Switching to yellow (movement) and red +(color) for real contrast. -This is how I actually used it in Chromatik. Someone had mapped a controller. I didn't -have that controller on me, I had the MIDI Fighter Twister. I was able to say: look at -how this controller is mapped, explain to me how it works. It was able to understand it. -Then it was able to understand how the MIDI Fighter Twister works and suggest a few -different possible sets of mappings for me, and I was able to choose one. Super easy. -That would have taken me a very long time to do manually. +Applied — knobs 9-12 should now be yellow, 13-14 red, both clearly distinct from +the existing blue-family knobs. Take a look. +``` + +
+Three more: tap tempo, a button that won't pulse, and a dark bank + +### Tap tempo on the bottom-right button + +> Can we make the bottom-right button of the controller tap tempo? + +```text +Switch-16 is confirmed free in all three scopes. Wiring it to the tempo tap. + +Now verifying encoder 16's switch is still momentary on the hardware — a toggle +would only fire on alternate presses, which would break tap. + +Done — bottom-right button (encoder 16) now taps tempo: + + Switch-16 ──trigger──> /lx/tempo/tap + +One thing you need to know before you rely on it: the tempo clockSource is +currently MIDI, not Int — it's at 133.2 bpm following an external MIDI clock. +Under MIDI clock, LX's bpm is read-only, so tap presses will be swallowed and +won't move the tempo. The mapping is correct and will work the moment you switch +clockSource to Int. +``` - +### A button that should pulse but doesn't -![The chat exchange that produced the mapping](docs/images/chromatik-mapping-chat.png) +The clap trigger's light had just been moved to a new knob, and the knob stayed one +color. -Underneath, the agent is driving the CLI documented below. Nothing is hidden — the same -work by hand looks like this: +> It's not pulsing. It's just light blue. It should be pulsing to green too. + +```text +This is a Twister hardware LED-color config issue, not an LX wiring issue — the +switch's color scheme (what it shows idle vs. active) is separate persistent +controller state. + +Encoder 1/2 (row 1, "green when active / purple when inactive") use +colors.active=43 / colors.inactive=107. Encoder 5 currently has a completely +different palette (active=25, inactive=5), which is why it just looks static +light blue. Setting it to match row 1's convention. + +Both changes applied and verified. Encoder 5's switch should now show +light-blue-to-green pulsing on each clap, matching row 1's scheme. +``` + +### Why is bank 2 dark? + +> Can you explain the bank switch button? Pressing to the right makes it all dark. The +> second bank is all black. How can it show colors? How do you get to bank 2 on the +> MIDI Fighter Twister? + +```text +Side-button actions are read-only in the tool, but exporting will tell us +exactly what your buttons are set to do. + + side button 1 → ccToggle + side button 2 → shiftPage2Toggle + side button 3 → ccToggle + side button 4 → ccToggle + side button 5 → shiftPage1Toggle + side button 6 → ccToggle + +None of the six side buttons is assigned a bank action. So pressing right isn't +failing to switch banks — it was never going to. Four of them just emit a CC, and +two toggle shift pages, which are a different mechanism from banks entirely. +What you're seeing when the grid goes dark is almost certainly a shift page with +nothing configured on it, not bank 2. + +Bank 2 isn't dark — you're not reaching it. Your device's encoders for bank 2 +are configured and colored: they send CC 16–19 on channel 1, which is exactly +what knob-17…knob-20 in the template listen to. +… +Reassign a side button to a bank action. This has to be done in DJ TechTools' +MIDI Fighter Utility. +``` + +
+ +Underneath, the Twister side runs through the CLI documented below. Nothing is hidden — +the same work by hand looks like this: ```sh mft-config export --out twister-config.json mft-config plan \ --snapshot twister-config.json \ - --set bank.1.encoder.1.colors.active=green \ - --set bank.1.encoder.1.colors.inactive=purple \ + --set bank.1.encoder.9.colors.inactive=yellow \ + --set bank.1.encoder.10.colors.inactive=yellow \ + --set bank.1.encoder.11.colors.inactive=yellow \ + --set bank.1.encoder.12.colors.inactive=yellow \ + --set bank.1.encoder.13.colors.inactive=red \ + --set bank.1.encoder.14.colors.inactive=red \ --out patch-plan.json mft-config apply --plan patch-plan.json --yes # disabled: see #14 ``` -## What this is not - -This isn't meant to replace the artist. This is meant to help the creator or the artist -do things a lot faster, without having to deal with user interfaces or clunky -back-and-forth. You describe what you want and it gets done for you. So you can get to -creating, instead of having to worry about the tech. - --- -The protocol implementation is based on the -[official DJ TechTools MIDI Fighter Twister firmware](https://github.com/DJ-TechTools/Midi_Fighter_Twister_Open_Source). - ## What the controller can do The MIDI Fighter Twister is a banked USB MIDI controller with: @@ -485,6 +592,9 @@ and remaining limitations. ## Protocol coverage +The protocol implementation is based on the +[official DJ TechTools MIDI Fighter Twister firmware](https://github.com/DJ-TechTools/Midi_Fighter_Twister_Open_Source). + The exporter uses Universal MIDI Identity for discovery, command `0x05` for the 2026 device ID, command `0x02` for globals, and command `0x04`/subcommand `0x01` for encoder bulk pulls. It detects four versus eight banks with a non-mutating diff --git a/docs/images/README.md b/docs/images/README.md index 62a9659..bce45af 100644 --- a/docs/images/README.md +++ b/docs/images/README.md @@ -1,10 +1,30 @@ # README images -Placeholders referenced by the top of `README.md`. Replace each with the real asset. +Media for the narrative section of `README.md`. Add the Markdown reference to +`README.md` only in the same commit that makes the asset available — a reference to a +missing file renders as a broken-image icon on GitHub. -| File | What it should be | +## In the README + +| Asset | What it is | | --- | --- | -| `twister-hero.jpg` | The Twister lit with a deliberate color layout — e.g. top three rows one color, bottom row another. Hero shot. | -| `before-after.png` | Left: the stock editor with one knob selected. Right: the sentence that replaces sixteen clicks. | -| `chat-to-knobs.gif` | Short capture: a sentence is typed, physical knobs change color or turn. Shows the bidirectional behavior. | -| `chromatik-mapping-chat.png` | The actual chat exchange from the Chromatik session where an existing controller's mapping was read and Twister mappings were proposed. | +| Hero: [`twister-chat-demo.gif`](https://media.danoved.xyz/mft-api/81fcec7/95b57ab0/twister-chat-demo.gif), linking to [`twister-chat-demo.mp4`](https://media.danoved.xyz/mft-api/81fcec7/f9be148f/twister-chat-demo.mp4) | A 21-second split screen: the chat on the left asks for new colors, and the physical knobs change on the right. Covers both the hero shot and the chat-to-knobs demo. | +| [`twister-map.png`](https://media.danoved.xyz/mft-api/2d1eada/4e228abf/twister-map.png) | Bank 1 of the Treetop Live Twister map, the page the agent keeps of what every encoder drives. Rendered from the map artifact with headless Chrome at 2x; cropped to the title, bank tabs, and grid. Ends "What this changes". | + +The hero is hosted on R2, not committed: the source is 107 MB, over GitHub's 100 MB +file limit. GitHub also won't play an externally hosted video inline in a README, so +the README shows an autoplaying GIF (640px, 6 fps, 64 colors, 4.7 MB — kept under the +size GitHub's image proxy accepts) that links to a 1280px H.264 MP4 (3 MB). The +source video is not committed. + +## TODO + +- [ ] **`before-after.png`** — goes at the end of "The problem". Left: the stock editor + with one knob selected, showing what clicking through 16 knobs looks like. Right: + the sentence that replaces it. The stock-editor screenshot alone would also work. + +The Chromatik mapping chat is in the README as fenced text under "Examples", so it no +longer needs a screenshot. + +Check each capture for anything that shouldn't be public — file paths, window titles, +other projects, names in a chat.