nx_font_gen.nx source
↩ module page · 238 lines · 16380 B
1// nx_font_gen.nx -- the GEN-AXES rung: a PARAMETRIC font GENERATOR (not one font). Glyphs are defined ONCE as
2// stroke CENTERLINES; a WEIGHT parameter (stroke radius) drives outline generation (each stroke -> a rectangle
3// contour, offset by the weight; multiple contours per glyph, TrueType nonzero-winding fills the union). ONE
4// definition -> a FAMILY: emits nishi_light/regular/bold.ttf (3 weights) from the same strokes, plus a comparison
5// page nishi_weights.html. Reuses the self-validated sfnt emitter (nx_font_ttf_emit) verbatim. Glyphs H I T (+
6// .notdef, space). These are 3 STATIC instances of the generator; the single-file VARIABLE font (gvar deltas) is
7// the next rung. license_tier: ORIGINAL expect_exit: 0
8import "nx_syscalls_x86_64.nx"
9const MAGIC_MAGIC_65536: i64 = 65536
10const MAGIC_MAGIC_16777216: i64 = 16777216
11const MAGIC_MAGIC_4294967296: i64 = 4294967296
12const MAGIC_MAGIC_4096: i64 = 4096
13const MAGIC_MAGIC_65535: i64 = 65535
14const MAGIC_MAGIC_65505: i64 = 65505
15const MAGIC_MAGIC_65466: i64 = 65466
16const MAGIC_MAGIC_65456: i64 = 65456
17const MAGIC_MAGIC_1594834165: i64 = 1594834165
18const MAGIC_MAGIC_1033: i64 = 1033
19const MAGIC_MAGIC_196608: i64 = 196608
20const MAGIC_MAGIC_262144: i64 = 262144
21const MAGIC_MAGIC_16384: i64 = 16384
22
23const MAGIC_ADJ: i64 = 2981146554
24
25func sw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
26func sn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 }
27
28func si16(v: i64) -> i64 { if v<0 { return v+MAGIC_MAGIC_65536 } return v }
29func w8(b: *u8, o: i64, v: i64) -> i64 { b[o]=(v%256) as u8; return o+1 }
30func w16(b: *u8, o: i64, v: i64) -> i64 { b[o]=((v/256)%256) as u8; b[o+1]=(v%256) as u8; return o+2 }
31func w32(b: *u8, o: i64, v: i64) -> i64 { b[o]=((v/MAGIC_MAGIC_16777216)%256) as u8; b[o+1]=((v/MAGIC_MAGIC_65536)%256) as u8; b[o+2]=((v/256)%256) as u8; b[o+3]=(v%256) as u8; return o+4 }
32func r16(b: *u8, o: i64) -> i64 { return (b[o] as i64)*256 + (b[o+1] as i64) }
33func r32(b: *u8, o: i64) -> i64 { return (b[o] as i64)*MAGIC_MAGIC_16777216 + (b[o+1] as i64)*MAGIC_MAGIC_65536 + (b[o+2] as i64)*256 + (b[o+3] as i64) }
34func align4(o: i64) -> i64 { while o%4 != 0 { o=o+1 } return o }
35func csum(b: *u8, off: i64, len: i64) -> i64 { var s: i64=0; var i: i64=off; while i < off+len { s = (s + r32(b,i)) % MAGIC_MAGIC_4294967296; i=i+4 } return s }
36func he_puts(buf: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var i: i64=0; while s[i]!=0 { buf[o]=s[i]; o=o+1; i=i+1 } return o }
37
38func b64c(v: i64) -> i64 { if v<26 { return 65+v } if v<52 { return 97+(v-26) } if v<62 { return 48+(v-52) } if v==62 { return 43 } return 47 }
39func b64_encode(inb: *u8, n: i64, out: *u8) -> i64 {
40 var o: i64=0; var i: i64=0
41 while i+3<=n { let a: i64=inb[i] as i64; let b: i64=inb[i+1] as i64; let c: i64=inb[i+2] as i64
42 out[o]=b64c(a/4) as u8; o=o+1; out[o]=b64c((a%4)*16 + b/16) as u8; o=o+1; out[o]=b64c((b%16)*4 + c/64) as u8; o=o+1; out[o]=b64c(c%64) as u8; o=o+1; i=i+3 }
43 let rem: i64=n-i
44 if rem==1 { let a: i64=inb[i] as i64; out[o]=b64c(a/4) as u8; o=o+1; out[o]=b64c((a%4)*16) as u8; o=o+1; out[o]=61 as u8; o=o+1; out[o]=61 as u8; o=o+1 }
45 if rem==2 { let a: i64=inb[i] as i64; let b: i64=inb[i+1] as i64; out[o]=b64c(a/4) as u8; o=o+1; out[o]=b64c((a%4)*16 + b/16) as u8; o=o+1; out[o]=b64c((b%16)*4) as u8; o=o+1; out[o]=61 as u8; o=o+1 }
46 out[o]=0 as u8; return o
47}
48
49// --- PARAMETRIC GENERATOR: strokes + weight radius wr -> rectangle contours ---
50func add_rect(px: *i64, py: *i64, ep: *i64, pc: i64, cc: i64, x0: i64, y0: i64, x1: i64, y1: i64) -> i64 {
51 px[pc]=x0; py[pc]=y0; px[pc+1]=x1; py[pc+1]=y0; px[pc+2]=x1; py[pc+2]=y1; px[pc+3]=x0; py[pc+3]=y1
52 ep[cc]=pc+3
53 return pc+4
54}
55// gid: 0 .notdef, 1 space, 2 H, 3 I, 4 T. wr = weight radius (stroke half-thickness).
56func gen_glyph(gid: i64, wr: i64, ep: *i64, px: *i64, py: *i64, meta: *i64) -> i64 {
57 if gid==0 { add_rect(px,py,ep,0,0, 80,0,520,700); meta[0]=1; meta[1]=4; return 0 }
58 if gid==1 { meta[0]=0; meta[1]=0; return 0 }
59 if gid==2 { // H: 2 verticals + mid bar
60 var pc: i64=0
61 pc=add_rect(px,py,ep,pc,0, 210-wr,0,210+wr,700)
62 pc=add_rect(px,py,ep,pc,1, 560-wr,0,560+wr,700)
63 pc=add_rect(px,py,ep,pc,2, 210,350-wr,560,350+wr)
64 meta[0]=3; meta[1]=12; return 0
65 }
66 if gid==3 { add_rect(px,py,ep,0,0, 385-wr,0,385+wr,700); meta[0]=1; meta[1]=4; return 0 } // I
67 var tc: i64=0 // T: top bar + stem
68 tc=add_rect(px,py,ep,tc,0, 60,700-2*wr,660,700)
69 tc=add_rect(px,py,ep,tc,1, 360-wr,0,360+wr,700)
70 meta[0]=2; meta[1]=8; return 0
71}
72
73func append_glyph(g: *u8, go: i64, ep: *i64, px: *i64, py: *i64, meta: *i64) -> i64 {
74 let nc: i64=meta[0]; let np: i64=meta[1]
75 if nc==0 { return go }
76 var xmin: i64=px[0]; var xmax: i64=px[0]; var ymin: i64=py[0]; var ymax: i64=py[0]
77 var i: i64=0
78 while i<np { if px[i]<xmin{xmin=px[i]} if px[i]>xmax{xmax=px[i]} if py[i]<ymin{ymin=py[i]} if py[i]>ymax{ymax=py[i]} i=i+1 }
79 var o: i64=go
80 o=w16(g,o,si16(nc)); o=w16(g,o,si16(xmin)); o=w16(g,o,si16(ymin)); o=w16(g,o,si16(xmax)); o=w16(g,o,si16(ymax))
81 i=0; while i<nc { o=w16(g,o,ep[i]); i=i+1 }
82 o=w16(g,o,0)
83 i=0; while i<np { o=w8(g,o,1); i=i+1 }
84 var prev: i64=0; i=0; while i<np { o=w16(g,o,si16(px[i]-prev)); prev=px[i]; i=i+1 }
85 prev=0; i=0; while i<np { o=w16(g,o,si16(py[i]-prev)); prev=py[i]; i=i+1 }
86 if o%2 != 0 { o=w8(g,o,0) }
87 return o
88}
89
90// emit a full sfnt into buf at weight wr. return total bytes. (sfnt logic = the self-validated nx_font_ttf_emit)
91func emit_ttf(buf: *u8, wr: i64) -> i64 {
92 let ep: *i64=sys_mmap(64) as *i64
93 let px: *i64=sys_mmap(512) as *i64
94 let py: *i64=sys_mmap(512) as *i64
95 let meta: *i64=sys_mmap(16) as *i64
96 let g: *u8=sys_mmap(MAGIC_MAGIC_4096)
97 let goff: *i64=sys_mmap(64) as *i64
98 var go: i64=0
99 var gid: i64=0
100 while gid<5 { goff[gid]=go; gen_glyph(gid,wr,ep,px,py,meta); go=append_glyph(g,go,ep,px,py,meta); gid=gid+1 }
101 goff[5]=go
102 let glyf_len: i64=go
103
104 let toff: *i64=sys_mmap(128) as *i64
105 let tlen: *i64=sys_mmap(128) as *i64
106 let tcs: *i64=sys_mmap(128) as *i64
107 let NT: i64=10
108 var o: i64=12 + 16*NT
109
110 o=align4(o); toff[0]=o
111 o=w16(buf,o,4); o=w16(buf,o,si16(600)); o=w16(buf,o,400); o=w16(buf,o,5); o=w16(buf,o,0)
112 o=w16(buf,o,si16(650));o=w16(buf,o,si16(700));o=w16(buf,o,si16(0));o=w16(buf,o,si16(140))
113 o=w16(buf,o,si16(650));o=w16(buf,o,si16(700));o=w16(buf,o,si16(0));o=w16(buf,o,si16(480))
114 o=w16(buf,o,si16(50));o=w16(buf,o,si16(260)); o=w16(buf,o,si16(0))
115 var pi: i64=0; while pi<10 { o=w8(buf,o,0); pi=pi+1 }
116 o=w32(buf,o,0);o=w32(buf,o,0);o=w32(buf,o,0);o=w32(buf,o,0)
117 o=w8(buf,o,78);o=w8(buf,o,73);o=w8(buf,o,83);o=w8(buf,o,72)
118 o=w16(buf,o,64); o=w16(buf,o,32); o=w16(buf,o,84)
119 o=w16(buf,o,si16(800));o=w16(buf,o,si16(-200));o=w16(buf,o,si16(0))
120 o=w16(buf,o,800);o=w16(buf,o,200)
121 o=w32(buf,o,1);o=w32(buf,o,0)
122 o=w16(buf,o,si16(500));o=w16(buf,o,si16(700)); o=w16(buf,o,0);o=w16(buf,o,32);o=w16(buf,o,1)
123 tlen[0]=o-toff[0]; o=align4(o); tcs[0]=csum(buf,toff[0],o-toff[0])
124
125 o=align4(o); toff[1]=o
126 o=w16(buf,o,0); o=w16(buf,o,1); o=w16(buf,o,3); o=w16(buf,o,1); o=w32(buf,o,12)
127 o=w16(buf,o,4); o=w16(buf,o,48); o=w16(buf,o,0); o=w16(buf,o,8); o=w16(buf,o,8); o=w16(buf,o,2); o=w16(buf,o,0)
128 o=w16(buf,o,32); o=w16(buf,o,73); o=w16(buf,o,84); o=w16(buf,o,MAGIC_MAGIC_65535)
129 o=w16(buf,o,0)
130 o=w16(buf,o,32); o=w16(buf,o,72); o=w16(buf,o,84); o=w16(buf,o,MAGIC_MAGIC_65535)
131 o=w16(buf,o,MAGIC_MAGIC_65505); o=w16(buf,o,MAGIC_MAGIC_65466); o=w16(buf,o,MAGIC_MAGIC_65456); o=w16(buf,o,1)
132 o=w16(buf,o,0); o=w16(buf,o,0); o=w16(buf,o,0); o=w16(buf,o,0)
133 tlen[1]=o-toff[1]; o=align4(o); tcs[1]=csum(buf,toff[1],o-toff[1])
134
135 o=align4(o); toff[2]=o
136 var gj: i64=0; while gj<glyf_len { buf[o]=g[gj]; o=o+1; gj=gj+1 }
137 tlen[2]=o-toff[2]; o=align4(o); tcs[2]=csum(buf,toff[2],o-toff[2])
138
139 o=align4(o); toff[3]=o
140 o=w32(buf,o,MAGIC_MAGIC_65536); o=w32(buf,o,MAGIC_MAGIC_65536); o=w32(buf,o,0); o=w32(buf,o,MAGIC_MAGIC_1594834165)
141 o=w16(buf,o,11); o=w16(buf,o,1000)
142 o=w32(buf,o,0);o=w32(buf,o,0); o=w32(buf,o,0);o=w32(buf,o,0)
143 o=w16(buf,o,si16(0));o=w16(buf,o,si16(0));o=w16(buf,o,720);o=w16(buf,o,700)
144 o=w16(buf,o,0); o=w16(buf,o,8); o=w16(buf,o,2); o=w16(buf,o,0); o=w16(buf,o,0)
145 tlen[3]=o-toff[3]; o=align4(o); tcs[3]=csum(buf,toff[3],o-toff[3])
146
147 o=align4(o); toff[4]=o
148 o=w32(buf,o,MAGIC_MAGIC_65536); o=w16(buf,o,si16(800)); o=w16(buf,o,si16(-200)); o=w16(buf,o,si16(0))
149 o=w16(buf,o,720); o=w16(buf,o,si16(0)); o=w16(buf,o,si16(0)); o=w16(buf,o,si16(720))
150 o=w16(buf,o,si16(1)); o=w16(buf,o,si16(0)); o=w16(buf,o,si16(0))
151 o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0)
152 o=w16(buf,o,si16(0)); o=w16(buf,o,5)
153 tlen[4]=o-toff[4]; o=align4(o); tcs[4]=csum(buf,toff[4],o-toff[4])
154
155 o=align4(o); toff[5]=o
156 o=w16(buf,o,600);o=w16(buf,o,si16(80)); o=w16(buf,o,400);o=w16(buf,o,si16(0)); o=w16(buf,o,700);o=w16(buf,o,si16(130)); o=w16(buf,o,600);o=w16(buf,o,si16(250)); o=w16(buf,o,720);o=w16(buf,o,si16(60))
157 tlen[5]=o-toff[5]; o=align4(o); tcs[5]=csum(buf,toff[5],o-toff[5])
158
159 o=align4(o); toff[6]=o
160 var li: i64=0; while li<6 { o=w16(buf,o,goff[li]/2); li=li+1 }
161 tlen[6]=o-toff[6]; o=align4(o); tcs[6]=csum(buf,toff[6],o-toff[6])
162
163 o=align4(o); toff[7]=o
164 o=w32(buf,o,MAGIC_MAGIC_65536); o=w16(buf,o,5); o=w16(buf,o,12); o=w16(buf,o,3)
165 o=w16(buf,o,0);o=w16(buf,o,0); o=w16(buf,o,2); o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0);o=w16(buf,o,0)
166 tlen[7]=o-toff[7]; o=align4(o); tcs[7]=csum(buf,toff[7],o-toff[7])
167
168 o=align4(o); toff[8]=o
169 o=w16(buf,o,0); o=w16(buf,o,4); o=w16(buf,o,54)
170 o=w16(buf,o,3);o=w16(buf,o,1);o=w16(buf,o,MAGIC_MAGIC_1033);o=w16(buf,o,1);o=w16(buf,o,20);o=w16(buf,o,0)
171 o=w16(buf,o,3);o=w16(buf,o,1);o=w16(buf,o,MAGIC_MAGIC_1033);o=w16(buf,o,2);o=w16(buf,o,14);o=w16(buf,o,20)
172 o=w16(buf,o,3);o=w16(buf,o,1);o=w16(buf,o,MAGIC_MAGIC_1033);o=w16(buf,o,4);o=w16(buf,o,20);o=w16(buf,o,0)
173 o=w16(buf,o,3);o=w16(buf,o,1);o=w16(buf,o,MAGIC_MAGIC_1033);o=w16(buf,o,6);o=w16(buf,o,18);o=w16(buf,o,34)
174 o=he_puts(buf,o,"" as *u8)
175 o=w8(buf,o,0);o=w8(buf,o,78);o=w8(buf,o,0);o=w8(buf,o,105);o=w8(buf,o,0);o=w8(buf,o,115);o=w8(buf,o,0);o=w8(buf,o,104);o=w8(buf,o,0);o=w8(buf,o,105);o=w8(buf,o,0);o=w8(buf,o,32);o=w8(buf,o,0);o=w8(buf,o,83);o=w8(buf,o,0);o=w8(buf,o,97);o=w8(buf,o,0);o=w8(buf,o,110);o=w8(buf,o,0);o=w8(buf,o,115)
176 o=w8(buf,o,0);o=w8(buf,o,82);o=w8(buf,o,0);o=w8(buf,o,101);o=w8(buf,o,0);o=w8(buf,o,103);o=w8(buf,o,0);o=w8(buf,o,117);o=w8(buf,o,0);o=w8(buf,o,108);o=w8(buf,o,0);o=w8(buf,o,97);o=w8(buf,o,0);o=w8(buf,o,114)
177 o=w8(buf,o,0);o=w8(buf,o,78);o=w8(buf,o,0);o=w8(buf,o,105);o=w8(buf,o,0);o=w8(buf,o,115);o=w8(buf,o,0);o=w8(buf,o,104);o=w8(buf,o,0);o=w8(buf,o,105);o=w8(buf,o,0);o=w8(buf,o,83);o=w8(buf,o,0);o=w8(buf,o,97);o=w8(buf,o,0);o=w8(buf,o,110);o=w8(buf,o,0);o=w8(buf,o,115)
178 tlen[8]=o-toff[8]; o=align4(o); tcs[8]=csum(buf,toff[8],o-toff[8])
179
180 o=align4(o); toff[9]=o
181 o=w32(buf,o,MAGIC_MAGIC_196608); o=w32(buf,o,0); o=w16(buf,o,si16(-100)); o=w16(buf,o,50); o=w32(buf,o,0);o=w32(buf,o,0);o=w32(buf,o,0);o=w32(buf,o,0);o=w32(buf,o,0)
182 tlen[9]=o-toff[9]; o=align4(o); tcs[9]=csum(buf,toff[9],o-toff[9])
183
184 let total: i64=o
185 var hh: i64=0
186 hh=w32(buf,hh,MAGIC_MAGIC_65536); hh=w16(buf,hh,NT); hh=w16(buf,hh,128); hh=w16(buf,hh,3); hh=w16(buf,hh,32)
187 let tags: *u8="OS/2cmapglyfheadhheahmtxlocamaxpnamepost" as *u8
188 var d: i64=12; var ti: i64=0
189 while ti<NT { buf[d]=tags[ti*4]; buf[d+1]=tags[ti*4+1]; buf[d+2]=tags[ti*4+2]; buf[d+3]=tags[ti*4+3]
190 w32(buf,d+4,tcs[ti]); w32(buf,d+8,toff[ti]); w32(buf,d+12,tlen[ti]); d=d+16; ti=ti+1 }
191 let fsum0: i64=csum(buf,0,total)
192 var adj: i64=MAGIC_ADJ - fsum0
193 if adj<0 { adj=adj+MAGIC_MAGIC_4294967296 }
194 w32(buf, toff[3]+8, adj)
195 return total
196}
197
198func main() -> i64 {
199 let W: *i64=sys_mmap(32) as *i64
200 W[0]=40; W[1]=66; W[2]=104 // light / regular / bold radii (the WEIGHT axis)
201 let b64: *u8=sys_mmap(MAGIC_MAGIC_65536)
202 let pg: *u8=sys_mmap(MAGIC_MAGIC_262144)
203 var po: i64=0
204 po=he_puts(pg,po,"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><meta name=\"color-scheme\" content=\"dark\"><title>Nishi Sans — one generator, a whole family</title><style>" as *u8)
205
206 var wi: i64=0
207 while wi<3 {
208 let buf: *u8=sys_mmap(MAGIC_MAGIC_16384) // fresh (zeroed) per weight
209 let total: i64=emit_ttf(buf, W[wi])
210 var path: *u8="web_assets/nishi_regular.ttf" as *u8
211 var fam: *u8="Nishi Regular" as *u8
212 if wi==0 { path="web_assets/nishi_light.ttf" as *u8; fam="Nishi Light" as *u8 }
213 if wi==2 { path="web_assets/nishi_bold.ttf" as *u8; fam="Nishi Bold" as *u8 }
214 let fd: i64=sys_openat_wr(path, 420)
215 if fd<0 { sw("SAVE-FAIL\n" as *u8); return 6 }
216 sys_write(fd, buf, total); sys_close(fd)
217 let fs: i64=csum(buf,0,total)
218 sw(" weight r=" as *u8); sn(W[wi]); sw(" -> " as *u8); sw(path); sw(" (" as *u8); sn(total); sw("B) self-check=" as *u8)
219 if fs==MAGIC_ADJ { sw("PASS\n" as *u8) } else { sw("FAIL\n" as *u8) }
220 b64_encode(buf, total, b64)
221 po=he_puts(pg,po,"@font-face{font-family:'" as *u8); po=he_puts(pg,po,fam); po=he_puts(pg,po,"';src:url(data:font/ttf;base64," as *u8); po=he_puts(pg,po,b64); po=he_puts(pg,po,") format('truetype')}" as *u8)
222 wi=wi+1
223 }
224
225 po=he_puts(pg,po,"*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;background:radial-gradient(1000px 500px at 50% -10%,#161326,#0A0A0F);color:#F5F5FA;font-family:ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif}.wrap{text-align:center;padding:32px}.tag{display:inline-block;font-size:.8rem;letter-spacing:.2em;text-transform:uppercase;color:#9EA0B8;margin-bottom:14px}.row{font-size:clamp(3rem,15vw,9rem);line-height:1.05;letter-spacing:.06em;background:linear-gradient(100deg,#8A7BFF,#FF7A59);-webkit-background-clip:text;background-clip:text;color:transparent}.l{font-family:'Nishi Light'}.r{font-family:'Nishi Regular'}.b{font-family:'Nishi Bold'}.cap{font-size:.75rem;letter-spacing:.15em;text-transform:uppercase;color:#6f7290;margin-top:2px}.note{color:#9EA0B8;max-width:48ch;margin:34px auto 0;font-size:1.05rem;line-height:1.65}.note b{color:#F5F5FA}.mono{font-family:ui-monospace,Consolas,monospace;color:#8A7BFF}</style></head><body><div class=\"wrap\">" as *u8)
226 po=he_puts(pg,po,"<span class=\"tag\">★ one generator → a whole family</span>" as *u8)
227 po=he_puts(pg,po,"<div class=\"row l\">HI IT</div><div class=\"cap\">Light — stroke r=40</div>" as *u8)
228 po=he_puts(pg,po,"<div class=\"row r\">HI IT</div><div class=\"cap\">Regular — stroke r=66</div>" as *u8)
229 po=he_puts(pg,po,"<div class=\"row b\">HI IT</div><div class=\"cap\">Bold — stroke r=104</div>" as *u8)
230 po=he_puts(pg,po,"<p class=\"note\">All three weights are the <b>same glyph definition</b> — stroke centerlines — run through <span class=\"mono\">nx_font_gen</span> at a different <b>weight parameter</b>. That is a font <b>generator</b>, not one font: change a number, get a new instance. Each is a real self-validated <span class=\"mono\">.ttf</span>. Next rung: fold these into ONE variable font (a weight axis), then the full alphabet, then more scripts.</p>" as *u8)
231 po=he_puts(pg,po,"</div></body></html>" as *u8)
232
233 let pfd: i64=sys_openat_wr("web_assets/nishi_weights.html" as *u8, 420)
234 if pfd<0 { sw("PAGE-SAVE-FAIL\n" as *u8); return 7 }
235 sys_write(pfd, pg, po); sys_close(pfd)
236 sw("nx_font_gen: 3 weights generated from ONE stroke definition -> web_assets/nishi_weights.html\n" as *u8)
237 return 0
238}