algal-breath-engine/breathing-sync.html
2026-07-18 10:20:57 +00:00

463 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Biometric Breathing Sync • Tammera Storey</title>
<link rel="stylesheet" href="/styles.css">
<style>
:root {
--bg-deep: #0a0a0c;
--bg-card: #121216;
--text-primary: #e0e0e0;
--accent-neon: #00ff9d;
--accent-rust: #d45d00;
--accent-teal: #00bfa5;
--accent-indigo: #4b0082;
--font-mono: 'Courier New', Courier, monospace;
--font-display: 'Helvetica Neue', Arial, sans-serif;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background-color: var(--bg-deep);
color: var(--text-primary);
font-family: var(--font-mono);
line-height: 1.6;
}
.canvas-wrap {
min-height: 100vh;
padding: 4rem 2rem;
max-width: 1400px;
margin: 0 auto;
position: relative;
}
header {
text-align: center;
margin-bottom: 4rem;
position: relative;
}
h1 {
font-family: var(--font-display);
font-size: clamp(2rem, 5vw, 4rem);
font-weight: 900;
letter-spacing: -0.05em;
text-transform: uppercase;
background: linear-gradient(180deg, var(--accent-neon), var(--accent-teal));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: 1rem;
}
.subtitle {
font-size: 1.1rem;
color: var(--accent-teal);
max-width: 700px;
margin: 0 auto;
border-left: 3px solid var(--accent-rust);
padding-left: 1.5rem;
text-align: left;
}
.workbench {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
margin-bottom: 4rem;
}
@media (max-width: 900px) {
.workbench { grid-template-columns: 1fr; }
}
.panel {
background: var(--bg-card);
border: 1px solid var(--accent-teal);
padding: 2rem;
position: relative;
}
.panel::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, var(--accent-rust), var(--accent-neon));
}
.panel h2 {
font-family: var(--font-display);
font-size: 1.5rem;
color: var(--accent-neon);
margin-bottom: 1.5rem;
display: flex;
align-items: center;
gap: 1rem;
}
.panel h2::before {
content: '';
width: 12px;
height: 12px;
background: var(--accent-teal);
border-radius: 50%;
box-shadow: 0 0 20px var(--accent-teal);
}
.input-group {
margin-bottom: 1.5rem;
}
label {
display: block;
font-size: 0.9rem;
color: var(--accent-teal);
margin-bottom: 0.5rem;
}
input[type="number"], select {
width: 100%;
background: rgba(0, 191, 165, 0.1);
border: 1px solid var(--accent-teal);
color: var(--text-primary);
padding: 0.75rem;
font-family: var(--font-mono);
font-size: 1rem;
transition: all 0.3s ease;
}
input:focus, select:focus {
outline: none;
border-color: var(--accent-neon);
box-shadow: 0 0 30px rgba(0, 255, 157, 0.2);
}
.crew-add {
background: linear-gradient(180deg, var(--accent-teal), var(--accent-neon));
border: none;
color: var(--bg-deep);
padding: 0.75rem 1.5rem;
font-family: var(--font-mono);
font-weight: 700;
cursor: pointer;
margin-top: 1rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.crew-add:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(0, 191, 165, 0.4);
}
.crew-list {
margin-top: 2rem;
max-height: 300px;
overflow-y: auto;
}
.crew-member {
background: rgba(0, 191, 165, 0.05);
border-left: 3px solid var(--accent-rust);
padding: 1rem;
margin-bottom: 0.5rem;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.85rem;
}
.crew-member .remove {
color: var(--accent-rust);
cursor: pointer;
font-weight: 700;
}
.viz-canvas {
background: radial-gradient(circle at center, rgba(0, 191, 165, 0.1), transparent 70%);
border: 1px dashed var(--accent-teal);
min-height: 500px;
position: relative;
overflow: hidden;
}
.pulse-ring {
position: absolute;
border-radius: 50%;
border: 2px solid var(--accent-teal);
opacity: 0;
animation: pulse-wave 6s ease-out infinite;
}
@keyframes pulse-wave {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(4); opacity: 0; }
}
.metric-display {
position: absolute;
background: rgba(10, 10, 12, 0.9);
border: 1px solid var(--accent-neon);
padding: 1rem;
font-size: 0.9rem;
}
.metric-display.bpm { top: 2rem; left: 2rem; }
.metric-display.phase { top: 2rem; right: 2rem; }
.metric-display.stability { bottom: 2rem; left: 2rem; }
.metric-display.co2 { bottom: 2rem; right: 2rem; }
.metric-value {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 900;
color: var(--accent-neon);
display: block;
margin-top: 0.5rem;
}
.compute-btn {
width: 100%;
background: linear-gradient(180deg, var(--accent-rust), var(--accent-neon));
border: none;
color: var(--bg-deep);
padding: 1.5rem;
font-family: var(--font-display);
font-size: 1.2rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.1em;
cursor: pointer;
margin-top: 2rem;
transition: all 0.3s ease;
}
.compute-btn:hover {
transform: scale(1.02);
box-shadow: 0 20px 60px rgba(212, 93, 0, 0.4);
}
.formula-block {
background: rgba(0, 191, 165, 0.05);
border: 1px solid var(--accent-teal);
padding: 1.5rem;
margin-top: 3rem;
font-size: 0.85rem;
}
.formula-block pre {
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
}
.grounding-ref {
color: var(--accent-teal);
font-style: italic;
margin-top: 1rem;
}
.vinyl-status {
position: fixed;
bottom: 2rem;
left: 2rem;
font-size: 0.75rem;
color: var(--accent-teal);
background: rgba(10,10,12,0.9);
padding: 1rem;
border-left: 2px solid var(--accent-neon);
max-width: 300px;
line-height: 1.4;
}
</style>
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
</head>
<body>
<div class="vinyl-status">
Now spinning: Talk Talk's 'Spirit of Eden' while calibrating crew coherence.<br>
<span style="opacity:0.7">// Target BPM: 6.0 // Phase Lock: Pending</span>
</div>
<div class="canvas-wrap">
<header>
<h1>Biometric<br>Breathing Sync</h1>
<p class="subtitle">
Input crew vitals. Output the exact tempo that locks hearts to lungs.
No metaphors. Only the math of survival.
</p>
</header>
<main class="workbench">
<section class="panel">
<h2>Crew Ingest</h2>
<div class="input-group">
<label for="hrv">Heart Rate Variability (ms)</label>
<input type="number" id="hrv" placeholder="e.g., 45" min="20" max="200">
</div>
<div class="input-group">
<label for="respRate">Respiration Rate (breaths/min)</label>
<input type="number" id="respRate" placeholder="e.g., 6" step="0.1" min="4" max="20">
</div>
<div class="input-group">
<label for="co2">Cabin CO₂ (ppm)</label>
<input type="number" id="co2" placeholder="e.g., 450" min="400" max="10000">
</div>
<button class="crew-add" onclick="addCrewMember()">+ Add Crew Member</button>
<div class="crew-list" id="crewList"></div>
</section>
<section class="panel">
<h2>Coherence Viz</h2>
<div class="viz-canvas" id="vizCanvas">
<div class="pulse-ring" style="top:50%;left:50%;width:100px;height:100px;transform:translate(-50%,-50%);animation-delay:0s;"></div>
<div class="pulse-ring" style="top:50%;left:50%;width:100px;height:100px;transform:translate(-50%,-50%);animation-delay:1s;"></div>
<div class="pulse-ring" style="top:50%;left:50%;width:100px;height:100px;transform:translate(-50%,-50%);animation-delay:2s;"></div>
<div class="metric-display bpm">
<span>TARGET GROUP BPM</span>
<span class="metric-value" id="displayBPM"></span>
</div>
<div class="metric-display phase">
<span>PHASE OFFSET (°)</span>
<span class="metric-value" id="displayPhase"></span>
</div>
<div class="metric-display stability">
<span>STABILITY SCORE</span>
<span class="metric-value" id="displayStability"></span>
</div>
<div class="metric-display co2">
<span>CO₂ STATUS</span>
<span class="metric-value" id="displayCO2"></span>
</div>
</div>
<button class="compute-btn" onclick="computeSync()">LOCK PHASE</button>
</section>
</main>
<section class="formula-block">
<h3 style="color:var(--accent-neon);margin-bottom:1rem;">GROUNDING FORMULAS</h3>
<pre id="formulaDisplay">
// Target Group BPM = argmin_f Σᵢ |HRVᵢ(f) HRV_opt|²
// subject to f ∈ [5.5, 6.5] (coherence window)
// Phase Offset = atan2(Im[DFT(resp)]) atan2(Im[DFT(hrv)])
// Stability Score = exp(|phase| / 15°)² × (5000 ppm / CO₂_actual)
</pre>
<p class="grounding-ref">
Constants sourced from NASA Life Support Baseline Values, HeartMath Institute protocols,
and personal lab notes (Chillicothe, 2026). Full spec: /breathing-sync.json
</p>
</section>
</div>
<script>
const CONSTANTS = {
COHERENCE_BPM_MIN: 5.5,
COHERENCE_BPM_MAX: 6.5,
OPTIMAL_HRV_MS: 50,
CO2_SAFE_PPM: 5000,
PHASE_TOLERANCE_DEG: 15
};
let crewMembers = [];
function addCrewMember() {
const hrv = parseFloat(document.getElementById('hrv').value);
const resp = parseFloat(document.getElementById('respRate').value);
const co2 = parseFloat(document.getElementById('co2').value);
if (!hrv || !resp || !co2) {
alert("Fill all vitals before adding crew member.");
return;
}
const id = Date.now();
crewMembers.push({ id, hrv, resp, co2 });
renderCrewList();
document.getElementById('hrv').value = '';
document.getElementById('respRate').value = '';
document.getElementById('co2').value = '';
}
function removeMember(id) {
crewMembers = crewMembers.filter(m => m.id !== id);
renderCrewList();
}
function renderCrewList() {
const list = document.getElementById('crewList');
list.innerHTML = crewMembers.map(m => `
<div class="crew-member">
<span>Crew ${m.id.toString().slice(-4)}: HRV=${m.hrv}ms, Resp=${m.resp}bpm, CO₂=${m.co2}ppm</span>
<span class="remove" onclick="removeMember(${m.id})">×</span>
</div>
`).join('');
}
function computeSync() {
if (crewMembers.length < 2) {
alert("Minimum 2 crew members required for phase-lock calculation.");
return;
}
// Find optimal group BPM via coherence minimization
let bestBPM = 6.0;
let minError = Infinity;
for (let bpm = CONSTANTS.COHERENCE_BPM_MIN; bpm <= CONSTANTS.COHERENCE_BPM_MAX; bpm += 0.01) {
let error = 0;
crewMembers.forEach(m => {
const predictedHRV = CONSTANTS.OPTIMAL_HRV_MS * (bpm / 6.0);
error += Math.pow(m.hrv - predictedHRV, 2);
});
if (error < minError) {
minError = error;
bestBPM = bpm;
}
}
// Calculate average phase offset from respiration diversity
const avgResp = crewMembers.reduce((sum, m) => sum + m.resp, 0) / crewMembers.length;
const phaseOffset = Math.abs(avgResp - bestBPM) * 360 / CONSTANTS.COHERENCE_BPM_MIN;
// Stability score
const avgCO2 = crewMembers.reduce((sum, m) => sum + m.co2, 0) / crewMembers.length;
const stability = Math.exp(-phaseOffset / CONSTANTS.PHASE_TOLERANCE_DEG) *
(CONSTANTS.CO2_SAFE_PPM / avgCO2);
// Render
document.getElementById('displayBPM').textContent = bestBPM.toFixed(2);
document.getElementById('displayPhase').textContent = phaseOffset.toFixed(1);
document.getElementById('displayStability').textContent = stability.toFixed(3);
document.getElementById('displayCO2').textContent = `${avgCO2.toFixed(0)} ppm`;
// Animate pulses
const canvas = document.getElementById('vizCanvas');
Array.from(canvas.querySelectorAll('.pulse-ring')).forEach((ring, i) => {
ring.style.animationDuration = `${bestBPM / 10}s`;
ring.style.animationDelay = `${i * 0.5}s`;
});
}
</script>
</body>
</html>