# GUI guidelines Use FLTK/C++ for windows, menus, dialogs, and the event loop. Keep all audio engine and project-domain logic in C. Main views: - Sequencer: tracks, clips, ruler, playhead, selection, zoom and scrolling. - Mixer: channels, faders, pan, mute/solo and meters. - Modular graph: nodes, ports, connections, validation feedback. - Transport: play/stop/record, tempo, meter, loop and position. Use custom-drawn widgets where ordinary controls are not a good fit: timeline, waveforms, piano roll, mixer strips and graph canvas. Keep drawing separate from project mutation. Never call FLTK from the audio thread. Visual direction: compact, high-contrast, restrained dark interface. Avoid excessive animation and modal configuration. Recreate broad usability ideas, not energyXT's exact artwork or proprietary resources. ## Phase 3 shell The shell opens JACK on startup through `xtc_backend.h`. It never accesses backend structures, processes samples, or calls JACK itself. Graph domain data is owned by opaque C objects, manipulated only through the C API. All backend control calls run on the GUI thread; FLTK is never called from an audio callback. No server is started and no audio ports are connected by the GUI. The initially empty graph produces silence. - **Play / F5:** start the engine. **Stop / F8:** deactivate it. **Space:** toggle. These are engine controls, not timeline playback or transport positioning. - **Reconnect / F6:** close the old client and open a fresh stopped client. Use this after server loss or sample-rate changes. A failed close preserves the handle and reports the failure instead of opening another client. - **View menu / Ctrl+1, Ctrl+2, Ctrl+3:** switch between sequencer, mixer and modular graph. Tabs provide the same view switching. Editors remain clearly labeled placeholders for sequencer/mixer; Modular Graph is implemented below. - **File / Quit / Ctrl+Q** or the window close button: close the backend and synchronize audio callbacks before hiding/destroying widgets. A failed close leaves the window open for a retry. Unsupported New/Open/Save actions are visibly disabled. About identifies the development milestone and version. The indicator shows disconnected, ready, running, server lost, format changed or process-error states. The status line shows rate, actual block size, mono layout, processed block count, xruns and process result. Command errors remain visible until a successful control action; periodic refresh does not erase them. A GUI-owned 100 ms timer reads atomic snapshots and collects retired plans. Label text changes only when needed. The timer is removed before successful close and again by the window destructor. No GUI locks are held across control calls. Operations such as opening JACK can briefly block the GUI; there is no worker/control-thread framework in this initial shell. MainWindow owns the backend handle and FLTK owns the window's children. The destructor also attempts cleanup on exceptional event-loop exit; if JACK close itself fails then, it reports to stderr and retains the callback context until process exit. Normal close/reconnect paths permit retry and release ownership only after successful close. The entry point catches C++ exceptions before process exit. Backend operations return C error codes throughout. Tests: `make test-gui` runs real widgets/callbacks/timers against a fake C backend under Xvfb, including control errors, startup without JACK, partially initialized handles, server/format notifications, view switching, retrying close, and timer removal. `make test-gui-jack` additionally requires a running JACK-compatible server, tests repeated start/stop, reconnect and active-client close, and creates no routes. Physical playback is outside this shell. See BUILD.md and the integration test README for sanitizer limitations and keyboard smoke results. ## Phase 4 modular editor Open **Modular Graph** or press **Ctrl+3**. Add oscillator (440 Hz), gain (0.10), pass-through meter or output nodes with the toolbar. Their parameters are fixed presets in this milestone and are drawn on each node; parameter editing and live meter display are not implemented. Connect oscillator → gain → meter → output for a simple test chain. No sound reaches hardware until ports are explicitly connected outside the GUI. Output nodes are required to render; isolated sources and an empty graph produce silence. Drag a node body/title to move it. Drag a circular output port to an input port to connect. Click a node or wire to select it (yellow outline/wire), then press Delete/Backspace or **Delete selection**. Deleting a node deletes its incident wires. Escape cancels a drag preview. Canvas scrollbars pan the view; positions are retained across edits/reconnect but not across application restart. There is no zoom, multiselection, undo, project persistence or external routing UI yet. The editor supports 64 nodes on a fixed 2000x4000 canvas. Every semantic action becomes a C graph command. The window owns the graph handle and publishes the C-created candidate through the backend. Cycle, invalid-direction, duplicate connection, missing-port, capacity and backend failures are shown below the canvas; failed edits leave the graph unchanged. Capacity feedback distinguishes the possible node limit/pending edit condition and allows retry. Editing while stopped replaces the prepared plan without starting playback. Editing with a disconnected startup backend stays local until reconnect. A lost or changed live backend requires reconnect before further semantic edits. Moving/selecting nodes does not touch the engine. The graph state line distinguishes offline, prepared, queued and active states. Queued explicitly means the drawing represents the next submitted graph while the engine finishes the previous plan. The 100 ms GUI timer observes audio adoption revisions and then shows active. Graphs are not edited in place on the audio thread. There is no automatic retry/hidden edit queue; users retry a rejected capacity edit. Plan replacement can reset oscillator phase and is not crossfaded. Render validation and active replacement tests are described in tests/integration/README.md.