Skip to content

Commit 5732e02

Browse files
committed
feat(solver): optimise interval solver with pooling and safety guards
- implemented rigorous mobius derivative intensity metric - added baseline euclidean particle tracer for verification - optimised solver with deep object pooling to eliminate GC stutter - forced safety guards: 3000 max segments, 0.001 min width, 32ms budget - tuned beam count to 30 for performance stability
1 parent a04e96a commit 5732e02

10 files changed

Lines changed: 1326 additions & 542 deletions

File tree

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,127 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>Möbius Caustic Solver</title>
77
<style>
8-
body { margin: 0; overflow: hidden; background: #111; color: #eee; font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; }
9-
canvas { background: #000; }
10-
#controls { position: absolute; top: 10px; left: 10px; padding: 10px; background: rgba(0,0,0,0.5); border-radius: 5px;}
8+
body {
9+
margin: 0;
10+
overflow: hidden;
11+
background: #111;
12+
color: #eee;
13+
font-family: sans-serif;
14+
display: flex;
15+
justify-content: center;
16+
align-items: center;
17+
height: 100vh;
18+
}
19+
canvas {
20+
background: #000;
21+
}
22+
#controls {
23+
position: absolute;
24+
top: 10px;
25+
left: 10px;
26+
padding: 10px;
27+
background: rgba(0, 0, 0, 0.5);
28+
border-radius: 5px;
29+
}
1130
</style>
12-
</head>
13-
<body>
31+
</head>
32+
<body>
1433
<canvas id="viewport" width="800" height="800"></canvas>
15-
<div id="controls">
16-
<p>Möbius Caustic Solver</p>
17-
<p>Status: Initializing...</p>
34+
<div
35+
id="dashboard"
36+
style="
37+
position: absolute;
38+
top: 10px;
39+
left: 10px;
40+
background: rgba(0, 0, 0, 0.85);
41+
color: #fff;
42+
padding: 15px;
43+
border-radius: 8px;
44+
font-family: 'Courier New', Courier, monospace;
45+
min-width: 300px;
46+
border: 1px solid #444;
47+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
48+
"
49+
>
50+
<h2
51+
style="
52+
margin: 0 0 10px 0;
53+
font-size: 16px;
54+
border-bottom: 1px solid #666;
55+
padding-bottom: 5px;
56+
"
57+
>
58+
Möbius Caustic Solver
59+
</h2>
60+
61+
<div
62+
style="
63+
margin-bottom: 8px;
64+
display: flex;
65+
justify-content: space-between;
66+
"
67+
>
68+
<span style="color: #aaa">Status:</span>
69+
<span id="ui-status" style="color: #0f0; font-weight: bold"
70+
>Initializing...</span
71+
>
72+
</div>
73+
74+
<div
75+
style="
76+
margin-bottom: 8px;
77+
display: flex;
78+
justify-content: space-between;
79+
"
80+
>
81+
<span style="color: #aaa">Quality:</span>
82+
<span id="ui-quality">LOW</span>
83+
</div>
84+
85+
<div style="margin-bottom: 8px">
86+
<div
87+
style="
88+
display: flex;
89+
justify-content: space-between;
90+
margin-bottom: 4px;
91+
"
92+
>
93+
<span style="color: #aaa">FPS:</span>
94+
<span id="ui-fps">--</span>
95+
</div>
96+
<div style="display: flex; justify-content: space-between">
97+
<span style="color: #aaa">Latency:</span>
98+
<span id="ui-latency">-- ms</span>
99+
</div>
100+
<!-- Performance Graph -->
101+
<canvas
102+
id="perf-graph"
103+
width="270"
104+
height="60"
105+
style="
106+
width: 100%;
107+
height: 60px;
108+
margin-top: 8px;
109+
background: #222;
110+
border: 1px solid #444;
111+
"
112+
></canvas>
113+
</div>
114+
115+
<div
116+
id="ui-alert"
117+
style="
118+
margin-top: 10px;
119+
padding: 5px;
120+
border-radius: 4px;
121+
display: none;
122+
"
123+
></div>
18124
</div>
19125
<script type="module" src="src/main.js"></script>
20-
</body>
126+
</body>
21127
</html>

projects/arithmetica-lucis/prototype/mobius-caustic-solver/src/core/complex.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,8 @@ export class Complex {
101101
const dy = this.im - c.im;
102102
return dx * dx + dy * dy;
103103
}
104+
105+
toString() {
106+
return `${this.re} + ${this.im}i`;
107+
}
104108
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Centralized Logging System for Arithmetica Lucis.
3+
* Provides unified console output and optional UI overlay integration.
4+
*/
5+
export class Logger {
6+
static DEBUG = 0;
7+
static INFO = 1;
8+
static WARN = 2;
9+
static ERROR = 3;
10+
11+
static LEVEL = Logger.INFO; // Default Limit
12+
13+
static uiTarget = null; // HTML Element to append logs to
14+
15+
static setMethod(uiElement) {
16+
Logger.uiTarget = uiElement;
17+
}
18+
19+
static format(level, message, source) {
20+
const timestamp = new Date().toISOString().split("T")[1].slice(0, -1);
21+
const prefix = source ? `[${timestamp}] [${source}]` : `[${timestamp}]`;
22+
return `${prefix} ${message}`;
23+
}
24+
25+
static debug(message, source) {
26+
if (Logger.LEVEL > Logger.DEBUG) return;
27+
console.debug(Logger.format("DEBUG", message, source));
28+
}
29+
30+
static info(message, source) {
31+
if (Logger.LEVEL > Logger.INFO) return;
32+
const formatted = Logger.format("INFO", message, source);
33+
console.info(formatted);
34+
Logger.sendToServer(formatted); // Persist INFO too
35+
}
36+
37+
static warn(message, source) {
38+
if (Logger.LEVEL > Logger.WARN) return;
39+
const formatted = Logger.format("WARN", message, source);
40+
console.warn(formatted);
41+
Logger.logToUI(formatted, "orange");
42+
}
43+
44+
static error(message, source) {
45+
const formatted = Logger.format("ERROR", message, source);
46+
console.error(formatted);
47+
Logger.logToUI(formatted, "red");
48+
}
49+
50+
static logToUI(text, color) {
51+
// Send to Server (Fire and Forget)
52+
Logger.sendToServer(text);
53+
54+
if (!Logger.uiTarget) return;
55+
// Simple append, could be fancier
56+
// We use innerHTML += but strictly safely for prototype
57+
const div = document.createElement("div");
58+
div.style.color = color;
59+
div.style.fontFamily = "monospace";
60+
div.style.fontSize = "12px";
61+
div.textContent = text;
62+
Logger.uiTarget.appendChild(div);
63+
64+
// Auto-scroll
65+
Logger.uiTarget.scrollTop = Logger.uiTarget.scrollHeight;
66+
}
67+
68+
static sendToServer(message) {
69+
// We use the relative path '/log' which works if served by our custom server.
70+
// We use skip waiting for response to avoid blocking UI.
71+
try {
72+
fetch("/log", {
73+
method: "POST",
74+
headers: { "Content-Type": "text/plain" },
75+
body: message,
76+
}).catch((e) => console.error("Failed to send log to server", e));
77+
} catch (e) {
78+
// Ignore network errors
79+
}
80+
}
81+
}

projects/arithmetica-lucis/prototype/mobius-caustic-solver/src/core/mobius.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,22 @@ export class Mobius {
4242
// (a b) (A B) = (aA+bC aB+bD)
4343
// (c d) (C D) (cA+dC cB+dD)
4444
const a = Complex.add(
45-
temp1,
45+
new Complex(),
4646
Complex.mul(temp2, this.a, other.a),
4747
Complex.mul(temp3, this.b, other.c)
4848
);
4949
const b = Complex.add(
50-
temp1,
50+
new Complex(),
5151
Complex.mul(temp2, this.a, other.b),
5252
Complex.mul(temp3, this.b, other.d)
5353
);
5454
const c = Complex.add(
55-
temp1,
55+
new Complex(),
5656
Complex.mul(temp2, this.c, other.a),
5757
Complex.mul(temp3, this.d, other.c)
5858
);
5959
const d = Complex.add(
60-
temp1,
60+
new Complex(),
6161
Complex.mul(temp2, this.c, other.b),
6262
Complex.mul(temp3, this.d, other.d)
6363
);
@@ -94,7 +94,9 @@ export class Mobius {
9494
const theta = Math.atan2(det.im, det.re) / 2;
9595
const sqrtDet = temp4.set(r * Math.cos(theta), r * Math.sin(theta));
9696

97-
if (r === 0) return this; // Should not happen for valid transforms
97+
if (r < 1e-9) {
98+
throw new Error("Mobius: Singular Matrix (Det=0). Cannot normalize.");
99+
}
98100

99101
Complex.div(this.a, this.a, sqrtDet);
100102
Complex.div(this.b, this.b, sqrtDet);
@@ -103,4 +105,25 @@ export class Mobius {
103105

104106
return this;
105107
}
108+
109+
/**
110+
* Calculates the derivative f'(z) at a point z.
111+
* f'(z) = (ad - bc) / (cz + d)^2
112+
* Since normalized, ad-bc = 1.
113+
* f'(z) = 1 / (cz + d)^2
114+
*/
115+
derivative(z) {
116+
// 1 / (cz + d)^2
117+
// denom = cz + d
118+
const denom = Complex.add(temp3, Complex.mul(temp4, this.c, z), this.d);
119+
// denomSq = denom * denom
120+
const denomSq = Complex.mul(temp1, denom, denom);
121+
122+
// result = 1 / denomSq
123+
// 1 is (1, 0)
124+
const one = new Complex(1, 0);
125+
const out = new Complex();
126+
Complex.div(out, one, denomSq);
127+
return out;
128+
}
106129
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Logger } from "./logger.js";
2+
3+
export class PerformanceMonitor {
4+
constructor(callbacks = {}) {
5+
this.callbacks = callbacks; // { onDegrade: (msg) => {}, ... }
6+
this.stats = {
7+
frameCount: 0,
8+
lastTime: performance.now(),
9+
frameTimes: [],
10+
consecutiveBadFrames: 0,
11+
degraded: false,
12+
budgetExceeded: false,
13+
};
14+
}
15+
16+
// Called every frame
17+
update() {
18+
const now = performance.now();
19+
const dt = now - this.stats.lastTime;
20+
this.stats.lastTime = now;
21+
22+
// --- INSTANT REACTIVITY ---
23+
// Rule: Degradation if > 33ms latency OR Budget Flag (> 12ms render time)
24+
if ((dt > 33 || this.stats.budgetExceeded) && !this.stats.degraded) {
25+
const msg = this.stats.budgetExceeded
26+
? "Frame Budget Exceeded > 12ms"
27+
: `High Latency (${Math.round(dt)}ms)`;
28+
Logger.error(`${msg}. Degrading Quality IMMEDIATELY.`, "Watchdog");
29+
30+
this.stats.budgetExceeded = false;
31+
this.stats.degraded = true;
32+
33+
if (this.callbacks.onDegrade) {
34+
this.callbacks.onDegrade(msg);
35+
}
36+
}
37+
38+
// --- Graph Data ---
39+
this.stats.frameTimes.push(dt);
40+
if (this.stats.frameTimes.length > 270) this.stats.frameTimes.shift();
41+
42+
if (this.callbacks.onGraphDraw) {
43+
this.callbacks.onGraphDraw(this.stats.frameTimes);
44+
}
45+
46+
// --- Periodic Logging & UI (1Hz) ---
47+
if (this.stats.frameCount++ % 60 === 0) {
48+
const fps = Math.round(1000 / (dt || 1));
49+
const latency = Math.round(dt);
50+
51+
if (this.callbacks.onStatsUpdate) {
52+
this.callbacks.onStatsUpdate(fps, latency);
53+
}
54+
}
55+
}
56+
57+
markBudgetExceeded() {
58+
this.stats.budgetExceeded = true;
59+
}
60+
}

0 commit comments

Comments
 (0)