/visualizeusingreact exchange of respiratory gases

Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Running Command

mkdir -p /tmp/workspace/gas-exchange-react && echo "Directory ready"

Writing File

~/gas-exchange-react/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Exchange of Respiratory Gases</title>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
      font-family: 'Segoe UI', Arial, sans-serif;
      background: #0f1b2d;
      color: #e8f0fe;
      min-height: 100vh;
    }
    #root { width: 100%; }
  </style>
</head>
<body>
  <div id="root"></div>

  <script type="text/babel">
    const { useState, useEffect, useRef } = React;

    /* ─── colour palette ─── */
    const C = {
      o2Rich:   '#e53e3e',  // bright red – O2-rich blood
      o2Poor:   '#4a6fa5',  // blue – deoxygenated blood
      o2Gas:    '#68d391',  // green – O2 gas molecules
      co2Gas:   '#f6ad55',  // amber – CO2 gas molecules
      alveoli:  '#bee3f8',
      tissue:   '#fefcbf',
      airway:   '#90cdf4',
      bg1:      '#1a2a4a',
      bg2:      '#162032',
      text:     '#e8f0fe',
      accent:   '#63b3ed',
      panel:    'rgba(255,255,255,0.07)',
      border:   'rgba(255,255,255,0.15)',
    };

    /* ══════════════════════════════════════════════════
       ANIMATED MOLECULE PARTICLE
    ══════════════════════════════════════════════════ */
    function Molecule({ x, y, type, size = 10, opacity = 1 }) {
      const color = type === 'O2' ? C.o2Gas : C.co2Gas;
      const label = type === 'O2' ? 'O₂' : 'CO₂';
      return (
        <g transform={`translate(${x},${y})`} opacity={opacity}>
          <circle r={size} fill={color} />
          <text
            textAnchor="middle"
            dominantBaseline="central"
            fontSize={size * 0.9}
            fontWeight="bold"
            fill="#1a202c"
          >{label}</text>
        </g>
      );
    }

    /* ══════════════════════════════════════════════════
       ANIMATED ARROW
    ══════════════════════════════════════════════════ */
    function Arrow({ x1, y1, x2, y2, color, label, dashed }) {
      const id = `arr-${x1}-${y1}`;
      const dx = x2 - x1, dy = y2 - y1;
      const angle = Math.atan2(dy, dx) * 180 / Math.PI;
      const len = Math.sqrt(dx*dx + dy*dy);
      return (
        <g>
          <defs>
            <marker id={id} markerWidth="8" markerHeight="8"
              refX="6" refY="3" orient="auto">
              <path d="M0,0 L0,6 L8,3 z" fill={color} />
            </marker>
          </defs>
          <line
            x1={x1} y1={y1} x2={x2 - 10 * Math.cos(angle * Math.PI/180)}
            y2={y2 - 10 * Math.sin(angle * Math.PI/180)}
            stroke={color} strokeWidth={2.5}
            strokeDasharray={dashed ? '6,4' : 'none'}
            markerEnd={`url(#${id})`}
          />
          {label && (
            <text
              x={(x1+x2)/2}
              y={(y1+y2)/2 - 8}
              textAnchor="middle"
              fontSize="11"
              fill={color}
              fontWeight="bold"
            >{label}</text>
          )}
        </g>
      );
    }

    /* ══════════════════════════════════════════════════
       PARTIAL PRESSURE TABLE
    ══════════════════════════════════════════════════ */
    const PP_DATA = [
      { site: 'Inspired air',      pO2: 159, pCO2: 0.3 },
      { site: 'Alveolar air',      pO2: 100, pCO2: 40  },
      { site: 'Pulmonary cap (venous)', pO2: 40,  pCO2: 45  },
      { site: 'Pulmonary cap (arterial)', pO2: 100, pCO2: 40  },
      { site: 'Systemic cap (arterial)',  pO2: 95,  pCO2: 40  },
      { site: 'Systemic cap (venous)',    pO2: 40,  pCO2: 45  },
      { site: 'Tissue cells',      pO2: 20,  pCO2: 60  },
    ];

    function PPTable() {
      return (
        <div style={{
          background: C.panel,
          border: `1px solid ${C.border}`,
          borderRadius: 12,
          padding: '16px 20px',
          marginTop: 20,
        }}>
          <h3 style={{ color: C.accent, marginBottom: 12, fontSize: 15 }}>
            Partial Pressures (mm Hg)
          </h3>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead>
              <tr style={{ borderBottom: `1px solid ${C.border}` }}>
                <th style={{ textAlign: 'left', padding: '4px 8px', color: '#a0aec0' }}>Site</th>
                <th style={{ textAlign: 'center', padding: '4px 8px', color: C.o2Gas }}>PO₂</th>
                <th style={{ textAlign: 'center', padding: '4px 8px', color: C.co2Gas }}>PCO₂</th>
              </tr>
            </thead>
            <tbody>
              {PP_DATA.map((row, i) => (
                <tr key={i} style={{ borderBottom: `1px solid rgba(255,255,255,0.05)` }}>
                  <td style={{ padding: '5px 8px' }}>{row.site}</td>
                  <td style={{ padding: '5px 8px', textAlign: 'center', color: C.o2Gas, fontWeight: 'bold' }}>{row.pO2}</td>
                  <td style={{ padding: '5px 8px', textAlign: 'center', color: C.co2Gas, fontWeight: 'bold' }}>{row.pCO2}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      );
    }

    /* ══════════════════════════════════════════════════
       MAIN DIAGRAM – SVG
    ══════════════════════════════════════════════════ */
    function GasExchangeDiagram({ tick }) {
      const W = 820, H = 560;
      // Animate molecule positions
      const phase = (tick % 60) / 60;  // 0→1 cycle

      // O2 molecule in alveolus moving into blood (lung)
      const lungO2x = 310 + phase * 80;
      const lungO2y = 185;

      // CO2 molecule from blood to alveolus (lung)
      const lungCO2x = 310 + (1 - phase) * 80;
      const lungCO2y = 220;

      // O2 molecule from blood to tissue
      const tissO2x = 520 + phase * 70;
      const tissO2y = 375;

      // CO2 molecule from tissue to blood
      const tissCO2x = 520 + (1 - phase) * 70;
      const tissCO2y = 405;

      return (
        <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', maxWidth: W, display: 'block', margin: '0 auto' }}>
          {/* ── background gradient ── */}
          <defs>
            <linearGradient id="bgGrad" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor="#1a2a4a" />
              <stop offset="100%" stopColor="#162032" />
            </linearGradient>
            <linearGradient id="bloodGrad" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={C.o2Rich} stopOpacity="0.7" />
              <stop offset="100%" stopColor={C.o2Rich} stopOpacity="0.4" />
            </linearGradient>
            <linearGradient id="venGrad" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={C.o2Poor} stopOpacity="0.7" />
              <stop offset="100%" stopColor={C.o2Poor} stopOpacity="0.4" />
            </linearGradient>
            <filter id="glow">
              <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
              <feMerge><feMergeNode in="coloredBlur"/><feMergeNode in="SourceGraphic"/></feMerge>
            </filter>
          </defs>
          <rect width={W} height={H} fill="url(#bgGrad)" rx="16" />

          {/* ══ TITLE ══ */}
          <text x={W/2} y={34} textAnchor="middle" fontSize="20" fontWeight="bold" fill={C.accent} filter="url(#glow)">
            Exchange of Respiratory Gases
          </text>
          <text x={W/2} y={52} textAnchor="middle" fontSize="12" fill="#90cdf4">
            Pulmonary (Lung) ↔ Systemic (Tissue) Gas Exchange via Diffusion
          </text>

          {/* ══════════════════════════════════
              SECTION A – LUNGS (left-centre)
          ══════════════════════════════════ */}
          {/* Alveolus sac */}
          <ellipse cx={210} cy={200} rx={120} ry={80} fill="rgba(190,227,248,0.12)" stroke={C.alveoli} strokeWidth={2} />
          <text x={210} y={126} textAnchor="middle" fontSize="13" fontWeight="bold" fill={C.alveoli}>ALVEOLUS</text>

          {/* Alveolar gas labels */}
          <text x={155} y={188} fontSize="11" fill={C.o2Gas}>PO₂ = 100</text>
          <text x={155} y={203} fontSize="11" fill={C.co2Gas}>PCO₂ = 40</text>

          {/* Pulmonary capillary – venous side */}
          <rect x={300} y={155} width={60} height={100} rx="10" fill="url(#venGrad)" stroke={C.o2Poor} strokeWidth={1.5} />
          <text x={330} y={148} textAnchor="middle" fontSize="10" fill={C.o2Poor}>Mixed venous</text>
          <text x={330} y={170} textAnchor="middle" fontSize="10" fill={C.text}>PO₂=40</text>
          <text x={330} y={183} textAnchor="middle" fontSize="10" fill={C.text}>PCO₂=45</text>

          {/* Pulmonary capillary – arterial side */}
          <rect x={380} y={155} width={60} height={100} rx="10" fill="url(#bloodGrad)" stroke={C.o2Rich} strokeWidth={1.5} />
          <text x={410} y={148} textAnchor="middle" fontSize="10" fill={C.o2Rich}>Oxygenated</text>
          <text x={410} y={170} textAnchor="middle" fontSize="10" fill={C.text}>PO₂=100</text>
          <text x={410} y={183} textAnchor="middle" fontSize="10" fill={C.text}>PCO₂=40</text>

          {/* Alveolar–capillary membrane label */}
          <line x1={299} y1={155} x2={299} y2={255} stroke="rgba(255,255,255,0.3)" strokeWidth={1} strokeDasharray="4,3" />
          <text x={299} y={272} textAnchor="middle" fontSize="10" fill="rgba(255,255,255,0.5)" transform="rotate(-90,299,272)" dy="-4">
          </text>
          <text x={265} y={278} textAnchor="middle" fontSize="10" fill="#a0aec0">Alveolar–capillary membrane</text>
          <text x={265} y={290} textAnchor="middle" fontSize="10" fill="#718096">(~0.5 µm thick)</text>

          {/* O2 diffusion arrow: alveolus → capillary */}
          <Arrow x1={248} y1={190} x2={296} y2={190} color={C.o2Gas} label="O₂ ↓ gradient" />
          {/* CO2 diffusion arrow: capillary → alveolus */}
          <Arrow x1={296} y1={218} x2={248} y2={218} color={C.co2Gas} label="CO₂ ↑ gradient" />

          {/* Animated O2 molecule */}
          <Molecule x={Math.min(lungO2x, 288)} y={lungO2y} type="O2" size={9} />
          {/* Animated CO2 molecule */}
          <Molecule x={Math.max(lungCO2x, 248)} y={lungCO2y} type="CO2" size={9} />

          {/* Inspiration arrow */}
          <Arrow x1={90} y1={120} x2={140} y2={160} color={C.airway} label="Inspiration" />
          <text x={62} y={113} fontSize="11" fill={C.airway}>PO₂=159</text>
          <text x={62} y={127} fontSize="11" fill={C.airway}>PCO₂≈0</text>

          {/* Expiration arrow */}
          <Arrow x1={140} y1={250} x2={90} y2={285} color={C.co2Gas} label="Expiration" dashed />

          {/* ══════════════════════════════════
              CIRCULATORY VESSELS
          ══════════════════════════════════ */}
          {/* Pulmonary vein (oxygenated → heart → body) */}
          <path d="M440 205 Q500 205 500 270 Q500 330 500 360" stroke={C.o2Rich} strokeWidth={14} fill="none" strokeOpacity="0.55" />
          <text x={510} y={295} fontSize="11" fill={C.o2Rich} fontWeight="bold">Pulmonary vein</text>
          <text x={510} y={310} fontSize="10" fill={C.o2Rich}>(oxygenated)</text>

          {/* Pulmonary artery (deoxygenated → lungs) */}
          <path d="M300 360 Q300 310 300 270 Q300 205 310 205" stroke={C.o2Poor} strokeWidth={14} fill="none" strokeOpacity="0.55" />
          <text x={182} y={340} fontSize="11" fill={C.o2Poor} fontWeight="bold">Pulmonary artery</text>
          <text x={182} y={355} fontSize="10" fill={C.o2Poor}>(deoxygenated)</text>

          {/* Heart icon placeholder */}
          <ellipse cx={400} cy={360} rx={38} ry={35} fill="rgba(229,62,62,0.2)" stroke={C.o2Rich} strokeWidth={2} />
          <text x={400} y={355} textAnchor="middle" fontSize="22">♥</text>
          <text x={400} y={378} textAnchor="middle" fontSize="11" fill={C.o2Rich}>Heart</text>

          {/* Aorta / systemic artery */}
          <path d="M438 360 Q500 360 540 360 Q580 360 600 370" stroke={C.o2Rich} strokeWidth={12} fill="none" strokeOpacity="0.55" />
          <text x={550} y={352} fontSize="11" fill={C.o2Rich}>Systemic artery</text>
          <text x={550} y={365} fontSize="10" fill={C.o2Rich}>PO₂=95, PCO₂=40</text>

          {/* Systemic vein */}
          <path d="M600 440 Q560 440 500 430 Q440 420 400 410 Q380 405 362 390" stroke={C.o2Poor} strokeWidth={12} fill="none" strokeOpacity="0.55" />
          <text x={490} y={452} fontSize="11" fill={C.o2Poor}>Systemic vein</text>
          <text x={490} y={466} fontSize="10" fill={C.o2Poor}>PO₂=40, PCO₂=45</text>

          {/* ══════════════════════════════════
              SECTION B – TISSUE (right)
          ══════════════════════════════════ */}
          <rect x={600} y={340} width={150} height={120} rx={14} fill="rgba(254,252,191,0.1)" stroke={C.tissue} strokeWidth={2} />
          <text x={675} y={328} textAnchor="middle" fontSize="13" fontWeight="bold" fill={C.tissue}>TISSUE / CELL</text>
          <text x={620} y={370} fontSize="11" fill={C.o2Gas}>PO₂ ≈ 20 mm Hg</text>
          <text x={620} y={385} fontSize="11" fill={C.co2Gas}>PCO₂ ≈ 60 mm Hg</text>
          <text x={620} y={400} fontSize="10" fill="#a0aec0">(mitochondria consume O₂</text>
          <text x={620} y={413} fontSize="10" fill="#a0aec0"> and produce CO₂)</text>

          {/* O2 diffusion: blood → tissue */}
          <Arrow x1={600} y1={375} x2={540} y2={385} color={C.o2Gas} label="O₂" />
          {/* CO2 diffusion: tissue → blood */}
          <Arrow x1={540} y1={405} x2={600} y2={410} color={C.co2Gas} label="CO₂" />

          {/* Animated tissue O2 */}
          <Molecule x={tissO2x} y={tissO2y} type="O2" size={9} />
          {/* Animated tissue CO2 */}
          <Molecule x={tissCO2x} y={tissCO2y} type="CO2" size={9} />

          {/* ══════════════════════════════════
              FICK'S LAW LABEL
          ══════════════════════════════════ */}
          <rect x={24} y={340} width={180} height={80} rx={10} fill={C.panel} stroke={C.border} />
          <text x={114} y={358} textAnchor="middle" fontSize="12" fontWeight="bold" fill={C.accent}>Fick's Law</text>
          <text x={114} y={375} textAnchor="middle" fontSize="11" fill={C.text}>V = D · A · ΔP / Δx</text>
          <text x={114} y={390} textAnchor="middle" fontSize="10" fill="#a0aec0">D(CO₂) ≈ 20× D(O₂)</text>
          <text x={114} y={405} textAnchor="middle" fontSize="10" fill="#a0aec0">Area↑ → V↑ | Thickness↑ → V↓</text>

          {/* ══════════════════════════════════
              LEGEND
          ══════════════════════════════════ */}
          <rect x={590} y={58} width={210} height={105} rx={10} fill={C.panel} stroke={C.border} />
          <text x={695} y={76} textAnchor="middle" fontSize="12" fontWeight="bold" fill={C.accent}>Legend</text>
          <circle cx={608} cy={92} r={7} fill={C.o2Gas} />
          <text x={620} y={96} fontSize="11" fill={C.text}>O₂ molecule (diffusing)</text>
          <circle cx={608} cy={112} r={7} fill={C.co2Gas} />
          <text x={620} y={116} fontSize="11" fill={C.text}>CO₂ molecule (diffusing)</text>
          <rect x={601} cy={128} width={14} height={8} fill={C.o2Rich} rx="2" />
          <rect x={601} y={126} width={14} height={8} fill={C.o2Rich} rx="2" />
          <text x={620} y={134} fontSize="11" fill={C.text}>Oxygenated blood</text>
          <rect x={601} y={144} width={14} height={8} fill={C.o2Poor} rx="2" />
          <text x={620} y={152} fontSize="11" fill={C.text}>Deoxygenated blood</text>

          {/* ══ DIFFUSION COEFFICIENT NOTE ══ */}
          <text x={W/2} y={H-14} textAnchor="middle" fontSize="10" fill="#718096">
            CO₂ diffuses ~20× faster than O₂ despite similar partial pressure gradients (higher solubility × MW ratio)
          </text>
        </svg>
      );
    }

    /* ══════════════════════════════════════════════════
       INFO CARDS
    ══════════════════════════════════════════════════ */
    const CARDS = [
      {
        title: 'Pulmonary Gas Exchange',
        color: '#63b3ed',
        icon: '🫁',
        points: [
          'O₂ diffuses from alveoli (PO₂=100) into pulmonary capillary blood (PO₂=40) — gradient 60 mm Hg',
          'CO₂ diffuses from mixed venous blood (PCO₂=45) into alveoli (PCO₂=40) — gradient 5 mm Hg',
          'Equilibration occurs within ~0.25 s (only 1/3 of capillary transit time)',
          'Alveolar–capillary membrane is only ~0.5 µm thick',
        ],
      },
      {
        title: 'Systemic / Tissue Gas Exchange',
        color: '#f6ad55',
        icon: '🔬',
        points: [
          'O₂ diffuses from systemic capillary blood (PO₂=95) into tissue cells (PO₂≈20) — gradient ~75 mm Hg',
          'CO₂ produced by mitochondria raises tissue PCO₂ to ~60 mm Hg; diffuses into blood (PCO₂=40)',
          'Result: arterialised blood becomes venous blood (PO₂=40, PCO₂=45)',
          'Higher metabolic rate → steeper gradients → more gas exchanged',
        ],
      },
      {
        title: "Fick's Law of Diffusion",
        color: '#68d391',
        icon: '📐',
        points: [
          'Rate ∝ Diffusion coefficient × Surface area × ΔPartial pressure',
          'Rate ∝ 1 / Membrane thickness',
          'D(CO₂) ≈ 20× D(O₂) because CO₂ is ~24× more soluble in water',
          'Emphysema: surface area↓ → DL↓; Fibrosis/oedema: thickness↑ → DL↓',
        ],
      },
      {
        title: 'Alveolar Gas Equation',
        color: '#e9d8fd',
        icon: '🧮',
        points: [
          'PAO₂ = PiO₂ − PACO₂ / R',
          'PiO₂ (humidified inspired) = (760−47) × 0.21 ≈ 150 mm Hg',
          'Respiratory exchange ratio R = VCO₂/VO₂ ≈ 0.8 at rest',
          'PAO₂ ≈ 150 − 40/0.8 ≈ 100 mm Hg',
        ],
      },
    ];

    function InfoCard({ card }) {
      return (
        <div style={{
          background: 'rgba(255,255,255,0.06)',
          border: `1px solid ${card.color}44`,
          borderLeft: `4px solid ${card.color}`,
          borderRadius: 12,
          padding: '16px 18px',
          flex: '1 1 320px',
          minWidth: 280,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
            <span style={{ fontSize: 22 }}>{card.icon}</span>
            <h3 style={{ color: card.color, fontSize: 15 }}>{card.title}</h3>
          </div>
          <ul style={{ paddingLeft: 18 }}>
            {card.points.map((p, i) => (
              <li key={i} style={{ marginBottom: 6, fontSize: 13, lineHeight: 1.5, color: '#cbd5e0' }}>{p}</li>
            ))}
          </ul>
        </div>
      );
    }

    /* ══════════════════════════════════════════════════
       HAEMOGLOBIN O2 DISSOCIATION CURVE (mini SVG)
    ══════════════════════════════════════════════════ */
    function ODC() {
      // Sigmoid curve points (simplified Hill equation)
      const W = 300, H = 160;
      const points = [];
      for (let pO2 = 0; pO2 <= 100; pO2 += 2) {
        const sat = Math.pow(pO2, 2.7) / (Math.pow(26, 2.7) + Math.pow(pO2, 2.7)) * 100;
        const px = 30 + (pO2 / 100) * 250;
        const py = 140 - (sat / 100) * 120;
        points.push(`${px},${py}`);
      }
      const pathD = 'M ' + points.join(' L ');

      return (
        <div style={{
          background: C.panel,
          border: `1px solid ${C.border}`,
          borderRadius: 12,
          padding: '16px 20px',
          marginTop: 20,
        }}>
          <h3 style={{ color: C.accent, marginBottom: 10, fontSize: 15 }}>
            Oxyhaemoglobin Dissociation Curve
          </h3>
          <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', maxWidth: W }}>
            <rect width={W} height={H} fill="rgba(0,0,0,0.2)" rx="8" />
            {/* axes */}
            <line x1={30} y1={140} x2={280} y2={140} stroke="#718096" strokeWidth={1.5} />
            <line x1={30} y1={20}  x2={30}  y2={140} stroke="#718096" strokeWidth={1.5} />
            {/* axis labels */}
            <text x={155} y={H-2} textAnchor="middle" fontSize="11" fill="#a0aec0">PO₂ (mm Hg)</text>
            <text x={8} y={80} textAnchor="middle" fontSize="11" fill="#a0aec0" transform="rotate(-90,8,80)">SaO₂ (%)</text>
            {/* tick marks */}
            {[0,25,50,75,100].map(v => (
              <g key={v}>
                <line x1={30 + v*2.5} y1={140} x2={30 + v*2.5} y2={144} stroke="#718096" />
                <text x={30 + v*2.5} y={154} textAnchor="middle" fontSize="9" fill="#718096">{v}</text>
              </g>
            ))}
            {[0,25,50,75,100].map(v => (
              <g key={v}>
                <line x1={26} y1={140 - v*1.2} x2={30} y2={140 - v*1.2} stroke="#718096" />
                <text x={22} y={140 - v*1.2 + 3} textAnchor="end" fontSize="9" fill="#718096">{v}</text>
              </g>
            ))}
            {/* sigmoid curve */}
            <polyline points={points.join(' ')} fill="none" stroke={C.o2Rich} strokeWidth={2.5} />
            {/* key points */}
            {/* tissue (40 mmHg, ~75%) */}
            <circle cx={30+40*2.5} cy={140 - (Math.pow(40,2.7)/(Math.pow(26,2.7)+Math.pow(40,2.7)))*120} r={5} fill={C.o2Poor} />
            <text x={30+40*2.5+6} y={140 - (Math.pow(40,2.7)/(Math.pow(26,2.7)+Math.pow(40,2.7)))*120} fontSize="9" fill={C.o2Poor}>Tissues (40)</text>
            {/* lung (100 mmHg, ~98%) */}
            <circle cx={30+100*2.5} cy={140 - (Math.pow(100,2.7)/(Math.pow(26,2.7)+Math.pow(100,2.7)))*120} r={5} fill={C.o2Gas} />
            <text x={30+100*2.5-50} y={140 - (Math.pow(100,2.7)/(Math.pow(26,2.7)+Math.pow(100,2.7)))*120 - 6} fontSize="9" fill={C.o2Gas}>Lungs (100)</text>
            {/* P50 line */}
            <line x1={30+26*2.5} y1={20} x2={30+26*2.5} y2={140} stroke="#718096" strokeDasharray="3,3" strokeWidth={1} />
            <text x={30+26*2.5+2} y={30} fontSize="9" fill="#718096">P₅₀=26</text>
          </svg>
          <p style={{ fontSize: 12, color: '#a0aec0', marginTop: 8 }}>
            At the lungs (PO₂=100), Hb is ~98% saturated. At the tissues (PO₂=40), Hb releases O₂ → saturation falls to ~75%.
            This ~23% difference represents the O₂ delivered per cardiac cycle.
          </p>
        </div>
      );
    }

    /* ══════════════════════════════════════════════════
       TAB NAVIGATION
    ══════════════════════════════════════════════════ */
    const TABS = ['Overview Diagram', 'Key Concepts', 'O₂-Hb Curve', 'Partial Pressures'];

    /* ══════════════════════════════════════════════════
       APP ROOT
    ══════════════════════════════════════════════════ */
    function App() {
      const [tab, setTab] = useState(0);
      const [tick, setTick] = useState(0);

      useEffect(() => {
        const id = setInterval(() => setTick(t => t + 1), 80);
        return () => clearInterval(id);
      }, []);

      return (
        <div style={{ maxWidth: 900, margin: '0 auto', padding: '20px 16px 40px' }}>
          {/* HEADER */}
          <div style={{
            textAlign: 'center',
            marginBottom: 24,
            padding: '24px 20px 16px',
            background: 'linear-gradient(135deg, rgba(99,179,237,0.15), rgba(104,211,145,0.1))',
            borderRadius: 16,
            border: `1px solid ${C.border}`,
          }}>
            <h1 style={{ fontSize: 28, fontWeight: 800, color: C.accent, marginBottom: 6 }}>
              🫁 Exchange of Respiratory Gases
            </h1>
            <p style={{ color: '#90cdf4', fontSize: 14 }}>
              Interactive visualization of O₂ and CO₂ exchange at the lungs and peripheral tissues
            </p>
          </div>

          {/* TAB BAR */}
          <div style={{ display: 'flex', gap: 8, marginBottom: 20, flexWrap: 'wrap' }}>
            {TABS.map((t, i) => (
              <button
                key={i}
                onClick={() => setTab(i)}
                style={{
                  padding: '8px 18px',
                  borderRadius: 8,
                  border: 'none',
                  cursor: 'pointer',
                  fontSize: 13,
                  fontWeight: 600,
                  background: tab === i ? C.accent : 'rgba(255,255,255,0.08)',
                  color: tab === i ? '#1a202c' : C.text,
                  transition: 'all 0.2s',
                }}
              >{t}</button>
            ))}
          </div>

          {/* TAB CONTENT */}
          {tab === 0 && (
            <div style={{
              background: C.panel,
              border: `1px solid ${C.border}`,
              borderRadius: 16,
              padding: 16,
            }}>
              <GasExchangeDiagram tick={tick} />
              <p style={{ textAlign: 'center', fontSize: 12, color: '#718096', marginTop: 8 }}>
                Molecules animate continuously. Arrows show net diffusion direction driven by partial pressure gradients.
              </p>
            </div>
          )}

          {tab === 1 && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 16 }}>
              {CARDS.map((c, i) => <InfoCard key={i} card={c} />)}
            </div>
          )}

          {tab === 2 && <ODC />}

          {tab === 3 && <PPTable />}

          {/* FOOTER CREDIT */}
          <p style={{ textAlign: 'center', fontSize: 11, color: '#4a5568', marginTop: 28 }}>
            Based on Costanzo Physiology 7th Ed · Murray &amp; Nadel's Respiratory Medicine · Fick's Law of Diffusion
          </p>
        </div>
      );
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>
Here is your interactive React visualization:

index

HTML File · HTML


What's inside

The app has 4 tabs, all styled on a dark physiology-themed canvas:

Tab 1 - Overview Diagram (animated SVG)

  • A full-width SVG showing the complete circuit: Alveolus → Pulmonary capillary → Heart → Systemic artery → Tissue → Systemic vein → Heart → Pulmonary artery → back to alveolus
  • Animated O₂ and CO₂ molecules moving across the alveolar-capillary membrane and the tissue-capillary membrane in real time
  • All key partial pressure values labelled at each site (PO₂ 100 in alveoli vs 40 in mixed venous, PCO₂ 45 in venous vs 40 in alveoli, etc.)
  • Fick's Law box: V = D · A · ΔP / Δx
  • A note that CO₂ diffuses ~20× faster than O₂

Tab 2 - Key Concepts (4 info cards)

  • Pulmonary gas exchange mechanics
  • Systemic/tissue gas exchange
  • Fick's Law in clinical context (emphysema = area↓, fibrosis = thickness↑)
  • Alveolar gas equation: PAO₂ = PiO₂ - PACO₂/R ≈ 100 mm Hg

Tab 3 - Oxyhaemoglobin Dissociation Curve

  • Sigmoid curve rendered with the Hill equation
  • Key points annotated: lungs (PO₂=100, SaO₂≈98%) and tissues (PO₂=40, SaO₂≈75%)
  • P₅₀ line marked at 26 mm Hg

Tab 4 - Partial Pressure Table

  • All 7 compartments from inspired air through to tissue cells, with PO₂ and PCO₂ at each step
Sources: Costanzo Physiology 7th Ed, Murray & Nadel's Respiratory Medicine
This is a shared conversation. Sign in to Orris to start your own chat.