A wheel step in the middle of a transition restarted the ease-out
curve at full speed, so a run of quick steps kicked at each one.
A pan called finish() first and made the zoom jump to its target.
Both made the zoom and the gliding lists feel jerky.
- A new step starts from the speed the view already has and then
eases out. Quick steps in one direction move in one stroke. A step
the other way still starts from rest.
- A pan takes the transition along. The zoom goes on while dragging
and lands where it was heading, moved by the pan. This covers all
eight pan places: scene and container, graph, plugin board,
texture and pixel art, timeline, pattern, song and sound.
- finish() is gone, it has no callers left. Dragging the scrollbar,
a jump to a row, another document or a new view size still end
the transition as before.
Found: on a second step the old curve jumped to 2.47 times the
speed the view had just before.
Tests:
- npm run check on stein2: 299 files, 4598 tests (5 new)
- e2e 46 on stein2: ALL PASSED, 24 checks (1 new). A pan by 40/30
px during a 1000 ms zoom step leaves it moving (2.33 on the way
from 2 to 3), it lands on 3 with the world point moved by the pan.
- Counter-checks: with the pace reset to 3 the new unit test fails
with 2.47 instead of at most 1.1. Without carry the pan test fails.
- melektaus-atx went offline mid-run, so both ran on stein2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the Chip and the Filter drawn as devices, a preset such as the
Laser is about 3060 units wide. In a window of 1280 px a fit then hit
the floor of 0.25 and cut the Notes node off on the left.
- ZOOM_LIMITS.min goes from 0.25 to 0.125. The graph zooms without
steps, so one more step is the floor halved. 0.125 is also the
smallest step of the scene view.
- It holds for the wheel, for Fit and for the node board of plugins.
- The grid still hides itself below 8 px, so it does not flicker.
Tests:
- Unit plugins and graph-framing: 55 tests green, the floor test now
expects 0.125.
- e2e 06 (atx): ALL PASSED, 149 checks. Only a comment that named 0.25
changed there.
- Gate (atx): CHECK EXIT 0, 285 files, 4377 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wheel and the Fit button used to jump to the new view. Now the
view takes a short way there, 200 ms by default, everywhere the editor
zooms. The zoom steps stay the same, only the change is shown.
- viewTween: tweenView is the way between two views as a pure
function. The scale moves by equal ratios, and the world point that
sits at the same place on screen in both views stays there. After a
wheel step that is the point under the pointer.
- ViewTween drives it on the ticker. A surface hands it reading,
writing and drawing its own view and wraps its wheel and Fit code in
change(). A step during a transition starts from where that one was
heading, so quick steps add up to exactly as many steps.
- Anything else that moves the view ends the transition. A pan jumps
to the target first, and saving a view saves the target.
- Wired into FreeViewport (Scene, Container, animation preview),
SheetCanvas (Texture, Curve, Pixel art, Vector art), GraphCanvas,
panAndZoom (Tile board, plugin node board) and the timeline.
- Menu > General settings... sets the time in ms, 0 jumps at once. It
is kept in this browser like the panel sizes, not in the project,
and it is not an undo step.
- A document that opens still comes up framed at once. The animation
preview frames a new subject itself instead of calling fit().
- The pixel art readout names the step the view is heading for.
Measured in the scene view at 200 ms on melektaus-atx, where every
frame of the transition is a full redraw:
- 500 sprites: redraw 6.7 ms, 16 frames, mean 18 ms
- 1000 sprites: redraw 13.0 ms, 9 frames, mean 27 ms
- 2000 sprites: redraw 32.2 ms, 5 frames, mean 58 ms
Tests:
- The harness sets 0 ms on every load, so the existing modules read
the step and not the way.
- e2e 46i samples one wheel step at 1000 ms a frame later: zoom 1.033
between 1 and 2, the point under the pointer kept at (134, -40). It
lands on the view a 0 ms jump reaches.
- e2e 46 and 49 expect the new menu entry.
- Gate (atx): 234 files, 3563 tests, CHECK EXIT 0 (+15)
- e2e 46,49 (atx): ALL PASSED, 43 checks (+3, sum 1735)
- Three counter-checks fail view-tween.test.ts as expected. e2e 46i
fails when the scene view does not carry its centre along.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a graph of many nodes the frame rate dropped while panning, and
more so while one node was dragged. Every pointer move rebuilt every
box, every text and every curve, and a drag also announced a changed
project, so the panels rebuilt along with it.
- Panning and zooming move the picture. GraphCanvas.applyView sets
position and scale and draws anew only the grid and the rubber
band. It used to call redraw().
- A node draws its box and makes its texts only when what they show
has changed. NodeView keeps a signature of what redraw reads and
one of what rebuildTexts reads, and returns early while they hold.
- A drag does not announce a changed project. GraphDrags writes the
model on every pointer move and asks the canvas once a frame to
follow (GraphCanvasHost.moved). state.preview() waits for the
command of the release.
- Nodes outside the picture are not drawn. inView in graphView.ts is
the rule, cull() applies it after every redraw and every change of
the view.
- The graph is a render group, and box and pins go into the batch.
The mask sits on a container above the group, on the group itself
it would be panned and zoomed along.
- The rubber band and the drop mark of a dragged behavior are drawn
on their own (drawBand), without a redraw of the graph.
Measured in the CI image with 388 nodes and 540 links, fitted to the
canvas, 240 pointer moves 16 ms apart:
- Pan, script per move: 25.2 ms before, 2.0 ms after
- Pan: 4.4 frames per second before, 18.7 after
- Drag a node: 2.7 frames per second before, 22.4 after
- The still picture: 9 frames per second before, 21 after
Not solved: the still picture of such a graph stays at 21 frames per
second in the test browser. What is left is the drawing itself, and
the frame rates are those of that browser, not of a desktop GPU.
Tests:
- Gate on melektaus-atx: 207 files, 3121 tests (3114 + 7), exit 0
- e2e 4,6,18,19,20,23,24,26,28,31,36,43,51,53 on melektaus-atx: 542
pass, 1 fail. The fail is module 51 after module 43, an order the
suite does not have, and it fails the same way without this
change. Module 51 alone: 12 checks, all pass.
- No full run and no smokes. The sum of 1660 (1656 + 4) is reckoned,
and the CI workflow is switched off.
- Seven unit tests: six for inView in tests/editor/graph-view.test.ts
and one in frame-preview.test.ts
- Four e2e checks in block 6z-xii of module 06: pan, drag, zoom in
and fit, a changed value
- Seven browser counter-probes fail 2 to 3 checks each
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tile tab zoomed freely, so the pixels of a tile could end up
unevenly wide at odd factors. Scene view, container tab and animation
preview already snap to FREE_ZOOM_STEPS. The tile tab now does the
same, so every pixel editor zooms alike.
- The wheel steps through FREE_ZOOM_STEPS, counted in device pixels.
The board position is rounded to whole device pixels.
- New wheelSteps() in src/viewport/view.ts turns wheel events into
steps: one notch is one step, a trackpad gathers 50 px per step.
FreeViewport uses it too, so the rule exists only once.
- Fit takes the largest step at which the whole board fits. Refitting
on a new tab or board size stays as before.
- panAndZoom takes an optional zoom rule instead of limits. Graph and
node board keep zooming freely.
- A saved view from before the steps snaps to the nearest step.
- The cap parameter of frameBoxes from 4027afc has no user anymore.
It is removed together with its unit test.
Fit rounds down, and below 100 percent the steps are far apart. In the
small e2e window the 48 px board lands at 25 instead of 41 percent,
the 16 px board at 100 instead of 124 percent.
Tests:
- check.sh: 161 files, 2370 tests, exit 0 (-1 cap test,
+1 wheelSteps test)
- e2e 1-5 and 39: all passed, 169 checks. Three checks in 39 now
expect steps: Fit on a step with the next one too large, one notch
goes 0.25 to 0.5, 16 px tiles refit to at least 100 percent.
- Counter check: a free Fit factor fails exactly those three checks
(zoom 0.413 and 1.2396).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>