Web performance: light animation, gestures on a compositor layer, no forced layouts
Deploy web Studio / deploy (push) Successful in 3m46s
Deploy web Studio / deploy (push) Successful in 3m46s
Measured with the new tools/bench_web.py on the web Studio's house demo, CPU slowed 6x:
- Idle: running CSS animations repainted the whole drawing every frame (99% of the main
thread in a window). Animations now step on about ten times a second by default
("light", 5% idle); the new toolbar button switches light / smooth / off and the browser
remembers it; [build] animation sets the default for built pages; view.animation().
Pan and zoom gestures pause them. Status LEDs pause off-screen and with the rest now.
- Pan 28 -> 10 ms, zoom 69 -> 11 ms per step: gestures move the drawing as one compositor
layer (transform) and set the viewBox once they end; --iso-k is set on the tags group
only and only when it changes; the stage box is read once per frame.
- Hover 22 -> 15 ms per move: the tooltip is placed once per frame on its own layer and
measured only when its text changes; the Studio's x/y readout updates ten times a second
in a contained box; hover work in the Studio runs once per frame.
- Long object lists skip layout of rows out of sight (content-visibility).
- WASM built with opt-level 3: engine render 11.7 -> 9.4 ms for 10% more download.
Checks: Studio 102/102 (animation modes, pan as a layer, contained readout), web 87/87.
This commit is contained in:
1 parent
19f4c83ae8
commit
a202283a60
15 files changed
+476
-31
No files matched your search
@@ -345,6 +345,45 @@ with sync_playwright() as p:
|
||||
pg.wait_for_timeout(600)
|
||||
pg.evaluate("__studio.select(null)")
|
||||
|
||||
# performance: animations step about ten times a second by default (no CSS animation runs on its
|
||||
# own), the toolbar button switches smooth / off / light; a pan moves the drawing as one layer and
|
||||
# draws it again (viewBox) only when the drag ends
|
||||
pg.evaluate("__studio.select(null)")
|
||||
pg.evaluate("localStorage.removeItem('isokit-anim')")
|
||||
an = lambda: pg.evaluate("__studio.view.animation()")
|
||||
running = lambda: pg.evaluate("document.querySelector('.iso-svg').getAnimations({subtree: true}).filter(a => a.playState === 'running').length")
|
||||
t0 = pg.evaluate("(() => { const a = document.querySelector('.iso-svg').getAnimations({subtree: true}); return a.length ? a[0].currentTime : null; })()")
|
||||
pg.wait_for_timeout(600)
|
||||
t1 = pg.evaluate("(() => { const a = document.querySelector('.iso-svg').getAnimations({subtree: true}); return a.length ? a[0].currentTime : null; })()")
|
||||
check(an() == "light" and running() == 0 and t0 is not None and 300 < t1 - t0 < 900,
|
||||
f"animations are light by default: none runs on its own, they step on ({t0} -> {t1})")
|
||||
btn = pg.locator('.iso-bar [data-a="anim"]')
|
||||
btn.click()
|
||||
pg.wait_for_timeout(500)
|
||||
check(an() == "smooth" and running() > 0 and "smooth" in btn.get_attribute("title"), f"the button switches to smooth ({running()} running)")
|
||||
btn.click()
|
||||
pg.wait_for_timeout(300)
|
||||
check(an() == "off" and running() == 0, "then off")
|
||||
btn.click()
|
||||
pg.wait_for_timeout(300)
|
||||
check(an() == "light" and pg.evaluate("localStorage.getItem('isokit-anim')") == "light", "then light again, remembered")
|
||||
vb0 = pg.evaluate("document.querySelector('.iso-svg').getAttribute('viewBox')")
|
||||
bx = pg.locator(".iso-stage").bounding_box()
|
||||
cx2, cy2 = bx["x"] + bx["width"] / 2, bx["y"] + bx["height"] / 2
|
||||
pg.mouse.move(cx2, cy2)
|
||||
pg.mouse.down(button="middle")
|
||||
for i in range(1, 9):
|
||||
pg.mouse.move(cx2 + 10 * i, cy2 + 4 * i)
|
||||
pg.wait_for_timeout(20)
|
||||
mid = pg.evaluate("[document.querySelector('.iso-svg').getAttribute('viewBox'), document.querySelector('.iso-svg').style.transform, document.querySelector('.iso-gesture') !== null]")
|
||||
pg.mouse.up(button="middle")
|
||||
pg.wait_for_timeout(300)
|
||||
end = pg.evaluate("[document.querySelector('.iso-svg').getAttribute('viewBox'), document.querySelector('.iso-svg').style.transform, document.querySelector('.iso-gesture') !== null]")
|
||||
check(mid[0] == vb0 and "translate" in mid[1] and mid[2] and end[0] != vb0 and end[1] == "" and not end[2],
|
||||
f"a pan moves the layer (viewBox kept, transform {mid[1][:40]}), the release draws it again")
|
||||
check(pg.evaluate("getComputedStyle(document.getElementById('cursor')).contain").startswith("strict") or "size" in pg.evaluate("getComputedStyle(document.getElementById('cursor')).contain"),
|
||||
"the pointer readout is a contained box (its text does not lay the page out again)")
|
||||
|
||||
# the middle mouse button only moves the camera: it never drags, selects or places anything
|
||||
pg.locator('#objects li[data-id="truck"]').click()
|
||||
pg.evaluate("__studio.view.focus('truck', 3)")
|
||||
|
||||
Reference in new issue
Block a user