ouroboros / source /scripts /check_scroll_story_layout.py
REXWind's picture
Publish the Ouroboros scientific showcase to CladeTeam
03677d0 verified
Raw History Blame Contribute Delete
3.51 kB
"""Targeted scroll-scene layout, rewind, and visibility-state regression."""
from playwright.sync_api import sync_playwright,expect
from pathlib import Path
import os,json
out=Path('artifacts/scroll-story-20261110')
with sync_playwright() as p:
b=p.chromium.launch(executable_path=os.environ.get('CHROMIUM_PATH'),args=['--no-sandbox','--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader'])
page=b.new_page(viewport={'width':1280,'height':720})
errors=[]
page.on('pageerror',lambda e:errors.append(str(e)))
page.goto(os.environ.get('PREVIEW_URL','http://127.0.0.1:7860'),wait_until='networkidle')
def at(p):
page.locator('.story-scroll').evaluate('(e,p)=>{const s=e.querySelector(".story-stage");window.scrollTo({top:scrollY+e.getBoundingClientRect().top-82+(e.offsetHeight-s.offsetHeight)*p,behavior:"instant"})}',p)
page.wait_for_timeout(1100)
at(.23)
expect(page.locator('.story-stage')).to_have_attribute('data-beat','1')
# Moving packets stay clear of the projection title/equation band.
at(.385);frame=page.locator('.dual-scene-svg').inner_html()
at(.96);at(.385)
assert page.locator('.dual-scene-svg').inner_html()==frame
at(1)
page.screenshot(path=str(out/'desktop-1280x720-joint.png'))
assert page.locator('.story-scrubber').bounding_box()['y'] < 720
svg=page.locator('.dual-scene-svg').bounding_box()
chapters=page.locator('.story-chapters').bounding_box()
assert svg['y']+svg['height'] <= chapters['y'], (svg, chapters)
assert page.locator('.ds-objective').bounding_box()['y'] < chapters['y']
page.locator('.story-chapters button').first.click()
expect(page.locator('.story-stage')).to_have_attribute('data-beat','0')
at(1)
assert page.evaluate('document.documentElement.scrollWidth<=innerWidth')
page.set_viewport_size({'width':1920,'height':1080});at(.475)
page.screenshot(path=str(out/'desktop-1920-residues.png'))
assert page.evaluate('document.documentElement.scrollWidth<=innerWidth')
page.set_viewport_size({'width':1440,'height':620})
expect(page.locator('#dual-learning')).to_have_attribute('data-story-mode','reading')
page.set_viewport_size({'width':1440,'height':1000})
expect(page.locator('#dual-learning')).to_have_attribute('data-story-mode','scroll')
# Runtime reduction yields all steps, and is reversible.
page.emulate_media(reduced_motion='reduce')
expect(page.locator('.reading-step')).to_have_count(6)
page.emulate_media(reduced_motion='no-preference')
at(.23)
# Dispatch the browser visibility event with its hidden state to exercise cleanup.
page.evaluate('Object.defineProperty(document,"hidden",{configurable:true,get:()=>true});document.dispatchEvent(new Event("visibilitychange"))')
page.wait_for_timeout(100)
frozen=page.locator('.story-stage').get_attribute('data-progress')
page.mouse.wheel(0,250);page.wait_for_timeout(400)
assert page.locator('.story-stage').get_attribute('data-progress')==frozen
page.evaluate('delete document.hidden;document.dispatchEvent(new Event("visibilitychange"))')
page.wait_for_timeout(1200)
assert page.locator('.story-stage').get_attribute('data-progress')!=frozen
assert not errors,errors
b.close()
(out/'final-layout-report.json').write_text(json.dumps({'checks':['1280x720 complete sticky stage','1920x1080 display','short viewport reading fallback','rewind after final projection-layout change','runtime reduced-motion switching','simulated hidden-tab visibility event freeze and resume'],'errors':errors},indent=2))
print('Final layout and timeline checks passed')