Skip to content

Releases: djenttleman/ReaSet

v3.0 — Armed transport, setlists that live with the project, and a new licence

Choose a tag to compare

@djenttleman djenttleman released this 11 Aug 05:20
dea2bbd

Install

Copy ReaSet.html and Sortable.min.js into REAPER's web root (the folder with main.js), then load Reaset.lua via Actions → ReaScript: Load… and run it once. Add it to your startup actions so it launches with REAPER.

Upgrading from v2.x: replace all three files. Your setlists migrate themselves the first time you open ReaSet with a saved project.


English

Licence — please read

ReaSet is now proprietary and free to use. You may use it for anything, including commercially, on as many machines as you like, and share unmodified copies. Selling it, or distributing modified versions, needs written permission. See LICENSE.

This is not retroactive. Versions up to v2.x were GPL v3 and stay GPL v3 for anyone who has them, permanently. You keep every right you had in those versions.

The change was possible because Reaset.lua never actually derived from the X-Raym scripts its own header claimed to inherit from — a line-by-line comparison finds 18 identical lines out of 119, and every one of them is end or break. Zero shared functions. X-Raym's own scripts in Legacy/ keep their GPL v3 and their authorship. Full evidence in docs/RELICENSING.md.

Transport — arm, don't detect

The end of a song used to be detected by the browser, which then sent a stop. That path can never be punctual: ~60 ms poll, plus a 72–107 ms round-trip, plus — the part that took longest to find — Main_OnCommand does not stop the transport on the spot. It stops it on the next audio block. A reposition landing in that gap runs while the transport is still rolling, so it seeks playback into the next song.

  • Auto-stop is now armed in advance. ReaSet tells REAPER where to stop before it matters, so REAPER stops in its own audio engine at the exact sample and no command travels at the critical moment. Measured on a real region transition: stops 10.7 ms before the boundary, never crossing it. Fixes the next song being briefly audible at the end of the current one.
  • If arming is not possible (no SWS, for instance) the old detection stays as the fallback. Losing precision is acceptable; losing auto-stop is not.
  • MIDI Init redesigned. It used to jump to the start of the next song and play ~100 ms there, which made that song's opening audible every single time. Now the transport simply starts 5 ms before the song you asked for.
  • Repositioning after a stop waits for the transport to confirm it stopped, instead of guessing with a timer shorter than the measured round-trip.

Setlists now live with the project

Setlists used to exist only in the localStorage of whichever browser built them. Open ReaSet on the iPad and your show was not there. Clear the browser's data and it was gone.

  • Setlists are now stored in <project folder>/reaset/setlists/, one JSON file each, written by Reaset.lua. They travel with the .rpp, they can be backed up and versioned, and a human can open and read them.
  • The disk is the only source of truth. The browser is a client, not a store — so a setlist built on the iPad shows up on the laptop with no merge at all, because both read the same file.
  • If the project cannot be read, ReaSet says so in the setlist dropdown and blocks saving, rather than letting you edit a phantom copy that will never be written.
  • Requires the project to have been saved at least once.
  • New Tools/ReaSet_LibraryDoctor.lua (read-only) reports which link broke when a setlist is not saving.

Fixed

  • Director→Player setlist sync silently dropped most edits. It triggered on the chunk count changing, and toggling a skip flag moves the payload by three characters — so the count stayed identical and the shared file was never rewritten. Players kept showing the old setlist with no sign anything had failed.
  • The web-interface directory was hardcoded, and on installs where that path is wrong, io.open fails silently: the file is never written, the browser gets a 404, and nobody returns an error. Now resolved by finding where ReaSet.html actually lives.

Español

Licencia — leer

ReaSet pasa a ser propietario y de uso gratuito. Podés usarlo para lo que quieras, incluso comercialmente, en las máquinas que quieras, y compartir copias sin modificar. Venderlo, o distribuir versiones modificadas, requiere permiso escrito. Ver LICENSE.

No es retroactivo. Las versiones hasta la v2.x fueron GPL v3 y lo siguen siendo para quien las tenga, para siempre. Conservás todos los derechos que tenías sobre esas versiones.

El cambio fue posible porque Reaset.lua nunca derivó realmente de los scripts de X-Raym que su propia cabecera decía heredar: la comparación línea a línea da 18 líneas idénticas sobre 119, y todas son end o break. Cero funciones compartidas. Los scripts de X-Raym en Legacy/ conservan su GPL v3 y su autoría. La evidencia completa está en docs/RELICENSING.md.

Transporte — armar, no detectar

El fin de una canción lo detectaba el navegador, que entonces mandaba un stop. Ese camino no puede ser puntual: poll de ~60 ms, más 72–107 ms de ida y vuelta, más —lo que más costó encontrar— Main_OnCommand no detiene el transporte en el acto: lo detiene en el próximo bloque de audio. Una reposición que caiga en ese hueco se ejecuta con el transporte todavía rodando, así que lleva la reproducción a la canción siguiente.

  • El auto-stop ahora se arma por adelantado. ReaSet le dice a REAPER dónde parar antes de que importe, así REAPER para en su propio motor de audio en la muestra exacta y no viaja ningún comando en el momento crítico. Medido en una transición real de regiones: para 10,7 ms antes del límite, sin cruzarlo nunca. Corrige que se escuche brevemente la canción siguiente al final de la actual.
  • Si armar no es posible (sin SWS, por ejemplo) la detección vieja queda como respaldo. Perder precisión es aceptable; perder el auto-stop no.
  • MIDI Init rediseñado. Saltaba al inicio de la canción siguiente y reproducía ~100 ms ahí, lo que hacía audible el comienzo de esa canción siempre. Ahora el transporte simplemente arranca 5 ms antes de la canción que pediste.
  • La reposición tras un stop espera a que el transporte confirme que paró, en vez de adivinar con un temporizador más corto que la ida y vuelta medida.

Los setlists ahora viven con el proyecto

Los setlists existían solo en el localStorage del navegador que los armó. Abrías ReaSet en el iPad y tu show no estaba. Borrabas los datos del navegador y se iba.

  • Se guardan en <carpeta del proyecto>/reaset/setlists/, un archivo JSON cada uno, escritos por Reaset.lua. Viajan con el .rpp, se pueden respaldar y versionar, y los puede abrir y leer una persona.
  • El disco es la única fuente de verdad. El navegador es un cliente, no un almacén — así que un setlist armado en el iPad aparece en la laptop sin ningún merge, porque los dos leen el mismo archivo.
  • Si no se puede leer el proyecto, ReaSet lo dice en la lista de setlists y bloquea el guardado, en vez de dejarte editar una copia fantasma que nunca se va a escribir.
  • Requiere que el proyecto se haya guardado al menos una vez.
  • Nuevo Tools/ReaSet_LibraryDoctor.lua (solo lectura) informa qué eslabón se cortó cuando un setlist no guarda.

Arreglado

  • La sincronización Director→Player descartaba en silencio casi todas las ediciones. Se disparaba con el cambio del conteo de chunks, y togglear un skip mueve el payload tres caracteres — así que el conteo quedaba idéntico y el archivo compartido nunca se reescribía. Los Players seguían mostrando el setlist viejo sin ninguna señal de que algo había fallado.
  • El directorio del web interface estaba hardcodeado, y en instalaciones donde esa ruta no es la correcta io.open falla en silencio: el archivo nunca se escribe, el navegador recibe un 404, y nadie devuelve un error. Ahora se resuelve buscando dónde vive realmente ReaSet.html.

Known limitation: Player devices do not yet follow the Director's active setlist automatically — see #4.

Full changelog: CHANGELOG.md

v2.2 — Live Lyrics Carousel, Reaset.lua Unification & Director/Player Mode

Choose a tag to compare

@djenttleman djenttleman released this 29 Jul 00:31
fcf3414

ReaSet Changelog


English


v2.2 — Live Lyrics Carousel, Reaset.lua Unification & Director/Player Mode

July 28, 2026

Installation & reliability

  • Reaset.lua: one script instead of three. Merges the native-loop engine, the lyrics bridge and the chords bridge into a single persistent background script. Lyrics/chords tracks are now optional — no error box if absent — and ULT_GetMediaItemNote is called defensively so a missing SWS install no longer breaks transport/loop control. No Action ID setup needed; the web UI auto-detects it. The original three scripts remain under Requirements/ as a legacy/advanced path.
  • Wi-Fi drop / reconnect phantom-seek fix. ReaSet issues absolute SET/POS commands based on its last polled position. If the poll stream cuts out (a tablet losing Wi-Fi) while REAPER keeps playing, the first fresh reply on reconnect used to trigger a stale loop/boundary decision that seeked REAPER backward to the pre-outage position — indistinguishable from a phantom tap. ReaSet now detects the gap (plus browser online/offline events) and suppresses only its own automatic transport commands for a short guard window while silently adopting REAPER's real position; explicit user taps are never suppressed.
  • Decorated track names. Lyrics/chords tracks no longer need to be named exactly lyrics/chords — prefixes, numbering and symbol decoration are stripped before matching (*Lyrics, 01 - Chords, [Lyrics], etc.), while names with an extra word (Backing Lyrics) are deliberately left alone.
  • Real per-bridge status. Instead of one generic "make sure you have a track named lyrics" hint for four different causes, the empty-state message now reports the actual one: script not running, no track matched, SWS missing, or track found with no item under the cursor.
  • Fixed two real detection bugs. A divider/folder track above the real one (e.g. === LYRICS ===) could silently shadow it forever; the bridge now prefers a track that actually has items. Renaming a track used to have no effect until REAPER restarted; it now re-scans every ~2s when the latched track stops matching.
  • Dead-bridge detection. A crashed (not just absent) script used to keep reporting stale, frozen values as if they were live — nothing distinguished a hung script from a working one. A live tick counter plus error capture now catches this and reports it before any stale data is shown.
  • ReaSet_Diagnose.lua, a new read-only diagnostic script: lists every track with its normalised name and item count, which track each bridge would pick, SWS availability, cursor position, a per-item Notes dump, and a self-test that proves the lookup pipeline works independent of where the playhead happens to sit.

Live Lyrics & Chords — Cover Flow carousel

  • Three-line verse context. The lyrics panel now shows the previous and next verse above/below the current one, each independently sized via a new gear-icon settings popover (size, weight, colour, context on/off).
  • Chords get the same context, laid out horizontally either side of the current chord.
  • A proper 3D carousel, not a flat slide: verses and chords sit on a drum and turn into place — lyrics vertically, chords horizontally — always facing the viewer square-on (no distracting tilt on the context lines). Tuned down from an initial 380ms turn to a snappy 100ms with a hard landing.
  • Independent size controls: Global, Principal (current line) and Secundario (context lines) can now be adjusted separately instead of one shared scale.
  • Song-boundary clamping. Previous/next context lines no longer bleed across song boundaries — the "previous" line from the last song vanishes rather than lingering at the next song's start, and "next" at a song's end shows the upcoming song's name instead of the next lyrics item on the timeline, whatever song that happens to belong to.
  • Constant spacing on wrap. A two-line current verse no longer crowds its neighbours — spacing now accounts for the verse's actual rendered height.
  • Quieter status messaging. An empty panel (an instrumental passage, a gap between verses) no longer shows a large centred "no data" block that reads like an error; a faint status strip at the bottom reports it instead, brightening only when something genuinely needs fixing.

New tool: Lyrics_Tapper.lua

  • A companion authoring tool for building the lyrics/chords/notes items ReaSet reads: paste text, arm, tap along (mouse or Space) to place one item per line — teleprompter-style, in the spirit of Ableset's lyrics tool.
  • Restyled with a dark, Ableset-inspired theme; the tapping/timing logic itself is untouched.
  • Fixed three real runtime bugs surfaced by actually running it: two ReaImGui API mismatches (CreateFont/PushFont argument counts) and a color-packing bug (ARGB vs. the RGBA REAPER's ReaImGui actually expects) that was producing an unreadable pink/transparent UI.
  • One more tap now finishes the take. Tapping through the last line used to require a separate "Stop & Save" click; the (N+1)th tap now closes the last item and finishes automatically.

Director / Player mode

  • A mode picker on first load. Every device choosing to open ReaSet picks Director (full control) or Player/Músico (read-only: live song, progress, lyrics, chords — nothing that reaches REAPER). The choice is remembered per device and doesn't re-ask on a refresh.
  • Enforced at the network layer, not just the UI: every command ReaSet could send to REAPER passes through one function, and Player mode drops anything that isn't a plain read — a stray click or leftover keyboard shortcut cannot move REAPER's transport.
  • Shared setlist sync. A Director's setlist (order, skip/loop/chain flags) auto-pushes to a small file Reaset.lua writes next to ReaSet.html; Players read it automatically, Directors pull manually with a confirmation. A pulled setlist that doesn't match the currently open REAPER project is rejected rather than silently applied.
  • Optional Director PIN. A Director can set a PIN from the sidebar; from then on, actively choosing Director (not recalling an already-stored choice) asks for it first. Stored as a hash in REAPER's own persisted state — no server, survives a REAPER restart.
  • Two-Directors-at-once warning. Each Director quietly re-announces itself every few seconds; a second device choosing Director while one is already active is warned before switching, and a banner appears if a second Director shows up later, mid-show.
  • None of this is a real security boundary — REAPER's own Web Interface has no authentication — and the README says so explicitly.

Also

  • Smooth Seek preference, per project: toggle whether manual song/section/MIDI navigation lets REAPER apply its own smooth-seek behaviour while playing, or always forces an immediate hard jump.

Español


v2.2 — Carrusel de letras en vivo, unificación de Reaset.lua y modo Director/Player

28 de julio de 2026

Instalación y fiabilidad

  • Reaset.lua: un script en vez de tres. Combina el motor de loop nativo, el puente de letras y el puente de acordes en un único script de fondo persistente. Los tracks de letras/acordes ahora son opcionales — sin cuadro de error si no existen — y ULT_GetMediaItemNote se llama defensivamente para que la falta de SWS ya no rompa el control de transporte/loop. No requiere configurar un Action ID; la web lo detecta sola. Los tres scripts originales siguen disponibles en Requirements/ como ruta legacy/avanzada.
  • Corrección del salto fantasma al reconectar Wi-Fi. ReaSet emite comandos SET/POS absolutos basados en la última posición sondeada. Si el flujo de sondeo se corta (una tablet que pierde Wi-Fi) mientras REAPER sigue reproduciendo, la primera respuesta fresca al reconectar solía disparar una decisión de loop/límite obsoleta que saltaba REAPER hacia atrás a la posición previa al corte — indistinguible de un tap fantasma. Ahora ReaSet detecta el corte (además de los eventos online/offline del navegador) y suprime solo sus propios comandos de transporte automáticos durante una ventana breve, adoptando en silencio la posición real de REAPER; los taps explícitos del usuario nunca se suprimen.
  • Nombres de track decorados. Los tracks de letras/acordes ya no necesitan llamarse exactamente lyrics/chords — prefijos, numeración y símbolos decorativos se eliminan antes de comparar (*Lyrics, 01 - Chords, [Lyrics], etc.), mientras que nombres con una palabra extra (Backing Lyrics) se dejan intencionalmente sin marcar.
  • Estado real por puente. En vez de un único aviso genérico "asegurate de tener un track llamado lyrics" para cuatro causas distintas, el mensaje de estado vacío ahora informa la causa real: script no corriendo, ningún track coincide, falta SWS, o track encontrado sin ítem bajo el cursor.
  • Dos bugs de detección reales corregidos. Un track divisor/carpeta por encima del real (ej. === LYRICS ===) podía taparlo para siempre en silencio; el puente ahora prefiere un track que realmente tenga ítems. Renombrar un track no tenía efecto hasta reiniciar REAPER; ahora se re-escanea cada ~2s cuando el track enganchado deja de coincidir.
  • Detección de puente muerto. Un script crasheado (no solo ausente) seguía reportando valores obsoletos y congelados como si estuvieran en vivo — nada distinguía un script colgado de uno funcionando. Un contador de tick en vivo más captura de errores detecta esto ahora y lo reporta antes de mostrar cualquier dato obsoleto.
  • ReaSet_Diagnose.lua, un nuevo script de diagnóstico de solo lectura: lista cada track con su nombre normalizado y cantidad de ítems, qué track elegiría cada puente, disponibilidad de SWS, posición del cursor, un volcado de Notes por ítem, y un self-test que prueba que el pipeline de búsqueda funci...
Read more

v2.1.1

Choose a tag to compare

@djenttleman djenttleman released this 28 Mar 01:35
04683ee

ReaSet Changelog


English


v2.1.1 — Playback & Native Loop Fixes

March 27, 2026

Bug fixes

  • Audio glitch at region end with auto-stop enabled — When region A's endpoint matched region B's startpoint, the last ~200ms of A would play back 2–3 times before REAPER processed the stop. Root cause: the transport tick (~33ms) fired the end-of-region command multiple times before receiving a response. Fixed with three coordinated changes:

    • ID-based deduplication (_lastRegionEndTrigger): the trigger fires only once per region and re-arms when the playhead re-enters the region.
    • Time-based lock (_endOfRegionLocked, 400ms): blocks re-triggers while REAPER processes the async stop. Applied across all end-of-region paths: autoStop, shouldPlayNext, and stopAfter.
    • Tighter detection window (timeRem > -0.1 instead of > -1): eliminates false positives when the cursor briefly lands just past the region endpoint.
  • delayAfter path missing lock protection — The delayAfter override sent a STOP but did not activate _endOfRegionLocked, allowing re-triggers during the configured pause when the next region was adjacent. Fixed with the same lock logic as the other paths.

  • Native REAPER loop was incorrectly cancelled — _reaperNativeLoopOff() was called unconditionally before checking activeRegion.loop, tearing down the native loop (Repeat + A/B points) and falling back to the internal JS loop instead. Fixed: if ReaSet_NativeLoop.lua's native loop is active for the current region (_nativeLoopSubId === activeRegion.id), the Lua script already handles the jump and JS no longer intervenes.

  • Stutter + stop when clicking a song with auto-stop enabled — Race condition between the user's click XHR and a stale pending transport response. When a song item was clicked, playRegion dispatched SET/POS + PLAY immediately. If a transport response arrived shortly after showing the old cursor position near the previous song's end (chain=false), the autoStop block dispatched a STOP that REAPER received after the PLAY, killing the new playback. Fixed with the _playRegionLocked flag (500ms): set by playRegion on every user-initiated play, checked by the autoStop block before sending its STOP. The 100ms repositioning setTimeout is also cancelled if the flag is still active.

  • Stutter + stop persistent: triggerMidi() internal STOP kills user playback — The true root cause of the bug. When the previous song's autoStop fires, its 100ms setTimeout calls triggerMidi() to pre-arm MIDI for the next song. triggerMidi() sends PLAY and schedules a STOP 100ms later. If the user clicks a song during that 100ms window, triggerMidi()'s internal STOP arrives at REAPER after the user's PLAY, killing their playback. Fixed by adding the _playbackInitiated flag (500ms), set exclusively by playRegion(), which triggerMidi() checks before sending its internal STOP. A separate flag from _playRegionLocked is required because cueRegion() also sets _playRegionLocked and legitimately needs triggerMidi()'s STOP to fire (to stop REAPER after the brief MIDI-arm play).

  • cueRegion unprotected against autoStop — The cue function (pre-position without playing) did not set _playRegionLocked, so if a stale transport response arrived while the cue was in progress, the autoStop block could send a spurious STOP or fire its 100ms repositioning setTimeout, overwriting the freshly cued position or triggering a duplicate triggerMidi. The same _playRegionLocked (500ms) guard applied to playRegion is now also applied to cueRegion.

  • Boundary marker assigned to both adjacent songs — When a marker was placed exactly at the junction where one song's endpoint coincides with the next song's startpoint, the range check [song.start - ε, song.end + ε] would include it in both songs, generating duplicate nested sections. Implemented _markerBelongsToSong() with semantic disambiguation: (1) if the marker's display name matches a candidate song's display name (case-insensitive), it belongs to that song; (2) "end" keywords (end, fin, outro, salida, cierre, coda, fade, etc.) → belongs to the song ending there; (3) "start" keywords (start, inicio, intro, entrada, apertura, begin, etc.) → belongs to the song starting there; (4) no keyword match → defaults to the song starting there (a boundary marker without exit-keywords most likely names the incoming section).

New file

  • Requirements/ReaSet_NativeLoop.lua — Persistent background script for REAPER. Listens to the ReaSet/nativeLoop ExtState every frame and, on signal, creates a visual region in the timeline, sets native A/B loop points, and enables Repeat. Detects playhead crossings and, after the configured number of passes (loopMax, 0 = infinite), disables Repeat and removes the region. Announces itself to ReaSet automatically via ReaSet/nativeLoopReady=1.

v2.1 — Display, Loop & Command System Overhaul

March 2026

New features

  • Real-time display filters — New "Display Filters" section in the sidebar with independent sliders to adjust Luminance (50–150%), Contrast (50–150%), and Saturation (0–200%) for the setlist body. Values are saved automatically and restored when the app restarts.
  • Fractional loop counter — When a section has +LOOP:N active, a badge shows the current pass as a fraction (e.g. 2/4) to the left of the song action buttons, in the corresponding nested section row, and in Live View next to the section name.
  • Context menu in nested sections — Nested section rows now have their own 3-dot menu (to the left of the name) with access to Notes and Color selection, using the same ID-based override system as songs.
  • Next section indicator in Live — Live View shows the next nested section to the right of the active name, separated by an arrow →. If no section is active but there is an upcoming one, it is also shown as a preview.
  • Secondary progress bar in Live — A second progress bar, thinner and shorter than the main one, reflects progress inside the active nested section. The fill color matches the color assigned to that section in the setlist body.
  • Command system in region names — Region and marker names in REAPER now support a full inline command system to control behavior, appearance, and duration directly from the project, without touching the app. See command reference below.

UI improvements

  • Higher visual contrast — All text, borders, badges, and card backgrounds in the setlist body increased luminance and opacity by 20%. Global variables --text-secondary and --text-subdued were updated accordingly. The transport bar and app background remain unchanged.
  • Live progress bar is now white — The main progress bar fill in Live View changed from green to pure white for better on-stage readability.
  • Drag handle and 3-dot button redesign — The handle has greater weight and contrast. The 3-dot button is now vertical (three SVG dots), with no circular background, and a vertical divider between both elements.
  • SVG icons in context menu — Song options menu icons (Stop, Timer, Notes, Color) replaced emojis with SVG icons consistent with the dark theme.

Bug fixes

  • Context menu did not close when clicking outside — The removeEventListener listener was executed unconditionally on every click, preventing the menu from closing after the first external interaction. Fixed.
  • +LOOP:N played N+1 times — Multiple updatePlaybackUI ticks within the 200ms window before REAPER responded to SET/POS caused duplicate loop-counter increments. Fixed with a dedupe guard _lastLoopFireKey keyed by sectionId:endPos.
  • Real-time loop changes were not applied — The _loopInit flag permanently blocked re-applying default loop state when detecting changes in region name. Replaced with _loopDefault, which tracks the last parsed value and applies changes immediately.
  • Setlists were not isolated per project — Override and setlist data in localStorage was shared across different REAPER projects. A per-project fingerprint (djb2 hash of sorted region IDs) was implemented as a suffix for all storage keys.
  • Keyboard shortcuts blocked typing in notes — Letter keys mapped to app functions were intercepting input while focus was in a <textarea>. Fixed with a tagName guard. Additionally, Enter saves and removes focus, and Escape only removes focus.
  • Secondary Live progress color did not match setlist color — The bar used the region raw color; it now goes through the same getClosestPaletteColor() pipeline as the body, ensuring both colors are identical.

v2.1 Command Reference

Commands are written directly in the region or marker name in REAPER. They can be combined in any order. The clean name left after parsing all commands is what is displayed in the app.

Combined example:

Chorus {dense pre-chorus} +LOOP:4 [green] [.bold] [1:20]

+ commands — Playback behavior

Command Description
+PAUSE Pauses playback when reaching the end of the section.
+SKIP Marks the section as skipped by default. It appears crossed out and with reduced opacity.
+LOOP Enables infinite looping for the section.
+LOOP:N Repeats the section exactly N times, then continues. The X/N badge is shown in real time.
+LOOPFULL Loop with absolute priority: if a song is queued, it waits for the loop to finish before jumping.

Brackets [] — Appearance and duration

Command Description
[color] Assigns a palette color to the card. See available colors below.
[mm:ss] Overrides the displayed section duration (minutes:seconds format).
[nosong] Excludes the item from numbering and total song count. Appears with reduced opacity.
[.class] Applies a ...
Read more

2.1.0 New Functions!

Choose a tag to compare

@djenttleman djenttleman released this 15 Mar 15:03
93997af

v2.1 — Display, Loop & Command System Overhaul

March 2026

New Features

  • Real-time Display Filters — New "Display Filters" section in the sidebar with independent sliders to adjust Luminance (50–150%), Contrast (50–150%), and Saturation (0–200%) of the setlist. Values ​​are saved automatically and recalled upon restarting the app.

  • Fractional Loop Counter — When a section has +LOOP:N active, a badge with the current loop count in fractional format (e.g., 2/4) appears to the left of the song's action buttons, in the row of the corresponding nested section, and in Live View next to the section name.

  • Context Menu in Nested Sections — Nested section rows now have their own 3-dot menu (to the left of the name) with access to Notes and Color selection, using the same ID-based override system as songs.

  • Next Section Indicator in Live — The Live view displays the next nested section to the right of the active name, separated by a → arrow. If there is no active section but one is coming up, it is also shown as a preview.

  • Secondary Progress Bar in Live — A second, thinner, and shorter progress bar reflects the progress within the active nested section. The fill color matches the color assigned to that section in the setlist.

  • Command System in Region Names — Region and marker names in REAPER now support a full inline command system to control behavior, appearance, and duration directly from the project, without opening the app. See the command reference below.

Interface Improvements

  • Increased Visual Contrast — All text, borders, badges, and card backgrounds in the setlist body have had their luminance and opacity increased by 20%. The global variables --text-secondary and --text-subdued have been updated accordingly. The transport bar and app background remain unchanged.

  • Progress Bar in Live View Now White — The fill color of the main progress bar in Live View has changed from green to pure white for improved readability.

  • Redesigned Drag Handle and 3-Dot Button — The handle now has greater weight and contrast. The 3-dot button is now vertical (three SVG dots), without a circular background, and with a vertical separator between the two elements.

  • SVG Icons in the Context Menu — The icons in the song options menu (Stop, Timer, Notes, Color) have been replaced with SVGs consistent with the dark theme.

Bug Fixes

  • Context menu not closing on outside click — The removeEventListener listener was firing unconditionally on every click, preventing the menu from closing after the first external interaction. Fixed.

  • +LOOP:N playing N+1 times — Multiple updatePlaybackUI ticks within the 200ms window before REAPER responded to SET/POS were causing a duplicate increment of the loop counter. Resolved with a _lastLoopFireKey deduplication guard keyed by sectionId:endPos.

  • Real-time loop changes not applying — The _loopInit flag was permanently blocking the re-application of the loop's default state upon detecting changes to the region name. Replaced with _loopDefault, which tracks the last parsed value and applies the change immediately.

  • Setlists not isolated per project — Overrides and setlist data in localStorage were shared between different REAPER projects. Implemented a per-project fingerprint (DJB2 hash of sorted region IDs) as a suffix to all storage keys.

  • Keyboard shortcuts blocked writing in notes — Letter keys associated with app functions intercepted input while focus was on a <textarea>. Fixed with guard for tagName. Additionally, Enter saves and removes focus, and Escape only removes focus.

  • Secondary progress bar color in Live did not match setlist — The bar used the region's raw color; it now goes through the same getClosestPaletteColor() pipeline as the body, ensuring both colors are identical.


Command Reference v2.1

Commands are written directly into the region or marker name in REAPER. They can be combined in any order. The clean name that remains after parsing all the commands is the one displayed in the app.

Combined Example:

Chorus {dense pre-chorus} +LOOP:4 [green] [.bold] [1:20]

+ Commands — Playback Behavior

| Command | Description |

|---|---|

+PAUSE | Pauses playback at the end of the section. |

+SKIP | Marks the section as skipped by default. It appears crossed out and with reduced opacity. |

+LOOP | Activates an infinite loop for the section. |

+LOOP:N | Repeats the section exactly N v

Repeats and then continues. The X/N badge is displayed in real time. |

+LOOPFULL | Loop with absolute priority: If there is a song in the queue, wait for the loop to finish before jumping. |


Square brackets [] — Appearance and duration

| Command | Description |

---|---|

[color] | Assigns a color from the palette to the card. See available colors below. |

[mm:ss] | Overrides the displayed duration of the section (minutes:seconds format). |

[nosong] | Excludes the element from the numbering and total song count. Appears with reduced opacity. |

[.class] | Applies a custom CSS class to the name. See available classes below. |

Available Colors:
gray · red · orange · amber · yellow · lime · green · emerald · teal · cyan · sky · blue · indigo · violet · purple · fuchsia · pink · rose

Available CSS Classes:
| Class | Effect |

---|---|

.bold | Extra bold name (900) with adjusted tracking. |

.dim | Name at 42% opacity. |

.italic | Italic name. |

.loud | Uppercase name with increased spacing and maximum weight. |


Braces {} — Informative Text

| Command | Description |

|---|---|

{text} | Displays auxiliary text in italics next to the section name. Not shown in Live View or Canvas. Useful for production notes visible in the setlist. |


Special Prefixes — Markers

| Command | Description |

|---|---|

> | Turns the marker into a section marker (sub-region of the active song). |

* | Ignores the marker completely; it does not appear in the app. |

>>> DestinationName | When the section ends, automatically jumps to the region whose name matches DestinationName. |


Reserved Words

| Name | Description |

|---|---|

STOP | Stop marker. Playback ends when it reaches this point. |

SONG END | Also known as STOP. |


v1.0.0 First Release

Choose a tag to compare

@djenttleman djenttleman released this 08 Mar 01:10
8add041

v 1.0.0 First release.

Full Changelog: https://github.com/djenttleman/ReaSet/commits/releases

v 2.0.0 New UI

Choose a tag to compare

@djenttleman djenttleman released this 08 Mar 03:43
1b3cdb4
  • Added new UI and polished functions.
  • Fixed Loop button not working on Live mode