Skip to content

feat(studio): drag items in the preview, snapping to the canvas, items, spacing, and a grid - #15

Merged
kixelated merged 8 commits into
mainfrom
quest/m0/snapping
Nov 3, 2026
Merged

kixelated merged 8 commits into
mainfrom
quest/m0/snapping

Conversation

@kixelated

@kixelated kixelated commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The preview was a picture only: items could be placed only by typing numbers in the Items panel, with nothing to line them up. The snapping quest asks for preview moves and resizes that snap to the canvas, other items, and a grid, with smart guides, equal-spacing hints, and a modifier that turns snapping off.

Approach

  • Direct manipulation in the preview (ui.rs, Panels::arrange), the gap the quest exposed: click an item of the layer the Items panel shows to select it, drag it to move, drag an edge or corner to resize. The selected item's edges are hit first, then the frontmost visible item; hidden items are never grabbed or outlined. Each frame drags from the rect and pointer at drag start, so snaps never accumulate.
  • Snapping math in a UI-free module (rs/moq-studio/src/snap.rs, no egui types, unit-tested): Grab::at (what a press holds), Grab::drag, and Snap::apply, which along each axis picks the nearest line within reach of a moving edge or center: canvas edges and center, other visible items' edges and centers (scene in preview plus top layer), grid lines, and, for moves, the spacing of neighboring pairs (centered between two, or repeating a pair's spacing). It returns guides for every line the item sits on and the equal gaps to mark. It lives in the studio, not moq-scene, per the quest Plan: snapping is a preview interaction.
  • Undo and autosave: every drag step commits set_item through State::commit with the drag's gesture id, so a drag is one history entry and autosaves like any edit. Undo, redo, or reload mid-drag lets go of it.
  • Settings: a Snap toggle (on by default), a Grid toggle (off) with a spacing in canvas pixels (40) in the Preview panel's header. Holding Ctrl (Cmd on macOS, egui's command) drags freely. Reach is 8 points on screen, converted to canvas pixels.

Impact

  • The preview selects, moves, and resizes items by dragging, with cursors, a selection outline with handles, and a hover outline.
  • Drags snap to the canvas, other items, equal spacing, and an optional grid, drawing guides and spacing marks; Ctrl/Cmd or the Snap toggle turns it off.
  • The Preview panel gains Snap, Grid, and grid-spacing controls. They are session state, not saved.
  • README.md documents preview editing and snapping. No scene-file change.

Alternatives

  • Snapping in moq-scene: rejected by the quest Plan; nothing but the preview drag consumes it.
  • Saving snap and grid settings: there is no app-settings store yet (eframe persistence is off), and the scene file holds the scene, not editor preferences.
  • Aspect-locked resizing (Shift), keyboard nudging, rotation handles, and marquee multi-select: not asked for by the quest; see Follow-ups.

Choices made without asking

  • Ctrl/Cmd as the snap-off modifier (OBS uses Ctrl; egui's command maps it to Cmd on macOS).
  • Equal spacing snaps, not only hints, since a hint at a fractional position is unreachable by hand.
  • Snap targets include the top layer's items when editing a scene, since both are drawn in the preview; only the Items panel's layer is clickable.
  • Grid default 40 px (divides 1920x1080 and 1280x720), off by default.
  • Unsnapped drags move in whole canvas pixels.

Follow-ups

  • Aspect-ratio lock while resizing (most sources are video with a fixed shape).
  • Arrow-key nudging of the selected item.
  • Persisting editor preferences (snap, grid) once an app-settings store exists.

Checks

just ci passes locally on an Apple Silicon Mac at 8e74d38, every feature set included (main's macOS capture fix landed in #14). The direnv hook test inside it ran too. The preview interaction was not exercised by hand in a running window; the geometry it relies on is unit-tested.

Review

Codex (quest review), gpt-6.1-sol, medium effort.

  • Round 1 on 35d56ae, 3 findings, all fixed in 699b8ed:
    • Spacing snaps applied to resizes (moved one edge by a whole-item offset): spacing candidates now join only whole-item moves, with a test.
    • A selected full-canvas item hid the items in front of it from clicks: the selected item takes priority only for its resize edges.
    • The release frame (drag_stopped without dragged) dropped the final pointer position: the drag now applies it, keeping the gesture id from drag start so it stays one undo step.
  • Round 2 on 699b8ed: no findings.
  • a3be27d merges origin/main without conflicts.
  • The online review (OpenAI) on a3be27d found that a hidden selected item was still grabbed by its edges, so a drag on a visible item across its old edge resized the hidden one, and its outline still showed. Fixed in 59b3b6b: the hit test moved into the UI-free snap::hit, which skips a hidden selected item, and only a visible selection is outlined. hits_the_selected_edges_then_the_front covers the overlapping hidden and visible case and fails without the fix.
  • Round 3 on 59b3b6b: no findings.
  • 8e74d38 merges origin/main (feat(studio): guided setup on first launch #7, fix(studio): fail loud when a worker thread cannot start #22), resolving one mod line conflict in main.rs by hand; the PR's added and removed lines are identical to 59b3b6b's, so the review exemption for merges that leave the diff unchanged covers it.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 3 commits November 2, 2026 19:58
Quest-Claim: 02b6deb84ba67f9c
…s, spacing, and a grid

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Snapping and guides feat(studio): drag items in the preview, snapping to the canvas, items, spacing, and a grid Nov 3, 2026
kixelated and others added 2 commits November 2, 2026 22:15
@kixelated
kixelated marked this pull request as ready for review November 3, 2026 06:20
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You'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 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 52576770-12da-4788-a99e-4d7d30694a6a
Commits

Reviewing files that changed from the base of the PR and between 875b709 and 5ae11a7.

Files selected for processing: 6
  • README.md
  • quest/m0/README.md
  • quest/m0/snapping.md
  • rs/moq-studio/src/main.rs
  • rs/moq-studio/src/snap.rs
  • rs/moq-studio/src/ui.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@kixelated kixelated left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: a3be27d

Skip hidden items in the selected resize hit test (rs/moq-studio/src/ui.rs:529–532). Select an item, hide it with Shown, then drag a visible item where it crosses the hidden item's former edge. Grab::at wins before the visibility-filtered search, so the hidden item is resized instead; its selection outline is also still painted. Make preview selection and handles respect visibility, or clear selection on hide, and cover the overlapping hidden/visible case.

The direct manipulation and snapping approach is otherwise a useful direction. Static GitHub review only; I did not run tests or an interactive session.

… item

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Contributor Author

Re the OpenAI review on a3be27d: agreed, and fixed in 59b3b6b. The preview's hit test moved into the UI-free snap::hit, which skips a hidden selected item. The preview outlines only a visible selection. The selection is kept rather than cleared, so the Filters panel can still edit a hidden item. hits_the_selected_edges_then_the_front covers the case where a hidden item overlaps a visible one, and it fails without the fix.

(Written by Claude Opus 5.5)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 59b3b6b

The previous hidden-item resize finding is fixed: hit testing now excludes hidden selections, the outline is suppressed, and the new overlapping-item test covers the reported case. No new actionable bugs found in this update.

Extracting the hit test into the existing geometry module is a straightforward approach. Static GitHub review only; I did not independently run tests or an interactive preview session.

@kixelated
kixelated merged commit 587cc9f into main Nov 3, 2026
2 checks passed
@kixelated
kixelated deleted the quest/m0/snapping branch November 3, 2026 20:28
kixelated added a commit that referenced this pull request Nov 4, 2026
Brings in effects (#17), preview dragging (#15), failover (#19), guests
(#10), the docs move (#26), and outside edits (#24).

- Compositor: main's effect pipeline replaces this branch's shader. A
  picture now carries whether its alpha is premultiplied, so a page
  drawn as an item, or read by a luminance mask, is unpremultiplied
  before its filters run.
- Preview: with Interact on, the pointer goes to the pages and the
  preview does not arrange items; off, dragging arranges as on main.
- Sources: the add form lists both Browser and LUT.
- README: both sides' panels, kinds, and sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant