Skip to content

Phase 1 Spike Results

Eric Dean edited this page Sep 30, 2026 · 1 revision

Phase 1 spike results

Phase 1 ran four throwaway experiments (spikes) to answer the riskiest questions before real code depended on the answers. Each spike ended in an architecture decision record (ADR). This page summarizes them in plain words. The spikes README has the commands, and each ADR has the full measurements.

All numbers come from one machine: a Microsoft Surface Laptop Studio 2. It has a 120 Hz screen at 150% scaling, and it runs Windows 11 with WebView2 154. It is much faster than the reference laptop, so the reference laptop must repeat the runs. The spike code never ships.

Spike Decision
Ink latency ADR 0004
Text on a freeform page ADR 0005
PDF export ADR 0006
Audio capture ADR 0007

Ink latency

Question: can a pen stroke reach the screen within 25 ms in WebView2? If not, and it can't be fixed, the interface moves to Flutter before Phase 2.

Answer: close, but not proven. A desynchronized 2D canvas that draws in the pointer handler showed ink 13.7 ms after injected input at the median, and 16.1 ms at the 95th percentile. On this screen, that is about one frame behind a plain native window. At the 95th percentile, every stack measured is estimated to miss the 60 Hz end-to-end budget, native windows included.

Decision: keep Tauri, so the Flutter fallback doesn't trigger. Phase 5 draws live ink on a desynchronized canvas in the pointer handler. It must also try two fixes: delegated ink trails with a real pen, and a native ink layer above the WebView.

Still to do:

  • A camera check with a Surface Pen and a Wacom tablet, filmed at 240 frames per second, which covers the parts the spike can't see.
  • A decision on whether the brand guide restates the pen budget in frames at the 95th percentile.
  • A reference laptop run.

Keep heavy work off the main thread while the pen draws. A busy main thread raised the 95th percentile from 16.1 to 22.5 ms.

Text on a freeform page

Question: does typing stay within 16 ms with several Tiptap editors on a zoomable canvas, mixed with ink?

Answer: yes for rendering, with three rules. With the rules, the page's own measure, from key down to drawn, stayed under 16 ms at the 95th percentile. On screen at 120 Hz, the display adds 9 to 13.5 ms, so no setup reached 16 ms on screen.

Decision: build each text container as its own Tiptap editor inside one "world" element that zooms with a single CSS transform. The rules are:

  1. Give every top-level block contain: paint. Without it, a 20-page note misses the budget (a 17.0 ms median, against 8.6 ms with it).
  2. Draw ink into cached tiles off the main thread. Never use SVG, and never redraw all of it each frame. Tiles took zooming and panning from 5 to 10 frames per second up to over 100.
  3. Add will-change: transform only during a zoom or pan gesture.

Still to do: the owner's review of the typing budget, a Phase 4 benchmark on the reference laptop, and a limit on how many off-screen editors stay mounted.

PDF export

Question: does WebView2's print to PDF match the paginated page on screen?

Answer: yes, to within 1 pixel at 144 DPI, once two layout rules are followed. Without them, text below a table moved by about 6 pixels. Ink stayed as vector paths. All 5 sheets exported as 5 pages, and manual page breaks landed in the same place.

Decision: export with WebView2 PrintToPdf from a hidden second WebView. Printing in the visible page stalled it for up to 50 ms at 5 pages, and half a second at 50. The two layout rules are:

  1. Nothing that affects layout may depend on the screen's pixel density. Use inset shadows, backgrounds, or SVG for table rules, never borders.
  2. Each paper size uses the width Chromium writes for it. A4 is 594.96 points wide.

Still to do:

  • Test static fonts, because variable fonts embed as Type 3 fonts.
  • Print a page on paper and measure it.
  • Open the PDFs in other viewers.
  • Repeat the timings at 100%, 125%, and 200% scaling.

Audio capture

Question: can cpal record the microphone and system audio at the same time?

Answer: yes. Over 10 minutes, both clocks matched the Windows performance counter within 0.1 parts per million, far inside the 9.3 parts per million that the 100 ms budget allows over 3 hours. Windows loopback delivers nothing while nothing plays, and it delivers a held packet when sound resumes. OpenNote fills those gaps with silence. Opus at 32 kbps took about 44 MB for 3 hours and used under 4% of one core per track.

Decision: use cpal on WASAPI in shared mode. Keep each source as its own track with a timeline that maps frame counts to performance counter times. Encode Opus in Ogg pages of at most 500 ms, so a crash loses under 1 second.

Still to do, by a person:

  1. Record a real Teams or Zoom meeting.
  2. Measure the offset between the microphone and loopback tracks.
  3. Try headsets, including Bluetooth, and device changes mid-recording.
  4. Record for 3 hours and check that a stroke at the end lands within 100 ms.

What changed in the plan

  • The Flutter fallback stays in reserve and didn't trigger.
  • Phase 4 gets a typing benchmark, and Phase 5 gets two ink fixes to try.
  • Phase 6 gets two layout rules and a hidden WebView for export.
  • Phase 9 gets per-track timelines and gap filling.

Related pages

Clone this wiki locally