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 — <em>type it, watch it move</em></h1><div class=card><h2>Text → 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> · <a href=/synth/wolf.stl download>wolf</a> · <a href=/synth/goblin.stl download>goblin</a> OBJ: <a href=/synth/human.obj download>human</a> · <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}