This 2D companion runs the identical 13-task release DAG and RCPSP scheduler as the 3D scene (architecture → platform builds → offline sync → push notifications → QA → store submission), but draws the result as a flat, pannable Gantt timeline instead of a 3D bar chart, with one row per resource track.
Critical path (CPM, unconstrained): a forward pass with infinite resources gives the earliest finish of the sink task — the theoretical floor no team size can beat, because it's bounded by dependencies alone:
EF(t) = duration(t) + max(EF(p) for p in predecessors(t))
CriticalPath = max(EF(t) for t with no successors)
RCPSP list scheduler (serial SGS): with finite capacity, tasks compete for their pool. Each task gets a priority equal to its tail length — the longest remaining chain of work after it finishes — so the most schedule-critical work is never left waiting behind less urgent work:
tail(t) = duration(t) + max(tail(s) for s in successors(t))
At each free resource unit: start the ready task with the largest tail(t)
The simulator re-runs this scheduler every time you move a capacity slider. Below the critical-path floor, adding developers to a track shortens the project; once a track's queue is empty the rest of the delay is pure dependency waiting — more heads stop helping, exactly the diminishing-returns effect real release plans hit when a bottleneck team (usually QA) can't be parallelized further.
Fixed vs. the 3D source: the 3D sim's "Critical path (∞ resources)" figure was computed by reading the backward tail(t) array only at sink tasks (no successors) — but tail(t) is a backward quantity (remaining work from t to the end), so at a sink it collapses to that task's own duration alone (2 days for "Store submission"), not the true critical path. The same backward array gives the right answer if you instead read it at the source tasks (no predecessors: just "Architecture & tech spec" here) — tail(root) already sums the full longest chain from that root down to the sink, which is exactly the unconstrained project length. This 2D sibling reads it there instead; verified numerically by also running the scheduler with near-infinite capacity for every track, which bottoms out at the same number.
- Capacity sliders — how many developers/testers work a track in parallel; re-solves the schedule live.
- Play — sweeps a "today" line through the Gantt timeline; bars glow while active.
- Resource-caused delay — the gap between the constrained schedule and the (corrected) unconstrained critical path: the cost of understaffing.
- Drag to pan, scroll/pinch to zoom — the timeline is not fixed to one scale; zoom in on the QA tail or out to see the whole 24-day worst case.