code wiki / (root) / nx_synth_serve.nx

nx_synth_serve.nx source

↩ module page · 344 lines · 21872 B

1// nx_synth_serve.nx -- the INTERACTIVE SYNTH STUDIO (all functionality LIVE): one loopback HTTP daemon that 2// serves the studio page + renders on demand. Type a caption -> neural text2motion clip; pick a move -> clip; 3// choose swap slots -> a creature still. Mounted behind the site proxy at /synth. Routes: 4// GET /synth or / -> the studio SPA 5// GET /synth/health -> {"ok":1} 6// POST /synth/api/text2motion body = caption text -> APNG (neural: learned encoder -> class -> tokens) 7// GET /synth/api/move?id=1..6 -> APNG (parametric move) 8// POST /synth/api/variant?sp&hv&ev&tv&build -> PNG still (swap-slot creature, skinned raymarch) 9// Forks per connection (heavy render mmaps reclaimed on child exit). Composes the proven synth organs; nothing 10// new in the render math. license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_skeleton.nx" 13import "nx_figure_render.nx" 14import "nx_movelib.nx" 15import "nx_motion_neural.nx" 16import "nx_text2motion.nx" 17import "nx_assetvariant.nx" 18import "nx_apng.nx" 19import "nx_png.nx" 20import "nx_pose_coach.nx" 21import "nx_lipsync.nx" 22import "nx_outfit.nx" 23 24// ---- tiny HTTP helpers (proven pattern from nx_gen_orchestrator) ------------------------------------ 25func sv_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 26func sv_itoa(dst: *u8, off: i64, v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; 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 o: i64=off; var q: i64=k-1; while q>=0{dst[o]=t[q];o=o+1;q=q-1} return o } 27func sv_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var i: i64=0; while s[i]!=(0 as u8){dst[o]=s[i]; o=o+1; i=i+1} return o } 28func sv_catb(dst: *u8, off: i64, src: *u8, n: i64) -> i64 { var o: i64=off; var i: i64=0; while i<n {dst[o]=src[i]; o=o+1; i=i+1} return o } 29func sv_starts(buf: *u8, n: i64, pre: *u8) -> i64 { var i: i64=0; while pre[i]!=(0 as u8){ if i>=n {return 0} if buf[i]!=pre[i]{return 0} i=i+1 } return 1 } 30func sv_find_seq(buf: *u8, n: i64, needle: *u8, nl: i64) -> i64 { if nl==0 {return 0} var i: i64=0; while i+nl<=n { var j: i64=0; var ok: i64=1; while j<nl { if buf[i+j]!=needle[j]{ok=0; j=nl} else {j=j+1} } if ok==1 {return i} i=i+1 } return 0-1 } 31func sv_send(cfd: i64, status: *u8, ctype: *u8, body: *u8, blen: i64) -> i64 { 32 let buf: *u8 = sys_mmap(262144); var o: i64 = 0 33 o = sv_cat(buf, o, "HTTP/1.1 " as *u8); o = sv_cat(buf, o, status) 34 o = sv_cat(buf, o, "\r\nContent-Type: " as *u8); o = sv_cat(buf, o, ctype) 35 o = sv_cat(buf, o, "\r\nContent-Length: " as *u8); o = sv_itoa(buf, o, blen) 36 o = sv_cat(buf, o, "\r\nConnection: close\r\nCache-Control: no-store\r\n\r\n" as *u8) 37 o = sv_catb(buf, o, body, blen) 38 sys_write(cfd, buf, o); return 0 39} 40func sv_send_bin(cfd: i64, ctype: *u8, body: *u8, blen: i64) -> i64 { 41 let hb: *u8 = sys_mmap(1024); var o: i64 = 0 42 o = sv_cat(hb, o, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8); o = sv_cat(hb, o, ctype) 43 o = sv_cat(hb, o, "\r\nContent-Length: " as *u8); o = sv_itoa(hb, o, blen) 44 o = sv_cat(hb, o, "\r\nConnection: close\r\nCache-Control: no-store\r\n\r\n" as *u8) 45 sys_write(cfd, hb, o) 46 var sent: i64 = 0 47 while sent < blen { let w: i64 = sys_write(cfd, (body as i64 + sent) as *u8, blen - sent); if w <= 0 { sent = blen } else { sent = sent + w } } 48 return 0 49} 50func sv_hdr_int(req: *u8, hend: i64, name: *u8, nl: i64) -> i64 { 51 let p: i64 = sv_find_seq(req, hend, name, nl); if p < 0 { return 0 } 52 var i: i64 = p + nl; if i < hend { if req[i]==(32 as u8) { i=i+1 } } 53 var v: i64 = 0; var stop: i64 = 0 54 while stop == 0 { if i >= hend { stop=1 } else { let c: i64 = req[i]&0xff; if c>=48 { if c<=57 { v=v*10+(c-48); i=i+1 } else { stop=1 } } else { stop=1 } } } 55 return v 56} 57func sv_read_full(cfd: i64, req: *u8, cap: i64) -> i64 { 58 var total: i64 = 0; var he: i64 = 0 - 1 59 while he < 0 { if total >= cap { return total } let r: i64 = sys_read(cfd, ((req as i64) + total) as *u8, cap - total); if r <= 0 { return total } total = total + r; he = sv_find_seq(req, total, "\r\n\r\n" as *u8, 4) } 60 let cl: i64 = sv_hdr_int(req, he, "\r\nContent-Length:" as *u8, 17) 61 var need: i64 = he + 4; if cl > 0 { need = he + 4 + cl } 62 while total < need { if total >= cap { return total } let r2: i64 = sys_read(cfd, ((req as i64) + total) as *u8, cap - total); if r2 <= 0 { return total } total = total + r2 } 63 return total 64} 65func sv_reqpath(req: *u8, rn: i64, out: *u8, cap: i64) -> i64 { 66 var s1: i64 = 0-1; var i: i64 = 0 67 while i < rn { if req[i]==(32 as u8) { s1=i; i=rn } else { i=i+1 } } 68 if s1 < 0 { out[0]=0 as u8; return 0 } 69 var p: i64 = s1+1; var o: i64 = 0 70 while p < rn { let c: u8 = req[p]; if c==(32 as u8) { p=rn } else { if o<cap-1 { out[o]=c; o=o+1 } p=p+1 } } 71 out[o]=0 as u8; return o 72} 73// query int: find "name=" in the request path, parse the decimal after it (default dflt). 74func sv_qint(path: *u8, pn: i64, name: *u8, dflt: i64) -> i64 { 75 let nl: i64 = sv_slen(name) 76 var i: i64 = 0 77 while i + nl + 1 <= pn { 78 var m: i64 = 1; var j: i64 = 0 79 while j < nl { if (path[i+j]&0xff)!=(name[j]&0xff) { m=0; j=nl } else { j=j+1 } } 80 if m == 1 { if (path[i+nl]&0xff)==61 { 81 var v: i64 = 0; var any: i64 = 0; var k: i64 = i+nl+1; var neg: i64 = 0 82 if k < pn { if (path[k]&0xff)==45 { neg=1; k=k+1 } } 83 var stop: i64 = 0 84 while stop==0 { if k>=pn { stop=1 } else { let c: i64 = path[k]&0xff; if c>=48 { if c<=57 { v=v*10+(c-48); any=1; k=k+1 } else { stop=1 } } else { stop=1 } } } 85 if any==1 { if neg==1 { return 0-v } return v } 86 } } 87 i = i + 1 88 } 89 return dflt 90} 91 92// ---- render: the FAST capsule figure (rig_draw) for motion; a zbuf lives per-call ------------------ 93const SV_W: i64 = 128 94const SV_H: i64 = 96 95 96// ---- POST /synth/api/text2motion : caption (body) -> neural motion APNG ---------------------------- 97func sv_do_text2motion(cfd: i64, body: *u8, bn: i64) -> i64 { 98 let cap: *u8 = sys_mmap(512) 99 var cl: i64 = bn; if cl > 500 { cl = 500 } 100 var i: i64 = 0; while i < cl { cap[i] = body[i]; i = i + 1 } cap[cl] = 0 as u8 101 let sk: i64 = sys_mmap(sk_bytes()) as i64 102 rig_build(sk) 103 let corpus: *i64 = sys_mmap(MN_N * MN_D * 8) as *i64 104 mn_build_corpus(sk, corpus) 105 let cb: *i64 = sys_mmap(MN_K * MN_D * 8) as *i64 106 mn_init_cb(corpus, cb); mn_train(corpus, cb, 15) 107 let tokens: *i64 = sys_mmap(MN_N * 8) as *i64 108 mn_tokenize(corpus, cb, tokens) 109 // learned encoder (trained here; deterministic) 110 let W: *i64 = sys_mmap(T2M_CLASSES * T2M_VOCAB * 8) as *i64 111 let caps: *i64 = sys_mmap(32 * 8) as *i64 112 let labs: *i64 = sys_mmap(32 * 8) as *i64 113 var nc: i64 = 0 114 caps[nc]="wave at them" as *u8 as i64; labs[nc]=0; nc=nc+1 115 caps[nc]="say hello with a wave" as *u8 as i64; labs[nc]=0; nc=nc+1 116 caps[nc]="wave hi" as *u8 as i64; labs[nc]=0; nc=nc+1 117 caps[nc]="cheer for the win" as *u8 as i64; labs[nc]=1; nc=nc+1 118 caps[nc]="celebrate excited" as *u8 as i64; labs[nc]=1; nc=nc+1 119 caps[nc]="cheer and celebrate" as *u8 as i64; labs[nc]=1; nc=nc+1 120 caps[nc]="sway to the rhythm" as *u8 as i64; labs[nc]=2; nc=nc+1 121 caps[nc]="dance and groove" as *u8 as i64; labs[nc]=2; nc=nc+1 122 caps[nc]="sway dance" as *u8 as i64; labs[nc]=2; nc=nc+1 123 caps[nc]="kick and march" as *u8 as i64; labs[nc]=3; nc=nc+1 124 caps[nc]="march step" as *u8 as i64; labs[nc]=3; nc=nc+1 125 caps[nc]="kick leg" as *u8 as i64; labs[nc]=3; nc=nc+1 126 caps[nc]="look around" as *u8 as i64; labs[nc]=4; nc=nc+1 127 caps[nc]="search and scan" as *u8 as i64; labs[nc]=4; nc=nc+1 128 caps[nc]="look and search" as *u8 as i64; labs[nc]=4; nc=nc+1 129 caps[nc]="stretch and reach" as *u8 as i64; labs[nc]=5; nc=nc+1 130 caps[nc]="circle the arm" as *u8 as i64; labs[nc]=5; nc=nc+1 131 caps[nc]="arm stretch" as *u8 as i64; labs[nc]=5; nc=nc+1 132 caps[nc]="clap for them" as *u8 as i64; labs[nc]=6; nc=nc+1 133 caps[nc]="clap and applaud" as *u8 as i64; labs[nc]=6; nc=nc+1 134 caps[nc]="applaud" as *u8 as i64; labs[nc]=6; nc=nc+1 135 caps[nc]="punch forward" as *u8 as i64; labs[nc]=7; nc=nc+1 136 caps[nc]="jab and punch" as *u8 as i64; labs[nc]=7; nc=nc+1 137 caps[nc]="fight jab" as *u8 as i64; labs[nc]=7; nc=nc+1 138 caps[nc]="take a bow" as *u8 as i64; labs[nc]=8; nc=nc+1 139 caps[nc]="bow to them" as *u8 as i64; labs[nc]=8; nc=nc+1 140 caps[nc]="bow" as *u8 as i64; labs[nc]=8; nc=nc+1 141 caps[nc]="jump and jack" as *u8 as i64; labs[nc]=9; nc=nc+1 142 caps[nc]="do a jump jack" as *u8 as i64; labs[nc]=9; nc=nc+1 143 caps[nc]="jack jump" as *u8 as i64; labs[nc]=9; nc=nc+1 144 t2m_train(W, caps, labs, nc, 40) 145 let cls: i64 = t2m_encode(W, cap) 146 let trc: *i64 = sys_mmap(MN_K * MN_K * 8) as *i64 147 t2m_class_bigram(tokens, cls, trc) 148 let st: *i64 = sys_mmap(8) as *i64; st[0] = 1337 + cls * 7 149 let gen: *i64 = sys_mmap(MN_FR * 8) as *i64 150 mn_generate(trc, tokens[cls * MN_FR], st, gen, MN_FR) 151 // render 152 let fb: *i64 = sys_mmap(SV_W * SV_H * 8) as *i64 153 let zb: *i64 = sys_mmap(SV_W * SV_H * 8) as *i64 154 let apbuf: *u8 = sys_mmap(8 * 1024 * 1024) 155 let seq: *i64 = sys_mmap(8) as *i64; seq[0] = 0 156 let vec: *i64 = sys_mmap(MN_D * 8) as *i64 157 var o: i64 = apng_open(apbuf, SV_W, SV_H, MN_FR) 158 var f: i64 = 0 159 while f < MN_FR { 160 let tk: i64 = gen[f] 161 var d: i64 = 0; while d < MN_D { vec[d] = cb[tk * MN_D + d]; d = d + 1 } 162 pose_apply(sk, vec); sk_update(sk) 163 rig_draw(sk, fb, zb, SV_W, SV_H, md_deg(15), 86) 164 var first: i64 = 0; if f == 0 { first = 1 } 165 o = apng_frame(apbuf, o, seq, fb, SV_W, SV_H, 8, first) 166 f = f + 1 167 } 168 o = apng_close(apbuf, o) 169 sv_send_bin(cfd, "image/png" as *u8, apbuf, o) 170 return 0 171} 172 173// ---- GET /synth/api/move?id= : parametric move APNG ------------------------------------------------ 174func sv_do_move(cfd: i64, path: *u8, pn: i64) -> i64 { 175 var id: i64 = sv_qint(path, pn, "id" as *u8, 1) 176 if id < 1 { id = 1 } if id > 10 { id = 10 } 177 let sk: i64 = sys_mmap(sk_bytes()) as i64 178 rig_build(sk) 179 let move: i64 = sys_mmap(move_bytes()) as i64 180 move_gen(move, id) 181 let hp: *i64 = mv_hdr(move); let period: i64 = hp[1] 182 let fb: *i64 = sys_mmap(SV_W * SV_H * 8) as *i64 183 let zb: *i64 = sys_mmap(SV_W * SV_H * 8) as *i64 184 let apbuf: *u8 = sys_mmap(8 * 1024 * 1024) 185 let seq: *i64 = sys_mmap(8) as *i64; seq[0] = 0 186 var o: i64 = apng_open(apbuf, SV_W, SV_H, 12) 187 var f: i64 = 0 188 while f < 12 { 189 let t: i64 = f * period / 12 190 move_pose_at(move, sk, t); sk_update(sk) 191 rig_draw(sk, fb, zb, SV_W, SV_H, md_deg(15), 86) 192 var first: i64 = 0; if f == 0 { first = 1 } 193 o = apng_frame(apbuf, o, seq, fb, SV_W, SV_H, 7, first) 194 f = f + 1 195 } 196 o = apng_close(apbuf, o) 197 sv_send_bin(cfd, "image/png" as *u8, apbuf, o) 198 return 0 199} 200 201// ---- POST /synth/api/variant?sp&hv&ev&tv&build : swap-slot creature, skinned raymarch still -------- 202const VR_W: i64 = 160 203const VR_H: i64 = 120 204const VR_FOCAL: i64 = 183 // 586*160/512 205func sv_do_variant(cfd: i64, path: *u8, pn: i64) -> i64 { 206 var sp: i64 = sv_qint(path, pn, "sp" as *u8, 0); if sp < 0 { sp = 0 } if sp > 2 { sp = 2 } 207 var hv: i64 = sv_qint(path, pn, "hv" as *u8, 0); if hv < 0 { hv = 0 } if hv > 2 { hv = 2 } 208 var ev: i64 = sv_qint(path, pn, "ev" as *u8, 1); if ev < 0 { ev = 0 } if ev > 1 { ev = 1 } 209 var tv: i64 = sv_qint(path, pn, "tv" as *u8, 0); if tv < 0 { tv = 0 } if tv > 1 { tv = 1 } 210 var bl: i64 = sv_qint(path, pn, "build" as *u8, 100); if bl < 70 { bl = 70 } if bl > 140 { bl = 140 } 211 var of: i64 = sv_qint(path, pn, "of" as *u8, 0); if of < 0 { of = 0 } if of > 4 { of = 4 } 212 let base: i64 = sys_mmap(sdf_bytes()) as i64 213 av_build(base, sp, hv, ev, tv, bl) 214 if of > 0 { let ovnp: *i64 = (base + O_NPART) as *i64; outfit_apply(base, ovnp[0], of) } 215 let fb: *i64 = sys_mmap(VR_W * VR_H * 8) as *i64 216 let cy4: i64 = it_cos4096(470); let sy4: i64 = it_sin4096(470) 217 let R: i64 = 5 * 1024 218 let rox: i64 = 0 - sy4 * R / 4096; let roz: i64 = 0 - cy4 * R / 4096 219 var y: i64 = 0 220 while y < VR_H { 221 let mc1: i64 = 24 + y * 30 / VR_H; let mc2: i64 = 26 + y * 28 / VR_H; let mc3: i64 = 40 + y * 26 / VR_H 222 let misscol: i64 = mc1 + mc2 * 256 + mc3 * 65536 223 var x: i64 = 0 224 while x < VR_W { 225 let ndcx: i64 = (2 * x + 1 - VR_W) * 1024 / (2 * VR_FOCAL) 226 let ndcy: i64 = (VR_H - (2 * y + 1)) * 1024 / (2 * VR_FOCAL) 227 let rl: i64 = sdf_isqrt(ndcx * ndcx + ndcy * ndcy + 1024 * 1024) 228 let vdx: i64 = ndcx * 1024 / rl; let rdy: i64 = ndcy * 1024 / rl; let vdz: i64 = 1024 * 1024 / rl 229 let rdx: i64 = (cy4 * vdx + sy4 * vdz) / 4096; let rdz: i64 = (0 - sy4 * vdx + cy4 * vdz) / 4096 230 let col: i64 = sdf_shade_ray(base, rox, 0, roz, rdx, rdy, rdz, 190, 172, 150, misscol) 231 fb[y * VR_W + x] = col 232 x = x + 1 233 } 234 y = y + 1 235 } 236 let pbuf: *u8 = sys_mmap(4 * 1024 * 1024) 237 let pl: i64 = write_png_buf(fb, VR_W, VR_H, pbuf) 238 sv_send_bin(cfd, "image/png" as *u8, pbuf, pl) 239 return 0 240} 241 242// ---- GET /synth/api/coach?err=N : the COACH reads your form. Compares a clean arm-raise (reference) to YOUR 243// attempt (same raise + `err` degrees of elbow bend) and returns a form score + the named off-joint. Reduce the 244// error -> the score climbs to 1000. (nx_pose_coach; tracks driven off the rig.) ---- 245const SVC_T: i64 = 16 246const SVC_NJ: i64 = 3 247func svc_jname(j: i64) -> *u8 { if j == 0 { return "shoulder" as *u8 } if j == 1 { return "elbow" as *u8 } return "wrist" as *u8 } 248func svc_track(sk: i64, track: *i64, elbowdeg: i64) -> i64 { 249 rig_build(sk) 250 var f: i64 = 0 251 while f < SVC_T { 252 let pitch: i64 = f * 90 / (SVC_T - 1) 253 sk_pose(sk, RG_SHR, 0, md_deg(pitch)) 254 sk_pose(sk, RG_ELR, md_deg(elbowdeg), 0) 255 sk_update(sk) 256 let b0: *i64 = sk_bone(sk, RG_SHR); track[(f*SVC_NJ+0)*3]=b0[15]; track[(f*SVC_NJ+0)*3+1]=b0[16]; track[(f*SVC_NJ+0)*3+2]=b0[17] 257 let b1: *i64 = sk_bone(sk, RG_ELR); track[(f*SVC_NJ+1)*3]=b1[15]; track[(f*SVC_NJ+1)*3+1]=b1[16]; track[(f*SVC_NJ+1)*3+2]=b1[17] 258 let b2: *i64 = sk_bone(sk, RG_WRR); track[(f*SVC_NJ+2)*3]=b2[15]; track[(f*SVC_NJ+2)*3+1]=b2[16]; track[(f*SVC_NJ+2)*3+2]=b2[17] 259 f = f + 1 260 } 261 return 0 262} 263func sv_do_coach(cfd: i64, path: *u8, pn: i64) -> i64 { 264 var err: i64 = sv_qint(path, pn, "err" as *u8, 0) 265 if err < 0 { err = 0 } if err > 90 { err = 90 } 266 let sk: i64 = sys_mmap(sk_bytes()) as i64 267 let reft: *i64 = sys_mmap(SVC_T * SVC_NJ * 3 * 8) as *i64 268 let att: *i64 = sys_mmap(SVC_T * SVC_NJ * 3 * 8) as *i64 269 svc_track(sk, reft, 0) 270 svc_track(sk, att, err) 271 let jdev: *i64 = sys_mmap(SVC_NJ * 8) as *i64 272 pc_score(reft, att, SVC_T, SVC_NJ, jdev) 273 let wj: i64 = pc_worst_joint(jdev, SVC_NJ) 274 let score: i64 = pc_form_score(jdev[wj], 1, 220) 275 let jb: *u8 = sys_mmap(512) 276 var o: i64 = sv_cat(jb, 0, "{\"form\":" as *u8) 277 o = sv_itoa(jb, o, score) 278 o = sv_cat(jb, o, ",\"worst\":\"" as *u8); o = sv_cat(jb, o, svc_jname(wj)) 279 o = sv_cat(jb, o, "\",\"dev\":" as *u8); o = sv_itoa(jb, o, jdev[wj]) 280 o = sv_cat(jb, o, ",\"err\":" as *u8); o = sv_itoa(jb, o, err); o = sv_cat(jb, o, "}" as *u8) 281 sv_send(cfd, "200 OK" as *u8, "application/json" as *u8, jb, o) 282 return 0 283} 284 285// ---- POST /synth/api/talk : body = text -> a TALKING FACE lip-syncing it (R6, nx_lipsync). ---- 286const TK_W: i64 = 96 287const TK_H: i64 = 96 288func sv_do_talk(cfd: i64, body: *u8, bn: i64) -> i64 { 289 let txt: *u8 = sys_mmap(256) 290 var cl: i64 = bn; if cl > 200 { cl = 200 } 291 var i: i64 = 0; while i < cl { txt[i] = body[i]; i = i + 1 } txt[cl] = 0 as u8 292 if cl == 0 { txt[0] = 104 as u8; txt[1] = 105 as u8; txt[2] = 0 as u8 } // default "hi" 293 let vh: *i64 = sys_mmap(220 * 8) as *i64 294 let vw: *i64 = sys_mmap(220 * 8) as *i64 295 let n: i64 = ls_text_visemes(txt, vh, vw, 200) 296 var nf: i64 = n; if nf < 2 { nf = 2 } if nf > 200 { nf = 200 } 297 let fb: *i64 = sys_mmap(TK_W * TK_H * 8) as *i64 298 let apbuf: *u8 = sys_mmap(12 * 1024 * 1024) 299 let seq: *i64 = sys_mmap(8) as *i64; seq[0] = 0 300 var o: i64 = apng_open(apbuf, TK_W, TK_H, nf) 301 var f: i64 = 0 302 while f < nf { 303 var oh: i64 = 1; var ow: i64 = 13 304 if f < n { oh = vh[f]; ow = vw[f] } 305 ls_face_frame(fb, TK_W, TK_H, oh, ow) 306 var first: i64 = 0; if f == 0 { first = 1 } 307 o = apng_frame(apbuf, o, seq, fb, TK_W, TK_H, 9, first) 308 f = f + 1 309 } 310 o = apng_close(apbuf, o) 311 sv_send_bin(cfd, "image/png" as *u8, apbuf, o) 312 return 0 313} 314 315const STUDIO_HTML: *u8 = "<!doctype html><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><title>Synth Studio</title><style>body{font-family:system-ui,sans-serif;max-width:860px;margin:2vh auto;padding:0 16px;background:#151118;color:#eae3da}h1{font-size:1.35rem}h1 em{color:#e6a582;font-style:normal}h2{font-size:.95rem;color:#a094aa;margin:26px 0 8px;text-transform:uppercase;letter-spacing:.1em}.card{background:#1f1a24;border:1px solid #372f3e;border-radius:10px;padding:16px;margin:10px 0}input,select,button{font:inherit;padding:9px 12px;border-radius:7px;border:1px solid #372f3e;background:#121019;color:#eae3da}button{background:#e6a582;color:#1b1418;border:0;cursor:pointer;font-weight:600}#cap{width:60%}.out img{max-width:100%;image-rendering:pixelated;border-radius:6px;background:#0c0a10;margin-top:10px}label{font-size:.82rem;color:#a094aa;margin-right:6px}.row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}a{color:#e6a582}</style><h1>Synth Studio &mdash; <em>type it, watch it move</em></h1><div class=card><h2>Text &rarr; motion (neural)</h2><div class=row><input id=cap placeholder=\"e.g. say hello with a wave\" value=\"say hello with a wave\"><button onclick=t2m()>Generate</button></div><div class=out id=o1></div></div><div class=card><h2>Named move</h2><div class=row><select id=mv><option value=1>wave</option><option value=2>cheer</option><option value=3>sway</option><option value=4>kick</option><option value=5>lookaround</option><option value=6>armcircle</option></select><button onclick=mv()>Play</button></div><div class=out id=o2></div></div><div class=card><h2>Creature (swap slots)</h2><div class=row><label>species</label><select id=sp><option value=0>human</option><option value=1>wolf</option><option value=2>goblin</option></select><label>head</label><select id=hv><option value=0>plain</option><option value=1>horns</option><option value=2>snout</option></select><label>ears</label><select id=ev><option value=1>pointed</option><option value=0>none</option></select><label>tail</label><select id=tv><option value=0>none</option><option value=1>tail</option></select><label>build</label><input id=bd type=number value=100 min=70 max=140 style=width:70px><button onclick=vr()>Render</button></div><div class=out id=o3></div></div><div class=card><h2>Download meshes</h2><p>STL: <a href=/synth/human.stl download>human</a> &middot; <a href=/synth/wolf.stl download>wolf</a> &middot; <a href=/synth/goblin.stl download>goblin</a> &nbsp; OBJ: <a href=/synth/human.obj download>human</a> &middot; <a href=/synth/wolf.obj download>wolf</a></p></div><script>function t2m(){var c=document.getElementById('cap').value;document.getElementById('o1').innerHTML='...';fetch('/synth/api/text2motion',{method:'POST',body:c}).then(function(r){return r.blob()}).then(function(b){document.getElementById('o1').innerHTML='<img src='+URL.createObjectURL(b)+'>'})}\nfunction mv(){var i=document.getElementById('mv').value;document.getElementById('o2').innerHTML='...';fetch('/synth/api/move?id='+i).then(function(r){return r.blob()}).then(function(b){document.getElementById('o2').innerHTML='<img src='+URL.createObjectURL(b)+'>'})}\nfunction vr(){var q='sp='+document.getElementById('sp').value+'&hv='+document.getElementById('hv').value+'&ev='+document.getElementById('ev').value+'&tv='+document.getElementById('tv').value+'&build='+document.getElementById('bd').value;document.getElementById('o3').innerHTML='...';fetch('/synth/api/variant?'+q,{method:'POST'}).then(function(r){return r.blob()}).then(function(b){document.getElementById('o3').innerHTML='<img src='+URL.createObjectURL(b)+'>'})}</script>" as *u8 316 317func sv_serve_conn(cfd: i64) -> i64 { 318 sys_set_socket_timeout(cfd, 200) 319 let req: *u8 = sys_mmap(131072) 320 let rn: i64 = sv_read_full(cfd, req, 131071) 321 if rn > 0 { 322 let he: i64 = sv_find_seq(req, rn, "\r\n\r\n" as *u8, 4) 323 var bodyp: *u8 = req; var bnn: i64 = 0 324 if he >= 0 { bodyp = ((req as i64) + he + 4) as *u8; bnn = rn - he - 4 } 325 let path: *u8 = sys_mmap(8192) 326 let plen: i64 = sv_reqpath(req, rn, path, 8192) 327 if sv_starts(req, rn, "POST /synth/api/text2motion" as *u8) == 1 { 328 sv_do_text2motion(cfd, bodyp, bnn) 329 } else { if sv_starts(req, rn, "POST /synth/api/talk" as *u8) == 1 { 330 sv_do_talk(cfd, bodyp, bnn) 331 } else { if sv_starts(path, plen, "/synth/api/move" as *u8) == 1 { 332 sv_do_move(cfd, path, plen) 333 } else { if sv_starts(path, plen, "/synth/api/variant" as *u8) == 1 { 334 sv_do_variant(cfd, path, plen) 335 } else { if sv_starts(path, plen, "/synth/api/coach" as *u8) == 1 { 336 sv_do_coach(cfd, path, plen) 337 } else { if sv_starts(path, plen, "/synth/health" as *u8) == 1 { 338 sv_send(cfd, "200 OK" as *u8, "application/json" as *u8, "{\"ok\":1}" as *u8, 8) 339 } else { 340 sv_send(cfd, "200 OK" as *u8, "text/html; charset=utf-8" as *u8, STUDIO_HTML, sv_slen(STUDIO_HTML)) 341 } } } } } } 342 } 343 return 0 344}