Files
reasampler/docs/product/design-view.md
T
daniel 1f24c4b095 docs: 1.0 documentation restructure
Split root CLAUDE.md into 19 per-directory files scoped to their source area.
Roll v0 history into docs/ARCHIVE.md; retire CONTEXT.md, CONTEXT-ARCHIVE.md,
PLAN.md, COMPLETED.md. Move plan docs under docs/. Rescue 9 live deferrals
into docs/TODO.md.
2026-07-29 15:09:48 -04:00

38 KiB

Design View — product notes

Framing, rationale, and design-direction calls behind the Design View phase. The tickable spec's landed history lives in docs/ARCHIVE.md (Phase D) and the architecture detail in src/core/view/CLAUDE.md + src/shell/view/CLAUDE.md (§Design View). This doc holds the why — the workflow narrative, the N-mode reasoning, the screenset differentiation, and the design-direction recommendations — so those don't clutter the build docs.

Status: settled with Daniel (2026-07-22). The two-canvas direction (item-level mode separation via fixed lanes) is also settled with Daniel (2026-07-23) — see the §Two-canvas direction section, which supersedes the "not a second canvas" framing below. Open items for Daniel are listed above that section.


What it is (and what it is not)

Design View is a track-visibility-plus-processing "mode" system. Tracks used purely for sound design — scratch oscillators, FX-mangling chains, resampling sources — get tagged into Design mode. The arrangement's real tracks stay in Arrange mode (the default). Toggling to a mode hides and disables the tracks that don't belong to it.

The value is mental separation plus clutter elimination, tuned to the resample workflow: be in Design view, resample something into the bank, flip to Arrange, place it. The design scaffolding never touches the arrangement while you're arranging, and the arrangement never buries the design bench while you're designing.

It is not a literal second canvas. REAPER has exactly one arrange timeline. Design View does not create a parallel surface, a separate window, or a duplicate project — that stays true and is enforced in review. It is the same timeline with a curated, filtered track set and the inactive content parked.

Superseded in one respect (2026-07-23). The original claim here was that Design View separates only tracks, not items. That is now extended: the settled §Two-canvas direction adds item-level mode separation on shared tracks via REAPER fixed lanes — so each stance can own its own items as well as its own tracks. It is still not a literal second surface/window/project; it is a mode projection over the one timeline that now reaches items. Read §Two-canvas direction for the settled shape; the sentence "It does not separate items" no longer holds.

This is the visibility/processing analog of the capture pillar's load-bearing rule. The capture pillar says capture and placement are separate acts. Design View says designing and arranging are separate stances on one timeline — and the tool enforces the separation without ever destroying the user's real state.


Why not REAPER screensets? (pre-answered)

REAPER already ships screensets, which save and recall track visibility. This is deliberately different on three axes:

  1. Live membership, not a flat snapshot. A screenset is a re-saved picture of "these tracks visible, those hidden" — you re-capture it every time the track set changes. Design View is a membership index: tag a track into a mode once, and it is handled forever, including tracks added later. You maintain membership, not snapshots.
  2. It disables processing, not just visibility. Screensets hide tracks; the hidden tracks still run their FX and still feed the mix. Design View parks the inactive mode's tracks: out of the mix, FX bypassed, FX taken offline to reclaim CPU. Flipping modes is a real load change, not a cosmetic one.
  3. It is integrated with the resample workflow. The toggle lives in the ReaSampler window, next to the bank, driven by the same actions that capture and place. It is part of the tool's loop, not a general window-management feature parked in a menu.

N-mode reasoning (why the model is not a boolean)

Daniel's instruction was explicit: design the data model as N-mode, ship the UI with two. "Design Mode, or any other future mode."

The cost of a boolean is a backfill cliff: the moment a third stance appears ("Mixdown" that hides everything but buses; "Print" that isolates a stem chain), a boolean model forces a migration of the persisted index and a rewrite of every call site that assumed two states. The cost of N-mode now is trivial: a mode is an identifier, membership is a GUID → set<ModeId> relation instead of a GUID → bool. The visibility/parking logic is already "is this track in the active mode?" — which is a set-membership test regardless of how many modes exist.

So: the model carries arbitrarily many modes; the UI exposes two. Adding a third mode later is a UI-and-naming task, not a data-migration task. This is the defer-the-feature, design-the-seam principle applied.

A mode is a small record: a stable id, a display name, and an ordinal for tab order. Two seed modes ship: Arrange (the implicit default; every untagged leaf belongs to it) and Design. Arrange is special only in that it is the fallback home for untagged leaves — structurally it is just another mode.


Membership model (the settled rules, in prose)

  • Default is Arrange. Every leaf track belongs to Arrange unless it opts in elsewhere. Untagged = Arrange.
  • Leaves opt in. You tag a leaf track into Design (or any mode). You never tag a parent.
  • Parents are derived, never tagged. A folder/parent track's visibility is the OR of two sources: (a) descendant-derived — it appears in every mode that any of its descendant leaves belongs to; or (b) its own membership — an untagged parent is an Arrange member by default, exactly like a leaf. If a folder holds two Design leaves and one Arrange leaf, the folder shows in both modes by descendant derivation. The case own-membership fixes: an untagged folder that carries its own FX/media above leaves that are all tagged Design still shows in Arrange (its own default) as well as Design (derived from its children) — without the own-membership clause it would vanish from Arrange even though the folder itself is an Arrange member. A parent is never parked in any mode it is visible in. Rule of thumb: tag leaves; parents follow — still the common case.
  • Master is always visible, in every mode, and the tool never touches its flags. (REAPER's own SDK forbids driving B_SHOWINTCP/B_SHOWINMIXER on the master track — the invariant and the API agree.)
  • One mode at a time, with two exceptions: a leaf can appear in more than one mode only via (a) the explicit show-both toggle, or (b) the parent-derivation rule above. Otherwise a leaf lives in exactly one mode.

The descendant-derived half of the parent rule is why the pure model must be folder-tree aware. Own-membership (part b) is answerable from the membership index alone, but descendant derivation (part a) is not — to know whether any child leaf is visible in mode M, the model needs the current parent↔child structure, which the shell reads from REAPER's I_FOLDERDEPTH and feeds in. The tree is an input to the pure model's visibility query, not something the model stores (folder structure is REAPER's truth and changes underneath us).


What a toggle actually does (the parking contract)

Toggling to mode M partitions every leaf into active (belongs to M, or show-both) and inactive (belongs to some other mode — tagged elsewhere, or untagged/Arrange when M is not Arrange). Untagged leaves are Arrange members and park identically to tagged ones; there is no unmanaged leaf. For each track:

Active leaves and derived-visible parents → restored to their snapshot values (see restore contract) and shown.

Inactive leaves → parked:

  • B_SHOWINTCP = 0 and B_SHOWINMIXER = 0 — hidden in both panels.
  • B_MAINSEND = 0 — removed from the mix (no audio to parent).
  • I_FXEN = 0 — FX chain bypassed.
  • TrackFX_SetOffline(track, fx, true) for each FX — taken offline to reclaim CPU.

Daniel chose the full CPU-park option over mix-removal-only, deliberately. The point of Design mode is a heavy FX bench you don't want taxing the CPU while you arrange, and vice versa. Half-parking (mix out, FX still resident) would leave the tax in place.

Documented caveat: offlined FX re-instantiate when the track returns to the active mode. Stateful plugins (convolution reverbs, samplers with loaded content, anything holding a tail or a big buffer) re-initialize on return — there may be a load hitch and any un-persisted internal state is lost. This is an accepted cost of the CPU reclaim, not a bug. It must be documented at the toggle affordance so the user isn't surprised.

Never touched: B_MUTE and I_SOLO. The tool owns visibility, B_MAINSEND, I_FXEN, and FX-offline — nothing else — across every managed leaf, tagged or untagged. The user's mute/solo survives every toggle, untouched. This is the exact analog of the capture pillar's non-destructive invariant: the tool never destroys the user's real state to do its job.


Non-destructive restore contract (the testable invariant)

For every flag the tool drives on a track, it snapshots the prior value before parking and restores exactly on toggle-back — restore from the snapshot, never to a hardcoded "on." If the user had B_MAINSEND = 0 on a track for their own reasons before it was parked, it comes back as 0, not 1.

While a track is parked/hidden, its tool-owned flags (B_SHOWINTCP, B_SHOWINMIXER, B_MAINSEND, I_FXEN, per-FX offline) are tool-owned: the user is not expected to hand-edit a hidden track's routing mid-mode, and the contract does not promise to merge concurrent hand-edits of a hidden track. The snapshot is the source of truth for restore.

This is enforceable and testable in the pure layer: given a snapshot record and a target mode, the model produces the exact set of (track, flag, value) restore operations, and a round-trip (snapshot → park → restore) returns every driven flag to its captured value. The shell's job is only to apply those operations to REAPER; the decision of what to restore to is pure and unit-tested — mirror of how bank_model owns the index logic and the shell only touches the DAW.


Persistence

The mode-membership index and the last-active mode ride in the existing "reasampler" project ext-state namespace and travel with the .rpp. On project open, the tool reapplies the active mode's visibility + processing state. Same namespace, same travel-with-the-project guarantee as the bank index — one "reasampler" blob, two logical sections (bank + view).

Snapshots (prior flag values for currently-parked tracks) also persist: if a project is saved while in Design mode with Arrange tracks parked, reopening it must be able to restore those Arrange tracks correctly later. A saved-while-parked project that lost its snapshots would restore parked tracks to a guessed "on" — violating the restore contract across a save boundary.


Design-direction recommendations (opinionated)

Naming: keep "Design View" as the feature; name modes for stances, not tracks

The feature is Design View. The modes are Arrange and Design — verbs- as-stances the user adopts, not labels for what's in them. "Arrange" and "Design" read as what you are doing right now, which is the whole mental-separation pitch. Resist "Main / Scratch" or "A / B" — they describe the tracks, not the stance, and they don't scale to a named third mode. When a third mode arrives it gets a stance name too ("Mixdown," "Print").

The toggle affordance: a segmented mode switch, not a checkbox

Recommendation: a segmented control (pill/tab switch) in the ReaSampler window header — [ Arrange | Design ] — with the active segment lit. Not a checkbox, not a menu item as the primary affordance.

Why segmented over the alternatives:

  • vs. a checkbox ("Design mode on/off"): a checkbox hardcodes the binary the data model is explicitly built to avoid. A segmented control grows to [ Arrange | Design | Mixdown ] with no redesign — the UI mirrors the N-mode model. Borrowed from DAW/plugin A/B/C compare switches and browser device-toolbar responsive-mode pickers, both of which are "pick one active view from a small set."
  • vs. a menu: a mode switch is a frequent, glanceable action in this workflow — you flip it many times a session. It wants to be always-visible and one-click, showing current state at rest. A menu hides both the state and the switch.

The segment also carries the current-mode indicator "for free" (the lit segment is the state), and it is the natural home for the offlined-FX caveat as a tooltip ("switching parks the other mode's FX offline; stateful plugins re-init on return").

Actions (below) drive the same toggle for keyboard/MIDI binding; the segmented control is the visible, discoverable surface over those actions.

Tagging affordance: act on the track selection, not a per-track widget

Tag/untag operates on the current REAPER track selection via an action (and a context entry), not a per-track button in ReaSampler's window. "Select your design tracks, hit Tag selected → Design." This matches how a user thinks ("these tracks are my design bench") and avoids ReaSampler having to render a full track list mirror. The bank_panel window shows a small membership summary (counts per mode) rather than a per-track control surface.


Action set (proposed)

Stable command-id strings follow the sampler family prefix chosen in M0. Default names below; all bindable, the toggle and mode-jumps also MIDI-bindable to suit the performance-adjacent workflow.

  • Toggle active mode — cycle Arrange ↔ Design (extensible to cycle-through-all when >2 modes). The segmented control's click target.
  • Activate mode: Arrange / Activate mode: Design — jump directly to a named mode (distinct from cycle; needed once there are >2, and nicer for bindings).
  • Tag selected tracks → Design / Tag selected tracks → Arrange — move the current selection's leaves into a mode. (Arrange = untag from any other mode.)
  • Untag selected tracks — return selection to the default (Arrange), explicit alias of "Tag → Arrange" for discoverability.
  • Show both for selected tracks (toggle) — see show-both semantics below.

Show-both semantics (resolved)

Show-both is a per-track "pin visible across modes" flag, and it re-enables processing whenever the track is shown. A show-both leaf:

  • appears in every mode's visible set (like a derived parent, but by explicit request on a leaf);
  • is never parked — its driven flags stay at their snapshot/restored values in all modes, FX online, in the mix.

Rationale: the use case is a track you need audible in both stances — a reference oscillator you design against and also hear in the arrangement, or a master-bus FX chain living on a normal track. "Show but keep parked" is not a real need (a track you can see but that's silent and offline is just clutter with a thumbnail), so show-both means show-and-run. It is the deliberate escape hatch from one-mode-at-a-time, and it costs CPU by design — that's the user's explicit call per track.

Show-both is stored on the membership record for the track, persists with the index, and is togglable per selection.


Module breakdown (pure / shell / persist / actions / UI)

Mirrors the capture pillar's split exactly.

Pure view_mode_model (REAPER-free, unit-tested — the mirror of bank_model):

  • Mode registry: ordered set of modes (id, display name, ordinal); Arrange + Design seeded; add/query more.
  • Membership index: track GUID → { mode ids } (normally one; multiple only via show-both), plus the per-track show-both flag. add / remove / retag / query.
  • Folder-tree-aware visibility derivation: given the current parent↔child tree (supplied by the shell) and the active mode, compute the visible set — active leaves, derived-visible parents, show-both leaves, master always in.
  • Parking/restore planner: given the active mode + a snapshot record, emit the exact (track, flag, value) operation lists for park and for restore. Pure and fully testable — this is where the restore-contract invariant is enforced.
  • JSON round-trip of modes + membership + show-both + snapshots + active mode.

REAPER-facing view shell:

  • Reads I_FOLDERDEPTH across the track list to build the parent↔child tree; feeds it to the pure model.
  • Applies the planner's operations: SetMediaTrackInfo_Value for B_SHOWINTCP / B_SHOWINMIXER / B_MAINSEND / I_FXEN; TrackFX_GetCount + loop TrackFX_SetOffline per FX.
  • Snapshots prior flag values before parking (reads the same flags it will drive).
  • Resolves track GUIDs via GetTrackGUID / guidToString / stringToGuid for the index; never uses track index (unstable across reorders).
  • Never touches the master track's visibility flags; never touches B_MUTE / I_SOLO on anything.

persist slice:

  • Serialize/deserialize the view section (modes + membership + show-both + snapshots
    • active mode) into the "reasampler" ext-state namespace alongside the bank.
  • On project open, rebuild the tree, reapply the active mode.

actions entries: the set listed above, registered with the command_id / gaccel / hookcommand pattern; toggle + mode-jumps MIDI-bindable.

UI (in the ReaSampler / bank_panel window): the segmented mode switch in the window header; a small per-mode membership count; the offlined-FX caveat as a tooltip on the switch.


Open items for Daniel

  1. Product-notes location. This doc was created at docs/product/ — the first product-notes directory in the repo. If notes belong elsewhere (notes/, docs/design/), say so and it moves. Flagging because establishing the directory is a project convention, not mine to assume silently.
  2. Phase namespace. Proposed Phase D (a lettered namespace) rather than M12. Confirm you're happy with letters for parallel, non-capture phases.
  3. SDK name correction. The brief cited B_SHOWINMCP; the verified SDK flag for mixer-panel visibility is B_SHOWINMIXER (SDK header line 2235). The spec uses the verified name. Just flagging the discrepancy so it isn't a surprise in review.
  4. Snapshot-across-save durability. I ruled that per-track snapshots must persist so a saved-while-parked project restores correctly. This adds snapshot data to the persisted blob. If you'd rather keep the persisted state lean and accept that saving-while-in-Design-mode is an edge case (e.g., force-restore-to- Arrange on save), that's a viable smaller alternative — flag if you prefer it.
  5. Reorder/delete robustness (deferred, not blocking). If a tagged leaf is deleted or a folder is restructured while parked, the index holds a stale GUID. The pure model should tolerate unknown GUIDs (ignore-and-prune on next reconcile) — noted as a hardening item for the build, not a phase-defining decision.

Two-canvas direction — settled (2026-07-23)

Status: settled with Daniel (2026-07-23). This section reopens and supersedes the "not a second canvas" decision above. Daniel's stated intent (verbatim): "I wasn't the one who specified single-canvas, that emerged from REAPER's design. I want to come as close as possible to supporting two separate design and arrange canvases, which are actually the same project but have different items and leaves." The single-canvas framing above was a derivation from a REAPER constraint, not a product choice — so it was reopened, and Daniel has now signed off on the mechanism (fixed item lanes) and resolved all five forks. Everything under this heading supersedes the "not a second canvas" language in What it is (and what it is not): Design View is now a mode projection that reaches both tracks and items. This is an additive sub-phase (Phase D2 / Phase E) on top of the shipped track-parking work — not a rewrite of it.

What actually changed in the ask

The shipped model separates modes by track membership on one shared timeline: tag a leaf into Design, and when you flip to Arrange that leaf is parked — hidden, out of the mix, FX offline. Because items ride their tracks, a Design track's items already vanish from the Arrange view. The "different leaves" half of Daniel's ask is already delivered. Flipping modes already gives you a different track set.

The genuinely new half is "different items." Daniel wants two canvases that differ not only in which tracks are present but in which items are present — including items that live on a track shared by both stances. Concretely: a track that exists in both Arrange and Design (a show-both reference track, or a folder carrying its own media) should be able to hold a design take that only appears in Design and an arrangement take that only appears in Arrange, on the same track, without the two colliding on the timeline. Track-parking can't express that, because parking is all-or-nothing per track — it can hide a whole track, never a subset of its items.

So the reframe is precise: the feature grows from track-level mode separation to track-level plus item-level mode separation. "Two canvases" = each stance owns its own item set, layered over the shared project, with tracks it doesn't want parked as today.

The hard constraint (and why it's not fatal)

REAPER has exactly one arrange timeline and one project item graph. There is no API to instantiate a second arrange surface, and the "no second window/no duplicate project" observation in the shipped framing is structurally true — you cannot conjure a literal second canvas. What is reversed is only the conclusion drawn from it: that item separation is therefore off the table. It isn't. Items carry per-item state (I_FIXEDLANE, C_LANEPLAYS, D_POSITION, track assignment) that the tool can drive to make an item present-or-absent per mode without destroying it. "Two canvases" becomes an item-visibility projection over one timeline, exactly as "two track sets" is a track-visibility projection over one timeline today. Same discipline, one level deeper.

Mechanism (settled) and the alternatives it beat

The settled mechanism is Option A — fixed lanes as per-mode item layers. The two alternatives (B timebase-offset, C subproject) are kept below because why they were rejected is load-bearing: both collide with settled invariants, and recording that keeps them from being re-proposed.

Option A — Fixed lanes as per-mode item layers (SETTLED)

REAPER's fixed-lane feature lets a single track hold multiple horizontal lanes of items sharing one timebase, with per-lane play/visibility control. Map each mode to a lane: Arrange items live in the Arrange lane, Design items in the Design lane. Toggling a mode sets C_LANEPLAYS so only the active mode's lane plays and shows; the collapse/hidden flags hide the inactive lane. Items keep their real positions and their real track — nothing is moved off the timeline, nothing is deleted.

SDK surface (verified present in vendor/reaper-sdk). Track-side: I_FREEMODE = 2 (fixed-lane mode), I_NUMFIXEDLANES, per-lane C_LANEPLAYS:N. Item-side: I_FIXEDLANE, C_LANEPLAYS, B_FIXEDLANE_HIDDEN. Two operational notes for the implementation spec: I_FREEMODE changes require UpdateTimeline() to take visible effect, and fixed lanes shipped in REAPER 7, which sets the runtime floor (see fork 5).

  • Fidelity to the two-canvas feel: high. Same track, same time position, but the design take and the arrange take are genuinely distinct item sets that never co-occupy the view. This is exactly "same project, different items."
  • Non-destructiveness: strong. Lane assignment and C_LANEPLAYS are reversible flags; the item is never relocated in time or deleted. Snapshot the prior lane state, restore on toggle — a direct extension of the existing snapshot/restore contract to a new flag family.
  • Fit with park/restore: clean. It's the same architecture — the planner gains an item-lane op family alongside the track-flag op family. Pure model stays pure: lane math (which lane = which mode, which C_LANEPLAYS value per mode) is REAPER-free and unit-testable, mirroring the existing flag planner.
  • Capture-pillar precision: untouched. Capture writes files to the bank and never inserts into the timeline; lanes are a placement/view concern downstream of capture. The null test and bit-identical invariants are unaffected because no capture path changes.
  • Portability/persistence: native. Fixed lanes and lane-plays are stored in the .rpp by REAPER itself; the tool only persists which lane maps to which mode (a small addition to the "reasampler" view section).
  • Cost / caveats: fixed lanes are a real REAPER mode on a track — enabling I_FREEMODE=2 changes how that track behaves for the user (lane buttons, comp behavior), and users unfamiliar with fixed lanes see new UI on managed tracks. Under the settled auto-tag membership rule (see Membership — settled below), a track becomes lane-split when it first needs to hold content for a second mode, not by a manual "make this a two-canvas track" opt-in. Requires REAPER 7, where fixed lanes shipped — this sets the runtime floor.

Option B — Timebase-region offset (each mode owns a stretch of the timeline)

Give each mode a disjoint region of the single timeline — Arrange from 0, Design starting at some large offset (say bar 1000). Items are authored in their mode's region; toggling a mode scrolls/zooms the arrange view to that region (GetSet_ArrangeView2) and optionally sets the loop/time selection there. Different items appear because you're looking at a different part of the timeline.

  • Fidelity: medium. It reads as two workspaces if the scroll is snappy, but they share tracks vertically — a Design track is still a lane on the same track strip, just at a different horizontal offset. It doesn't give per-track item layering; a shared track shows both stances' items if you scroll between them.
  • Non-destructiveness: high (items just have positions), but positions become semantically loaded — an item's D_POSITION now encodes its mode. That collides with the capture pillar's null test, which re-inserts a capture at its source position to verify it nulls. If source positions live in the Design region, the null-test placement logic has to be region-aware. Friction with a load-bearing invariant.
  • Fit with park/restore: awkward. Parking is per-track; this is per-region. Two orthogonal separation axes that don't compose cleanly.
  • Portability: fine (just positions + a stored offset), but the offset is a magic constant that leaks into every position calculation.
  • Verdict: clever, but it overloads timeline position with mode semantics and rubs against the capture invariants. Not recommended.

Option C — Dual sub-projects / project tabs (true separation, heavy)

REAPER supports project tabs and subprojects (a project rendered as an item in a parent). Model Design as a genuinely separate project surface, imported/rendered back into Arrange. This is the only option that yields a literally separate canvas.

  • Fidelity: highest — it is two canvases.
  • Cost: enormous, and it fights the whole premise. "Same project" is Daniel's explicit constraint; a subproject is a different project file with its own item graph, its own render boundary, and a copy/sync problem between the two. The capture pillar's "one bank per project, GUID-keyed project identity, travels with the .rpp" assumption breaks — which project owns the bank? Persistence, reconcile, and the show-both/derivation model all have to be rethought across a project boundary. This is a different product.
  • Verdict: rejected. It satisfies "two canvases" literally by violating "same project." Daniel asked for close as possible within one project, not a second project.

The settled shape

Option A — fixed lanes as per-mode item layers — layered on top of the shipped track-parking model. The shipped model already delivers "different leaves"; this adds "different items" using a native REAPER mechanism that (a) preserves every precision invariant, (b) extends the existing snapshot/restore architecture rather than replacing it, (c) keeps the pure/shell split intact (lane math is pure, lane writes are shell), and (d) persists natively. It is the transplant-a-known-pattern move: REAPER already solved "multiple item sets, one track, one timebase, switchable visibility" for comping — we repurpose comping lanes as mode lanes.

The mental model: modes are a projection, and now the projection reaches items as well as tracks. A track can be Arrange-only (parked in Design as today), Design-only (parked in Arrange as today), or shared-and-lane-split (present in both, but showing each mode its own lane of items). The third case is the new capability and the concrete meaning of "two canvases."

Phase namespace: Phase D2 / Phase E (per the lettered-phase convention for parallel features) — additive to the shipped D1 track-mode work, not a rewrite.

Membership — settled (auto-tag by active mode at creation)

The earlier draft floated a manual per-track opt-in ("make this a two-canvas track"). That is superseded. The settled rule, verbatim from Daniel:

"Items AND tracks added to the timeline in arrange mode or design mode should be tagged as for that mode only. Existing tracks and items default to arrange. If an item is added to arrange mode, it does not appear in design mode. If an item is added in design mode, it is NOT part of the arrange mode."

Unpacked into the settled model:

  • Auto-tag at creation, not manual opt-in. New content — both new tracks and new items — is tagged to whatever mode is active at the moment it is created. There is no separate "convert this track" gesture; membership follows the active stance automatically.
  • Pre-existing content defaults to Arrange. Every track and item that existed before the mode system (or before this sub-phase) is an Arrange member, exactly as the track-level default already established.
  • Membership is exclusive. Design-created content never appears in Arrange, and Arrange-created content never appears in Design — the one exception is the existing show-both escape hatch, which continues to pin a leaf visible across modes.
  • Track level unchanged; item level is the new reach. At the track level this is the same tag-to-active-mode rule already settled. What is new: when a shared track (present in both stances — a show-both track, or a folder carrying its own media) gains an item in Design mode, that item lands in the track's Design lane and is invisible/silent in Arrange, and vice versa. That per-item split is the fixed-lane mechanism doing its job.

This resolves the old fork 2 (opt-in vs. automatic) in favor of automatic, and it is the through-line that also settles fork 4 (capture placement) below.

Inactive-mode items — settled (hidden AND silenced)

When you are in one mode, the other mode's items on a shared track are both hidden and silenced: the off-mode lane is set C_LANEPLAYS = 0 — neither shown nor played. This matches the exclusive-membership rule (Design-created content is not part of Arrange, so it must not sound there) and the track-level principle already settled: flipping modes is a real change, not a cosmetic one. A user who wants the design lane audible under the arrangement uses show-both, which is the deliberate opt-out; the default is full separation.

Managed vs. manual lanes — settled (2026-07-23)

Fixed lanes are not only the mechanism we borrow for mode-item layering — they are also REAPER's native comping surface. A user may want their own multiple lanes on a track (manual comp takes, alternate reads) that have nothing to do with the mode system. So a fixed-lane track can host both kinds of lane at once, and the tool must not confuse them. Daniel's constraint, verbatim intent: "as long as I can still opt in manually to put multiple lanes on a track. we must index which lanes are managed and which lanes are manual."

The settled distinction:

  • Managed lanes — minted and owned by the mode system to represent a mode's item set on that track. Mode toggles drive these: the active mode's managed lane shows and plays (C_LANEPLAYS), inactive-mode managed lanes are hidden and silenced. These are the lanes the two-canvas mechanism creates and controls.
  • Manual lanes — lanes the user created outside the mode system (native REAPER comping, alternate takes). The mode system did not mint these and must never touch them: a mode toggle never shows, hides, silences, re-lanes, or re-plays a manual lane. Its C_LANEPLAYS state is the user's, left exactly as they set it.

This is the fixed-lane analog of the two invariants already load-bearing in D1 — never touch B_MUTE/I_SOLO and never touch the master — extended to a third surface: never drive a lane the tool did not mint. It is the same non-destructive promise (the tool owns only what it created) reaching one level deeper, into the lane dimension.

Lane-ownership index (the new data)

The tool maintains a lane-ownership index: per (track GUID, lane) it records whether the lane is managed (and if so, which mode owns it) or manual. This rides in the "reasampler" view_state alongside the membership index, GUID-keyed and portable — same travel-with-the-.rpp guarantee as everything else in the view section. Deciding which lanes a toggle may touch (managed only) is a pure, testable query over this index; reading REAPER's live lane state is shell. The seam is the same as everywhere else in the phase.

Lane-identity fragility — flag for the implementation spec, not solved here. REAPER's I_FIXEDLANE is the lane's identity and is how the ownership index keys to a specific lane. Whether I_FIXEDLANE values survive lane reorder / renumber / deletion without the index going stale is a design point the technical spec must resolve (the same class of concern as GUID-keyed reorder-safety for tracks). The product decision is only that managed and manual lanes are indexed and distinct; how the index stays correct under lane reordering is an implementation call, not a product one.

What a mode toggle does to manual lanes (intended behavior)

A mode toggle leaves every manual lane exactly as the user set it — its C_LANEPLAYS (play/show) state is untouched across the toggle. Only managed lanes are partitioned into active (shown/played) and inactive (hidden/silenced). Concretely: if a shared track has an Arrange managed lane, a Design managed lane, and two manual comp lanes the user is auditioning, flipping Arrange↔Design swaps which managed lane plays and leaves both manual lanes precisely as they were.

Interaction with auto-tag. Auto-tag applies to content the user adds as normal timeline content — items dropped, recorded, or placed onto the arrange surface in the active mode. It does not reach into a lane the user is hand-managing: items a user adds to a manual lane are not auto-tagged to the active mode, because the user has taken explicit lane control there and the tool respects that boundary — the manual/managed distinction is exactly the signal that this content is outside the mode system.

Auto-tag/manual-lane boundary heuristic — flag for the implementation spec. Distinguishing "item added as normal timeline content (auto-tag it)" from "item added to a manual lane the user hand-manages (leave it alone)" may need a heuristic at the detection layer — e.g., an item landing in a lane the ownership index marks manual is exempt from auto-tag; an item landing outside any managed lane on a mode-managed track follows the active-mode rule. The precise rule is an open implementation design point, not invented here. The product decision is the boundary itself: manual-lane content is off-limits to auto-tag.

Capture placement — settled (mode-aware)

Daniel's rule is general over "items added to the timeline." So an explicit placement while in Design mode — including capture-and-place — lands the item in the Design lane; the same rule governs manual insertion. This is the same auto-tag rule reaching the placement pillar, not a new special case.

The capture load-bearing principle is untouched. Capture still writes a file to the bank and an index entry and never auto-inserts into the timeline. This rule governs only where an explicit placement lands once the user chooses to place — it does not create any auto-insertion path. The precision invariants (null test, bit-identical repeats, non-destructive, exact bounds, relative paths) are entirely unaffected: no capture path changes; lanes are a placement/view concern downstream of the file.

REAPER version floor — settled (v7)

Fixed lanes shipped in REAPER 7, so this sub-phase sets the runtime floor at v7. The full API surface (track-side I_FREEMODE=2 / I_NUMFIXEDLANES / C_LANEPLAYS:N, item-side I_FIXEDLANE / C_LANEPLAYS / B_FIXEDLANE_HIDDEN) is verified present in the vendored SDK header. No version gate branch is needed — below v7 the sub-phase is simply unavailable.

Technical consideration — detecting new content (for the implementation spec)

REAPER exposes no clean "item added" / "track added" event callback. The auto-tag rule therefore requires the shell to detect new track/item GUIDs by diffing project state on the panel's existing timer. The bank_panel already polls and fingerprints the bank; this extends that same machinery to the timeline's tracks and items.

  • Cadence / correctness. Each poll, the shell compares the live track/item GUID set against the previous poll's set; any GUID new since the last poll is tagged to the then-active mode. The diffing cadence and the "new-since-last-poll ⇒ tag" correctness rule are a design point the implementation must handle (e.g., first poll after project open must not mass-tag pre-existing content — pre-existing defaults to Arrange, per the membership rule).
  • Pure/shell split. The tagging decision — given a set of new GUIDs plus the active mode, produce the membership writes — is pure and unit-testable, mirroring the existing planner. The detection — diffing REAPER's live item/track set each timer tick — is shell. Keep the seam here: the shell hands the pure model "these GUIDs are new, the active mode is M," and the model returns the membership mutations.