melete-ai 0.88.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/bin/melete-server.mjs +345 -0
- package/bin/melete.mjs +165 -0
- package/dist/achievability.d.ts +38 -0
- package/dist/achievability.d.ts.map +1 -0
- package/dist/achievability.js +135 -0
- package/dist/achievability.js.map +1 -0
- package/dist/aegis.d.ts +52 -0
- package/dist/aegis.d.ts.map +1 -0
- package/dist/aegis.js +191 -0
- package/dist/aegis.js.map +1 -0
- package/dist/arms.d.ts +70 -0
- package/dist/arms.d.ts.map +1 -0
- package/dist/arms.js +399 -0
- package/dist/arms.js.map +1 -0
- package/dist/batch.d.ts +30 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +151 -0
- package/dist/batch.js.map +1 -0
- package/dist/bench.d.ts +49 -0
- package/dist/bench.d.ts.map +1 -0
- package/dist/bench.js +124 -0
- package/dist/bench.js.map +1 -0
- package/dist/certify.d.ts +48 -0
- package/dist/certify.d.ts.map +1 -0
- package/dist/certify.js +125 -0
- package/dist/certify.js.map +1 -0
- package/dist/cliff.d.ts +41 -0
- package/dist/cliff.d.ts.map +1 -0
- package/dist/cliff.js +132 -0
- package/dist/cliff.js.map +1 -0
- package/dist/confidence.d.ts +38 -0
- package/dist/confidence.d.ts.map +1 -0
- package/dist/confidence.js +98 -0
- package/dist/confidence.js.map +1 -0
- package/dist/constrained.d.ts +59 -0
- package/dist/constrained.d.ts.map +1 -0
- package/dist/constrained.js +191 -0
- package/dist/constrained.js.map +1 -0
- package/dist/cortex.d.ts +56 -0
- package/dist/cortex.d.ts.map +1 -0
- package/dist/cortex.js +81 -0
- package/dist/cortex.js.map +1 -0
- package/dist/costaware.d.ts +49 -0
- package/dist/costaware.d.ts.map +1 -0
- package/dist/costaware.js +185 -0
- package/dist/costaware.js.map +1 -0
- package/dist/drift.d.ts +36 -0
- package/dist/drift.d.ts.map +1 -0
- package/dist/drift.js +157 -0
- package/dist/drift.js.map +1 -0
- package/dist/efficiency.d.ts +49 -0
- package/dist/efficiency.d.ts.map +1 -0
- package/dist/efficiency.js +143 -0
- package/dist/efficiency.js.map +1 -0
- package/dist/engine.d.ts +64 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +130 -0
- package/dist/engine.js.map +1 -0
- package/dist/federated.d.ts +38 -0
- package/dist/federated.d.ts.map +1 -0
- package/dist/federated.js +121 -0
- package/dist/federated.js.map +1 -0
- package/dist/frontier.d.ts +51 -0
- package/dist/frontier.d.ts.map +1 -0
- package/dist/frontier.js +117 -0
- package/dist/frontier.js.map +1 -0
- package/dist/guardian.d.ts +46 -0
- package/dist/guardian.d.ts.map +1 -0
- package/dist/guardian.js +101 -0
- package/dist/guardian.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +44 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +167 -0
- package/dist/interaction.js.map +1 -0
- package/dist/interactive.d.ts +25 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +75 -0
- package/dist/interactive.js.map +1 -0
- package/dist/inverse.d.ts +44 -0
- package/dist/inverse.d.ts.map +1 -0
- package/dist/inverse.js +141 -0
- package/dist/inverse.js.map +1 -0
- package/dist/ipshield.d.ts +62 -0
- package/dist/ipshield.d.ts.map +1 -0
- package/dist/ipshield.js +104 -0
- package/dist/ipshield.js.map +1 -0
- package/dist/journalist.d.ts +56 -0
- package/dist/journalist.d.ts.map +1 -0
- package/dist/journalist.js +132 -0
- package/dist/journalist.js.map +1 -0
- package/dist/lineage.d.ts +43 -0
- package/dist/lineage.d.ts.map +1 -0
- package/dist/lineage.js +112 -0
- package/dist/lineage.js.map +1 -0
- package/dist/metabrain.d.ts +59 -0
- package/dist/metabrain.d.ts.map +1 -0
- package/dist/metabrain.js +215 -0
- package/dist/metabrain.js.map +1 -0
- package/dist/mixedspace.d.ts +61 -0
- package/dist/mixedspace.d.ts.map +1 -0
- package/dist/mixedspace.js +267 -0
- package/dist/mixedspace.js.map +1 -0
- package/dist/multiobjective.d.ts +42 -0
- package/dist/multiobjective.d.ts.map +1 -0
- package/dist/multiobjective.js +123 -0
- package/dist/multiobjective.js.map +1 -0
- package/dist/noise.d.ts +45 -0
- package/dist/noise.d.ts.map +1 -0
- package/dist/noise.js +148 -0
- package/dist/noise.js.map +1 -0
- package/dist/noiserobust.d.ts +71 -0
- package/dist/noiserobust.d.ts.map +1 -0
- package/dist/noiserobust.js +215 -0
- package/dist/noiserobust.js.map +1 -0
- package/dist/oracle.d.ts +63 -0
- package/dist/oracle.d.ts.map +1 -0
- package/dist/oracle.js +106 -0
- package/dist/oracle.js.map +1 -0
- package/dist/poopt.d.ts +79 -0
- package/dist/poopt.d.ts.map +1 -0
- package/dist/poopt.js +148 -0
- package/dist/poopt.js.map +1 -0
- package/dist/portfolio.d.ts +51 -0
- package/dist/portfolio.d.ts.map +1 -0
- package/dist/portfolio.js +132 -0
- package/dist/portfolio.js.map +1 -0
- package/dist/prescription.d.ts +57 -0
- package/dist/prescription.d.ts.map +1 -0
- package/dist/prescription.js +131 -0
- package/dist/prescription.js.map +1 -0
- package/dist/prime.d.ts +85 -0
- package/dist/prime.d.ts.map +1 -0
- package/dist/prime.js +157 -0
- package/dist/prime.js.map +1 -0
- package/dist/provenance.d.ts +77 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +155 -0
- package/dist/provenance.js.map +1 -0
- package/dist/rashomon.d.ts +40 -0
- package/dist/rashomon.d.ts.map +1 -0
- package/dist/rashomon.js +93 -0
- package/dist/rashomon.js.map +1 -0
- package/dist/reliability.d.ts +79 -0
- package/dist/reliability.d.ts.map +1 -0
- package/dist/reliability.js +197 -0
- package/dist/reliability.js.map +1 -0
- package/dist/replay.d.ts +62 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +146 -0
- package/dist/replay.js.map +1 -0
- package/dist/replicate.d.ts +72 -0
- package/dist/replicate.d.ts.map +1 -0
- package/dist/replicate.js +103 -0
- package/dist/replicate.js.map +1 -0
- package/dist/resonance.d.ts +32 -0
- package/dist/resonance.d.ts.map +1 -0
- package/dist/resonance.js +190 -0
- package/dist/resonance.js.map +1 -0
- package/dist/sensitivity.d.ts +44 -0
- package/dist/sensitivity.d.ts.map +1 -0
- package/dist/sensitivity.js +109 -0
- package/dist/sensitivity.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1410 -0
- package/dist/server.js.map +1 -0
- package/dist/shape.d.ts +37 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +170 -0
- package/dist/shape.js.map +1 -0
- package/dist/sloppiness.d.ts +44 -0
- package/dist/sloppiness.d.ts.map +1 -0
- package/dist/sloppiness.js +194 -0
- package/dist/sloppiness.js.map +1 -0
- package/dist/sovereign.d.ts +77 -0
- package/dist/sovereign.d.ts.map +1 -0
- package/dist/sovereign.js +144 -0
- package/dist/sovereign.js.map +1 -0
- package/dist/space.d.ts +38 -0
- package/dist/space.d.ts.map +1 -0
- package/dist/space.js +107 -0
- package/dist/space.js.map +1 -0
- package/dist/surprise.d.ts +43 -0
- package/dist/surprise.d.ts.map +1 -0
- package/dist/surprise.js +123 -0
- package/dist/surprise.js.map +1 -0
- package/dist/territory.d.ts +43 -0
- package/dist/territory.d.ts.map +1 -0
- package/dist/territory.js +102 -0
- package/dist/territory.js.map +1 -0
- package/dist/trace.d.ts +58 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +0 -0
- package/dist/trace.js.map +1 -0
- package/dist/transfer.d.ts +46 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +112 -0
- package/dist/transfer.js.map +1 -0
- package/dist/twin.d.ts +41 -0
- package/dist/twin.d.ts.map +1 -0
- package/dist/twin.js +116 -0
- package/dist/twin.js.map +1 -0
- package/examples/train.mjs +8 -0
- package/examples/tune.mjs +11 -0
- package/package.json +56 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,1410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MELETE WEB — discovery-as-a-service. A self-contained HTTP surface so anyone (or any agent) can POST an
|
|
3
|
+
* objective + a search space and get back the discovered optimum AND its signed, verifiable trace — no
|
|
4
|
+
* install. The landing page is a live demo; the JSON endpoints are the product; /pitch is the buyer deck.
|
|
5
|
+
*
|
|
6
|
+
* This module owns the landing page + the pitch deck (pure strings) + the endpoint catalogue. The HTTP
|
|
7
|
+
* server + the sandboxed objective evaluation live in bin/melete-server.mjs (node:http + node:vm).
|
|
8
|
+
*/
|
|
9
|
+
export const ENDPOINTS = [
|
|
10
|
+
{ method: "GET", path: "/health", what: "liveness + version" },
|
|
11
|
+
{ method: "GET", path: "/pitch", what: "the investor / acquirer slide deck" },
|
|
12
|
+
{ method: "POST", path: "/discover", what: "run a discovery — {space, objective, budget, goal, engine} → {best, armStats, trace}" },
|
|
13
|
+
{ method: "POST", path: "/verify", what: "re-verify a discovery trace offline — {trace} → {ok, reason}" },
|
|
14
|
+
];
|
|
15
|
+
const SHELL_CSS = `
|
|
16
|
+
:root{--ink:#16172b;--ink2:#5b5d77;--line:#e7e8f0;--bg:#ffffff;--soft:#f7f8fc;--ind:#5b53e8;--teal:#0ea5b7;--grad:linear-gradient(96deg,#6d5cf0,#0ea5b7)}
|
|
17
|
+
*{box-sizing:border-box}
|
|
18
|
+
body{margin:0;background:var(--bg);color:var(--ink);font:16px/1.65 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased}
|
|
19
|
+
a{color:var(--ind);text-decoration:none;font-weight:600}a:hover{text-decoration:underline}
|
|
20
|
+
.langsw{position:fixed;top:14px;right:16px;z-index:60;display:flex;background:#fff;border:1px solid var(--line);border-radius:999px;padding:3px;gap:2px;box-shadow:0 4px 14px rgba(20,20,50,.12)}
|
|
21
|
+
.lb{border:0;background:transparent;border-radius:999px;padding:6px 13px;font-size:13px;font-weight:700;color:#6a6c84;cursor:pointer}
|
|
22
|
+
.lb.on{background:var(--grad);color:#fff}
|
|
23
|
+
.cmodal{display:none;position:fixed;inset:0;background:rgba(20,18,40,.55);z-index:100;align-items:center;justify-content:center;padding:18px}
|
|
24
|
+
.cbox{background:#fff;border-radius:20px;padding:26px 26px 20px;max-width:430px;width:100%;position:relative;box-shadow:0 30px 80px -20px rgba(20,20,60,.5)}
|
|
25
|
+
.cclose{position:absolute;top:12px;right:14px;border:0;background:#f1f2f8;border-radius:50%;width:30px;height:30px;font-size:14px;cursor:pointer;color:#6a6c84}
|
|
26
|
+
.ctab{width:100%;border-collapse:collapse;font-size:14.5px}
|
|
27
|
+
.ctab td{padding:11px 8px;border-bottom:1px solid var(--line)}
|
|
28
|
+
.ctab tr:last-child td{border-bottom:0}
|
|
29
|
+
.ctab td:first-child{font-weight:700;color:#33344e;white-space:nowrap}
|
|
30
|
+
.thtag{display:inline-block;background:#e9fbf3;color:#0e9f6e;border:1px solid #b7ecd4;border-radius:999px;padding:1px 7px;font-size:10.5px;font-weight:700;margin-left:4px}
|
|
31
|
+
.wrap{max-width:1000px;margin:0 auto;padding:0 24px}
|
|
32
|
+
.grad{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
33
|
+
.hero{position:relative;overflow:hidden;text-align:center;padding:84px 24px 54px;background:radial-gradient(70% 90% at 50% -10%,#eef0ff,transparent 60%)}
|
|
34
|
+
.eyebrow{display:inline-block;font-size:12.5px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--ind);background:#eeecfe;border:1px solid #ddd9fb;padding:5px 13px;border-radius:999px;margin-bottom:18px}
|
|
35
|
+
h1.brand{font-size:72px;line-height:.98;margin:0;font-weight:850;letter-spacing:-2.5px}
|
|
36
|
+
.tag{font-size:23px;color:#33344e;margin:16px auto 8px;font-weight:600;max-width:680px;line-height:1.35}
|
|
37
|
+
.sub{color:var(--ink2);font-size:16px;margin:0 0 26px}
|
|
38
|
+
.cta{display:inline-flex;gap:12px;flex-wrap:wrap;justify-content:center}
|
|
39
|
+
.btn{display:inline-block;border-radius:12px;padding:13px 24px;font-weight:700;font-size:15.5px;cursor:pointer;border:0}
|
|
40
|
+
.btn.primary{background:var(--grad);color:#fff;box-shadow:0 8px 24px -8px rgba(93,83,232,.6)}
|
|
41
|
+
.btn.ghost{background:#fff;color:var(--ink);border:1.5px solid var(--line)}
|
|
42
|
+
.pills{margin:26px 0 0}
|
|
43
|
+
.pill{display:inline-block;background:#fff;border:1px solid var(--line);border-radius:999px;padding:6px 14px;font-size:13px;color:#44465e;font-weight:600;margin:3px;box-shadow:0 1px 2px rgba(20,20,40,.04)}
|
|
44
|
+
section{padding:46px 0;border-top:1px solid var(--line)}
|
|
45
|
+
h2{font-size:13px;letter-spacing:1.6px;text-transform:uppercase;color:#9698ad;margin:0 0 20px;font-weight:800}
|
|
46
|
+
.lead{font-size:22px;line-height:1.45;color:#2a2b42;margin:0;font-weight:500}
|
|
47
|
+
.lead b{font-weight:800}
|
|
48
|
+
.steps{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
|
|
49
|
+
.step{background:var(--soft);border:1px solid var(--line);border-radius:16px;padding:20px}
|
|
50
|
+
.step .n{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:9px;background:var(--grad);color:#fff;font-weight:800;font-size:15px;margin-bottom:10px}
|
|
51
|
+
.step h3{margin:0 0 5px;font-size:17px}.step p{margin:0;color:var(--ink2);font-size:14.5px}
|
|
52
|
+
.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
|
53
|
+
@media(max-width:760px){.grid,.steps{grid-template-columns:1fr}h1.brand{font-size:50px}.tag{font-size:20px}}
|
|
54
|
+
.card{background:#fff;border:1px solid var(--line);border-radius:16px;padding:20px;box-shadow:0 2px 10px rgba(20,20,50,.03)}
|
|
55
|
+
.card h3{margin:0 0 6px;font-size:17px}
|
|
56
|
+
.card .who{color:var(--teal);font-size:12px;font-weight:800;letter-spacing:.4px;margin-bottom:9px;text-transform:uppercase}
|
|
57
|
+
.card p{margin:0;color:var(--ink2);font-size:14.5px}
|
|
58
|
+
table{width:100%;border-collapse:collapse;font-size:14.5px}
|
|
59
|
+
th,td{padding:11px 12px;border-bottom:1px solid var(--line);text-align:left}
|
|
60
|
+
th{color:#9698ad;font-weight:700;font-size:12px;text-transform:uppercase;letter-spacing:.5px}
|
|
61
|
+
.win{color:#0e9f6e;font-weight:800}
|
|
62
|
+
code{font-family:ui-monospace,Menlo,monospace;background:#f1f2f8;border-radius:6px;padding:2px 7px;font-size:13.5px;color:#4338ca}
|
|
63
|
+
pre{font-family:ui-monospace,Menlo,monospace;background:#16172b;color:#d7d9f0;border-radius:12px;padding:16px;overflow:auto;font-size:13px;line-height:1.55}
|
|
64
|
+
label{display:block;color:#6a6c84;font-size:12px;margin:14px 0 5px;font-weight:700;letter-spacing:.3px;text-transform:uppercase}
|
|
65
|
+
input,select{width:100%;background:#fff;border:1.5px solid var(--line);border-radius:10px;color:var(--ink);padding:12px;font-family:ui-monospace,monospace;font-size:13.5px}
|
|
66
|
+
input:focus,select:focus{outline:0;border-color:var(--ind)}
|
|
67
|
+
.muted{color:#9092a8}
|
|
68
|
+
footer{padding:40px 0 80px;color:#9092a8;font-size:13px;text-align:center;border-top:1px solid var(--line)}
|
|
69
|
+
#map{display:none;margin-top:18px}
|
|
70
|
+
#map.on{display:block}
|
|
71
|
+
.mapgrid{display:grid;grid-template-columns:1.1fr .9fr;gap:18px;align-items:start}
|
|
72
|
+
@media(max-width:760px){.mapgrid{grid-template-columns:1fr}}
|
|
73
|
+
canvas{border-radius:12px;border:1px solid var(--line);background:#fff}
|
|
74
|
+
#surf{width:100%;height:auto;aspect-ratio:1/1;display:block}
|
|
75
|
+
#conv{width:100%}
|
|
76
|
+
.caps{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#9698ad;margin-bottom:8px}
|
|
77
|
+
.player{display:flex;align-items:center;gap:11px;margin-top:11px}
|
|
78
|
+
.pbtn{background:var(--grad);color:#fff;border:0;border-radius:9px;padding:8px 15px;font-weight:700;font-size:13px;cursor:pointer;white-space:nowrap}
|
|
79
|
+
#scrub{flex:1;accent-color:var(--ind)}
|
|
80
|
+
.legend{display:flex;flex-wrap:wrap;gap:7px 13px;margin-top:12px;font-size:12px;color:#5b5d77;font-weight:600}
|
|
81
|
+
.legdot{display:inline-flex;align-items:center;gap:5px}
|
|
82
|
+
.legdot i{width:11px;height:11px;border-radius:50%;display:inline-block;box-shadow:0 0 0 1px rgba(0,0,0,.06)}
|
|
83
|
+
.kv{font-size:14px;color:#33344e}.kv b{color:var(--ink)}
|
|
84
|
+
.bar{height:9px;border-radius:6px;background:var(--grad);margin:2px 0 9px}
|
|
85
|
+
.result{margin-top:14px;background:var(--soft);border:1px solid var(--line);border-radius:12px;padding:16px;font-size:14.5px;color:#2a2b42;min-height:24px}
|
|
86
|
+
.narrate{margin-top:12px;background:linear-gradient(135deg,#f3f1ff,#eafcf8);border:1.5px solid #ddd9fb;border-radius:14px;padding:16px 18px;font-size:15px;line-height:1.65;color:#26283f}
|
|
87
|
+
.savings{margin-top:12px;background:rgba(255,255,255,.82);backdrop-filter:blur(12px) saturate(1.2);-webkit-backdrop-filter:blur(12px) saturate(1.2);border:1px solid #ecebf6;border-radius:18px;padding:17px 20px;font-size:14.5px;line-height:1.6;color:#26283f;box-shadow:0 1px 2px rgba(30,25,80,.04),0 20px 46px -34px rgba(70,55,160,.42)}
|
|
88
|
+
.modetabs{display:inline-flex;background:#f1f2f8;border:1px solid var(--line);border-radius:11px;padding:4px;gap:4px;margin-bottom:6px}
|
|
89
|
+
.mt{background:transparent;border:0;border-radius:8px;padding:8px 14px;font-size:13.5px;font-weight:700;color:#6a6c84;cursor:pointer}
|
|
90
|
+
.mt.on{background:#fff;color:var(--ind);box-shadow:0 1px 4px rgba(20,20,50,.08)}
|
|
91
|
+
.advbox{display:none;margin-top:6px;padding-top:8px;border-top:1px dashed var(--line)}
|
|
92
|
+
.indcard{cursor:pointer;transition:transform .15s,box-shadow .15s;border:1.5px solid var(--line)}
|
|
93
|
+
.indcard:hover{transform:translateY(-3px);box-shadow:0 12px 28px -10px rgba(80,60,220,.28);border-color:#c7c2f5}
|
|
94
|
+
.indcard .go{margin-top:10px;color:var(--ind);font-weight:700;font-size:13.5px}
|
|
95
|
+
.scenario{background:var(--soft);border:1px solid var(--line);border-radius:12px;padding:13px 16px;margin:12px 0}
|
|
96
|
+
.srow{display:flex;gap:12px;padding:5px 0;font-size:14.5px;color:#33344e;line-height:1.4}
|
|
97
|
+
.srow b{min-width:94px;white-space:nowrap}
|
|
98
|
+
.adv{margin-top:6px}
|
|
99
|
+
.adv summary{cursor:pointer;color:var(--ind);font-size:13px;font-weight:700;padding:6px 0;list-style:none}
|
|
100
|
+
.adv summary::-webkit-details-marker{display:none}
|
|
101
|
+
.adv summary::before{content:"⚙ ";opacity:.7}
|
|
102
|
+
.story{background:linear-gradient(180deg,#f7f8ff,#fff);border:1px solid var(--line);border-radius:16px;padding:22px 24px}
|
|
103
|
+
.story p{margin:0 0 12px}.story p:last-child{margin:0}
|
|
104
|
+
.chat{font-size:14.5px;color:#33344e;margin:3px 0;padding-left:14px;border-left:2px solid #ddd9fb}
|
|
105
|
+
.meli{display:block;animation:bob 3.4s ease-in-out infinite}
|
|
106
|
+
.meli.hero{width:104px;height:auto;margin:0 auto 8px}
|
|
107
|
+
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
|
|
108
|
+
.orb{transform-box:fill-box;transform-origin:center;animation:pulse 1.9s ease-in-out infinite}
|
|
109
|
+
@keyframes pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.24);opacity:.82}}
|
|
110
|
+
.arm{transform-box:fill-box;transform-origin:bottom center;animation:wave 2.6s ease-in-out infinite}
|
|
111
|
+
@keyframes wave{0%,100%{transform:rotate(-30deg)}50%{transform:rotate(-10deg)}}
|
|
112
|
+
.eyes{transform-box:fill-box;transform-origin:center;animation:blink 5s ease-in-out infinite}
|
|
113
|
+
@keyframes blink{0%,93%,100%{transform:scaleY(1)}96%{transform:scaleY(.12)}}
|
|
114
|
+
.spark{transform-box:fill-box;transform-origin:center}
|
|
115
|
+
.spark.s1{animation:twinkle 1.9s ease-in-out infinite}.spark.s2{animation:twinkle 2.4s ease-in-out .6s infinite}
|
|
116
|
+
@keyframes twinkle{0%,100%{opacity:.25;transform:scale(.6) rotate(0)}50%{opacity:1;transform:scale(1.15) rotate(40deg)}}
|
|
117
|
+
@media(prefers-reduced-motion:reduce){.meli,.orb,.arm,.eyes,.spark{animation:none}}
|
|
118
|
+
.storybook{display:flex;flex-direction:column;gap:18px}
|
|
119
|
+
.panel{display:flex;align-items:center;gap:26px;border:2.5px solid var(--line);border-radius:24px;padding:24px 28px;opacity:0;transform:translateY(36px) scale(.97);transition:opacity .6s cubic-bezier(.2,.7,.2,1),transform .6s cubic-bezier(.2,.7,.2,1)}
|
|
120
|
+
.panel.in{opacity:1;transform:none}
|
|
121
|
+
.panel:nth-child(even){flex-direction:row-reverse}
|
|
122
|
+
.panel-art{flex:0 0 172px;position:relative;display:flex;justify-content:center}
|
|
123
|
+
.panel-art .meli{width:154px;height:auto}
|
|
124
|
+
.panel-text{flex:1;min-width:0}
|
|
125
|
+
.panel-text p{margin:0;font-size:19.5px;line-height:1.55;color:#26283f}
|
|
126
|
+
.beatnum{display:inline-flex;width:32px;height:32px;align-items:center;justify-content:center;border-radius:10px;background:var(--grad);color:#fff;font-weight:800;font-size:15px;margin-bottom:11px;box-shadow:0 4px 10px -2px rgba(80,60,220,.4)}
|
|
127
|
+
.panel.wish{background:linear-gradient(155deg,#fff0f8,#fff);border-color:#f9a8d4;box-shadow:0 10px 30px -12px rgba(236,72,153,.30)}
|
|
128
|
+
.panel.maze{background:linear-gradient(155deg,#eef0ff,#fff);border-color:#a5b4fc;box-shadow:0 10px 30px -12px rgba(99,102,241,.30)}
|
|
129
|
+
.panel.think{background:linear-gradient(155deg,#f3eeff,#fff);border-color:#c4b5fd;box-shadow:0 10px 30px -12px rgba(139,92,246,.30)}
|
|
130
|
+
.panel.dance{background:linear-gradient(155deg,#e8fcf4,#fff);border-color:#5eead4;box-shadow:0 10px 30px -12px rgba(13,148,136,.30)}
|
|
131
|
+
.panel.win{background:linear-gradient(155deg,#fff7e6,#fff);border-color:#fcd34d;box-shadow:0 12px 34px -10px rgba(245,158,11,.40)}
|
|
132
|
+
.prop{position:absolute;pointer-events:none;opacity:0;transition:opacity .5s .25s}
|
|
133
|
+
.panel.in .prop{opacity:1}
|
|
134
|
+
.prop.hearts{top:-4px;right:24px;font-size:26px;animation:floatup 2.6s ease-in-out infinite}
|
|
135
|
+
.prop.cups{top:4px;left:-2px;font-size:17px;line-height:1.2;opacity:.4 !important;letter-spacing:3px}
|
|
136
|
+
.prop.bubble{top:2px;right:0;background:#fff;border:1.5px solid #ddd9fb;border-radius:13px;padding:7px 12px;font-size:13.5px;color:#4338ca;font-weight:700;box-shadow:0 4px 12px rgba(80,60,220,.14)}
|
|
137
|
+
.panel.in .prop.bubble{animation:pop .5s .35s both}
|
|
138
|
+
.prop.cup{top:2px;right:6px;font-size:36px}
|
|
139
|
+
.prop.cup .score{position:absolute;top:4px;right:46px;font-family:ui-monospace,monospace;font-size:13px;font-weight:700;color:#0e9f6e;background:#e9fbf3;border:1px solid #b7ecd4;border-radius:8px;padding:3px 9px;white-space:nowrap}
|
|
140
|
+
.prop.star{top:-6px;left:52%;margin-left:-15px;font-size:32px}
|
|
141
|
+
.panel.in .prop.star{animation:pop .6s .4s both}
|
|
142
|
+
.prop.seal{bottom:6px;right:2px;font-size:12.5px;font-weight:700;color:#0e9f6e;background:#e9fbf3;border:1px solid #b7ecd4;border-radius:999px;padding:5px 11px}
|
|
143
|
+
.panel.think.in .orb{animation:pulse 1s ease-in-out infinite}
|
|
144
|
+
.panel.win.in .meli{animation:cheer .75s ease 1}
|
|
145
|
+
@keyframes cheer{0%{transform:translateY(0) rotate(0)}30%{transform:translateY(-17px) rotate(-6deg)}60%{transform:translateY(-4px) rotate(5deg)}100%{transform:translateY(0)}}
|
|
146
|
+
@keyframes floatup{0%,100%{transform:translateY(0)}50%{transform:translateY(-10px)}}
|
|
147
|
+
@keyframes pop{0%{transform:scale(0);opacity:0}70%{transform:scale(1.15)}100%{transform:scale(1);opacity:1}}
|
|
148
|
+
@media(max-width:640px){.panel,.panel:nth-child(even){flex-direction:column;text-align:center}.panel-text p{font-size:17.5px}.prop.cup .score{position:static;display:inline-block;margin-top:6px}}
|
|
149
|
+
@media(prefers-reduced-motion:reduce){.panel{transition:none;opacity:1;transform:none}}
|
|
150
|
+
/*premium-layer*/
|
|
151
|
+
/*select-styled*/
|
|
152
|
+
select{appearance:none !important;-webkit-appearance:none !important;-moz-appearance:none !important;background-color:#f5f3ff !important;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236d28d9' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") !important;background-repeat:no-repeat !important;background-position:right 13px center !important;background-size:13px !important;border:1.5px solid #d6cffa !important;border-radius:11px !important;padding:11px 40px 11px 14px !important;font-weight:600 !important;font-size:14px !important;color:#33344e !important;cursor:pointer;transition:border-color .15s,box-shadow .15s,background-color .15s}
|
|
153
|
+
select:hover{border-color:#b3a6f0 !important;background-color:#efeaff !important}
|
|
154
|
+
select:focus{outline:none;border-color:var(--ind) !important;box-shadow:0 0 0 3px rgba(91,83,232,.18) !important}
|
|
155
|
+
select option{font-weight:500;color:#1a1b30;background:#fff}
|
|
156
|
+
/*gsteps-anim*/
|
|
157
|
+
#gsteps>div:last-child>div>div:first-child{animation:gbglow 3.6s ease-in-out infinite}
|
|
158
|
+
#gsteps>div:last-child>div:nth-child(2)>div:first-child{animation-delay:.9s}
|
|
159
|
+
#gsteps>div:last-child>div:nth-child(3)>div:first-child{animation-delay:1.8s}
|
|
160
|
+
#gsteps>div:last-child>div:nth-child(4)>div:first-child{animation-delay:2.7s}
|
|
161
|
+
@keyframes gbglow{0%,55%,100%{box-shadow:0 0 0 0 rgba(99,102,241,0);transform:scale(1)}30%{box-shadow:0 0 0 7px rgba(99,102,241,.20);transform:scale(1.08)}}
|
|
162
|
+
@media(prefers-reduced-motion:reduce){#gsteps>div:last-child>div>div:first-child{animation:none}}
|
|
163
|
+
/*hl*/
|
|
164
|
+
#reliproof>h2,#pricing>h2,#guide>h2{font-size:32px;line-height:1.12;letter-spacing:-1px;text-transform:none;color:var(--ink);margin:8px 0 12px;font-weight:800}
|
|
165
|
+
@media(max-width:640px){#reliproof>h2,#pricing>h2,#guide>h2{font-size:25px}}
|
|
166
|
+
html{scroll-behavior:smooth}
|
|
167
|
+
.btn{transition:transform .15s ease,box-shadow .15s ease,filter .15s ease}
|
|
168
|
+
.btn:hover{transform:translateY(-1px)}
|
|
169
|
+
.btn.primary:hover{box-shadow:0 14px 32px -8px rgba(93,83,232,.7);filter:brightness(1.04)}
|
|
170
|
+
.btn.ghost:hover{border-color:var(--ind);color:var(--ind)}
|
|
171
|
+
.btn:active{transform:translateY(0)}
|
|
172
|
+
.card{transition:box-shadow .2s ease,transform .2s ease}
|
|
173
|
+
input{transition:border-color .15s ease,box-shadow .15s ease}
|
|
174
|
+
input:focus,textarea:focus{outline:none;border-color:var(--ind)!important;box-shadow:0 0 0 3px rgba(91,83,232,.16)}
|
|
175
|
+
b,strong,.result,input[type=number]{font-variant-numeric:tabular-nums}
|
|
176
|
+
::selection{background:rgba(91,83,232,.18)}
|
|
177
|
+
h1.brand{letter-spacing:-2.5px;font-feature-settings:"ss01","cv01"}
|
|
178
|
+
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.btn,.card{transition:none}}
|
|
179
|
+
/* — elegant FUTURISTIC layer (white, luxe, clearly visible) — */
|
|
180
|
+
body{background:#fbfbfe;font-variant-numeric:tabular-nums}
|
|
181
|
+
/* visible mesh-gradient aurora blooms (Linear/Stripe style) — white-dominant, slowly drifting */
|
|
182
|
+
body::before{content:"";position:fixed;inset:-20% -10%;z-index:-2;pointer-events:none;
|
|
183
|
+
background:radial-gradient(34% 34% at 82% 6%,rgba(20,184,166,.20),transparent 62%),
|
|
184
|
+
radial-gradient(40% 40% at 6% 12%,rgba(109,92,240,.18),transparent 60%),
|
|
185
|
+
radial-gradient(36% 38% at 92% 78%,rgba(167,139,250,.16),transparent 60%),
|
|
186
|
+
radial-gradient(30% 30% at 14% 92%,rgba(14,165,183,.14),transparent 60%);
|
|
187
|
+
filter:blur(20px);animation:meshDrift 26s ease-in-out infinite alternate}
|
|
188
|
+
@keyframes meshDrift{0%{transform:translate3d(0,0,0) scale(1)}50%{transform:translate3d(0,-2.2%,0) scale(1.06)}100%{transform:translate3d(1.5%,1.5%,0) scale(1.03)}}
|
|
189
|
+
/* faint precision grid over the blooms */
|
|
190
|
+
body::after{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.5;
|
|
191
|
+
background-image:radial-gradient(circle at 1px 1px,rgba(80,70,160,.07) 1px,transparent 0);background-size:30px 30px}
|
|
192
|
+
@media(prefers-reduced-motion:reduce){body::before{animation:none}}
|
|
193
|
+
/* frosted-glass cards with depth + a gradient hairline */
|
|
194
|
+
.card{border-radius:22px;border:1px solid rgba(230,228,248,.9);background:rgba(255,255,255,.82);backdrop-filter:blur(14px) saturate(1.25);-webkit-backdrop-filter:blur(14px) saturate(1.25);
|
|
195
|
+
box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 2px 6px rgba(30,25,80,.05),0 30px 60px -36px rgba(70,55,160,.45);
|
|
196
|
+
transition:transform .55s cubic-bezier(.22,1,.36,1),box-shadow .55s cubic-bezier(.22,1,.36,1)}
|
|
197
|
+
.card:hover{transform:translateY(-3px);box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 2px 6px rgba(30,25,80,.06),0 44px 80px -36px rgba(70,55,160,.55)}
|
|
198
|
+
.btn{transition:transform .4s cubic-bezier(.22,1,.36,1),box-shadow .4s cubic-bezier(.22,1,.36,1),filter .25s}
|
|
199
|
+
.btn.primary{box-shadow:0 12px 30px -10px rgba(99,76,240,.65)}
|
|
200
|
+
.btn.primary:hover{transform:translateY(-2px);box-shadow:0 20px 42px -12px rgba(99,76,240,.78)}
|
|
201
|
+
.pill{background:rgba(255,255,255,.78);backdrop-filter:blur(8px) saturate(1.2);box-shadow:0 1px 2px rgba(20,20,40,.05),0 10px 22px -16px rgba(60,50,140,.6)}
|
|
202
|
+
h1.brand .grad{filter:drop-shadow(0 8px 30px rgba(109,92,240,.35))}
|
|
203
|
+
h2{letter-spacing:-.6px}
|
|
204
|
+
.wrap section h2{position:relative}
|
|
205
|
+
.wrap section h2::after{content:"";display:block;width:52px;height:3px;margin-top:10px;border-radius:9px;background:linear-gradient(90deg,#6d5cf0,#14b8a6)}
|
|
206
|
+
.eyebrow{background:linear-gradient(96deg,#6d5cf0,#0ea5b7);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;font-weight:800;letter-spacing:.7px}
|
|
207
|
+
.relcard:hover{transform:translateY(-4px)}
|
|
208
|
+
.m60card{background:rgba(255,255,255,.72);backdrop-filter:blur(10px);border:1px solid #ecebf6;border-radius:16px;padding:15px 16px;display:flex;gap:12px;align-items:flex-start;box-shadow:0 14px 32px -26px rgba(70,55,160,.5);transition:transform .45s cubic-bezier(.22,1,.36,1)}
|
|
209
|
+
.m60card:hover{transform:translateY(-3px)}
|
|
210
|
+
.m60n{flex:0 0 auto;width:26px;height:26px;border-radius:50%;background:linear-gradient(135deg,#6d5cf0,#0ea5b7);color:#fff;font-weight:800;font-size:14px;display:flex;align-items:center;justify-content:center}
|
|
211
|
+
.m60t{font-size:13.5px;color:#33344e;line-height:1.5}
|
|
212
|
+
.laycard{display:flex;gap:11px;align-items:flex-start;background:#fff;border:1px solid #f0eef9;border-radius:13px;padding:13px 14px}
|
|
213
|
+
.layi{font-size:18px;line-height:1.2}
|
|
214
|
+
.laycard b{font-size:13px;letter-spacing:.4px;color:#1a1b30}
|
|
215
|
+
.laysub{font-size:12px;color:#6a6c84;margin-top:3px;line-height:1.45}
|
|
216
|
+
@keyframes jline{to{opacity:1}}
|
|
217
|
+
/* Sci-Fi Command Center — Umbrella-lab containment console (per-vertical live demo) */
|
|
218
|
+
.cmdcenter{background:radial-gradient(130% 120% at 50% -10%,#0d1322,#05060d 70%);border-radius:20px;padding:20px 22px;font-family:ui-monospace,Menlo,monospace;overflow:hidden;position:relative;isolation:isolate}
|
|
219
|
+
/* faint hex/grid floor of the lab */
|
|
220
|
+
.cmdcenter::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.5;background-image:linear-gradient(rgba(255,255,255,.035) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.035) 1px,transparent 1px);background-size:34px 34px;-webkit-mask-image:radial-gradient(120% 100% at 50% 0%,#000 30%,transparent 78%);mask-image:radial-gradient(120% 100% at 50% 0%,#000 30%,transparent 78%)}
|
|
221
|
+
/* faint static CRT scanlines only — no moving sweep (kept the panel calm, not busy) */
|
|
222
|
+
.cmdcenter::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;border-radius:20px;background:repeating-linear-gradient(0deg,rgba(255,255,255,.014) 0 1px,transparent 1px 3px)}
|
|
223
|
+
.cmdcenter>*{position:relative;z-index:2}
|
|
224
|
+
/* corner containment brackets */
|
|
225
|
+
.ccbrk{position:absolute;width:18px;height:18px;border:2px solid var(--cc,#22d3ee);opacity:.7;z-index:4}
|
|
226
|
+
.ccbrk.tl{top:9px;left:9px;border-right:0;border-bottom:0}.ccbrk.tr{top:9px;right:9px;border-left:0;border-bottom:0}
|
|
227
|
+
.ccbrk.bl{bottom:9px;left:9px;border-right:0;border-top:0}.ccbrk.br{bottom:9px;right:9px;border-left:0;border-top:0}
|
|
228
|
+
.cchead{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
|
|
229
|
+
.ccrec{width:9px;height:9px;border-radius:50%;background:var(--cc,#22d3ee);box-shadow:0 0 12px var(--cc,#22d3ee);animation:ccrec 1.4s ease-in-out infinite}
|
|
230
|
+
@keyframes ccrec{50%{opacity:.25}}
|
|
231
|
+
/* HUD provenance strip — every field is a real number from THIS run */
|
|
232
|
+
.cchud{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 12px}
|
|
233
|
+
.cchud span{font-size:10px;letter-spacing:.4px;color:#9fb0d0;background:rgba(255,255,255,.045);border:1px solid rgba(255,255,255,.09);border-radius:7px;padding:3px 8px}
|
|
234
|
+
.cchud b{color:#e6edff;font-weight:700}
|
|
235
|
+
.ccgrid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:16px}
|
|
236
|
+
@media(max-width:760px){.ccgrid{grid-template-columns:1fr}}
|
|
237
|
+
.ccscene{border:1px solid rgba(255,255,255,.09);border-radius:14px;background:radial-gradient(120% 120% at 50% 0%,rgba(255,255,255,.05),transparent 60%);padding:10px}
|
|
238
|
+
.ccscene svg{width:100%;height:auto;display:block}
|
|
239
|
+
.ccgauge{margin:7px 2px 0}
|
|
240
|
+
.ccgrow{display:flex;justify-content:space-between;font-size:11px;margin:0 0 3px}
|
|
241
|
+
.ccbar{height:6px;border-radius:9px;background:rgba(255,255,255,.07);overflow:hidden}
|
|
242
|
+
.ccfill{height:100%;border-radius:9px;transition:width 1.1s cubic-bezier(.22,1,.36,1)}
|
|
243
|
+
.cclog{border:1px solid rgba(255,255,255,.09);border-radius:14px;background:rgba(3,4,10,.86);padding:13px 15px;font-size:12.5px;line-height:1.62;min-height:150px;overflow-wrap:anywhere}
|
|
244
|
+
.ccline{margin:2px 0;white-space:pre-wrap}
|
|
245
|
+
.cccur{display:inline-block;width:8px;background:currentColor;animation:ccblink 1s steps(1) infinite;margin-left:1px}
|
|
246
|
+
@keyframes ccblink{50%{opacity:0}}
|
|
247
|
+
/* ENGINE CORE — the real competing strategies (the multi-strategy "AI-multiverse" brain) */
|
|
248
|
+
.cccore{margin-top:13px;border-top:1px solid rgba(255,255,255,.1);padding-top:11px}
|
|
249
|
+
.cccore-h{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:#9fb0d0;margin-bottom:8px}
|
|
250
|
+
.ccarms{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:7px}
|
|
251
|
+
.ccarm{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:9px;padding:7px 9px}
|
|
252
|
+
.ccarm .an{font-size:11px;color:#e6edff;font-weight:700;display:flex;align-items:center;gap:5px}
|
|
253
|
+
.ccarm .am{height:4px;border-radius:9px;margin-top:5px;background:rgba(255,255,255,.08);overflow:hidden}
|
|
254
|
+
.ccarm .af{height:100%;border-radius:9px}
|
|
255
|
+
.ccarm .aw{font-size:9.5px;color:#8595b8;margin-top:4px;letter-spacing:.2px}
|
|
256
|
+
.ccmore{background:transparent;border:1px solid var(--cc,#22d3ee);color:var(--cc,#22d3ee);font-family:inherit;font-size:12.5px;font-weight:700;letter-spacing:.3px;padding:8px 15px;border-radius:10px;cursor:pointer;transition:background .2s,box-shadow .2s}
|
|
257
|
+
.ccmore:hover{background:var(--cc,#22d3ee)1a;box-shadow:0 0 18px var(--cc,#22d3ee)55}
|
|
258
|
+
.ccmore:disabled{opacity:.5;cursor:default}
|
|
259
|
+
.galcard{position:relative;cursor:pointer;border-radius:16px;padding:17px 16px;background:rgba(255,255,255,.8);backdrop-filter:blur(10px);border:1px solid #ecebf6;box-shadow:0 16px 36px -28px rgba(70,55,160,.5);transition:transform .45s cubic-bezier(.22,1,.36,1),box-shadow .45s,border-color .3s;overflow:hidden}
|
|
260
|
+
.galcard::before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--gc)}
|
|
261
|
+
.galcard:hover{transform:translateY(-4px);border-color:var(--gc);box-shadow:0 30px 60px -30px var(--gc)}
|
|
262
|
+
.gicon{font-size:24px}
|
|
263
|
+
.gtitle{font-size:15px;font-weight:800;color:#1a1b30;margin-top:7px;letter-spacing:-.2px}
|
|
264
|
+
.gsec{font-size:11px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:var(--gc);margin-top:2px}
|
|
265
|
+
.gknobs{font-size:12px;color:#6a6c84;margin-top:9px;line-height:1.5}
|
|
266
|
+
.grun{display:inline-block;margin-top:11px;font-size:12.5px;font-weight:800;color:#fff;background:var(--gc);padding:6px 13px;border-radius:9px}
|
|
267
|
+
/* Meli sits crisp on the panel — no blurred halo (keeps the sharp dark mascot) */
|
|
268
|
+
.herochar,.panel-art{position:relative}
|
|
269
|
+
.herochar>.meli,.panel-art>.meli{position:relative;z-index:1}
|
|
270
|
+
.herostats{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin:26px auto 0;max-width:760px}
|
|
271
|
+
.hstat{flex:1;min-width:148px;background:rgba(255,255,255,.7);backdrop-filter:blur(12px) saturate(1.2);border:1px solid #ecebf6;border-radius:16px;padding:15px 14px;box-shadow:0 1px 2px rgba(30,25,80,.04),0 18px 40px -32px rgba(70,55,160,.45);transition:transform .5s cubic-bezier(.22,1,.36,1)}
|
|
272
|
+
.hstat:hover{transform:translateY(-3px)}
|
|
273
|
+
.hsnum{font-size:26px;font-weight:800;letter-spacing:-.5px;background:linear-gradient(135deg,#6d5cf0,#0ea5b7);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;font-variant-numeric:tabular-nums}
|
|
274
|
+
.hslbl{font-size:12px;color:#6a6c84;margin-top:4px;line-height:1.35;font-weight:500}
|
|
275
|
+
.primegradtext{background:linear-gradient(135deg,#e11d48,#a855f7)!important;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
|
|
276
|
+
@keyframes branchGrow{to{stroke-dashoffset:0}}
|
|
277
|
+
@keyframes nodePop{to{opacity:1}}
|
|
278
|
+
@keyframes primeSpin{to{transform:rotate(1turn)}}
|
|
279
|
+
@keyframes primeShimmer{0%{background-position:-160% 0}100%{background-position:260% 0}}
|
|
280
|
+
@keyframes primeFloat{0%,100%{transform:translateY(0) rotate(45deg)}50%{transform:translateY(-4px) rotate(45deg)}}
|
|
281
|
+
@keyframes primeIn{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
|
|
282
|
+
.primewrap{position:relative;border-radius:26px;padding:0;animation:primeIn .7s cubic-bezier(.22,1,.36,1)}
|
|
283
|
+
.primeborder{position:absolute;inset:0;border-radius:26px;padding:1.5px;background:linear-gradient(135deg,#e11d48,#f43f8e 30%,#a855f7 58%,#6d5cf0 82%,#0ea5b7);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;z-index:2}
|
|
284
|
+
.primeinner{position:relative;z-index:3;background:#fff;border-radius:24px;padding:24px 26px;overflow:hidden}
|
|
285
|
+
.primegem{width:28px;height:28px;border-radius:6px;background:linear-gradient(135deg,#e11d48,#f43f8e 40%,#a855f7);box-shadow:0 6px 18px -4px rgba(225,29,72,.55),inset 0 1px 3px rgba(255,255,255,.7);transform:rotate(45deg)}
|
|
286
|
+
.primeglint{background:linear-gradient(110deg,transparent 30%,rgba(255,255,255,.85) 48%,transparent 66%);background-size:220% 100%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;animation:primeShimmer 5s linear infinite}
|
|
287
|
+
@media(prefers-reduced-motion:reduce){.primeglint,.primewrap{animation:none}}
|
|
288
|
+
@media(prefers-reduced-motion:reduce){[style*="branchGrow"]{stroke-dashoffset:0!important;animation:none!important}[style*="nodePop"]{opacity:1!important;animation:none!important}}
|
|
289
|
+
`;
|
|
290
|
+
/** Meli — Melete's original mascot: an antenna-topped discovery sprite (the glowing orb = "the next
|
|
291
|
+
* experiment to try"). 100% geometric SVG — no third-party / copyrighted art. Works in every browser +
|
|
292
|
+
* mobile (inline SVG + CSS animation, no libraries). */
|
|
293
|
+
function meli(cls = "") {
|
|
294
|
+
return `<svg class="meli ${cls}" viewBox="0 0 200 224" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Meli, the Melete mascot">
|
|
295
|
+
<defs>
|
|
296
|
+
<linearGradient id="mbody" x1="0.1" y1="0" x2="0.9" y2="1"><stop offset="0" stop-color="#7d6df6"/><stop offset="0.55" stop-color="#5b53e8"/><stop offset="1" stop-color="#0ea5b7"/></linearGradient>
|
|
297
|
+
<radialGradient id="mgloss" cx="0.36" cy="0.24" r="0.55"><stop offset="0" stop-color="#ffffff" stop-opacity="0.55"/><stop offset="1" stop-color="#ffffff" stop-opacity="0"/></radialGradient>
|
|
298
|
+
<radialGradient id="orbG" cx="0.4" cy="0.34" r="0.72"><stop offset="0" stop-color="#fffdf0"/><stop offset="0.5" stop-color="#fcd34d"/><stop offset="1" stop-color="#f59e0b"/></radialGradient>
|
|
299
|
+
<filter id="msoft" x="-40%" y="-40%" width="180%" height="180%"><feGaussianBlur stdDeviation="7"/></filter>
|
|
300
|
+
<filter id="mglow" x="-90%" y="-90%" width="280%" height="280%"><feGaussianBlur stdDeviation="5.5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
|
|
301
|
+
</defs>
|
|
302
|
+
<ellipse cx="100" cy="210" rx="56" ry="11" fill="#16172b" opacity="0.10"/>
|
|
303
|
+
<path class="ant" d="M104 70 C 120 44, 142 46, 148 22" stroke="#0ea5b7" stroke-width="5" fill="none" stroke-linecap="round"/>
|
|
304
|
+
<g class="orb" filter="url(#mglow)"><circle cx="150" cy="18" r="13" fill="url(#orbG)"/><circle cx="145" cy="13" r="3.4" fill="#fff" opacity="0.9"/></g>
|
|
305
|
+
<path class="spark s1" d="M172 34 l2.2 6.4 6.4 2.2 -6.4 2.2 -2.2 6.4 -2.2 -6.4 -6.4 -2.2 6.4 -2.2 z" fill="#fcd34d"/>
|
|
306
|
+
<path class="spark s2" d="M128 6 l1.6 4.6 4.6 1.6 -4.6 1.6 -1.6 4.6 -1.6 -4.6 -4.6 -1.6 4.6 -1.6 z" fill="#67e8f9"/>
|
|
307
|
+
<g filter="url(#msoft)" opacity="0.45"><path d="M100 60 C 148 60, 168 96, 166 130 C 164 170, 134 196, 100 196 C 66 196, 36 170, 34 130 C 32 96, 52 60, 100 60 Z" fill="#4338ca"/></g>
|
|
308
|
+
<ellipse cx="78" cy="196" rx="16" ry="9" fill="#4f46d6"/><ellipse cx="122" cy="196" rx="16" ry="9" fill="#4f46d6"/>
|
|
309
|
+
<ellipse class="arm" cx="162" cy="120" rx="11" ry="21" fill="url(#mbody)" transform="rotate(-30 162 120)"/>
|
|
310
|
+
<ellipse cx="38" cy="142" rx="11" ry="21" fill="url(#mbody)" transform="rotate(26 38 142)"/>
|
|
311
|
+
<path d="M100 54 C 150 54, 168 92, 166 128 C 164 168, 134 194, 100 194 C 66 194, 36 168, 34 128 C 32 92, 50 54, 100 54 Z" fill="url(#mbody)"/>
|
|
312
|
+
<ellipse cx="88" cy="116" rx="50" ry="46" fill="url(#mgloss)"/>
|
|
313
|
+
<ellipse cx="100" cy="152" rx="42" ry="34" fill="#ffffff" opacity="0.10"/>
|
|
314
|
+
<g class="eyes">
|
|
315
|
+
<ellipse cx="80" cy="120" rx="14.5" ry="16.5" fill="#fff"/><ellipse cx="120" cy="120" rx="14.5" ry="16.5" fill="#fff"/>
|
|
316
|
+
<circle cx="83" cy="124" r="7.2" fill="#1a1b30"/><circle cx="123" cy="124" r="7.2" fill="#1a1b30"/>
|
|
317
|
+
<circle cx="86" cy="120.5" r="2.7" fill="#fff"/><circle cx="126" cy="120.5" r="2.7" fill="#fff"/>
|
|
318
|
+
<circle cx="80" cy="127" r="1.4" fill="#fff" opacity="0.7"/><circle cx="120" cy="127" r="1.4" fill="#fff" opacity="0.7"/>
|
|
319
|
+
</g>
|
|
320
|
+
<path d="M84 146 Q100 160 116 146" stroke="#1a1b30" stroke-width="5" fill="none" stroke-linecap="round"/>
|
|
321
|
+
<ellipse cx="62" cy="140" rx="7.5" ry="4.6" fill="#ff8fb1" opacity="0.55"/><ellipse cx="138" cy="140" rx="7.5" ry="4.6" fill="#ff8fb1" opacity="0.55"/>
|
|
322
|
+
</svg>`;
|
|
323
|
+
}
|
|
324
|
+
/** The Wave-Particle map projection (shared, exact, with the client). Tested for accuracy in
|
|
325
|
+
* serverGauntlet: higher score rises, back rows sit higher, everything stays inside the 600×600 canvas. */
|
|
326
|
+
const VZ_C = { mL: 54, plotW: 486, mT: 130, depth: 250, skew: 44, h: 120 };
|
|
327
|
+
export function vizProject(gi, gj, t, nx, ny) {
|
|
328
|
+
const fx = nx > 1 ? gi / (nx - 1) : 0.5, fz = ny > 1 ? gj / (ny - 1) : 0.5;
|
|
329
|
+
return [VZ_C.mL + fx * VZ_C.plotW + fz * VZ_C.skew, VZ_C.mT + (1 - fz) * VZ_C.depth - t * VZ_C.h];
|
|
330
|
+
}
|
|
331
|
+
export function landingPage(version = "0.4.0") {
|
|
332
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
333
|
+
<title>Melete — find the best answer in the fewest experiments</title><style>${SHELL_CSS}
|
|
334
|
+
.aurora{position:fixed;top:0;left:0;right:0;height:3px;z-index:60;background:linear-gradient(90deg,#6d5cf0,#14b8a6,#6d5cf0,#a78bfa,#14b8a6);background-size:300% 100%;animation:auroraShift 9s linear infinite}
|
|
335
|
+
@keyframes auroraShift{0%{background-position:0% 50%}100%{background-position:300% 50%}}
|
|
336
|
+
@media (prefers-reduced-motion:reduce){.aurora{animation:none}}</style></head><body>
|
|
337
|
+
<div class="aurora"></div>
|
|
338
|
+
<div class="langsw"><button id="lang-en" class="lb on" onclick="setLang('en')">EN</button><button id="lang-th" class="lb" onclick="setLang('th')">ไทย</button></div>
|
|
339
|
+
|
|
340
|
+
<div class="cmodal" id="contactModal" onclick="if(event.target===this)hideContact()">
|
|
341
|
+
<div class="cbox">
|
|
342
|
+
<button class="cclose" onclick="hideContact()" aria-label="close">✕</button>
|
|
343
|
+
<div style="width:74px;margin:0 auto 4px">${meli()}</div>
|
|
344
|
+
<h3 style="text-align:center;margin:0 0 2px;font-size:21px">💬 Contact — Shinnapat <span class="muted" style="font-weight:500">(Melete)</span></h3>
|
|
345
|
+
<p class="muted" style="text-align:center;margin:0 0 16px;font-size:14px">Licensing · acquisition · questions · 🇹🇭 Thailand-based</p>
|
|
346
|
+
<table class="ctab">
|
|
347
|
+
<tr><td>📧 Email</td><td><a href="mailto:patsa2561@gmail.com">patsa2561@gmail.com</a></td></tr>
|
|
348
|
+
<tr><td>🟢 WhatsApp <span class="thtag">Thailand ☎</span></td><td><a href="https://wa.me/66939455645">+66 93 945 5645</a></td></tr>
|
|
349
|
+
<tr><td>✈️ Telegram</td><td><a href="https://t.me/devson2561">@devson2561</a></td></tr>
|
|
350
|
+
<tr><td>💬 Discord</td><td>pat195 <span class="muted">(shinnapat)</span></td></tr>
|
|
351
|
+
<tr><td>🐙 GitHub</td><td><a href="https://github.com/patsa2561-art">@patsa2561-art</a></td></tr>
|
|
352
|
+
<tr><td>📦 npm</td><td><a href="https://www.npmjs.com/~mneme_npm">@mneme_npm</a></td></tr>
|
|
353
|
+
</table>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<div class="hero">
|
|
358
|
+
<div class="herochar">${meli("hero")}</div>
|
|
359
|
+
<span class="eyebrow" data-i18n="eyebrow">The Sovereign Verifiable AI Analyst & Optimizer</span>
|
|
360
|
+
<h1 class="brand"><span class="grad">Melete</span></h1>
|
|
361
|
+
<p class="tag" data-i18n="heroTag">Tell Melete what you can change and what <b>"good"</b> means. It finds the <b>best recipe in the fewest real-world experiments</b> — then tells you exactly what to do with it.</p>
|
|
362
|
+
<p class="sub" data-i18n="heroSub">Analyze · optimize · certify — on your machine (sovereign), data never leaves, every verdict cryptographically signed & verifiable offline.</p><p class="sub" style="margin-top:-18px">v${version}</p>
|
|
363
|
+
<div class="cta">
|
|
364
|
+
<a class="btn primary" data-i18n="ctaTry" href="#try">See it discover (live) →</a>
|
|
365
|
+
<a class="btn ghost" data-i18n="ctaPitch" href="/pitch">The 60-second pitch</a>
|
|
366
|
+
<a class="btn ghost" data-i18n="ctaApi" href="/docs" target="_blank" rel="noopener">🔌 Connect via API</a>
|
|
367
|
+
</div>
|
|
368
|
+
<div class="pills">
|
|
369
|
+
<span class="pill" data-i18n="pill1">🎯 best answer, fewest tries</span>
|
|
370
|
+
<span class="pill" data-i18n="pill2">🚀 no data needed — starts from scratch</span>
|
|
371
|
+
<span class="pill" data-i18n="pill3">🔒 runs on your machine</span>
|
|
372
|
+
<span class="pill" data-i18n="pill4">🔏 every answer signed</span>
|
|
373
|
+
</div>
|
|
374
|
+
<div class="herostats">
|
|
375
|
+
<div class="hstat"><div class="hsnum">39</div><div class="hslbl" data-i18n="hs1">verified engines</div></div>
|
|
376
|
+
<div class="hstat"><div class="hsnum">≥99%</div><div class="hslbl" data-i18n="hs2">of the true optimum, every benchmark</div></div>
|
|
377
|
+
<div class="hstat"><div class="hsnum">100%</div><div class="hslbl" data-i18n="hs3">on your machine · signed</div></div>
|
|
378
|
+
<div class="hstat"><div class="hsnum primegradtext">◆ Φ</div><div class="hslbl" data-i18n="hs4">one brain, smart about everything</div></div>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<div class="wrap">
|
|
383
|
+
|
|
384
|
+
<section id="sixty" style="margin-top:8px">
|
|
385
|
+
<div class="eyebrow" data-i18n="m60_eye">Understand the whole thing in 60 seconds</div>
|
|
386
|
+
<h2 data-i18n="m60_h">What Melete is — in one minute</h2>
|
|
387
|
+
<p style="max-width:760px;color:#475;font-size:16px;line-height:1.6" data-i18n="m60_p">You have a system you can <b>measure</b> — an ML pipeline, a server/DB/network config, a recipe, a simulation. Melete finds the best <b>and most robust</b> setting in the fewest experiments, explains why in plain language, and hands you a <b>signed verdict you (or an auditor) can re-verify offline</b>. It runs on your machine — your data never leaves.</p>
|
|
388
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:13px;margin:20px 0 8px">
|
|
389
|
+
<div class="m60card"><div class="m60n">1</div><div class="m60t" data-i18n="m60_s1"><b>Tell it</b> what you can change + what "good" means</div></div>
|
|
390
|
+
<div class="m60card"><div class="m60n">2</div><div class="m60t" data-i18n="m60_s2"><b>It proposes</b> a setting → you measure it (or give a formula) → repeat</div></div>
|
|
391
|
+
<div class="m60card"><div class="m60n">3</div><div class="m60t" data-i18n="m60_s3"><b>You get</b> the best robust recipe + a signed, replayable verdict</div></div>
|
|
392
|
+
</div>
|
|
393
|
+
<div style="margin-top:18px;padding:18px 20px;background:rgba(255,255,255,.7);backdrop-filter:blur(12px);border:1px solid #ecebf6;border-radius:18px;box-shadow:0 18px 44px -34px rgba(70,55,160,.4)">
|
|
394
|
+
<div style="font-size:12px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#8890a8;margin-bottom:10px" data-i18n="m60_inside">Inside: 43 engines, organized as 4 layers</div>
|
|
395
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px">
|
|
396
|
+
<div class="laycard"><span class="layi">🔍</span><div><b>DISCOVER</b><div class="laysub" data-i18n="lay1">find the best setting in the fewest tries</div></div></div>
|
|
397
|
+
<div class="laycard"><span class="layi">◆</span><div><b>DECIDE</b><div class="laysub" data-i18n="lay2">the Φ brain's safety-first call + 🛡 the robust one</div></div></div>
|
|
398
|
+
<div class="laycard"><span class="layi">🔬</span><div><b>DIAGNOSE</b><div class="laysub" data-i18n="lay3">plain-language why: which knobs, cliffs, shape, ceiling</div></div></div>
|
|
399
|
+
<div class="laycard"><span class="layi">👑</span><div><b>CERTIFY</b><div class="laysub" data-i18n="lay4">signed, offline-verifiable, step-by-step replayable</div></div></div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</section>
|
|
403
|
+
|
|
404
|
+
<section id="gallery" style="margin-top:26px">
|
|
405
|
+
<div class="eyebrow" data-i18n="gal_eye">Live demo — pick your world, press one button</div>
|
|
406
|
+
<h2 data-i18n="gal_h">See Melete run on YOUR industry</h2>
|
|
407
|
+
<p style="max-width:760px;color:#475;font-size:15.5px;line-height:1.6" data-i18n="gal_p">Each card runs the <b>real Melete engine</b> on a simulated, industry-shaped problem — then sums up the result in plain language (every number is from the real run). In production you connect your own system as the oracle.</p>
|
|
408
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-top:18px">
|
|
409
|
+
<div class="galcard" onclick="gVertical('aerospace')" style="--gc:#22d3ee"><div class="gicon">📡</div><div class="gtitle">Deep-Space Satellite Comms</div><div class="gsec">Aerospace · SpaceX/NASA-class</div><div class="gknobs">freq · phase-array · packet depth → throughput under solar storms</div><div class="grun">▶ run live</div></div>
|
|
410
|
+
<div class="galcard" onclick="gVertical('genomics')" style="--gc:#a855f7"><div class="gicon">💊</div><div class="gtitle">Precision Drug Formulation</div><div class="gsec">Pharma · Genomics</div><div class="gknobs">pH · incubation · genome target → bioavailability − toxicity</div><div class="grun">▶ run live</div></div>
|
|
411
|
+
<div class="galcard" onclick="gVertical('ml')" style="--gc:#6d5cf0"><div class="gicon">🧠</div><div class="gtitle">Air-Gapped LLM Tuning</div><div class="gsec">Banking / Gov</div><div class="gknobs">learning-rate · quantization · RAG chunk → tokens/s, safety, −GPU cost</div><div class="grun">▶ run live</div></div>
|
|
412
|
+
<div class="galcard" onclick="gVertical('database')" style="--gc:#10b981"><div class="gicon">💾</div><div class="gtitle">DB & Kernel Cost-Cut</div><div class="gsec">Cloud infra</div><div class="gknobs">TCP buffer · thread affinity · shared buffers → −latency, −cloud $</div><div class="grun">▶ run live</div></div>
|
|
413
|
+
<div class="galcard" onclick="gVertical('solar')" style="--gc:#f59e0b"><div class="gicon">☀️</div><div class="gtitle">Solar Grid & Micro-Inverter</div><div class="gsec">Energy · IoT</div><div class="gknobs">MPPT freq · charge rate · PV tilt → power, −inverter heat</div><div class="grun">▶ run live</div></div>
|
|
414
|
+
<div class="galcard" onclick="gVertical('devops')" style="--gc:#ef4444"><div class="gicon">🛡️</div><div class="gtitle">DevOps Compliance Guardrail</div><div class="gsec">Security</div><div class="gknobs">IAM TTL · firewall · payload size → attack-block %, −friction</div><div class="grun">▶ run live</div></div>
|
|
415
|
+
</div>
|
|
416
|
+
<p class="muted" style="font-size:11.5px;margin-top:12px" data-i18n="gal_note">⚠ Simulated environments (real engine, real signed verdict). No live link to any satellite/grid — connect your own telemetry as the oracle in production.</p>
|
|
417
|
+
</section>
|
|
418
|
+
|
|
419
|
+
<section id="flab" style="margin-top:30px">
|
|
420
|
+
<div class="eyebrow" data-i18n="flabEye">FRONTIER LAB · DEEP-TECH, PROVEN</div>
|
|
421
|
+
<h2 data-i18n="flabH">The 3 ways optimizers die in the real world — engineered out, every one proven</h2>
|
|
422
|
+
<p style="max-width:780px;color:#475;font-size:15.5px;line-height:1.6" data-i18n="flabP">Each button runs the REAL Melete engine via the on-box API. Numbers are live, not canned. Press one.</p>
|
|
423
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px;margin-top:18px">
|
|
424
|
+
<div class="galcard" onclick="gFLab('noise')" style="--gc:#22d3ee"><div class="gtitle" data-i18n="flabNoiseT">📡 Noise-Robust</div><div class="gknobs" data-i18n="flabNoiseD">A noisy signal that reads 99% then 40% — find the value you can TRUST, not a lucky spike.</div><div class="grun" data-i18n="flabRun">▶ run live</div></div>
|
|
425
|
+
<div class="galcard" onclick="gFLab('mixed')" style="--gc:#a855f7"><div class="gtitle" data-i18n="flabMixedT">🧩 Mixed-Space</div><div class="gknobs" data-i18n="flabMixedD">Categorical + integer + conditional knobs (storage engine, thread count) — not just dials.</div><div class="grun" data-i18n="flabRun">▶ run live</div></div>
|
|
426
|
+
<div class="galcard" onclick="gFLab('prov')" style="--gc:#34d399"><div class="gtitle" data-i18n="flabProvT">📜 Provenance Seal</div><div class="gknobs" data-i18n="flabProvD">A 24/7 run history sealed into a constant-size, signed, tamper-evident proof.</div><div class="grun" data-i18n="flabRun">▶ run live</div></div>
|
|
427
|
+
</div>
|
|
428
|
+
<div id="flabout" style="margin-top:16px"></div>
|
|
429
|
+
<div style="margin-top:20px;background:linear-gradient(135deg,#f3f1ff,#eafcf8);border:1px solid #ddd9fb;border-radius:18px;padding:22px 24px">
|
|
430
|
+
<div class="eyebrow" data-i18n="flabUseEye">USE IT ON YOUR OWN SYSTEM</div>
|
|
431
|
+
<h3 style="font-size:19px;margin:4px 0 12px;color:#1a1b30" data-i18n="flabUseH">These demos used a formula. On your machine, the “oracle” is YOUR real measurement.</h3>
|
|
432
|
+
<div style="font-size:14px;color:#33344e;line-height:1.85;max-width:820px">
|
|
433
|
+
<div data-i18n="flabUse1">① Define your knobs (the settings you can change) + your score (what you measure — a yield %, a latency, a benchmark, an assay readout).</div>
|
|
434
|
+
<div data-i18n="flabUse2">② Point the oracle at YOUR system — a function that runs your real process / calls your API / reads your instrument and returns that score. The same proven engine searches it.</div>
|
|
435
|
+
<div data-i18n="flabUse3">③ Runs fully on your machine (sovereign — your data never leaves); every result is Ed25519-signed for your audit / patent trail.</div>
|
|
436
|
+
</div>
|
|
437
|
+
<div style="font-size:12.5px;color:#6a6c84;margin:14px 0 6px;font-weight:600" data-i18n="flabUseCap">Self-host the same engine (npm) and plug in your real measurement:</div>
|
|
438
|
+
<pre style="margin:0;background:#0a0c18;color:#cdd6ee;border:1px solid #1d2740;border-radius:13px;padding:15px 17px;font-size:12.5px;line-height:1.6;overflow-x:auto;font-family:ui-monospace,Menlo,monospace">npm i melete-ai
|
|
439
|
+
|
|
440
|
+
import { mixedDiscover } from "melete-ai";
|
|
441
|
+
|
|
442
|
+
const result = mixedDiscover({
|
|
443
|
+
space: [ /* your knobs: real | int | categorical, + conditional */ ],
|
|
444
|
+
oracle: (cfg) => measureYourRealSystem(cfg), // ← your benchmark / assay / API call
|
|
445
|
+
budget: 300, goal: "maximize",
|
|
446
|
+
});
|
|
447
|
+
console.log(result.best); // the best configuration, in the fewest real runs
|
|
448
|
+
// also: noiseRobustDiscover (noisy oracle) · buildCheckpoint (signed O(1) provenance)</pre>
|
|
449
|
+
<div style="font-size:12px;color:#8890a8;margin-top:9px" data-i18n="flabUseApi">…or POST a JS-expression objective to the hosted API for a quick formula test: /discover · /mixed · /noise-robust</div>
|
|
450
|
+
<div style="margin-top:14px"><button class="btn primary" onclick="showContact()">📩 <span data-i18n="btn_contact">Contact about Melete</span></button> <a class="btn ghost" href="/docs" target="_blank" rel="noopener">API docs</a></div>
|
|
451
|
+
</div>
|
|
452
|
+
</section>
|
|
453
|
+
<script>
|
|
454
|
+
function flabShell(col,title,sub,bodyHtml,foot){var th=(LANG==='th');return '<div class="cmdcenter" style="--cc:'+col+';border:1px solid '+col+'55;box-shadow:0 26px 60px -30px '+col+'66, inset 0 0 70px '+col+'0c"><span class="ccbrk tl"></span><span class="ccbrk tr"></span><span class="ccbrk bl"></span><span class="ccbrk br"></span><div class="cchead"><span class="ccrec"></span><span style="font-size:13px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:'+col+'">'+title+'</span><span style="font-size:12px;color:#cdd6ee;font-weight:700">'+sub+'</span></div>'+bodyHtml+'<div style="margin-top:11px;padding-top:10px;border-top:1px solid #ffffff14;font-size:11px;color:#8a98b8">'+foot+'</div></div>';}
|
|
455
|
+
function flabBar(label,frac,col,rightTxt){var w=Math.max(2,Math.min(100,Math.round(frac*100)));return '<div style="margin:6px 0"><div style="display:flex;justify-content:space-between;font-size:11.5px;margin-bottom:3px"><span style="color:#cdd6ee">'+label+'</span><span style="color:#8a98b8;font-variant-numeric:tabular-nums">'+(rightTxt||'')+'</span></div><div style="height:6px;border-radius:9px;background:rgba(255,255,255,.07);overflow:hidden"><div style="height:100%;width:'+w+'%;border-radius:9px;background:linear-gradient(90deg,'+col+'55,'+col+');box-shadow:0 0 9px '+col+'aa"></div></div></div>';}
|
|
456
|
+
function gFLab(which){var out=document.getElementById('flabout');var th=(LANG==='th');if(out)out.innerHTML='<div class="muted" style="font-size:13px">▶ '+(th?'กำลังรัน engine จริง…':'running the real engine…')+'</div>';if(out&&out.scrollIntoView)setTimeout(function(){out.scrollIntoView({behavior:'smooth',block:'center'});},150);
|
|
457
|
+
var url,body;
|
|
458
|
+
if(which==='noise'){url='/noise-robust';body={space:[{name:'x',type:'real',min:0,max:1},{name:'y',type:'real',min:0,max:1}],objective:'100*Math.exp(-(((x-0.3)**2)+((y-0.3)**2))/0.05)',budget:110,noise:35,seed:3};}
|
|
459
|
+
else if(which==='mixed'){url='/mixed';body={space:[{name:'engine',type:'categorical',choices:['A','B','C']},{name:'x',type:'real',min:0,max:1},{name:'n',type:'int',min:3,max:7},{name:'tune',type:'real',min:0,max:1,activeWhen:{dim:'engine',equals:'B'}}],objective:'(engine===\\'B\\'?1.0:(engine===\\'C\\'?0.71:0.62))*Math.exp(-(((x-0.7)**2)/0.04))*Math.exp(-(((n-5)**2)/6))*(engine===\\'B\\'?Math.exp(-(((tune-0.3)**2)/0.05)):1)*100',budget:500,seed:1};}
|
|
460
|
+
else{url='/provenance';body={count:20000,windowSize:50};}
|
|
461
|
+
fetch(url,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(body)}).then(function(r){return r.json();}).then(function(j){if(j.error){if(out)out.innerHTML='<div style="color:#c33;font-size:13px">⚠ '+j.error+'</div>';return;}if(which==='noise')flabNoise(j);else if(which==='mixed')flabMixed(j);else flabProv(j);}).catch(function(e){if(out)out.innerHTML='<div style="color:#c33;font-size:13px">⚠ '+e.message+'</div>';});}
|
|
462
|
+
function flabNoise(j){var th=(LANG==='th');var col='#22d3ee';var rec=Object.keys(j.best.experiment).map(function(k){return k+'='+(+j.best.experiment[k]).toFixed(2);}).join(' · ');
|
|
463
|
+
var pts=(j.points||[]).slice(0,5);var mx=1;pts.forEach(function(p){if(Math.abs(p.mean)>mx)mx=Math.abs(p.mean);});
|
|
464
|
+
var bars=pts.map(function(p){var rc=Object.keys(p.experiment).map(function(k){return (+p.experiment[k]).toFixed(2);}).join(',');return flabBar('('+rc+')',Math.abs(p.mean)/mx,col,'μ '+p.mean+' ± '+p.std+' · n'+p.n);}).join('');
|
|
465
|
+
var body='<div class="ccgrid"><div>'
|
|
466
|
+
+'<div style="display:flex;align-items:baseline;gap:9px;margin:6px 2px"><span style="font-size:30px;font-weight:800;color:'+col+';text-shadow:0 0 16px '+col+'88">'+(+j.bestMean).toFixed(1)+'</span><span style="font-size:12px;color:#8a98b8">'+(th?'ค่าเฉลี่ยที่เชื่อถือได้ ± ':'trustworthy mean ± ')+j.bestStd+' (n='+j.bestN+')</span></div>'
|
|
467
|
+
+'<div style="font-size:13px;color:#cdd6ee;margin:2px 2px 6px">'+(th?'สูตร: ':'recipe: ')+'<b style="color:#e6edff">'+rec+'</b></div>'
|
|
468
|
+
+'<div style="font-size:12px;color:#8a98b8;margin:2px 2px">'+(th?'ขอบล่างที่มั่นใจ (LCB) ':'lower-confidence bound ')+'<b style="color:'+col+'">'+(+j.bestLcb).toFixed(1)+'</b></div>'
|
|
469
|
+
+'<div style="margin-top:10px;padding:10px 12px;border-radius:11px;background:rgba(251,191,36,.08);border:1px solid #fbbf2455"><div style="font-size:12px;color:#fbbf24;font-weight:700">'+(th?'❌ ปฏิเสธค่าฟลุค':'❌ rejected the lucky spike')+'</div><div style="font-size:12.5px;color:#cdd6ee;margin-top:3px">'+(th?'optimizer ทั่วไปจะรายงาน ':'a naive optimizer would report ')+'<b>'+(+j.luckyMax.value).toFixed(1)+'</b> '+(th?'(ค่าที่ฟลุคอ่านสูงครั้งเดียว) — Melete กรองทิ้งเพราะแกว่งเกินไป':'(one lucky high reading) — Melete filtered it as noise')+'</div></div></div>'
|
|
470
|
+
+'<div><div class="cccore-h" style="margin-top:0">'+(th?'จุดที่วัด (เรียงตามค่าที่เชื่อถือได้)':'measured points (by trustworthy value)')+'</div>'+bars+'</div></div>';
|
|
471
|
+
document.getElementById('flabout').innerHTML=flabShell(col,(th?'มอนิเตอร์ความทนทาน · #2':'LIVE ROBUSTNESS MONITOR · #2'),(th?'ทนสัญญาณรบกวน':'noise-robust'),body,(th?'noise σ='+j.noise+' · '+j.evaluations+' การวัด (วัดซ้ำ) · เลือกด้วย lower-confidence-bound — ของจริงจาก /noise-robust':'noise σ='+j.noise+' · '+j.evaluations+' measurements (replicated) · selected by lower-confidence-bound — live from /noise-robust'));}
|
|
472
|
+
function flabMixed(j){var th=(LANG==='th');var col='#a855f7';var rec=Object.keys(j.best.experiment).map(function(k){var v=j.best.experiment[k];return k+'='+(typeof v==='number'?(+v).toFixed(2):v);}).join(' · ');
|
|
473
|
+
var lb=(j.byCombo||[]).slice(0,6);var mx=1;lb.forEach(function(c){if(Math.abs(c.value)>mx)mx=Math.abs(c.value);});
|
|
474
|
+
var rows=lb.map(function(c,i){var combo=Object.keys(c.combo).map(function(k){return k+'='+c.combo[k];}).join(' · ');return flabBar((i+1)+'. '+combo,Math.abs(c.value)/mx,col,(+c.value).toFixed(1));}).join('');
|
|
475
|
+
var body='<div class="ccgrid"><div>'
|
|
476
|
+
+'<div style="display:flex;align-items:baseline;gap:9px;margin:6px 2px"><span style="font-size:30px;font-weight:800;color:'+col+';text-shadow:0 0 16px '+col+'88">'+(+j.best.value).toFixed(1)+'</span><span style="font-size:12px;color:#8a98b8">'+(th?'คะแนนของสูตรที่ชนะ':'winning configuration score')+'</span></div>'
|
|
477
|
+
+'<div style="font-size:13px;color:#cdd6ee;margin:2px 2px">'+(th?'สูตร: ':'recipe: ')+'<b style="color:#e6edff">'+rec+'</b></div>'
|
|
478
|
+
+'<div style="font-size:12px;color:#8a98b8;margin:8px 2px">'+(th?'ชนะ category: ':'winning category: ')+'<b style="color:'+col+'">'+Object.keys(j.bestCombo).map(function(k){return k+'='+j.bestCombo[k];}).join(' · ')+'</b></div></div>'
|
|
479
|
+
+'<div><div class="cccore-h" style="margin-top:0">'+(th?'กระดานแข่ง — '+j.comboCount+' การจัดวางที่แข่งกัน':'leaderboard — '+j.comboCount+' configurations competed')+'</div>'+rows+'</div></div>';
|
|
480
|
+
document.getElementById('flabout').innerHTML=flabShell(col,(th?'สนามตัวแปรผสม · #1':'MIXED ARENA · #1'),(th?'categorical + integer + conditional':'categorical + integer + conditional'),body,(th?j.comboCount+' combos'+(j.sampledCombos?' (สุ่ม)':' (ครบ)')+' · '+j.evaluations+' การทดลอง · ของจริงจาก /mixed':j.comboCount+' combos'+(j.sampledCombos?' (sampled)':' (enumerated)')+' · '+j.evaluations+' experiments · live from /mixed'));}
|
|
481
|
+
function flabProv(j){var th=(LANG==='th');var col='#34d399';
|
|
482
|
+
var seal='<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:8px"><svg viewBox="0 0 120 120" style="width:120px;height:120px"><circle cx="60" cy="60" r="50" fill="none" stroke="'+col+'" stroke-width="3" opacity="0.5"><animate attributeName="r" values="46;52;46" dur="3s" repeatCount="indefinite"/></circle><circle cx="60" cy="60" r="38" fill="'+col+'18" stroke="'+col+'" stroke-width="2"/><text x="60" y="56" text-anchor="middle" font-size="26" fill="'+col+'">🔏</text><text x="60" y="80" text-anchor="middle" font-size="11" font-weight="800" fill="'+col+'" font-family="ui-monospace,Menlo,monospace">SEALED</text></svg></div>';
|
|
483
|
+
var body='<div class="ccgrid"><div>'+seal+'</div><div>'
|
|
484
|
+
+'<div style="display:flex;align-items:baseline;gap:9px;margin:6px 2px"><span style="font-size:30px;font-weight:800;color:'+col+';text-shadow:0 0 16px '+col+'88">'+(+j.count).toLocaleString()+'</span><span style="font-size:12px;color:#8a98b8">'+(th?'เหตุการณ์ → ':'events → ')+'<b style="color:'+col+'">'+(+j.sizeBytes).toLocaleString()+' B</b> '+(th?'(ขนาดคงที่ O(1))':'(constant size · O(1))')+'</span></div>'
|
|
485
|
+
+'<div style="font-size:11.5px;color:#8a98b8;font-family:ui-monospace,Menlo,monospace;margin:4px 2px 10px;overflow-wrap:anywhere">root '+String(j.foldedRoot).slice(0,32)+'…</div>'
|
|
486
|
+
+'<div style="display:flex;flex-direction:column;gap:6px">'
|
|
487
|
+
+'<div style="font-size:13px;color:'+(j.signatureValid?'#34d399':'#fbbf24')+'">'+(j.signatureValid?'✓ ':'… ')+(th?'ลายเซ็น Ed25519 ตรวจ offline ผ่าน':'Ed25519 signature verifies offline')+'</div>'
|
|
488
|
+
+'<div style="font-size:13px;color:'+(j.intactVerifies?'#34d399':'#fbbf24')+'">'+(j.intactVerifies?'✓ ':'… ')+(th?'ประวัติครบถ้วน ตรวจกับสตรีมจริงผ่าน':'full history re-verifies against the stream')+'</div>'
|
|
489
|
+
+'<div style="font-size:13px;color:'+(j.tamperDetected?'#34d399':'#c0392b')+'">'+(j.tamperDetected?'✓ ':'✗ ')+(th?'แก้เหตุการณ์เก่าแม้จุดเดียว → จับได้':'altering ANY past event → DETECTED')+'</div></div></div></div>';
|
|
490
|
+
document.getElementById('flabout').innerHTML=flabShell(col,(th?'ตราผนึกประวัติ · #3':'PROVENANCE SEAL · #3'),(th?'หลักฐานขนาดคงที่ แก้ไม่ได้':'constant-size tamper-evident proof'),body,(th?'hash-chain + sliding window + Ed25519 · '+j.algo+' · ของจริงจาก /provenance':'hash-chain + sliding window + Ed25519 · '+j.algo+' · live from /provenance'));}
|
|
491
|
+
</script>
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
<section><h2 data-i18n="h_what">What it does — one example</h2>
|
|
495
|
+
<div class="story" data-i18n="story">
|
|
496
|
+
<p style="font-size:19px;font-weight:600;color:#1a1b30;margin-bottom:14px">You run a coffee shop and want the <b>best espresso</b>. You can change three things — water temperature, grind, and how many grams of coffee. There are thousands of combinations, and testing one means <b>brewing a cup and tasting it</b>. You can't try them all.</p>
|
|
497
|
+
<p style="color:#33344e;margin-bottom:6px">Melete works like a brilliant assistant who suggests the next cup to brew:</p>
|
|
498
|
+
<div class="chat">☕ Melete: “Try <b>92°, grind 6, 18g</b>.” → you brew it, taste it: <b>7/10</b>.</div>
|
|
499
|
+
<div class="chat">☕ Melete: “Now try <b>93°, grind 5, 19g</b>.” → you taste: <b>8.5/10</b>.</div>
|
|
500
|
+
<div class="chat" style="opacity:.6">… a few more …</div>
|
|
501
|
+
<div class="chat">🎯 After ~<b>20 cups</b>, it found your best recipe — instead of randomly trying 200.</div>
|
|
502
|
+
<p style="color:#33344e;margin-top:14px">Swap “coffee” for a <b>training run</b>, a <b>chemical reaction</b>, or a <b>price</b> — it's the same: Melete finds the best settings in the <b>fewest expensive tries</b>, and signs a <b>proof</b> of how it got there. <span class="muted">You bring the thing you can adjust and a way to score one try; it brings the strategy.</span></p>
|
|
503
|
+
</div></section>
|
|
504
|
+
|
|
505
|
+
<section><h2 data-i18n="h_meli">Meet Meli — a tiny story</h2>
|
|
506
|
+
<div class="storybook">
|
|
507
|
+
|
|
508
|
+
<div class="panel wish" data-beat>
|
|
509
|
+
<div class="panel-art">${meli()}<span class="prop hearts">💛</span></div>
|
|
510
|
+
<div class="panel-text"><span class="beatnum">1</span>
|
|
511
|
+
<p data-i18n="sb1">Once upon a time, a little coffee shop wished for the <b>most delicious espresso in the world</b>.</p></div>
|
|
512
|
+
</div>
|
|
513
|
+
|
|
514
|
+
<div class="panel maze" data-beat>
|
|
515
|
+
<div class="panel-art">${meli()}<span class="prop cups">☕☕☕<br>☕☕☕</span></div>
|
|
516
|
+
<div class="panel-text"><span class="beatnum">2</span>
|
|
517
|
+
<p data-i18n="sb2">But there were <b>thousands of ways</b> to make it — and every single test meant brewing, and tasting, a whole cup. Trying them all? <b>Impossible.</b></p></div>
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
<div class="panel think" data-beat>
|
|
521
|
+
<div class="panel-art">${meli()}<span class="prop bubble">brew <b>this</b> one →</span></div>
|
|
522
|
+
<div class="panel-text"><span class="beatnum">3</span>
|
|
523
|
+
<p data-i18n="sb3">Then came <b>Meli</b> — who never tries everything. Meli looks, thinks, and the little light glows: <i>“brew <b>this</b> one next.”</i></p></div>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div class="panel dance" data-beat>
|
|
527
|
+
<div class="panel-art">${meli()}<span class="prop cup">☕<span class="score">7 → 8.5 → 9.2</span></span></div>
|
|
528
|
+
<div class="panel-text"><span class="beatnum">4</span>
|
|
529
|
+
<p data-i18n="sb4">You brew it, you taste it — <b>7 out of 10</b>. Meli smiles, <b>learns</b>, and picks an even smarter cup. 8.5… 9.2…</p></div>
|
|
530
|
+
</div>
|
|
531
|
+
|
|
532
|
+
<div class="panel win" data-beat>
|
|
533
|
+
<div class="panel-art">${meli()}<span class="prop star">⭐</span><span class="prop seal">📜 verified ✓</span></div>
|
|
534
|
+
<div class="panel-text"><span class="beatnum">5</span>
|
|
535
|
+
<p data-i18n="sb5">In about <b>twenty cups</b>, Meli found the <b>perfect recipe</b> — and sealed a magical <b>proof</b> of how, so the whole world could trust it. <b>The end ✨</b></p>
|
|
536
|
+
<a class="btn primary" href="#try" style="margin-top:14px;display:inline-block">▶ Now watch Meli do it for real</a></div>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
</div></section>
|
|
540
|
+
|
|
541
|
+
<section style="display:none"><h2 data-i18n="h_how">How it works — 3 steps</h2>
|
|
542
|
+
<div class="steps">
|
|
543
|
+
<div class="step"><span class="n">1</span><h3 data-i18n="st1h">Set the dials</h3><p data-i18n="st1p">List what you can change and its range — temperature 85–96°, learning-rate 0–0.1, price $1–100.</p></div>
|
|
544
|
+
<div class="step"><span class="n">2</span><h3 data-i18n="st2h">Score one try</h3><p data-i18n="st2p">Your real process returns one number: brew → taste, train → accuracy, price → revenue. No dataset needed.</p></div>
|
|
545
|
+
<div class="step"><span class="n">3</span><h3 data-i18n="st3h">Discover & prove</h3><p data-i18n="st3p">Melete proposes the next experiment, learns, converges to the best — and signs a verifiable trace of how.</p></div>
|
|
546
|
+
</div></section>
|
|
547
|
+
|
|
548
|
+
<section><h2 data-i18n="h_who">Who it's for & what they get</h2>
|
|
549
|
+
<div class="grid">
|
|
550
|
+
<div class="card"><div class="who">AI / ML teams</div><h3>Hyperparameter & system tuning</h3><p data-i18n="wh1">Tune learning rates, architectures, RAG/serving configs, compiler flags — fewer GPU-hours to the best model, with a provable tuning record.</p></div>
|
|
551
|
+
<div class="card"><div class="who">Pharma · Chemistry · Materials</div><h3>Formulation & reaction discovery</h3><p data-i18n="wh2">Find the reagent mix / conditions that maximise yield or potency in far fewer assays — and a tamper-proof discovery trail for patents & audits.</p></div>
|
|
552
|
+
<div class="card"><div class="who">Semiconductor · Manufacturing</div><h3>Process optimisation</h3><p data-i18n="wh3">Tune deposition / etch / print parameters against real KPIs on-prem — air-gapped, data never leaves the fab, result still verifiable.</p></div>
|
|
553
|
+
<div class="card"><div class="who">Quant · Product · Growth</div><h3>Pricing & expensive A/B</h3><p data-i18n="wh4">Search price points, configurations, and policies where each test is costly — converge faster than grid or manual search.</p></div>
|
|
554
|
+
</div>
|
|
555
|
+
<p class="muted" style="margin-top:16px">Every case: <b>fewer expensive experiments</b> to the best answer + a <b>cryptographic proof</b> of how it was found.</p></section>
|
|
556
|
+
|
|
557
|
+
<section id="try"><h2 data-i18n="h_see">See it discover — just watch</h2>
|
|
558
|
+
<div id="nfbanner" style="background:linear-gradient(120deg,#f3f1ff,#eafcf8);border:1px solid #e0dbf3;border-radius:16px;padding:18px;margin:14px 0;display:flex;gap:16px;align-items:center;flex-wrap:wrap"><div style="flex:1;min-width:240px;font-size:14px;color:#33344e;line-height:1.55"><b data-i18n="nf_h">Use it on your real process — no formula, no code.</b><br><span data-i18n="nf_sub">The demo below needs a formula (for developers). To use Melete on your real process with no formula — it proposes, you measure, you type the score — use the guided mode.</span></div><button class="btn primary" onclick="gotoGuide()" data-i18n="nf_btn">👉 Use the no-formula mode</button></div>
|
|
559
|
+
<p class="lead" style="font-size:18px;margin:0 0 4px" data-i18n="see_lead">👇 Just press the purple button and watch. Melete tests settings one by one and zeroes in on the best — like the coffee story above, but live.</p>
|
|
560
|
+
<p class="muted" style="margin:0 0 16px" data-i18n="see_sub">This is a demo, so the "score" is calculated instantly by a formula. In real life, the score is whatever YOU measure (a taste rating, a yield %, a benchmark) — and you type it in. <a href="#use">How to use it for your own work →</a></p>
|
|
561
|
+
<div class="card">
|
|
562
|
+
<div class="modetabs"><button class="mt on" id="mt-simple" onclick="setMode('simple')">🟢 Simple — pick & watch</button><button class="mt" id="mt-advanced" onclick="setMode('advanced')">⚙️ Advanced — edit the values</button></div>
|
|
563
|
+
<label data-i18n="scenarioL">Scenario</label>
|
|
564
|
+
<select id="preset" onchange="loadPreset()">
|
|
565
|
+
<option value="coffee">☕ Best espresso recipe — temperature · grind · dose</option>
|
|
566
|
+
<option value="price">💸 Best price point — which price earns the most</option>
|
|
567
|
+
<option value="pharma">💊 Drug formulation — pH · temperature · excipient → stability</option>
|
|
568
|
+
<option value="peak">📈 Find a hidden peak — the simplest demo (2 knobs)</option>
|
|
569
|
+
<option value="etch">🔬 Semiconductor etch — power · pressure · time → yield</option>
|
|
570
|
+
<option value="gpu">⚡ GPU kernel tuning — tile · unroll · occupancy → throughput</option>
|
|
571
|
+
<option value="llm">🧠 LLM serving — batch · KV-cache · quantization → tokens/sec</option>
|
|
572
|
+
</select>
|
|
573
|
+
<div id="scenario" class="scenario"></div>
|
|
574
|
+
<div id="advbox" class="advbox">
|
|
575
|
+
<div style="background:#fff7ed;border:1px solid #fed7aa;border-radius:14px;padding:16px;margin:8px 0;display:flex;gap:14px;align-items:center;flex-wrap:wrap"><div style="flex:1;min-width:240px;font-size:13.5px;color:#7c2d12;line-height:1.55" data-i18n="sim_note"><b>You do NOT write these formulas.</b> This box is a browser simulation so you can watch the algorithm work. A pharma researcher (or anyone) uses the no-formula guided mode — enter your variables (pH, temperature…), make the recipe, measure the real result, type the score.</div><button class="btn primary" onclick="gotoGuide()" data-i18n="sim_btn">👉 No-formula mode</button></div>
|
|
576
|
+
<label>Space — the variables (name · type · min · max)</label>
|
|
577
|
+
<input id="space" value='[{"name":"x","type":"real","min":0,"max":10},{"name":"y","type":"real","min":0,"max":10}]'>
|
|
578
|
+
<label>Objective — the simulated score (a formula, browser demo only)</label>
|
|
579
|
+
<input id="obj" value="Math.exp(-((x-7.2)**2+(y-3.4)**2)/3)">
|
|
580
|
+
<label>Budget — experiments allowed</label>
|
|
581
|
+
<input id="budget" value="40">
|
|
582
|
+
</div>
|
|
583
|
+
<label style="display:flex;align-items:center;gap:9px;margin-top:14px;font-size:14px;color:#33344e;cursor:pointer"><input type="checkbox" id="reliable" style="width:16px;height:16px"> <span data-i18n="rel_lbl">⚡ Reliable mode — add a Nelder–Mead polish (slower; nails hard curved valleys to the true optimum)</span></label>
|
|
584
|
+
<button class="btn primary" style="margin-top:12px;width:100%" onclick="run()" data-i18n="watch">▶ Watch Melete discover</button>
|
|
585
|
+
<div id="runsrc" style="display:none"></div>
|
|
586
|
+
<div class="result" id="out">Pick a scenario, then press Watch — the best settings, a movie of how it searched, and a signed proof appear here.</div>
|
|
587
|
+
<div id="prime" style="display:none;margin-bottom:14px"></div>
|
|
588
|
+
<div id="journalist" style="display:none;margin-bottom:14px"></div>
|
|
589
|
+
<div id="rx" style="display:none;margin-bottom:14px"></div>
|
|
590
|
+
<div id="hero" style="display:none;margin-bottom:14px"></div>
|
|
591
|
+
<div id="eta" style="display:none;margin:14px 0"></div>
|
|
592
|
+
<div id="brain" style="display:none;margin:14px 0"></div>
|
|
593
|
+
<div id="aegis" style="display:none;margin:14px 0"></div>
|
|
594
|
+
<div id="sovcard" style="display:none;margin:14px 0"></div>
|
|
595
|
+
<div class="narrate" id="narrate" style="display:none"></div>
|
|
596
|
+
<div class="savings" id="savings" style="display:none"></div>
|
|
597
|
+
<div class="savings" id="baseline" style="display:none;margin-top:12px"></div>
|
|
598
|
+
<div class="savings" id="frontier" style="display:none;margin-top:12px"></div>
|
|
599
|
+
<div class="savings" id="cert" style="display:none;margin-top:12px"></div>
|
|
600
|
+
<div class="savings" id="poopt" style="display:none;margin-top:12px"></div>
|
|
601
|
+
<div class="savings" id="sens" style="display:none;margin-top:12px"></div>
|
|
602
|
+
<div class="savings" id="noise" style="display:none;margin-top:12px"></div>
|
|
603
|
+
<div class="savings" id="inter" style="display:none;margin-top:12px"></div>
|
|
604
|
+
<div class="savings" id="drift" style="display:none;margin-top:12px"></div>
|
|
605
|
+
<div class="savings" id="sloppy" style="display:none;margin-top:12px"></div>
|
|
606
|
+
<div class="savings" id="cliff" style="display:none;margin-top:12px"></div>
|
|
607
|
+
<div class="savings" id="rashomon" style="display:none;margin-top:12px"></div>
|
|
608
|
+
<div class="savings" id="shape" style="display:none;margin-top:12px"></div>
|
|
609
|
+
<div id="whatif" style="display:none;margin-top:12px"></div>
|
|
610
|
+
<div id="batchp" style="display:none;margin-top:12px"></div>
|
|
611
|
+
|
|
612
|
+
<div id="map">
|
|
613
|
+
<div class="mapgrid">
|
|
614
|
+
<div>
|
|
615
|
+
<div class="caps" data-i18n="cinema">Discovery cinema — watch Meli search</div>
|
|
616
|
+
<canvas id="surf" width="600" height="600"></canvas>
|
|
617
|
+
<div class="player">
|
|
618
|
+
<button id="play" class="pbtn" onclick="togglePlay()">▶ Replay</button>
|
|
619
|
+
<input id="scrub" type="range" min="0" max="1" value="1" oninput="scrubTo(+this.value)">
|
|
620
|
+
<span id="stepn" class="muted" style="font-size:12.5px;min-width:78px;text-align:right"></span>
|
|
621
|
+
</div>
|
|
622
|
+
<div id="legend" class="legend"></div>
|
|
623
|
+
<div class="muted" id="mapcap" style="font-size:12.5px;margin-top:6px">Heat = the score it learned · each dot = one experiment, coloured by the <b>strategy</b> that proposed it · ★ = best.</div>
|
|
624
|
+
</div>
|
|
625
|
+
<div>
|
|
626
|
+
<div class="caps" data-i18n="climb">How the score climbed (higher = better)</div>
|
|
627
|
+
<canvas id="conv" width="380" height="120" style="height:96px"></canvas>
|
|
628
|
+
<div id="teampanel" style="display:none">
|
|
629
|
+
<div class="caps" style="margin-top:16px" data-i18n="team">Meli's team — who did the work</div>
|
|
630
|
+
<div class="muted" style="font-size:12px;margin:-3px 0 8px" data-i18n="teamhint">Expert detail: the search helpers Meli used, and how many tries each got. You don't need this to use the result.</div>
|
|
631
|
+
<div id="arms"></div>
|
|
632
|
+
</div>
|
|
633
|
+
<div class="caps" style="margin-top:16px">Proof</div>
|
|
634
|
+
<div id="proof" class="kv"></div>
|
|
635
|
+
</div>
|
|
636
|
+
</div></div>
|
|
637
|
+
</div></section>
|
|
638
|
+
|
|
639
|
+
<section><h2 data-i18n="h_ind">Click an industry — see Melete work on it</h2>
|
|
640
|
+
<p class="muted" style="margin:0 0 16px">Each card runs the live demo on a realistic, domain-shaped scenario. <b data-i18n="ind_intro">The browser score is a simulated model</b> of the process — the <b>optimisation is real & reproducible</b>; connect your real assay / benchmark / process for real numbers.</p>
|
|
641
|
+
<div class="grid">
|
|
642
|
+
<div class="card indcard" onclick="tryScenario('pharma')"><div class="who">💊 Pharma · biotech</div><h3 data-i18n="t_pharma">Drug formulation</h3><p data-i18n="d_pharma">Variables: pH · temperature · excipient %. Goal: stability / potency. Melete finds the most stable formulation in ~60 assays — instead of hundreds.</p><div class="go" data-i18n="runnow">▶ Run it now</div></div>
|
|
643
|
+
<div class="card indcard" onclick="tryScenario('gpu')"><div class="who">⚡ AI infrastructure · accelerators</div><h3 data-i18n="t_gpu">GPU kernel tuning</h3><p data-i18n="d_gpu">Variables: tile size · unroll · occupancy. Goal: throughput (GFLOP/s). Find the fastest config in ~50 benchmark runs.</p><div class="go" data-i18n="runnow">▶ Run it now</div></div>
|
|
644
|
+
<div class="card indcard" onclick="tryScenario('etch')"><div class="who">🔬 Semiconductor · fab</div><h3 data-i18n="t_etch">Plasma-etch process</h3><p data-i18n="d_etch">Variables: power · pressure · time. Goal: wafer yield %. Tune the recipe to maximum yield — air-gapped, on-prem.</p><div class="go" data-i18n="runnow">▶ Run it now</div></div>
|
|
645
|
+
<div class="card indcard" onclick="tryScenario('llm')"><div class="who">🧠 The AI world itself</div><h3 data-i18n="t_llm">LLM serving config</h3><p data-i18n="d_llm">Variables: batch size · KV-cache · quantization. Goal: tokens/sec at a quality bar. Melete optimises AI infrastructure too — and can tune prompts, agents & routing the same way.</p><div class="go" data-i18n="runnow">▶ Run it now</div></div>
|
|
646
|
+
<div class="card indcard" onclick="tryScenario('coffee')"><div class="who">☕ Everyday</div><h3 data-i18n="t_esp">Best espresso recipe</h3><p data-i18n="d_esp">Variables: temp · grind · dose. Goal: taste. The friendliest way to watch the idea click.</p><div class="go" data-i18n="runnow">▶ Run it now</div></div>
|
|
647
|
+
</div></section>
|
|
648
|
+
|
|
649
|
+
<section id="pricing" style="margin-top:46px;display:none">
|
|
650
|
+
<div class="eyebrow" data-i18n="pr_eyebrow">PRICING</div>
|
|
651
|
+
<h2 data-i18n="pr_h">Start free. Pay when it saves you money.</h2>
|
|
652
|
+
<p data-i18n="pr_sub" style="max-width:720px;color:#475;font-size:16px;line-height:1.6">The value is fewer expensive experiments, certified — so you only pay once Melete is already saving you more than it costs.</p>
|
|
653
|
+
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:18px;margin-top:22px"><div style="position:relative;background:#fff;border-radius:18px;padding:26px;border:1px solid #e9e4f5"><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9" data-i18n="pr_free_name">Free</div><div style="font-size:30px;font-weight:800;color:#1a1b30;margin:6px 0 2px" data-i18n="pr_free_price">$0</div><div style="font-size:13px;color:#8890a8;min-height:34px" data-i18n="pr_free_tag">Open web + CLI, forever</div><div style="font-size:14px;color:#33344e;line-height:1.9;margin:14px 0" data-i18n="pr_free_f">✓ Run discoveries<br>✓ Signed, replicable trace<br>✓ Optimality certificate<br>✓ No signup</div><button class="btn ghost" style="width:100%" onclick="gotoTry()" data-i18n="pr_free_btn">▶ Try it now</button></div><div style="position:relative;background:#fff;border-radius:18px;padding:26px;border:2px solid #6366f1;box-shadow:0 18px 50px -22px rgba(99,102,241,.5)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#6366f1;color:#fff;font-size:11px;font-weight:800;letter-spacing:.5px;padding:4px 12px;border-radius:99px" data-i18n="pr_pop">POPULAR</div><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9" data-i18n="pr_pro_name">Pro</div><div style="font-size:30px;font-weight:800;color:#1a1b30;margin:6px 0 2px" data-i18n="pr_pro_price">Early access</div><div style="font-size:13px;color:#8890a8;min-height:34px" data-i18n="pr_pro_tag">For teams on a real process</div><div style="font-size:14px;color:#33344e;line-height:1.9;margin:14px 0" data-i18n="pr_pro_f">✓ Connect your process via API<br>✓ Reliable mode + batch runs<br>✓ Priority support<br>✓ Private workspace</div><button class="btn primary" style="width:100%" onclick="showContact()" data-i18n="pr_pro_btn">Talk to us</button></div><div style="position:relative;background:#fff;border-radius:18px;padding:26px;border:1px solid #e9e4f5"><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9" data-i18n="pr_ent_name">Enterprise</div><div style="font-size:30px;font-weight:800;color:#1a1b30;margin:6px 0 2px" data-i18n="pr_ent_price">Air-gapped</div><div style="font-size:13px;color:#8890a8;min-height:34px" data-i18n="pr_ent_tag">Regulated + on-prem</div><div style="font-size:14px;color:#33344e;line-height:1.9;margin:14px 0" data-i18n="pr_ent_f">✓ Runs fully offline — data never leaves<br>✓ Signed proof for audits and patents<br>✓ SLA + onboarding<br>✓ Self-hosted</div><button class="btn ghost" style="width:100%" onclick="showContact()" data-i18n="pr_ent_btn">Talk to us</button></div></div>
|
|
654
|
+
</section>
|
|
655
|
+
<script>function gotoTry(){var t=document.getElementById("try");if(t){t.scrollIntoView({behavior:"smooth"});}}
|
|
656
|
+
function gotoGuide(){var g=document.getElementById("guide");if(g){g.scrollIntoView({behavior:"smooth"});}}</script>
|
|
657
|
+
|
|
658
|
+
<section><div class="card" style="text-align:center;background:linear-gradient(120deg,#f3f1ff,#eafcf8);border-color:#ddd9fb;padding:28px">
|
|
659
|
+
<div style="width:64px;margin:0 auto 6px">${meli()}</div>
|
|
660
|
+
<h3 style="font-size:23px;margin:0 0 8px" data-i18n="cta_h">Like Melete? Talk to the maker.</h3>
|
|
661
|
+
<p style="margin:0 auto 16px;color:#33344e;font-size:16px;max-width:560px" data-i18n="cta_body">Built by one developer who genuinely loves this stuff. Got a question, an idea, or a process you want to try it on? Just reach out — happy to chat.</p>
|
|
662
|
+
<button class="btn primary" onclick="showContact()">📩 <span data-i18n="btn_contact">Contact about Melete</span></button>
|
|
663
|
+
<a class="btn ghost" href="/pitch"><span data-i18n="btn_pitch">Read the pitch</span></a>
|
|
664
|
+
</div></section>
|
|
665
|
+
|
|
666
|
+
<section id="reliproof" style="margin-top:46px">
|
|
667
|
+
<div class="eyebrow" data-i18n="pf_eyebrow">PROVEN · MEASURED · CERTIFIED</div>
|
|
668
|
+
<h2 data-i18n="pf_h">≥99% of the true optimum — on every landscape</h2>
|
|
669
|
+
<p data-i18n="pf_sub" style="max-width:740px;color:#475;font-size:16px;line-height:1.6">Most optimizers win on easy surfaces and quietly fail on the hard ones. Melete is benchmarked on 7 deliberately adversarial landscapes, each normalised so the score is literally the % of the true optimum reached — and it clears ≥99% on every one, every seed.</p>
|
|
670
|
+
${(() => {
|
|
671
|
+
const L = [
|
|
672
|
+
{ n: "Smooth", p: 100, d: "easy" }, { n: "Rastrigin", p: 100, d: "hard" }, { n: "Ackley", p: 100, d: "hard" },
|
|
673
|
+
{ n: "Rosenbrock", p: 99.5, d: "brutal" }, { n: "Griewank", p: 100, d: "hard" }, { n: "High-dim 5D", p: 99.6, d: "brutal" }, { n: "Needle", p: 100, d: "brutal" },
|
|
674
|
+
];
|
|
675
|
+
const avg = (L.reduce((s, x) => s + x.p, 0) / L.length);
|
|
676
|
+
const dc = { easy: ["#0e9f6e", "#ecfdf5"], hard: ["#b45309", "#fff7ed"], brutal: ["#c0392b", "#fef2f2"] };
|
|
677
|
+
const ring = (p, size, fs) => `<div style="position:relative;width:${size}px;height:${size}px;border-radius:50%;background:conic-gradient(#6d5cf0 ${(p * 3.6).toFixed(1)}deg,#ece9fb 0)"><div style="position:absolute;inset:5px;border-radius:50%;background:#fff;display:flex;align-items:center;justify-content:center;font-family:ui-monospace,Menlo,monospace;font-weight:800;font-size:${fs}px;color:#4c3fd6">${p === 100 ? "100" : p.toFixed(1)}<span style="font-size:${fs * 0.5}px;margin-top:${fs * 0.18}px">%</span></div></div>`;
|
|
678
|
+
const cards = L.map((x) => `<div class="relcard" style="background:rgba(255,255,255,.9);border:1px solid #efeafc;border-radius:18px;padding:16px 12px;display:flex;flex-direction:column;align-items:center;gap:9px;box-shadow:0 14px 34px -26px rgba(80,60,180,.5);transition:transform .45s cubic-bezier(.22,1,.36,1)">${ring(x.p, 64, 17)}<div style="font-size:12.5px;font-weight:700;color:#2b2c44;letter-spacing:.2px">${x.n}</div><span style="font-size:10px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:${dc[x.d][0]};background:${dc[x.d][1]};padding:2px 8px;border-radius:99px">${x.d}</span></div>`).join("");
|
|
679
|
+
return `<div style="margin-top:26px;display:flex;gap:26px;align-items:center;flex-wrap:wrap">
|
|
680
|
+
${ring(avg, 132, 32)}
|
|
681
|
+
<div style="flex:1;min-width:230px"><div style="font-size:19px;font-weight:800;color:#1a1b30;letter-spacing:-.3px">${avg.toFixed(1)}% <span style="font-weight:600;color:#5b5d77;font-size:16px" data-i18n="pf_avg">average of the true optimum reached</span></div><div style="font-size:13.5px;color:#8890a8;margin-top:5px" data-i18n="pf_avg2">across 7 adversarial landscapes · every seed · ≥99% on every single one — including the brutal ones (Rosenbrock's banana valley, a 5-D haystack, a lone needle).</div></div>
|
|
682
|
+
</div>
|
|
683
|
+
<div style="margin-top:22px;display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:13px">${cards}</div>
|
|
684
|
+
<div style="margin-top:24px;padding-top:18px;border-top:1px solid #efeafc;font-size:13.5px;color:#46485f;line-height:1.65" data-i18n="pf_engine">How: a 3-paradigm engine — portfolio global-explore → certificate-guided Lipschitz infill → Nelder–Mead polish. Every result also carries an optimality certificate: a provable bound on how much better the true best could be.</div>`;
|
|
685
|
+
})()}
|
|
686
|
+
<p class="muted" data-i18n="pf_note" style="margin-top:12px;font-size:12px">Reproducible: this is the open reliability gauntlet — re-run it and check every number yourself.</p>
|
|
687
|
+
</section>
|
|
688
|
+
|
|
689
|
+
<section id="verifybox" style="margin-top:46px;display:none">
|
|
690
|
+
<div class="eyebrow" data-i18n="vf_eyebrow">VERIFY · NO TRUST NEEDED</div>
|
|
691
|
+
<h2 data-i18n="vf_h">Verify any Proof of Optimization — offline</h2>
|
|
692
|
+
<p data-i18n="vf_sub" style="max-width:720px;color:#475;font-size:16px;line-height:1.6">Anyone can check a Melete certificate without trusting us. Paste a downloaded certificate (or drop the .json file) — it recomputes the efficiency claim and checks the Ed25519 signature with the public key embedded in the certificate itself.</p>
|
|
693
|
+
<div class="card" style="max-width:700px;margin-top:16px;padding:20px">
|
|
694
|
+
<textarea id="vfin" placeholder="paste proof-of-optimization.json here" style="width:100%;height:110px;padding:11px;border:1px solid #ccd;border-radius:10px;font-size:12.5px;font-family:ui-monospace,monospace;resize:vertical"></textarea>
|
|
695
|
+
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-top:10px"><input type="file" id="vffile" accept="application/json,.json" onchange="vfLoad(event)" style="font-size:13px"><button class="btn ghost" onclick="vfSample()" data-i18n="vf_sample">▶ Load a sample</button><button class="btn primary" onclick="vfRun()" data-i18n="vf_btn">Verify certificate</button></div>
|
|
696
|
+
<div id="vfout" style="margin-top:14px"></div>
|
|
697
|
+
</div>
|
|
698
|
+
</section>
|
|
699
|
+
<script>
|
|
700
|
+
function vfLoad(e){var f=e.target.files&&e.target.files[0];if(!f)return;var r=new FileReader();r.onload=function(){document.getElementById("vfin").value=String(r.result||"");};r.readAsText(f);}
|
|
701
|
+
function vfSample(){var th=(LANG==="th");var out=document.getElementById("vfout");out.textContent=th?"กำลังสร้างตัวอย่างให้ดู…":"making a sample for you…";fetch("/discover",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({space:[{name:"x",type:"real",min:-5,max:5},{name:"y",type:"real",min:-5,max:5}],objective:"Math.exp(-(x*x+y*y)/8)",budget:30,goal:"maximize",subject:"sample run"})}).then(function(r){return r.json();}).then(function(j){if(j&&j.poopt){document.getElementById("vfin").value=JSON.stringify(j.poopt,null,2);vfRun();}else{out.innerHTML='<span style="color:#c33">error</span>';}}).catch(function(){out.innerHTML='<span style="color:#c33">error</span>';});}
|
|
702
|
+
function vfRun(){var th=(LANG==="th");var out=document.getElementById("vfout");var cert;try{cert=JSON.parse(document.getElementById("vfin").value);}catch(e){out.innerHTML='<span style="color:#c33">'+(th?"JSON ไม่ถูกต้อง":"invalid JSON")+'</span>';return;}out.textContent=th?"กำลังตรวจ…":"verifying…";fetch("/poopt/verify",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(cert)}).then(function(r){return r.json();}).then(function(v){if(v.ok){out.innerHTML='<div style="color:#0e9f6e;font-weight:800;font-size:17px">✓ '+(th?"ถูกต้อง — ลายเซ็น + ตัวเลขตรวจสอบผ่าน":"Valid — signature + claim verified")+'</div><div style="font-size:13px;color:#475;margin-top:5px">'+(v.subject||"")+" · "+(th?"ประหยัด ":"saved ")+(v.experimentsSaved!=null?(+v.experimentsSaved).toLocaleString():"?")+" "+(th?"การทดลอง":"experiments")+" ("+(v.efficiencyPct!=null?(+v.efficiencyPct).toFixed(1):"?")+"%)"+(v.co2SavedKg!=null?(" · CO₂ "+(+v.co2SavedKg).toLocaleString()+" kg"):"")+'</div>';}else{out.innerHTML='<div style="color:#c0392b;font-weight:800;font-size:17px">✗ '+(th?"ไม่ผ่าน":"Invalid")+'</div><div style="font-size:13px;color:#475;margin-top:5px">'+(v.reason||"")+'</div>';}}).catch(function(){out.innerHTML='<span style="color:#c33">error</span>';});}
|
|
703
|
+
</script>
|
|
704
|
+
|
|
705
|
+
<section id="moo" style="margin-top:46px">
|
|
706
|
+
<div class="eyebrow" data-i18n="mo_eyebrow">MULTI-OBJECTIVE</div>
|
|
707
|
+
<h2 data-i18n="mo_h">Optimize several goals at once — see the trade-offs</h2>
|
|
708
|
+
<p data-i18n="mo_sub" style="max-width:720px;color:#475;font-size:16px;line-height:1.6">Real problems have competing goals — more yield AND less cost. There is no single best, so Melete finds the Pareto front: the set of best-possible trade-offs. Define your goals + variables, run the same propose → measure → repeat loop scoring each objective, and watch the front fill in.</p>
|
|
709
|
+
<div class="card" style="max-width:720px;margin-top:16px;padding:22px"><div id="mobody"></div></div>
|
|
710
|
+
</section>
|
|
711
|
+
<script>
|
|
712
|
+
var moVars=[{name:'temperature',min:20,max:40},{name:'time (min)',min:1,max:60}];
|
|
713
|
+
var moGoals=[{name:'yield',goal:'maximize'},{name:'cost',goal:'minimize'}];
|
|
714
|
+
var moObs=[],moNext=null,moSpace=[],moGoalsR=[];
|
|
715
|
+
function moFmt(e){return moSpace.map(function(d){return d.name+' = <b>'+(+e[d.name]).toFixed(2)+'</b>';}).join(' · ');}
|
|
716
|
+
function moAddObj(){if(moGoals.length<6)moGoals.push({name:'',goal:'maximize'});moRenderSetup();}
|
|
717
|
+
function moDelObj(i){moGoals.splice(i,1);moRenderSetup();}
|
|
718
|
+
function moAddVar(){moVars.push({name:'',min:0,max:1});moRenderSetup();}
|
|
719
|
+
function moDelVar(i){moVars.splice(i,1);moRenderSetup();}
|
|
720
|
+
function moRenderSetup(){var c=document.getElementById('mobody');if(!c)return;var th=(LANG==='th');
|
|
721
|
+
var gh=moGoals.map(function(g,i){return '<div style="display:flex;gap:6px;margin-bottom:6px;align-items:center"><input value="'+String(g.name||'').replace(/"/g,'"')+'" oninput="moGoals['+i+'].name=this.value" placeholder="'+(th?'ชื่อเป้าหมาย':'goal name')+'" style="flex:2;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><select onchange="moGoals['+i+'].goal=this.value" style="padding:8px;border:1px solid #ccd;border-radius:8px;font-size:13px"><option value="maximize"'+(g.goal!=='minimize'?' selected':'')+'>'+(th?'มากสุด':'maximize')+'</option><option value="minimize"'+(g.goal==='minimize'?' selected':'')+'>'+(th?'น้อยสุด':'minimize')+'</option></select><button onclick="moDelObj('+i+')" style="border:none;background:#f3f3f7;border-radius:8px;width:34px;height:34px;cursor:pointer;color:#888">×</button></div>';}).join('');
|
|
722
|
+
var vh=moVars.map(function(v,i){return '<div style="display:flex;gap:6px;margin-bottom:6px;align-items:center"><input value="'+String(v.name||'').replace(/"/g,'"')+'" oninput="moVars['+i+'].name=this.value" placeholder="'+(th?'ชื่อตัวแปร':'variable')+'" style="flex:2;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><input type="number" step="any" value="'+v.min+'" oninput="moVars['+i+'].min=this.value" placeholder="min" style="flex:1;width:0;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><input type="number" step="any" value="'+v.max+'" oninput="moVars['+i+'].max=this.value" placeholder="max" style="flex:1;width:0;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><button onclick="moDelVar('+i+')" style="border:none;background:#f3f3f7;border-radius:8px;width:34px;height:34px;cursor:pointer;color:#888">×</button></div>';}).join('');
|
|
723
|
+
c.innerHTML='<div style="font-size:13px;font-weight:700;color:#475;margin-bottom:8px">'+(th?'เป้าหมาย (ใส่ได้หลายเป้า)':'Goals (add several)')+'</div>'+gh+'<button class="btn ghost" onclick="moAddObj()" style="font-size:13px;padding:6px 12px;margin-bottom:16px">+ '+(th?'เพิ่มเป้าหมาย':'add goal')+'</button><div style="font-size:13px;font-weight:700;color:#475;margin:6px 0 8px">'+(th?'ตัวแปรที่ปรับได้':'Variables you can change')+'</div>'+vh+'<button class="btn ghost" onclick="moAddVar()" style="font-size:13px;padding:6px 12px">+ '+(th?'เพิ่มตัวแปร':'add variable')+'</button><br><button class="btn primary" onclick="moStart()" style="margin-top:16px">'+(th?'▶ เริ่มหา trade-off':'▶ Start finding trade-offs')+'</button>';
|
|
724
|
+
}
|
|
725
|
+
function moStart(){var th=(LANG==='th');var dims=moVars.filter(function(v){return v.name&&isFinite(+v.min)&&isFinite(+v.max)&&(+v.max)>(+v.min);}).map(function(v){return {name:v.name,type:'real',min:+v.min,max:+v.max};});var goals=moGoals.filter(function(g){return g.name;}).map(function(g){return {name:g.name,goal:g.goal==='minimize'?'minimize':'maximize'};});if(dims.length<1){alert(th?'ใส่ตัวแปรอย่างน้อย 1 ตัว':'add at least one variable');return;}if(goals.length<2){alert(th?'multi-objective ต้องมีอย่างน้อย 2 เป้าหมาย':'add at least 2 goals for multi-objective');return;}moSpace=dims;moGoalsR=goals;moObs=[];moAsk();}
|
|
726
|
+
function moAsk(){fetch('/next-multi',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({space:moSpace,goals:moGoalsR,observations:moObs})}).then(function(r){return r.json();}).then(function(j){if(j.error){document.getElementById('mobody').innerHTML='<span style="color:#c33">'+j.error+'</span>';return;}moNext=j.next;moRenderLoop(j);}).catch(function(){document.getElementById('mobody').innerHTML='<span style="color:#c33">error</span>';});}
|
|
727
|
+
function moRecord(){var vals=[];for(var i=0;i<moGoalsR.length;i++){var el=document.getElementById('mov'+i);var v=el?parseFloat(el.value):NaN;if(!isFinite(v))return;vals.push(v);}moObs.push({experiment:moNext,values:vals});moAsk();}
|
|
728
|
+
function moRenderLoop(j){var th=(LANG==='th');var inputs=moGoalsR.map(function(g,i){return '<div style="margin:6px 12px 6px 0;display:inline-block"><label style="font-size:12px;color:#475">'+g.name+' ('+(g.goal==='minimize'?(th?'น้อยดี':'lower=better'):(th?'มากดี':'higher=better'))+')</label><br><input id="mov'+i+'" type="number" step="any" style="padding:8px;border:1px solid #ccd;border-radius:8px;width:140px;font-size:15px"></div>';}).join('');
|
|
729
|
+
document.getElementById('mobody').innerHTML='<div style="color:#8890a8;font-size:13px">'+(th?'รอบที่':'Round')+' '+(moObs.length+1)+'</div><div style="font-size:16px;margin:8px 0;color:#1a1b30">'+(th?'ลองค่านี้':'Try this setting')+':<br>'+moFmt(moNext)+'</div><div style="font-size:13px;color:#475;margin-top:6px">'+(th?'วัดจริงแล้วใส่คะแนนแต่ละเป้า:':'Measure for real, then enter each objective:')+'</div>'+inputs+'<br><button class="btn primary" style="margin-top:6px" onclick="moRecord()">'+(th?'บันทึก & ถัดไป ▶':'Record & next ▶')+'</button>'+moPlot(j.paretoFront||[]);
|
|
730
|
+
}
|
|
731
|
+
function moPlot(front){var th=(LANG==='th');if(!front||!front.length)return '';var head='<div style="margin-top:18px;font-size:13px;font-weight:800;color:#7c3aed;text-transform:uppercase;letter-spacing:.3px">'+(th?'Pareto front — ตัวเลือกดีที่สุด ('+front.length+')':'Pareto front — best trade-offs ('+front.length+')')+'</div>';
|
|
732
|
+
if(moGoalsR.length===2&&moObs.length>=2){var ax=moObs.map(function(o){return o.values[0];}),ay=moObs.map(function(o){return o.values[1];});var mnx=Math.min.apply(null,ax),mxx=Math.max.apply(null,ax),mny=Math.min.apply(null,ay),mxy=Math.max.apply(null,ay);var rx=(mxx-mnx)||1,ry=(mxy-mny)||1,W=320,H=190,P=26;function px(x){return P+((x-mnx)/rx)*(W-2*P);}function py(y){return H-P-((y-mny)/ry)*(H-2*P);}var all=moObs.map(function(o){return '<circle cx="'+px(o.values[0]).toFixed(1)+'" cy="'+py(o.values[1]).toFixed(1)+'" r="3" fill="#cbd5e1"/>';}).join('');var fr=front.map(function(o){return '<circle cx="'+px(o.values[0]).toFixed(1)+'" cy="'+py(o.values[1]).toFixed(1)+'" r="5.5" fill="#7c3aed"/>';}).join('');return head+'<svg width="'+W+'" height="'+H+'" style="margin-top:8px;background:#faf8ff;border:1px solid #ece7ff;border-radius:10px;max-width:100%">'+all+fr+'<text x="'+(W/2)+'" y="'+(H-6)+'" font-size="10" fill="#8890a8" text-anchor="middle">'+moGoalsR[0].name+' →</text><text x="6" y="16" font-size="10" fill="#8890a8">'+moGoalsR[1].name+' ↑</text></svg><div style="font-size:11.5px;color:#8890a8;margin-top:4px">'+(th?'จุดม่วง = ตัวเลือกดีที่สุด (ไม่มีตัวไหนเหนือกว่าได้ทุกด้าน)':'purple = the best trade-offs (none is beaten on every goal)')+'</div>';}
|
|
733
|
+
var rows=front.slice(0,10).map(function(o){return '<div style="font-size:13px;color:#33344e;padding:3px 0;border-bottom:1px solid #f3f0ff">'+moGoalsR.map(function(g,i){return '<b>'+g.name+'</b>='+(+o.values[i]).toFixed(2);}).join(' · ')+'</div>';}).join('');return head+'<div style="margin-top:6px">'+rows+'</div>';
|
|
734
|
+
}
|
|
735
|
+
try{moRenderSetup();}catch(e){}
|
|
736
|
+
</script>
|
|
737
|
+
<section><h2 data-i18n="h_proven">Proven, not claimed</h2>
|
|
738
|
+
<p style="margin:0 0 14px;color:#33344e" data-i18n="prov_intro">No single optimiser wins on every landscape. A bandit spends each experiment on whichever strategy is winning <i>on your problem</i> — one engine, no per-problem tuning.</p>
|
|
739
|
+
<table><tr><th data-i18n="tl_land">landscape</th><th>Melete</th><th data-i18n="tl_bay">single Bayesian</th><th data-i18n="tl_rand">random</th></tr>
|
|
740
|
+
<tr><td data-i18n="tl_smooth">smooth</td><td class="win">1.000</td><td>0.999</td><td>0.838</td></tr>
|
|
741
|
+
<tr><td data-i18n="tl_rug">rugged (many traps)</td><td class="win" data-i18n="tl_best">best 🏆 beats every single algorithm</td><td data-i18n="tl_far">far behind</td><td data-i18n="tl_far">far behind</td></tr>
|
|
742
|
+
<tr><td data-i18n="tl_hd">high-dimensional</td><td class="win">0.996</td><td>0.987</td><td>0.555</td></tr></table>
|
|
743
|
+
<p class="muted" style="margin-top:10px">≈ 26 experiments vs ~95 for random to reach 99% of a hidden optimum (3.7×). Reproduce with <code>melete bench --robust</code>.</p></section>
|
|
744
|
+
|
|
745
|
+
<section id="guide" style="margin-top:38px">
|
|
746
|
+
<h2 data-i18n="g_h">Use it on your real process — you measure</h2>
|
|
747
|
+
<p data-i18n="g_intro" style="max-width:720px;color:#475;font-size:16px;line-height:1.6">No code, no formula. Melete proposes the next experiment; you go run it for real and type the score back; it proposes the next — converging to the best in as few real tries as possible. Edit your own variables below — for example a pharma scientist enters pH, temperature, excipient %; Melete then says which recipe to make next. Connect your real process via the API for production.</p>
|
|
748
|
+
<div id="gsteps" style="margin:18px 0"><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9;margin-bottom:12px" data-i18n="gs_h">How it works — 4 steps</div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px"><div style="background:#fff;border:1px solid #e7e0ff;border-radius:14px;padding:16px"><div style="width:30px;height:30px;border-radius:50%;background:linear-gradient(96deg,#6d5cf0,#0ea5b7);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:15px">1</div><div style="margin-top:10px;font-size:13px;color:#33344e;line-height:1.5" data-i18n="gs1"></div></div><div style="background:#fff;border:1px solid #e7e0ff;border-radius:14px;padding:16px"><div style="width:30px;height:30px;border-radius:50%;background:linear-gradient(96deg,#6d5cf0,#0ea5b7);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:15px">2</div><div style="margin-top:10px;font-size:13px;color:#33344e;line-height:1.5" data-i18n="gs2"></div></div><div style="background:#fff;border:1px solid #e7e0ff;border-radius:14px;padding:16px"><div style="width:30px;height:30px;border-radius:50%;background:linear-gradient(96deg,#6d5cf0,#0ea5b7);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:15px">3</div><div style="margin-top:10px;font-size:13px;color:#33344e;line-height:1.5" data-i18n="gs3"></div></div><div style="background:#fff;border:1px solid #e7e0ff;border-radius:14px;padding:16px"><div style="width:30px;height:30px;border-radius:50%;background:linear-gradient(96deg,#6d5cf0,#0ea5b7);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:15px">4</div><div style="margin-top:10px;font-size:13px;color:#33344e;line-height:1.5" data-i18n="gs4"></div></div></div></div><div id="ghowreal" style="background:#fffbeb;border:1px solid #fde68a;border-radius:14px;padding:16px;margin:16px 0;font-size:13.5px;color:#78350f;line-height:1.6" data-i18n="g_howreal"><b>Using Melete in your real project — 2 ways:</b><br><b>1) Through this website (no code)</b> — for slow / expensive hand-measured experiments: Melete proposes, you run it in your lab/system, you type the score. Best for physical experiments you measure by hand anyway.<br><b>2) Connected & automated</b> — <code>melete tune</code>, <code>POST /next</code>, or the npm library, on YOUR own servers (air-gapped): your code runs each test and feeds the score back in a loop. Best for benchmarks, simulations, pipelines. <a href="/docs" style="font-weight:700;color:#b45309">→ API docs</a></div><div class="card" style="max-width:660px;margin-top:16px;padding:22px"><div id="gBody"><div id="gind"><div style="font-size:13px;color:#475;margin-bottom:8px" data-i18n="g_pick">Start from your industry — or edit the variables yourself:</div><select id="gindsel" onchange="if(this.value){gIndustry(this.value);}" style="width:100%;max-width:360px;padding:11px 14px;border:1px solid #ccd;border-radius:12px;font-size:14px;font-weight:600;color:#33344e;background:#fff;cursor:pointer;margin-bottom:16px"><option value="" data-i18n="g_pickopt">Choose your field…</option><option value="pharma">💊 Pharma · biotech</option><option value="fab">🔬 Semiconductor</option><option value="food">☕ Food & drink</option><option value="print">🖨 3D printing</option><option value="ml">⚡ AI / ML</option><option value="safety">🛡 AI safety</option><option value="cyber">🔐 Cybersecurity</option><option value="fintech">💳 Fintech risk</option><option value="network">🌐 Network tuning</option><option value="agri">🌾 Agriculture</option><option value="energy">⚡ Energy</option><option value="mfg">🏭 Manufacturing</option></select></div><div id="gex" data-i18n="g_ex" style="background:#f0f9ff;border:1px solid #bae6fd;border-radius:12px;padding:13px;margin-bottom:14px;font-size:13px;color:#075985;line-height:1.55"><b>Example — AI security engineer:</b> adjust <b>[filter threshold · temperature · rate limit]</b>, then measure <b>[% of red-team attacks your system blocks]</b> as the score. Melete proposes the next config → you run your attack suite → type the % → repeat → it finds the safest config in the fewest tests.</div><div id="gvars"></div><button class="btn ghost" onclick="gAddVar()" style="margin-top:2px;font-size:13px;padding:7px 12px">+ <span data-i18n="g_addvar">add variable</span></button><br><div style="margin-top:14px"><label style="font-size:13px;color:#475;font-weight:600" data-i18n="g_target">🎯 Target (optional)</label><br><input id="gtarget" type="number" step="any" placeholder="e.g. 95" style="margin-top:5px;padding:9px 12px;border:1px solid #ccd;border-radius:10px;width:160px;font-size:14px"><div style="font-size:11.5px;color:#8890a8;margin-top:4px" data-i18n="g_targethint">the score you need — Melete tells you if it is reachable with these variables</div></div><button class="btn primary" onclick="gAuto()" data-i18n="g_auto" style="margin-top:14px">▶ Watch Melete solve it (auto)</button> <button class="btn ghost" data-i18n="g_start" onclick="gStart()" style="margin-top:14px">I will measure myself</button></div></div>
|
|
749
|
+
<script>
|
|
750
|
+
var gObs=[],gNext=null,gGoal='maximize',gAdvice=null,gAutoF=null,gAutoOn=false,gTerritory=null,gConfidence=null,gAchiev=null,gTarget=NaN,gInverse=null;
|
|
751
|
+
var gSpace=[];
|
|
752
|
+
var gVarDefs=[{name:'pH',min:3,max:9},{name:'temperature (°C)',min:20,max:40},{name:'excipient %',min:0,max:30}];
|
|
753
|
+
function gRenderVars(){var c=document.getElementById('gvars');if(!c)return;var th=(LANG==='th');
|
|
754
|
+
c.innerHTML='<div style="font-size:13px;color:#475;margin-bottom:8px">'+(th?'สิ่งที่คุณปรับได้ (ชื่อ · ต่ำสุด · สูงสุด) — แก้เป็นของคุณได้เลย ไม่ต้องมีสูตร':'What you can change (name · min · max) — edit to your own, no formula needed')+'</div>'
|
|
755
|
+
+gVarDefs.map(function(v,i){return '<div style="display:flex;gap:6px;margin-bottom:6px;align-items:center"><input value="'+String(v.name).replace(/"/g,""")+'" oninput="gVarDefs['+i+'].name=this.value" placeholder="'+(th?'ชื่อ':'name')+'" style="flex:2;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><input type="number" step="any" value="'+v.min+'" oninput="gVarDefs['+i+'].min=this.value" placeholder="min" style="flex:1;width:0;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><input type="number" step="any" value="'+v.max+'" oninput="gVarDefs['+i+'].max=this.value" placeholder="max" style="flex:1;width:0;padding:8px;border:1px solid #ccd;border-radius:8px;font-size:14px"><button onclick="gDelVar('+i+')" title="remove" style="border:none;background:#f3f3f7;border-radius:8px;width:34px;height:34px;cursor:pointer;color:#888">×</button></div>';}).join('');}
|
|
756
|
+
function gAddVar(){gVarDefs.push({name:'',min:0,max:1});gRenderVars();}
|
|
757
|
+
function gDelVar(i){gVarDefs.splice(i,1);gRenderVars();}
|
|
758
|
+
function gReadVars(){return gVarDefs.filter(function(v){return v.name&&isFinite(+v.min)&&isFinite(+v.max)&&(+v.max)>(+v.min);}).map(function(v){return {name:v.name,type:'real',min:+v.min,max:+v.max};});}
|
|
759
|
+
var gIND={pharma:[{name:'pH',min:3,max:9},{name:'temperature (°C)',min:20,max:40},{name:'excipient %',min:0,max:30}],fab:[{name:'power (W)',min:100,max:1000},{name:'pressure (mTorr)',min:5,max:100},{name:'time (s)',min:10,max:120}],food:[{name:'temperature (°C)',min:60,max:100},{name:'time (min)',min:1,max:30},{name:'sugar %',min:0,max:20}],print:[{name:'nozzle temp (°C)',min:180,max:260},{name:'speed (mm/s)',min:20,max:150},{name:'layer height (mm)',min:0.05,max:0.4}],ml:[{name:'batch size',min:1,max:64},{name:'learning-rate ×1000',min:1,max:100},{name:'dropout %',min:0,max:50}],safety:[{name:'filter threshold',min:0,max:1},{name:'temperature',min:0,max:2},{name:'rate limit (req/min)',min:1,max:100},{name:'max retries',min:0,max:5}],cyber:[{name:'firewall sensitivity',min:0,max:1},{name:'session timeout (min)',min:1,max:60},{name:'max login attempts',min:1,max:10},{name:'IDS threshold',min:0,max:1}],fintech:[{name:'risk score cutoff',min:0,max:1},{name:'txn limit ($)',min:100,max:100000},{name:'review threshold',min:0,max:1},{name:'velocity window (min)',min:1,max:60}],network:[{name:'MTU',min:576,max:9000},{name:'buffer size (KB)',min:16,max:1024},{name:'max connections',min:10,max:10000},{name:'timeout (ms)',min:50,max:5000}],agri:[{name:'nitrogen (kg/ha)',min:0,max:300},{name:'irrigation (mm/wk)',min:0,max:100},{name:'seed density',min:10,max:80},{name:'soil pH',min:4,max:8}],energy:[{name:'turbine angle (°)',min:0,max:45},{name:'flow rate',min:10,max:100},{name:'pressure (bar)',min:1,max:50},{name:'temperature (°C)',min:50,max:600}],mfg:[{name:'temperature (°C)',min:100,max:400},{name:'pressure (bar)',min:1,max:100},{name:'speed (units/min)',min:10,max:500},{name:'cycle time (s)',min:5,max:120}]};
|
|
760
|
+
function gIndustry(k){var p=gIND[k];if(!p)return;gVarDefs=p.map(function(x){return {name:x.name,min:x.min,max:x.max};});gGoal='maximize';gRenderVars();}
|
|
761
|
+
var GI={en:{round:'Round',next:'Melete proposes — go measure this',score:'Your measured score',rec:'Record & next ▶',best:'Best so far',err:'Could not reach Melete'},th:{round:'รอบที่',next:'Melete เสนอ — ลองวัดค่านี้จริง',score:'คะแนนที่คุณวัดได้',rec:'บันทึก & ถัดไป ▶',best:'ดีที่สุดตอนนี้',err:'เชื่อมต่อ Melete ไม่ได้'}};
|
|
762
|
+
function gL(){return GI[(localStorage.getItem('mlang')||'en')]||GI.en;}
|
|
763
|
+
function gFmt(e){return gSpace.map(function(d){return d.name+' = <b>'+(+e[d.name]).toFixed(2)+'</b>';}).join(' · ');}
|
|
764
|
+
function gAuto(){var th=(LANG==='th');var sp=gReadVars();if(!sp.length){alert(th?'ใส่ตัวแปรอย่างน้อย 1 ตัว':'add at least one variable');return;}gSpace=sp;gGoal='maximize';gObs=[];gAutoOn=true;gAutoF=function(e){var t=0;for(var i=0;i<gSpace.length;i++){var d=gSpace[i];var opt=d.min+0.6*((d.max-d.min)||1);var rng=(d.max-d.min)||1;var z=((+e[d.name]-opt)/rng);t+=-z*z;}return 10+t*8;};gAutoStep();}
|
|
765
|
+
function gAutoStep(){if(!gAutoOn)return;var done=(gObs.length>=20)||(gAdvice&&gAdvice.recommendation==='STOP'&&gObs.length>=6);if(done){gAutoOn=false;gAutoView(true);return;}fetch('/next',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({space:gSpace,observations:gObs,goal:'maximize'})}).then(function(r){return r.json();}).then(function(j){if(j.error){document.getElementById('gBody').innerHTML='<span style="color:#c33">'+j.error+'</span>';gAutoOn=false;return;}gNext=j.next;gAdvice=j.advice||null;var v=gAutoF(gNext);gObs.push({experiment:gNext,value:v});gAutoView(false);setTimeout(gAutoStep,500);}).catch(function(){gAutoOn=false;});}
|
|
766
|
+
function gAutoView(done){var th=(LANG==='th');var last=gObs[gObs.length-1];if(!last)return;var dir=(gGoal==='minimize')?-1:1;var best=gObs.reduce(function(a,b){return (dir*b.value>dir*a.value)?b:a;});var banner=done?('<div style="background:#ecfdf5;border:1px solid #a7f3d0;border-radius:10px;padding:11px;font-size:13.5px;color:#0e7a4f;font-weight:700;margin-bottom:12px">\u2713 '+(th?'เสร็จ! Melete หาคำตอบที่ดีที่สุดเจอใน '+gObs.length+' ครั้ง (จำลอง) — ของจริงคุณใส่คะแนนที่วัดเองแต่ละครั้ง':'Done! Melete found the best in '+gObs.length+' tries (simulated) — in real use YOU enter your measured score each round')+'</div>'):('<div style="background:#eef2ff;border:1px solid #c7d2fe;border-radius:10px;padding:11px;font-size:13.5px;color:#4338ca;font-weight:600;margin-bottom:12px">\u25b6 '+(th?'กำลังเล่นอัตโนมัติ (จำลองการวัด) — ของจริงคุณใส่คะแนนเอง':'Auto-playing with simulated scores — in real use YOU enter the score')+'</div>');var tail=done?('<div style="margin-top:12px"><button class="btn ghost" onclick="gAuto()" style="font-size:13px;padding:8px 14px">\u21ba '+(th?'เล่นใหม่':'replay')+'</button> <span style="font-size:12px;color:#8890a8;margin-left:8px">'+(th?'(โหลดหน้าใหม่เพื่อใส่ตัวแปรของคุณเอง)':'(reload to enter your own variables)')+'</span></div>'):'';document.getElementById('gBody').innerHTML=banner+'<div style="color:#8890a8;font-size:13px">'+(th?'รอบที่':'Round')+' '+gObs.length+'</div><div style="font-size:15px;margin:6px 0;color:#1a1b30">'+gFmt(last.experiment)+' \u2192 '+(th?'คะแนน':'score')+' <b>'+(+last.value).toFixed(2)+'</b></div><div style="font-size:13px;color:#475">'+(th?'ดีที่สุดตอนนี้':'best so far')+': <b>'+(+best.value).toFixed(2)+'</b></div>'+gSpark()+tail;}
|
|
767
|
+
function gStart(){var sp=gReadVars();if(!sp.length){alert(LANG==='th'?'ใส่ตัวแปรอย่างน้อย 1 ตัว (ชื่อ + ต่ำสุด/สูงสุด)':'Add at least one variable (name + min/max).');return;}gSpace=sp;gObs=[];var te=document.getElementById('gtarget');gTarget=te?parseFloat(te.value):NaN;gAsk();}
|
|
768
|
+
try{gRenderVars();}catch(e){}
|
|
769
|
+
function gAsk(){var b={space:gSpace,observations:gObs,goal:gGoal};if(isFinite(gTarget))b.target=gTarget;fetch('/next',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(b)}).then(function(r){return r.json();}).then(function(j){if(j.error){document.getElementById('gBody').innerHTML='<span style="color:#c33">'+j.error+'</span>';return;}gNext=j.next;gAdvice=j.advice||null;gTerritory=j.territory||null;gConfidence=j.confidence||null;gAchiev=j.achievability||null;gInverse=j.inverse||null;gRender(j.best);}).catch(function(){document.getElementById('gBody').innerHTML='<span style="color:#c33">'+gL().err+'</span>';});}
|
|
770
|
+
function gSpark(){if(!gObs||gObs.length<2)return '';var dir=(gGoal==='minimize')?-1:1;var bs=[],b=-Infinity;for(var i=0;i<gObs.length;i++){var v=dir*gObs[i].value;if(v>b)b=v;bs.push(b);}var lo=Math.min.apply(null,bs),hi=Math.max.apply(null,bs),rng=(hi-lo)||1;var W=220,H=44,n=bs.length;var pts=bs.map(function(v,i){var x=n>1?(i/(n-1))*W:0;var y=H-((v-lo)/rng)*(H-6)-3;return x.toFixed(1)+','+y.toFixed(1);}).join(' ');var th=(LANG==='th');return '<div style="margin-top:14px"><div style="font-size:11px;color:#8890a8;text-transform:uppercase;letter-spacing:.3px;margin-bottom:5px">'+(th?'ดีขึ้นเรื่อยๆ ('+n+' ครั้ง)':'best so far — improving ('+n+')')+'</div><svg width="'+W+'" height="'+H+'" viewBox="0 0 '+W+' '+H+'"><defs><linearGradient id="gspg" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#6366f1"/><stop offset="1" stop-color="#14b8a6"/></linearGradient></defs><polyline points="'+pts+'" fill="none" stroke="url(#gspg)" stroke-width="2.5" stroke-linejoin="round" stroke-linecap="round"/></svg></div>';}
|
|
771
|
+
function gTerr(){if(!gTerritory||!gTerritory.classification||gTerritory.classification==='unknown')return '';var th=(LANG==='th');var tc=gTerritory.classification;var tcol=tc==='refine'?'#0e9f6e':(tc==='leap'?'#c0392b':'#b45309');var tlbl=th?(tc==='refine'?'ปรับละเอียด — อยู่ในเขตที่วัดมาแล้ว (ปลอดภัย)':(tc==='leap'?'กระโดดเข้าเขตใหม่ — ยังไม่เคยวัดแถวนี้ คำทำนายคือการเดา (ระวังถ้าการทดลองแพง/อันตราย)':'ก้าวออกนอกเขตเดิมเล็กน้อย')):(tc==='refine'?'safe refinement — inside the measured region':(tc==='leap'?'bold leap into unmeasured territory — the prediction here is a guess':'stepping outward, partly beyond the data'));return '<div style="margin-top:10px;font-size:13px;color:'+tcol+';font-weight:600">\ud83e\udded '+tlbl+'</div>';}
|
|
772
|
+
function gConf(){if(!gConfidence||!gConfidence.recommendation||gConfidence.recommendation==='unknown'||!isFinite(gConfidence.confidence))return '';var th=(LANG==='th');var cf=Math.round(gConfidence.confidence*100);var pi=(gConfidence.pImprove*100).toFixed(1);var col=cf>=95?'#0e7a4f':'#6a6c84';return '<div style="margin-top:8px;font-size:12.5px;color:'+col+'">\ud83c\udfb2 '+(th?('มั่นใจ '+cf+'% ว่าหยุดได้ (โอกาสทดลองต่อแล้วดีกว่า ~'+pi+'%)'):(cf+'% confidence you can stop \u2014 ~'+pi+'% chance the next experiment improves'))+'</div>';}
|
|
773
|
+
function gReach(){if(!gAchiev||!gAchiev.verdict||gAchiev.verdict==='unknown')return '';var th=(LANG==='th');var v=gAchiev.verdict;var col=v==='unreachable'?'#c0392b':(v==='achieved'?'#0e7a4f':'#4338ca');var icon=v==='unreachable'?'⛔':(v==='achieved'?'✓':'🎯');var tgt=(+gAchiev.target),cl=(+gAchiev.ceiling);var msg;if(v==='achieved'){msg=th?('ถึงเป้า '+tgt+' แล้ว (ดีสุดตอนนี้ '+(+gAchiev.bestSoFar)+')'):('target '+tgt+' already met (best '+(+gAchiev.bestSoFar)+')');}else if(v==='reachable'){msg=th?('เป้า '+tgt+' เป็นไปได้ — เพดานประเมิน ~'+cl+' ทำต่อได้'):('target '+tgt+' looks reachable — estimated ceiling ~'+cl+', keep going');}else{msg=th?('เป้า '+tgt+' สูงกว่าเพดานที่ตัวแปรชุดนี้ทำได้ (~'+cl+') — น่าจะไปไม่ถึง ต้องเพิ่มตัวแปรใหม่ หรือผ่อนเป้า'):('target '+tgt+' is above the ceiling these variables can reach (~'+cl+') — likely out of reach; add a new lever or relax the target');}return '<div style="margin-top:8px;font-size:12.5px;color:'+col+';font-weight:600">'+icon+' '+msg+'</div>';}
|
|
774
|
+
function gRecipes(){if(!gInverse||!gInverse.feasible||!gInverse.solutions||!gInverse.solutions.length)return '';var th=(LANG==='th');var fr=gInverse.recipeFreedom;var n=gInverse.solutions.length;var s0=gInverse.solutions[0];var rec=gSpace.map(function(d){return d.name+'='+(+s0.experiment[d.name]).toFixed(2);}).join(' · ');var probe=gInverse.proposedProbe?gSpace.map(function(d){return d.name+'='+(+gInverse.proposedProbe[d.name]).toFixed(2);}).join(' · '):'';var head=th?((fr==='many'?'หลายสูตร':(fr==='few'?'สองสามสูตร':'สูตรเดียว'))+'ที่ให้ผลตรงเป้า '+(+gInverse.target)):((fr==='many'?'Several recipes':(fr==='few'?'A couple of recipes':'One recipe'))+' hit target '+(+gInverse.target));var probeLine=probe?('<div style="font-size:12px;color:#475;margin-top:3px">'+(th?'ลองค่านี้ต่อให้ตรงเป๊ะ: ':'try this next to land precisely: ')+'<b>'+probe+'</b></div>'):'';return '<div style="margin-top:10px;padding:10px 12px;background:#f5f3ff;border:1px solid #ddd6fe;border-radius:10px"><div style="font-size:12.5px;font-weight:700;color:#6d28d9">🧬 '+(th?'ออกแบบย้อนกลับ — ':'Inverse design — ')+head+'</div><div style="font-size:12.5px;color:#33344e;margin-top:3px">'+(th?'เช่น: ':'e.g. ')+'<b>'+rec+'</b> → '+(+s0.value).toFixed(3)+'</div>'+probeLine+'</div>';}
|
|
775
|
+
function gRender(best){var L=gL();var th=(LANG==='th');var advHtml='';if(gAdvice&&gAdvice.recommendation==='STOP'){advHtml='<div style="margin-top:12px;padding:10px 12px;background:#ecfdf5;border:1px solid #a7f3d0;border-radius:10px;color:#0e7a4f;font-size:13.5px;font-weight:600">✓ '+(th?'Melete แนะนำว่าหยุดได้แล้ว — ทดลองต่อไม่น่าจะดีขึ้นพอคุ้ม':'Melete suggests you can stop now — more experiments are unlikely to beat this enough to be worth it')+'</div>';}else if(gAdvice&&gAdvice.recommendation==='CONTINUE'){advHtml='<div style="margin-top:12px;padding:10px 12px;background:#eef2ff;border:1px solid #c7d2fe;border-radius:10px;color:#4338ca;font-size:13.5px;font-weight:600">↗ '+(th?'ยังดีขึ้นอยู่ — ลองต่อได้เลย':'Still improving — keep going')+'</div>';}var bestHtml=best?('<div style="margin-top:12px;color:#475">'+L.best+': <b>'+(+best.value).toFixed(3)+'</b> @ '+gFmt(best.experiment)+'</div>'):'';document.getElementById('gBody').innerHTML='<div style="color:#8890a8;font-size:13px;letter-spacing:.3px">'+L.round+' '+(gObs.length+1)+'</div><div style="font-size:17px;margin:8px 0;color:#1a1b30">'+L.next+':<br>'+gFmt(gNext)+'</div><label style="font-size:13px;color:#475">'+L.score+'</label><br><input id="gScore" type="number" step="any" style="padding:9px;border:1px solid #ccd;border-radius:9px;width:150px;font-size:15px" onkeydown="if(event.keyCode===13)gRecord()" /> <button class="btn primary" style="padding:9px 16px" onclick="gRecord()">'+L.rec+'</button>'+bestHtml+gTerr()+gSpark()+advHtml+gConf()+gReach()+gRecipes();var sc=document.getElementById('gScore');if(sc)sc.focus();}
|
|
776
|
+
function gRecord(){var v=parseFloat((document.getElementById('gScore')||{}).value);if(!isFinite(v))return;gObs.push({experiment:gNext,value:v});gAsk();}
|
|
777
|
+
</script>
|
|
778
|
+
</section>
|
|
779
|
+
<section id="use"><h2 data-i18n="h_use">Use it for your work — answer 3 questions</h2>
|
|
780
|
+
<p class="lead" style="margin:0 0 18px" data-i18n="use_lead">No dataset, no formula. Just answer these about <b>your</b> process:</p>
|
|
781
|
+
<div class="steps">
|
|
782
|
+
<div class="step"><span class="n">1</span><h3 data-i18n="u_q1">What can you adjust?</h3><p data-i18n="q1d">List the knobs + their real limits (your machine's range). <span class="muted">→ that's the SPACE.</span></p></div>
|
|
783
|
+
<div class="step"><span class="n">2</span><h3 data-i18n="u_q2">After one try, what number tells you how good it was?</h3><p data-i18n="q2d">You <b>measure</b> it — taste a score, read accuracy, read revenue. You don't calculate it. <span class="muted">→ that's the SCORE.</span></p></div>
|
|
784
|
+
<div class="step"><span class="n">3</span><h3 data-i18n="u_q3">How many tries can you afford?</h3><p data-i18n="q3d">Brews, training runs, assays you'll pay for. <span class="muted">→ that's the BUDGET.</span></p></div>
|
|
785
|
+
</div>
|
|
786
|
+
<div class="grid" style="margin-top:18px">
|
|
787
|
+
<div class="card"><div class="who">☕ <span data-i18n="ex_cof_l">A coffee shop</span></div><p data-i18n="ex_cof"><b>Knobs:</b> temp 85–96° · grind 1–10 · dose 14–22g<br><b>Score:</b> a barista tastes each shot, 0–10<br><b>Budget:</b> 30 shots → Melete finds the recipe in ~20.</p></div>
|
|
788
|
+
<div class="card"><div class="who">🤖 <span data-i18n="ex_ml_l">An ML team</span></div><p data-i18n="ex_ml"><b>Knobs:</b> learning-rate 0–0.1 · depth 1–12<br><b>Score:</b> the training script prints accuracy<br><b>Budget:</b> 40 runs → fewer GPU-hours to the best model.</p></div>
|
|
789
|
+
</div>
|
|
790
|
+
<p class="lead" style="margin:24px 0 12px;font-size:18px" data-i18n="u_two">Then run it one of two ways:</p>
|
|
791
|
+
<p style="margin:0 0 6px;color:#33344e"><b>A) <span data-i18n="tw_a_b">Connect your process</span></b><span data-i18n="tw_a_d"> — Melete runs it for you and reads the number (this is the real product, like installing a tool):</span></p>
|
|
792
|
+
<pre>melete tune --cmd "python train.py --lr {lr} --depth {depth}" \\
|
|
793
|
+
--space '[{"name":"lr","type":"real","min":0,"max":0.1},{"name":"depth","type":"int","min":1,"max":12}]'</pre>
|
|
794
|
+
<p style="margin:16px 0 6px;color:#33344e"><b>B) <span data-i18n="tw_b_b">From an agent or pipeline</span></b><span data-i18n="tw_b_d"> — call the HTTP API or the library; your code returns the score each step:</span></p>
|
|
795
|
+
<pre>POST https://melete.mneme-ai.space/discover · npm i melete-ai · discoverSigned({ space, oracle })</pre>
|
|
796
|
+
<p class="muted" style="margin-top:14px" data-i18n="sandbox"><b>This website = a sandbox to try it.</b> Real work = connect your real process (A or B). 🔒 Air-gapped: zero dependencies + local signing ⇒ runs fully offline, result still verifiable.</p></section>
|
|
797
|
+
|
|
798
|
+
</div>
|
|
799
|
+
<footer>
|
|
800
|
+
<span data-i18n="foot_honest">Honest: the engine is a context-adaptive ensemble — its guarantee is robustness + verifiable provenance, measured & reproducible (not a single "magic" algorithm).</span><br>
|
|
801
|
+
<a href="/pitch">Pitch deck</a> · <a href="/health">/health</a> · Melete v${version} · the discovery muse
|
|
802
|
+
</footer>
|
|
803
|
+
|
|
804
|
+
<script>
|
|
805
|
+
var LANG='en';try{var _sl=localStorage.getItem('mlang');if(_sl)LANG=_sl;}catch(e){}
|
|
806
|
+
var T={
|
|
807
|
+
en:{flabEye:'FRONTIER LAB · DEEP-TECH, PROVEN',flabH:'The 3 ways optimizers die in the real world — engineered out, every one proven',flabP:'Each button runs the REAL Melete engine via the on-box API. Numbers are live, not canned. Press one.',flabNoiseT:'📡 Noise-Robust',flabNoiseD:'A noisy signal that reads 99% then 40% — find the value you can TRUST, not a lucky spike.',flabMixedT:'🧩 Mixed-Space',flabMixedD:'Categorical + integer + conditional knobs (storage engine, thread count) — not just dials.',flabProvT:'📜 Provenance Seal',flabProvD:'A 24/7 run history sealed into a constant-size, signed, tamper-evident proof.',flabRun:'▶ run live',flabUseEye:'USE IT ON YOUR OWN SYSTEM',flabUseH:'These demos used a formula. On your machine, the “oracle” is YOUR real measurement.',flabUse1:'① Define your knobs (the settings you can change) + your score (what you measure — a yield %, a latency, a benchmark, an assay readout).',flabUse2:'② Point the oracle at YOUR system — a function that runs your real process / calls your API / reads your instrument and returns that score. The same proven engine searches it.',flabUse3:'③ Runs fully on your machine (sovereign — your data never leaves); every result is Ed25519-signed for your audit / patent trail.',flabUseCap:'Self-host the same engine (npm) and plug in your real measurement:',flabUseApi:'…or POST a JS-expression objective to the hosted API for a quick formula test: /discover · /mixed · /noise-robust',watch:'▶ Watch Melete discover',replay:'▶ Replay',team:"Meli's team — who did the work",teamhint:"Expert detail: the helpers Meli used. You don't need this to use the result.",climb:'How the score climbed (higher = better)',cinema:'Discovery cinema — watch Meli search',scenarioL:'Scenario',knobs:'You adjust',score:'You score',budget:'Tries',ph:'Pick a scenario, then press Watch.',plainHdr:'Summary',tried:'Melete tried',settings:'settings and zeroed in on the best one',eyebrow:'The Sovereign Verifiable AI Analyst & Optimizer',ctaTry:'See it discover (live) →',ctaPitch:'The 60-second pitch',h_what:'What it does — one example',h_meli:'Meet Meli — a tiny story',h_how:'How it works — 3 steps',h_who:"Who it's for & what they get",h_see:'See it discover — just watch',see_lead:'👇 Just press the purple button and watch. Melete tests settings one by one and zeroes in on the best — like the coffee story above, but live.',see_sub:'This is a demo, so the "score" is calculated instantly by a formula. In real life, the score is whatever YOU measure (a taste rating, a yield %, a benchmark) — and you type it in. <a href="#use">How to use it for your own work →</a>',h_ind:'Click an industry — see Melete work on it',h_proven:'Proven, not claimed',h_use:'Use it for your work — answer 3 questions',heroTag:'Tell Melete what you can change and what <b>"good"</b> means. It finds the <b>best recipe in the fewest real-world experiments</b> — then tells you exactly what to do with it.',heroSub:'Analyze · optimize · certify — on your machine (sovereign), data never leaves, every verdict cryptographically signed & verifiable offline.',ctaApi:'🔌 Connect via API',pill1:'🎯 best answer, fewest tries',pill2:'🚀 no data needed — starts from scratch',pill3:'🔒 runs on your machine',pill4:'🔏 every answer signed',hs1:'verified engines',hs2:'of the true optimum, every benchmark',hs3:'on your machine · signed',hs4:'one brain, smart about everything',m60_eye:'Understand the whole thing in 60 seconds',m60_h:'What Melete is — in one minute',m60_p:'You have a system you can <b>measure</b> — an ML pipeline, a server/DB/network config, a recipe, a simulation. Melete finds the best <b>and most robust</b> setting in the fewest experiments, explains why in plain language, and hands you a <b>signed verdict you (or an auditor) can re-verify offline</b>. It runs on your machine — your data never leaves.',m60_s1:'<b>Tell it</b> what you can change + what "good" means',m60_s2:'<b>It proposes</b> a setting → you measure it (or give a formula) → repeat',m60_s3:'<b>You get</b> the best robust recipe + a signed, replayable verdict',m60_inside:'Inside: 43 engines, organized as 4 layers',lay1:'find the best setting in the fewest tries',lay2:'the Φ brain — a safety-first call + 🛡 the robust one',lay3:'plain-language why: which knobs, cliffs, shape, ceiling',lay4:'signed, offline-verifiable, step-by-step replayable',gal_eye:'Live demo — pick your world, press one button',gal_h:'See Melete run on YOUR industry',gal_p:'Each card runs the <b>real Melete engine</b> on a simulated, industry-shaped problem — then sums up the result in plain language (every number is from the real run). In production you connect your own system as the oracle.',gal_note:'⚠ Simulated environments (real engine, real signed verdict). No live link to any satellite/grid — connect your own telemetry as the oracle in production.',g_auto:'▶ Watch Melete solve it (auto)',mo_eyebrow:'MULTI-OBJECTIVE',mo_h:'Optimize several goals at once — see the trade-offs',mo_sub:'Real problems have competing goals — more yield AND less cost. There is no single best, so Melete finds the Pareto front: the set of best-possible trade-offs. Define your goals + variables, run the propose-measure-repeat loop scoring each objective, and watch the front fill in.',g_howreal:'<b>Using Melete in your real project — 2 ways:</b><br><b>1) Through this website (no code)</b> — for slow / expensive hand-measured experiments: Melete proposes, you run it in your lab/system, you type the score. Best for physical experiments you measure by hand anyway.<br><b>2) Connected & automated</b> — <code>melete tune</code>, <code>POST /next</code>, or the npm library, on YOUR own servers (air-gapped): your code runs each test and feeds the score back in a loop. Best for benchmarks, simulations, pipelines.',g_pickopt:'Choose your field…',gs_h:'How it works — 4 steps',gs1:'Tell Melete what you can change — or pick your field above',gs2:'Melete proposes the exact next setting to try',gs3:'You run it for real and type the score you measured',gs4:'Repeat ~20–40× → the best config + a signed proof',g_ex:'<b>Example — AI security engineer:</b> adjust <b>[filter threshold · temperature · rate limit]</b>, then measure <b>[% of red-team attacks your system blocks]</b> as the score. Melete proposes the next config → you run your attack suite → type the % → repeat → it finds the safest config in the fewest tests.',vf_eyebrow:'VERIFY · NO TRUST NEEDED',vf_h:'Verify any Proof of Optimization — offline',vf_sub:'Optional — for auditors & reviewers; you do NOT need this to use Melete. After you run a discovery and download its certificate, anyone can drop it here to check it — it recomputes the efficiency claim and verifies the Ed25519 signature with the public key embedded in the certificate. New here? Press “Load a sample”.',vf_sample:'▶ Load a sample',vf_btn:'Verify certificate',sim_note:'<b>You do NOT write these formulas.</b> This box is a browser simulation so you can watch the algorithm work. A pharma researcher (or anyone) uses the no-formula guided mode — enter your variables (pH, temperature…), make the recipe, measure the real result, type the score.',sim_btn:'👉 No-formula mode',nf_h:'Use it on your real process — no formula, no code.',nf_sub:'The demo below needs a formula (for developers). To use Melete on your real process with no formula — it proposes, you measure, you type the score — use the guided mode.',nf_btn:'👉 Use the no-formula mode',g_pick:'Start from your industry — or edit the variables yourself:',g_addvar:'add variable',pr_eyebrow:'PRICING',pr_h:'Start free. Pay when it saves you money.',pr_sub:'The value is fewer expensive experiments, certified — so you only pay once Melete is already saving you more than it costs.',pr_pop:'POPULAR',pr_free_name:'Free',pr_free_price:'$0',pr_free_tag:'Open web + CLI, forever',pr_free_f:'✓ Run discoveries<br>✓ Signed, replicable trace<br>✓ Optimality certificate<br>✓ No signup',pr_free_btn:'▶ Try it now',pr_pro_name:'Pro',pr_pro_price:'Early access',pr_pro_tag:'For teams on a real process',pr_pro_f:'✓ Connect your process via API<br>✓ Reliable mode + batch runs<br>✓ Priority support<br>✓ Private workspace',pr_pro_btn:'Talk to us',pr_ent_name:'Enterprise',pr_ent_price:'Air-gapped',pr_ent_tag:'Regulated + on-prem',pr_ent_f:'✓ Runs fully offline — data never leaves<br>✓ Signed proof for audits and patents<br>✓ SLA + onboarding<br>✓ Self-hosted',pr_ent_btn:'Talk to us',pf_eyebrow:'PROVEN · MEASURED · CERTIFIED',pf_h:'≥99% of the true optimum — on every landscape',pf_sub:'Most optimizers win on easy surfaces and quietly fail on the hard ones. Melete is benchmarked on 7 deliberately adversarial landscapes, each normalised so the score is literally the % of the true optimum reached — and it clears ≥99% on every one, every seed.',pf_engine:'How: a 3-paradigm engine — portfolio global-explore → certificate-guided Lipschitz infill → Nelder–Mead polish. Every result also carries an optimality certificate: a provable bound on how much better the true best could be.',pf_avg:'average of the true optimum reached',pf_avg2:'across 7 adversarial landscapes · every seed · ≥99% on every single one — including the brutal ones (Rosenbrock\\'s banana valley, a 5-D haystack, a lone needle).',pf_note:'Reproducible: this is the open reliability gauntlet — re-run it and check every number yourself.',rel_lbl:'⚡ Reliable mode — add a Nelder–Mead polish (slower; nails hard curved valleys to the true optimum)',btn_contact:'Contact the maker',use_lead:'No dataset, no formula. Just answer these about <b>your</b> process:',q1d:'List the knobs + their real limits (the range of your machine). <span class="muted">→ this is the SPACE.</span>',q2d:'You <b>measure</b> it — taste a score, read accuracy, read revenue. You do not calculate it. <span class="muted">→ this is the SCORE.</span>',q3d:'Brews, training runs, assays you pay for. <span class="muted">→ this is the BUDGET.</span>',ex_cof:'<b>Knobs:</b> temp 85–96° · grind 1–10 · dose 14–22g<br><b>Score:</b> a barista tastes each shot, 0–10<br><b>Budget:</b> 30 shots → Melete finds the recipe in ~20.',ex_ml:'<b>Knobs:</b> learning-rate 0–0.1 · depth 1–12<br><b>Score:</b> the training script prints accuracy<br><b>Budget:</b> 40 runs → fewer GPU-hours to the best model.',ex_cof_l:'A coffee shop',ex_ml_l:'An ML team',tw_a_b:'Connect your process',tw_a_d:' — Melete runs it for you and reads the number (this is the real product, like installing a tool):',tw_b_b:'From an agent or pipeline',tw_b_d:' — call the HTTP API or the library; your code returns the score each step:',sandbox:'<b>This website = a sandbox to try it.</b> Real work = connect your real process (A or B). 🔒 Air-gapped: zero dependencies + local signing ⇒ runs fully offline, result still verifiable.',prov_intro:'No single optimiser wins on every landscape. A bandit spends each experiment on whichever strategy is winning <i>on your problem</i> — one engine, no per-problem tuning.',btn_pitch:'Read the pitch',cta_body:'Built by one developer who genuinely loves this stuff. Got a question, an idea, or a process you want to try it on? Just reach out — happy to chat.',tl_land:'landscape',tl_bay:'single Bayesian',tl_rand:'random',tl_smooth:'smooth',tl_rug:'rugged (many traps)',tl_hd:'high-dimensional',tl_best:'best 🏆 beats every single algorithm',tl_far:'far behind',u_q1:'What can you adjust?',u_q2:'After one try, what number tells you how good it was?',u_q3:'How many tries can you afford?',u_two:'Then run it one of two ways:',cta_h:'Like Melete? Talk to the maker.',foot_honest:'Honest: the engine is a context-adaptive ensemble — its guarantee is robustness + verifiable provenance, measured & reproducible (not a single "magic" algorithm).',g_h:'Use it on your real process — you measure',g_intro:'No code, no formula. Melete proposes the next experiment; you go run it for real and type the score back; it proposes the next — converging to the best in as few real tries as possible. (Demo space below: espresso temp · grind · dose. Connect your own process through the API.)',g_start:'▶ Start guiding',g_target:'🎯 Target (optional)',g_targethint:'the score you need — Melete tells you if it is reachable with these variables',ind_intro:'The browser score is a simulated model</b> of the process — the <b>optimisation is real & reproducible</b>; connect your real assay / benchmark / process for real numbers.',t_pharma:'Drug formulation',t_gpu:'GPU kernel tuning',t_etch:'Plasma-etch process',t_llm:'LLM serving config',t_esp:'Best espresso recipe',d_pharma:'Variables: pH · temperature · excipient %. Goal: stability / potency. Melete finds the most stable formulation in ~60 assays — instead of hundreds.',d_gpu:'Variables: tile size · unroll · occupancy. Goal: throughput (GFLOP/s). Find the fastest config in ~50 benchmark runs.',d_etch:'Variables: power · pressure · time. Goal: wafer yield %. Tune the recipe to maximum yield — air-gapped, on-prem.',d_llm:'Variables: batch size · KV-cache · quantization. Goal: tokens/sec at a quality bar. Melete optimises AI infrastructure too — and can tune prompts, agents & routing the same way.',d_esp:'Variables: temp · grind · dose. Goal: taste. The friendliest way to watch the idea click.',runnow:'▶ Run it now',sb1:'Once upon a time, a little coffee shop wished for the <b>most delicious espresso in the world</b>.',sb2:'But there were <b>thousands of ways</b> to make it — and every single test meant brewing, and tasting, a whole cup. Trying them all? <b>Impossible.</b>',sb3:'Then came <b>Meli</b> — who never tries everything. Meli looks, thinks, and the little light glows: <i>“brew <b>this</b> one next.”</i>',sb4:'You brew it, you taste it — <b>7 out of 10</b>. Meli smiles, <b>learns</b>, and picks an even smarter cup. 8.5… 9.2…',sb5:'In about <b>twenty cups</b>, Meli found the <b>perfect recipe</b> — and sealed a magical <b>proof</b> of how, so the whole world could trust it. <b>The end ✨</b>',st1h:'Set the dials',st1p:'List what you can change and its range — temperature 85–96°, learning-rate 0–0.1, price $1–100.',st2h:'Score one try',st2p:'Your real process returns one number: brew → taste, train → accuracy, price → revenue. No dataset needed.',st3h:'Discover & prove',st3p:'Melete proposes the next experiment, learns, converges to the best — and signs a verifiable trace of how.',wh1:'Tune learning rates, architectures, RAG/serving configs, compiler flags — fewer GPU-hours to the best model, with a provable tuning record.',wh2:'Find the reagent mix / conditions that maximise yield or potency in far fewer assays — and a tamper-proof discovery trail for patents & audits.',wh3:'Tune deposition / etch / print parameters against real KPIs on-prem — air-gapped, data never leaves the fab, result still verifiable.',wh4:'Search price points, configurations, and policies where each test is costly — converge faster than grid or manual search.',story:'<p style="font-size:19px;font-weight:600;color:#1a1b30;margin-bottom:14px">You run a coffee shop and want the <b>best espresso</b>. You can change three things — water temperature, grind, and how many grams of coffee. Thousands of combinations, and each test means <b>brewing a cup and tasting it</b>. You can’t try them all.</p><p style="color:#33344e;margin-bottom:6px">Melete is like a brilliant assistant who tells you the next cup to brew:</p><div class="chat">☕ Melete: “Try <b>92°, grind 6, 18g</b>.” → you brew it, taste it: <b>7/10</b>.</div><div class="chat">☕ Melete: “Now try <b>93°, grind 5, 19g</b>.” → you taste: <b>8.5/10</b>.</div><div class="chat" style="opacity:.6">… a few more …</div><div class="chat">🎯 After ~<b>20 cups</b> it found your best recipe — instead of randomly trying 200.</div><p style="color:#33344e;margin-top:14px">Swap “coffee” for a <b>training run</b>, a <b>chemical reaction</b>, or a <b>price</b> — same idea: Melete finds the best settings in the <b>fewest expensive tries</b> and signs a <b>proof</b> of how.</p>',winning:'The winning setup',signed:'Every step is cryptographically signed — the result is independently verifiable. No faking, no guessing.'},
|
|
808
|
+
th:{flabEye:'ห้องแล็บแนวหน้า · DEEP-TECH พิสูจน์แล้ว',flabH:'3 จุดตายของ optimizer ในโลกจริง — เราออกแบบให้รอดทุกข้อ และพิสูจน์ทุกตัว',flabP:'แต่ละปุ่มรัน engine จริงของ Melete ผ่าน API บนเครื่อง ตัวเลขสดจริง ไม่ใช่ของปลอม กดเลย',flabNoiseT:'📡 ทนสัญญาณรบกวน',flabNoiseD:'สัญญาณที่อ่านได้ 99% แล้ว 40% — หาค่าที่ “เชื่อถือได้” ไม่ใช่ค่าฟลุค',flabMixedT:'🧩 ตัวแปรผสม',flabMixedD:'categorical + integer + conditional (storage engine, thread count) ไม่ใช่แค่ลูกบิด',flabProvT:'📜 ตราผนึกประวัติ',flabProvD:'ประวัติการรัน 24/7 ผนึกเป็นหลักฐานขนาดคงที่ เซ็นแล้ว แก้ไม่ได้',flabRun:'▶ รันสด',flabUseEye:'ใช้กับระบบจริงของคุณ',flabUseH:'เดโมพวกนี้ใช้สูตรจำลอง แต่บนเครื่องคุณ “oracle” คือการวัดผลจริงของคุณเอง',flabUse1:'① กำหนดปุ่มที่คุณปรับได้ + คะแนนที่คุณวัด (yield %, latency, ผลเบนช์มาร์ก, ค่าจาก assay)',flabUse2:'② ชี้ oracle ไปที่ระบบของคุณ — ฟังก์ชันที่รันกระบวนการจริง / เรียก API / อ่านค่าจากเครื่องมือ แล้วคืนคะแนนนั้น engine ตัวเดิมที่พิสูจน์แล้วจะค้นหาให้',flabUse3:'③ รันบนเครื่องคุณทั้งหมด (sovereign — ข้อมูลไม่ออกไปไหน) ทุกผลลัพธ์เซ็น Ed25519 ไว้ใช้ยื่นตรวจ/จดสิทธิบัตร',flabUseCap:'รัน engine ตัวเดียวกันเอง(npm) แล้วเสียบการวัดผลจริงของคุณเข้าไป:',flabUseApi:'…หรือ POST objective แบบสูตร JS ไปที่ API ที่โฮสต์ไว้ เพื่อทดสอบเร็วๆ: /discover · /mixed · /noise-robust',watch:'▶ ดู Melete ค้นพบ',replay:'▶ เล่นใหม่',team:'ทีมของ Meli — ใครลงมือบ้าง',teamhint:'รายละเอียดผู้เชี่ยวชาญ: ผู้ช่วยที่ Meli ใช้ ไม่จำเป็นต้องรู้ก็ใช้ผลได้',climb:'คะแนนไต่ขึ้นยังไง (สูง = ดี)',cinema:'โรงหนังการค้นพบ — ดู Meli ค้นหา',scenarioL:'เลือกสถานการณ์',knobs:'สิ่งที่ปรับได้',score:'วัดเป็นคะแนน',budget:'จำนวนครั้ง',ph:'เลือกสถานการณ์ แล้วกดดู',plainHdr:'สรุป',tried:'Melete ลอง',settings:'แบบ แล้วล็อกแบบที่ดีที่สุด',eyebrow:'AI วิเคราะห์ · ตรวจสอบ · ปรับแต่ง ที่รันในตึกคุณเอง',ctaTry:'ลองใช้งาน →',ctaPitch:'พิตช์ 60 วินาที',h_what:'Melete ทำอะไร — ตัวอย่างเดียวจบ',h_meli:'รู้จัก Meli — นิทานสั้น ๆ',h_how:'ทำงานยังไง — 3 ขั้น',h_who:'ใครใช้ได้ & ได้อะไร',h_see:'ดู Melete ค้นพบ — แค่กดดู',see_lead:'👇 แค่กดปุ่มสีม่วงแล้วดู Melete จะลองค่าทีละชุดแล้วค่อยๆ เจาะหาค่าที่ดีที่สุด — เหมือนเรื่องกาแฟด้านบน แต่ดูสดๆ',see_sub:'นี่คือตัวอย่างสาธิต "คะแนน" เลยคำนวณจากสูตรให้ทันที ในชีวิตจริงคะแนนคือสิ่งที่<b>คุณวัดเอง</b> (คะแนนรสชาติ · % ที่ได้ · ผลเบนช์มาร์ก) แล้วพิมพ์ใส่ <a href="#use">วิธีเอาไปใช้กับงานคุณ →</a>',h_ind:'เลือกอุตสาหกรรม — ดู Melete ทำงานจริง',h_proven:'พิสูจน์ได้ ไม่ใช่แค่พูด',h_use:'ใช้กับงานของคุณ — ตอบ 3 คำถาม',heroTag:'บอก Melete ว่าคุณปรับอะไรได้ และคำว่า <b>"ดี"</b> คืออะไร — มันจะหา<b>สูตรที่ดีที่สุดด้วยการทดลองจริงน้อยครั้งที่สุด</b> แล้วบอกชัดๆ ว่าให้ลงมือทำอะไรต่อ',heroSub:'วิเคราะห์ · ปรับแต่ง · รับรอง — รันในตึกคุณ (sovereign) ข้อมูลไม่ออกไปไหน ทุกคำตัดสินเซ็นด้วยคริปโต ตรวจ offline ได้',ctaApi:'🔌 เชื่อมต่อผ่าน API',pill1:'🎯 คำตอบที่ดีที่สุด ลองน้อยครั้งสุด',pill2:'🚀 ไม่ต้องมีข้อมูลก่อน — เริ่มจากศูนย์ได้',pill3:'🔒 รันบนเครื่องคุณเอง',pill4:'🔏 ทุกคำตอบมีลายเซ็น',hs1:'เครื่องยนต์ที่พิสูจน์แล้ว',hs2:'ของจุดที่ดีที่สุดจริง ทุกเบนช์มาร์ก',hs3:'รันบนเครื่องคุณ · เซ็นยืนยัน',hs4:'สมองเดียว ฉลาดทุกเรื่อง',m60_eye:'เข้าใจทั้งระบบใน 60 วินาที',m60_h:'Melete คืออะไร — ใน 1 นาที',m60_p:'คุณมีระบบที่ <b>วัดผลได้</b> — ML pipeline, config ของ server/DB/network, สูตร, หรือ simulation. Melete หาค่าที่<b>ดีที่สุดและทนทานที่สุด</b>ด้วยการทดลองน้อยครั้งสุด อธิบายเหตุผลเป็นภาษาคน และให้ <b>คำตัดสินที่เซ็น ตรวจซ้ำได้เองแบบ offline</b> — รันบนเครื่องคุณ ข้อมูลไม่ออกไปไหน',m60_s1:'<b>บอกมัน</b>ว่าปรับอะไรได้ + คำว่า "ดี" คืออะไร',m60_s2:'<b>มันเสนอ</b>ค่าหนึ่ง → คุณวัดผล (หรือใส่สูตร) → วนซ้ำ',m60_s3:'<b>คุณได้</b>สูตรที่ดี+ทน + คำตัดสินที่เซ็น เล่นซ้ำได้',m60_inside:'ภายใน: 43 เครื่องยนต์ จัดเป็น 4 ชั้น',lay1:'หาค่าที่ดีที่สุด ในจำนวนครั้งน้อยสุด',lay2:'คำตัดสินของสมอง Φ ที่ปลอดภัยมาก่อน + 🛡 ตัวที่ทนทาน',lay3:'บอกเหตุผลภาษาคน: ปุ่มไหนสำคัญ หน้าผา รูปทรง เพดาน',lay4:'เซ็นแล้ว ตรวจ offline ได้ เล่นซ้ำทีละขั้น',gal_eye:'ลองสด — เลือกวงการคุณ กดปุ่มเดียว',gal_h:'ดู Melete ทำงานบนวงการของคุณ',gal_p:'แต่ละการ์ดรัน <b>engine จริงของ Melete</b> บนโจทย์จำลองทรงอุตสาหกรรมนั้น — แล้วสรุปผลให้คุณเข้าใจง่ายเป็นภาษาคน (ทุกตัวเลขมาจากผลรันจริง). ใน production คุณต่อระบบของคุณเองเป็น oracle',gal_note:'⚠ สภาพแวดล้อมจำลอง (engine จริง ใบรับรองเซ็นจริง) ไม่มีการต่อดาวเทียม/กริดจริง — ต่อ telemetry ของคุณเองเป็น oracle ใน production',g_auto:'▶ ดู Melete ทำงานเอง (อัตโนมัติ)',mo_eyebrow:'หลายเป้าหมาย',mo_h:'optimize หลายเป้าพร้อมกัน — เห็น trade-off',mo_sub:'ปัญหาจริงมีเป้าที่ขัดกัน — ผลผลิตมากขึ้นแต่ต้นทุนต้องน้อยลง ไม่มีดีที่สุดตัวเดียว Melete จึงหา Pareto front: เซตของจุดแลกเปลี่ยนที่ดีที่สุด ตั้งเป้าหมาย + ตัวแปร แล้วรันลูปเสนอ-วัด-ใส่คะแนนแต่ละเป้า ดู front ค่อยๆ เต็มขึ้น',g_howreal:'<b>เอาไปใช้จริงในโปรเจค — 2 ทาง:</b><br><b>1) ผ่านเว็บนี้ (ไม่ต้องเขียนโค้ด)</b> — สำหรับการทดลองที่ช้า/แพง วัดด้วยมือ: Melete เสนอ คุณไปทำจริงในแล็บ/ระบบ แล้วพิมพ์คะแนน เหมาะกับการทดลองจริงที่ยังไงก็ต้องวัดเองอยู่แล้ว<br><b>2) เชื่อมระบบอัตโนมัติ</b> — <code>melete tune</code>, <code>POST /next</code> หรือ npm library รันบนเซิร์ฟเวอร์ของคุณเอง (air-gapped): โค้ดของคุณรันการทดสอบเองแล้วป้อนคะแนนกลับวนลูป เหมาะกับ benchmark, simulation, pipeline <a href="/docs" style="font-weight:700;color:#b45309">→ คู่มือ API</a>',g_pickopt:'เลือกสายงานของคุณ…',gs_h:'ใช้งานยังไง — 4 ขั้น',gs1:'บอก Melete ว่าปรับอะไรได้ — หรือเลือกสายงานด้านบน',gs2:'Melete บอกค่าถัดไปที่ควรลอง แบบเป๊ะๆ',gs3:'คุณไปทำจริง แล้วพิมพ์คะแนนที่วัดได้',gs4:'วนซ้ำ ~20–40 ครั้ง → ได้ config ดีสุด + ใบรับรองที่เซ็นแล้ว',g_ex:'<b>ตัวอย่าง — วิศวกรความปลอดภัย AI:</b> ปรับ <b>[ความเข้มฟิลเตอร์ · temperature · rate limit]</b> แล้ววัด <b>[% การโจมตีจาก red-team ที่ระบบบล็อกได้]</b> เป็นคะแนน Melete เสนอ config ถัดไป → คุณรันชุดโจมตี → ใส่ % → วนซ้ำ → เจอ config ที่ปลอดภัยสุดในจำนวนเทสน้อยสุด',vf_eyebrow:'ตรวจสอบ · ไม่ต้องเชื่อเรา',vf_h:'ตรวจสอบใบรับรอง Proof of Optimization — แบบ offline',vf_sub:'เป็นของ optional — สำหรับผู้ตรวจสอบ ไม่จำเป็นต่อการใช้งาน Melete หลังจากคุณรัน discovery แล้วกดดาวน์โหลดใบรับรอง ใครก็ลากไฟล์มาวางตรงนี้เพื่อตรวจได้ — ระบบคำนวณตัวเลขซ้ำ + ตรวจลายเซ็น Ed25519 ด้วย public key ที่ฝังในใบเอง · ยังไม่มีไฟล์? กด “ดูตัวอย่าง”',vf_sample:'▶ ดูตัวอย่าง',vf_btn:'ตรวจสอบใบรับรอง',sim_note:'<b>คุณไม่ต้องเขียนสูตรพวกนี้</b> กล่องนี้คือการจำลองในเบราว์เซอร์ไว้ดูอัลกอริทึมทำงาน นักวิจัยยา (หรือใครก็ตาม) ใช้โหมดไม่ต้องมีสูตร — ใส่ตัวแปรของคุณ (pH, อุณหภูมิ…) ผสมสูตร วัดผลจริง แล้วใส่คะแนน',sim_btn:'👉 โหมดไม่ต้องมีสูตร',nf_h:'ใช้กับงานจริงของคุณได้เลย — ไม่ต้องมีสูตร ไม่ต้องเขียนโค้ด',nf_sub:'เดโมด้านล่างต้องใส่สูตร (สำหรับนักพัฒนา) ถ้าจะใช้ Melete กับงานจริงโดยไม่ต้องมีสูตร — มันเสนอ คุณวัด คุณใส่คะแนน — ใช้โหมด guided',nf_btn:'👉 ใช้โหมดไม่ต้องมีสูตร',g_pick:'เริ่มจากอุตสาหกรรมของคุณ — หรือแก้ตัวแปรเองก็ได้:',g_addvar:'เพิ่มตัวแปร',pr_eyebrow:'ราคา',pr_h:'เริ่มฟรี จ่ายเมื่อมันช่วยคุณประหยัดเงิน',pr_sub:'คุณค่าคือลดจำนวนการทดลองที่แพง พร้อมใบรับรอง — จ่ายก็ต่อเมื่อ Melete ช่วยประหยัดได้มากกว่าค่าใช้จ่ายแล้ว',pr_pop:'ยอดนิยม',pr_free_name:'ฟรี',pr_free_price:'$0',pr_free_tag:'เว็บ + CLI แบบเปิด ตลอดไป',pr_free_f:'✓ รัน discovery ได้เต็ม<br>✓ ใบบันทึกที่เซ็น+ตรวจซ้ำได้<br>✓ ใบรับรองความเหมาะที่สุด<br>✓ ไม่ต้องสมัคร',pr_free_btn:'▶ ลองเลย',pr_pro_name:'Pro',pr_pro_price:'Early access',pr_pro_tag:'สำหรับทีมที่มีกระบวนการจริง',pr_pro_f:'✓ เชื่อมกระบวนการของคุณผ่าน API<br>✓ Reliable mode + รันเป็นชุด<br>✓ ซัพพอร์ตลำดับแรก<br>✓ พื้นที่ทำงานส่วนตัว',pr_pro_btn:'คุยกับเรา',pr_ent_name:'Enterprise',pr_ent_price:'Air-gapped',pr_ent_tag:'องค์กรคุมเข้ม + รันในองค์กร',pr_ent_f:'✓ รันออฟไลน์เต็มที่ — ข้อมูลไม่ออกจากองค์กร<br>✓ ใบพิสูจน์ที่เซ็น สำหรับ audit และสิทธิบัตร<br>✓ SLA + ช่วยตั้งระบบ<br>✓ ติดตั้งเองในเซิร์ฟเวอร์คุณ',pr_ent_btn:'คุยกับเรา',pf_eyebrow:'พิสูจน์แล้ว · วัดได้ · มีใบรับรอง',pf_h:'≥99% ของจุดที่ดีที่สุดจริง — บนทุกภูมิทัศน์',pf_sub:'optimizer ส่วนใหญ่ชนะบนสนามง่าย แล้วแอบแพ้บนสนามยาก Melete ถูกทดสอบบน 7 ภูมิทัศน์ที่ออกแบบให้โหด แต่ละสนามปรับให้คะแนน = %ของจุดที่ดีที่สุดจริง — และผ่าน ≥99% ทุกสนาม ทุก seed',pf_engine:'ทำได้ยังไง: เครื่องยนต์ 3 พาราไดม์ — portfolio สำรวจทั่ว → infill นำทางด้วยใบรับรอง (Lipschitz) → ขัดเงา Nelder–Mead และทุกผลลัพธ์มีใบรับรองความเหมาะที่สุด: ขอบเขตที่พิสูจน์ได้ว่าของจริงดีกว่านี้ได้ไม่เกินเท่าไร',pf_avg:'ของจุดที่ดีที่สุดจริง (เฉลี่ย)',pf_avg2:'บน 7 ภูมิทัศน์สุดโหด · ทุก seed · ผ่าน ≥99% ทุกสนาม — รวมสนามโคตรโหด (หุบเขากล้วย Rosenbrock, เข็มในมหาสมุทร 5 มิติ, เข็มโดดเดี่ยว)',pf_note:'ตรวจซ้ำได้: นี่คือ reliability gauntlet แบบเปิด — รันเองแล้วเช็คทุกตัวเลขได้',rel_lbl:'⚡ โหมด Reliable — เพิ่มการขัดเงาแบบ Nelder–Mead (ช้าลง แต่พิชิตหุบเขายากให้ถึงจุดที่ดีที่สุดจริง)',btn_contact:'ติดต่อคนทำ',use_lead:'ไม่ต้องมีชุดข้อมูล ไม่ต้องมีสูตร แค่ตอบ 3 ข้อนี้เกี่ยวกับ<b>งานของคุณ</b>:',q1d:'ระบุปุ่มที่ปรับได้ + ขีดจำกัดจริง (ช่วงของเครื่องคุณ) <span class="muted">→ นี่คือ SPACE</span>',q2d:'คุณ<b>วัด</b>มัน — ชิมให้คะแนน อ่านความแม่น อ่านยอดขาย ไม่ต้องคำนวณเอง <span class="muted">→ นี่คือ SCORE</span>',q3d:'จำนวนการชง การเทรน การทดลองที่คุณต้องจ่าย <span class="muted">→ นี่คือ BUDGET</span>',ex_cof:'<b>ปุ่ม:</b> อุณหภูมิ 85–96° · บด 1–10 · ปริมาณ 14–22g<br><b>คะแนน:</b> บาริสต้าชิมแต่ละช็อต ให้ 0–10<br><b>งบ:</b> 30 ช็อต → Melete เจอสูตรใน ~20 ช็อต',ex_ml:'<b>ปุ่ม:</b> learning-rate 0–0.1 · depth 1–12<br><b>คะแนน:</b> สคริปต์เทรนพิมพ์ค่าความแม่น<br><b>งบ:</b> 40 รอบ → ใช้ GPU น้อยลงกว่าจะได้โมเดลที่ดีที่สุด',ex_cof_l:'ร้านกาแฟ',ex_ml_l:'ทีม ML',tw_a_b:'เชื่อมต่อกระบวนการของคุณ',tw_a_d:' — Melete รันให้คุณแล้วอ่านค่าตัวเลขเอง (นี่คือตัวโปรดักต์จริง เหมือนติดตั้งเครื่องมือ):',tw_b_b:'จาก agent หรือ pipeline',tw_b_d:' — เรียก HTTP API หรือไลบรารี; โค้ดของคุณคืนคะแนนกลับมาในแต่ละขั้น:',sandbox:'<b>เว็บนี้ = สนามทดลอง</b> งานจริง = เชื่อมต่อกระบวนการจริงของคุณ (ทาง A หรือ B) 🔒 Air-gapped: ไม่มี dependency + เซ็นในเครื่อง ⇒ รันออฟไลน์ได้เต็มที่ ผลยังตรวจสอบได้',prov_intro:'ไม่มีอัลกอริทึมเดียวที่ชนะทุกภูมิทัศน์ปัญหา bandit จะทุ่มแต่ละการทดลองให้กลยุทธ์ที่กำลังชนะ<i>บนปัญหาของคุณ</i> — เอนจินเดียว ไม่ต้องจูนรายปัญหา',btn_pitch:'อ่านพิตช์เด็ค',cta_body:'สร้างโดยนักพัฒนาคนเดียวที่หลงใหลเรื่องนี้จริง ๆ มีคำถาม มีไอเดีย หรืออยากลองใช้กับงานของคุณ — ทักมาได้เลย ยินดีคุยครับ',tl_land:'ภูมิทัศน์ปัญหา',tl_bay:'Bayesian เดี่ยว',tl_rand:'สุ่ม',tl_smooth:'เรียบ',tl_rug:'ขรุขระ (กับดักเยอะ)',tl_hd:'มิติสูง',tl_best:'ดีที่สุด 🏆 ชนะทุกอัลกอริทึม',tl_far:'ตามหลังห่าง',u_q1:'คุณปรับอะไรได้บ้าง?',u_q2:'ลอง 1 ครั้งแล้ว ตัวเลขไหนบอกว่าดีแค่ไหน?',u_q3:'คุณลองได้กี่ครั้ง?',u_two:'จากนั้นใช้งานได้ 2 ทาง:',cta_h:'ชอบ Melete ไหม? ทักหาคนทำได้เลย',foot_honest:'ตามตรง: เอนจินเป็นชุดอัลกอริทึมที่ปรับตามบริบท — สิ่งที่รับประกันคือความทนทาน + ที่มาที่ตรวจสอบได้ วัดผลและทำซ้ำได้จริง (ไม่ใช่อัลกอริทึม "วิเศษ" ตัวเดียว)',g_h:'ใช้กับงานจริงของคุณ — คุณเป็นคนวัด',g_intro:'ไม่ต้องเขียนโค้ด ไม่ต้องมีสูตร Melete เสนอการทดลองถัดไป คุณไปลองจริงแล้วพิมพ์คะแนนกลับมา แล้วมันเสนออันต่อไป — ลู่เข้าหาค่าที่ดีที่สุดในจำนวนครั้งจริงที่น้อยที่สุด แก้ตัวแปรของคุณเองด้านล่างได้เลย — เช่น นักวิทยาศาสตร์ยาใส่ pH, อุณหภูมิ, สัดส่วนสารช่วย %; แล้ว Melete จะบอกว่าควรผสมสูตรไหนต่อ เชื่อมต่อกระบวนการจริงผ่าน API สำหรับใช้งานจริง',g_start:'▶ เริ่มแนะนำ',g_target:'🎯 เป้าหมาย (ถ้ามี)',g_targethint:'คะแนนที่คุณต้องการ — Melete จะบอกว่าเป็นไปได้ไหมกับตัวแปรชุดนี้',ind_intro:'ทุกการ์ดรันเดโมจริงบนสถานการณ์ที่ออกแบบให้เหมือนงานจริงในแต่ละวงการ <b>คะแนนในเบราว์เซอร์เป็นแบบจำลอง</b>ของกระบวนการ — แต่<b>การค้นหาค่าที่ดีที่สุดเป็นของจริงและทำซ้ำได้</b>; เชื่อมต่อการทดลอง/เบนช์มาร์ก/กระบวนการจริงของคุณ เพื่อได้ตัวเลขจริง</p>',t_pharma:'สูตรตำรับยา',t_gpu:'จูน GPU kernel',t_etch:'กระบวนการพลาสมาเอตช์',t_llm:'คอนฟิกการเสิร์ฟ LLM',t_esp:'สูตรเอสเพรสโซที่ดีที่สุด',d_pharma:'ตัวแปร: pH · อุณหภูมิ · สัดส่วนสารช่วย %. เป้าหมาย: ความคงตัว/ฤทธิ์ยา Melete หาสูตรที่คงตัวที่สุดใน ~60 การทดลอง — แทนที่จะเป็นหลายร้อย',d_gpu:'ตัวแปร: tile size · unroll · occupancy. เป้าหมาย: throughput (GFLOP/s) หาคอนฟิกที่เร็วที่สุดใน ~50 รอบเบนช์มาร์ก',d_etch:'ตัวแปร: กำลัง · ความดัน · เวลา เป้าหมาย: % wafer yield จูนสูตรให้ได้ yield สูงสุด — air-gapped รันในองค์กร',d_llm:'ตัวแปร: batch size · KV-cache · quantization. เป้าหมาย: tokens/sec ที่คุณภาพกำหนด Melete จูนโครงสร้างพื้นฐาน AI ได้ด้วย — และจูน prompt, agent & routing แบบเดียวกัน',d_esp:'ตัวแปร: อุณหภูมิ · การบด · ปริมาณ เป้าหมาย: รสชาติ วิธีที่เข้าใจง่ายที่สุดในการเห็นไอเดียนี้ทำงาน',runnow:'▶ ลองเลย',sb1:'กาลครั้งหนึ่ง ร้านกาแฟเล็ก ๆ ใฝ่ฝันถึง <b>เอสเพรสโซที่อร่อยที่สุดในโลก</b>',sb2:'แต่มันทำได้ <b>เป็นพันวิธี</b> — และการลองแต่ละครั้ง ต้องชงและชิมจริงทั้งแก้ว จะลองให้ครบ? <b>เป็นไปไม่ได้</b>',sb3:'แล้ว <b>Meli</b> ก็มา — ผู้ที่ไม่เคยลองทุกอย่าง Meli มอง คิด แล้วไฟดวงน้อยก็สว่าง: <i>“ชง<b>แก้วนี้</b>ต่อสิ”</i>',sb4:'คุณชง คุณชิม — <b>7 เต็ม 10</b> Meli ยิ้ม <b>เรียนรู้</b> แล้วเลือกแก้วที่ฉลาดกว่าเดิม 8.5… 9.2…',sb5:'ราว ๆ <b>ยี่สิบแก้ว</b> Meli ก็เจอ <b>สูตรที่สมบูรณ์แบบ</b> — แล้วผนึก <b>ใบรับรอง</b>วิเศษว่าได้มายังไง ให้ทั้งโลกเชื่อถือได้ <b>จบบริบูรณ์ ✨</b>',st1h:'ตั้งค่าที่ปรับได้',st1p:'ระบุสิ่งที่ปรับได้และช่วงของมัน — อุณหภูมิ 85–96° · learning-rate 0–0.1 · ราคา $1–100',st2h:'ให้คะแนน 1 ครั้ง',st2p:'กระบวนการจริงของคุณคืนตัวเลขมา 1 ค่า: ชง→ชิม, เทรน→ความแม่น, ตั้งราคา→ยอดขาย — ไม่ต้องมีชุดข้อมูล',st3h:'ค้นพบ & พิสูจน์',st3p:'Melete เสนอการทดลองถัดไป เรียนรู้ ลู่เข้าหาค่าที่ดีที่สุด — แล้วเซ็นใบบันทึกที่ตรวจสอบได้ว่าทำมายังไง',wh1:'จูน learning rate, สถาปัตยกรรมโมเดล, RAG/serving, compiler flags — ใช้ GPU น้อยลงกว่าจะได้โมเดลที่ดีที่สุด พร้อมบันทึกการจูนที่พิสูจน์ได้',wh2:'หาสูตรผสมสาร/สภาวะที่ให้ yield หรือฤทธิ์สูงสุด ในจำนวนการทดลองที่น้อยลงมาก — พร้อมบันทึกการค้นพบที่แก้ไขไม่ได้ สำหรับสิทธิบัตรและการตรวจสอบ',wh3:'จูนพารามิเตอร์ deposition/etch/print ตาม KPI จริงในองค์กร — air-gapped ข้อมูลไม่ออกจากโรงงาน แต่ผลยังตรวจสอบได้',wh4:'ค้นหาจุดราคา การตั้งค่า และนโยบาย ที่การทดสอบแต่ละครั้งมีต้นทุน — ลู่เข้าเร็วกว่าการไล่กริดหรือลองเอง',story:'<p style="font-size:19px;font-weight:600;color:#1a1b30;margin-bottom:14px">คุณเปิดร้านกาแฟ และอยากได้ <b>เอสเพรสโซที่อร่อยที่สุด</b> สิ่งที่ปรับได้มี 3 อย่าง — อุณหภูมิน้ำ ความละเอียดการบด และปริมาณกาแฟเป็นกรัม ผสมกันได้เป็นพันแบบ และการลองแต่ละแบบ คือ<b>ต้องชงจริงแล้วชิม</b> จะลองทุกแบบ—เป็นไปไม่ได้</p><p style="color:#33344e;margin-bottom:6px">Melete เปรียบเหมือนผู้ช่วยอัจฉริยะ ที่บอกว่าควรชงแก้วถัดไปยังไง:</p><div class="chat">☕ Melete: “ลอง <b>92° บด 6 ใส่ 18g</b>” → คุณชงแล้วชิม: <b>7/10</b></div><div class="chat">☕ Melete: “งั้นลอง <b>93° บด 5 ใส่ 19g</b>” → คุณชิม: <b>8.5/10</b></div><div class="chat" style="opacity:.6">… อีกไม่กี่แก้ว …</div><div class="chat">🎯 ครบ ~<b>20 แก้ว</b> ก็เจอสูตรที่ดีที่สุด — แทนที่จะสุ่มชง 200 แก้ว</div><p style="color:#33344e;margin-top:14px">เปลี่ยน “กาแฟ” เป็น <b>การเทรนโมเดล</b> <b>ปฏิกิริยาเคมี</b> หรือ <b>ราคา</b> — หลักการเดียวกัน: Melete หาค่าที่ดีที่สุดใน<b>จำนวนครั้งที่น้อยที่สุด</b> แล้วเซ็น<b>ใบรับรอง</b>ว่าได้มายังไง</p>',winning:'สูตรที่ชนะ',signed:'ทุกขั้นเซ็นด้วยคริปโต — ผลตรวจสอบได้จริง ไม่มีโม้ ไม่มีเดา'}
|
|
809
|
+
};
|
|
810
|
+
function tr(k){var o=T[LANG]||T.en;return o[k]!=null?o[k]:T.en[k];}
|
|
811
|
+
function showContact(){document.getElementById('contactModal').style.display='flex';}
|
|
812
|
+
function hideContact(){document.getElementById('contactModal').style.display='none';}
|
|
813
|
+
function setLang(l){LANG=l;try{localStorage.setItem('mlang',l);}catch(e){}
|
|
814
|
+
var e1=document.getElementById('lang-en'),e2=document.getElementById('lang-th');if(e1)e1.className='lb'+(l==='en'?' on':'');if(e2)e2.className='lb'+(l==='th'?' on':'');
|
|
815
|
+
var els=document.querySelectorAll('[data-i18n]');for(var i=0;i<els.length;i++){var v=tr(els[i].getAttribute('data-i18n'));if(v!=null)els[i].innerHTML=v;}
|
|
816
|
+
if(typeof loadPreset==='function')loadPreset();
|
|
817
|
+
if(window.LASTJ)renderMap(window.LASTJ);
|
|
818
|
+
}
|
|
819
|
+
var PRESETS={
|
|
820
|
+
peak:{space:'[{"name":"x","type":"real","min":0,"max":10},{"name":"y","type":"real","min":0,"max":10}]',obj:'Math.exp(-((x-7.2)**2+(y-3.4)**2)/3)',budget:40,
|
|
821
|
+
s:['🎛️ Knobs','two dials, x & y, each 0–10'],t:['🧪 Score','a hidden peak the demo simulates — highest at one secret spot'],b:['🎯 Budget','40 tries — watch it find the secret high point']},
|
|
822
|
+
coffee:{space:'[{"name":"temp","type":"real","min":85,"max":96},{"name":"grind","type":"real","min":1,"max":10},{"name":"dose","type":"real","min":14,"max":22}]',obj:'10 - (temp-92)**2*0.08 - (grind-5.5)**2*0.15 - (dose-18)**2*0.1',budget:50,
|
|
823
|
+
s:['🎛️ Knobs','temperature 85–96° · grind 1–10 · dose 14–22g'],t:['🧪 Score','a simulated taste rating (real life: a barista tastes it — you don\\'t calculate anything)'],b:['🎯 Budget','50 brews — Melete finds the best recipe without being told it']},
|
|
824
|
+
price:{space:'[{"name":"price","type":"real","min":1,"max":100}]',obj:'price * (100 - price)',budget:30,
|
|
825
|
+
s:['🎛️ Knobs','one dial: price, $1–100'],t:['🧪 Score','revenue (price × how many still buy at that price)'],b:['🎯 Budget','30 tries — find the price that earns the most']},
|
|
826
|
+
pharma:{space:'[{"name":"ph","type":"real","min":3,"max":9},{"name":"temp","type":"real","min":2,"max":40},{"name":"excipient","type":"real","min":0,"max":30}]',obj:'95 - 6*(ph-6.5)**2 - 0.35*(temp-5)**2 - 0.5*(excipient-12)**2',budget:60,
|
|
827
|
+
s:['🎛️ Variables','drug formulation — pH 3–9 · temperature 2–40°C · excipient 0–30%'],t:['🧪 Score','a simulated stability/potency score (real life: a lab assay measures it)'],b:['🎯 Budget','60 assays — Melete finds the most stable formulation']},
|
|
828
|
+
gpu:{space:'[{"name":"tile","type":"int","min":8,"max":128},{"name":"unroll","type":"int","min":1,"max":8},{"name":"occupancy","type":"real","min":0.1,"max":1}]',obj:'9000 - 2*(tile-64)**2 - 130*(unroll-4)**2 - 9000*(occupancy-0.75)**2',budget:50,
|
|
829
|
+
s:['🎛️ Variables','GPU kernel — tile size 8–128 · unroll 1–8 · target occupancy 0.1–1.0'],t:['🧪 Score','a simulated throughput in GFLOP/s (real life: run the kernel + benchmark)'],b:['🎯 Budget','50 benchmark runs — Melete finds the fastest config']},
|
|
830
|
+
etch:{space:'[{"name":"power","type":"real","min":100,"max":1000},{"name":"pressure","type":"real","min":5,"max":100},{"name":"time","type":"real","min":10,"max":120}]',obj:'98 - 0.00008*(power-650)**2 - 0.012*(pressure-35)**2 - 0.004*(time-70)**2',budget:60,
|
|
831
|
+
s:['🎛️ Variables','plasma etch — power 100–1000W · pressure 5–100mTorr · time 10–120s'],t:['🧪 Score','a simulated wafer yield % (real life: measure the finished wafer)'],b:['🎯 Budget','60 runs — Melete tunes the process to maximum yield']},
|
|
832
|
+
llm:{space:'[{"name":"batch","type":"int","min":1,"max":64},{"name":"kv_cache_gb","type":"real","min":1,"max":40},{"name":"quant_bits","type":"int","min":4,"max":16}]',obj:'4200 - 1.5*(batch-32)**2 - 4*(kv_cache_gb-24)**2 - 32*(quant_bits-8)**2',budget:55,
|
|
833
|
+
s:['🎛️ Variables','LLM serving — batch 1–64 · KV-cache 1–40GB · quantization 4–16 bits'],t:['🧪 Score','a simulated tokens/sec at a quality bar (real life: load-test the server)'],b:['🎯 Budget','55 configs — Melete finds the fastest serving setup']},
|
|
834
|
+
};
|
|
835
|
+
function tryScenario(k){var sel=document.getElementById('preset');sel.value=k;loadPreset();var t=document.getElementById('try');if(t)t.scrollIntoView({behavior:'smooth',block:'start'});setTimeout(run,650);}
|
|
836
|
+
function setMode(m){var adv=(m==='advanced');var set=function(id,sh){var el=document.getElementById(id);if(el)el.style.display=sh;};
|
|
837
|
+
set('advbox',adv?'block':'none');set('teampanel',adv?'block':'none');set('legend',adv?'flex':'none');
|
|
838
|
+
var s=document.getElementById('mt-simple'),v=document.getElementById('mt-advanced');if(s)s.className='mt'+(!adv?' on':'');if(v)v.className='mt'+(adv?' on':'');}
|
|
839
|
+
function loadPreset(){var p=PRESETS[document.getElementById('preset').value];document.getElementById('space').value=p.space;document.getElementById('obj').value=p.obj;document.getElementById('budget').value=p.budget;
|
|
840
|
+
var rows=[['🎛️ '+tr('knobs'),p.s[1]],['🧪 '+tr('score'),p.t[1]],['🎯 '+tr('budget'),p.b[1]]];
|
|
841
|
+
document.getElementById('scenario').innerHTML=rows.map(function(r){return '<div class="srow"><b>'+r[0]+'</b><span>'+r[1]+'</span></div>'}).join('');
|
|
842
|
+
document.getElementById('out').textContent=tr('ph');var m=document.getElementById('map');if(m)m.className='';}
|
|
843
|
+
var ARMCOL={gp:'#6d5cf0',cmaes:'#0ea5b7',"kernel-ucb":'#f97316',"trust-region":'#a855f7',anneal:'#ef4444',maximin:'#22c55e',"basin-hop":'#eab308',random:'#94a3b8',seed:'#cbd5e1'};
|
|
844
|
+
var STRAT={
|
|
845
|
+
gp:['🔮 The Forecaster','predicts which untried setting will score high','🔮 ผู้พยากรณ์','ทายว่าจุดไหนน่าจะคะแนนสูง'],
|
|
846
|
+
cmaes:['🧬 The Evolver','breeds better tries from the best so far','🧬 นักวิวัฒน์','ผสมพันธุ์ค่าที่ดีให้ดีขึ้นเรื่อยๆ'],
|
|
847
|
+
"kernel-ucb":['⚖️ The Balancer','weighs the best-known against the unknown','⚖️ นักชั่งใจ','ชั่งระหว่างของดีที่รู้แล้วกับที่ยังไม่รู้'],
|
|
848
|
+
"trust-region":['🔍 The Zoomer','zooms in carefully around the current best','🔍 นักซูม','ซูมเข้าใกล้ค่าที่ดีที่สุดอย่างระวัง'],
|
|
849
|
+
anneal:['🌡️ The Wanderer','roams boldly early, then settles down','🌡️ นักท่อง','ออกสำรวจกว้างตอนแรก แล้วค่อยนิ่ง'],
|
|
850
|
+
maximin:['🛰️ The Scout','checks the most unexplored areas','🛰️ นักสอดแนม','ไปดูพื้นที่ที่ยังไม่เคยลอง'],
|
|
851
|
+
"basin-hop":['🦘 The Jumper','leaps to fresh regions to escape dead ends','🦘 นักกระโดด','กระโดดไปจุดใหม่เพื่อหนีทางตัน'],
|
|
852
|
+
random:['🎲 The Wildcard','tries random spots as a sanity check','🎲 ไพ่ตาย','ลองสุ่มเพื่อเช็คความชัวร์'],
|
|
853
|
+
seed:['🌱 The Opening','the first spread-out tries to get going','🌱 การเปิดเกม','ลองกระจายๆ ช่วงเริ่มต้น']
|
|
854
|
+
};
|
|
855
|
+
function sName(a){var s=STRAT[a]||[a,'',a,''];return LANG==='th'?(s[2]||s[0]):s[0];}
|
|
856
|
+
function sDesc(a){var s=STRAT[a]||['','','',''];return LANG==='th'?(s[3]||s[1]):s[1];}
|
|
857
|
+
function heat(t){t=Math.max(0,Math.min(1,t));var a=[40,32,84],b=[14,120,170],c=[16,185,160],d=[250,232,80];var seg=t<.33?[a,b,t/.33]:t<.66?[b,c,(t-.33)/.33]:[c,d,(t-.66)/.34];return 'rgb('+seg[0].map(function(v,i){return Math.round(v+(seg[1][i]-v)*seg[2])}).join(',')+')';}
|
|
858
|
+
var MAP={};
|
|
859
|
+
function fmt(v){var r=Math.round(v*100)/100;return ''+r;}
|
|
860
|
+
function drawFrame(k){
|
|
861
|
+
var s=MAP.surface,S=600,cv=document.getElementById('surf'),x=cv.getContext('2d');x.clearRect(0,0,S,S);
|
|
862
|
+
var p=MAP.path||[];
|
|
863
|
+
if(s){ try{ drawWaveParticle(x,S,k); }catch(err){ drawFlat(x,S,k); } }
|
|
864
|
+
else if(MAP.dims && MAP.dims.length>=2){ drawParallel(x,S,k); }
|
|
865
|
+
else { x.fillStyle='#9092a8';x.font='15px system-ui';x.textAlign='center';x.fillText('Run a scenario to see the discovery map.',S/2,S/2); }
|
|
866
|
+
var sn=document.getElementById('stepn');if(sn)sn.textContent='exp '+Math.min(k+1,p.length)+' / '+p.length;
|
|
867
|
+
var sc=document.getElementById('scrub');if(sc)sc.value=k;
|
|
868
|
+
}
|
|
869
|
+
// flat heat-map fallback (2-D)
|
|
870
|
+
function drawFlat(x,S,k){
|
|
871
|
+
var s=MAP.surface,p=MAP.path,zmin=Math.min.apply(null,s.z),zmax=Math.max.apply(null,s.z),zr=(zmax-zmin)||1,cw=S/s.nx;
|
|
872
|
+
for(var j=0;j<s.ny;j++)for(var i=0;i<s.nx;i++){x.fillStyle=heat((s.z[j*s.nx+i]-zmin)/zr);x.fillRect(i*cw,S-(j+1)*cw,cw+1.2,cw+1.2);}
|
|
873
|
+
var toX=function(e){return (e[s.xName]-s.xMin)/((s.xMax-s.xMin)||1)*S;},toY=function(e){return S-(e[s.yName]-s.yMin)/((s.yMax-s.yMin)||1)*S;};
|
|
874
|
+
for(var t=0;t<=k&&t<p.length;t++){var P=p[t],cur=(t===k);x.beginPath();x.arc(toX(P.experiment),toY(P.experiment),cur?9:5.5,0,7);x.fillStyle=ARMCOL[P.arm]||'#94a3b8';x.fill();x.lineWidth=1;x.strokeStyle='#fff';x.stroke();}
|
|
875
|
+
}
|
|
876
|
+
// WAVE-PARTICLE map (2-D): the learned score surface as a rippling 2.5-D terrain (the WAVE) + each
|
|
877
|
+
// experiment as a glowing quanta-dot sitting on it (the PARTICLE) + a gold star at the peak.
|
|
878
|
+
var VZ={mL:54,plotW:486,mT:130,depth:250,skew:44,h:120,floorY:472,floorD:72};
|
|
879
|
+
function vproj(gi,gj,t,nx,ny){var fx=nx>1?gi/(nx-1):0.5,fz=ny>1?gj/(ny-1):0.5;return [VZ.mL+fx*VZ.plotW+fz*VZ.skew, VZ.mT+(1-fz)*VZ.depth-t*VZ.h];}
|
|
880
|
+
function fproj(gi,gj,nx,ny){var fx=nx>1?gi/(nx-1):0.5,fz=ny>1?gj/(ny-1):0.5;return [VZ.mL+fx*VZ.plotW+fz*VZ.skew, VZ.floorY-fz*VZ.floorD];}
|
|
881
|
+
function drawContourFloor(x,s,nx,ny,zmin,zr){
|
|
882
|
+
var st=2,gi,gj;
|
|
883
|
+
for(gj=0;gj<ny-1;gj+=st)for(gi=0;gi<nx-1;gi+=st){var t=(s.z[gj*nx+gi]-zmin)/zr,band=Math.floor(t*7)/7;
|
|
884
|
+
var a=fproj(gi,gj,nx,ny),b=fproj(gi+st,gj,nx,ny),c=fproj(gi+st,gj+st,nx,ny),d=fproj(gi,gj+st,nx,ny);
|
|
885
|
+
x.beginPath();x.moveTo(a[0],a[1]);x.lineTo(b[0],b[1]);x.lineTo(c[0],c[1]);x.lineTo(d[0],d[1]);x.closePath();
|
|
886
|
+
x.fillStyle=heat(band);x.globalAlpha=0.34;x.fill();x.globalAlpha=1;}
|
|
887
|
+
var c0=fproj(0,0,nx,ny),c1=fproj(nx-1,0,nx,ny),c2=fproj(nx-1,ny-1,nx,ny),c3=fproj(0,ny-1,nx,ny);
|
|
888
|
+
x.strokeStyle='rgba(110,110,150,.20)';x.lineWidth=1;x.beginPath();x.moveTo(c0[0],c0[1]);x.lineTo(c1[0],c1[1]);x.lineTo(c2[0],c2[1]);x.lineTo(c3[0],c3[1]);x.closePath();x.stroke();
|
|
889
|
+
}
|
|
890
|
+
function drawWaveParticle(x,S,k){
|
|
891
|
+
var s=MAP.surface,nx=s.nx,ny=s.ny,p=MAP.path,zmin=Math.min.apply(null,s.z),zmax=Math.max.apply(null,s.z),zr=(zmax-zmin)||1;
|
|
892
|
+
drawContourFloor(x,s,nx,ny,zmin,zr);
|
|
893
|
+
for(var gj=ny-1;gj>=0;gj--){
|
|
894
|
+
var rmax=0,i;for(i=0;i<nx;i++){var tt=(s.z[gj*nx+i]-zmin)/zr;if(tt>rmax)rmax=tt;}
|
|
895
|
+
x.beginPath();for(i=0;i<nx;i++){var t=(s.z[gj*nx+i]-zmin)/zr,P=vproj(i,gj,t,nx,ny);i?x.lineTo(P[0],P[1]):x.moveTo(P[0],P[1]);}
|
|
896
|
+
var br=vproj(nx-1,gj,0,nx,ny),bl=vproj(0,gj,0,nx,ny);x.lineTo(br[0],br[1]);x.lineTo(bl[0],bl[1]);x.closePath();
|
|
897
|
+
x.fillStyle=heat(rmax*0.9+0.05);x.globalAlpha=0.9;x.fill();x.globalAlpha=1;
|
|
898
|
+
x.beginPath();for(i=0;i<nx;i++){var t2=(s.z[gj*nx+i]-zmin)/zr,Q=vproj(i,gj,t2,nx,ny);i?x.lineTo(Q[0],Q[1]):x.moveTo(Q[0],Q[1]);}
|
|
899
|
+
x.strokeStyle='rgba(255,255,255,.45)';x.lineWidth=1;x.stroke();
|
|
900
|
+
}
|
|
901
|
+
for(var u=0;u<=k&&u<p.length;u++){var e=p[u].experiment,gi=(e[s.xName]-s.xMin)/((s.xMax-s.xMin)||1)*(nx-1),gjj=(e[s.yName]-s.yMin)/((s.yMax-s.yMin)||1)*(ny-1),tv=(p[u].value-zmin)/zr,Z=vproj(gi,gjj,tv,nx,ny),cur=(u===k);
|
|
902
|
+
x.save();x.shadowColor='rgba(255,255,255,.9)';x.shadowBlur=cur?16:7;x.beginPath();x.arc(Z[0],Z[1],cur?7:4,0,7);x.fillStyle=heat(tv*0.85+0.15);x.fill();x.lineWidth=1.4;x.strokeStyle='#fff';x.stroke();x.restore();}
|
|
903
|
+
var bi=MAP.bestIdx;if(k>=bi){var b=MAP.best.experiment,gib=(b[s.xName]-s.xMin)/((s.xMax-s.xMin)||1)*(nx-1),gjb=(b[s.yName]-s.yMin)/((s.yMax-s.yMin)||1)*(ny-1),tb=(MAP.best.value-zmin)/zr,B=vproj(gib,gjb,tb,nx,ny);
|
|
904
|
+
x.save();x.shadowColor='#fbbf24';x.shadowBlur=22;x.font='32px system-ui';x.textAlign='center';x.textBaseline='middle';x.fillStyle='#fde047';x.fillText('★',B[0],B[1]);x.restore();}
|
|
905
|
+
}
|
|
906
|
+
// parallel-coordinates: works for ANY number of variables (3D, 5D, 8D…) — each line is one experiment
|
|
907
|
+
function drawParallel(x,S,k){
|
|
908
|
+
var dims=MAP.dims,n=dims.length,p=MAP.path,pad=60,W=S-2*pad,H=S-2*pad-18,top=pad;
|
|
909
|
+
var vals=p.map(function(q){return q.value}),vmin=Math.min.apply(null,vals),vmax=Math.max.apply(null,vals),vr=(vmax-vmin)||1;
|
|
910
|
+
var ax=function(i){return n>1?pad+i/(n-1)*W:pad+W/2;};
|
|
911
|
+
var ay=function(i,val){var d=dims[i];return top+H-((val-d.min)/((d.max-d.min)||1))*H;};
|
|
912
|
+
x.lineWidth=1.5;
|
|
913
|
+
for(var i=0;i<n;i++){var X=ax(i);x.strokeStyle='#e7e8f0';x.beginPath();x.moveTo(X,top);x.lineTo(X,top+H);x.stroke();
|
|
914
|
+
x.fillStyle='#5b5d77';x.font='700 12px system-ui';x.textAlign='center';x.fillText(dims[i].name,X,top-16);
|
|
915
|
+
x.fillStyle='#b3b5c6';x.font='10px ui-monospace';x.fillText(fmt(dims[i].max),X,top-3);x.fillText(fmt(dims[i].min),X,top+H+15);}
|
|
916
|
+
for(var t=0;t<=k&&t<p.length;t++){var q=p[t];x.beginPath();for(var j=0;j<n;j++){var XX=ax(j),YY=ay(j,+q.experiment[dims[j].name]);j?x.lineTo(XX,YY):x.moveTo(XX,YY);}
|
|
917
|
+
x.strokeStyle=heat((q.value-vmin)/vr);x.globalAlpha=(t===k)?1:0.45;x.lineWidth=(t===k)?3.2:1.5;x.stroke();x.globalAlpha=1;}
|
|
918
|
+
var bi=MAP.bestIdx;if(k>=bi){var b=p[bi];x.beginPath();for(var jj=0;jj<n;jj++){var BX=ax(jj),BY=ay(jj,+b.experiment[dims[jj].name]);jj?x.lineTo(BX,BY):x.moveTo(BX,BY);}x.strokeStyle='#f59e0b';x.lineWidth=4.5;x.stroke();
|
|
919
|
+
for(var j2=0;j2<n;j2++){x.fillStyle='#fbbf24';x.beginPath();x.arc(ax(j2),ay(j2,+b.experiment[dims[j2].name]),5.5,0,7);x.fill();x.strokeStyle='#fff';x.lineWidth=1.6;x.stroke();}}
|
|
920
|
+
}
|
|
921
|
+
var TIMER=null;
|
|
922
|
+
function stopPlay(){if(TIMER){clearInterval(TIMER);TIMER=null;}document.getElementById('play').textContent='▶ Replay';}
|
|
923
|
+
function togglePlay(){if(TIMER){stopPlay();return;}var p=MAP.path;if(!p)return;document.getElementById('play').textContent='⏸ Pause';var k=(+document.getElementById('scrub').value>=p.length-1)?0:+document.getElementById('scrub').value;var iv=Math.max(22,Math.round(3200/p.length));TIMER=setInterval(function(){drawFrame(k);if(k>=p.length-1){stopPlay();return;}k++;},iv);}
|
|
924
|
+
function scrubTo(v){stopPlay();drawFrame(v);}
|
|
925
|
+
function renderMap(j){
|
|
926
|
+
document.getElementById('map').className='on';
|
|
927
|
+
MAP={surface:j.surface,dims:j.dims,path:j.path||[],best:j.best};
|
|
928
|
+
var cap=document.getElementById('mapcap');if(cap)cap.innerHTML=j.surface?'Heat = the score it learned · each dot = one experiment, coloured by the <b>strategy</b> that proposed it · ★ = best.':'Each line = one experiment across all '+(j.dims?j.dims.length:'')+' variables · <b>brighter line = higher score</b> · gold = the best found.';
|
|
929
|
+
var bi=0,bv=-Infinity;MAP.path.forEach(function(p,i){if(p.value>bv){bv=p.value;bi=i;}});MAP.bestIdx=bi;
|
|
930
|
+
document.getElementById('scrub').max=Math.max(1,MAP.path.length-1);
|
|
931
|
+
// legend (only arms that appeared) — friendly names
|
|
932
|
+
var used={};MAP.path.forEach(function(p){used[p.arm]=1;});
|
|
933
|
+
document.getElementById('legend').innerHTML=Object.keys(used).map(function(a){return '<span class="legdot"><i style="background:'+(ARMCOL[a]||'#94a3b8')+'"></i>'+sName(a)+'</span>';}).join('');
|
|
934
|
+
// convergence
|
|
935
|
+
var cv=document.getElementById('conv'),cc=cv.getContext('2d'),W=cv.width,H=cv.height;cc.clearRect(0,0,W,H);
|
|
936
|
+
var run=[],b=-Infinity;MAP.path.forEach(function(p){b=Math.max(b,p.value);run.push(b);});
|
|
937
|
+
var lo=Math.min.apply(null,run),hi=Math.max.apply(null,run),rg=(hi-lo)||1;
|
|
938
|
+
cc.strokeStyle='#5b53e8';cc.lineWidth=2.5;cc.lineJoin='round';cc.beginPath();run.forEach(function(v,i){var X=i/(run.length-1||1)*W,Y=H-9-(v-lo)/rg*(H-18);i?cc.lineTo(X,Y):cc.moveTo(X,Y);});cc.stroke();
|
|
939
|
+
// arm bars
|
|
940
|
+
var tot=(j.armStats||[]).reduce(function(s,a){return s+a.pulls},0)||1;
|
|
941
|
+
document.getElementById('arms').innerHTML=(j.armStats||[]).filter(function(a){return a.pulls>0}).sort(function(a,b){return b.pulls-a.pulls}).map(function(a){return '<div class="kv" style="display:flex;justify-content:space-between;font-size:13px;align-items:center;gap:8px"><span title="'+sDesc(a.name)+'"><i style="display:inline-block;width:9px;height:9px;border-radius:50%;background:'+(ARMCOL[a.name]||'#94a3b8')+';margin-right:6px"></i>'+sName(a.name)+' <span class="muted" style="font-size:11px">('+a.name+')</span></span><span class="muted">'+a.pulls+'×</span></div><div class="bar" style="width:'+Math.round(a.pulls/tot*100)+'%;background:'+(ARMCOL[a.name]||'#94a3b8')+'"></div>'}).join('');
|
|
942
|
+
// proof
|
|
943
|
+
document.getElementById('proof').innerHTML='best score <b>'+(+j.best.value).toFixed(4)+'</b> · '+j.evaluations+' experiments<br>📜 '+j.trace.frames.length+' frames · <b style="color:'+(j.verify?'#0e9f6e':'#dc2626')+'">'+(j.verify?'verified ✓':'unverified')+'</b> (Ed25519, offline)';
|
|
944
|
+
// ── plain-language narration (anyone, any job, understands) ──
|
|
945
|
+
var top2=(j.armStats||[]).filter(function(a){return a.pulls>0}).sort(function(a,b){return b.pulls-a.pulls}).slice(0,2).map(function(a){return sName(a.name)});
|
|
946
|
+
var bestStr=Object.keys(j.best.experiment).map(function(kk){var v=j.best.experiment[kk];return '<b>'+kk+'</b> = '+(Math.round(v*1000)/1000)}).join(' · ');
|
|
947
|
+
var nar=document.getElementById('narrate');
|
|
948
|
+
nar.style.display='block';
|
|
949
|
+
nar.innerHTML='<b>📖 '+tr('plainHdr')+':</b> '+tr('tried')+' <b>'+j.evaluations+'</b> '+tr('settings')+' ('+(LANG==='th'?'คะแนน':'score')+' <b>'+(+j.best.value).toFixed(2)+'</b>).'
|
|
950
|
+
+'<br>🏆 <b>'+tr('winning')+':</b> '+bestStr+'.'
|
|
951
|
+
+'<br>📜 '+tr('signed');
|
|
952
|
+
renderPrime();
|
|
953
|
+
renderJournalist();
|
|
954
|
+
renderRx();
|
|
955
|
+
renderHero();
|
|
956
|
+
renderEta();
|
|
957
|
+
renderBrain();
|
|
958
|
+
renderAegis();
|
|
959
|
+
renderSovereign();
|
|
960
|
+
renderSavings();
|
|
961
|
+
renderBaseline();
|
|
962
|
+
renderFrontier();
|
|
963
|
+
renderCert();
|
|
964
|
+
renderPoopt();
|
|
965
|
+
renderSens();
|
|
966
|
+
renderNoise();
|
|
967
|
+
renderInter();
|
|
968
|
+
renderDrift();
|
|
969
|
+
renderSloppy();
|
|
970
|
+
renderCliff();
|
|
971
|
+
renderRashomon();
|
|
972
|
+
renderShape();
|
|
973
|
+
renderWhatif();
|
|
974
|
+
renderBatch();
|
|
975
|
+
stopPlay();setTimeout(togglePlay,250); // auto-play the discovery
|
|
976
|
+
}
|
|
977
|
+
function renderSavings(){
|
|
978
|
+
var j=window.LASTJ;if(!j||!j.dims)return;var sv=document.getElementById('savings');if(!sv)return;
|
|
979
|
+
var D=j.dims.length, grid=Math.min(20000,Math.round(Math.pow(8,D))), used=j.evaluations||1, saved=Math.max(0,grid-used), pct=Math.round(saved/grid*100);
|
|
980
|
+
window.__saved=saved;
|
|
981
|
+
var th=(LANG==='th');
|
|
982
|
+
sv.style.display='block';
|
|
983
|
+
sv.innerHTML='<div style="font-size:13px;font-weight:800;color:#0e9f6e;letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">⚡ '+(th?'ประหยัดจำนวนการทดลอง':'Fewer experiments')+'</div>'
|
|
984
|
+
+(th?'การไล่ทดลองแบบกริดให้ทั่ว (~8 จุดต่อ 1 ตัวแปร) ต้องใช้ราว <b>'+grid.toLocaleString()+'</b> ครั้ง · Melete ใช้ <b>'+used+'</b> ครั้ง → น้อยลง <b>~'+saved.toLocaleString()+'</b> ครั้ง ('+pct+'%).'
|
|
985
|
+
:'A full grid sweep (~8 points per variable) would need about <b>'+grid.toLocaleString()+'</b> runs · Melete used <b>'+used+'</b> → about <b>'+saved.toLocaleString()+'</b> fewer ('+pct+'%).')
|
|
986
|
+
+'<div style="margin-top:10px;font-size:14px">'+(th?'ถ้า 1 การทดลองของคุณมีต้นทุน $':'If one experiment costs you $')+' <input id="cost" type="number" min="0" placeholder="'+(th?'ใส่ตัวเลข':'your number')+'" oninput="gMoney()" style="width:120px;display:inline-block;padding:6px 8px;border:1px solid #ccd;border-radius:8px"> <span id="money"></span></div>'
|
|
987
|
+
+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'เป็นการประมาณเทียบกับการไล่กริด ไม่ใช่การรับประกัน — ตัวเลขจริงขึ้นกับกระบวนการของคุณ':'An estimate versus a grid sweep, not a guarantee — your real number depends on your process.')+'</div>';
|
|
988
|
+
}
|
|
989
|
+
function gMoney(){
|
|
990
|
+
var c=document.getElementById('cost'),m=document.getElementById('money');if(!c||!m)return;
|
|
991
|
+
var v=parseFloat(c.value);var th=(LANG==='th');
|
|
992
|
+
if(isFinite(v)&&v>0&&window.__saved){m.innerHTML='→ <b style="color:#0e9f6e;font-size:16px">≈ $'+Math.round(window.__saved*v).toLocaleString()+'</b> '+(th?'ที่ประหยัดได้':'saved');}
|
|
993
|
+
else{m.innerHTML='';}
|
|
994
|
+
}
|
|
995
|
+
function renderFrontier(){
|
|
996
|
+
var j=window.LASTJ;if(!j||!j.frontier)return;var el=document.getElementById('frontier');if(!el)return;
|
|
997
|
+
var f=j.frontier;var th=(LANG==='th');var rec=f.recommendation;
|
|
998
|
+
var color=rec==='STOP'?'#0e9f6e':(rec==='CONTINUE'?'#6366f1':'#8890a8');
|
|
999
|
+
var label=th?(rec==='STOP'?'พอแล้ว — เจอค่าที่ดีในทางปฏิบัติแล้ว':(rec==='CONTINUE'?'ควรทดลองต่อ — ยังขยับขึ้นได้':'ยังบอกไม่ได้ — ข้อมูลยังน้อย'))
|
|
1000
|
+
:(rec==='STOP'?'STOP — practical best reached':(rec==='CONTINUE'?'RUN ANOTHER — still improving':'UNKNOWN — too few experiments'));
|
|
1001
|
+
var head=th?'ควรทดลองต่ออีกไหม?':'Should you run another experiment?';
|
|
1002
|
+
var nExp=(j.evaluations||f.n);
|
|
1003
|
+
var bestTxt=isFinite(f.best)?((th?'ดีที่สุดตอนนี้ ':'best so far ')+'<b>'+(+f.best).toPrecision(4)+'</b> '+(th?'จาก ':'in ')+nExp+(th?' ครั้ง':' experiments')):'';
|
|
1004
|
+
var gain=(isFinite(f.expectedGainNext)&&rec!=='UNKNOWN')?('<div style="margin-top:6px;color:#475;font-size:13px">'+(th?'คาดว่าทดลองอีก 1 ครั้งจะดีขึ้น ~':'one more is expected to gain ~')+'<b>'+(+f.expectedGainNext).toExponential(2)+'</b></div>'):'';
|
|
1005
|
+
var money=(f.spentSoFar!=null)?('<div style="margin-top:4px;color:#475;font-size:13px">'+(th?'ใช้ไปแล้วราว $':'spent so far ≈ $')+(+f.spentSoFar).toLocaleString()+'</div>'):'';
|
|
1006
|
+
el.style.display='block';
|
|
1007
|
+
el.innerHTML='<div style="font-size:13px;font-weight:800;color:'+color+';letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">🧭 '+head+'</div>'
|
|
1008
|
+
+'<div style="font-size:16px;color:'+color+';font-weight:700">'+label+'</div>'
|
|
1009
|
+
+'<div style="margin-top:6px;color:#33344e">'+bestTxt+'</div>'+gain+money
|
|
1010
|
+
+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'คำแนะนำจากเส้นทางการทดลองของคุณเอง (ผลตอบแทนลดน้อยถอยลง) — เป็นตัวช่วยตัดสินใจ ไม่ใช่การรับประกัน':'From your own diminishing-returns curve — decision support, not a guarantee.')+'</div>';
|
|
1011
|
+
}
|
|
1012
|
+
function renderCert(){
|
|
1013
|
+
var j=window.LASTJ;if(!j||!j.certificate)return;var el=document.getElementById('cert');if(!el)return;
|
|
1014
|
+
var c=j.certificate;var th=(LANG==='th');
|
|
1015
|
+
if(!(c.n>=2)){el.style.display='none';return;}
|
|
1016
|
+
var within=Math.max(0.01,+c.withinPct);
|
|
1017
|
+
var gpct=Math.max(0,(100/within-1)*100); // the optimum is provably AT MOST this % above your result
|
|
1018
|
+
var gtxt=gpct>=999?'∞':(gpct<10?gpct.toFixed(1):Math.round(gpct).toString());
|
|
1019
|
+
var rel=j.reliable?('<span style="display:inline-block;margin-left:8px;padding:2px 8px;border-radius:99px;background:#eef;color:#4338ca;font-size:12px;font-weight:700">⚡ '+(th?'โหมด Reliable':'reliable mode')+'</span>'):'';
|
|
1020
|
+
el.style.display='block';
|
|
1021
|
+
el.innerHTML='<div style="font-size:13px;font-weight:800;color:#7c3aed;letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">💎 '+(th?'ใบรับรองความเหมาะที่สุด':'Optimality certificate')+rel+'</div>'
|
|
1022
|
+
+'<div style="font-size:16px;color:#1a1b30">'+(th?'พิสูจน์ได้ว่ามีค่าที่ดีกว่านี้ได้ไม่เกิน ':'the true optimum is provably at most ')+'<b style="color:#7c3aed">'+gtxt+'%</b> '+(th?'เหนือผลของคุณ':'above your result')+'</div>'
|
|
1023
|
+
+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'ภายใต้ขอบเขต Lipschitz ที่ประมาณจากข้อมูลของคุณ — กล่องดำอาจซ่อนยอดแหลมระหว่างจุดที่วัด จึงเป็นการรับรองแบบมีเงื่อนไข ตรวจซ้ำได้':'Under a Lipschitz bound estimated from your data — a black box can hide a sharper spike between samples, so it is a conditional, reproducible certificate.')+'</div>';
|
|
1024
|
+
}
|
|
1025
|
+
function renderPoopt(){
|
|
1026
|
+
var j=window.LASTJ;if(!j||!j.poopt){return;}var el=document.getElementById('poopt');if(!el)return;
|
|
1027
|
+
var p=j.poopt;var th=(LANG==='th');
|
|
1028
|
+
var co2=(p.co2SavedKg!=null)?('<div style="margin-top:4px;color:#475;font-size:13px">'+(th?'ลด CO₂ โดยประมาณ ':'≈ CO₂ saved ')+'<b>'+(+p.co2SavedKg).toLocaleString()+' kg</b> '+(th?'(จากค่าที่คุณใส่)':'(from your factors)')+'</div>'):'';
|
|
1029
|
+
el.style.display='block';
|
|
1030
|
+
el.innerHTML='<div style="font-size:13px;font-weight:800;color:#0e7490;letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">💠 '+(th?'ใบรับรองการ optimize (Proof of Optimization)':'Proof of Optimization')+'</div>'
|
|
1031
|
+
+'<div style="font-size:16px;color:#1a1b30"><b style="color:#0e7490">'+(+p.experimentsSaved).toLocaleString()+'</b> '+(th?'การทดลองน้อยกว่าการไล่ทั้งหมด':'fewer experiments than brute force')+' ('+(+p.efficiencyPct).toFixed(1)+'%)</div>'+co2
|
|
1032
|
+
+'<div style="margin-top:8px;font-size:12px;color:#0e9f6e">🔒 '+(th?'เซ็น Ed25519 · ตรวจสอบ offline ได้โดยไม่ต้องเชื่อเรา':'signed Ed25519 · verifiable offline, no trust in us required')+'</div>'
|
|
1033
|
+
+'<div style="margin-top:8px;padding:9px 11px;background:#f0fdfa;border:1px solid #bfeee6;border-radius:9px;font-size:12.5px;color:#155e54;line-height:1.55">'+(th?'<b>นี่คืออะไร:</b> หลักฐานกันปลอมว่าคุณหาคำตอบนี้มาอย่างซื่อสัตย์ ใช้การทดลองน้อยกว่าการลองทุกแบบ '+(+p.efficiencyPct).toFixed(0)+'% <br><b>เอาไปใช้:</b> แนบไปกับรายงาน/ส่งให้ลูกค้า·ผู้ตรวจสอบ·QA — ใครก็ตรวจได้เองว่าผลไม่ได้กุ (ลากไฟล์มาตรวจที่ช่อง verify ด้านบนได้เลย)':'<b>What it is:</b> a tamper-proof receipt that you reached this result honestly, using '+(+p.efficiencyPct).toFixed(0)+'% fewer experiments than trying everything.<br><b>Use it:</b> attach it to a report / hand it to a client · auditor · QA — anyone can verify offline that the result wasn\\'t faked (drop the file into the verify box above).')+'</div>'
|
|
1034
|
+
+'<button class="btn ghost" style="margin-top:10px;font-size:13px;padding:8px 14px" onclick="dlPoopt()">⬇ '+(th?'ดาวน์โหลดใบรับรอง':'Download certificate')+'</button>';
|
|
1035
|
+
}
|
|
1036
|
+
function dlPoopt(){var j=window.LASTJ;if(!j||!j.poopt)return;try{var blob=new Blob([JSON.stringify(j.poopt,null,2)],{type:"application/json"});var url=URL.createObjectURL(blob);var a=document.createElement("a");a.href=url;a.download="proof-of-optimization.json";document.body.appendChild(a);a.click();a.remove();URL.revokeObjectURL(url);}catch(e){}}
|
|
1037
|
+
function renderSens(){var j=window.LASTJ;if(!j||!j.sensitivity)return;var el=document.getElementById('sens');if(!el)return;var sv=j.sensitivity;var th=(LANG==='th');if(sv.robustness==='unknown'||!sv.variables||!sv.variables.length){el.style.display='none';return;}var color=sv.robustness==='robust'?'#0e9f6e':(sv.robustness==='fragile'?'#c0392b':'#b45309');var rlabel=th?(sv.robustness==='robust'?'ทน (ที่ราบกว้าง)':(sv.robustness==='fragile'?'เปราะ (ยอดแหลม)':'ปานกลาง')):sv.robustness;var rows=sv.variables.slice().sort(function(a,b){return b.importancePct-a.importancePct;}).map(function(v){var w=Math.max(3,Math.min(100,v.importancePct));var tol=(Math.abs(v.toleranceAbs)<1)?(+v.toleranceAbs).toFixed(3):(+v.toleranceAbs).toFixed(1);return '<div style="margin:7px 0"><div style="display:flex;justify-content:space-between;font-size:13px"><span style="color:#33344e;font-weight:600">'+v.name+'</span><span style="color:#8890a8">'+(th?'คุมที่ ±':'hold ±')+tol+' ('+v.importancePct+'%)</span></div><div style="height:6px;background:#eee;border-radius:9px;overflow:hidden;margin-top:3px"><div style="height:100%;width:'+w+'%;background:linear-gradient(90deg,#6366f1,#0ea5b7)"></div></div></div>';}).join('');el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;color:'+color+';letter-spacing:.4px;text-transform:uppercase;margin-bottom:8px">🎯 '+(th?'ต้องคุมแต่ละค่าแน่นแค่ไหน':'How tightly to hold each knob')+' · '+rlabel+'</div>'+rows+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'แถบยาว = ไวต่อการเปลี่ยน ต้องคุมแน่น · ประเมินจากการวัดของคุณ (Taguchi robust design)':'longer bar = more sensitive, hold it tighter · estimated from your measurements (Taguchi robust design)')+'</div>';}
|
|
1038
|
+
function renderNoise(){var j=window.LASTJ;if(!j||!j.noise)return;var el=document.getElementById('noise');if(!el)return;var nz=j.noise;var th=(LANG==='th');if(nz.recommendation==='unknown'){el.style.display='none';return;}var color=nz.recommendation==='trust'?'#0e9f6e':(nz.recommendation==='replicate'?'#c0392b':'#b45309');var label=th?(nz.recommendation==='trust'?'ผลวัดสะอาด เชื่อถือได้':(nz.recommendation==='replicate'?'noise สูง — ควรวัดซ้ำก่อนเชื่อผล':'มีบางจุดที่ควรวัดซ้ำ')):(nz.recommendation==='trust'?'measurements look clean':(nz.recommendation==='replicate'?'high noise — replicate before trusting':'some readings worth re-checking'));var flagged=(nz.outliers&&nz.outliers.length)?('<div style="margin-top:6px;font-size:13px;color:#475">'+(th?'จุดที่น่าจะวัดพลาด: ':'likely mis-measured readings: ')+'<b>'+nz.outliers.length+'</b></div>'):'';var snrTxt=(nz.snr>999)?'\u221e':(+nz.snr).toFixed(1);el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;color:'+color+';letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">\ud83d\udd2c '+(th?'ความน่าเชื่อถือของการวัด':'Measurement reliability')+'</div><div style="font-size:15px;color:'+color+';font-weight:700">'+label+'</div><div style="font-size:13px;color:#475;margin-top:4px">noise \u03c3 \u2248 '+(+nz.noiseSigma).toPrecision(3)+' \u00b7 SNR \u2248 '+snrTxt+'</div>'+flagged+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'ประเมินจากความต่างของผลที่จุดใกล้ๆ กัน — ยิ่งใกล้แต่ผลต่างมาก = วัดมี noise':'estimated from disagreement between near-identical settings — close settings, very different scores = a noisy meter')+'</div>';}
|
|
1039
|
+
function renderInter(){var j=window.LASTJ;if(!j||!j.interactions)return;var el=document.getElementById('inter');if(!el)return;var it=j.interactions;var th=(LANG==='th');if(!it.pairs||!it.pairs.length){el.style.display='none';return;}var top=it.pairs.slice(0,5);var rows=top.map(function(p){var w=Math.max(3,Math.min(100,Math.round(p.strength*100)));var c=p.coupled?'#7c3aed':'#cbd5e1';return '<div style="margin:6px 0"><div style="display:flex;justify-content:space-between;font-size:13px"><span style="color:#33344e;font-weight:600">'+p.a+' \u00d7 '+p.b+(p.coupled?(' <span style="color:#7c3aed;font-weight:700">'+(th?'\u2014 ปรับร่วมกัน':'\u2014 tune together')+'</span>'):'')+'</span><span style="color:#8890a8">'+(+p.strength).toFixed(2)+'</span></div><div style="height:6px;background:#eee;border-radius:9px;overflow:hidden;margin-top:3px"><div style="height:100%;width:'+w+'%;background:'+c+'"></div></div></div>';}).join('');var head=it.hasInteraction?(th?'ปุ่มที่ coupled กัน (ปรับแยกไม่ได้)':'Coupled knobs (cannot tune independently)'):(th?'ตัวแปรปรับแยกกันได้ (ไม่ค่อย coupled)':'Variables are fairly independent');el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;color:#7c3aed;letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">\ud83d\udd17 '+(th?'แผนที่การจับคู่ตัวแปร':'Variable interaction map')+'</div><div style="font-size:14px;color:#33344e;font-weight:600;margin-bottom:6px">'+head+'</div>'+rows+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'แถบยาว/ม่วง = สองตัวนี้ส่งผลต่อกัน ค่าที่ดีของตัวหนึ่งขึ้นกับอีกตัว (DOE interaction)':'longer/purple = these two affect each other; the best value of one depends on the other (DOE interaction)')+'</div>';}
|
|
1040
|
+
function gExport(){var j=window.LASTJ;if(!j||!j.prescription)return;var p=j.prescription;var th=(LANG==='th');var sig=(j.trace&&j.trace.signature)?j.trace.signature:'';var card={product:'Melete — Recipe Certificate',decision:p.decision,recipe:p.recipe,expected:p.expected,improvement:{vsFirstTry:p.vsStartPct+'%',vsRandom:p.vsRandomPct+'%'},confidencePct:p.confidencePct,robustnessPct:p.robustnessPct,trustPct:p.trustPct,holdTolerances:p.tolerances,experiments:p.evaluations,driftWarning:p.driftWarning,goal:j.goal,signed:!!j.verify,signature:sig?(sig.slice(0,32)+'…'):'',note:p.note,generated:'melete.mneme-ai.space'};var blob=new Blob([JSON.stringify(card,null,2)],{type:'application/json'});var url=URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.download='melete-recipe.json';document.body.appendChild(a);a.click();document.body.removeChild(a);setTimeout(function(){URL.revokeObjectURL(url);},1000);}
|
|
1041
|
+
function renderPrime(){var j=window.LASTJ;var el=document.getElementById('prime');if(!el)return;var pr=j&&j.prime;if(!pr||!isFinite(pr.processIQ)||pr.grade==='unknown'){el.style.display='none';return;}var th=(LANG==='th');var kc={safety:'#c0392b','feasibility':'#b45309',breakthrough:'#a21caf',trust:'#b45309',refine:'#b45309',ship:'#0e9f6e','more-data':'#3b82f6'}[pr.decisive.kind]||'#6d28d9';var gl=th?({'world-class':'ระดับโลก',strong:'แข็งแรง',developing:'กำลังพัฒนา',fragile:'เปราะบาง'}[pr.grade]):pr.grade;var iq=pr.processIQ;var deg=Math.round(iq*3.6);var head=th?({safety:'⚠ ความปลอดภัยมาก่อน',feasibility:'🎯 ต้องเพิ่มตัวแปรใหม่',breakthrough:'⭐ เจอจุดที่อาจเป็นการค้นพบใหม่',trust:'⏱ ตรวจสอบความน่าเชื่อก่อน',refine:'🔁 ปรับให้ทนทานก่อน',ship:'✅ พร้อมใช้งานจริง','more-data':'↗ ลองต่ออีกหน่อย'}[pr.decisive.kind]):({safety:'⚠ Safety first',feasibility:'🎯 Add a new lever',breakthrough:'⭐ A possible breakthrough appeared',trust:'⏱ Verify trust first',refine:'🔁 Make it robust first',ship:'✅ Ready to ship','more-data':'↗ Keep going'}[pr.decisive.kind]);
|
|
1042
|
+
var kicons={safety:'🛡',feasibility:'🎯',breakthrough:'⭐',trust:'⏱',refine:'🔁',ship:'✅','more-data':'↗'};
|
|
1043
|
+
var ranked=(pr.insights||[]).slice(0,3).map(function(ins,idx){var ic=kicons[ins.kind]||'•';var c=(idx===0)?kc:'#8890a8';return '<div style="display:flex;gap:9px;align-items:flex-start;margin:5px 0;'+(idx===0?'':'opacity:.75')+'"><span style="flex:0 0 auto;font-size:13px;margin-top:1px">'+ic+'</span><span style="font-size:12.5px;color:'+(idx===0?'#33344e':'#5b5d77')+';line-height:1.5'+(idx===0?';font-weight:600':'')+'">'+ins.headline+'</span></div>';}).join('');
|
|
1044
|
+
var iqlabel=th?'สมอง':'process IQ';
|
|
1045
|
+
el.style.display='block';
|
|
1046
|
+
el.innerHTML='<div class="primewrap" style="box-shadow:0 34px 80px -42px rgba(160,40,110,.55)"><div class="primeborder"></div><div class="primeinner"><div style="position:absolute;inset:0;background:radial-gradient(55% 70% at 100% 0%,rgba(225,29,72,.05),transparent 60%),radial-gradient(50% 60% at 0% 100%,rgba(109,92,240,.05),transparent 60%);pointer-events:none"></div><div style="position:relative">'
|
|
1047
|
+
+'<div style="display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-bottom:14px"><span class="primegem"></span><span class="primeglint" style="font-size:16px;font-weight:900;letter-spacing:2px">MELETE PRIME</span></div>'
|
|
1048
|
+
+'<div style="display:flex;gap:24px;align-items:center;flex-wrap:wrap"><div style="flex:0 0 auto;position:relative;width:130px;height:130px;border-radius:50%;background:conic-gradient('+kc+' '+deg+'deg,#f1eef6 0)"><div style="position:absolute;inset:6px;border-radius:50%;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;box-shadow:0 8px 24px -10px rgba(190,20,80,.4),inset 0 0 0 1px #f3eef8"><div style="font-family:ui-monospace,Menlo,monospace;font-size:34px;font-weight:800;color:'+kc+';line-height:1">'+iq+'</div><div style="font-size:9px;letter-spacing:.5px;text-transform:uppercase;color:#9aa0b8;font-weight:700;margin-top:2px">'+iqlabel+'</div><div style="font-size:10px;font-weight:800;color:'+kc+';margin-top:1px">'+gl+'</div></div></div>'
|
|
1049
|
+
+'<div style="flex:1;min-width:250px"><div style="font-size:13px;color:#9aa0b8;font-weight:700;letter-spacing:.4px;text-transform:uppercase;margin-bottom:2px">'+(th?'คำตัดสิน':'the decision')+'</div><div style="font-size:21px;font-weight:800;color:'+kc+';margin-bottom:9px;letter-spacing:-.3px">'+head+'</div>'+ranked+'</div></div>'
|
|
1050
|
+
+'<div style="font-size:11.5px;color:#9aa0b8;margin-top:14px;padding-top:12px;border-top:1px solid #f0ecf6;line-height:1.5">'+(th?'สมองหลักรวมทุกเลนส์ (ประสิทธิภาพ·ทนทาน·ปลอดภัย·เพดาน·ความน่าเชื่อ·ปุ่มที่สำคัญ·การค้นพบเกินคาด) แล้วจัดลำดับ “ปลอดภัยมาก่อน” เหลือ 1 คำตัดสิน — สิ่งที่ไม่มีเครื่องมือไหนในโลกทำ':'one brain composing every lens (efficiency · robustness · safety · ceiling · trust · which-knobs · breakthroughs) into a single safety-first decision — what no other tool ships')+'</div>'
|
|
1051
|
+
+'</div></div></div>';}
|
|
1052
|
+
function renderRx(){var j=window.LASTJ;var el=document.getElementById('rx');if(!el)return;var p=j&&j.prescription;if(!p||!p.recipe||!p.recipe.length||p.decision==='unknown'){el.style.display='none';return;}var th=(LANG==='th');
|
|
1053
|
+
var D={ship:{ic:'✅',col:'#0e9f6e',bg:'#ecfdf5',bd:'#a7f3d0',t:th?'ใช้สูตรนี้ได้เลย':'Ready — use this recipe',s:th?'Melete มั่นใจว่านี่คือจุดที่ดีที่สุดแล้ว':'this is your best setting'},
|
|
1054
|
+
'more-data':{ic:'↗',col:'#3b82f6',bg:'#eff6ff',bd:'#bfdbfe',t:th?'ยังดีขึ้นได้ — ลองต่ออีกหน่อย':'Keep going — still improving',s:th?'อีกไม่กี่รอบน่าจะดีขึ้นอีก':'a few more runs should help'},
|
|
1055
|
+
refine:{ic:'🔁',col:'#b45309',bg:'#fffbeb',bd:'#fde68a',t:th?'ปรับให้ทนทานก่อนใช้':'Refine before you ship',s:th?'จุดที่ดีที่สุดยังเปราะ ปรับให้ทนการแกว่งในโลกจริง':'the best point is fragile — find one that survives real-world wobble'},
|
|
1056
|
+
'new-lever':{ic:'🎯',col:'#c0392b',bg:'#fef2f2',bd:'#fecaca',t:th?'ต้องเพิ่มตัวแปรใหม่':'Add a new lever',s:th?'เป้าหมายเกินเพดานของตัวแปรชุดนี้':'target is beyond what these knobs can reach'}}[p.decision];
|
|
1057
|
+
var chips=p.recipe.map(function(r){return '<span style="display:inline-block;background:#fff;border:1px solid '+D.bd+';border-radius:9px;padding:5px 11px;margin:3px 5px 3px 0;font-size:14px;font-weight:700;color:#1a1b30">'+r.name+' = '+r.value+'</span>';}).join('');
|
|
1058
|
+
var steps=({ship:th?['ตั้งค่าตามสูตรนี้ในกระบวนการจริงของคุณ','รัน 1 ครั้งเพื่อยืนยันคะแนน','ถ้าตรง — ล็อกใช้เป็นค่ามาตรฐานได้เลย']:['Set these exact values in your real process','Run it once to confirm the score','If it matches — lock it in as your standard'],
|
|
1059
|
+
'more-data':th?['ปล่อยให้ Melete แนะนำต่ออีก 5–10 รอบ','ใส่คะแนนจริงแต่ละรอบ']:['Let Melete propose 5–10 more rounds','Feed back your real score each round'],
|
|
1060
|
+
refine:th?['ลองค่ารอบๆ สูตรนี้ (ขยับทีละน้อย)','เลือกจุดที่คะแนนไม่ตกแม้ค่าจะเพี้ยนเล็กน้อย']:['Try settings just around this recipe','Pick the one whose score holds when values drift a little'],
|
|
1061
|
+
'new-lever':th?['เพิ่มตัวแปรใหม่ที่คุมได้ (เช่น อุณหภูมิ/เวลา/สารเติม)','หรือผ่อนเป้าหมายลงให้อยู่ในวิสัยที่ทำได้']:['Add a new variable you can control (temperature / time / an additive)','Or relax the target to something reachable']})[p.decision];
|
|
1062
|
+
var stepsHtml=steps.map(function(s,i){return '<div style="display:flex;gap:9px;align-items:flex-start;margin:6px 0"><span style="flex:0 0 auto;width:20px;height:20px;border-radius:50%;background:'+D.col+';color:#fff;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center;margin-top:1px">'+(i+1)+'</span><span style="font-size:13.5px;color:#33344e;line-height:1.5">'+s+'</span></div>';}).join('');
|
|
1063
|
+
var worth=(isFinite(p.vsStartPct)&&p.vsStartPct>0)?('<div style="font-size:14px;color:#0e7a4f;font-weight:700;margin:2px 0 10px">📈 '+(th?'ดีขึ้น ':'')+'+'+p.vsStartPct+'%'+(th?' จากจุดเริ่มต้นของคุณ':' better than your first try')+(isFinite(p.vsRandomPct)&&p.vsRandomPct>0?(' · +'+p.vsRandomPct+'%'+(th?' จากการสุ่ม':' vs guessing')):'')+'</div>'):'';
|
|
1064
|
+
var tol=(p.tolerances&&p.tolerances.length)?('<div style="font-size:12.5px;color:#475;margin-top:10px;padding-top:10px;border-top:1px dashed '+D.bd+'">🎚 '+(th?'คุมแต่ละค่าไม่ให้เกิน: ':'Hold each knob within: ')+p.tolerances.map(function(t){return '<b>'+t.name+' ±'+t.plusMinus+'</b>';}).join(' · ')+'</div>'):'';
|
|
1065
|
+
var warn=p.driftWarning?('<div style="font-size:12.5px;color:#c0392b;margin-top:8px">⏱ '+(th?'ผลอาจปนเปื้อนตามเวลา — ทดสอบผู้ชนะใหม่อีกครั้งก่อนเชื่อ':'results may be time-confounded — re-test the winner fresh before trusting')+'</div>'):'';
|
|
1066
|
+
el.style.display='block';
|
|
1067
|
+
el.innerHTML='<div style="background:'+D.bg+';border:1.5px solid '+D.bd+';border-radius:20px;padding:22px 24px;box-shadow:0 16px 40px -26px rgba(20,30,80,.4)">'
|
|
1068
|
+
+'<div style="display:flex;align-items:center;gap:11px;margin-bottom:3px"><span style="font-size:25px">'+D.ic+'</span><span style="font-size:18px;font-weight:800;color:'+D.col+'">'+D.t+'</span><button onclick="gExport()" style="margin-left:auto;border:1px solid '+D.bd+';background:#fff;color:'+D.col+';border-radius:9px;padding:6px 12px;font-size:12.5px;font-weight:700;cursor:pointer">📋 '+(th?'ดาวน์โหลดใบสั่งงาน':'Export recipe')+'</button></div>'
|
|
1069
|
+
+'<div style="font-size:13px;color:#64708a;margin:0 0 14px 36px">'+D.s+'</div>'
|
|
1070
|
+
+'<div style="font-size:12px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#8890a8;margin-bottom:6px">'+(th?'สูตรของคุณ':'Your recipe')+'</div>'
|
|
1071
|
+
+'<div style="margin-bottom:4px">'+chips+'<span style="font-size:14px;color:#475;margin-left:6px">→ '+(th?'คะแนน ':'score ')+'<b style="color:#1a1b30">'+(+p.expected).toPrecision(4)+'</b></span></div>'
|
|
1072
|
+
+worth
|
|
1073
|
+
+'<div style="font-size:12px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#8890a8;margin:6px 0 4px">'+(th?'ทำต่อยังไง':'Do this next')+'</div>'+stepsHtml
|
|
1074
|
+
+tol+warn
|
|
1075
|
+
+'<div style="margin-top:12px;padding-top:11px;border-top:1px dashed '+D.bd+';font-size:12px;color:#475;line-height:1.6">'+(th?'<b>📄 ปุ่ม "ดาวน์โหลดใบสั่งงาน" ได้ไฟล์อะไร + ใครใช้:</b><br>• <b>วิศวกร/ช่างเทคนิค/แล็บของคุณ</b> → เอาสูตรนี้ไปตั้งค่าในเครื่อง/กระบวนการจริง<br>• <b>ผู้ตรวจ/ฝ่าย Compliance/ผู้ยื่นสิทธิบัตร</b> → เอาใบรับรองที่เซ็นไปตรวจ (offline) ว่าผลนี้จริง ทำซ้ำได้<br>• ไฟล์ = สูตร + คะแนน + ใบรับรองเซ็น Ed25519 (พิสูจน์ที่มาได้)':'<b>📄 What the "Export recipe" file is + who uses it:</b><br>• <b>Your engineer / technician / lab</b> → apply this recipe in the real machine/process<br>• <b>Your auditor / compliance / patent filing</b> → verify the signed certificate (offline) that this result is real & reproducible<br>• File = the recipe + score + an Ed25519 signature (provable provenance)')+'</div>'
|
|
1076
|
+
+'</div>';}
|
|
1077
|
+
function renderShape(){var j=window.LASTJ;var el=document.getElementById('shape');if(!el)return;var sh=j&&j.shape;if(!sh||!sh.shape||sh.shape==='unknown'){el.style.display='none';return;}var th=(LANG==='th');var icon={peak:'⛰',ridge:'🏔',saddle:'🐴',plateau:'🍞',bowl:'🥣'}[sh.shape]||'◆';var nm=th?({peak:'ยอดแหลม',ridge:'สันเขา',saddle:'อานม้า',plateau:'ที่ราบ',bowl:'ขอบ/ชาม'}[sh.shape]):sh.shape.toUpperCase();var col=(sh.shape==='saddle')?'#b45309':(sh.shape==='ridge'||sh.shape==='plateau')?'#0e9f6e':'#6d28d9';var note=th?({peak:'ยอดแหลม — มีจุดที่ดีที่สุดจุดเดียว ต้องคุมค่าให้แน่น',ridge:'สันเขา — มีทั้ง '+sh.flatDirections+' แนวที่ได้คะแนนพอๆ กัน คุณมีอิสระเลือกตามนั้น (เลือกถูกสุด)',saddle:'อานม้า — ดีขึ้นทางหนึ่งจะแย่อีกทาง ต้องระวัง เป็นการแลกเปลี่ยน',plateau:'ที่ราบ — กว้างและแบน เกือบทุกค่าใกล้ๆ ได้ผลพอๆ กัน',bowl:'ขอบ/ชาม — ค่าที่ดีสุดเท่าที่วัดได้อยู่ที่ขอบ ลองดันขีดจำกัดต่อ'}[sh.shape]):sh.note;el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:'+col+';margin-bottom:4px">'+icon+' '+(th?'รูปทรงของคำตอบ':'Shape of the optimum')+'</div><div style="font-size:17px;color:'+col+';font-weight:800;margin-bottom:5px">'+icon+' '+nm+'</div><div style="font-size:13.5px;color:#33344e;line-height:1.55">'+note+'</div><div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'อ่านจากความโค้งของพื้นผิว (eigenvalue ของ Hessian) — เรขาคณิตเดียวกับที่นักฟิสิกส์ใช้จำแนกจุดวิกฤต':'read from the surface curvature (Hessian eigenvalues) — the geometry physicists use to classify critical points')+'</div>';}
|
|
1078
|
+
function renderRashomon(){var j=window.LASTJ;var el=document.getElementById('rashomon');if(!el)return;var rs=j&&j.rashomon;if(!rs||!rs.recipes||rs.recipes.length<2){el.style.display='none';return;}var th=(LANG==='th');var dims=(j.space||[]);var rows=rs.recipes.slice(0,4).map(function(rc,i){var cfg=dims.length?dims.map(function(d){return d.name+'='+(+rc.settings[d.name]).toFixed(d.type==='int'?0:2);}).join(' · '):Object.keys(rc.settings).map(function(k){return k+'='+rc.settings[k];}).join(' · ');return '<div style="display:flex;gap:9px;align-items:center;margin:5px 0;font-size:13px"><span style="flex:0 0 auto;width:20px;height:20px;border-radius:6px;background:linear-gradient(135deg,#6d5cf0,#14b8a6);color:#fff;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center">'+(i+1)+'</span><span style="color:#1a1b30">'+cfg+'</span><span style="color:#8890a8;margin-left:auto;font-variant-numeric:tabular-nums">'+(+rc.value).toPrecision(4)+'</span></div>';}).join('');el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9;margin-bottom:4px">🎭 '+(th?'มีหลายสูตรที่ดีพอๆ กัน':'You have options — equally-good recipes')+'</div><div style="font-size:14px;color:#1a1b30;font-weight:700;margin-bottom:8px">'+(th?(rs.recipes.length+' สูตรที่ต่างกันจริง ได้คะแนนใกล้เคียงจุดที่ดีที่สุด'):(rs.recipes.length+' genuinely different recipes all score near the best'))+'</div>'+rows+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'เลือกอันที่ถูกสุด/ปลอดภัยสุด/สะดวกสุดได้เลย — ดีพอๆ กัน (Rashomon set / equifinality)':'pick the cheapest · safest · most convenient — they\\'re all about as good (Rashomon set / equifinality)')+'</div>';}
|
|
1079
|
+
function renderCliff(){var j=window.LASTJ;var el=document.getElementById('cliff');if(!el)return;var c=j&&j.cliffs;if(!c||!c.cliffs||!c.cliffs.length){el.style.display='none';return;}var th=(LANG==='th');var col=c.optimumOnCliff?'#c0392b':'#b45309';var top=c.cliffs.slice(0,3).map(function(cl){return '<div style="font-size:13px;color:#33344e;margin:4px 0">⚠ '+(th?'ใกล้ ':'near ')+'<b>'+cl.variable+' ≈ '+cl.at[cl.variable]+'</b> — '+(th?'ขยับนิดเดียวผลตกลง ':'a small step drops the result by ')+'<b>'+cl.drop+'</b> ('+cl.steepness+(th?'× ชันกว่าปกติ)':'× steeper than normal)')+'</div>';}).join('');el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:'+col+';margin-bottom:6px">🪨 '+(th?'หน้าผา / จุดพลิก':'Cliffs / tipping points')+'</div>'+(c.optimumOnCliff?'<div style="font-size:14px;color:#c0392b;font-weight:700;margin-bottom:6px">'+(th?'⚠ จุดที่ดีที่สุดของคุณอยู่ริมหน้าผา — เพี้ยนนิดเดียวผลพังได้ ควรถอยมาจุดที่ราบกว่า':'⚠ your best setting sits on a cliff edge — a tiny drift can collapse it; step back to a flatter one')+'</div>':'')+top+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'จุดที่ "ขยับนิดเดียวแล้วผลตกฮวบ" — อันตรายเรื่องความเสถียรในการผลิตจริง':'where a tiny change makes the result fall off a cliff — a stability risk in real production')+'</div>';}
|
|
1080
|
+
function renderSloppy(){var j=window.LASTJ;var el=document.getElementById('sloppy');if(!el)return;var s=j&&j.sloppiness;if(!s||!isFinite(s.effectiveDims)||!s.directions||!s.directions.length){el.style.display='none';return;}var th=(LANG==='th');var combo=function(d){return d.loadings.filter(function(l){return Math.abs(l.weight)>0.25;}).map(function(l){return (l.weight<0?'−':'')+l.name;}).join(' & ')||d.loadings[0].name;};var stiff=s.directions[0];var free=s.effectiveDims<s.totalDims;var bars=s.directions.map(function(d){var w=Math.max(3,Math.round(d.stiffness*100));var c=d.kind==='stiff'?'#6d5cf0':'#c9cde0';return '<div style="margin:6px 0"><div style="display:flex;justify-content:space-between;font-size:12.5px"><span style="color:#33344e">'+combo(d)+(d.kind==='sloppy'?' <span style="color:#0e9f6e;font-weight:700">'+(th?'← อิสระ ตั้งได้ตามใจ':'← free, set it freely')+'</span>':'')+'</span><span style="color:#8890a8;font-variant-numeric:tabular-nums">'+(d.stiffness*100).toFixed(0)+'%</span></div><div style="height:6px;background:#f0eefb;border-radius:9px;overflow:hidden;margin-top:3px"><div style="height:100%;width:'+w+'%;background:'+(d.kind==='stiff'?'linear-gradient(90deg,#6d5cf0,#14b8a6)':c)+';border-radius:9px"></div></div></div>';}).join('');el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9;margin-bottom:6px">🎛 '+(th?'ปุ่มที่สำคัญจริง':'How many knobs really matter')+'</div><div style="font-size:15px;color:#1a1b30;font-weight:700;margin-bottom:9px">'+(th?('สำคัญจริง '+s.effectiveDims+' จาก '+s.totalDims+' ชุดผสม'):(s.effectiveDims+' of '+s.totalDims+' combinations truly matter'))+'</div>'+bars+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(free?(th?'ทิศ stiff ต้องคุมแน่น · ทิศ sloppy ตั้งให้ถูก/ง่ายสุดได้เลย ไม่กระทบผล (sloppy-model / effective dimensionality)':'hold the stiff combination tight · the sloppy ones you can set however is cheapest — they barely affect the result (sloppy-model analysis)'):(th?'ทุกตัวแปรสำคัญแยกกัน ไม่มีทิศที่ตั้งฟรีได้':'every variable matters independently — no free directions'))+'</div>';}
|
|
1081
|
+
var VERT_THEME={aerospace:'#22d3ee',genomics:'#a855f7',solar:'#f59e0b',ml:'#6d5cf0',database:'#10b981',devops:'#ef4444'};
|
|
1082
|
+
function ccKnobFrac(exp,dims,name){var d=null;for(var i=0;i<dims.length;i++){if(dims[i].name===name)d=dims[i];}if(!d)return 0.5;var mn=+(d.min!=null?d.min:0),mx=+(d.max!=null?d.max:1);var val=+exp[name];return mx>mn?Math.max(0,Math.min(1,(val-mn)/(mx-mn))):0.5;}
|
|
1083
|
+
function ccDefs(col){return '<defs><filter id="ccg" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="2.6" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs>';}
|
|
1084
|
+
function ccMix(p){var a=[239,68,68],b=[16,185,129];return 'rgb('+Math.round(a[0]+(b[0]-a[0])*p)+','+Math.round(a[1]+(b[1]-a[1])*p)+','+Math.round(a[2]+(b[2]-a[2])*p)+')';}
|
|
1085
|
+
// Per-vertical Sci-Fi command-center scene — every shape is driven by THIS run's real numbers (score + found knobs)
|
|
1086
|
+
function vScene(key,pct,exp,dims,col){
|
|
1087
|
+
var p=Math.max(0,Math.min(1,pct/100));var d=ccDefs(col);var s='';
|
|
1088
|
+
if(key==='aerospace'){
|
|
1089
|
+
var spin=(15-9*p).toFixed(1);var beamOp=(0.14+0.78*p).toFixed(2);var bw=(1+2.6*p).toFixed(1);
|
|
1090
|
+
s='<svg viewBox="0 0 320 190">'+d
|
|
1091
|
+
+'<path d="M-20 210 A 250 150 0 0 1 340 210 Z" fill="'+col+'12" stroke="'+col+'3a" stroke-width="1.4"/>'
|
|
1092
|
+
+'<ellipse cx="160" cy="80" rx="136" ry="50" fill="none" stroke="'+col+'40" stroke-width="1.2" stroke-dasharray="3 6"/>'
|
|
1093
|
+
+'<g transform="translate(160 80)"><g><animateTransform attributeName="transform" type="rotate" from="0 0 0" to="360 0 0" dur="'+spin+'s" repeatCount="indefinite"/><g transform="translate(136 0)"><rect x="-6" y="-3" width="12" height="6" rx="1.5" fill="'+col+'" filter="url(#ccg)"/><rect x="-13" y="-1.4" width="6" height="2.8" fill="'+col+'aa"/><rect x="7" y="-1.4" width="6" height="2.8" fill="'+col+'aa"/></g></g></g>'
|
|
1094
|
+
+'<g transform="translate(160 80)"><g><animateTransform attributeName="transform" type="rotate" from="200 0 0" to="560 0 0" dur="'+(spin*1.7).toFixed(1)+'s" repeatCount="indefinite"/><circle cx="136" cy="0" r="3" fill="#fff"/></g></g>'
|
|
1095
|
+
+'<polygon points="42,170 62,170 52,150" fill="'+col+'" filter="url(#ccg)"/>'
|
|
1096
|
+
+'<line x1="52" y1="150" x2="296" y2="42" stroke="'+col+'" stroke-width="'+bw+'" opacity="'+beamOp+'"><animate attributeName="opacity" values="'+beamOp+';0.16;'+beamOp+'" dur="1.5s" repeatCount="indefinite"/></line>'
|
|
1097
|
+
+'<circle cx="296" cy="42" r="4" fill="#fff" filter="url(#ccg)"/></svg>';
|
|
1098
|
+
}else if(key==='genomics'){
|
|
1099
|
+
var N=11,glow=(0.32+0.66*p).toFixed(2),rung='',sa='M',sb='M';
|
|
1100
|
+
for(var i=0;i<N;i++){var xx=42+i*23.6;var ph=i*0.62;var yA=(95+38*Math.sin(ph)).toFixed(1);var yB=(95-38*Math.sin(ph)).toFixed(1);sa+=(i?' L':'')+xx.toFixed(1)+' '+yA;sb+=(i?' L':'')+xx.toFixed(1)+' '+yB;rung+='<line x1="'+xx.toFixed(1)+'" y1="'+yA+'" x2="'+xx.toFixed(1)+'" y2="'+yB+'" stroke="'+col+'" stroke-width="1.5" opacity="'+(0.22+0.5*Math.abs(Math.sin(ph))).toFixed(2)+'"/><circle cx="'+xx.toFixed(1)+'" cy="'+yA+'" r="3.4" fill="'+col+'"/><circle cx="'+xx.toFixed(1)+'" cy="'+yB+'" r="3.4" fill="#fff" opacity="0.82"/>';}
|
|
1101
|
+
s='<svg viewBox="0 0 320 190">'+d+'<g filter="url(#ccg)" opacity="'+glow+'"><animateTransform attributeName="transform" type="translate" values="0 -4;0 4;0 -4" dur="3.6s" repeatCount="indefinite"/><path d="'+sa+'" fill="none" stroke="'+col+'" stroke-width="2.4"/><path d="'+sb+'" fill="none" stroke="'+col+'88" stroke-width="2.4"/>'+rung+'</g></svg>';
|
|
1102
|
+
}else if(key==='solar'){
|
|
1103
|
+
var tl=ccKnobFrac(exp,dims,'tiltAngle');var ang=(-32+tl*52).toFixed(0);var rays='';
|
|
1104
|
+
for(var i=0;i<12;i++){var a=i*30*Math.PI/180;rays+='<line x1="'+(52+13*Math.cos(a)).toFixed(1)+'" y1="'+(52+13*Math.sin(a)).toFixed(1)+'" x2="'+(52+21*Math.cos(a)).toFixed(1)+'" y2="'+(52+21*Math.sin(a)).toFixed(1)+'" stroke="'+col+'" stroke-width="2"/>';}
|
|
1105
|
+
var cells='';for(var r=0;r<3;r++){for(var c=0;c<4;c++){cells+='<rect x="'+(154+c*23).toFixed(0)+'" y="'+(106+r*13).toFixed(0)+'" width="20" height="11" rx="1.5" fill="'+col+'33" stroke="'+col+'88" stroke-width="0.8"/>';}}
|
|
1106
|
+
var fillH=(30*p).toFixed(1);
|
|
1107
|
+
s='<svg viewBox="0 0 320 190">'+d
|
|
1108
|
+
+'<g><g><animateTransform attributeName="transform" type="rotate" from="0 52 52" to="360 52 52" dur="20s" repeatCount="indefinite"/>'+rays+'</g><circle cx="52" cy="52" r="13" fill="'+col+'" filter="url(#ccg)"/></g>'
|
|
1109
|
+
+'<g transform="rotate('+ang+' 200 124)"><rect x="150" y="102" width="100" height="46" rx="3" fill="'+col+'18" stroke="'+col+'" stroke-width="1.3"/>'+cells+'</g>'
|
|
1110
|
+
+'<line x1="208" y1="150" x2="282" y2="158" stroke="'+col+'55" stroke-width="1.5"/><circle r="2.6" fill="#fff"><animateMotion dur="'+(1.6-0.9*p).toFixed(2)+'s" repeatCount="indefinite" path="M208 150 L282 158"/></circle>'
|
|
1111
|
+
+'<rect x="276" y="150" width="26" height="34" rx="3" fill="none" stroke="'+col+'"/><rect x="279" y="'+(182-(+fillH)).toFixed(1)+'" width="20" height="'+fillH+'" rx="1.5" fill="'+col+'" opacity="0.85"/></svg>';
|
|
1112
|
+
}else if(key==='ml'){
|
|
1113
|
+
var layers=[3,4,4,3],cols=layers.length,nodes='',edges='',pos=[];
|
|
1114
|
+
for(var c=0;c<cols;c++){var xx=46+c*76;var L=layers[c];pos[c]=[];for(var r=0;r<L;r++){var yy=(38+(150-38)*(L>1?r/(L-1):0.5));pos[c].push([xx,yy]);nodes+='<circle cx="'+xx+'" cy="'+yy.toFixed(1)+'" r="5" fill="'+col+'" filter="url(#ccg)"/>';}}
|
|
1115
|
+
for(var c=0;c<cols-1;c++){for(var a=0;a<pos[c].length;a++){for(var b=0;b<pos[c+1].length;b++){edges+='<line x1="'+pos[c][a][0]+'" y1="'+pos[c][a][1].toFixed(1)+'" x2="'+pos[c+1][b][0]+'" y2="'+pos[c+1][b][1].toFixed(1)+'" stroke="'+col+'" stroke-width="0.7" opacity="0.16"/>';}}}
|
|
1116
|
+
var pd='M'+pos[0][0][0]+' '+pos[0][0][1].toFixed(1)+' L'+pos[1][1][0]+' '+pos[1][1][1].toFixed(1)+' L'+pos[2][1][0]+' '+pos[2][1][1].toFixed(1)+' L'+pos[3][0][0]+' '+pos[3][0][1].toFixed(1);
|
|
1117
|
+
var dur=(2.4-1.6*p).toFixed(2);
|
|
1118
|
+
s='<svg viewBox="0 0 320 190">'+d+edges+nodes+'<circle r="3.6" fill="#fff" filter="url(#ccg)"><animateMotion dur="'+dur+'s" repeatCount="indefinite" path="'+pd+'"/></circle><circle r="3" fill="'+col+'"><animateMotion dur="'+dur+'s" begin="'+(+dur/2).toFixed(2)+'s" repeatCount="indefinite" path="'+pd+'"/></circle></svg>';
|
|
1119
|
+
}else if(key==='database'){
|
|
1120
|
+
var pc=ccMix(p),pipes='';
|
|
1121
|
+
for(var i=0;i<5;i++){var yy=42+i*27;pipes+='<rect x="40" y="'+yy+'" width="240" height="11" rx="5.5" fill="rgba(255,255,255,.05)"/><line x1="46" y1="'+(yy+5.5)+'" x2="274" y2="'+(yy+5.5)+'" stroke="'+pc+'" stroke-width="5.5" stroke-dasharray="14 10" stroke-linecap="round" opacity="0.88"><animate attributeName="stroke-dashoffset" values="0;-48" dur="'+(1.5-0.95*p).toFixed(2)+'s" repeatCount="indefinite"/></line>';}
|
|
1122
|
+
s='<svg viewBox="0 0 320 190">'+d+pipes+'<text x="160" y="184" fill="'+pc+'" font-size="11" font-weight="700" text-anchor="middle" font-family="ui-monospace,Menlo,monospace">I/O FLOW '+Math.round(p*100)+'% '+(p>0.66?'· OPTIMAL':(p>0.4?'· EASING':'· BOTTLENECK'))+'</text></svg>';
|
|
1123
|
+
}else if(key==='devops'){
|
|
1124
|
+
var sh='M160 26 L250 54 L250 108 C250 150 210 168 160 182 C110 168 70 150 70 108 L70 54 Z';
|
|
1125
|
+
var fy=(182-(182-26)*p).toFixed(1);var hex='';
|
|
1126
|
+
for(var r=0;r<6;r++){for(var c=0;c<5;c++){hex+='<circle cx="'+(86+c*36).toFixed(0)+'" cy="'+(44+r*26).toFixed(0)+'" r="3" fill="none" stroke="'+col+'" stroke-width="0.7" opacity="0.4"/>';}}
|
|
1127
|
+
s='<svg viewBox="0 0 320 190">'+d+'<clipPath id="ccsh"><path d="'+sh+'"/></clipPath>'
|
|
1128
|
+
+'<g clip-path="url(#ccsh)"><rect x="70" y="26" width="180" height="160" fill="'+col+'10"/><rect x="70" y="'+fy+'" width="180" height="170" fill="'+col+'44"><animate attributeName="opacity" values="0.7;1;0.7" dur="2.2s" repeatCount="indefinite"/></rect>'+hex+'</g>'
|
|
1129
|
+
+'<path d="'+sh+'" fill="none" stroke="'+col+'" stroke-width="2" filter="url(#ccg)"/>'
|
|
1130
|
+
+'<text x="160" y="104" fill="#fff" font-size="13" font-weight="800" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" opacity="'+(p>0.5?'0.96':'0.45')+'">VERIFIED</text>'
|
|
1131
|
+
+'<text x="160" y="126" fill="'+col+'" font-size="16" font-weight="800" text-anchor="middle">'+(p>0.5?'✓':'…')+'</text>'
|
|
1132
|
+
+'<text x="160" y="146" fill="'+col+'" font-size="10" text-anchor="middle" font-family="ui-monospace,Menlo,monospace">'+Math.round(p*100)+'% BLOCKED</text></svg>';
|
|
1133
|
+
}else{
|
|
1134
|
+
s='<svg viewBox="0 0 320 190">'+d+'<circle cx="160" cy="95" r="'+(20+50*p).toFixed(0)+'" fill="none" stroke="'+col+'" stroke-width="2" filter="url(#ccg)"/></svg>';
|
|
1135
|
+
}
|
|
1136
|
+
return s;
|
|
1137
|
+
}
|
|
1138
|
+
function ccGauges(dims,exp,col,pct,v){
|
|
1139
|
+
var head='<div style="display:flex;align-items:baseline;gap:9px;margin:11px 2px 4px"><span style="font-size:30px;font-weight:800;color:'+col+';text-shadow:0 0 16px '+col+'88">'+pct.toFixed(1)+'</span><span style="font-size:11px;color:#8a98b8">'+((v.scoreName||'score')+(v.scoreUnit?(' · '+v.scoreUnit):''))+'</span></div>';
|
|
1140
|
+
var bars=dims.map(function(dd){var val=+exp[dd.name];var mn=+(dd.min!=null?dd.min:0),mx=+(dd.max!=null?dd.max:1);var fr=mx>mn?Math.max(0,Math.min(1,(val-mn)/(mx-mn))):0.5;var vs=(dd.type==='int')?String(Math.round(val)):(Math.abs(val)<1?val.toFixed(3):val.toFixed(1));return '<div class="ccgauge"><div class="ccgrow"><span style="color:'+col+';font-weight:700">'+dd.name+'</span><span style="color:#cdd6ee;font-variant-numeric:tabular-nums">'+vs+'</span></div><div class="ccbar"><div class="ccfill" style="width:'+(fr*100).toFixed(1)+'%;background:linear-gradient(90deg,'+col+'55,'+col+');box-shadow:0 0 9px '+col+'aa"></div></div></div>';}).join('');
|
|
1141
|
+
return head+bars;
|
|
1142
|
+
}
|
|
1143
|
+
// true terminal typewriter — types each real narration line char-by-char with a blinking cursor
|
|
1144
|
+
function typeLog(el,lines,col){
|
|
1145
|
+
if(!el)return;if(window.__cclogT){clearTimeout(window.__cclogT);window.__cclogT=null;}
|
|
1146
|
+
el.innerHTML='';
|
|
1147
|
+
function colorOf(L){return (L.indexOf('✓')>=0||L.indexOf('🔏')>=0)?'#34d399':(L.indexOf('⚠')>=0?'#fbbf24':col);}
|
|
1148
|
+
function esc(s){return s.replace(/&/g,'&').replace(/</g,'<');}
|
|
1149
|
+
var divs=lines.map(function(L){var dv=document.createElement('div');dv.className='ccline';dv.style.color=colorOf(L);el.appendChild(dv);return dv;});
|
|
1150
|
+
var reduce=(window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches);
|
|
1151
|
+
if(reduce){for(var i=0;i<lines.length;i++)divs[i].innerHTML=esc(lines[i]);return;}
|
|
1152
|
+
var cur=document.createElement('span');cur.className='cccur';cur.innerHTML=' ';
|
|
1153
|
+
var li=0,ci=0;
|
|
1154
|
+
function step(){
|
|
1155
|
+
if(li>=lines.length){if(divs.length)divs[divs.length-1].appendChild(cur);window.__cclogT=null;return;}
|
|
1156
|
+
var L=lines[li];ci++;divs[li].innerHTML=esc(L.slice(0,ci));divs[li].appendChild(cur);
|
|
1157
|
+
var nl=(ci>=L.length);if(nl){li++;ci=0;}
|
|
1158
|
+
window.__cclogT=setTimeout(step,nl?170:11);
|
|
1159
|
+
}
|
|
1160
|
+
step();
|
|
1161
|
+
}
|
|
1162
|
+
// HUD provenance strip — every field is a REAL number from this run (proves it is computed, not mocked)
|
|
1163
|
+
function ccHud(j,col){var th=(LANG==='th');var nStrat=((j.armStats||[]).filter(function(x){return x.pulls>0;})).length;var hash=(j.sovereign&&j.sovereign.certify&&j.sovereign.certify.payloadHash)?('#'+j.sovereign.certify.payloadHash.slice(0,8).toUpperCase()):'—';var ver=!!j.verify;return '<div class="cchud"><span>'+(th?'เครื่องยนต์':'ENGINE')+' <b>'+(j.engine||'portfolio')+'</b></span><span>'+(th?'การทดลอง':'EXPERIMENTS')+' <b>'+(j.evaluations||'?')+'</b></span><span>'+(th?'กลยุทธ์':'STRATEGIES')+' <b>'+nStrat+'</b></span><span>'+(th?'เซ็น':'SIGNED')+' <b>'+hash+'</b></span><span style="color:'+(ver?'#34d399':'#fbbf24')+'">'+(th?'ตรวจสอบ':'VERIFIED')+' <b>'+(ver?'✓':'…')+'</b></span></div>';}
|
|
1164
|
+
// ENGINE CORE — the REAL competing strategies the engine ran (the genuine multi-strategy "AI-multiverse" brain)
|
|
1165
|
+
function ccArms(j,col){var a=(j.armStats||[]).filter(function(x){return x.pulls>0;}).sort(function(x,y){return y.pulls-x.pulls;});if(!a.length)return '';var th=(LANG==='th');var tot=a.reduce(function(s,x){return s+x.pulls;},0)||1;var cells=a.map(function(x){var w=Math.round(x.pulls/tot*100);var c=(typeof ARMCOL!=='undefined'&&ARMCOL[x.name])||col;return '<div class="ccarm"><div class="an"><i style="display:inline-block;width:8px;height:8px;border-radius:50%;background:'+c+'"></i>'+sName(x.name)+'</div><div class="am"><div class="af" style="width:'+w+'%;background:'+c+'"></div></div><div class="aw">'+x.pulls+'× · '+(x.improvements||0)+' '+(th?'ครั้งที่ดีขึ้น':'wins')+'</div></div>';}).join('');return '<div class="cccore"><div class="cccore-h">⚙ '+(th?('แกนสมอง — '+a.length+' กลยุทธ์แข่งกันค้นหาสด (สมองหลายกลยุทธ์จริง ไม่ใช่ข้อความสำเร็จรูป)'):('ENGINE CORE — '+a.length+' strategies competed live (a real multi-strategy brain, not canned text)'))+'</div><div class="ccarms">'+cells+'</div></div>';}
|
|
1166
|
+
// WHAT YOU DO NEXT — the persona-tailored bridge from demo to your real work (answers "เอาไปทำอะไรต่อ")
|
|
1167
|
+
function ccNextStep(v,exp,dims,col,pct){var th=(LANG==='th');var recipe=dims.map(function(d){var val=+exp[d.name];var vs=(d.type==='int')?String(Math.round(val)):(Math.abs(val)<1?val.toFixed(3):val.toFixed(1));return d.name+'='+vs;}).join(' · ');
|
|
1168
|
+
var P={aerospace:['If you run a satellite link','ถ้าคุณดูแลลิงก์ดาวเทียม'],genomics:['If you are a drug researcher','ถ้าคุณเป็นนักวิจัยยา'],solar:['If you run a solar / grid site','ถ้าคุณดูแลโรงไฟฟ้าโซลาร์/กริด'],ml:['If you tune models (bank / gov)','ถ้าคุณจูนโมเดล (แบงก์/รัฐ)'],database:['If you run production infra','ถ้าคุณดูแลระบบ/ฐานข้อมูลจริง'],devops:['If you own security & compliance','ถ้าคุณดูแลความปลอดภัย/คอมไพลแอนซ์']}[v.key]||['If this is your process','ถ้านี่คือกระบวนการของคุณ'];
|
|
1169
|
+
var who=th?P[1]:P[0];
|
|
1170
|
+
var s1=th?('① ใช้สูตรนี้: <b style="color:#e6edff">'+recipe+'</b> → '+(v.scoreName||'score')+' '+pct.toFixed(1)):('① Lock this recipe: <b style="color:#e6edff">'+recipe+'</b> → '+(v.scoreName||'score')+' '+pct.toFixed(1));
|
|
1171
|
+
var s2=th?'② ยืนยัน: เอาค่านี้ไปลอง <u>จริงหนึ่งครั้ง</u> ในงานของคุณ (แทนการจำลอง)':'② Confirm it: run this ONE setting for real, once (instead of the simulation)';
|
|
1172
|
+
var s3=th?('③ ทำกับงานจริงของคุณ: '+v.realWorld+' — Melete ค้นหาแบบเดียวกันบนระบบจริงของคุณ ออฟไลน์ 100% แล้วเซ็นใบรับรองให้ยื่นตรวจ/จดสิทธิบัตร'):('③ Do it on YOUR problem: '+v.realWorld+' — Melete runs the same search on your real system, fully offline, and signs a certificate for your audit / patent trail');
|
|
1173
|
+
return '<div style="margin-top:13px;border-top:1px solid rgba(255,255,255,.1);padding-top:12px"><div class="cccore-h" style="color:'+col+'">▸ '+(th?'แล้วเอาไปทำอะไรต่อ — ':'WHAT YOU DO NEXT — ')+who+'</div><div style="font-size:12.5px;color:#cdd6ee;line-height:1.75">'+s1+'<br>'+s2+'<br>'+s3+'</div><div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px"><button class="ccmore" onclick="gMore()">▶ '+(th?'ลองต่ออีกหน่อย (รันเพิ่ม)':'Run more experiments')+'</button><button class="ccmore" onclick="gDL(\\'melete-verdict.json\\',(window.LASTJ||{}).sovereign)">↓ '+(th?'ใบรับรองที่เซ็นแล้ว':'Signed certificate')+'</button></div><div style="font-size:10.5px;color:#7a89a8;margin-top:8px">'+(th?'“ลองต่ออีกหน่อย” = กดเพื่อให้ Melete รันการทดลองเพิ่ม (ไม่รันเองอัตโนมัติ) — ตัวเลขอัปเดตสดทุกครั้ง พิสูจน์ว่าคำนวณจริง ไม่ใช่ mockup':'“Run more” = press to let Melete run extra experiments (it does NOT auto-run) — the numbers update live each press, proving it is really computed, not a mockup')+'</div></div>';}
|
|
1174
|
+
function renderJournalist(){var j=window.LASTJ;var el=document.getElementById('journalist');if(!el)return;if(!j||!j.narration||!j.vertical){el.style.display='none';return;}var th=(LANG==='th');var v=j.vertical;var col=VERT_THEME[v.key]||'#22d3ee';var lines=(j.narration.lines||[]).slice();var pct=Math.max(0,Math.min(100,+((j.best&&j.best.value))||0));var dims=(j.space||[]);var exp=(j.best&&j.best.experiment)||{};el.style.display='block';
|
|
1175
|
+
var brk='<span class="ccbrk tl"></span><span class="ccbrk tr"></span><span class="ccbrk bl"></span><span class="ccbrk br"></span>';
|
|
1176
|
+
var head='<div class="cchead"><span class="ccrec"></span><span style="font-size:13px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:'+col+'">'+v.emoji+' MELETE COMMAND CENTER</span><span style="font-size:12px;color:#cdd6ee;font-weight:700">'+v.title+'</span><span style="font-size:10.5px;color:#7a89a8;margin-left:auto">'+v.sector+'</span></div>';
|
|
1177
|
+
var scene='<div class="ccscene">'+vScene(v.key,pct,exp,dims,col)+ccGauges(dims,exp,col,pct,v)+'</div>';
|
|
1178
|
+
var foot='<div style="margin-top:11px;padding-top:10px;border-top:1px solid #ffffff14;font-size:11px;color:#8a98b8">'+(th?'⚙ ปุ่ม·คะแนน: ':'⚙ knobs · score: ')+v.knobsCopy+' → '+v.scoreCopy+'</div>';
|
|
1179
|
+
el.innerHTML='<div class="cmdcenter" style="--cc:'+col+';border:1px solid '+col+'55;box-shadow:0 26px 60px -30px '+col+'66, inset 0 0 70px '+col+'0c">'+brk+head+ccHud(j,col)+'<div class="ccgrid">'+scene+'<div class="cclog" id="cclog"></div></div>'+ccArms(j,col)+ccNextStep(v,exp,dims,col,pct)+foot+'</div>';
|
|
1180
|
+
typeLog(document.getElementById('cclog'),lines,col);}
|
|
1181
|
+
// source-of-result banner — always shows WHICH button produced what you're looking at (kills the "where did this come from / why did it change" confusion)
|
|
1182
|
+
function setRunSrc(kind,label,col){var el=document.getElementById('runsrc');if(!el)return;var th=(LANG==='th');el.style.display='block';el.innerHTML='<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 12px;padding:11px 15px;border-radius:13px;border:1px solid '+col+'66;background:linear-gradient(90deg,'+col+'22,'+col+'08);box-shadow:0 0 0 1px '+col+'22 inset,0 10px 30px -22px '+col+'88"><span style="width:8px;height:8px;border-radius:50%;background:'+col+';box-shadow:0 0 10px '+col+'"></span><span style="font-size:11px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:'+col+'">'+(th?'ผลลัพธ์จาก':'RESULT FROM')+'</span><span style="font-size:14.5px;font-weight:800;color:#1a1b30">'+label+'</span><span style="font-size:11.5px;color:#8890a8;margin-left:auto">'+kind+'</span></div>';}
|
|
1183
|
+
function gMore(){if(!window.__vkey)return;var nb=Math.min(160,(window.__vbudget||50)+40);gVertical(window.__vkey,nb);}
|
|
1184
|
+
function gVertical(key,budget){window.__vkey=key;var b=Math.max(20,Math.min(160,budget||50));window.__vbudget=b;var out=document.getElementById('out');var t=document.getElementById('try');if(t)t.scrollIntoView({behavior:'smooth',block:'start'});if(out)out.textContent=(b>50?('▶ running '+b+' experiments on the '+key+' scenario…'):('▶ running real Melete engine on the '+key+' scenario…'));stopPlay();
|
|
1185
|
+
fetch('/discover',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({vertical:key,budget:b})}).then(function(r){return r.json();}).then(function(j){window.LASTJ=j;if(j.error){if(out)out.textContent='⚠ '+j.error;return;}var th=(LANG==='th');var vt=(j.vertical&&j.vertical.title)||key;setRunSrc((th?'การ์ด Live Demo · กดอีกครั้งเพื่อรันใหม่':'Live-demo card · press again to re-run')+(b>50?(' · '+b+' '+(th?'การทดลอง':'experiments')):''),(j.vertical&&j.vertical.emoji?j.vertical.emoji+' ':'')+vt,VERT_THEME[key]||'#22d3ee');if(out)out.innerHTML='🔬 <b>Best:</b> '+(+j.best.value).toFixed(2)+' at <b>'+JSON.stringify(j.best.experiment)+'</b> · '+j.evaluations+' experiments';renderMap(j);var jel=document.getElementById('journalist');if(jel&&jel.scrollIntoView)setTimeout(function(){jel.scrollIntoView({behavior:'smooth',block:'center'});},200);}).catch(function(e){if(out)out.textContent='⚠ '+e.message;});}
|
|
1186
|
+
function gDL(name,obj){try{var b=new Blob([JSON.stringify(obj,null,2)],{type:'application/json'});var u=URL.createObjectURL(b);var a=document.createElement('a');a.href=u;a.download=name;document.body.appendChild(a);a.click();document.body.removeChild(a);setTimeout(function(){URL.revokeObjectURL(u);},800);}catch(e){}}
|
|
1187
|
+
function gVerifyVerdict(){var j=window.LASTJ;if(!j||!j.sovereign)return;var th=(LANG==='th');var o=document.getElementById('sovout');o.innerHTML='<span style="color:#8890a8;font-size:13px">'+(th?'กำลังตรวจ…':'verifying…')+'</span>';fetch('/sovereign/verify',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(j.sovereign)}).then(function(r){return r.json();}).then(function(v){o.innerHTML='<span style="color:'+(v.ok?'#0e7a4f':'#c0392b')+';font-size:13.5px;font-weight:700">'+(v.ok?'✓ ':'✗ ')+(th?(v.ok?'ลายเซ็นถูกต้อง — provenance ตรวจ offline ผ่าน':'ตรวจไม่ผ่าน: '+v.reason):v.reason)+'</span>';}).catch(function(){o.innerHTML='<span style="color:#c33;font-size:13px">error</span>';});}
|
|
1188
|
+
function gReplay(){var j=window.LASTJ;if(!j||!j.replayToken)return;var th=(LANG==='th');var o=document.getElementById('sovout');o.innerHTML='<span style="color:#8890a8;font-size:13px">'+(th?'กำลังเล่นซ้ำ…':'replaying…')+'</span>';fetch('/replay/verify',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(j.replayToken)}).then(function(r){return r.json();}).then(function(v){var ok=v.signatureValid&&v.reproduced;o.innerHTML='<span style="color:'+(ok?'#0e7a4f':'#c0392b')+';font-size:13.5px;font-weight:700">'+(ok?'⏪ ':'✗ ')+(th?(ok?'เล่นซ้ำได้เป๊ะทุกขั้น (DISCOVER→DECIDE→DIAGNOSE) — offline ไม่ต้องมีเซิร์ฟเวอร์':'เล่นซ้ำไม่ตรง: '+v.reason):v.reason)+'</span>';}).catch(function(){o.innerHTML='<span style="color:#c33;font-size:13px">error</span>';});}
|
|
1189
|
+
function renderSovereign(){var j=window.LASTJ;var el=document.getElementById('sovcard');if(!el)return;var s=j&&j.sovereign;if(!s||!s.certify){el.style.display='none';return;}var th=(LANG==='th');var hash=s.certify.payloadHash?s.certify.payloadHash.slice(0,18)+'…':'';var iq=(s.decide&&isFinite(s.decide.processIQ))?s.decide.processIQ:'';var dec=s.decide?s.decide.decision:'';var hasReplay=!!j.replayToken;el.style.display='block';el.innerHTML='<div style="background:rgba(255,255,255,.86);backdrop-filter:blur(12px);border:1px solid #d9d3f4;border-radius:20px;padding:21px 23px;box-shadow:0 28px 60px -36px rgba(70,40,140,.5)"><div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:6px"><span style="font-size:19px">👑</span><span style="font-size:13px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#6d28d9">'+(th?'คำตัดสินที่เซ็น + ตรวจสอบได้':'Signed Sovereign Verdict')+'</span><span style="font-size:11px;font-weight:700;color:#0e7a4f;background:#ecfdf5;border:1px solid #bfeee0;padding:2px 8px;border-radius:99px">'+s.certify.standard+'</span></div><div style="font-size:13px;color:#475;margin-bottom:3px">'+(th?'การตัดสิน: ':'decision: ')+'<b style="color:#1a1b30">'+dec+'</b>'+(iq!==''?(' · Φ IQ <b>'+iq+'</b>'):'')+'</div><div style="font-size:11.5px;color:#9aa0b8;font-family:ui-monospace,Menlo,monospace;margin-bottom:12px">Ed25519 · sha256 · hash '+hash+'</div><div style="display:flex;gap:8px;flex-wrap:wrap"><button class="btn ghost" style="font-size:12.5px;padding:8px 13px" onclick="gDL(\\'melete-verdict.json\\',window.LASTJ.sovereign)">⬇ '+(th?'ใบรับรอง':'Verdict')+'</button>'+(hasReplay?('<button class="btn ghost" style="font-size:12.5px;padding:8px 13px" onclick="gDL(\\'melete-replay-token.json\\',window.LASTJ.replayToken)">⬇ '+(th?'Replay Token':'Replay token')+'</button>'):'')+'<button class="btn primary" style="font-size:12.5px;padding:8px 13px" onclick="gVerifyVerdict()">✓ '+(th?'ตรวจ offline':'Verify offline')+'</button>'+(hasReplay?('<button class="btn primary" style="font-size:12.5px;padding:8px 13px" onclick="gReplay()">⏪ '+(th?'เล่นซ้ำ':'Replay')+'</button>'):'')+'</div><div id="sovout" style="margin-top:11px"></div><div class="muted" style="font-size:11.5px;margin-top:9px">'+(th?'ดาวน์โหลดแล้วส่งให้ผู้ตรวจ/compliance ได้เลย — เขา re-run เองพิสูจน์ได้ ไม่ต้องเชื่อเรา (provenance + reproducibility ไม่ใช่ proof ว่าโค้ดไม่มีบั๊ก)':'hand it to an auditor — they re-verify & replay it themselves, no trust in us required (provenance + reproducibility — not a proof your code is bug-free)')+'</div></div>';}
|
|
1190
|
+
function renderAegis(){var j=window.LASTJ;var el=document.getElementById('aegis');if(!el)return;var a=j&&j.aegis;if(!a||!a.best||!a.best.experiment){el.style.display='none';return;}var th=(LANG==='th');var dims=(j.space||[]);var rb=a.best.experiment;var raw=a.rawBest&&a.rawBest.experiment;var sgn=(j.goal==='minimize')?-1:1;var traded=(+a.tradedHeight)||0;var robPct=Math.round((+a.robustnessOfBest||0)*100);
|
|
1191
|
+
var fragile=(raw && (Math.abs(sgn*((+a.rawBest.value)-(+a.best.value)))>0.02*Math.max(1e-9,Math.abs(+a.rawBest.value)))) && robPct<92;
|
|
1192
|
+
var chip=function(e){return dims.length?dims.map(function(d){return '<span style="display:inline-block;background:#fff;border:1px solid #cdeee6;border-radius:8px;padding:4px 9px;margin:2px 4px 2px 0;font-size:13px;font-weight:700;color:#1a1b30">'+d.name+'='+(+e[d.name]).toFixed(d.type==='int'?0:2)+'</span>';}).join(''):'';};
|
|
1193
|
+
el.style.display='block';
|
|
1194
|
+
var inner;
|
|
1195
|
+
if(fragile){inner='<div style="font-size:15px;color:#0e7a4f;font-weight:800;margin-bottom:7px">'+(th?'พบสูตรที่ "ทนทานกว่า" — รอดโลกจริง':'A more ROBUST setting — one that survives the real world')+'</div><div style="margin-bottom:4px">'+chip(rb)+'<span style="font-size:14px;color:#475;margin-left:4px">→ '+(+a.best.value).toPrecision(4)+' · '+(th?'ทนทาน ':'robust ')+robPct+'%</span></div><div style="font-size:12.5px;color:#8890a8;margin-top:6px">'+(th?'ยอดที่คะแนนสูงสุด ('+(raw?dims.map(function(d){return d.name+'='+(+raw[d.name]).toFixed(2);}).join(' '):'')+' → '+(+a.rawBest.value).toPrecision(4)+') แหลม/เปราะ — ขยับนิดเดียวอาจตกฮวบ AEGIS เลยแนะค่าที่นิ่งกว่า (แลกความสูง '+traded.toFixed(3)+' เพื่อความเสถียร)':'the highest-scoring peak ('+(+a.rawBest.value).toPrecision(4)+') is sharp/fragile — a tiny drift can collapse it, so AEGIS recommends the steadier setting (traded '+traded.toFixed(3)+' of height for stability)')+'</div>';}
|
|
1196
|
+
else{inner='<div style="font-size:15px;color:#0e7a4f;font-weight:800;margin-bottom:6px">✓ '+(th?'จุดที่ดีที่สุดของคุณทนทานอยู่แล้ว':'Your optimum is already robust')+'</div><div style="font-size:13px;color:#475">'+chip(rb)+'<span style="margin-left:4px">'+(th?'ทนต่อการแกว่งในโลกจริง ':'survives real-world wobble ')+'('+(th?'ทนทาน ':'robust ')+robPct+'%)</span></div>';}
|
|
1197
|
+
el.innerHTML='<div style="background:rgba(255,255,255,.82);backdrop-filter:blur(12px);border:1px solid #c7ece2;border-radius:20px;padding:20px 22px;box-shadow:0 26px 58px -36px rgba(14,122,79,.4)"><div style="display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:8px"><span style="font-size:18px">🛡</span><span style="font-size:13px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#0e7a4f">AEGIS</span><span style="font-size:12px;color:#0e9f6e;font-weight:600">'+(th?'เครื่องยนต์ที่หาคำตอบ "ทนทาน" ไม่ใช่แค่คะแนนสูง':'the engine that finds a robust answer, not just a high score')+'</span></div>'+inner+'<div class="muted" style="font-size:11.5px;margin-top:9px">'+(th?'AEGIS เลือกค่าที่ผลไม่ตกแม้สภาพจริงจะแกว่ง — สิ่งที่ optimizer ทั่วไปไม่ทำ':'AEGIS picks the setting whose result holds even when conditions wobble — what ordinary optimizers don\\'t do')+'</div></div>';}
|
|
1198
|
+
// CONVERGENCE VORTEX — the search drawn as a gravity well: radius = score (the glowing gold core IS the
|
|
1199
|
+
// best answer), dashed rings mark real score levels, lineage edges flow inward. Every coordinate encodes a
|
|
1200
|
+
// real number, so it's legible AND honest (no arbitrary scatter). Obsidian-dark, tap-to-trace, mobile.
|
|
1201
|
+
function renderBrain(){var j=window.LASTJ;var el=document.getElementById('brain');if(!el)return;var t=j&&j.lineage;if(!t||!t.nodes||t.nodes.length<3||t.root<0){el.style.display='none';return;}var th=(LANG==='th');var N=t.nodes;var goalMin=(j.goal==='minimize');
|
|
1202
|
+
var vmin=Infinity,vmax=-Infinity;for(var i=0;i<N.length;i++){if(N[i].value<vmin)vmin=N[i].value;if(N[i].value>vmax)vmax=N[i].value;}var vr=Math.max(1e-9,vmax-vmin);
|
|
1203
|
+
var dims=(j.space||[]);var obsr=(j.observations||[]);
|
|
1204
|
+
var fmtv=function(v){return (Math.abs(v)<1?(+v).toFixed(2):(+v).toFixed(1));};
|
|
1205
|
+
var q=function(v){return goalMin?((vmax-v)/vr):((v-vmin)/vr);}; // 1 = best
|
|
1206
|
+
var colQ=function(qq){qq=Math.max(0,Math.min(1,qq));var st=[[0,91,108,240],[0.5,34,211,238],[0.82,52,211,153],[1,251,191,36]];for(var s=1;s<st.length;s++){if(qq<=st[s][0]){var a=st[s-1],b=st[s];var u=(qq-a[0])/((b[0]-a[0])||1);return 'rgb('+Math.round(a[1]+(b[1]-a[1])*u)+','+Math.round(a[2]+(b[2]-a[2])*u)+','+Math.round(a[3]+(b[3]-a[3])*u)+')';}}return 'rgb(251,191,36)';};
|
|
1207
|
+
// build the search tree (children by array index) + a radial tidy-tree angle (sunburst sectors by leaf count)
|
|
1208
|
+
var kids={};for(var k=0;k<N.length;k++){var pp=N[k].parent;if(pp!=null){(kids[pp]=kids[pp]||[]).push(k);}}
|
|
1209
|
+
var rootPos=0;for(var k=0;k<N.length;k++){if(N[k].i===t.root){rootPos=k;break;}}
|
|
1210
|
+
var leaves=new Array(N.length);for(var k=0;k<N.length;k++)leaves[k]=0;
|
|
1211
|
+
var cnt=function(u){var c=kids[u];if(!c||!c.length){leaves[u]=1;return 1;}var s=0;for(var z=0;z<c.length;z++)s+=cnt(c[z]);leaves[u]=s;return s;};cnt(rootPos);
|
|
1212
|
+
var ang=new Array(N.length);for(var k=0;k<N.length;k++)ang[k]=NaN;
|
|
1213
|
+
var asn=function(u,a0,a1){ang[u]=(a0+a1)/2;var c=kids[u];if(!c)return;var span=a1-a0,acc=a0;for(var z=0;z<c.length;z++){var w=span*(leaves[c[z]]||1)/(leaves[u]||1);asn(c[z],acc,acc+w);acc+=w;}};
|
|
1214
|
+
asn(rootPos,-Math.PI/2,-Math.PI/2+2*Math.PI);
|
|
1215
|
+
for(var k=0;k<N.length;k++){if(isNaN(ang[k]))ang[k]=-Math.PI/2+2*Math.PI*k/N.length;}
|
|
1216
|
+
var W=640,H=440,cx0=320,cy0=212,Rmax=180;
|
|
1217
|
+
var rad=function(qq){return Rmax*Math.pow(1-Math.max(0,Math.min(1,qq)),0.74);};
|
|
1218
|
+
var jit=function(k){return ((N[k].i*1103515245+12345)%1000)/1000;};
|
|
1219
|
+
var SX=new Array(N.length),SY=new Array(N.length),Q=new Array(N.length);
|
|
1220
|
+
for(var k=0;k<N.length;k++){var qq=q(N[k].value);Q[k]=qq;var rr=(k===rootPos)?0:Math.max(16,rad(qq)+(jit(k)-0.5)*10);SX[k]=cx0+rr*Math.cos(ang[k]);SY[k]=cy0+rr*Math.sin(ang[k]);}
|
|
1221
|
+
// dashed score-level rings (so the radius axis has a real meaning)
|
|
1222
|
+
var rings='';[0.5,0.9].forEach(function(ql){var rr=rad(ql);var sv=goalMin?(vmax-ql*vr):(vmin+ql*vr);rings+='<circle cx="'+cx0+'" cy="'+cy0+'" r="'+rr.toFixed(1)+'" fill="none" stroke="#ffffff14" stroke-width="1" stroke-dasharray="2 5"/><text x="'+cx0+'" y="'+(cy0-rr+12).toFixed(1)+'" font-size="9" fill="#9aa6c8" text-anchor="middle" font-family="ui-monospace,Menlo,monospace">'+fmtv(sv)+'</text>';});
|
|
1223
|
+
// lineage edges flowing inward toward the core
|
|
1224
|
+
var edges='';for(var k=0;k<N.length;k++){if(k===rootPos)continue;var pp=N[k].parent;if(pp==null)continue;var x1=SX[k],y1=SY[k],x2=SX[pp],y2=SY[pp];var mxp=(x1+x2)/2,myp=(y1+y2)/2;var cxp=mxp+(cx0-mxp)*0.22,cyp=myp+(cy0-myp)*0.22;var tt=Q[k];var sw=(0.5+tt*2.3).toFixed(2);var op=(0.1+tt*0.5).toFixed(2);var dl=(0.1+(1-tt)*0.5).toFixed(2);edges+='<path d="M'+x1.toFixed(1)+' '+y1.toFixed(1)+' Q'+cxp.toFixed(1)+' '+cyp.toFixed(1)+' '+x2.toFixed(1)+' '+y2.toFixed(1)+'" fill="none" stroke="'+colQ(tt)+'" stroke-width="'+sw+'" stroke-linecap="round" opacity="'+op+'" pathLength="1" style="stroke-dasharray:1;stroke-dashoffset:1;animation:branchGrow 1s ease forwards;animation-delay:'+dl+'s"/>';}
|
|
1225
|
+
var core='<circle cx="'+cx0+'" cy="'+cy0+'" r="26" fill="#fbbf24" opacity="0.12"><animate attributeName="r" values="22;33;22" dur="3.2s" repeatCount="indefinite"/></circle><circle cx="'+cx0+'" cy="'+cy0+'" r="13" fill="#fbbf24" opacity="0.2"/>';
|
|
1226
|
+
// a signal pulsing the deepest lineage into the core
|
|
1227
|
+
var deep=0;for(var k=0;k<N.length;k++)if(N[k].depth>N[deep].depth)deep=k;
|
|
1228
|
+
var pcs=[];var pcur=deep,pg=0;while(pcur!=null&&pg++<N.length+1){pcs.push(pcur);pcur=N[pcur].parent;}
|
|
1229
|
+
var pulse='';if(pcs.length>2){var pd='';for(var z=0;z<pcs.length;z++)pd+=(z?' L':'M')+SX[pcs[z]].toFixed(1)+' '+SY[pcs[z]].toFixed(1);pulse='<circle r="3" fill="#fff"><animateMotion dur="2.6s" repeatCount="indefinite" path="'+pd+'"/><animate attributeName="opacity" values="0;1;1;0" dur="2.6s" repeatCount="indefinite"/></circle>';}
|
|
1230
|
+
var nodes='';for(var k=0;k<N.length;k++){var tt=Q[k];var isRoot=(k===rootPos);var rr=(isRoot?7.5:(2.4+tt*5.2)).toFixed(1);var op=(0.5+tt*0.5).toFixed(2);var dl=(0.1+(1-tt)*0.6).toFixed(2);var tip='score '+(+N[k].value).toFixed(3);if(obsr[N[k].i]&&obsr[N[k].i].experiment&&dims.length)tip+=' · '+dims.map(function(d){return d.name+'='+(+obsr[N[k].i].experiment[d.name]).toFixed(2);}).join(', ');nodes+='<circle cx="'+SX[k].toFixed(1)+'" cy="'+SY[k].toFixed(1)+'" r="'+rr+'" fill="'+(isRoot?'#fde047':colQ(tt))+'" opacity="'+op+'" style="opacity:0;animation:nodePop .5s ease forwards;animation-delay:'+dl+'s"><title>'+(isRoot?'★ best · ':'')+tip+'</title></circle>';}
|
|
1231
|
+
var star='<text x="'+SX[rootPos].toFixed(1)+'" y="'+(SY[rootPos]+5).toFixed(1)+'" font-size="17" text-anchor="middle" fill="#fde047" style="opacity:0;animation:nodePop .6s ease forwards;animation-delay:.9s">★</text>';
|
|
1232
|
+
var SC=[];for(var k=0;k<N.length;k++)SC.push({sx:SX[k],sy:SY[k],parent:N[k].parent,value:N[k].value,i:N[k].i});
|
|
1233
|
+
window.BRAIN={W:W,H:H,root:t.root,nodes:SC};
|
|
1234
|
+
var brec=(obsr[t.root]&&obsr[t.root].experiment&&dims.length)?dims.map(function(d){return d.name+'='+(+obsr[t.root].experiment[d.name]).toFixed(2);}).join(' · '):'';
|
|
1235
|
+
var binfo='<div id="braininfo" style="margin-top:10px;padding:10px 13px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:11px;font-size:13.5px;color:#cdd6ee">⭐ '+(th?'จุดที่ดีที่สุด: ':'best so far: ')+'<b style="color:#fde047">'+brec+'</b> → '+(th?'คะแนน ':'score ')+(+N[rootPos].value).toFixed(2)+'</div>';
|
|
1236
|
+
el.style.display='block';
|
|
1237
|
+
el.innerHTML='<div style="background:radial-gradient(120% 100% at 50% 0%,#0d1322,#05060d 72%);border:1px solid #1d2740;border-radius:20px;padding:20px 22px;box-shadow:0 26px 58px -34px rgba(20,20,50,.7)"><div style="margin-bottom:3px"><span style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#a5b4fc">🧠 '+(th?'สมองการค้นพบ — แผนที่การลู่เข้าหาคำตอบ':'Discovery brain — the convergence map')+'</span></div><div style="font-size:12.5px;color:#9aa6c8;margin-bottom:3px">'+(th?'ยิ่งจุดใกล้แกนกลางที่เรืองแสง = คะแนนยิ่งดี · เส้น = เส้นทางการค้นหาที่ไหลเข้าหา “สูตรที่ดีที่สุด” (★ ตรงกลาง) · วงประ = ระดับคะแนน':'closer to the glowing core = higher score · lines = the search flowing inward to the best recipe (★ at center) · dashed rings = score levels')+'</div><div style="font-size:12px;color:#a5b4fc;font-weight:600;margin-bottom:6px">👆 '+(th?'แตะ/คลิกจุดไหนก็ได้ → เส้นทางจากจุดนั้นถึงคำตอบดีที่สุดจะสว่างขึ้น + โชว์สูตร (มือถือก็แตะได้)':'Tap/click any dot → its path to the best answer lights up + shows the recipe (works on mobile)')+'</div><svg viewBox="0 0 '+W+' '+H+'" style="width:100%;height:auto;display:block;cursor:pointer" onclick="gBrainClick(event)">'+rings+edges+'<g id="brainpath"></g>'+core+pulse+nodes+star+'</svg>'+binfo+'<div style="font-size:11.5px;color:#7a89a8;margin-top:7px">'+(th?'จุดใหญ่/อุ่น = คะแนนสูง · ★ ทอง = สูตรที่ดีที่สุด · '+N.length+' การทดลอง':'bigger / warmer = higher score · ★ gold = the best recipe · '+N.length+' experiments')+'</div></div>';}
|
|
1238
|
+
function gBrainClick(evt){var B=window.BRAIN;if(!B)return;var svg=evt.currentTarget;var r=svg.getBoundingClientRect();var mx=(evt.clientX-r.left)/r.width*B.W,my=(evt.clientY-r.top)/r.height*B.H;var bi=-1,bd=1e18;for(var i=0;i<B.nodes.length;i++){var dd=(B.nodes[i].sx-mx)*(B.nodes[i].sx-mx)+(B.nodes[i].sy-my)*(B.nodes[i].sy-my);if(dd<bd){bd=dd;bi=i;}}if(bi<0)return;var chain=[];var cur=bi,g=0;while(cur!=null&&g++<B.nodes.length+1){chain.push(cur);cur=B.nodes[cur].parent;}var d='M'+B.nodes[chain[0]].sx.toFixed(1)+' '+B.nodes[chain[0]].sy.toFixed(1);for(var i=1;i<chain.length;i++)d+=' L'+B.nodes[chain[i]].sx.toFixed(1)+' '+B.nodes[chain[i]].sy.toFixed(1);var s=B.nodes[chain[0]],e=B.nodes[chain[chain.length-1]];var g2=document.getElementById('brainpath');if(!g2)return;g2.innerHTML='<path d="'+d+'" fill="none" stroke="#a5b4fc" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round" opacity="0.97" pathLength="1" style="stroke-dasharray:1;stroke-dashoffset:1;animation:branchGrow 1.1s ease forwards;filter:drop-shadow(0 0 4px #a5b4fc)"/><circle cx="'+s.sx.toFixed(1)+'" cy="'+s.sy.toFixed(1)+'" r="6" fill="#a5b4fc"><animate attributeName="r" values="5;9;5" dur="1.4s" repeatCount="indefinite"/></circle><circle cx="'+e.sx.toFixed(1)+'" cy="'+e.sy.toFixed(1)+'" r="9" fill="none" stroke="#fde047" stroke-width="2.5"><animate attributeName="r" values="9;14;9" dur="1.6s" repeatCount="indefinite"/></circle>';
|
|
1239
|
+
var bn=B.nodes[bi];var inf=document.getElementById('braininfo');var LJ=window.LASTJ;if(inf&&LJ&&LJ.observations&&LJ.observations[bn.i]&&LJ.observations[bn.i].experiment){var ex=LJ.observations[bn.i].experiment;var rc=(LJ.space||[]).map(function(d){return d.name+'='+(+ex[d.name]).toFixed(2);}).join(' · ');var th=(LANG==='th');inf.innerHTML='👆 '+(th?'จุดที่เลือก: ':'this point: ')+'<b>'+rc+'</b> → '+(th?'คะแนน ':'score ')+(+bn.value).toFixed(2)+(bn.i===B.root?(' · '+(th?'⭐ ดีที่สุด':'⭐ the best')):'');}}
|
|
1240
|
+
function renderEta(){var j=window.LASTJ;var el=document.getElementById('eta');if(!el)return;var e=j&&j.efficiency;if(!e||!isFinite(e.eta)||e.grade==='unknown'){el.style.display='none';return;}var th=(LANG==='th');var pct=Math.round(e.eta*100);var deg=Math.round(e.eta*360);var gcol=e.grade==='exceptional'?'#0e9f6e':(e.grade==='strong'?'#3b82f6':(e.grade==='fair'?'#b45309':'#c0392b'));var glabel=th?(e.grade==='exceptional'?'ยอดเยี่ยม':(e.grade==='strong'?'แข็งแรง':(e.grade==='fair'?'พอใช้':'อ่อน'))):e.grade;
|
|
1241
|
+
var facts=[['G',e.gain,th?'ได้ผลจริง':'gain captured'],['R',e.robustness,th?'ทนทาน':'robust optimum'],['T',e.trust,th?'เชื่อถือได้':'trustworthy']];
|
|
1242
|
+
var bars=facts.map(function(f){var w=Math.max(2,Math.round(f[1]*100));var weak=(e.weakestLink&&((f[0]==='G'&&e.weakestLink==='gain')||(f[0]==='R'&&e.weakestLink==='robustness')||(f[0]==='T'&&e.weakestLink==='trust')));var bc=weak?'#c0392b':'#7c6cf0';return '<div style="margin:7px 0"><div style="display:flex;justify-content:space-between;font-size:12px;color:#475;margin-bottom:3px"><span><b style="font-family:ui-monospace,Menlo,monospace;color:'+bc+'">'+f[0]+'</b> · '+f[2]+(weak?(' <span style="color:#c0392b;font-weight:700">'+(th?'← จุดอ่อน':'← weak link')+'</span>'):'')+'</span><span style="font-variant-numeric:tabular-nums;color:#33344e;font-weight:700">'+(+f[1]).toFixed(2)+'</span></div><div style="height:7px;background:#f0eefb;border-radius:99px;overflow:hidden"><div style="height:100%;width:'+w+'%;background:linear-gradient(90deg,#6d5cf0,#14b8a6);border-radius:99px;transition:width .9s cubic-bezier(.22,1,.36,1)"></div></div></div>';}).join('');
|
|
1243
|
+
el.style.display='block';
|
|
1244
|
+
el.innerHTML='<div style="position:relative;background:#fff;border:1px solid #ece8fb;border-radius:20px;padding:22px;box-shadow:0 18px 48px -28px rgba(99,76,240,.45);overflow:hidden">'
|
|
1245
|
+
+'<div style="position:absolute;inset:0;background:radial-gradient(120% 80% at 100% 0%,rgba(20,184,166,.06),transparent 60%),radial-gradient(120% 90% at 0% 100%,rgba(109,92,240,.07),transparent 55%);pointer-events:none"></div>'
|
|
1246
|
+
+'<div style="position:relative;display:flex;gap:22px;align-items:center;flex-wrap:wrap">'
|
|
1247
|
+
+'<div style="flex:0 0 auto;width:118px;height:118px;border-radius:50%;background:conic-gradient('+gcol+' '+deg+'deg,#eee9fb 0);display:flex;align-items:center;justify-content:center">'
|
|
1248
|
+
+'<div style="width:92px;height:92px;border-radius:50%;background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;box-shadow:inset 0 0 0 1px #f1edfd">'
|
|
1249
|
+
+'<div style="font-family:ui-monospace,Menlo,monospace;font-size:27px;font-weight:800;color:'+gcol+';line-height:1">'+(+e.eta).toFixed(2)+'</div>'
|
|
1250
|
+
+'<div style="font-size:10.5px;letter-spacing:.5px;text-transform:uppercase;color:'+gcol+';font-weight:700;margin-top:2px">'+glabel+'</div></div></div>'
|
|
1251
|
+
+'<div style="flex:1;min-width:230px">'
|
|
1252
|
+
+'<div style="display:flex;align-items:baseline;gap:9px;flex-wrap:wrap"><span style="font-size:12px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#6d28d9">'+(th?'ประสิทธิภาพการค้นพบ':'Discovery efficiency')+'</span><span style="font-family:ui-monospace,Menlo,monospace;font-size:15px;color:#33344e">η = ∛(G·R·T)</span></div>'
|
|
1253
|
+
+'<div style="font-size:12px;color:#8890a8;margin:4px 0 10px">'+(th?'เลขเดียวที่ซื่อสัตย์ — ได้ผลจริง × ทนทาน × ไม่ถูกปนเปื้อน (geometric mean: เก่งด้านเดียวโกงไม่ได้)':'one honest number — real gain × robust × not confounded (geometric mean: you can\\'t fake it by being good at one thing)')+'</div>'
|
|
1254
|
+
+bars
|
|
1255
|
+
+'<div style="font-size:11px;color:#a0a4b8;margin-top:9px;font-family:ui-monospace,Menlo,monospace">'+(+e.gain).toFixed(2)+' · '+(+e.robustness).toFixed(2)+' · '+(+e.trust).toFixed(2)+' → η '+(+e.eta).toFixed(2)+' · '+e.evaluations+(th?' การทดลอง':' runs')+'</div>'
|
|
1256
|
+
+'</div></div></div>';}
|
|
1257
|
+
function renderBatch(){var j=window.LASTJ;var el=document.getElementById('batchp');if(!el)return;if(!j||!j.space||!j.observations||j.observations.length<4){el.style.display='none';return;}var th=(LANG==='th');el.style.display='block';el.innerHTML='<div style="background:rgba(255,255,255,.82);backdrop-filter:blur(12px);border:1px solid #e7e4f6;border-radius:18px;padding:18px 20px;box-shadow:0 24px 54px -36px rgba(70,55,160,.5)"><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#0e7a8a;margin-bottom:3px">🔬 '+(th?'รันหลายเครื่องพร้อมกัน':'Run several at once')+'</div><div style="font-size:12.5px;color:#8890a8;margin-bottom:11px">'+(th?'ถ้าคุณมีหลายเครื่อง/หลายเตา Melete เลือกชุดการทดลองที่คุ้มสุด+หลากหลาย ให้รันขนานกันรอบเดียว':'If you have several machines/reactors, Melete picks the most valuable, diverse set to run in parallel this round')+'</div><div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap"><label style="font-size:13px;color:#33344e;font-weight:600">'+(th?'จำนวนเครื่อง':'how many at once')+'</label><input id="bk" type="number" min="2" max="12" value="4" style="width:72px;padding:8px;border:1px solid #d7d9ea;border-radius:9px;font-size:14px"><button class="btn primary" onclick="gBatch()" style="font-size:13.5px;padding:9px 16px">🔬 '+(th?'วางแผนรันขนาน':'Plan the parallel batch')+'</button></div><div id="bkout" style="margin-top:12px"></div></div>';}
|
|
1258
|
+
function gBatch(){var j=window.LASTJ;if(!j||!j.space)return;var th=(LANG==='th');var k=parseInt((document.getElementById('bk')||{}).value,10)||4;var out=document.getElementById('bkout');out.innerHTML='<span style="color:#8890a8;font-size:13px">'+(th?'กำลังวางแผน…':'planning…')+'</span>';fetch('/batch',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({space:j.space,observations:j.observations,goal:j.goal||'maximize',k:k})}).then(function(r){return r.json();}).then(function(b){if(b.error||!b.batch){out.innerHTML='<span style="color:#c33;font-size:13px">'+(b.error||'—')+'</span>';return;}var rows=b.batch.map(function(e,i){var cfg=j.space.map(function(d){return d.name+'='+(+e[d.name]).toFixed(d.type==='int'?0:2);}).join(' · ');return '<div style="display:flex;gap:9px;align-items:center;margin:5px 0;font-size:13.5px"><span style="flex:0 0 auto;width:22px;height:22px;border-radius:6px;background:linear-gradient(135deg,#6d5cf0,#14b8a6);color:#fff;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center">'+(i+1)+'</span><span style="color:#1a1b30">'+cfg+'</span></div>';}).join('');out.innerHTML='<div style="font-size:12.5px;color:#475;margin-bottom:6px">'+(th?'รัน '+b.batch.length+' ชุดนี้พร้อมกันได้เลย แล้วเอาคะแนนกลับมาใส่:':'Run these '+b.batch.length+' in parallel, then feed the scores back:')+'</div>'+rows;}).catch(function(){out.innerHTML='<span style="color:#c33;font-size:13px">error</span>';});}
|
|
1259
|
+
function renderWhatif(){var j=window.LASTJ;var el=document.getElementById('whatif');if(!el)return;if(!j||!j.space||!j.observations||j.observations.length<4||!j.best){el.style.display='none';return;}var th=(LANG==='th');var dims=j.space;var best=j.best.experiment||{};var inputs=dims.map(function(d){var v=best[d.name]!=null?(+best[d.name]):((+(d.min||0)+ +(d.max||1))/2);var step=(d.type==='int')?'1':'any';return '<div style="display:flex;align-items:center;gap:8px;margin:5px 0"><label style="flex:0 0 38%;font-size:13px;color:#33344e;font-weight:600">'+d.name+'</label><input class="wifx" data-n="'+d.name+'" type="number" step="'+step+'" value="'+(+v).toFixed(d.type==='int'?0:2)+'" style="flex:1;padding:8px 10px;border:1px solid #d7d9ea;border-radius:9px;font-size:14px;width:0"><span style="font-size:11px;color:#9aa0b8;flex:0 0 auto">'+(+(d.min||0))+'–'+(+(d.max||1))+'</span></div>';}).join('');
|
|
1260
|
+
el.style.display='block';
|
|
1261
|
+
el.innerHTML='<div style="background:rgba(255,255,255,.82);backdrop-filter:blur(12px);border:1px solid #e7e4f6;border-radius:18px;padding:18px 20px;box-shadow:0 24px 54px -36px rgba(70,55,160,.5)"><div style="font-size:13px;font-weight:800;letter-spacing:.4px;text-transform:uppercase;color:#6d28d9;margin-bottom:3px">🔮 '+(th?'ลองถามดู — "ถ้าฉันตั้งค่าเป็น…?"':'Ask "what if I set it to…?"')+'</div><div style="font-size:12.5px;color:#8890a8;margin-bottom:11px">'+(th?'พิมพ์ค่าที่อยากลอง แล้วดูคะแนนที่ Melete ทำนาย — โดยไม่ต้องทดลองจริง (มันจะบอกตรงๆ ว่ามั่นใจหรือเดา)':'Type a setting and see Melete\\'s predicted score — without running it (it tells you if it\\'s sure or guessing)')+'</div>'+inputs+'<button class="btn primary" onclick="gPredict()" style="margin-top:10px;font-size:13.5px;padding:9px 16px">🔮 '+(th?'ทำนายคะแนน':'Predict the score')+'</button><div id="wifout" style="margin-top:12px"></div></div>';}
|
|
1262
|
+
function gPredict(){var j=window.LASTJ;if(!j||!j.space)return;var th=(LANG==='th');var q={};document.querySelectorAll('.wifx').forEach(function(i){var v=parseFloat(i.value);if(isFinite(v))q[i.getAttribute('data-n')]=v;});var out=document.getElementById('wifout');out.innerHTML='<span style="color:#8890a8;font-size:13px">'+(th?'กำลังทำนาย…':'predicting…')+'</span>';fetch('/predict',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({space:j.space,observations:j.observations,query:q})}).then(function(r){return r.json();}).then(function(p){if(p.error||!isFinite(p.predicted)){out.innerHTML='<span style="color:#c33;font-size:13px">'+(p.error||'—')+'</span>';return;}var cmap={measured:{c:'#0e7a4f',t:th?'เชื่อถือได้ (วัดใกล้ตรงนี้แล้ว)':'reliable — measured near here'},confident:{c:'#0e7a4f',t:th?'ค่อนข้างเชื่อถือได้':'fairly reliable'},rough:{c:'#b45309',t:th?'ประมาณคร่าวๆ':'a rough estimate'},guess:{c:'#c0392b',t:th?'นี่คือการเดา — ควรทดลองจริงก่อนเชื่อ':'a GUESS — test it before trusting'}};var cm=cmap[p.confidence]||cmap.rough;out.innerHTML='<div style="display:flex;align-items:baseline;gap:10px;flex-wrap:wrap"><span style="font-size:26px;font-weight:800;font-family:ui-monospace,Menlo,monospace;color:'+cm.c+'">'+(+p.predicted).toPrecision(4)+'</span><span style="font-size:13px;color:#475">'+(isFinite(p.uncertainty)&&p.uncertainty>0?('± '+(+p.uncertainty).toPrecision(2)+' · '):'')+'<b style="color:'+cm.c+'">'+cm.t+'</b></span></div>';}).catch(function(){out.innerHTML='<span style="color:#c33;font-size:13px">error</span>';});}
|
|
1263
|
+
function renderDrift(){var j=window.LASTJ;if(!j||!j.drift)return;var el=document.getElementById('drift');if(!el)return;var dr=j.drift;var th=(LANG==='th');if(!dr.note||dr.note.indexOf('need')>=0){el.style.display='none';return;}var color=dr.detected?'#c0392b':'#0e9f6e';var label=dr.detected?(th?'พบแนวโน้มตามเวลา — ผลอาจปนเปื้อน (confound)':'a time-trend was found — results may be confounded'):(th?'ไม่พบแนวโน้มตามเวลา — ผลไม่ปนเปื้อนกับลำดับ':'no time-trend — results are not confounded with order');var corr=(+dr.residualOrderCorr).toFixed(2);var pct=Math.round((+dr.driftFraction)*100);var w=Math.max(3,Math.min(100,Math.round(Math.abs(+dr.residualOrderCorr)*100)));var bar=dr.detected?'<div style="height:6px;background:#eee;border-radius:9px;overflow:hidden;margin-top:7px"><div style="height:100%;width:'+w+'%;background:linear-gradient(90deg,#f59e0b,#c0392b)"></div></div>':'';var detail=dr.detected?('<div style="font-size:13px;color:#475;margin-top:4px">'+(th?'สัมพันธ์กับลำดับ ':'correlation with order ')+corr+' · ≈'+pct+(th?'% ของการกระจายผล · ทดสอบผู้ชนะใหม่อีกครั้ง':'% of the spread · re-test the winner fresh')+'</div>'):'';el.style.display='block';el.innerHTML='<div style="font-size:13px;font-weight:800;color:'+color+';letter-spacing:.4px;text-transform:uppercase;margin-bottom:6px">⏱ '+(th?'ผลถูกปนเปื้อนตามเวลาไหม':'Time-confound check')+'</div><div style="font-size:15px;color:'+color+';font-weight:700">'+label+'</div>'+bar+detail+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'เช็คว่าส่วนที่ตัวแปรอธิบายไม่ได้ ค่อยๆ เปลี่ยนตามลำดับการทดลองหรือไม่ (เครื่องร้อน/สารเปลี่ยนล็อต) — ความถูกต้องเชิงวิทยาศาสตร์':'checks whether the part your variables can\\'t explain drifts with measurement order (a warming rig, a new reagent batch) — scientific validity')+'</div>';}
|
|
1264
|
+
function renderBaseline(){
|
|
1265
|
+
var j=window.LASTJ;if(!j||!j.baseline)return;var el=document.getElementById('baseline');if(!el)return;
|
|
1266
|
+
var b=j.baseline;var th=(LANG==='th');var min=(j.goal==='minimize');
|
|
1267
|
+
function imp(ref){ if(ref==null||!isFinite(ref))return null; var d=min?(ref-b.best):(b.best-ref); var base=Math.abs(ref)>1e-9?Math.abs(ref):(Math.abs(b.best)>1e-9?Math.abs(b.best):1); return d/base*100; }
|
|
1268
|
+
var vsR=imp(b.random), vsS=imp(b.start);
|
|
1269
|
+
function fmt(p){ if(p==null)return ''; return (p>=0?'+':'')+(Math.abs(p)>=10?Math.round(p):p.toFixed(1))+'%'; }
|
|
1270
|
+
var color=(vsR!=null&&vsR>=0)?'#0e9f6e':'#8890a8';
|
|
1271
|
+
var rows='';
|
|
1272
|
+
rows+='<div style="display:flex;justify-content:space-between;padding:4px 0"><span style="color:#8890a8">'+(th?'จุดเริ่มต้น (ลองครั้งแรก)':'starting point (first try)')+'</span><b>'+(+b.start).toPrecision(4)+'</b></div>';
|
|
1273
|
+
if(b.random!=null)rows+='<div style="display:flex;justify-content:space-between;padding:4px 0"><span style="color:#8890a8">'+(th?'สุ่ม (งบเท่ากัน)':'random search (same budget)')+'</span><b>'+(+b.random).toPrecision(4)+'</b></div>';
|
|
1274
|
+
rows+='<div style="display:flex;justify-content:space-between;padding:4px 0;border-top:1px solid #e7e7ef;margin-top:4px"><span style="color:#1a1b30;font-weight:700">Melete</span><b style="color:#6d28d9">'+(+b.best).toPrecision(4)+'</b></div>';
|
|
1275
|
+
el.style.display='block';
|
|
1276
|
+
el.innerHTML='<div style="font-size:13px;font-weight:800;color:#0e9f6e;letter-spacing:.4px;text-transform:uppercase;margin-bottom:8px">📊 '+(th?'ตัวเลขนี้ดีแค่ไหน — เทียบกับเกณฑ์':'How good is this number? — vs baselines')+'</div>'
|
|
1277
|
+
+rows
|
|
1278
|
+
+'<div style="font-size:15px;margin-top:10px;color:#1a1b30">'+(vsR!=null?('<b style="color:'+color+'">'+fmt(vsR)+'</b> '+(th?'ดีกว่าการสุ่ม':'better than random')):'')+(vsS!=null&&isFinite(vsS)?(' · <b>'+fmt(vsS)+'</b> '+(th?'เหนือจุดเริ่มต้น':'over your start')):'')+'</div>'
|
|
1279
|
+
+'<div class="muted" style="font-size:11.5px;margin-top:8px">'+(th?'เทียบบนงบจำนวนการทดลองเท่ากัน — ทำให้คะแนนดิบมีความหมาย':'Compared at the same experiment budget — so the raw score actually means something.')+'</div>';
|
|
1280
|
+
}
|
|
1281
|
+
function renderHero(){
|
|
1282
|
+
var j=window.LASTJ;if(!j||!j.best){return;}var el=document.getElementById('hero');if(!el)return;
|
|
1283
|
+
var th=(LANG==='th');var min=(j.goal==='minimize');
|
|
1284
|
+
function tile(label,val){return '<div style="background:rgba(255,255,255,.08);border-radius:14px;padding:14px"><div style="font-size:11px;color:#a5b4fc;text-transform:uppercase;letter-spacing:.3px">'+label+'</div><div style="font-size:18px;font-weight:700;margin-top:4px">'+val+'</div></div>';}
|
|
1285
|
+
var chips=Object.keys(j.best.experiment||{}).map(function(k){var v=j.best.experiment[k];var vs=(typeof v==='number')?(Math.abs(v)>=100?Math.round(v):(+v).toFixed(2)):v;return '<span style="display:inline-block;background:rgba(255,255,255,.14);color:#fff;border-radius:9px;padding:6px 11px;margin:3px 4px 3px 0;font-size:13px;font-weight:600">'+k+' = '+vs+'</span>';}).join('');
|
|
1286
|
+
var vsR=null,vsS=null;
|
|
1287
|
+
if(j.baseline){var b=j.baseline;var imp=function(ref){if(ref==null||!isFinite(ref))return null;var d=min?(ref-b.best):(b.best-ref);var base=Math.abs(ref)>1e-9?Math.abs(ref):1;return d/base*100;};vsR=imp(b.random);vsS=imp(b.start);}
|
|
1288
|
+
function pct(p){return p==null?'':((p>=0?'+':'')+(Math.abs(p)>=10?Math.round(p):p.toFixed(1))+'%');}
|
|
1289
|
+
var rec=j.frontier?j.frontier.recommendation:null;
|
|
1290
|
+
var recTxt=th?(rec==='STOP'?'พอแล้ว':(rec==='CONTINUE'?'ลองต่อได้':'—')):(rec==='STOP'?'Done':(rec==='CONTINUE'?'Run more':'—'));
|
|
1291
|
+
var gtxt='—';if(j.certificate&&j.certificate.withinPct){var w=Math.max(0.01,j.certificate.withinPct);var g=Math.max(0,(100/w-1)*100);gtxt='≤'+(g>=999?'∞':(g<10?g.toFixed(1):Math.round(g)))+'%';}
|
|
1292
|
+
var score=(+j.best.value);var scoreTxt=(Math.abs(score)>=1000?Math.round(score).toLocaleString():(+score).toPrecision(5));
|
|
1293
|
+
el.style.display='block';
|
|
1294
|
+
el.innerHTML='<div style="border-radius:22px;padding:28px;background:linear-gradient(135deg,#1a1b30,#2d2b55);color:#fff;box-shadow:0 22px 60px -26px rgba(45,43,85,.7)">'
|
|
1295
|
+
+'<div style="font-size:12px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:#a5b4fc">🏆 '+(th?'สูตรที่ดีที่สุดที่เจอ':'Best recipe found')+(j.reliable?' · ⚡ reliable':'')+'</div>'
|
|
1296
|
+
+'<div style="margin:12px 0 4px">'+chips+'</div>'
|
|
1297
|
+
+'<div style="display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-top:8px"><div style="font-size:42px;font-weight:800;line-height:1">'+scoreTxt+'</div>'
|
|
1298
|
+
+'<div style="font-size:14px;color:#c7d2fe">'+(vsR!=null?('<b style="color:#6ee7b7">'+pct(vsR)+'</b> '+(th?'ดีกว่าสุ่ม':'vs random')):'')+(vsS!=null&&isFinite(vsS)?(' · <b>'+pct(vsS)+'</b> '+(th?'เหนือจุดเริ่ม':'vs start')):'')+'</div></div>'
|
|
1299
|
+
+'<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:22px">'+tile(th?'การทดลอง':'experiments',(j.evaluations||'—'))+tile(th?'ควรทำต่อ?':'next step',recTxt)+tile(th?'รับรอง':'certified',gtxt)+'</div>'
|
|
1300
|
+
+'<div style="margin-top:18px;font-size:13px;color:'+(j.verify?'#6ee7b7':'#fca5a5')+'">'+(j.verify?('🔒 '+(th?'เซ็นและตรวจสอบแล้ว (Ed25519 ออฟไลน์)':'signed & verified (Ed25519, offline)')):'⚠ unverified')+'</div>'
|
|
1301
|
+
+'</div>';
|
|
1302
|
+
}
|
|
1303
|
+
async function run(){
|
|
1304
|
+
var out=document.getElementById('out');out.textContent='discovering…';document.getElementById('map').className='';stopPlay();
|
|
1305
|
+
window.__vkey=null;var _th=(LANG==='th');setRunSrc(_th?'ปุ่ม “ดู Melete ค้นพบ” · จากค่าที่คุณตั้งในกล่องด้านบน':'the “Watch Melete” button · from the settings in the box above',_th?'⚙ โจทย์ที่คุณตั้งเอง':'⚙ Your custom problem','#6d5cf0');
|
|
1306
|
+
try{
|
|
1307
|
+
var space=JSON.parse(document.getElementById('space').value);
|
|
1308
|
+
var body={space:space,objective:document.getElementById('obj').value,budget:+document.getElementById('budget').value,goal:'maximize',reliable:!!(document.getElementById('reliable')&&document.getElementById('reliable').checked)};
|
|
1309
|
+
var r=await fetch('/discover',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(body)});
|
|
1310
|
+
var j=await r.json();window.LASTJ=j;
|
|
1311
|
+
if(j.error){out.textContent='⚠ '+j.error;return;}
|
|
1312
|
+
out.innerHTML='🔬 <b>Best:</b> score '+(+j.best.value).toFixed(5)+' at <b>'+JSON.stringify(j.best.experiment)+'</b> · found in <b>'+j.evaluations+'</b> experiments. <span class="muted">▶ watch it search below</span>';
|
|
1313
|
+
renderMap(j);
|
|
1314
|
+
}catch(e){out.textContent='⚠ '+e.message;}
|
|
1315
|
+
}
|
|
1316
|
+
// storybook — reveal each comic panel as it scrolls into view (synced Meli effects via CSS)
|
|
1317
|
+
(function(){var ps=[].slice.call(document.querySelectorAll('.panel[data-beat]'));
|
|
1318
|
+
if(!('IntersectionObserver' in window)){ps.forEach(function(p){p.classList.add('in')});return;}
|
|
1319
|
+
var io=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting){e.target.classList.add('in');io.unobserve(e.target);}})},{threshold:0.3,rootMargin:'0px 0px -8% 0px'});
|
|
1320
|
+
ps.forEach(function(p){io.observe(p)});})();
|
|
1321
|
+
setMode('simple');loadPreset();setLang(LANG);
|
|
1322
|
+
</script>
|
|
1323
|
+
</body></html>`;
|
|
1324
|
+
}
|
|
1325
|
+
export function pitchDeck(version = "0.4.0") {
|
|
1326
|
+
const slides = [
|
|
1327
|
+
`<div class="pgem"></div><h1 class="brand">Melete</h1><p class="big">The discovery brain for any expensive process.</p><p class="dim">Tell it what you can change and what "good" means — it finds the best recipe in the fewest real-world experiments, then hands you one decision. · v${version}</p><p class="dim" style="margin-top:18px">→ / space to advance</p>`,
|
|
1328
|
+
`<h2>The problem</h2><p class="big">Ideas are cheap. <b>Experiments are expensive.</b></p><ul><li>Every lab assay, training run, process batch, pricing test costs real time & money — and the search space is enormous.</li><li>Two questions decide who wins: <b>which experiment next?</b> and <b>can you prove how you got there?</b></li><li>Existing optimisers (Vizier, Optuna, Ax) answer the first as a wall of plots — and leave a human to figure out what to actually DO.</li></ul>`,
|
|
1329
|
+
`<h2>The brain</h2><div class="pcardrow"><div class="pgemlg"></div><div><p class="big" style="margin:0">◆ MELETE PRIME</p><p class="dim" style="margin-top:6px">one brain that's smart about everything, in a single decision</p></div></div><ul><li>It runs <b>every lens</b> — how good, how robust, how safe, where the cliffs are, is it drifting, which knobs really matter, is a breakthrough hiding — and <b>triages them by danger</b> into ONE verdict.</li><li><b>Safety outranks ambition:</b> an optimum on a cliff edge is overruled no matter how high it scores; an unreachable target is called before a month is wasted.</li><li>No competitor ships this synthesis. It's the steering wheel on top of the engine.</li></ul>`,
|
|
1330
|
+
`<h2>The formula</h2><p class="big">A single, <b>provable</b> Process-Intelligence score.</p><div class="pformula">Φ = 100 · ∛(O·R·T) · ½(1+C) · U · S · F</div><ul><li><b>O·R·T</b> optimized · robust · trustworthy — a <b>geometric</b> core: any one collapsing collapses Φ (you can't fake it).</li><li>Gated by confidence, understanding, safety, feasibility.</li><li><b>Proven</b> in tests: bounded [0,100] · identity · conjunctive · monotone. Complexity <code>O(n²·D + n·D² + D³)</code> — under a second.</li></ul>`,
|
|
1331
|
+
`<h2>What it sees</h2><p class="big">39 verified engines. One verdict.</p><div class="pgrid"><span>η efficiency</span><span>robustness</span><span>cliffs / tipping points</span><span>achievable ceiling</span><span>time-confound drift</span><span>effective dimensionality</span><span>response shape</span><span>breakthrough radar</span><span>the recipe family</span><span>safe / constrained</span><span>what-if twin</span><span>parallel batch</span></div><p class="dim" style="margin-top:14px">Each is an independently tested module; PRIME composes them.</p>`,
|
|
1332
|
+
`<h2>Proof — measured & reproducible</h2><table><tr><th>adversarial landscape</th><th>Melete</th><th>Bayesian</th><th>random</th></tr><tr><td>smooth</td><td class="win">100%</td><td>99.9%</td><td>83.8%</td></tr><tr><td>rugged / multimodal</td><td class="win">best 🏆</td><td>far behind</td><td>far behind</td></tr><tr><td>high-D (5-D)</td><td class="win">99.6%</td><td>98.7%</td><td>55.5%</td></tr></table><div class="pstats"><div><b>≥99%</b><span>true optimum, every benchmark</span></div><div><b>39 / 39</b><span>engines pass 100/100</span></div><div><b>71</b><span>tests, 0 failed</span></div><div><b>3.7×</b><span>fewer experiments</span></div></div>`,
|
|
1333
|
+
`<h2>The moat</h2><p class="big">Not one algorithm — a defensible <b>composition</b>.</p><ul><li><b>The synthesis brain</b> — safety-first triage of every lens into one decision; nobody else ships it.</li><li><b>Verifiable provenance</b> — every result Ed25519-signed, checkable offline with a public key. Patents & audits need it.</li><li><b>Sovereign</b> — runs air-gapped, on the customer's machine; data never touches a cloud. The angle big-tech can't match.</li><li><b>Universal f(x)</b> — one engine, every domain (pharma · materials · energy · ML · pricing), on-prem.</li></ul>`,
|
|
1334
|
+
`<h2>Honesty</h2><ul><li>Not a "magic" algorithm, not "quantum". The win is <b>the synthesis brain + robustness + verifiable provenance</b> — all measured, all reproducible.</li><li>Optimisation can't be 100% accurate — so we ship 39 <b>100%-passing</b> gauntlets, 71 tests, and benchmarks you can re-run.</li><li>The brain is software; the physical lab/robot is the customer's — we plug into it.</li></ul>`,
|
|
1335
|
+
`<h2>The ask</h2><p class="big">License it, or acquire the code.</p><ul><li>Clean, dependency-free TypeScript: 39 engines + signed trace + universal oracle + HTTP service + CLI + one-command deploy.</li><li>Live at <b>melete.mneme-ai.space</b> with full tests. Sale transfers the repo, the <code>melete-ai</code> npm namespace, and the roadmap.</li><li>For anyone who runs expensive experiments at scale — or sells tooling to those who do.</li></ul><p style="font-size:18px;margin-top:10px;color:#33344e">📧 <b>patsa2561@gmail.com</b> · 🟢 WhatsApp <b>+66 93 945 5645</b> · ✈️ <b>@devson2561</b></p><a class="pbtn-cta" href="mailto:patsa2561@gmail.com?subject=Melete">📩 Get in touch</a>`,
|
|
1336
|
+
];
|
|
1337
|
+
const slideHtml = slides.map((s, i) => `<section class="slide"${i === 0 ? " data-active" : ""}>${s}</section>`).join("\n");
|
|
1338
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
1339
|
+
<title>Melete — pitch</title><style>
|
|
1340
|
+
:root{color-scheme:light}*{box-sizing:border-box}
|
|
1341
|
+
body{margin:0;background:#fbfbfe;color:#16172b;font:18px/1.6 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;overflow:hidden;font-variant-numeric:tabular-nums}
|
|
1342
|
+
body::before{content:"";position:fixed;inset:-20% -10%;z-index:-2;pointer-events:none;background:radial-gradient(34% 34% at 82% 6%,rgba(225,29,72,.13),transparent 62%),radial-gradient(40% 40% at 6% 12%,rgba(109,92,240,.16),transparent 60%),radial-gradient(36% 38% at 92% 80%,rgba(168,85,247,.14),transparent 60%),radial-gradient(30% 30% at 12% 92%,rgba(14,165,183,.13),transparent 60%);filter:blur(22px)}
|
|
1343
|
+
body::after{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.5;background-image:radial-gradient(circle at 1px 1px,rgba(80,70,160,.06) 1px,transparent 0);background-size:30px 30px}
|
|
1344
|
+
.slide{position:fixed;inset:0;display:none;flex-direction:column;justify-content:center;max-width:960px;margin:0 auto;padding:6vh 7vw}
|
|
1345
|
+
.slide[data-active]{display:flex;animation:fade .5s cubic-bezier(.22,1,.36,1)}
|
|
1346
|
+
@keyframes fade{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
|
|
1347
|
+
.brand{font-size:82px;margin:0;font-weight:850;letter-spacing:-2.5px;background:linear-gradient(95deg,#6d5cf0,#0ea5b7,#a855f7);-webkit-background-clip:text;background-clip:text;color:transparent;filter:drop-shadow(0 10px 34px rgba(109,92,240,.32))}
|
|
1348
|
+
h2{font-size:14px;letter-spacing:2px;text-transform:uppercase;color:#0ea5b7;margin:0 0 22px;font-weight:800}
|
|
1349
|
+
.big{font-size:35px;font-weight:800;line-height:1.25;margin:0 0 18px;color:#16172b;letter-spacing:-.5px}
|
|
1350
|
+
.dim{color:#6a6c84;font-size:16px;max-width:680px}
|
|
1351
|
+
ul{margin:0;padding-left:4px;list-style:none}li{margin:13px 0;color:#33344e;font-size:19px;padding-left:26px;position:relative}li::before{content:"◆";position:absolute;left:0;color:#6d5cf0;font-size:13px;top:5px}li b{color:#16172b}
|
|
1352
|
+
table{border-collapse:collapse;font-size:18px;margin:6px 0 20px}th,td{padding:11px 26px 11px 0;text-align:left}th{color:#9698ad;font-size:13px;text-transform:uppercase}td{border-bottom:1px solid #eceef6}
|
|
1353
|
+
.win{color:#0e9f6e;font-weight:800}code{font-family:ui-monospace,monospace;background:#f1f2f8;border-radius:6px;padding:2px 8px;font-size:15px;color:#4338ca}
|
|
1354
|
+
.pgem{width:46px;height:46px;border-radius:10px;background:linear-gradient(135deg,#e11d48,#f43f8e 40%,#a855f7);transform:rotate(45deg);box-shadow:0 10px 30px -6px rgba(225,29,72,.55),inset 0 1px 4px rgba(255,255,255,.7);margin-bottom:30px}
|
|
1355
|
+
.pgemlg{flex:0 0 auto;width:56px;height:56px;border-radius:12px;background:linear-gradient(135deg,#e11d48,#f43f8e 40%,#a855f7);transform:rotate(45deg);box-shadow:0 12px 34px -6px rgba(225,29,72,.55),inset 0 1px 4px rgba(255,255,255,.7)}
|
|
1356
|
+
.pcardrow{display:flex;align-items:center;gap:30px;margin-bottom:18px}
|
|
1357
|
+
.pformula{font-family:ui-monospace,Menlo,monospace;font-size:26px;font-weight:800;color:#4c3fd6;background:rgba(255,255,255,.7);backdrop-filter:blur(12px);border:1px solid #e7e0ff;border-radius:16px;padding:18px 22px;margin:4px 0 18px;box-shadow:0 18px 44px -30px rgba(99,76,240,.5);display:inline-block}
|
|
1358
|
+
.pgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:8px}
|
|
1359
|
+
.pgrid span{background:rgba(255,255,255,.72);backdrop-filter:blur(10px);border:1px solid #ecebf6;border-radius:12px;padding:11px 14px;font-size:14px;font-weight:600;color:#33344e;box-shadow:0 12px 26px -22px rgba(70,55,160,.5)}
|
|
1360
|
+
.pstats{display:flex;flex-wrap:wrap;gap:14px;margin-top:6px}
|
|
1361
|
+
.pstats div{flex:1;min-width:140px;background:rgba(255,255,255,.72);backdrop-filter:blur(10px);border:1px solid #ecebf6;border-radius:14px;padding:14px 16px;box-shadow:0 16px 34px -28px rgba(70,55,160,.5)}
|
|
1362
|
+
.pstats b{display:block;font-size:25px;font-weight:800;letter-spacing:-.5px;background:linear-gradient(135deg,#6d5cf0,#0ea5b7);-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
1363
|
+
.pstats span{font-size:12.5px;color:#6a6c84}
|
|
1364
|
+
.nav{position:fixed;bottom:20px;left:0;right:0;text-align:center;color:#9698ad;font-size:13px;z-index:9}
|
|
1365
|
+
.nav a{color:#5b53e8;text-decoration:none;font-weight:700}.dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:#d9dbe9;margin:0 3px}.dot.on{background:#6d5cf0;width:18px;border-radius:4px}
|
|
1366
|
+
.pbar{position:fixed;top:0;left:0;height:3px;background:linear-gradient(90deg,#e11d48,#a855f7,#6d5cf0,#0ea5b7);z-index:10;transition:width .4s cubic-bezier(.22,1,.36,1)}
|
|
1367
|
+
.pbtn-cta{display:inline-block;margin-top:18px;background:linear-gradient(95deg,#6d5cf0,#0ea5b7);color:#fff;border-radius:12px;padding:13px 26px;font-weight:800;font-size:17px;text-decoration:none;box-shadow:0 14px 32px -12px rgba(99,76,240,.6)}
|
|
1368
|
+
@media(prefers-reduced-motion:reduce){.slide[data-active]{animation:none}body::before{animation:none}}
|
|
1369
|
+
</style></head><body>
|
|
1370
|
+
<div class="pbar" id="pbar" style="width:0"></div>
|
|
1371
|
+
${slideHtml}
|
|
1372
|
+
<div class="nav"><span id="dots"></span> <span id="ctr"></span> · <a href="/">← demo</a></div>
|
|
1373
|
+
<script>
|
|
1374
|
+
var s=[].slice.call(document.querySelectorAll('.slide')),i=0;
|
|
1375
|
+
var dots=s.map(function(_,k){return '<span class="dot'+(k===0?' on':'')+'"></span>'}).join('');
|
|
1376
|
+
document.getElementById('dots').innerHTML=dots;
|
|
1377
|
+
function show(n){i=Math.max(0,Math.min(s.length-1,n));s.forEach(function(el,k){if(k===i)el.setAttribute('data-active','');else el.removeAttribute('data-active');});
|
|
1378
|
+
document.querySelectorAll('.dot').forEach(function(d,k){d.className='dot'+(k===i?' on':'')});document.getElementById('ctr').textContent=(i+1)+' / '+s.length;document.getElementById('pbar').style.width=((i+1)/s.length*100)+'%';}
|
|
1379
|
+
show(0);
|
|
1380
|
+
document.addEventListener('keydown',function(e){if(['ArrowRight','ArrowDown',' ','PageDown'].includes(e.key)){show(i+1);e.preventDefault();}else if(['ArrowLeft','ArrowUp','PageUp'].includes(e.key))show(i-1);else if(e.key==='Home')show(0);else if(e.key==='End')show(s.length-1);});
|
|
1381
|
+
document.addEventListener('click',function(e){if(e.target.tagName!=='A')show(i+1);});
|
|
1382
|
+
</script></body></html>`;
|
|
1383
|
+
}
|
|
1384
|
+
// ── gauntlet ──────────────────────────────────────────────────────────────────
|
|
1385
|
+
export function serverGauntlet() {
|
|
1386
|
+
const html = landingPage("9.9.9");
|
|
1387
|
+
const pitch = pitchDeck("9.9.9");
|
|
1388
|
+
const checks = [
|
|
1389
|
+
{ name: "LANDING-RENDERS", pass: html.startsWith("<!doctype html>") && html.includes("Melete") && html.length > 4000, detail: "world-class landing page renders with hero + sections" },
|
|
1390
|
+
{ name: "LIGHT-THEME", pass: html.includes("--bg:#ffffff") && !html.includes("background:#07070c"), detail: "clean light theme (not the old dark background)" },
|
|
1391
|
+
{ name: "DEMO-FORM", pass: html.includes('id="space"') && html.includes('id="obj"') && html.includes('id="preset"') && html.includes("/discover"), detail: "demo has worked examples + posts to /discover" },
|
|
1392
|
+
{ name: "DISCOVERY-MAP", pass: html.includes("Discovery cinema") && html.includes('id="surf"') && html.includes("renderMap") && html.includes("heat(") && html.includes("drawParallel") && html.includes("drawWaveParticle"), detail: "interactive discovery cinema: 2-D Wave-Particle terrain OR an any-dimension parallel-coordinates view, animated + convergence + strategy" },
|
|
1393
|
+
{ name: "VIZ-ACCURACY", pass: (() => { const nx = 44, ny = 44; const rises = vizProject(20, 20, 1, nx, ny)[1] < vizProject(20, 20, 0, nx, ny)[1]; const exactH = Math.abs((vizProject(20, 20, 0, nx, ny)[1] - vizProject(20, 20, 1, nx, ny)[1]) - 120) < 1e-9; const depthOrder = vizProject(0, ny - 1, 0, nx, ny)[1] < vizProject(0, 0, 0, nx, ny)[1]; let inB = true; for (const c of [[0, 0, 0], [nx - 1, ny - 1, 1], [nx - 1, 0, 1], [0, ny - 1, 1], [22, 22, 0.5]]) {
|
|
1394
|
+
const pr = vizProject(c[0], c[1], c[2], nx, ny);
|
|
1395
|
+
if (pr[0] < 0 || pr[0] > 600 || pr[1] < 0 || pr[1] > 600)
|
|
1396
|
+
inB = false;
|
|
1397
|
+
} const det = JSON.stringify(vizProject(7, 9, 0.6, nx, ny)) === JSON.stringify(vizProject(7, 9, 0.6, nx, ny)); return rises && exactH && depthOrder && inB && det; })(), detail: "the Wave-Particle projection is faithful: higher score rises, back rows sit higher, peaks stay inside the canvas, deterministic" },
|
|
1398
|
+
{ name: "WHO-ITS-FOR+STEPS", pass: html.includes("Who it's for") && html.includes("Pharma") && html.includes("AI / ML teams") && html.includes("How it works") && html.includes("Score one try"), detail: "audiences + the 3-step explainer (journalist-style, 1-minute readable)" },
|
|
1399
|
+
{ name: "MELI-STORYBOOK", pass: html.includes("Meet Meli") && html.includes('class="meli') && html.includes("storybook") && html.includes('data-beat') && html.includes("IntersectionObserver") && html.includes('linearGradient id="mbody"') && html.includes("@keyframes blink"), detail: "original animated mascot (Meli) stars in an interactive scroll-revealed comic storybook with synced effects — geometric art, no third-party/copyright, every browser + mobile" },
|
|
1400
|
+
{ name: "MODES+INDUSTRY", pass: html.includes("Simple — pick") && html.includes("Advanced — edit") && html.includes("setMode") && html.includes("Click an industry") && html.includes("Drug formulation") && html.includes("GPU kernel tuning") && html.includes("tryScenario") && html.includes("Contact about Melete"), detail: "Simple/Advanced modes + clickable industry scenarios (pharma / GPU / semiconductor) that run live, + a licensing/acquisition contact CTA" },
|
|
1401
|
+
{ name: "NO-DATASET", pass: html.includes("No dataset") && html.includes("melete tune"), detail: "explains no dataset is needed + shows the real `melete tune` usage" },
|
|
1402
|
+
{ name: "AIR-GAPPED", pass: html.toLowerCase().includes("air-gapped") && html.includes("runs fully offline"), detail: "states the air-gapped / on-prem positioning" },
|
|
1403
|
+
{ name: "PITCH-DECK", pass: pitch.startsWith("<!doctype html>") && pitch.includes("The ask") && pitch.includes("The moat") && html.includes('href="/pitch"'), detail: "HTML pitch deck renders (problem→product→moat→proof→ask) and is linked from the landing page" },
|
|
1404
|
+
{ name: "VERSION+CATALOG", pass: html.includes("9.9.9") && ENDPOINTS.length === 4 && ENDPOINTS.some((e) => e.path === "/pitch"), detail: "version injected; endpoint catalogue incl /pitch + /discover + /verify" },
|
|
1405
|
+
{ name: "HONEST-COPY", pass: html.toLowerCase().includes("honest") && html.toLowerCase().includes("no single"), detail: "page states the honest framing (robustness, not a magic algorithm)" },
|
|
1406
|
+
];
|
|
1407
|
+
return { score: checks.every((c) => c.pass) ? 100 : 0, checks };
|
|
1408
|
+
}
|
|
1409
|
+
export function docsPage(version) { return "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Melete API</title>\n<style>:root{color-scheme:light}*{box-sizing:border-box}body{font:15.5px/1.7 ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;max-width:860px;margin:0 auto;padding:52px 22px 64px;color:#1a1b30;background:#fbfbfe;font-variant-numeric:tabular-nums}body::before{content:\"\";position:fixed;inset:-20% -10%;z-index:-2;pointer-events:none;background:radial-gradient(34% 34% at 86% 4%,rgba(20,184,166,.16),transparent 62%),radial-gradient(40% 40% at 4% 9%,rgba(109,92,240,.16),transparent 60%),radial-gradient(34% 36% at 94% 84%,rgba(168,85,247,.13),transparent 60%);filter:blur(22px)}body::after{content:\"\";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.5;background-image:radial-gradient(circle at 1px 1px,rgba(80,70,160,.06) 1px,transparent 0);background-size:30px 30px}h1{font-size:42px;margin:14px 0 6px;letter-spacing:-1.5px;font-weight:850;background:linear-gradient(95deg,#6d5cf0,#0ea5b7,#a855f7);-webkit-background-clip:text;background-clip:text;color:transparent;filter:drop-shadow(0 8px 26px rgba(109,92,240,.28))}h2{font-size:13px;text-transform:uppercase;letter-spacing:1px;color:#6d28d9;margin:36px 0 10px;font-weight:800}code{font-family:ui-monospace,Menlo,monospace;background:#f3f1ff;color:#4338ca;padding:1px 6px;border-radius:6px;font-size:13px}pre{background:linear-gradient(160deg,#1c1d33,#15162a);color:#e7e7f5;padding:17px 18px;border-radius:14px;overflow:auto;font-size:12.5px;line-height:1.6;box-shadow:0 22px 50px -30px rgba(20,20,60,.6),inset 0 1px 0 rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.06)}pre code{background:none;color:inherit;padding:0}.f{border-collapse:collapse;width:100%;font-size:14px;margin:8px 0}.f td{border-bottom:1px solid #efedf7;padding:9px 6px;vertical-align:top}.f td:first-child{font-family:ui-monospace,monospace;color:#6d28d9;white-space:nowrap;font-size:13px;font-weight:600}a{color:#5b53e8;font-weight:600;text-decoration:none}a:hover{text-decoration:underline}.muted{color:#8890a8;font-size:13.5px}.card{background:rgba(255,255,255,.78);backdrop-filter:blur(13px) saturate(1.2);-webkit-backdrop-filter:blur(13px) saturate(1.2);border:1px solid #ecebf6;border-radius:18px;padding:20px 20px 9px;margin:14px 0;box-shadow:0 1px 2px rgba(30,25,80,.04),0 22px 50px -34px rgba(70,55,160,.42)}.ret{display:inline-block;background:linear-gradient(135deg,#ecfdf5,#e6fffb);color:#0e7a4f;font-size:11px;font-weight:800;padding:3px 9px;border-radius:7px;text-transform:uppercase;letter-spacing:.3px;border:1px solid #bfeee0}.langsw{position:fixed;top:14px;right:16px;display:flex;background:#fff;border:1px solid #e7e8f0;border-radius:999px;padding:3px;gap:2px;box-shadow:0 4px 14px rgba(20,20,50,.12)}.lb{border:0;background:transparent;border-radius:999px;padding:6px 13px;font-size:13px;font-weight:700;color:#6a6c84;cursor:pointer}.lb.on{background:linear-gradient(96deg,#6d5cf0,#0ea5b7);color:#fff}</style>\n</head><body>\n<div class=\"langsw\"><button class=\"lb\" id=\"lbEN\" onclick=\"setLang('en')\">EN</button><button class=\"lb\" id=\"lbTH\" onclick=\"setLang('th')\">ไทย</button></div>\n<a href=\"/\">← Melete</a>\n<h1>Melete API</h1>\n<p class=\"muted\" data-i18n=\"d_sub\">Connect your real process. Base URL <code>https://melete.mneme-ai.space</code> · all JSON · no auth on the demo.</p>\n<p data-i18n=\"d_loop\"><b>The loop:</b> POST your results so far → get the next experiment to try → run it in your system → measure a score → POST again with the new result → repeat until it converges. <b>You</b> run the experiment; <b>Melete</b> decides what to try next.</p>\n<h2 data-i18n=\"d_ex_h\">Copy-paste examples</h2>\n<div class=\"card\"><p class=\"muted\" data-i18n=\"d_ex_p\">The whole loop in real code — replace <code>run_my_experiment</code> with your actual lab/benchmark/process.</p>\n<p style=\"font-size:12px;color:#8890a8;margin:6px 0 2px\">Python</p>\n<pre><code>import requests\nbase = \"https://melete.mneme-ai.space\"\nspace = [{\"name\":\"pH\",\"type\":\"real\",\"min\":3,\"max\":9}]\nobs = []\nfor _ in range(20):\n r = requests.post(base+\"/next\", json={\"space\":space,\"observations\":obs,\"goal\":\"maximize\"}).json()\n x = r[\"next\"] # the setting Melete wants you to try\n score = run_my_experiment(x) # ← YOU measure it for real\n obs.append({\"experiment\": x, \"value\": score})\n if r[\"advice\"][\"recommendation\"] == \"STOP\": break\nprint(\"best:\", max(obs, key=lambda o: o[\"value\"]))</code></pre>\n<p style=\"font-size:12px;color:#8890a8;margin:10px 0 2px\">JavaScript / Node</p>\n<pre><code>const base = \"https://melete.mneme-ai.space\";\nconst space = [{name:\"pH\", type:\"real\", min:3, max:9}];\nlet obs = [];\nfor (let i = 0; i < 20; i++) {\n const r = await fetch(base+\"/next\", {method:\"POST\",\n headers:{\"content-type\":\"application/json\"},\n body: JSON.stringify({space, observations:obs, goal:\"maximize\"})}).then(r => r.json());\n const score = await runMyExperiment(r.next); // ← YOU measure it\n obs.push({experiment: r.next, value: score});\n if (r.advice.recommendation === \"STOP\") break;\n}</code></pre></div>\n<h2 data-i18n=\"d_next_h\">POST /next — the guided loop</h2>\n<div class=\"card\"><table class=\"f\">\n<tr><td>space</td><td data-i18n=\"d_f_space\">what you can change: <code>[{name, type:\"real\"|\"int\", min, max}]</code></td></tr>\n<tr><td>observations</td><td data-i18n=\"d_f_obs\">everything measured so far: <code>[{experiment:{name:value}, value:number}]</code> — empty <code>[]</code> on the first call</td></tr>\n<tr><td>goal</td><td data-i18n=\"d_f_goal\"><code>\"maximize\"</code> or <code>\"minimize\"</code></td></tr>\n<tr><td>costPerExperiment</td><td data-i18n=\"d_f_cost\"><i>optional</i> — cost per experiment; enables the money stop-advice</td></tr>\n</table><p><span class=\"ret\">returns</span> <code>{ next, best, advice:{recommendation:\"CONTINUE\"|\"STOP\"} }</code></p></div>\n<h2 data-i18n=\"d_multi_h\">POST /next-multi — multi-objective (Pareto)</h2>\n<div class=\"card\"><p data-i18n=\"d_multi_p\">Like <code>/next</code>, but <code>goals</code> has one entry per objective and each observation carries <code>values[]</code>:</p>\n<pre><code>{\"space\":[...], \"goals\":[{\"name\":\"yield\",\"goal\":\"maximize\"},{\"name\":\"cost\",\"goal\":\"minimize\"}],\n \"observations\":[{\"experiment\":{...}, \"values\":[90, 40]}]}</code></pre>\n<p><span class=\"ret\">returns</span> <code>{ next, paretoFront:[ ...best trade-offs... ], paretoSize }</code></p></div>\n<h2 data-i18n=\"d_disc_h\">POST /discover — one-shot (you supply a formula)</h2>\n<div class=\"card\"><p data-i18n=\"d_disc_p\">For automatable objectives: pass an <code>objective</code> expression in your variable names — Melete runs the whole loop and returns the best + a signed trace + a Proof of Optimization + a sensitivity report.</p>\n<pre><code>{\"space\":[{\"name\":\"x\",\"type\":\"real\",\"min\":-5,\"max\":5}], \"objective\":\"-(x-2)**2\", \"budget\":40, \"goal\":\"maximize\"}</code></pre>\n<p><span class=\"ret\">returns</span> <code>{ best, evaluations, frontier, certificate, poopt, sensitivity, trace, verify }</code></p></div>\n<h2 data-i18n=\"d_poopt_h\">POST /poopt/verify — verify a certificate offline</h2>\n<div class=\"card\"><p data-i18n=\"d_poopt_p\">POST a downloaded <code>proof-of-optimization.json</code> → <code>{ ok, reason, efficiencyPct }</code>. Zero-server option: <code>npm i -g melete-ai</code> then <code>melete poopt cert.json</code>.</p></div>\n<h2 data-i18n=\"d_self_h\">Self-hosted & air-gapped</h2>\n<div class=\"card\"><p data-i18n=\"d_self_p\"><code>npm i -g melete-ai</code> · run <code>melete-server</code> on your own machine — data never leaves. Or call the library directly:</p><pre><code>import { proposeNext, proposeNextMulti } from \"melete-ai\"</code></pre></div>\n<p class=\"muted\" data-i18n=\"d_footer\" style=\"margin-top:24px\">Melete v__VER__ · MIT · <a href=\"/\">home</a></p>\n<script>\nvar T={en:{\n d_sub:'Connect your real process. Base URL <code>https://melete.mneme-ai.space</code> · all JSON · no auth on the demo.',\n d_loop:'<b>The loop:</b> POST your results so far → get the next experiment to try → run it in your system → measure a score → POST again with the new result → repeat until it converges. <b>You</b> run the experiment; <b>Melete</b> decides what to try next.',\n d_ex_h:'Copy-paste examples',\n d_ex_p:'The whole loop in real code — replace <code>run_my_experiment</code> with your actual lab/benchmark/process.',\n d_next_h:'POST /next — the guided loop',\n d_f_space:'what you can change: <code>[{name, type:\"real\"|\"int\", min, max}]</code>',\n d_f_obs:'everything measured so far: <code>[{experiment:{name:value}, value:number}]</code> — empty <code>[]</code> on the first call',\n d_f_goal:'<code>\"maximize\"</code> or <code>\"minimize\"</code>',\n d_f_cost:'<i>optional</i> — cost per experiment; enables the money stop-advice',\n d_multi_h:'POST /next-multi — multi-objective (Pareto)',\n d_multi_p:'Like <code>/next</code>, but <code>goals</code> has one entry per objective and each observation carries <code>values[]</code>:',\n d_disc_h:'POST /discover — one-shot (you supply a formula)',\n d_disc_p:'For automatable objectives: pass an <code>objective</code> expression in your variable names — Melete runs the whole loop and returns the best + a signed trace + a Proof of Optimization + a sensitivity report.',\n d_poopt_h:'POST /poopt/verify — verify a certificate offline',\n d_poopt_p:'POST a downloaded <code>proof-of-optimization.json</code> → <code>{ ok, reason, efficiencyPct }</code>. Zero-server option: <code>npm i -g melete-ai</code> then <code>melete poopt cert.json</code>.',\n d_self_h:'Self-hosted & air-gapped',\n d_self_p:'<code>npm i -g melete-ai</code> · run <code>melete-server</code> on your own machine — data never leaves. Or call the library directly:',\n d_footer:'Melete v__VER__ · MIT · <a href=\"/\">home</a>'\n},th:{\n d_sub:'เชื่อมต่อกระบวนการจริงของคุณ Base URL <code>https://melete.mneme-ai.space</code> · เป็น JSON ทั้งหมด · เดโมไม่ต้องมี auth',\n d_loop:'<b>ลูปการทำงาน:</b> POST ผลที่วัดมาแล้ว → ได้การทดลองถัดไปที่ควรลอง → ไปรันในระบบของคุณ → วัดคะแนน → POST ใหม่พร้อมผลล่าสุด → วนจนลู่เข้า <b>คุณ</b>เป็นคนรันการทดลอง <b>Melete</b> เป็นคนเลือกว่าลองอะไรต่อ',\n d_ex_h:'ตัวอย่างโค้ด ก็อปวางได้เลย',\n d_ex_p:'ลูปทั้งหมดในโค้ดจริง — แทน <code>run_my_experiment</code> ด้วยแล็บ/เบนช์มาร์ก/กระบวนการจริงของคุณ',\n d_next_h:'POST /next — ลูปแนะนำ (guided)',\n d_f_space:'สิ่งที่คุณปรับได้: <code>[{name, type:\"real\"|\"int\", min, max}]</code>',\n d_f_obs:'ทุกอย่างที่วัดมาแล้ว: <code>[{experiment:{name:value}, value:number}]</code> — ครั้งแรกส่ง <code>[]</code> ว่างได้',\n d_f_goal:'<code>\"maximize\"</code> (มากสุด) หรือ <code>\"minimize\"</code> (น้อยสุด)',\n d_f_cost:'<i>ไม่บังคับ</i> — ต้นทุนต่อการทดลอง; เปิดคำแนะนำเรื่องเงิน/เมื่อไหร่ควรหยุด',\n d_multi_h:'POST /next-multi — หลายเป้าหมาย (Pareto)',\n d_multi_p:'เหมือน <code>/next</code> แต่ <code>goals</code> มีหนึ่งรายการต่อหนึ่งเป้าหมาย และแต่ละ observation มี <code>values[]</code>:',\n d_disc_h:'POST /discover — ทำครั้งเดียวจบ (คุณใส่สูตร objective)',\n d_disc_p:'สำหรับงานที่รันอัตโนมัติได้: ส่งนิพจน์ <code>objective</code> ในชื่อตัวแปรของคุณ — Melete รันทั้งลูปแล้วคืนค่าที่ดีที่สุด + ใบบันทึกที่เซ็น + Proof of Optimization + รายงาน sensitivity',\n d_poopt_h:'POST /poopt/verify — ตรวจใบรับรองแบบ offline',\n d_poopt_p:'POST ไฟล์ <code>proof-of-optimization.json</code> ที่ดาวน์โหลดไว้ → <code>{ ok, reason, efficiencyPct }</code> หรือตรวจโดยไม่ต้องมีเซิร์ฟเวอร์: <code>npm i -g melete-ai</code> แล้ว <code>melete poopt cert.json</code>',\n d_self_h:'รันเอง & air-gapped',\n d_self_p:'<code>npm i -g melete-ai</code> · รัน <code>melete-server</code> บนเครื่องของคุณเอง — ข้อมูลไม่ออกไปไหน หรือเรียก library ตรงๆ:',\n d_footer:'Melete v__VER__ · MIT · <a href=\"/\">หน้าแรก</a>'\n}};\nfunction setLang(l){if(l!=='th')l='en';try{localStorage.setItem('mlang',l)}catch(e){}var en=document.getElementById('lbEN'),th=document.getElementById('lbTH');if(en)en.className='lb'+(l==='en'?' on':'');if(th)th.className='lb'+(l==='th'?' on':'');document.documentElement.lang=l;var n=document.querySelectorAll('[data-i18n]');for(var i=0;i<n.length;i++){var k=n[i].getAttribute('data-i18n');if(T[l]&&T[l][k]!=null)n[i].innerHTML=T[l][k];}}\nvar _l='en';try{_l=localStorage.getItem('mlang')||'en'}catch(e){}setLang(_l);\n</script>\n</body></html>".split("__VER__").join(String(version)); }
|
|
1410
|
+
//# sourceMappingURL=server.js.map
|