title
How should handles snap
dated
April-Juli '26
This labnote outlines a design & prototype of how snaps could work (and are currently implemented) in playbook. This document is meant to document the design decisions and tradeoffs, and to serve as a reference for future work.
This design makes the interactions around handles directly downstream of selection, which is similar to how handles work in most other editing tools. However, unlike most other tools, I made the draggable handles userspace entities rather than a special affordance. This is kind of weird, but I think it’s nesscesary, because it allows us to construct parts with handles in userspace.
When you select a part that has handles inside, they will become visible. This is done by setting the visibility property (which is available for all entities in the scenegraph) to peek.
When a component is selected, you can either move the whole component by dragging the pencil anywhere on screen, or, move an individual handle, by dragging it with the pencil.
When you drag a handle, any other handles that are snappable become temporarily visible. Snapping happens when you drag a handle close to another handle. Under the hood, this creates a snap propagator which maintains the snap constraint.
You can unsnap the handle by dragging it away again. The unsnapping is dependent on selection. For instance, if I snap together two line segments, and then select them both, I can move around the snapped point. If I only select one of the line segments, it will unsnap. Conceptually, I think of this as “holding” the handle inside the selection. If you want to make the snapping permanent, you can group the selected components. This will cause them to always be selected together.
You can also snap handles to curves. Under the hood, this creates a ‘point-on-curve’ propagator, which keeps the handle on the curve. You can now move, rotate and even deform the curve, and the handle will try to stay on the curve, maintaining it’s parametric position along the curve if possible.
On the surface this seems straightforward enough, but for this to feel good the logic is actually quite subtle:
peekingThe actual snap-to-position behaviour of the handle is done through a propagator. This, again requires some subtlety to feel good:
Conceptually we can implement this whole thing in terms of ‘tools’. This means that the selection gestures are essentially just shortcuts.
This design takes some getting used to, but it allows you to quickly snap together components without needing to switch between different tools. It also makes sure the handles aren’t cluttering the screen when they aren’t needed. You can even unsnap overlapping shapes using the ‘pinprick’ selection gesture, which only every selects a single entity.
Other designs are possible, but I think this inevitably involves more complex gestures or switching between different tools/modes to differentiate, we explored different approaches in: