code wiki / (root) / nx_font_gen.nx

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 &mdash; 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\">&#9733; one generator &rarr; a whole family</span>" as *u8) 227 po=he_puts(pg,po,"<div class=\"row l\">HI IT</div><div class=\"cap\">Light &mdash; stroke r=40</div>" as *u8) 228 po=he_puts(pg,po,"<div class=\"row r\">HI IT</div><div class=\"cap\">Regular &mdash; stroke r=66</div>" as *u8) 229 po=he_puts(pg,po,"<div class=\"row b\">HI IT</div><div class=\"cap\">Bold &mdash; 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> &mdash; stroke centerlines &mdash; 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}