The split-view scratchpad was the last surface on the old ink_canvas. Move
its inking engine to the performant PenCanvas while keeping the infinite
auto-expanding world.
Key idea: store strokes in absolute WORLD pixels (InkStroke — unchanged
saveScratchpad format) and render through PenCanvas by normalizing against
the CURRENT world size. When the world auto-expands, stored world coords do
not move — only the normalization divisor grows — so ink stays put with zero
drift (proven by the world-expand-stability test).
- Replace InteractiveViewer+SizedBox+InkCanvas with PenCanvas (own pan/zoom,
minScale 0.1 to survey the big world); keep the AnnotationToolbar.
- Stroke callbacks go through ink_stroke_adapter; load filters to freehand
so the canvas list stays 1:1 with the undo manager.
- Pen/highlighter/eraser map from the toolbar's PenTool; width is world px.
The left PDF-reference pane (SfPdfViewer, read-only) is unchanged.
Tests: world-expand stability added. flutter analyze: 0. Suite: 270/270.
Notes now use the single performant inking engine (PenCanvas) instead of
the old ink_canvas, per "all note features on the pen-first canvas".
- ink_stroke_adapter: pure InkStroke<->PenStroke bridge (normalize against
a logical note page; drop non-freehand shapes/text). Round-trip tested.
- pen_palette_widgets: shared M3 ToolButton/PaletteDivider/RoundIconButton
so PDF + note editors use identical chrome (PenEditorScreen migrated to
them; its private copies deleted).
- PenNoteScreen: PenCanvas over a white logical page, undo/redo, title,
save -> Note.strokes (+ local OCR for search). Pressure curve, eraser
size/mode and palm rejection all inherited from the shared canvas.
- Route home (new/open) + search note hits -> PenNoteScreen; remove the
now-redundant "Pen Canvas (beta)" spike button; delete the dead old
note_editor_screen.
Tests: ink_stroke_adapter (5) + pen_note_screen widget (load + commit, 2).
flutter analyze: 0 issues. Full suite: 265/265.