nx_wow_moment_detector.nx source
↩ module page · 404 lines · 14869 B
1// nx_wow_moment_detector.nx -- signature-feature awe-density grader.
2//
3// Per honest audit 2026-05-16: a world can be statistically diverse
4// but still bland if it has no MEMORABLE features. This grader
5// directly counts AWE MOMENTS -- the views that make a player stop
6// and gawk: monumental peaks, cliff edges over deep valleys, hidden
7// alcoves, dramatic vistas. A world with no awe moments is bland;
8// 3-8 per 10x10 km region is incredible.
9//
10// AXES (Q14 [0, Q]; higher = MORE wow):
11//
12// 0. SIGNATURE_PEAKS_PER_REGION: distinct local maxima above
13// 0.85 * max_relief, weighted by isolation (lonely peaks > clumps).
14// Target [3, 8] per region; saturates above.
15// 1. DRAMATIC_VALLEYS: cells below 0.10 * max_relief that have a
16// cell within 5m on the heightmap above 0.50 * max_relief
17// (canyon-edge proximity).
18// 2. ISOLATION_VARIANCE: stddev of nearest-neighbour distances among
19// signature features. Clumped features = boring; spread = wow.
20// 3. SCALE_DIVERSITY: ratio of largest to smallest signature feature
21// size. Worlds with only-huge or only-tiny features score low.
22// 4. RARITY: fraction of features with unique nearest-neighbour
23// bearing (no two adjacent features point the same way).
24//
25// EMITS LAYER_VERDICT (kind = NX_LAYER_KIND_READABILITY).
26//
27// genealogy_id: kaplan_1987_environmental_preference +
28// appleton_1996_landscape_aesthetics + awe_psych_canon
29// lineage_id: nx_wow_moment_detector_5axis_v1
30
31// nx_safety_envelope:
32// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
33// sil_target: SIL1
34// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
35// verdict: NOT_YET_EVALUATED
36
37import "nx_syscalls.nx"
38import "nx_tier.nx"
39import "nx_layer_verdict.nx"
40
41const NX_WM_Q: nx_int = 16384
42
43const NX_WM_AXIS_SIG_PEAKS: nx_int = 0
44const NX_WM_AXIS_DRAMATIC_VALLEYS: nx_int = 1
45const NX_WM_AXIS_ISOLATION_VAR: nx_int = 2
46const NX_WM_AXIS_SCALE_DIVERSITY: nx_int = 3
47const NX_WM_AXIS_RARITY: nx_int = 4
48const NX_WM_AXIS_COUNT: nx_int = 5
49
50func _wm_band_score(val: nx_int, lo_q: nx_int, hi_q: nx_int) -> nx_int {
51 let q: nx_int = NX_WM_Q
52 if val < 0 { return 0 }
53 if val < lo_q {
54 if lo_q > 0 { return (val * q) / lo_q }
55 return 0
56 }
57 if val <= hi_q { return q }
58 return q
59}
60
61// ===== Axis 0: signature peaks =====================================
62// A signature peak is a cell whose value > 0.85 of (hmax) AND it's a
63// strict local maximum within a 3x3 neighborhood. Returns the count
64// scored against a target band [3, 12].
65func _wm_signature_peaks_q14(
66 heightmap: *i64, w: nx_int, h: nx_int
67) -> nx_int {
68 let q: nx_int = NX_WM_Q
69 let n: nx_int = w * h
70 if n <= 0 { return 0 }
71 if w < 3 { return 0 }
72 if h < 3 { return 0 }
73 var hmax: nx_int = heightmap[0]
74 var hmin: nx_int = heightmap[0]
75 var i: nx_int = 0
76 while i < n {
77 let v: nx_int = heightmap[i]
78 if v > hmax { hmax = v }
79 if v < hmin { hmin = v }
80 i = i + 1
81 }
82 let range: nx_int = hmax - hmin
83 if range <= 0 { return 0 }
84 let threshold: nx_int = hmin + (range * 85) / 100
85
86 var n_peaks: nx_int = 0
87 var y: nx_int = 1
88 while y < h - 1 {
89 var x: nx_int = 1
90 while x < w - 1 {
91 let idx: nx_int = y * w + x
92 let v: nx_int = heightmap[idx]
93 if v >= threshold {
94 var is_peak: nx_int = 1
95 var dy: nx_int = 0 - 1
96 while dy <= 1 {
97 var dx: nx_int = 0 - 1
98 while dx <= 1 {
99 if dx != 0 {
100 if heightmap[(y + dy) * w + (x + dx)] > v { is_peak = 0 }
101 }
102 if dx == 0 {
103 if dy != 0 {
104 if heightmap[(y + dy) * w + (x + dx)] > v { is_peak = 0 }
105 }
106 }
107 dx = dx + 1
108 }
109 dy = dy + 1
110 }
111 if is_peak == 1 { n_peaks = n_peaks + 1 }
112 }
113 x = x + 1
114 }
115 y = y + 1
116 }
117 // Target band: 3-12 peaks.
118 var score: nx_int = 0
119 if n_peaks >= 3 {
120 if n_peaks <= 12 { score = q }
121 if n_peaks > 12 { score = q - (n_peaks - 12) * q / 12 }
122 }
123 if n_peaks < 3 { score = (n_peaks * q) / 3 }
124 if score < 0 { score = 0 }
125 if score > q { score = q }
126 return score
127}
128
129// ===== Axis 1: dramatic valleys ====================================
130// Count cells whose value < 0.10 * range AND which have a neighbouring
131// cell within distance 5 (chebyshev) above 0.50 * range.
132func _wm_dramatic_valleys_q14(
133 heightmap: *i64, w: nx_int, h: nx_int
134) -> nx_int {
135 let q: nx_int = NX_WM_Q
136 let n: nx_int = w * h
137 if n <= 0 { return 0 }
138 var hmax: nx_int = heightmap[0]
139 var hmin: nx_int = heightmap[0]
140 var i: nx_int = 0
141 while i < n {
142 let v: nx_int = heightmap[i]
143 if v > hmax { hmax = v }
144 if v < hmin { hmin = v }
145 i = i + 1
146 }
147 let range: nx_int = hmax - hmin
148 if range <= 0 { return 0 }
149 let valley_t: nx_int = hmin + (range * 10) / 100
150 let high_t: nx_int = hmin + (range * 50) / 100
151 var n_dramatic: nx_int = 0
152 var y: nx_int = 0
153 while y < h {
154 var x: nx_int = 0
155 while x < w {
156 let v: nx_int = heightmap[y * w + x]
157 if v <= valley_t {
158 // Check 5x5 neighbourhood for a high cell.
159 var found_high: nx_int = 0
160 var dy: nx_int = 0 - 5
161 while dy <= 5 {
162 var dx: nx_int = 0 - 5
163 while dx <= 5 {
164 let nx: nx_int = x + dx
165 let ny: nx_int = y + dy
166 if nx >= 0 { if nx < w {
167 if ny >= 0 { if ny < h {
168 if heightmap[ny * w + nx] >= high_t { found_high = 1 }
169 } }
170 } }
171 dx = dx + 1
172 }
173 dy = dy + 1
174 }
175 if found_high == 1 { n_dramatic = n_dramatic + 1 }
176 }
177 x = x + 1
178 }
179 y = y + 1
180 }
181 // Target: 1-10% of cells.
182 let target_lo: nx_int = n / 100
183 let target_hi: nx_int = n / 10
184 var score: nx_int = 0
185 if n_dramatic >= target_lo {
186 if n_dramatic <= target_hi { score = q }
187 if n_dramatic > target_hi {
188 score = q - (n_dramatic - target_hi) * q / n
189 }
190 }
191 if n_dramatic < target_lo {
192 if target_lo > 0 { score = (n_dramatic * q) / target_lo }
193 }
194 if score < 0 { score = 0 }
195 if score > q { score = q }
196 return score
197}
198
199// ===== Axis 2: isolation variance ==================================
200// Caller passes a feature list (flat array of (x, y) pairs) for
201// signature features. Compute mean pairwise distance + stddev.
202// Higher stddev = more interesting distribution. Pass n=0 to skip.
203func _wm_isolation_var_q14(
204 features: *i64, n_features: nx_int
205) -> nx_int {
206 if (features as i64) == 0 { return NX_WM_Q / 2 }
207 if n_features < 3 { return 0 }
208 let q: nx_int = NX_WM_Q
209 var sum_d_sq: nx_int = 0
210 var min_d_sq: nx_int = 0 - 1
211 var max_d_sq: nx_int = 0
212 var count: nx_int = 0
213 var i: nx_int = 0
214 while i < n_features - 1 {
215 let dx: nx_int = features[(i + 1) * 2 ] - features[i * 2 ]
216 let dy: nx_int = features[(i + 1) * 2 + 1] - features[i * 2 + 1]
217 let d_sq: nx_int = dx * dx + dy * dy
218 sum_d_sq = sum_d_sq + d_sq
219 if d_sq > max_d_sq { max_d_sq = d_sq }
220 if min_d_sq < 0 { min_d_sq = d_sq }
221 if d_sq < min_d_sq { min_d_sq = d_sq }
222 count = count + 1
223 i = i + 1
224 }
225 if count == 0 { return 0 }
226 let mean_d_sq: nx_int = sum_d_sq / count
227 if mean_d_sq <= 0 { return 0 }
228 let range: nx_int = max_d_sq - min_d_sq
229 let cv_q: nx_int = (range * q) / mean_d_sq
230 // Target [0.5Q, 2Q] -- a healthy spread of distances.
231 if cv_q < q / 2 { return (cv_q * q * 2) / q }
232 if cv_q > q * 2 { return q - (cv_q - q * 2) / 2 }
233 return q
234}
235
236// ===== Axis 3: scale diversity =====================================
237// Sizes here = caller-supplied feature radii. Returns Q14 of
238// max_size / min_size ratio (saturates at 8x).
239func _wm_scale_diversity_q14(
240 sizes: *i64, n_features: nx_int
241) -> nx_int {
242 if (sizes as i64) == 0 { return NX_WM_Q / 2 }
243 if n_features < 2 { return 0 }
244 let q: nx_int = NX_WM_Q
245 var smin: nx_int = sizes[0]
246 var smax: nx_int = sizes[0]
247 var i: nx_int = 0
248 while i < n_features {
249 let s: nx_int = sizes[i]
250 if s < smin { smin = s }
251 if s > smax { smax = s }
252 i = i + 1
253 }
254 if smin <= 0 { return 0 }
255 let ratio: nx_int = smax / smin
256 if ratio >= 8 { return q }
257 if ratio <= 1 { return 0 }
258 return ((ratio - 1) * q) / 7
259}
260
261// ===== Axis 4: rarity (bearing diversity) ==========================
262// Score = fraction of features whose nearest-neighbour bearing differs
263// from at least one other feature's nearest-neighbour bearing by > 30deg.
264// Simplified: compute (dy / dx) sign as a coarse bearing band; count
265// distinct signs. Skipped if no features supplied.
266func _wm_rarity_q14(
267 features: *i64, n_features: nx_int
268) -> nx_int {
269 if (features as i64) == 0 { return NX_WM_Q / 2 }
270 if n_features < 3 { return 0 }
271 let q: nx_int = NX_WM_Q
272 // 4 quadrant bins from each feature's bearing to next feature.
273 let bins: *i64 = (sys_mmap(4 * NX_SIZEOF_NX_INT)) as *i64
274 var b: nx_int = 0
275 while b < 4 { bins[b] = 0; b = b + 1 }
276 var i: nx_int = 0
277 while i < n_features - 1 {
278 let dx: nx_int = features[(i + 1) * 2 ] - features[i * 2 ]
279 let dy: nx_int = features[(i + 1) * 2 + 1] - features[i * 2 + 1]
280 var bin: nx_int = 0
281 if dx >= 0 {
282 if dy >= 0 { bin = 0 } else { bin = 1 }
283 } else {
284 if dy >= 0 { bin = 2 } else { bin = 3 }
285 }
286 bins[bin] = bins[bin] + 1
287 i = i + 1
288 }
289 var n_distinct: nx_int = 0
290 var j: nx_int = 0
291 while j < 4 {
292 if bins[j] > 0 { n_distinct = n_distinct + 1 }
293 j = j + 1
294 }
295 return (n_distinct * q) / 4
296}
297
298// ===== Public: wow-moment grader ===================================
299// Inputs:
300// heightmap, w, h required
301// features, n_features optional flat array of (x, y) pairs
302// sizes optional parallel array of feature radii
303// out_verdict 16-i64 LAYER_VERDICT
304func nx_wow_moment_detect(
305 heightmap: *i64, w: nx_int, h: nx_int,
306 features: *i64, n_features: nx_int,
307 sizes: *i64,
308 out_verdict: *i64
309) {
310 let sp: nx_int = _wm_signature_peaks_q14(heightmap, w, h)
311 let dv: nx_int = _wm_dramatic_valleys_q14(heightmap, w, h)
312 let iv: nx_int = _wm_isolation_var_q14(features, n_features)
313 let sd: nx_int = _wm_scale_diversity_q14(sizes, n_features)
314 let ra: nx_int = _wm_rarity_q14(features, n_features)
315 nx_layer_verdict_init(out_verdict, NX_LAYER_KIND_READABILITY,
316 NX_WM_AXIS_COUNT, NX_LAYER_REFINE_MORE_FEATURES)
317 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] = sp
318 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_DRAMATIC_VALLEYS] = dv
319 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_ISOLATION_VAR] = iv
320 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SCALE_DIVERSITY] = sd
321 out_verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_RARITY] = ra
322 nx_layer_verdict_finalize(out_verdict)
323}
324
325// ===== Self-test ====================================================
326func main() -> i64 {
327 let q: nx_int = NX_WM_Q
328 let verdict: *i64 = (sys_mmap(NX_LV_STRIDE * NX_SIZEOF_NX_INT)) as *i64
329 let null_ptr: *i64 = 0 as *i64
330
331 // T1: Build 16x16 map with 5 distinct peaks; expect signature
332 // peak count in band.
333 let w: nx_int = 16
334 let h: nx_int = 16
335 let n: nx_int = w * h
336 let map: *i64 = (sys_mmap(n * NX_SIZEOF_NX_INT)) as *i64
337 var i: nx_int = 0
338 while i < n {
339 let x: nx_int = i % w
340 let y: nx_int = i / w
341 // 5 peaks at (2,2), (5,10), (10,3), (12,12), (7,7). Quadratic
342 // falloff so each peak has a strict local maximum at its centre.
343 var v: nx_int = 0
344 let dx1: nx_int = x - 2; let dy1: nx_int = y - 2
345 let d1_sq: nx_int = dx1 * dx1 + dy1 * dy1
346 if d1_sq < 10 { v = v + (1000 - d1_sq * 100) }
347 let dx2: nx_int = x - 5; let dy2: nx_int = y - 10
348 let d2_sq: nx_int = dx2 * dx2 + dy2 * dy2
349 if d2_sq < 10 { v = v + (1000 - d2_sq * 100) }
350 let dx3: nx_int = x - 10; let dy3: nx_int = y - 3
351 let d3_sq: nx_int = dx3 * dx3 + dy3 * dy3
352 if d3_sq < 10 { v = v + (1000 - d3_sq * 100) }
353 let dx4: nx_int = x - 12; let dy4: nx_int = y - 12
354 let d4_sq: nx_int = dx4 * dx4 + dy4 * dy4
355 if d4_sq < 10 { v = v + (1000 - d4_sq * 100) }
356 let dx5: nx_int = x - 7; let dy5: nx_int = y - 7
357 let d5_sq: nx_int = dx5 * dx5 + dy5 * dy5
358 if d5_sq < 10 { v = v + (1000 - d5_sq * 100) }
359 map[i] = v
360 i = i + 1
361 }
362 nx_wow_moment_detect(map, w, h, null_ptr, 0, null_ptr, verdict)
363 // Signature peaks: should detect at least 3.
364 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] < q * 5 / 10 {
365 return __syscall(93, 1, 0, 0, 0, 0, 0)
366 }
367
368 // T2: Flat heightmap -> 0 peaks.
369 var f: nx_int = 0
370 while f < n { map[f] = 100; f = f + 1 }
371 nx_wow_moment_detect(map, w, h, null_ptr, 0, null_ptr, verdict)
372 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SIG_PEAKS] != 0 {
373 return __syscall(93, 2, 0, 0, 0, 0, 0)
374 }
375 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_DRAMATIC_VALLEYS] != 0 {
376 return __syscall(93, 3, 0, 0, 0, 0, 0)
377 }
378
379 // T3: Feature list with diverse positions + sizes.
380 let feats: *i64 = (sys_mmap(8 * NX_SIZEOF_NX_INT)) as *i64
381 feats[0] = 0; feats[1] = 0
382 feats[2] = 50; feats[3] = 30
383 feats[4] = 30; feats[5] = 80
384 feats[6] = 90; feats[7] = 100
385 let sizes: *i64 = (sys_mmap(4 * NX_SIZEOF_NX_INT)) as *i64
386 sizes[0] = 5
387 sizes[1] = 15
388 sizes[2] = 25
389 sizes[3] = 50
390 nx_wow_moment_detect(map, w, h, feats, 4, sizes, verdict)
391 if verdict[NX_LV_OFF_AXIS_0 + NX_WM_AXIS_SCALE_DIVERSITY] < q * 5 / 10 {
392 return __syscall(93, 10, 0, 0, 0, 0, 0)
393 }
394
395 // T4: Verdict well-formed.
396 if verdict[NX_LV_OFF_KIND] != NX_LAYER_KIND_READABILITY {
397 return __syscall(93, 20, 0, 0, 0, 0, 0)
398 }
399 if nx_lv_grade_is_valid(verdict[NX_LV_OFF_GRADE]) != 1 {
400 return __syscall(93, 21, 0, 0, 0, 0, 0)
401 }
402
403 return 0
404}