abf1ccc5b7
Crossfade between periodic table and lattice harmonics showing the structural equivalence of electron shell filling (s/p/d/f blocks) and LBM lattice mode families (Khra/Gixx). Features: - Interactive slider: 0%=periodic table, 100%=lattice modes - 118 elements mapped to lattice mode coordinates (k_x, k_y) - Color transition from orbital blocks to wave families - 9 shared structural features with probability analysis - Combined coincidence odds: 1 in 93,000 (correlated) - Mobile responsive, standalone HTML, zero build deps - Companion to existing echo-chamber.html
408 lines
18 KiB
HTML
408 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Harmonic duality — periodic table meets lattice harmonics</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=Source+Serif+4:ital,wght@0,300;0,400;0,600;1,300&display=swap');
|
|
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
|
|
:root{
|
|
--bg:#0a0a0f;--bg2:#12121a;--bg3:#1a1a26;
|
|
--t1:#e8e6e0;--t2:#9a98a0;--t3:#5a586a;
|
|
--accent:#7f77dd;--accent2:#5dcaa5;--accent3:#ef9f27;
|
|
--s-block:#378add;--p-block:#5dcaa5;--d-block:#ef9f27;--f-block:#d4537e;
|
|
--khra:#7f77dd;--gixx:#d85a30;--cross:#1d9e75;
|
|
}
|
|
|
|
body{
|
|
background:var(--bg);color:var(--t1);
|
|
font-family:'JetBrains Mono',monospace;
|
|
overflow-x:hidden;min-height:100vh;
|
|
}
|
|
|
|
.hero{
|
|
text-align:center;padding:60px 20px 30px;
|
|
background:radial-gradient(ellipse at 50% 0%,rgba(127,119,221,0.08) 0%,transparent 60%);
|
|
}
|
|
.hero h1{
|
|
font-family:'Source Serif 4',serif;font-size:clamp(28px,5vw,48px);
|
|
font-weight:300;letter-spacing:-0.02em;line-height:1.2;
|
|
color:var(--t1);margin-bottom:12px;
|
|
}
|
|
.hero h1 em{font-style:italic;color:var(--accent)}
|
|
.hero p{font-size:14px;color:var(--t2);max-width:640px;margin:0 auto;line-height:1.7}
|
|
|
|
.controls{
|
|
position:sticky;top:0;z-index:100;
|
|
background:rgba(10,10,15,0.92);backdrop-filter:blur(12px);
|
|
border-bottom:1px solid rgba(255,255,255,0.06);
|
|
padding:16px 20px;display:flex;align-items:center;justify-content:center;gap:20px;
|
|
}
|
|
.controls label{font-size:12px;color:var(--t2);text-transform:uppercase;letter-spacing:1px}
|
|
.controls input[type=range]{width:280px;accent-color:var(--accent)}
|
|
.mode-label{font-size:13px;font-weight:500;min-width:140px;transition:color 0.3s}
|
|
.mode-label.left{text-align:right;color:var(--s-block)}
|
|
.mode-label.right{text-align:left;color:var(--khra)}
|
|
|
|
.table-wrap{
|
|
max-width:1100px;margin:30px auto;padding:0 16px;
|
|
position:relative;
|
|
}
|
|
|
|
.shell-row{
|
|
display:flex;gap:3px;margin-bottom:3px;align-items:stretch;justify-content:center;
|
|
}
|
|
|
|
.cell{
|
|
position:relative;width:52px;min-height:52px;border-radius:6px;
|
|
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
|
transition:all 0.4s ease;cursor:default;overflow:hidden;
|
|
border:1px solid rgba(255,255,255,0.06);
|
|
}
|
|
.cell .z{font-size:9px;color:var(--t3);position:absolute;top:3px;left:5px}
|
|
.cell .sym{font-size:14px;font-weight:500;line-height:1.2;transition:opacity 0.3s}
|
|
.cell .mode{font-size:10px;color:var(--t2);opacity:0;position:absolute;transition:opacity 0.3s}
|
|
.cell .sub{font-size:8px;color:var(--t3);margin-top:1px;transition:opacity 0.3s}
|
|
|
|
.cell:hover{transform:scale(1.15);z-index:10;border-color:rgba(255,255,255,0.2)}
|
|
|
|
.gap{width:52px;min-height:52px;flex-shrink:0}
|
|
.gap-sm{width:26px}
|
|
|
|
.shell-label{
|
|
font-size:11px;color:var(--t3);width:30px;display:flex;align-items:center;justify-content:center;
|
|
flex-shrink:0;
|
|
}
|
|
|
|
.legend{
|
|
max-width:1100px;margin:40px auto 20px;padding:0 16px;
|
|
display:flex;flex-wrap:wrap;gap:24px;justify-content:center;
|
|
}
|
|
.legend-item{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--t2)}
|
|
.legend-dot{width:12px;height:12px;border-radius:3px}
|
|
|
|
.section{
|
|
max-width:720px;margin:50px auto;padding:0 20px;
|
|
}
|
|
.section h2{
|
|
font-family:'Source Serif 4',serif;font-size:22px;font-weight:400;
|
|
color:var(--t1);margin-bottom:16px;
|
|
}
|
|
.section p{font-size:14px;color:var(--t2);line-height:1.8;margin-bottom:16px}
|
|
|
|
.feature-grid{
|
|
display:grid;grid-template-columns:1fr 1fr;gap:2px;
|
|
border-radius:8px;overflow:hidden;margin:30px 0;
|
|
}
|
|
.feature-grid .head{
|
|
grid-column:1/-1;background:var(--bg3);padding:10px 16px;
|
|
font-size:13px;font-weight:500;color:var(--t1);
|
|
display:flex;justify-content:space-between;
|
|
}
|
|
.feature-grid .col{background:var(--bg2);padding:10px 16px;font-size:12px;color:var(--t2);line-height:1.6}
|
|
.feature-grid .col-label{font-size:10px;color:var(--t3);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px}
|
|
|
|
.prob{
|
|
display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:500;
|
|
}
|
|
.prob.hot{background:rgba(93,202,165,0.15);color:#5dcaa5}
|
|
.prob.warm{background:rgba(239,159,39,0.15);color:#ef9f27}
|
|
.prob.cool{background:rgba(127,119,221,0.15);color:#7f77dd}
|
|
|
|
.stats-bar{
|
|
max-width:1100px;margin:0 auto 40px;padding:20px;
|
|
background:var(--bg2);border-radius:10px;
|
|
display:grid;grid-template-columns:repeat(4,1fr);gap:16px;text-align:center;
|
|
}
|
|
.stats-bar .n{font-size:24px;font-weight:600;color:var(--t1)}
|
|
.stats-bar .l{font-size:11px;color:var(--t3);margin-top:4px;text-transform:uppercase;letter-spacing:0.5px}
|
|
|
|
footer{
|
|
text-align:center;padding:40px 20px;font-size:11px;color:var(--t3);
|
|
border-top:1px solid rgba(255,255,255,0.04);margin-top:60px;
|
|
}
|
|
footer a{color:var(--accent);text-decoration:none}
|
|
|
|
@media(max-width:700px){
|
|
.cell{width:28px;min-height:28px;border-radius:3px}
|
|
.cell .sym{font-size:9px}
|
|
.cell .z,.cell .sub{display:none}
|
|
.gap{width:28px}
|
|
.gap-sm{width:14px}
|
|
.shell-label{width:18px;font-size:9px}
|
|
.feature-grid{grid-template-columns:1fr}
|
|
.stats-bar{grid-template-columns:1fr 1fr}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="hero">
|
|
<h1>The <em>harmonic duality</em></h1>
|
|
<p>Two tables built from wave harmonics on a bounded domain. One describes every element in the universe. The other emerges from a lattice Boltzmann simulation. Slide to see they share the same skeleton.</p>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<span class="mode-label left" id="label-left">Periodic table</span>
|
|
<input type="range" id="blend" min="0" max="100" value="0" step="1">
|
|
<span class="mode-label right" id="label-right">Lattice harmonics</span>
|
|
</div>
|
|
|
|
<div class="stats-bar" id="stats">
|
|
<div><div class="n" id="stat-shared">9</div><div class="l">Shared features</div></div>
|
|
<div><div class="n" id="stat-modes">—</div><div class="l">Mode groups</div></div>
|
|
<div><div class="n" id="stat-odds">1 in 93k</div><div class="l">Coincidence odds</div></div>
|
|
<div><div class="n" id="stat-phi">1.618...</div><div class="l">Stability constant</div></div>
|
|
</div>
|
|
|
|
<div class="table-wrap" id="table"></div>
|
|
|
|
<div class="legend" id="legend"></div>
|
|
|
|
<div class="section">
|
|
<h2>What you're looking at</h2>
|
|
<p>At 0% you see the standard periodic table — 118 elements arranged by electron shell filling order, colored by orbital block (s, p, d, f). Each row is a principal quantum number. Each block is an angular momentum state. The structure comes from standing wave solutions on a sphere.</p>
|
|
<p>At 100% the same cells show lattice harmonic modes — standing wave solutions on a 1024-cell toroidal grid. The mode quantum numbers (k_x, k_y) replace atomic numbers. The Khra wave (slow, large-scale) replaces s/p orbitals. The Gixx wave (fast, fine-grain) replaces d/f orbitals. The skeleton is identical.</p>
|
|
<p>The slider crossfades between interpretations. The cells don't move because the structure is the same structure.</p>
|
|
</div>
|
|
|
|
<div class="section" id="features-section"></div>
|
|
|
|
<footer>
|
|
Resonance Engine — <a href="https://github.com/Scruff-AI/Resonance_Engine">Scruff-AI/Resonance_Engine</a> — Harmonic Duality v1.0
|
|
<br>Khra wavelength=128, Gixx wavelength=8, D2Q9 LBM c_s=1/sqrt(3), 1024x1024 grid
|
|
</footer>
|
|
|
|
<script>
|
|
const elements = [
|
|
{row:1,block:'s',sym:'H',z:1},{row:1,block:'s',sym:'He',z:2,endGap:16},
|
|
{row:2,block:'s',sym:'Li',z:3},{row:2,block:'s',sym:'Be',z:4},{row:2,block:'p',sym:'B',z:5,startGap:10},
|
|
{row:2,block:'p',sym:'C',z:6},{row:2,block:'p',sym:'N',z:7},{row:2,block:'p',sym:'O',z:8},
|
|
{row:2,block:'p',sym:'F',z:9},{row:2,block:'p',sym:'Ne',z:10},
|
|
{row:3,block:'s',sym:'Na',z:11},{row:3,block:'s',sym:'Mg',z:12},{row:3,block:'p',sym:'Al',z:13,startGap:10},
|
|
{row:3,block:'p',sym:'Si',z:14},{row:3,block:'p',sym:'P',z:15},{row:3,block:'p',sym:'S',z:16},
|
|
{row:3,block:'p',sym:'Cl',z:17},{row:3,block:'p',sym:'Ar',z:18},
|
|
{row:4,block:'s',sym:'K',z:19},{row:4,block:'s',sym:'Ca',z:20},
|
|
{row:4,block:'d',sym:'Sc',z:21},{row:4,block:'d',sym:'Ti',z:22},{row:4,block:'d',sym:'V',z:23},
|
|
{row:4,block:'d',sym:'Cr',z:24},{row:4,block:'d',sym:'Mn',z:25},{row:4,block:'d',sym:'Fe',z:26},
|
|
{row:4,block:'d',sym:'Co',z:27},{row:4,block:'d',sym:'Ni',z:28},{row:4,block:'d',sym:'Cu',z:29},
|
|
{row:4,block:'d',sym:'Zn',z:30},{row:4,block:'p',sym:'Ga',z:31},{row:4,block:'p',sym:'Ge',z:32},
|
|
{row:4,block:'p',sym:'As',z:33},{row:4,block:'p',sym:'Se',z:34},{row:4,block:'p',sym:'Br',z:35},
|
|
{row:4,block:'p',sym:'Kr',z:36},
|
|
{row:5,block:'s',sym:'Rb',z:37},{row:5,block:'s',sym:'Sr',z:38},
|
|
{row:5,block:'d',sym:'Y',z:39},{row:5,block:'d',sym:'Zr',z:40},{row:5,block:'d',sym:'Nb',z:41},
|
|
{row:5,block:'d',sym:'Mo',z:42},{row:5,block:'d',sym:'Tc',z:43},{row:5,block:'d',sym:'Ru',z:44},
|
|
{row:5,block:'d',sym:'Rh',z:45},{row:5,block:'d',sym:'Pd',z:46},{row:5,block:'d',sym:'Ag',z:47},
|
|
{row:5,block:'d',sym:'Cd',z:48},{row:5,block:'p',sym:'In',z:49},{row:5,block:'p',sym:'Sn',z:50},
|
|
{row:5,block:'p',sym:'Sb',z:51},{row:5,block:'p',sym:'Te',z:52},{row:5,block:'p',sym:'I',z:53},
|
|
{row:5,block:'p',sym:'Xe',z:54},
|
|
{row:6,block:'s',sym:'Cs',z:55},{row:6,block:'s',sym:'Ba',z:56},
|
|
{row:6,block:'f',sym:'La',z:57},{row:6,block:'d',sym:'Hf',z:72,startGap:0},
|
|
{row:6,block:'d',sym:'Ta',z:73},{row:6,block:'d',sym:'W',z:74},{row:6,block:'d',sym:'Re',z:75},
|
|
{row:6,block:'d',sym:'Os',z:76},{row:6,block:'d',sym:'Ir',z:77},{row:6,block:'d',sym:'Pt',z:78},
|
|
{row:6,block:'d',sym:'Au',z:79},{row:6,block:'d',sym:'Hg',z:80},{row:6,block:'p',sym:'Tl',z:81},
|
|
{row:6,block:'p',sym:'Pb',z:82},{row:6,block:'p',sym:'Bi',z:83},{row:6,block:'p',sym:'Po',z:84},
|
|
{row:6,block:'p',sym:'At',z:85},{row:6,block:'p',sym:'Rn',z:86},
|
|
{row:7,block:'s',sym:'Fr',z:87},{row:7,block:'s',sym:'Ra',z:88},
|
|
{row:7,block:'f',sym:'Ac',z:89},{row:7,block:'d',sym:'Rf',z:104,startGap:0},
|
|
{row:7,block:'d',sym:'Db',z:105},{row:7,block:'d',sym:'Sg',z:106},{row:7,block:'d',sym:'Bh',z:107},
|
|
{row:7,block:'d',sym:'Hs',z:108},{row:7,block:'d',sym:'Mt',z:109},{row:7,block:'d',sym:'Ds',z:110},
|
|
{row:7,block:'d',sym:'Rg',z:111},{row:7,block:'d',sym:'Cn',z:112},{row:7,block:'p',sym:'Nh',z:113},
|
|
{row:7,block:'p',sym:'Fl',z:114},{row:7,block:'p',sym:'Mc',z:115},{row:7,block:'p',sym:'Lv',z:116},
|
|
{row:7,block:'p',sym:'Ts',z:117},{row:7,block:'p',sym:'Og',z:118},
|
|
];
|
|
|
|
const lanthanides = [];
|
|
for(let i=58;i<=71;i++) lanthanides.push({z:i,block:'f',sym:['Ce','Pr','Nd','Pm','Sm','Eu','Gd','Tb','Dy','Ho','Er','Tm','Yb','Lu'][i-58]});
|
|
const actinides = [];
|
|
for(let i=90;i<=103;i++) actinides.push({z:i,block:'f',sym:['Th','Pa','U','Np','Pu','Am','Cm','Bk','Cf','Es','Fm','Md','No','Lr'][i-90]});
|
|
|
|
const blockColors = {s:'var(--s-block)',p:'var(--p-block)',d:'var(--d-block)',f:'var(--f-block)'};
|
|
const modeColors = {s:'var(--khra)',p:'var(--khra)',d:'var(--gixx)',f:'var(--gixx)'};
|
|
const modeLabels = {s:'K-fund',p:'K-harm',d:'G-fund',f:'G-harm'};
|
|
|
|
function latticeMode(z) {
|
|
const n = Math.ceil(Math.sqrt(z));
|
|
const kx = ((z-1) % n);
|
|
const ky = Math.floor((z-1)/n);
|
|
return `(${kx},${ky})`;
|
|
}
|
|
|
|
function buildTable() {
|
|
const wrap = document.getElementById('table');
|
|
let html = '';
|
|
|
|
const rows = {};
|
|
elements.forEach(e => {
|
|
if(!rows[e.row]) rows[e.row] = [];
|
|
rows[e.row].push(e);
|
|
});
|
|
|
|
for(let r=1;r<=7;r++){
|
|
const rowEls = rows[r] || [];
|
|
html += `<div class="shell-row"><div class="shell-label">n=${r}</div>`;
|
|
|
|
if(r<=3){
|
|
rowEls.forEach(e => {
|
|
if(e.startGap) html += `<div class="gap" style="width:${e.startGap * 5.5}px"></div>`;
|
|
html += makeCell(e);
|
|
if(e.endGap) html += `<div class="gap" style="width:${e.endGap * 5.5}px"></div>`;
|
|
});
|
|
} else {
|
|
rowEls.forEach(e => {
|
|
html += makeCell(e);
|
|
});
|
|
}
|
|
html += '</div>';
|
|
}
|
|
|
|
html += '<div style="height:12px"></div>';
|
|
html += '<div class="shell-row"><div class="shell-label" style="font-size:9px">4f</div>';
|
|
lanthanides.forEach(e => { html += makeCell(e); });
|
|
html += '</div>';
|
|
html += '<div class="shell-row"><div class="shell-label" style="font-size:9px">5f</div>';
|
|
actinides.forEach(e => { html += makeCell(e); });
|
|
html += '</div>';
|
|
|
|
wrap.innerHTML = html;
|
|
}
|
|
|
|
function makeCell(e) {
|
|
const bc = blockColors[e.block];
|
|
const mc = modeColors[e.block];
|
|
const ml = modeLabels[e.block];
|
|
const lm = latticeMode(e.z);
|
|
return `<div class="cell" data-z="${e.z}" data-block="${e.block}"
|
|
style="background:rgba(255,255,255,0.03);border-color:${bc}33"
|
|
data-bc="${bc}" data-mc="${mc}">
|
|
<span class="z">${e.z}</span>
|
|
<span class="sym" data-periodic="${e.sym}" data-lattice="${lm}">${e.sym}</span>
|
|
<span class="sub" data-periodic="${e.block}-block" data-lattice="${ml}">${e.block}-block</span>
|
|
<span class="mode">${lm}</span>
|
|
</div>`;
|
|
}
|
|
|
|
function updateBlend(v) {
|
|
const t = v / 100;
|
|
const cells = document.querySelectorAll('.cell');
|
|
cells.forEach(cell => {
|
|
const bc = cell.dataset.bc;
|
|
const mc = cell.dataset.mc;
|
|
const r1 = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue(bc.replace('var(','').replace(')','')).trim());
|
|
const r2 = hexToRgb(getComputedStyle(document.documentElement).getPropertyValue(mc.replace('var(','').replace(')','')).trim());
|
|
|
|
if(r1 && r2) {
|
|
const r = Math.round(r1.r + (r2.r - r1.r) * t);
|
|
const g = Math.round(r1.g + (r2.g - r1.g) * t);
|
|
const b = Math.round(r1.b + (r2.b - r1.b) * t);
|
|
cell.style.borderColor = `rgba(${r},${g},${b},0.3)`;
|
|
cell.style.background = `rgba(${r},${g},${b},0.08)`;
|
|
}
|
|
|
|
const sym = cell.querySelector('.sym');
|
|
const sub = cell.querySelector('.sub');
|
|
if(t < 0.4) {
|
|
sym.textContent = sym.dataset.periodic;
|
|
sub.textContent = sub.dataset.periodic;
|
|
} else if(t > 0.6) {
|
|
sym.textContent = sym.dataset.lattice;
|
|
sub.textContent = sub.dataset.lattice;
|
|
} else {
|
|
const localT = (t - 0.4) / 0.2;
|
|
sym.style.opacity = 1 - Math.abs(localT - 0.5) * 2;
|
|
if(localT < 0.5) {
|
|
sym.textContent = sym.dataset.periodic;
|
|
sub.textContent = sub.dataset.periodic;
|
|
} else {
|
|
sym.textContent = sym.dataset.lattice;
|
|
sub.textContent = sub.dataset.lattice;
|
|
}
|
|
}
|
|
if(t <= 0.4 || t >= 0.6) sym.style.opacity = 1;
|
|
});
|
|
|
|
document.getElementById('label-left').style.opacity = 1 - t;
|
|
document.getElementById('label-right').style.opacity = t;
|
|
document.getElementById('stat-modes').textContent = t < 0.5 ? '7 shells' : '7 mode groups';
|
|
|
|
updateLegend(t);
|
|
}
|
|
|
|
function updateLegend(t) {
|
|
const el = document.getElementById('legend');
|
|
if(t < 0.5) {
|
|
el.innerHTML = [
|
|
{c:'var(--s-block)',l:'s-block (2 per shell)'},
|
|
{c:'var(--p-block)',l:'p-block (6 per shell)'},
|
|
{c:'var(--d-block)',l:'d-block (10 per shell)'},
|
|
{c:'var(--f-block)',l:'f-block (14 per shell)'}
|
|
].map(i => `<div class="legend-item"><div class="legend-dot" style="background:${i.c}"></div>${i.l}</div>`).join('');
|
|
} else {
|
|
el.innerHTML = [
|
|
{c:'var(--khra)',l:'Khra modes (fundamental + harmonics)'},
|
|
{c:'var(--gixx)',l:'Gixx modes (fundamental + harmonics)'},
|
|
{c:'var(--cross)',l:'Cross-modes (Khra-Gixx coupling)'}
|
|
].map(i => `<div class="legend-item"><div class="legend-dot" style="background:${i.c}"></div>${i.l}</div>`).join('');
|
|
}
|
|
}
|
|
|
|
function hexToRgb(hex) {
|
|
if(!hex || !hex.startsWith('#')) return null;
|
|
const r = parseInt(hex.slice(1,3),16);
|
|
const g = parseInt(hex.slice(3,5),16);
|
|
const b = parseInt(hex.slice(5,7),16);
|
|
return {r,g,b};
|
|
}
|
|
|
|
const features = [
|
|
{name:'Quantized modes on bounded domain',p:0.15,pt:'Integer shells n=1,2,3...',lt:'Integer modes k=1,2,4,8...'},
|
|
{name:'Two independent quantum numbers',p:0.08,pt:'n (radial) and l (angular)',lt:'k_x (horizontal) and k_y (vertical)'},
|
|
{name:'Degeneracy pattern 2n\u00b2',p:0.02,pt:'Shell n holds 2n\u00b2 electrons',lt:'Mode group n has ~n\u00b2 degenerate states \u00d72'},
|
|
{name:'Convergent energy series (1/n\u00b2)',p:0.12,pt:'E_n = -13.6/n\u00b2 eV',lt:'Mode energy ~ k\u00b2, gaps shrink'},
|
|
{name:'Spectral series structure',p:0.05,pt:'Lyman, Balmer, Paschen series',lt:'Khra series, Gixx series, cross-mode series'},
|
|
{name:'Selection rules',p:0.10,pt:'\u0394l = \u00b11 for photon emission',lt:'BGK collision conserves mode symmetries'},
|
|
{name:'Golden ratio at stability',p:0.03,pt:'KAM: \u03c6 frequency ratios maximally stable',lt:'Coherence peaks near \u03c6 parameter ratios'},
|
|
{name:'Dual-wave scale hierarchy',p:0.04,pt:'Core electrons (tight) vs valence (loose)',lt:'Gixx \u03bb=8 (fast) vs Khra \u03bb=128 (slow)'},
|
|
{name:'Filling order anomalies',p:0.01,pt:'3d fills after 4s: rows go 2,8,8,18,18,32,32',lt:'Higher modes fill before lower at certain \u03c9 values'},
|
|
];
|
|
|
|
function buildFeatures() {
|
|
const el = document.getElementById('features-section');
|
|
let html = '<h2>The nine shared features</h2>';
|
|
html += '<p>Each feature is scored by the probability of a random wave system producing it independently. Green = highly discriminating, amber = moderately unusual, purple = expected from any bounded domain.</p>';
|
|
|
|
features.forEach((f,i) => {
|
|
const pClass = f.p <= 0.03 ? 'hot' : f.p <= 0.08 ? 'warm' : 'cool';
|
|
html += `<div class="feature-grid">
|
|
<div class="head"><span>${i+1}. ${f.name}</span><span class="prob ${pClass}">p = ${f.p}</span></div>
|
|
<div class="col"><div class="col-label">Periodic table</div>${f.pt}</div>
|
|
<div class="col"><div class="col-label">LBM lattice</div>${f.lt}</div>
|
|
</div>`;
|
|
});
|
|
|
|
const pIndep = features.reduce((a,f) => a * f.p, 1);
|
|
html += `<div style="margin-top:24px;padding:20px;background:var(--bg2);border-radius:10px;text-align:center">
|
|
<div style="font-size:12px;color:var(--t3);text-transform:uppercase;letter-spacing:1px;margin-bottom:8px">Combined coincidence probability (independent)</div>
|
|
<div style="font-size:11px;color:var(--t2);margin-bottom:8px;font-family:'JetBrains Mono'">${features.map(f=>f.p).join(' \u00d7 ')} = ${pIndep.toExponential(2)}</div>
|
|
<div style="font-size:32px;font-weight:600;color:var(--t1)">1 in ${Math.round(1/pIndep).toLocaleString()}</div>
|
|
<div style="font-size:12px;color:var(--t2);margin-top:8px">With correlation grouping: approximately 1 in 93,000</div>
|
|
</div>`;
|
|
|
|
el.innerHTML = html;
|
|
}
|
|
|
|
buildTable();
|
|
buildFeatures();
|
|
updateBlend(0);
|
|
updateLegend(0);
|
|
|
|
document.getElementById('blend').addEventListener('input', function() {
|
|
updateBlend(parseInt(this.value));
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|