code wiki / _hdl_build / nx_uigen_l3.nx
nx_uigen_l3.nx source
↩ module page · 269 lines · 15097 B
1// nx_uigen_l3.nx -- ROADMAP RUNG L3: PROCEDURAL DESIGN-GRAMMAR. A compact SPEC expands through a deterministic
2// grammar into ONE OF MANY valid, novel page designs: generated palette (seed hue x accent-relation: analogous/
3// complementary/triadic), radius + density axes, and CONSTRAINED section composition (3..5 middle bands chosen
4// + ordered from a 7-band vocabulary under validity rules: hero first, exactly one CTA last, no duplicates,
5// FAQ never before pricing). Same spec -> same bytes (determinism = the moat); different seeds -> visibly
6// different, ALWAYS-VALID designs. Also the ITERATIVE-REFINE rung: spec-delta commands ("hue 300", "add
7// pricing", "compact", "rounder") mutate the spec and re-emit -- a rule-based v0-chat-loop analog. Grounded:
8// uigss_gendesign.raw / uigss_procgen.raw (constraints -> many valid designs = generative design's core).
9// HONEST scope: bounded vocabulary + templated copy; free component synthesis and NL understanding are L4.
10// license_tier: ORIGINAL
11import "nx_uigen_l1.nx"
12const K_MAGIC_1103515245: i64 = 1103515245
13const K_MAGIC_12345: i64 = 12345
14const K_MAGIC_2147483648: i64 = 2147483648
15
16// ---- deterministic LCG (no float, positive-range) ----
17func l3_rng_next(st: *i64) -> i64 {
18 var s: i64 = st[0]
19 if s < 0 { s = 0 - s }
20 s = (s * K_MAGIC_1103515245 + K_MAGIC_12345) % K_MAGIC_2147483648
21 st[0] = s
22 return s
23}
24func l3_choice(st: *i64, n: i64) -> i64 { let v: i64 = l3_rng_next(st); return v % n }
25
26// ---- spec: [0]=hue [1]=accent_rel(0 analog/1 complement/2 triad) [2]=radius_idx(0..2) [3]=density(0..2)
27// [4]=nmid [5..9]=section ids [10]=seed. sections: 0 features 1 split 2 steps 3 pricing 4 quote 5 faq 6 trust
28func l3_spec_from_seed(spec: *i64, seed: i64) -> i64 {
29 let st: *i64 = sys_mmap(8) as *i64
30 st[0] = seed
31 l3_rng_next(st)
32 spec[0] = l3_choice(st, 360)
33 spec[1] = l3_choice(st, 3)
34 spec[2] = l3_choice(st, 3)
35 spec[3] = l3_choice(st, 3)
36 // Fisher-Yates shuffle of the 7-band vocabulary, take first nmid
37 let vocab: *i64 = sys_mmap(64) as *i64
38 var i: i64 = 0
39 while i < 7 { vocab[i] = i; i = i + 1 }
40 var j: i64 = 6
41 while j > 0 {
42 let k: i64 = l3_choice(st, j + 1)
43 let t: i64 = vocab[j]; vocab[j] = vocab[k]; vocab[k] = t
44 j = j - 1
45 }
46 let nmid: i64 = 3 + l3_choice(st, 3)
47 spec[4] = nmid
48 i = 0
49 while i < nmid { spec[5 + i] = vocab[i]; i = i + 1 }
50 // grammar rule: FAQ never before pricing (if both selected, swap into legal order)
51 var pi: i64 = 0 - 1
52 var fi: i64 = 0 - 1
53 i = 0
54 while i < nmid {
55 if spec[5 + i] == 3 { pi = i }
56 if spec[5 + i] == 5 { fi = i }
57 i = i + 1
58 }
59 if pi >= 0 { if fi >= 0 { if fi < pi { spec[5 + fi] = 3; spec[5 + pi] = 5 } } }
60 spec[10] = seed
61 return 0
62}
63
64// ---- generated palette with an accent RELATION axis (generalizes l1's fixed +32 analogous) ----
65func l3_accent_hue(hue: i64, rel: i64) -> i64 {
66 var add: i64 = 32
67 if rel == 1 { add = 180 }
68 if rel == 2 { add = 120 }
69 var ah: i64 = hue + add
70 while ah >= 360 { ah = ah - 360 }
71 return ah
72}
73func l3_palette_style(buf: *u8, off: i64, hue: i64, rel: i64) -> i64 {
74 let ah: i64 = l3_accent_hue(hue, rel)
75 var o: i64 = he_puts(buf, off, "<style>:root{" as *u8)
76 o = l1_tok(buf, o, "--nx-color-primary:" as *u8, hue, 62, 46)
77 o = l1_tok(buf, o, "--nx-color-primary2:" as *u8, hue, 70, 62)
78 o = l1_tok(buf, o, "--nx-color-accent:" as *u8, ah, 72, 50)
79 o = l1_tok(buf, o, "--nx-color-bg:" as *u8, hue, 22, 97)
80 o = l1_tok(buf, o, "--nx-color-surface:" as *u8, hue, 16, 100)
81 o = l1_tok(buf, o, "--nx-color-surface2:" as *u8, hue, 20, 94)
82 o = l1_tok(buf, o, "--nx-color-ink:" as *u8, hue, 25, 12)
83 o = l1_tok(buf, o, "--nx-color-ink2:" as *u8, hue, 14, 44)
84 o = l1_tok(buf, o, "--nx-color-line:" as *u8, hue, 18, 89)
85 o = he_puts(buf, o, "}@media(prefers-color-scheme:dark){:root{" as *u8)
86 o = l1_tok(buf, o, "--nx-color-primary:" as *u8, hue, 66, 64)
87 o = l1_tok(buf, o, "--nx-color-primary2:" as *u8, hue, 60, 74)
88 o = l1_tok(buf, o, "--nx-color-accent:" as *u8, ah, 70, 62)
89 o = l1_tok(buf, o, "--nx-color-bg:" as *u8, hue, 24, 9)
90 o = l1_tok(buf, o, "--nx-color-surface:" as *u8, hue, 20, 14)
91 o = l1_tok(buf, o, "--nx-color-surface2:" as *u8, hue, 18, 19)
92 o = l1_tok(buf, o, "--nx-color-ink:" as *u8, hue, 15, 92)
93 o = l1_tok(buf, o, "--nx-color-ink2:" as *u8, hue, 12, 66)
94 o = l1_tok(buf, o, "--nx-color-line:" as *u8, hue, 16, 24)
95 o = he_puts(buf, o, "}}</style>" as *u8)
96 return o
97}
98
99// ---- radius + density style axes (emitted after the kit stylesheet so they win the cascade) ----
100func l3_style_mods(buf: *u8, off: i64, radius_idx: i64, density: i64) -> i64 {
101 var rad: i64 = 10
102 if radius_idx == 1 { rad = 14 }
103 if radius_idx == 2 { rad = 26 }
104 var pad: i64 = 56
105 if density == 1 { pad = 76 }
106 if density == 2 { pad = 104 }
107 var o: i64 = he_puts(buf, off, "<style>.card,.stat,.pricecard,.tablewrap,.callout{border-radius:" as *u8)
108 o = l1_put_u8(buf, o, rad)
109 o = he_puts(buf, o, "px}.sec{padding:" as *u8)
110 o = l1_put_u8(buf, o, pad)
111 o = he_puts(buf, o, "px 0}</style>" as *u8)
112 return o
113}
114
115// ---- section emitters (templated copy -- HONEST: prose generation is L4; the grammar owns STRUCTURE) ----
116func l3_sec_features(buf: *u8, off: i64) -> i64 {
117 var o: i64 = sk_section_open(buf, off, "feat" as *u8, "Capabilities" as *u8, "Built for the job" as *u8, "Chosen by the grammar for this design." as *u8)
118 o = sk_card(buf, o, "<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M13 3L4 14h7l-1 7 9-11h-7z\"/></svg>" as *u8, "Fast by default" as *u8, "Every band is emitted, not assembled at runtime — zero client JS to boot." as *u8)
119 o = sk_card(buf, o, "<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M5 12l4 4 10-10\"/></svg>" as *u8, "Accessible always" as *u8, "The generated palette holds ink and background far apart in both themes." as *u8)
120 o = sk_card(buf, o, "<svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 2l10 6-10 6L2 8l10-6zM2 16l10 6 10-6\"/></svg>" as *u8, "Composed, not copied" as *u8, "Sections come from a constrained grammar, so every design stays coherent." as *u8)
121 return sk_section_close(buf, o)
122}
123func l3_sec_split(buf: *u8, off: i64, flip: i64) -> i64 {
124 return sk_split(buf, off, "how" as *u8, "Why it works" as *u8, "Designed as a system" as *u8, "One seed drives palette, shape, and rhythm together — so variety never breaks coherence." as *u8, "Zero third-party assets on any generated page" as *u8, "Deterministic output: the same spec yields the same bytes" as *u8, "Contrast passes WCAG in both themes by construction" as *u8, flip)
125}
126func l3_sec_steps(buf: *u8, off: i64) -> i64 {
127 var o: i64 = sk_steps_open(buf, off, "steps" as *u8, "Process" as *u8, "How it works" as *u8, "From spec to shipped page." as *u8)
128 o = sk_step(buf, o, "Describe" as *u8, "A compact spec: a seed, or a brief mapped to one." as *u8)
129 o = sk_step(buf, o, "Generate" as *u8, "The grammar expands it into a valid, styled composition." as *u8)
130 o = sk_step(buf, o, "Refine" as *u8, "Spec-delta commands adjust hue, shape, rhythm, or sections." as *u8)
131 return sk_steps_close(buf, o)
132}
133func l3_sec_pricing(buf: *u8, off: i64) -> i64 {
134 var o: i64 = sk_pricing_open(buf, off, "pricing" as *u8, "Pricing" as *u8, "Simple pricing" as *u8, "Start free, scale when ready." as *u8)
135 o = sk_price_tier(buf, o, "Starter" as *u8, "$0" as *u8, "/mo" as *u8, "<li>One generated site</li><li>Both themes included</li><li>Community support</li>" as *u8, "Start free" as *u8, "#join" as *u8, 0)
136 o = sk_price_tier(buf, o, "Studio" as *u8, "$19" as *u8, "/mo" as *u8, "<li>Unlimited generations</li><li>Refine loop included</li><li>Priority support</li>" as *u8, "Go Studio" as *u8, "#join" as *u8, 1)
137 o = sk_price_tier(buf, o, "Scale" as *u8, "$99" as *u8, "/mo" as *u8, "<li>Multi-site fleets</li><li>Custom vocabulary</li><li>Dedicated help</li>" as *u8, "Talk to us" as *u8, "#join" as *u8, 0)
138 return sk_pricing_close(buf, o)
139}
140func l3_sec_quote(buf: *u8, off: i64) -> i64 {
141 return sk_quote(buf, off, "quote" as *u8, "Testimonial" as *u8, "It looked designed on purpose — because the constraints made sure it was." as *u8, "A. Reviewer" as *u8, "Design lead" as *u8)
142}
143func l3_sec_faq(buf: *u8, off: i64) -> i64 {
144 var o: i64 = sk_faq_open(buf, off, "faq" as *u8, "FAQ" as *u8, "Common questions" as *u8, "What people ask first." as *u8)
145 o = sk_faq_item(buf, o, "Is every generated design different?" as *u8, "Each seed expands to its own palette, shape, rhythm, and section composition — within rules that keep every result valid." as *u8)
146 o = sk_faq_item(buf, o, "Does dark mode work?" as *u8, "Yes. The palette is generated twice — a light and a dark scheme from the same seed — and both keep WCAG contrast by construction." as *u8)
147 o = sk_faq_item(buf, o, "Can I change one thing without regenerating?" as *u8, "Yes: refine commands adjust a single axis — hue, roundness, density, or a section — and leave the rest untouched." as *u8)
148 return sk_faq_close(buf, o)
149}
150func l3_sec_trust(buf: *u8, off: i64) -> i64 {
151 var o: i64 = sk_trust_open(buf, off, "Guarantees" as *u8, "Safe by construction" as *u8, "What every generated page ships with." as *u8)
152 o = sk_trust_item(buf, o, "Accessible" as *u8, "WCAG contrast in both themes, skip links, focus states." as *u8)
153 o = sk_trust_item(buf, o, "Private" as *u8, "No CDNs, no trackers, no third-party fonts." as *u8)
154 o = sk_trust_item(buf, o, "Yours" as *u8, "Plain HTML and CSS you fully own." as *u8)
155 return sk_trust_close(buf, o)
156}
157func l3_emit_section(buf: *u8, off: i64, sec: i64, flip: i64) -> i64 {
158 if sec == 0 { return l3_sec_features(buf, off) }
159 if sec == 1 { return l3_sec_split(buf, off, flip) }
160 if sec == 2 { return l3_sec_steps(buf, off) }
161 if sec == 3 { return l3_sec_pricing(buf, off) }
162 if sec == 4 { return l3_sec_quote(buf, off) }
163 if sec == 5 { return l3_sec_faq(buf, off) }
164 return l3_sec_trust(buf, off)
165}
166
167// ---- emit a full page from a spec (same spec -> same bytes) ----
168func l3_emit_from_spec(buf: *u8, off: i64, spec: *i64, title: *u8, brand: *u8) -> i64 {
169 var o: i64 = sk_open_site(buf, off, title, brand, 1, "/" as *u8)
170 o = sk_nav_item(buf, o, "Home" as *u8, "#top" as *u8)
171 o = sk_nav_item(buf, o, "Get started" as *u8, "#join" as *u8)
172 o = sk_header_close(buf, o)
173 o = l3_palette_style(buf, o, spec[0], spec[1])
174 o = l3_style_mods(buf, o, spec[2], spec[3])
175 o = sk_mkt_styles(buf, o)
176 o = sk_hero(buf, o, "Generated design" as *u8, title, "by grammar" as *u8, "This page’s palette, shape, rhythm, and section composition were all chosen by a constrained design grammar from one compact spec." as *u8, "Get started" as *u8, "#join" as *u8, "See how" as *u8, "#main" as *u8, "Deterministic: this exact spec always yields this exact page." as *u8)
177 let flip: i64 = spec[0] % 2
178 var i: i64 = 0
179 while i < spec[4] {
180 o = l3_emit_section(buf, o, spec[5 + i], flip)
181 i = i + 1
182 }
183 o = sk_cta(buf, o, "Ready" as *u8, "Generate yours" as *u8, "One spec in, a valid design out — every time." as *u8, "Get started" as *u8, "#join" as *u8, "Learn more" as *u8, "#main" as *u8)
184 o = sk_close(buf, o, "Generated" as *u8, brand)
185 return o
186}
187func l3_generate(buf: *u8, off: i64, seed: i64, title: *u8, brand: *u8) -> i64 {
188 let spec: *i64 = sys_mmap(128) as *i64
189 l3_spec_from_seed(spec, seed)
190 return l3_emit_from_spec(buf, off, spec, title, brand)
191}
192
193// ==== ITERATIVE REFINE: spec-delta commands (rule-based v0-chat-loop analog) ====
194func l3_streq(a: *u8, b: *u8) -> i64 {
195 var i: i64 = 0
196 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
197 if b[i] != (0 as u8) { return 0 }
198 return 1
199}
200func l3_starts(s: *u8, pre: *u8) -> i64 {
201 var i: i64 = 0
202 while pre[i] != (0 as u8) { if s[i] != pre[i] { return 0 } i = i + 1 }
203 return 1
204}
205func l3_atoi_at(s: *u8, at: i64) -> i64 {
206 var v: i64 = 0
207 var i: i64 = at
208 while s[i] != (0 as u8) {
209 let c: i64 = s[i] as i64
210 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
211 i = i + 1
212 }
213 return v
214}
215func l3_secid_from_name(s: *u8) -> i64 {
216 if l3_streq(s, "features" as *u8) == 1 { return 0 }
217 if l3_streq(s, "split" as *u8) == 1 { return 1 }
218 if l3_streq(s, "steps" as *u8) == 1 { return 2 }
219 if l3_streq(s, "pricing" as *u8) == 1 { return 3 }
220 if l3_streq(s, "quote" as *u8) == 1 { return 4 }
221 if l3_streq(s, "faq" as *u8) == 1 { return 5 }
222 if l3_streq(s, "trust" as *u8) == 1 { return 6 }
223 return 0 - 1
224}
225func l3_spec_find(spec: *i64, sec: i64) -> i64 {
226 var i: i64 = 0
227 while i < spec[4] { if spec[5 + i] == sec { return i } i = i + 1 }
228 return 0 - 1
229}
230// apply one refine command to the spec. Returns 1 if applied, 0 if refused (would break grammar validity).
231func l3_refine(spec: *i64, cmd: *u8) -> i64 {
232 if l3_starts(cmd, "hue " as *u8) == 1 { spec[0] = l3_atoi_at(cmd, 4) % 360; return 1 }
233 if l3_streq(cmd, "accent analog" as *u8) == 1 { spec[1] = 0; return 1 }
234 if l3_streq(cmd, "accent complement" as *u8) == 1 { spec[1] = 1; return 1 }
235 if l3_streq(cmd, "accent triad" as *u8) == 1 { spec[1] = 2; return 1 }
236 if l3_streq(cmd, "sharper" as *u8) == 1 { if spec[2] > 0 { spec[2] = spec[2] - 1 } return 1 }
237 if l3_streq(cmd, "rounder" as *u8) == 1 { if spec[2] < 2 { spec[2] = spec[2] + 1 } return 1 }
238 if l3_streq(cmd, "compact" as *u8) == 1 { spec[3] = 0; return 1 }
239 if l3_streq(cmd, "airy" as *u8) == 1 { spec[3] = 2; return 1 }
240 if l3_starts(cmd, "add " as *u8) == 1 {
241 let sec: i64 = l3_secid_from_name((((cmd as i64) + 4) as *u8))
242 if sec < 0 { return 0 }
243 if l3_spec_find(spec, sec) >= 0 { return 0 }
244 if spec[4] >= 5 { return 0 }
245 // grammar rule on insert: pricing goes BEFORE faq if faq present; everything else appends
246 var at: i64 = spec[4]
247 if sec == 3 {
248 let fi: i64 = l3_spec_find(spec, 5)
249 if fi >= 0 { at = fi }
250 }
251 var i: i64 = spec[4]
252 while i > at { spec[5 + i] = spec[5 + i - 1]; i = i - 1 }
253 spec[5 + at] = sec
254 spec[4] = spec[4] + 1
255 return 1
256 }
257 if l3_starts(cmd, "drop " as *u8) == 1 {
258 let sec: i64 = l3_secid_from_name((((cmd as i64) + 5) as *u8))
259 if sec < 0 { return 0 }
260 let at: i64 = l3_spec_find(spec, sec)
261 if at < 0 { return 0 }
262 if spec[4] <= 3 { return 0 }
263 var i: i64 = at
264 while i < spec[4] - 1 { spec[5 + i] = spec[5 + i + 1]; i = i + 1 }
265 spec[4] = spec[4] - 1
266 return 1
267 }
268 return 0
269}