code wiki / _hdl_build / nx_browser_xp.nx
nx_browser_xp.nx source
↩ module page · 96 lines · 4751 B
1// nx_browser_xp.nx -- EXPERIENTIAL BROWSER TEST, reusable organ + MCP tool. Drives the REAL render core
2// (br_layout + br_draw_fb_at -- the SAME path every OS surface ships) through a human SCROLL session on any
3// staged page and RECORDS it as a browser-playable APNG MOVIE + a full-page shot. Proves render behavior the
4// way a human tester SEES it, no human needed -- the experiential-evidence capability, callable over MCP.
5// argv[1] = html file to load (default _offc/nxhtml.html)
6// argv[2] = output path prefix (default knowledge/status/xp)
7// Writes <prefix>_scroll.png (APNG, 12 frames top->bottom) + <prefix>_full.png (full-page RGB shot).
8// license_tier: ORIGINAL expect_exit: 0
9import "nx_browser_render.nx"
10import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
11import "nx_apng_write.nx"
12
13func xp_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
14// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
15// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
16// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
17// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
18func xp_num(v: i64) -> i64 { nxi_out(v); return 0 }
19
20const XP_VW: i64 = 500 // viewport width in page px (scale 1 -> 500px-wide frames)
21const XP_VH: i64 = 400 // viewport height in page px
22const XP_NF: i64 = 12 // scroll frames top->bottom
23
24// render one scroll frame at scale 1 into rgb (XP_VW x XP_VH)
25func xp_frame(page: *Page, sy: i64, url: *u8, ulen: i64, rgb: *u8) -> i64 {
26 let fb: *Framebuffer = sys_mmap(NX_FRAMEBUFFER_BYTES) as *Framebuffer
27 let px: *u8 = sys_mmap(XP_VW*XP_VH*4 + 64)
28 nx_framebuffer_init(fb, px, XP_VW, XP_VH)
29 br_draw_fb_at(fb, page, XP_VW, url, ulen, 1, sy)
30 var p: i64 = 0
31 while p < XP_VW*XP_VH { rgb[p*3]=px[p*4]; rgb[p*3+1]=px[p*4+1]; rgb[p*3+2]=px[p*4+2]; p=p+1 }
32 return 0
33}
34// build "<prefix><suffix>" (both null-terminated) into out; returns len
35func xp_path(prefix: *u8, suffix: *u8, out: *u8) -> i64 {
36 var n: i64 = 0
37 while prefix[n]!=(0 as u8) { out[n]=prefix[n]; n=n+1 }
38 var j: i64 = 0
39 while suffix[j]!=(0 as u8) { out[n]=suffix[j]; n=n+1; j=j+1 }
40 out[n]=0 as u8
41 return n
42}
43
44func main(argc: i64, argv: *i64) -> i64 {
45 var htmlpath: *u8 = "_offc/nxhtml.html\x00" as *u8
46 if argc > 1 { htmlpath = argv[1] as *u8 }
47 var prefix: *u8 = "knowledge/status/xp\x00" as *u8
48 if argc > 2 { prefix = argv[2] as *u8 }
49
50 xp_puts("BROWSER-XP: experiential scroll session on " as *u8); xp_puts(htmlpath); xp_puts("\n" as *u8)
51 let lp: *i64 = sys_mmap(16) as *i64
52 let html: *u8 = sys_read_file(htmlpath, lp)
53 if lp[0] <= 0 { xp_puts("xp: cannot read html\n" as *u8); sys_exit(1); return 1 }
54
55 let page: *Page = sys_mmap(NX_PAGE_BYTES) as *Page
56 page.raw = html
57 page.raw_len = lp[0]
58 br_layout(page, XP_VW)
59 if page.ok != 1 { xp_puts("xp: layout failed\n" as *u8); sys_exit(2); return 2 }
60 xp_puts(" layout ok page_h=" as *u8); xp_num(page.page_h); xp_puts("\n" as *u8)
61
62 // ---- SCROLL MOVIE: XP_NF frames from top to bottom ----
63 let sp: *u8 = sys_mmap(512)
64 xp_path(prefix, "_scroll.png\x00" as *u8, sp)
65 let rgb: *u8 = sys_mmap(XP_VW*XP_VH*3 + 64)
66 let st: *ApngState = sys_mmap(NX_APNG_STATE_BYTES) as *ApngState
67 apng_open(st, sp, XP_VW, XP_VH, XP_NF, 1, 4)
68 var maxsy: i64 = page.page_h - XP_VH
69 if maxsy < 0 { maxsy = 0 }
70 var f: i64 = 0
71 while f < XP_NF {
72 var sy: i64 = 0
73 if XP_NF > 1 { sy = (maxsy * f) / (XP_NF - 1) }
74 xp_frame(page, sy, "nishi://xp/scroll\x00" as *u8, 17, rgb)
75 apng_frame(st, rgb)
76 f = f + 1
77 }
78 apng_close(st)
79 xp_puts(" SCROLL MOVIE: " as *u8); xp_num(XP_NF); xp_puts(" frames -> " as *u8); xp_puts(sp); xp_puts("\n" as *u8)
80
81 // ---- FULL-PAGE SHOT (still) ----
82 let fpp: *u8 = sys_mmap(512)
83 xp_path(prefix, "_full.png\x00" as *u8, fpp)
84 br_shot_png(page, "nishi://xp/full\x00" as *u8, 15, fpp)
85 xp_puts(" FULL SHOT -> " as *u8); xp_puts(fpp); xp_puts("\n" as *u8)
86
87 // ---- verify the movie landed + is animated (acTL chunk 'a''c' at bytes 37-38 after IHDR) ----
88 let vp: *i64 = sys_mmap(16) as *i64
89 vp[0] = 0 - 1
90 let cb: *u8 = sys_read_file(sp, vp)
91 var ok: i64 = 0
92 if vp[0] > 50000 { if (cb[37] as i64)==97 { if (cb[38] as i64)==99 { ok=1 } } }
93 xp_puts("BROWSER-XP verdict=" as *u8)
94 if ok==1 { xp_puts("GREEN movie_bytes=" as *u8); xp_num(vp[0]); xp_puts("\n" as *u8); sys_exit(0); return 0 }
95 xp_puts("RED (movie missing / not animated)\n" as *u8); sys_exit(1); return 1
96}