Files
feuerwerk/src/editor/GeneralSettingsDialog.ts
T
adminandClaude Opus 5.5 cf6043a066 Show a wheel step or Fit as a short zoom transition (#309)
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>
2026-10-03 21:01:10 +02:00

46 lines
1.5 KiB
TypeScript

import { Label, NumberField } from '../ui';
import { type GeneralSettings, ZOOM_TRANSITION_MAX_MS, zoomTransitionMs } from './generalSettings';
import { FormDialog } from './FormDialog';
/**
* How the editor behaves for whoever sits at it (#309), as opposed to the project's own settings:
* kept in this browser, the same in every project, and not an undo step.
*/
export class GeneralSettingsDialog extends FormDialog {
private zoomMs: number;
private readonly zoomField: NumberField;
constructor(settings: GeneralSettings, onApply: (settings: GeneralSettings) => void) {
super(340, 'General settings');
this.zoomMs = settings.zoomTransitionMs;
this.zoomField = new NumberField(this.zoomMs, {
width: 150,
min: 0,
max: ZOOM_TRANSITION_MAX_MS,
step: 10,
decimals: 0,
onInput: (value) => {
this.zoomMs = value;
},
onChange: (value) => {
this.zoomMs = value;
},
});
this.content.add(this.formRow(this.fieldLabel('Zoom (ms)'), this.zoomField));
this.content.add(
new Label('How long a zoom or Fit takes to settle. 0 jumps at once.', { style: 'muted' }),
);
this.addButtons('Apply', 'primary', () => onApply({ zoomTransitionMs: zoomTransitionMs(this.zoomMs) }));
}
/** The settings as the fields stand (test hook). */
values(): GeneralSettings {
return { zoomTransitionMs: this.zoomMs };
}
/** The zoom field itself, so a check can type into it. */
get zoomControl(): NumberField {
return this.zoomField;
}
}