Commit Graph

5 Commits

Author SHA1 Message Date
Skyler Lehmkuhl 64bf9bb431 Type the rest of the audio-controller boundary (no more bare-f64 wrapping)
Push Beats/Seconds through the remaining controller methods that took a bare
f64 and let the audio thread wrap it in a newtype, so the caller's domain is
now compiler-checked (the seam that hid the recording bug):

- seek -> Seconds
- set_trim_start/set_trim_end -> Seconds / Option<Seconds> (metatrack, always seconds)
- add_midi_note, add_loaded_midi_clip, update_midi_clip_notes -> Beats
- add_automation_point, remove_automation_point, automation_add_keyframe,
  automation_remove_keyframe -> Beats

Command enums stay raw f64 transport; only the public signatures + call sites
change. No behavior change — every caller already passed the right domain, this
just makes it enforced.

Two deliberate exceptions, documented in place:
- trim_clip stays f64: the TrimClip handler interprets it as Seconds for a
  sampled-audio clip but Beats for a MIDI clip, so no single newtype fits;
  callers pass the clip's own trim value, which matches its content domain.
- The piano-roll MIDI note model stays f64 internally (a beats-only subsystem
  with no seconds anywhere); it's converted to Beats at the update_midi_clip_notes
  boundary in UpdateMidiNotesAction, same as trim_start f64 -> Seconds at add_audio_clip.
2026-07-11 14:33:22 -04:00
Skyler Lehmkuhl b14972f657 P6a: mobile music surface (keyboard-primary instrument pane)
The mobile Piano Roll becomes a unified, keyboard-primary instrument surface
(wireframe Plate 04/08): a playable keyboard as the base, revealing a
Synthesia-style falling-notes roll above it when the pane is tall enough.

- Shared keyboard geometry (panes/keyboard_layout.rs): width-driven, pan-aware
  pitch->x, so the roll's note columns stay aligned with the Virtual Piano keys.
  Shared keyboard_octave + keyboard_pan_x in SharedPaneState.
- Piano Roll vertical mode (is_mobile): notes as columns falling toward an amber
  now-line by the keys, tempo-map converted (beats->seconds) so onsets cross the
  line exactly when they sound. Vertical drag scrubs the timeline; horizontal
  drag smoothly scrolls the keys (snaps to nearest key on release). Long-press
  creates a note (drag to size) or resizes an existing one; pan suppresses it.
  The keyboard is embedded (reuses Virtual Piano render + MIDI); the standalone
  VirtualPiano stack slot is removed. show_roll is driven by the snapped pane
  size-class so the keyboard<->roll reveal lands on a stack snap point.
- Virtual Piano: renders via the shared layout on mobile, colors playback_notes
  like pressed keys, gates note-on/glissando to presses that start on the keys
  (never gating release), and hides QWERTY hints on mobile.
- Transport formats by document.timeline_mode (Measures->bar.beat.tick,
  Frames->MM:SS:FF, Seconds->MM:SS.mmm) — per project type, like desktop.
- In-pane instrument header (name + Presets + REC). Recording is driven from the
  app each frame (not the Timeline pane's render) so REC works regardless of
  visible panes, and stopping playback stops recording.
- Compose/Record intent opens Timeline + instrument pane; mobile central panel is
  full-bleed (no inner margin) so panes sit flush.
- phone-ui-sketches.html: inst-bar moved to the top of the music surface.
2026-07-02 07:50:37 -04:00
Skyler Lehmkuhl 943ff7c15f Unify colors via theme CSS variables; theme egui visuals
Add Theme::var(name, ctx) (CSS custom-property getter) and Theme::apply_to_egui(ctx)
which maps the palette onto egui's global Visuals so standard widgets share the
theme colors. Add a mobile::palette::Palette built from the theme each frame and
replace the duplicated per-file C_* color constants across all mobile modules
(omni, topbar, stack, inspector, transport, intent, shell) with it. Add --scrim
and --accent-* category vars to styles.css. Apply the theme visuals every frame in
update(). Mobile and the main UI now share one CSS-variable-driven palette that
responds to light/dark/user themes.
2026-07-01 07:08:00 -04:00
Skyler Lehmkuhl 76e7963f03 Add Lucide icon font for the mobile UI
Bundle Lucide (ISC license) at assets/fonts/lucide.ttf and register it as the
egui font family "lucide" via mobile/icons.rs::install (called in EditorApp::new).
Icons are drawn as text with icons::font(size) + PUA codepoint constants.

Switch the stack headers (grip, maximize/minimize, node⇄instrument), the footer
chevron, and the transport play/pause to Lucide glyphs instead of relying on
egui's limited built-in emoji-icon-font.
2026-06-30 01:02:03 -04:00
Skyler Lehmkuhl 5ee2df5db7 Add mobile UI shell scaffold behind LB_MOBILE_UI
New src/mobile/ module renders a phone-style shell: top surface tabs
(Stage/Time/Nodes/Mixer/Tree), a single full-bleed hero pane reusing the
existing PaneInstance renderers, a resizable timeline ribbon (peek/half/full
snap tiers riding above the floor), and a fixed transport bar wired to the
audio controller (play/pause, timecode, project scrub).

Gated entirely on the LB_MOBILE_UI env var: when set, main() opens a
phone-aspect window and update() routes the central panel through
render_mobile_shell instead of render_layout_node, sharing the same
build_frame context and post-render drain. Desktop is unchanged when unset.

Tabs mirror the pane list; per the wireframe the Toolbar and Infopanel do
not become tabs (they become the omnibutton and inspector in later phases),
and the Nodes surface is a placeholder pending the focus/patch rework.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 22:40:54 -04:00