Repository navigation
The studio's look - #164
Conversation
Quest-Claim: 86434662537bd6a8
The kit (rs/moq-studio/src/kit) holds the tokens of the mock-ups' kit.css, bundled Inter, Barlow Condensed, and JetBrains Mono, Lucide icons drawn through egui_extras' SVG loader, and the studio's own widgets. Today's panels wear it, the effects read its colors and draw as each widget does rather than from spots the panels register, and `just shots kit` shows every widget in every state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Maintainer decision on the kit's open decisions (asked by the
Update the quest's Plan, the mock-ups' (Written by Claude Opus 5.5 with high effort) |
Per the maintainer's decision on #164: rename SEL to ACCENT and draw on air (tally, ON AIR tag, program glow, recording) with it; red (ERR) is errors alone, a clipping meter and unhealthy health among them; a mute stays amber. The mock-ups' kit.css tokens, frames, and the quests' plans follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and edit as one gesture Review findings: the gain readout took a grid column of its own, shifting pan, delay, and the sends from their headings; a focused slider let the arrows move focus away; a press on the track edited before its drag started, and the release edited again, so one drag took several undos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Applied the maintainer's decision at 53f663f:
The PR stays a draft on one item: the review reached its design checkpoint on the slider's pointer handling, under (Written by Claude Opus 5.5) |
|
Maintainer decision on the review's design checkpoint and the red scope (asked by the
(Written by Claude Opus 5.5 with high effort) |
A release in the same frame as the last pointer move dropped that move, since the slider and fader edited only while dragged(). Apply the pointer on drag_stopped() too, and count the release in Gestures::of so its edit undoes with the drag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Applied the checkpoint decision in e542acd: (Written by Claude Opus 5.5) |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 33 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
There was a problem hiding this comment.
ℹ️ No blocking issues. Two regressions in today's panels are worth fixing before merge; details inline.
Reviewed changes
I reviewed the whole PR at e542acd: the kit's tokens, faces, icons and widgets, the effects rewiring, and today's panels moved onto the kit. quest context could not run because the review shell has no quest or nix binary.
- Tokens and style (
kit.rs): thekit.csscolors go into egui's darkStyle.ACCENTmarks on air and selection,ERRmarks errors only, andCUEmarks cued, muted and degraded states, as the maintainer decided. - Faces and icons (
kit/fonts.rs,kit/icon.rs,sh/kit-assets.sh): the fonts are subset. Inter's weights are set through its variable axis. Lucide SVGs are recolored white soegui_extrascan tint them. - Widgets (
kit/widgets.rs): the widgets keep no state of their own. The slider and fader sense drag only and apply the pointer position on release too.Gestures::ofnow counts the release frame as part of the drag. - Effects (
fx.rs,ui.rs):Fx::followkeeps the on-air, take and verdict state each frame, and each widget draws its own effect. This replaces theSpotslist, and a newViewerwrapsPanelsfor the dock. I checked the lock order:engine.stateis released before the menu bar's health pill locksengine.health. - Panels: Preview and Program sit in tally frames, Scenes are pads, Items use eye buttons and drag fields, the join link opens in a
Sheet, health is a pill with a popover, and the Audio gain is akit::Sliderwith a readout. - Mock-ups and plans:
--air/--selare replaced by--accent/--erracrosskit.css,kit.jsand the quest plans. - Gallery:
kitandkit_sheetare added tojust shots.
claude-opus-5-5 | 𝕏
The gain moved to kit::Slider beside a plain readout, losing the exact entry egui's slider had: the readout is now a kit::Number over dB. The health pill showed Not live without relays even when a source failed; an Unhealthy or Degraded verdict now wins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found. Both earlier findings are fixed.
Reviewed changes
This review covers the changes since the last Pullfrog review at e542acd.
- Health pill: an
UnhealthyorDegradedverdict now wins over Not live. A failed or stalled source, or a stopped output, now shows on the pill even when no relay is set. - Gain field: the gain readout is now an editable
kit::Numberin dB. Its parser reads-infas silence, andclamp_existing_to_range(false)shows a gain past +12 dB from a scene file without cutting it. The slider's response and the field's response both go throughgestures.of, so each edit still undoes as one step. - Test:
a_typed_gain_is_exactchecks that a +20 dB gain survives being drawn, and that typing0gives a gain of exactly1.0.
claude-opus-5-5 | 𝕏
The value's button now spans the field, its label and unit drawn inside it, so a press past a short numeral no longer misses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
This review covers the changes since the last Pullfrog review at 07ae291: the merge of main at 768ad41, which brings no net change to this PR's files, and one fix to kit::Number.
- Whole-field
kit::Number: the label and unit are now passed asDragValue::prefix/suffixatoms, and the button'sinteract_sizeis set to the field's size, so a press anywhere on the field drags or types. I checked this against egui 0.36.2'sDragValue. When the value atom is mapped, it is rebuilt fromRichTextand loses itsatom_grow. That leaves the trailingAtom::grow()as the only growing atom, so the text stays at the left of the field. In edit mode theTextEdittakesinteract_sizeminusbutton_paddingand fills the field exactly. As in egui's ownDragValue, the label and unit are hidden while typing. - Test:
a_number_drags_from_anywhere_on_its_fielddrags from 60% to 80% of a 120 px field, which is well past the numeral, and checks that the value changed.
claude-opus-5-5 | 𝕏

Implements quest/m0/ux/kit.md: the studio's own look, which every page quest builds on.
rs/moq-studio/src/kit.rs): the colors, radius, and faces ofquest/m0/ux/mock/kit.css, installed into egui's style so its own widgets (text fields, menus, combo boxes) wear them too. One accent (ACCENT, blue until branding replaces that one value) is on air (the ON AIR tag, the tally frame, the program's glow, recording) and selection, toggles, and sliders; red (ERR) is errors alone, egui's error color, a clipping meter, and unhealthy health among them; amber (CUE) is cued, off air, muted, and degraded, and egui's warning color.kit/fonts.rs,assets/fonts): Barlow Condensed for state and names, Inter (variable, set to 400/500/600 per family) for the interface, JetBrains Mono for numbers. Subset to Latin, Greek, and Cyrillic bysh/kit-assets.sh, about 515 KB together; egui's own faces stay behind them as fallbacks.kit/icon.rs,assets/icons): 25 Lucide SVGs named by role (Icon::Undo,Icon::Listen, ...), drawn withegui_extras' SVG loader at any size and tint. Adding one issh/kit-assets.sh <name>and a variant.kit/widgets.rs): icon button (names itself and its key in a tooltip), pill, tag, toggle, slider, fader, segmented meter, drag number field, popover, tooltip, sheet, keycap, scene pad, and tally frame, plus the stage wash as a radial gradient mesh. None keeps state; each takes its value from the caller.Fx::followtakes on air, takes, and health once a frame, and the widgets draw their spots (keycap, tally frame, health) where they paint, soui.rsno longer gathers spots. Effects read the tokens; the keycap's plastic isP3, the program's glow and the recording pulse are the accent, and the unhealthy electric is red.mock/kit.cssnow has--accent(renamed from--sel) and--errin place of--air; every mock-up draws on air in the accent, a clip red, and a mute amber, and every frame is re-rendered. The ux epic's Decisions record the rule, andlive.md,go-live.md,mix.md, and m1'smultiview.mdfollow it.Gestures::of(ui.rs) counts the release as the drag's last frame, so one drag, its release-frame move included, is one undo. The gain's readout is an editablekit::Numberin dB (typed, so it can go back to exactly 0 dB; a gain past +12 dB from a scene file is shown, not cut), and the menu bar's health pill lets an Unhealthy or Degraded verdict win over Not live, so a failed source shows without a relay (both found by Pullfrog).just shotsgainskit(every widget in every state) andkit_sheet(the sheet over it), fromkit/gallery.rs.No public API or wire change: everything is in the
moq-studiobinary.moq-sceneis untouched.Views
After the color decision: the gallery (accent for on air, selection, toggles, and sliders; red for the clipped meter's top segment and the Unhealthy pill; amber for the mute, NEXT, and OFF AIR), and the sheet:
The mock-ups it draws from, re-rendered with the new
kit.csstokens (shell-live,shell-hover,mix-strip):Today's panels, before (
main), with this PR's first look (red on air), and now. Every tab view shares the tally frames and pads, sostudio,audio(the gain readout back in its column), andhealthstand for the rest; the earlieraftercolumn shows the others in red:main)Validation
just cipasses (308 tests), including new tests: the faces load with Inter's weight axis covering 400 to 600; a slider follows the pointer and the arrow keys; a toggle flips (both throughegui_kittest).just shotsrenders all 14 views, the two new ones included.UI frame time,
main(0ad0e18) against this branch, in a real compositor: headless sway 1.12 at 1440x900@60, Mesa RADV on the host's AMD Radeon 610M iGPU (this host has no NVIDIA GPU, so the program was composited but not encoded), a show with an image, a color, a looping tone, and a clip, effects on. Four alternating 60 s rounds each; a patch never committed logged the frame interval, eframe's CPU time per frame, and the UI thread's on-CPU time per frame from/proc/thread-self/schedstat. Measured while a separate build loaded the host, its load average falling from about 22 to 3 over the runs, so the CPU numbers are noisy:maininterval / UI thread on-CPUBoth hold 60 fps. In the quietest round the UI thread spends 0.88 ms per frame on
mainand 0.96 ms here; across rounds the difference is within the noise, so no regression measures. Re-measuring on an idle NVIDIA host with the encoder running would firm this up.After the color decision (this iteration):
just cipasses (310 tests, two new: a focused slider keeps the arrow keys, and a press on a slider starts its drag; both fail on the previous head's slider and pass now);just shotsrenders all 14 views, and the views were read back: the tally frames, ON AIR tags, pads, toggles, and sliders draw in the accent, the gallery's clipped meter lights its top segment red, its mute is amber, and its new Unhealthy pill is red. Every mock-up frame was re-rendered withmock/render.shfrom the editedkit.cssand read back (shell-live,mix-strip). The change is colors only, so the frame-time measurement above stands.After the checkpoint answer (this iteration):
just cipasses (312 tests, two new:a_slider_keeps_the_move_its_release_makespresses at 75%, moves to 50%, and releases at 25% in one frame, anda_drag_and_its_release_are_one_gesturechecks every edit of such a drag, the release's included, carries one gesture). Each was run against the previous head's code first and failed: the slider missed the release position (the value assertion), and the release edit got its own undo step ([Some(1), Some(1), Some(1), None]). Then, for Pullfrog's findings:just cipasses (313 tests;a_typed_gain_is_exactstarts at +20 dB, asserts rendering leaves it, then types 0 and gets gain 1.0 exactly; its first assertion failed beforeclamp_existing_to_range(false)), andjust shots audio healthwas read back: the gain field sits beside the slider in the Gain column; the health view has no problems, so its pill still reads Not live.mainat 768ad41 (moq-dev/studio#163, fix: ignored tests name the real render-sw recipe, and docs match the code #165, ci: the moq pin is checked to be on moq's main #166; no textual conflicts):just cipasses (316 tests).just shotsat the merged head against the previous head: every Still view is pixel-identical (the Health view has no viewer reports, so feat!: catch the studio up to moq's main #163's dropped Playout column never shows), and only Livesetupdiffers, by its measured encoder timings. The local review's shadow round found that a number field took presses only over its numeral;kit::Numbernow makes the whole field oneDragValue, with the label and unit as its prefix and suffix. New testa_number_drags_from_anywhere_on_its_fieldfailed on the previous code (value stayed 0) and passes now;just cipasses (317 tests), and every Still view is pixel-identical to before the fix.Decisions
sh/kit-assets.shregenerates every asset from pinned sources (Google Fonts at a commit,lucide-static1.73.0).egui_extrasfor SVG icons bringsresvg0.45 beside the build script's 0.50 (two copies in the build, not the binary's behavior). The alternative, rasterizing the icons inbuild.rs, would fix their size; the loader draws them sharp at any scale.Pose, test only) so the gallery can show hover and press without a pointer.Fx::followreplaces the spot listui.rsbuilt, so a page that draws a keycap or tally frame gets its effect without wiring.expect(dead_code)naming the quest that will use each, so the gallery shows the whole kit now.accenttoken, renamed fromsel, for on air, selection, toggles, and sliders (rejected: a separatelivetoken). ✅ A clipping meter is red and a muted channel amber (rejected: both red; both amber). ✅ The gallery's look is accepted as shown. Red against amber is settled by the first: red is errors only, amber cued, off air, and degraded.error_fg_color, everycolored_labelof a failure) and the Unhealthy health verdict, whose problems are failures (relay unreachable, output stopped, source failed or stalled), are red, including the pill, the relay's unreachable dot, and the Health panel's electric flicker. Degraded, stalled and CPU-fallback source labels, and a guest offline or ended stay amber. Recording, which is not an error, is the accent, as are the mock-ups' recording dots. The app logo's red gradient and the lower third inside the fake pictures are content, not state, and keep their red.Gestures::oftreats the release as part of the drag for undo, and a test releases at a new position (rejected: rebuildingkit::Slideronegui::Slider; merging as is).live.mdmoved into its Plan, pointing the page at the kit, and the epic README now names the kit for painter work.Models
Size: L
Implementer: Claude, claude-opus-5-5, unknown effort
Implementer: Claude Code, claude-opus-5-5, unknown effort (iterate, M)
Implementer: Claude Code, claude-opus-5-5, unknown effort (iterate, S)
Implementer: Claude Code, claude-opus-5-5, unknown effort (iterate, S)
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)
Review
Rewritten by
quest reviewafter each round.Head: 1b5604a
Base: origin/main at 768ad41
Risk: medium,
the base has no RISK.md to name what is always high or customer-facing, so every change is mediumClassified: medium by default
Reviewer: Codex, gpt-6.1-sol, xhigh effort
Session:
01a1de18-d9d3-7fa2-ba9c-c4bfee066388, round 1Score: 9/10,
Source review found no actionable regressions; builds, tests, and quest context were not run, as instructed.Rounds: 7; first round 2 (high 1, medium 1); findings 4 (high 1, medium 3): fixed 4, refuted 0, open 0
Findings: none
Reviewer: Codex, gpt-6.1-sol, high effort, shadow
Session:
01a1dcd9-67e2-73c2-8067-1cc4a1bed30cRounds: 2; first round 3 (high 1, medium 2); findings 3 (high 1, medium 2): fixed 3, refuted 0, open 0