Skip to content

fix(ink): responsive pen input during saves; no per-frame re-render on pan/zoom (0.3.9) - #60

Merged
markm39 merged 3 commits into
mainfrom
fix/nonblocking-drawing-capture
Oct 13, 2026
Merged

markm39 merged 3 commits into
mainfrom
fix/nonblocking-drawing-capture

Conversation

@markm39

@markm39 markm39 commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Problem

After 0.3.8 (continuous documents), on iPad:

  • Writing lags during autosave. Every save serialized the whole document on the UI thread (iOS main / Android GL), base64- and JSON-encoded it there, sent ~20 MB through JS, then decoded it again to split it into pages. Strokes drawn during a save were delayed.
  • Pan/zoom lags (both apps). Continuous mode sent a new crop rect every frame, so native re-rendered (and resized) the ink drawable ~60 times a second.

Fix

  • snapshotDrawing() copies committed strokes under the engine lock; serialization runs on a background thread (iOS getBase64Data, Android getBase64Data/persistEngineToFile).
  • New native captureDocument(viewTag, pageCount, pageHeight) (iOS + Android) partitions the stroke copy off-thread; ContinuousDocumentCanvas uses it. No whole-document round trip through JS.
  • resolveDocumentRenderTarget: overscanned crop reused until the view leaves it, resolution held during a gesture, nearest crisp bucket on settle, never above the native 4096 px cap. ContinuousDocumentCanvas no longer re-renders its subtree on each viewport frame.
  • Typed DocumentChangedDuringCaptureError / isDocumentCaptureSuperseded for superseded saves.

Evidence (iPad Pro 13" M5 simulator, Release, 100-page × 200-stroke fixture — not physical-iPad numbers)

before (0.3.8) after
Main-thread stall per autosave (median / max, 20 saves) 59 / 63 ms 6 / 9 ms
Main-thread save time over 35 s of writing 1,148 ms 114 ms
Background save CPU over 35 s of writing 7.46 s 2.36 s
OpenNotes scroll+zoom test, app CPU 3.47 s 1.68 s
Writing test peak memory 720 MB 644 MB

Mac engine bench, 20k strokes: serialize 23.8 ms (old main-thread work) vs snapshot copy 1.5 ms.

Tests

  • jest 156 passed, tsc clean; new documentRenderTarget tests, capture args test.
  • Native smokes: serialization, eraser, selection, zoom, document-jni, new test:native:snapshot-smoke (snapshot encodes identically to live serialization; unaffected by strokes drawn while encoding off-thread). Added to CI.
  • Android: Kotlin compiled against RN 0.81 classes (no new errors vs main); JNI compiled; no device build available locally.
  • OpenNotes Release UI tests on simulator: cross-page stroke undo/redo/save/relaunch/export, cross-page text and asset history, rotated image crop, dense interaction audit, invalid-payload recovery — all pass.

@markm39
markm39 merged commit 7062022 into main Oct 13, 2026
1 check passed
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