From 84680ba1cf3434eea17b6208da85add4ca953587 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Sun, 20 Sep 2026 21:55:24 +0200 Subject: [PATCH] Describe onFrame, the frame queue of the render loop (#129) Architecture was missing the rule a drag now follows: work that costs more per pointer event than a frame is worth is collected per key and run once, before the frame it belongs in. Tests: none, wiki text only. Co-Authored-By: Claude Opus 5 --- Architecture.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Architecture.md b/Architecture.md index b3fee32..e985dbf 100644 --- a/Architecture.md +++ b/Architecture.md @@ -204,6 +204,16 @@ just as well on a screen that froze a minute ago. The drawn-frame counter is the `__gm.renderStats()` gives it, and step 33 is the check that the editor really does go quiet and really does wake up again. +**Work that costs more per pointer event than a frame is worth waits for the frame** — +`onFrame(key, fn)` runs `fn` once before the next frame is drawn, however often it was asked for +under that key, and `cancelFrameWork(key)` drops it. A drag writes the model on every pointer +move, and a model event rebuilds the panels, the run in the editor and any picture drawn from the +model: on a busy scene that measured 36 ms per pointer move, while a mouse reports around 125 +times a second and the screen takes 60. Without coalescing the pointer outruns the drawing and the +editor only catches up once the hand stops. The work runs **before** `app.render()`, not after, +so what it writes is in the frame it waited for. The Vector art tab's drag uses it; while the +gesture runs, its own copy of the rings is the truth and it never reads the model back. + The toolbar's right edge shows the frame rate in edit and play mode alike; `__gm.fps()` exposes the same number to tests. It counts **drawn** frames over the time the renderer was **awake**: idle seconds are not slow seconds, so the readout answers "how smooth is it while it moves" and