Untitled

Anonymous
plain_text
09/14/2026 9:44 AM
17.6 KB
2
Indexable
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Serene Flow - A Satisfying Well-Being Experience</title>
  <style>
    * {
      box-sizing: border-box;
      user-select: none;
    }
    body, html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
      background: #0f172a;
      font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
      color: #f8fafc;
    }
    #canvas {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
    }
    .ui-layer {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 2;
      pointer-events: none;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding: 30px;
    }
    .header {
      text-align: center;
      background: rgba(15, 23, 42, 0.65);
      backdrop-filter: blur(12px);
      padding: 15px 30px;
      border-radius: 20px;
      border: 1px solid rgba(255, 255, 255, 0.1);
      align-self: center;
      box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
    }
    h1 {
      margin: 0;
      font-size: 1.5rem;
      font-weight: 400;
      letter-spacing: 2px;
      color: #38bdf8;
    }
    p.subtitle {
      margin: 5px 0 0 0;
      font-size: 0.85rem;
      color: #94a3b8;
    }
    .hud {
      display: flex;
      justify-content: center;
      gap: 40px;
      margin-top: 15px;
    }
    .stat {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    .stat-label {
      font-size: 0.75rem;
      text-transform: uppercase;
      letter-spacing: 1px;
      color: #cbd5e1;
      margin-bottom: 5px;
    }
    .stat-bar {
      width: 140px;
      height: 8px;
      background: rgba(255, 255, 255, 0.1);
      border-radius: 4px;
      overflow: hidden;
    }
    .stat-fill {
      height: 100%;
      width: 50%;
      border-radius: 4px;
      transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.6s ease;
    }
    #harmony-fill { background: linear-gradient(90deg, #38bdf8, #34d399); }
    #calm-fill { background: linear-gradient(90deg, #a78bfa, #f472b6); }

    .toast {
      position: absolute;
      bottom: 40px;
      left: 50%;
      transform: translateX(-50%);
      background: rgba(15, 23, 42, 0.85);
      backdrop-filter: blur(16px);
      border: 1px solid rgba(56, 189, 248, 0.3);
      padding: 16px 28px;
      border-radius: 30px;
      text-align: center;
      max-width: 500px;
      width: 90%;
      box-shadow: 0 10px 30px rgba(0,0,0,0.5);
      opacity: 0;
      transition: opacity 0.5s ease, transform 0.5s ease;
      pointer-events: auto;
    }
    .toast.show {
      opacity: 1;
      transform: translateX(-50%) translateY(-10px);
    }
    .toast-title {
      font-weight: 600;
      font-size: 1rem;
      color: #38bdf8;
      margin-bottom: 4px;
    }
    .toast-body {
      font-size: 0.88rem;
      color: #e2e8f0;
      line-height: 1.4;
    }
    .start-prompt {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 1.1rem;
      color: #94a3b8;
      background: rgba(15, 23, 42, 0.8);
      padding: 15px 30px;
      border-radius: 30px;
      border: 1px solid rgba(255, 255, 255, 0.1);
      pointer-events: none;
      transition: opacity 0.5s ease;
    }
  </style>
</head>
<body>

  <canvas id="canvas"></canvas>

  <div class="ui-layer">
    <div class="header">
      <h1>SERENE FLOW</h1>
      <p class="subtitle">Pop floating energy nodes to nurture well-being & harmony</p>
      <div class="hud">
        <div class="stat">
          <span class="stat-label">Harmony & Purpose</span>
          <div class="stat-bar"><div id="harmony-fill" class="stat-fill" style="width: 50%;"></div></div>
        </div>
        <div class="stat">
          <span class="stat-label">Inner Calm</span>
          <div class="stat-bar"><div id="calm-fill" class="stat-fill" style="width: 50%;"></div></div>
        </div>
      </div>
    </div>

    <div id="start-prompt" class="start-prompt">Click or Tap anywhere to begin soothing sound</div>

    <div id="toast" class="toast">
      <div id="toast-title" class="toast-title">Welcome</div>
      <div id="toast-body" class="toast-body">Glide your cursor or tap nodes to build personal health and workplace synergy.</div>
    </div>
  </div>

<script>
// --- Audio Engine (Web Audio API Pentatonic Chimes) ---
let audioCtx = null;
const pentatonicScale = [261.63, 293.66, 329.63, 392.00, 440.00, 523.25, 587.33, 659.25]; // C Major / A Minor Pentatonic

function initAudio() {
  if (!audioCtx) {
    audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  }
  if (audioCtx.state === 'suspended') {
    audioCtx.resume();
  }
  document.getElementById('start-prompt').style.opacity = '0';
}

function playChime(freqIndex, isPositive = true) {
  if (!audioCtx) return;

  const freq = pentatonicScale[freqIndex % pentatonicScale.length];
  const osc = audioCtx.createOscillator();
  const gain = audioCtx.createGain();

  osc.type = isPositive ? 'sine' : 'triangle';
  osc.frequency.setValueAtTime(freq, audioCtx.currentTime);

  // Soft envelope
  gain.gain.setValueAtTime(0, audioCtx.currentTime);
  gain.gain.linearRampToValueAtTime(isPositive ? 0.25 : 0.15, audioCtx.currentTime + 0.05);
  gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + (isPositive ? 1.5 : 0.8));

  osc.connect(gain);
  gain.connect(audioCtx.destination);

  osc.start();
  osc.stop(audioCtx.currentTime + (isPositive ? 1.5 : 0.8));
}

// --- Well-Being Knowledge Base ---
const nodeData = [
  // HHS Framework Essentials
  { category: "Protection from Harm", title: "Psychological Safety", body: "Creating environment where open voice and mental health are normalized. (HHS Essential)", color: "#38bdf8", type: "positive" },
  { category: "Connection & Community", title: "Belonging & Trust", body: "Fostering prosocial inclusion and peer social support builds resilience. (HHS Essential)", color: "#34d399", type: "positive" },
  { category: "Work-Life Harmony", title: "Autonomy & Rest", body: "Flexible schedules and respecting non-work boundaries protect against burnout. (HHS Essential)", color: "#a78bfa", type: "positive" },
  { category: "Mattering at Work", title: "Dignity & Gratitude", body: "Knowing your work matters and receiving authentic recognition boosts morale. (HHS Essential)", color: "#f472b6", type: "positive" },
  { category: "Opportunity for Growth", title: "Learning & Mentorship", body: "Clear pathways for skill advancement build optimism and pride. (HHS Essential)", color: "#fbbf24", type: "positive" },

  // Narconon Healthy Choice Principles
  { category: "Life Choice", title: "Natural Stress Relief", body: "Replacing harmful substance coping with exercise, art, and deep breathing. (Narconon Guide)", color: "#34d399", type: "positive" },
  { category: "Life Choice", title: "Genuine Connection", body: "Engaging in face-to-face relationships instead of chemical isolation. (Narconon Guide)", color: "#38bdf8", type: "positive" },
  { category: "Life Choice", title: "Passion Projects", body: "Investing time in creative hobbies builds natural dopamine and self-worth. (Narconon Guide)", color: "#fbbf24", type: "positive" },

  // Mild Stressor / Reframing Nodes
  { category: "Workplace Hazard", title: "Unpredictable Work Hours", body: "Constant schedule flux increases anxiety. Rebalance with clear boundary setting.", color: "#f87171", type: "stressor" },
  { category: "Life Hazard", title: "Chemical Fatigue Loop", body: "Relying on stimulants or sedatives harms physical health. Choose true rest.", color: "#fb923c", type: "stressor" }
];

// --- Canvas Engine & Particles ---
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let width, height;
let nodes = [];
let particles = [];
let ripples = [];
let harmony = 50;
let calm = 50;

function resize() {
  width = canvas.width = window.innerWidth;
  height = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();

class Node {
  constructor(data) {
    this.data = data;
    this.radius = Math.random() * 20 + 35;
    this.x = Math.random() * (width - this.radius * 2) + this.radius;
    this.y = Math.random() * (height - this.radius * 2) + this.radius;
    this.vx = (Math.random() - 0.5) * 0.8;
    this.vy = (Math.random() - 0.5) * 0.8;
    this.pulse = Math.random() * Math.PI * 2;
    this.color = data.color;
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.pulse += 0.02;

    if (this.x - this.radius < 0 || this.x + this.radius > width) this.vx *= -1;
    if (this.y - this.radius < 0 || this.y + this.radius > height) this.vy *= -1;
  }

  draw() {
    ctx.save();
    ctx.beginPath();
    const currentRadius = this.radius + Math.sin(this.pulse) * 4;
    
    // Outer Glow
    const gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, currentRadius * 1.5);
    gradient.addColorStop(0, this.color + '88');
    gradient.addColorStop(0.5, this.color + '33');
    gradient.addColorStop(1, 'transparent');

    ctx.fillStyle = gradient;
    ctx.arc(this.x, this.y, currentRadius * 1.5, 0, Math.PI * 2);
    ctx.fill();

    // Inner Core
    ctx.beginPath();
    ctx.arc(this.x, this.y, currentRadius * 0.7, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.shadowColor = this.color;
    ctx.shadowBlur = 15;
    ctx.fill();

    ctx.restore();
  }
}

class Particle {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
    this.radius = Math.random() * 4 + 2;
    this.vx = (Math.random() - 0.5) * 4;
    this.vy = (Math.random() - 0.5) * 4;
    this.alpha = 1;
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.alpha -= 0.015;
  }

  draw() {
    ctx.save();
    ctx.globalAlpha = Math.max(0, this.alpha);
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.restore();
  }
}

class Ripple {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.radius = 5;
    this.alpha = 0.5;
  }

  update() {
    this.radius += 2.5;
    this.alpha -= 0.01;
  }

  draw() {
    ctx.save();
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.strokeStyle = `rgba(56, 189, 248, ${Math.max(0, this.alpha)})`;
    ctx.lineWidth = 1.5;
    ctx.stroke();
    ctx.restore();
  }
}

// Populate initial nodes
function spawnNodes() {
  nodes = [];
  nodeData.forEach(data => {
    nodes.push(new Node(data));
  });
}
spawnNodes();

// --- Main Loop ---
function animate() {
  ctx.clearRect(0, 0, width, height);

  // Background subtle grid/stars
  ctx.fillStyle = 'rgba(255, 255, 255, 0.03)';
  for (let i = 0; i < 20; i++) {
    ctx.fillRect((i * 137) % width, (i * 241) % height, 2, 2);
  }

  // Update & Draw Ripples
  ripples.forEach((r, i) => {
    r.update();
    r.draw();
    if (r.alpha <= 0) ripples.splice(i, 1);
  });

  // Update & Draw Particles
  particles.forEach((p, i) => {
    p.update();
    p.draw();
    if (p.alpha <= 0) particles.splice(i, 1);
  });

  // Update & Draw Nodes
  nodes.forEach(node => {
    node.update();
    node.draw();
  });

  requestAnimationFrame(animate);
}
animate();

// --- Interaction Handler ---
function handleInteraction(e) {
  initAudio();

  const rect = canvas.getBoundingClientRect();
  const x = (e.clientX || e.touches[0].clientX) - rect.left;
  const y = (e.clientY || e.touches[0].clientY) - rect.top;

  ripples.push(new Ripple(x, y));

  // Check collision with nodes
  for (let i = nodes.length - 1; i >= 0; i--) {
    const node = nodes[i];
    const dist = Math.hypot(node.x - x, node.y - y);

    if (dist < node.radius * 1.3) {
      // Create Burst Particles
      for (let p = 0; p < 18; p++) {
        particles.push(new Particle(node.x, node.y, node.color));
      }

      // Audio & Gameplay Stats
      const isPositive = node.data.type === 'positive';
      playChime(Math.floor(Math.random() * pentatonicScale.length), isPositive);

      if (isPositive) {
        harmony = Math.min(100, harmony + 8);
        calm = Math.min(100, calm + 6);
      } else {
        calm = Math.max(20, calm - 4);
      }
      updateHUD();

      // Show Toast Info
      showToast(node.data.title, `${node.data.category}: ${node.data.body}`);

      // Respawn Node smoothly
      const data = node.data;
      nodes.splice(i, 1);
      setTimeout(() => {
        nodes.push(new Node(data));
      }, 2500);

      break;
    }
  }
}

function updateHUD() {
  document.getElementById('harmony-fill').style.width = harmony + '%';
  document.getElementById('calm-fill').style.width = calm + '%';
}

let toastTimeout;
function showToast(title, body) {
  const toast = document.getElementById('toast');
  document.getElementById('toast-title').innerText = title;
  document.getElementById('toast-body').innerText = body;

  toast.classList.add('show');
  clearTimeout(toastTimeout);
  toastTimeout = setTimeout(() => {
    toast.classList.remove('show');
  }, 4500);
}

window.addEventListener('click', handleInteraction);
window.addEventListener('touchstart', (e) => handleInteraction(e), { passive: true });
</script>

</body>
</html>
Editor is loading...
Leave a Comment