docs: settle Design View two-canvas sub-phase (fixed-lane per-item modes)

Item-level mode separation via REAPER fixed lanes; new content auto-tags to
the active mode; inactive lanes hidden and silenced; a managed-vs-manual lane
index keeps toggles off user comp lanes; capture placement mode-aware.
Precision invariants unaffected; REAPER 7 floor.
This commit is contained in:
2026-07-23 16:32:58 -04:00
parent 3791e6c119
commit 1688de553b
2 changed files with 504 additions and 13 deletions
+164 -5
View File
@@ -184,9 +184,27 @@ are **Arrange** mode (the default). Toggling to a mode **hides and disables** th
tracks that don't belong to it. Workflow value: mental separation + clutter
elimination — be in Design view, resample into the bank, flip to Arrange, place it.
**This is not a separate canvas.** REAPER has exactly one arrange timeline. Design
View is the *same timeline* with a curated, filtered track set and the inactive
tracks parked — not a second surface, window, or duplicated project.
Design View is a **mode projection over REAPER's single arrange timeline**
reaching both **tracks** (parked per mode) and **items** (lane-split per mode on
shared tracks). It approximates two canvases without a second surface: same project,
same timeline, but each stance sees its own tracks and its own items. It **never**
duplicates the project or opens a second window.
> **Two-canvas reach — settled (2026-07-23).** The original single-canvas framing
> here was derived from a REAPER constraint, not chosen as a product stance. Daniel
> reopened it — "as close as possible to two separate design and arrange canvases,
> same project, different items and leaves" — and has now signed off on the
> mechanism and resolved all forks. The "different leaves" half is delivered by
> track-parking (D1). The "different items" half is delivered by **per-item mode
> membership via REAPER fixed lanes** (track-side `I_FREEMODE=2`, `I_NUMFIXEDLANES`,
> `C_LANEPLAYS:N`; item-side `I_FIXEDLANE`, `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN`):
> each mode owns a lane on a shared track, and toggling shows/plays only the active
> mode's lane. This is an item-visibility projection over the one timeline — the
> exact analog of today's track-visibility projection — with still **no** literal
> second surface, window, or duplicate project. It is an **additive sub-phase (Phase
> D2 / Phase E)** on top of D1, spec'd in *§Two-canvas sub-phase* below. Full framing
> and the rejected alternatives (timebase-offset, subproject) live in
> `docs/product/design-view.md` §Two-canvas direction.
It is the visibility/processing analog of the capture pillar's load-bearing rule:
**designing and arranging are separate stances on one timeline**, and the tool
@@ -297,10 +315,21 @@ togglable per selection.
## Non-goals / guardrails
- **No second canvas.** Do not build a parallel arrange surface — reject any such
path in review.
- **No *literal* second canvas.** A literal second arrange surface, a second window,
or a duplicated project stays **rejected** — reject any such path in review. This
guardrail was **narrowed (2026-07-23), not lifted**: per-item mode separation via
REAPER fixed lanes on shared tracks (an item-visibility projection over the one
timeline) is now **allowed** and specified in *§Two-canvas sub-phase* below. Paths
that remain **rejected**: subproject / second-project-file approaches, and
overloading item `D_POSITION` with mode semantics (timebase-offset regions) — the
latter collides with the capture null test. See `docs/product/design-view.md`
§Two-canvas direction for why those were rejected.
- **Never touch mute/solo.** Any code path reading/writing `B_MUTE` / `I_SOLO` is a
bug.
- **Never drive a manual lane** (Phase D2). A mode toggle touches only **managed**
lanes (minted by the mode system, keyed in the lane-ownership index). Any code path
that shows, hides, silences, or re-lanes a **manual** lane — a user-created comp/take
lane outside the mode system — is a bug. The tool drives only lanes it created.
- **Every leaf is managed.** The mode system owns all leaf tracks: an untagged leaf
is an Arrange member, and when the active mode is not Arrange it is fully parked
and snapshot-restored exactly like a tagged leaf out of its mode. **show-both** is
@@ -325,6 +354,136 @@ togglable per selection.
- Interaction with the user having a screenset active (Design View drives the same
flags a screenset recall would; last writer wins — confirm no surprising fight).
## Two-canvas sub-phase (Phase D2 / Phase E) — additive to D1
> **Additive sub-phase, settled 2026-07-23.** Extends D1's track-level mode
> projection to **item level** so each stance owns its own items as well as its own
> tracks. Nothing in D1 changes; this wraps it. Runtime floor rises to **REAPER 7**
> for this sub-phase (fixed lanes shipped in v7). Product framing in
> `docs/product/design-view.md` §Two-canvas direction.
### What it adds
On a track present in **both** stances (a show-both track, or a folder carrying its
own media), each mode owns a **fixed lane**: the active mode's lane shows and plays;
the inactive mode's lane is hidden and silent. A Design take and an Arrange take can
then live on the *same track, same time position*, without colliding on the view.
Track-only-in-one-mode content is still handled by D1 track-parking, unchanged.
### Settled decisions
- **Mechanism: fixed item lanes.** Map mode → lane; toggle drives per-lane play/show
so only the active mode's lane is present. Items keep their real position and real
track — nothing is moved in time or deleted. SDK surface (**verified present in
`vendor/reaper-sdk`**): track-side `I_FREEMODE = 2`, `I_NUMFIXEDLANES`,
`C_LANEPLAYS:N`; item-side `I_FIXEDLANE`, `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN`.
**`I_FREEMODE` changes require `UpdateTimeline()`** to take visible effect.
- **Membership: auto-tag by active mode at creation.** New content — **both new
tracks and new items** — is tagged to whatever mode is active when it is created.
Pre-existing content defaults to **Arrange**. Membership is **exclusive**:
Design-created content never appears in Arrange and vice versa, except via the
existing **show-both** escape hatch. (This is the same tag-to-active-mode rule as
D1 track membership, now reaching items on shared tracks.)
- **Inactive-mode content is hidden AND silenced.** The off-mode lane is set
`C_LANEPLAYS = 0` — neither shown nor played — consistent with exclusive
membership and with D1's "flipping modes is a real change, not cosmetic." Show-both
is the deliberate opt-out for a lane that must stay audible across modes.
- **Managed vs. manual lanes — indexed and distinct.** Fixed lanes are also REAPER's
native comping surface: a user may keep **their own** manual lanes (comp takes,
alternate reads) on a track alongside the mode system's lanes. The tool maintains a
**lane-ownership index** — per (track GUID, lane): **managed** (which mode owns it)
vs **manual** (user-minted, outside the mode system). Mode operations touch **only
managed lanes**; manual lanes are never shown, hidden, silenced, or re-laned by a
toggle, and their `C_LANEPLAYS` stays exactly as the user set it. Items a user adds
to a **manual** lane are **not** auto-tagged (auto-tag governs normal timeline
content, not hand-managed lanes). The ownership index rides in `"reasampler"`
`view_state` alongside the membership index, GUID-keyed and portable.
- **Capture placement is mode-aware.** An **explicit** placement while in Design mode
— including capture-and-place — lands the item in the **Design lane**; the same
rule governs manual insertion. **The capture load-bearing principle is untouched:**
capture still writes a file + index entry and **never** auto-inserts; this governs
only *where an explicit placement lands*.
- **REAPER floor: v7.** No version-gate branch — below v7 this sub-phase is simply
unavailable.
### Precision invariants (unaffected — called out explicitly)
The capture precision invariants — **null test, bit-identical repeats,
non-destructive, exact bounds, relative-paths-only** — are **entirely unaffected** by
this sub-phase. No capture path changes; lanes are a placement/view concern
downstream of the written file. Lane assignment and `C_LANEPLAYS` are **reversible
flags**: the item is never relocated in time or deleted, so the sub-phase extends the
D1 non-destructive snapshot/restore contract to a new (item-lane) flag family rather
than introducing any destructive operation.
**New invariant — mode operations touch only managed lanes.** A mode toggle drives
only lanes the mode system minted (managed lanes, keyed in the lane-ownership index).
Manual lanes — user-created comp/take lanes outside the mode system — are **never**
shown, hidden, silenced, or re-laned by a toggle; their `C_LANEPLAYS` is left exactly
as the user set it. This is the fixed-lane analog of *never touch `B_MUTE`/`I_SOLO`*
and *never touch master*: **the tool drives only what it created.** Enforceable and
testable in the pure layer — the "which lanes may this toggle touch" decision is a
pure query over the ownership index; only reading REAPER's live lane state is shell.
### Module architecture (preserve the pure/shell split)
- **Pure (`view_mode_model` extension).** Lane math — which lane maps to which mode,
which `C_LANEPLAYS` value per mode, the item-lane op family alongside the existing
track-flag op family — is **REAPER-free and unit-tested**, mirroring the D1
planner. The **lane-ownership index** (per (track GUID, lane): managed-which-mode vs
manual) and the **"which lanes may this toggle touch" query** (managed only) are
pure and unit-tested — the planner emits lane ops for managed lanes only and never
for manual lanes. The **auto-tag decision** is pure too: given *a set of new
track/item GUIDs + the active mode* — and, for items, whether the item landed in a
manual lane (exempt) — produce the membership writes.
- **Shell.** Two shell responsibilities. (1) **Apply** the planner's item-lane ops
(`I_FREEMODE`/`I_FIXEDLANE`/`C_LANEPLAYS`/`B_FIXEDLANE_HIDDEN` via the media-item
info setters, `UpdateTimeline()` after `I_FREEMODE` changes) — for managed lanes
only. (2) **Detect** new content and read live lane state — see below.
- **Persistence.** The tool persists which lane maps to which mode **and the
managed/manual ownership index** (a small addition to the `"reasampler"` view
section); REAPER stores fixed lanes and lane-plays in the `.rpp` natively.
### New-content detection (implementation design point)
REAPER exposes **no clean "item added" / "track added" event callback.** Auto-tagging
therefore requires the shell to **diff project state on the panel's existing timer**
the `bank_panel` already polls and fingerprints the bank; this extends that machinery
to the timeline's tracks and items.
- Each poll, compare 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.**
- Correctness the implementation must handle: the **first poll after project open must
not mass-tag** pre-existing content (pre-existing defaults to Arrange, per the
membership rule).
- **Manual-lane exemption (design point).** An item added to a **manual** lane is
**not** auto-tagged — auto-tag governs normal timeline content, not lanes the user
hand-manages. Distinguishing the two may need a heuristic at detection (e.g., an item
whose `I_FIXEDLANE` is marked manual in the ownership index is exempt; content
outside any managed lane on a mode-managed track follows the active-mode rule). The
precise rule is an **open implementation design point**; the settled boundary is that
manual-lane content is off-limits to auto-tag.
- **Lane-identity fragility (design point).** `I_FIXEDLANE` is the lane's identity and
is how the ownership index keys to a lane. Whether the index survives lane
reorder/renumber/deletion without going stale is an **implementation design point**
(same class as GUID-keyed reorder-safety for tracks) — flag, don't solve here.
- Pure/shell seam: the **detection** (diffing REAPER's live set each tick, reading live
lane ownership) is shell; the **tagging decision** and the **managed/manual lane
query** (new GUIDs + active mode + manual-lane exemption ⇒ membership + lane writes)
are pure and unit-tested.
### REAPER API surface (verify all signatures)
- Fixed lanes — track: `I_FREEMODE` (=2), `I_NUMFIXEDLANES`, `C_LANEPLAYS:N` via
`GetMediaTrackInfo_Value`/`SetMediaTrackInfo_Value`; item: `I_FIXEDLANE`,
`C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN` via `GetMediaItemInfo_Value` /
`SetMediaItemInfo_Value`. Call `UpdateTimeline()` after `I_FREEMODE` changes.
- Detection reuses the `bank_panel` timer + GUID fingerprinting already in place;
item GUIDs via the item's `GUID` (`GetSetMediaItemInfo_String` `"GUID"`), track
GUIDs via `GetTrackGUID` as in D1.
- **Verify every name/signature against the SDK header before use** — the surface is
verified *present*, but confirm argument order, types, and flag values.
---
# Multi-bank — additive phase spec
+340 -8
View File
@@ -6,8 +6,10 @@ detail in `CONTEXT.md` (§Design View). This doc holds the *why* — the workflo
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). Open items for Daniel are listed at the
bottom.
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.
---
@@ -25,12 +27,19 @@ 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 second canvas.** REAPER has exactly one arrange timeline. Design
View does not create a parallel surface, a separate window, or a duplicate
project. It is the *same timeline* with a curated, filtered track set and the
inactive tracks parked. Anyone expecting a second arrange view will be
disappointed — and that expectation must be headed off in the spec, not
discovered in review.
**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
@@ -345,3 +354,326 @@ tooltip on the switch.
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.