# Balloon ## Microsim ### Live player <div class="microsim-player"> <iframe src="https://editor.p5js.org/sciencenibber/full/JJ37eYM7T" width="100%" height="620" frameborder="0" sandbox="allow-scripts allow-same-origin"></iframe> </div> <div class="microsim-fallback"> <img src="Microsims/thumbs/Balloon.png" alt="Balloon microsim poster" style="width:100%;border:1px solid #4445;border-radius:6px;"> <p><em>Live microsim (desktop) · <a href="https://editor.p5js.org/sciencenibber/sketches/JJ37eYM7T">open sketch in the p5.js editor</a></em></p> </div> **Editor URL:** https://editor.p5js.org/sciencenibber/sketches/JJ37eYM7T **Description (100 words):** A side-view ascent simulator. A shaded balloon hovers in a 30-km atmospheric column tinted by air density. Four sliders let the reader pick the [[Lifting_gas|lifting gas]] (helium, hydrogen, hot air, methane), the sea-level envelope volume V_0, the payload mass, and an ascent-speed multiplier. Press play and the balloon climbs along a drag-limited terminal [[Velocity|velocity]]; as it rises, ambient pressure falls and the envelope expands by Boyle's law (V grows visibly with altitude). A dashed magenta line marks the calculated equilibrium altitude z_eq, and a right-side panel reads out live rho_air, rho_gas, V(z), F_lift, F_net, and z to show the buoyancy budget exactly where it tips negative. ```js // ===================================================================== // Balloon.js -- Wikitube microsim // Article: Balloon en.wikitube.io/wiki/Balloon // Room: Helium Pattern: 8 (Geometry crossover -- // topological / spatial visualization) // --------------------------------------------------------------------- // Idea: a side-view ascent simulator for a buoyant balloon in the // US Standard Atmosphere. The reader picks a lifting gas (helium, // hydrogen, hot air, or methane), sets the sea-level envelope volume // and the payload mass, and watches the balloon climb until net lift // goes to zero. As the balloon rises ambient pressure drops and the // envelope expands (Boyle's law at constant T), so the shaded // ellipse grows visibly with altitude -- the article's central // spatial fact, made interactive. // // Physics laid out on the canvas: // // F_lift = (rho_air - rho_gas) * V * g [buoyancy] // F_net = F_lift - m_payload * g [free body] // P V = constant [Boyle, T fixed] // rho_air = rho_0 * exp(-z / H) [isothermal atm] // // Equilibrium altitude z_eq is where rho_air(z) * V(z) equals the // total system mass m_gas + m_payload. The integrator walks the // balloon up the column with a simple drag-limited terminal velocity // so the ascent feels readable rather than instantaneous. // // Atmosphere: a simplified two-region model -- exponential decay of // density with scale height H = 8.5 km up to the tropopause (~11 km), // then a slower decay above. Good enough to land equilibrium // altitudes within ~10% of a NASA US-Std-1976 reference, which is // the right precision for the microsim's pedagogical job. // // Visual layout (720 x 520 canvas): // * top-left: HUD title + en.wikitube.io/wiki/Balloon subtitle // * top-right: control hints (play / pause / reset, gas-cycle) // * left band: altitude axis 0 - 30 km, atmospheric-density tint // * center: the balloon -- shaded ellipse + payload box + tether // * right band: live readout panel (V, rho_air, rho_gas, F_lift, // F_net, current altitude, equilibrium altitude) // * bottom: four sliders (gas idx, V_0 in m^3, m_payload in kg, // ascent speed multiplier) + canonical equation // // Conventions (Wikitube Betterfire Standard v0): // * single ARTICLE constant at the top, single quotes // * p5.disableFriendlyErrors = true to keep the editor console clean // * non-ASCII (Greek rho, dot, arrow) lives in COMMENTS ONLY; // every text() string literal is ASCII // * Energy-room palette (P5_JS_EDITOR section 4, line 165) // * all createSlider calls carry .position(x, y).size(w) // ===================================================================== const ARTICLE = 'Balloon'; const TITLE = ARTICLE.replace(/_/g, ' '); p5.disableFriendlyErrors = true; // ----- Energy room palette (P5_JS_EDITOR section 4, line 165) -------- const BG = 18; const FG = 240; const DIM = [240, 240, 240, 140]; const HOT = [220, 110, 60]; // warm: hot-air gas, equation const COLD = [60, 130, 220]; // cool: atmosphere tint const COLDER = [40, 80, 180]; // deep cool: high-altitude tint const STRUCT = [120, 130, 150]; // structural grey: payload, axis const TRAJ = [240, 220, 80]; // yellow accent: balloon envelope const SCRATCH = [120, 120, 120, 90]; // grid scratch lines const ACCENT = [200, 100, 220]; // tether / highlight // ----- Physical constants ------------------------------------------- const G = 9.80665; // m/s^2, standard gravity const T_AMBIENT = 288.15; // K, sea-level temperature const P0 = 101325; // Pa, sea-level pressure const RHO_0 = 1.225; // kg/m^3, sea-level air density const R_SPEC_AIR = 287.05; // J/(kg*K), specific gas const, air const H_SCALE = 8500; // m, scale height (isothermal atm) const Z_TROPO = 11000; // m, tropopause altitude const Z_MAX = 30000; // m, plot ceiling // ----- Gas catalog -- molar mass drives the density at T_AMBIENT, P0 // rho = P * M / (R_univ * T); we precompute rho_0 for each gas. The // hot-air entry uses the rho at the chosen burner temperature (388 K). const R_UNIV = 8.31446; // J/(mol*K), universal gas const const GASES = [ // [label, M (kg/mol), T_gas (K), color] ['Helium', 0.0040026, T_AMBIENT, [180, 220, 255]], ['Hydrogen', 0.0020159, T_AMBIENT, [255, 200, 200]], ['Hot air', 0.028964, 388.15, [255, 170, 80]], ['Methane', 0.016043, T_AMBIENT, [160, 255, 180]] ]; function gasDensity(gIdx) { const [, M, T_gas] = GASES[gIdx]; return (P0 * M) / (R_UNIV * T_gas); } // ----- Atmosphere model --------------------------------------------- // Two-region exponential: scale height H = 8500 m below tropopause, // then a softer decay above (effective H' = 6000 m) so the model // doesn't run too rich at 25-30 km. function rhoAir(z) { if (z <= Z_TROPO) { return RHO_0 * Math.exp(-z / H_SCALE); } const rho_tropo = RHO_0 * Math.exp(-Z_TROPO / H_SCALE); return rho_tropo * Math.exp(-(z - Z_TROPO) / 6000); } function pAir(z) { // Same form for P, since isothermal scaling gives P proportional to rho. if (z <= Z_TROPO) { return P0 * Math.exp(-z / H_SCALE); } const p_tropo = P0 * Math.exp(-Z_TROPO / H_SCALE); return p_tropo * Math.exp(-(z - Z_TROPO) / 6000); } // Envelope volume from Boyle's law at constant T_gas: // P_inside = P_air(z), so V(z) = V_0 * P_0 / P_air(z) function envelopeVolume(V0, z) { return V0 * P0 / pAir(z); } // ----- Sliders + state ---------------------------------------------- let gasSlider, volumeSlider, payloadSlider, speedSlider; let playBtn, resetBtn, gasBtn; let gIdx = 0; // 0 = helium (default) let z_current = 0; // m, current altitude let v_current = 0; // m/s, current vertical velocity let playing = false; let lastReset = 0; // ----- Layout rectangles (set in setup) ----------------------------- let columnX, columnY, columnW, columnH; let readoutX, readoutY, readoutW, readoutH; function setup() { createCanvas(720, 520); pixelDensity(2); textFont('system-ui'); // Side view: altitude column on the left, payload column in middle, // numerical readout column on the right. columnX = 70; columnY = 60; columnW = 280; columnH = 360; readoutX = columnX + columnW + 30; readoutY = columnY; readoutW = width - readoutX - 30; readoutH = columnH; // Sliders along the bottom strip. Each carries explicit position+size // per Betterfire Standard (P5_JS_EDITOR section 2). const sliderY = height - 60; gasSlider = createSlider(0, GASES.length - 1, 0, 1) .position(70, sliderY).size(120); volumeSlider = createSlider(1, 200, 30, 1) .position(220, sliderY).size(120); payloadSlider = createSlider(0, 80, 5, 1) .position(370, sliderY).size(120); speedSlider = createSlider(1, 200, 50, 1) .position(520, sliderY).size(120); // Buttons sit above the sliders. playBtn = createButton('play / pause') .position(70, height - 30).size(110, 22); playBtn.mousePressed(() => { playing = !playing; }); resetBtn = createButton('reset') .position(190, height - 30).size(80, 22); resetBtn.mousePressed(() => { z_current = 0; v_current = 0; playing = false; }); } function draw() { background(BG); // Pull every slider value once at the top of draw(). gIdx = gasSlider.value(); const V0 = volumeSlider.value(); // m^3 sea-level envelope const m_payload = payloadSlider.value(); // kg const speedMult = speedSlider.value() / 50; // 1 -> 1x; 200 -> 4x const rho_gas_0 = gasDensity(gIdx); const m_gas = rho_gas_0 * V0; // Net force at current altitude (drives the integrator). const rho_a = rhoAir(z_current); const V_z = envelopeVolume(V0, z_current); // Gas mass is conserved; gas density scales with the expanded volume. const rho_g = m_gas / V_z; const F_lift = (rho_a - rho_g) * V_z * G; const F_net = F_lift - m_payload * G; // Equilibrium altitude: scan the column for the height where // (rho_air(z) - rho_gas(z)) * V(z) * g - m_payload * g changes sign. const z_eq = findEquilibrium(V0, m_gas, m_payload); // Integrate ascent with a simple drag-limited terminal velocity. // Drag balances net force at v_term ~ sqrt(2 |F_net| / (rho_a * Cd * A)). if (playing) { const A_cross = Math.PI * Math.pow((3 * V_z) / (4 * Math.PI), 2 / 3); // cross section of a sphere of volume V const Cd = 0.47; const v_term = Math.sign(F_net) * Math.sqrt(2 * Math.abs(F_net) / (rho_a * Cd * A_cross + 1e-6)); // Relax toward terminal velocity. v_current += (v_term - v_current) * 0.08; z_current += v_current * (deltaTime / 1000) * speedMult; if (z_current < 0) { z_current = 0; v_current = 0; } if (z_current > Z_MAX) { z_current = Z_MAX; v_current = 0; } } drawColumn(z_eq); drawBalloon(V_z, z_current); drawReadout(rho_a, rho_g, V_z, F_lift, F_net, z_eq, m_gas, m_payload); drawSliderLabels(V0, m_payload, speedMult); drawHUD(); drawEquation(); } // ===================================================================== // Equilibrium-altitude scan // ===================================================================== // Walk the column from 0 to Z_MAX in 200 steps; equilibrium is the // first z where lift turns negative. Returns Z_MAX if balloon never // reaches equilibrium (over-buoyant) or -1 if it cannot lift off. function findEquilibrium(V0, m_gas, m_payload) { const N = 200; let prevF = ((RHO_0) - (m_gas / V0)) * V0 * G - m_payload * G; if (prevF <= 0) return -1; // can't lift off for (let i = 1; i <= N; i++) { const z = (i / N) * Z_MAX; const V_z = envelopeVolume(V0, z); const F = (rhoAir(z) - m_gas / V_z) * V_z * G - m_payload * G; if (F <= 0) { // Linear interpolate between the bracketing steps. const zPrev = ((i - 1) / N) * Z_MAX; const frac = prevF / (prevF - F); return zPrev + frac * (z - zPrev); } prevF = F; } return Z_MAX; } // ===================================================================== // Drawing // ===================================================================== // ----- atmospheric column with altitude axis ------------------------ function drawColumn(z_eq) { // Background gradient: dense at the bottom, thin at the top. noStroke(); const NBANDS = 60; for (let i = 0; i < NBANDS; i++) { const z = (i / NBANDS) * Z_MAX; const rho = rhoAir(z); const alpha = map(rho, 0, RHO_0, 30, 180); const r = lerp(COLDER[0], COLD[0], rho / RHO_0); const g = lerp(COLDER[1], COLD[1], rho / RHO_0); const b = lerp(COLDER[2], COLD[2], rho / RHO_0); fill(r, g, b, alpha); const y0 = map(z + Z_MAX / NBANDS, 0, Z_MAX, columnY + columnH, columnY); const y1 = map(z, 0, Z_MAX, columnY + columnH, columnY); rect(columnX, y0, columnW, y1 - y0 + 1); } // Altitude axis ticks (every 5 km). stroke(...STRUCT); strokeWeight(1); fill(...STRUCT); textSize(10); textAlign(RIGHT, CENTER); for (let z = 0; z <= Z_MAX; z += 5000) { const y = map(z, 0, Z_MAX, columnY + columnH, columnY); line(columnX - 4, y, columnX, y); noStroke(); text(nf(z / 1000, 1, 0) + ' km', columnX - 8, y); stroke(...STRUCT); } // Tropopause marker. const yTropo = map(Z_TROPO, 0, Z_MAX, columnY + columnH, columnY); stroke(...DIM); strokeWeight(1); drawingContext.setLineDash([4, 4]); line(columnX, yTropo, columnX + columnW, yTropo); drawingContext.setLineDash([]); noStroke(); fill(...DIM); textSize(10); textAlign(LEFT, BOTTOM); text('tropopause', columnX + 6, yTropo - 2); // Equilibrium-altitude dashed line. if (z_eq > 0 && z_eq < Z_MAX) { const yEq = map(z_eq, 0, Z_MAX, columnY + columnH, columnY); stroke(...ACCENT, 200); strokeWeight(1.2); drawingContext.setLineDash([6, 4]); line(columnX, yEq, columnX + columnW, yEq); drawingContext.setLineDash([]); noStroke(); fill(...ACCENT); textSize(10); textAlign(LEFT, BOTTOM); text('z_eq = ' + nf(z_eq / 1000, 1, 1) + ' km', columnX + 6, yEq - 2); } // Ground. fill(...STRUCT); noStroke(); rect(columnX, columnY + columnH, columnW, 4); } // ----- balloon at current altitude ---------------------------------- function drawBalloon(V_z, z) { // Map balloon volume to a pixel radius. Use cube root so volume // grows visibly without overflowing the canvas at high altitude. // r_px = K * V^(1/3); K chosen so V=30 m^3 -> r=26 px. const r_px = 26 * Math.pow(V_z / 30, 1 / 3); const xc = columnX + columnW / 2; const yc = map(z, 0, Z_MAX, columnY + columnH - 14, columnY + 30); // Tether to the payload box. stroke(...ACCENT); strokeWeight(1); line(xc, yc + r_px, xc, yc + r_px + 18); // Payload box (5 px tall, scales gently with payload mass). const m_payload = payloadSlider.value(); const boxH = 5 + Math.min(m_payload * 0.2, 12); fill(...STRUCT); noStroke(); rectMode(CENTER); rect(xc, yc + r_px + 18 + boxH / 2, 16, boxH, 1); rectMode(CORNER); // Envelope: shaded ellipse for a 3D feel. Highlight a quarter-circle. const gasCol = GASES[gIdx][3]; noStroke(); // Soft outer glow. fill(gasCol[0], gasCol[1], gasCol[2], 60); ellipse(xc, yc, r_px * 2.4, r_px * 2.6); // Main envelope. fill(gasCol[0], gasCol[1], gasCol[2], 220); ellipse(xc, yc, r_px * 2, r_px * 2.2); // Highlight crescent (upper-left). fill(255, 255, 255, 70); ellipse(xc - r_px * 0.35, yc - r_px * 0.45, r_px * 0.9, r_px * 0.7); // Outline. stroke(...TRAJ, 200); strokeWeight(1.2); noFill(); ellipse(xc, yc, r_px * 2, r_px * 2.2); } // ----- right-side numerical readout --------------------------------- function drawReadout(rho_a, rho_g, V_z, F_lift, F_net, z_eq, m_gas, m_payload) { noStroke(); fill(BG + 6); rect(readoutX, readoutY, readoutW, readoutH, 4); stroke(...STRUCT, 120); strokeWeight(1); noFill(); rect(readoutX, readoutY, readoutW, readoutH, 4); noStroke(); fill(FG); textSize(12); textAlign(LEFT, TOP); let y = readoutY + 12; const x = readoutX + 12; const dy = 18; text('Gas : ' + GASES[gIdx][0], x, y); y += dy; text('rho_gas : ' + nf(rho_g, 1, 4) + ' kg/m^3', x, y); y += dy; text('rho_air : ' + nf(rho_a, 1, 4) + ' kg/m^3', x, y); y += dy; text('V(z) : ' + nf(V_z, 1, 1) + ' m^3', x, y); y += dy; text('m_gas : ' + nf(m_gas, 1, 2) + ' kg', x, y); y += dy; text('m_pay : ' + nf(m_payload, 1, 1) + ' kg', x, y); y += dy; y += 6; fill(F_lift > 0 ? TRAJ : HOT); text('F_lift : ' + nf(F_lift, 1, 1) + ' N', x, y); y += dy; fill(F_net > 0 ? TRAJ : HOT); text('F_net : ' + nf(F_net, 1, 1) + ' N', x, y); y += dy; fill(FG); y += 6; text('z : ' + nf(z_current / 1000, 1, 2) + ' km', x, y); y += dy; text('v_z : ' + nf(v_current, 1, 2) + ' m/s', x, y); y += dy; fill(ACCENT); text('z_eq : ' + (z_eq < 0 ? 'no liftoff' : (z_eq >= Z_MAX ? '> 30 km' : nf(z_eq / 1000, 1, 2) + ' km')), x, y); } // ----- slider labels at the bottom ---------------------------------- function drawSliderLabels(V0, m_payload, speedMult) { noStroke(); fill(...DIM); textSize(11); textAlign(LEFT, BOTTOM); const ySliderLabel = height - 64; text('gas: ' + GASES[gIdx][0], 70, ySliderLabel); text('V_0 = ' + nf(V0, 1, 0) + ' m^3', 220, ySliderLabel); text('m_payload = ' + nf(m_payload, 1, 0) + ' kg', 370, ySliderLabel); text('speed x ' + nf(speedMult, 1, 2), 520, ySliderLabel); } // ----- HUD: title + wikitube subtitle ------------------------------- function drawHUD() { noStroke(); fill(FG); textSize(22); textAlign(LEFT, TOP); text(TITLE, 14, 14); fill(...DIM); textSize(12); text('Wikitube microsim . en.wikitube.io/wiki/' + ARTICLE, 14, 40); // Top-right hint line. fill(...DIM); textSize(11); textAlign(RIGHT, TOP); text('play / pause to launch . reset to ground', width - 14, 16); text('Boyle expansion: V(z) = V_0 * P_0 / P(z)', width - 14, 30); } // ----- bottom-right canonical equation ------------------------------ function drawEquation() { noStroke(); fill(...HOT); textSize(13); textAlign(RIGHT, BOTTOM); text('F_lift = (rho_air - rho_gas) * V * g', width - 14, height - 88); } ``` ## Links (Wikipedia order) <!-- injected from _registry/childlinks/Balloon.json (2026-07-30T02:09:12Z) --> `Aerobot` · `Air_balloon_(disambiguation)` · `Airship` · `Angioplasty` · `Association_of_Science_and_Technology_Centers` · `Atheroma` · `Atmosphere_of_Earth` · `Atmospheric_pressure` · `Balloon_(aeronautics)` · `Balloon_(disambiguation)` · `Balloon_catheter` · `Balloon_drops_at_United_States_presidential_nominating_conventions` · `Balloon_modelling` · `Balloon_popping` · `Balloon_release` · `Balloon_rocket` · `Balloon_tamponade` · `Barrage_balloon` · `Biodegradation` · `Blood_vessel` · `Buoyancy` · `California_Balloon_Law` · `Catheter` · `Convention_(meeting)` · [[Density]] · [[Electric_power_transmission]] · `Finland` · `Flogo` · `Foley_catheter` · `France` · `Gas_balloon` · [[Helium]] · `Helium_atom` · `Helsinki` · `Hevea_brasiliensis` · `High-altitude_balloon` · `Hot_air_balloon` · [[Hydrogen]] · `Italy` · `Jacques_Charles` · `Jewish_Community_Relations_Council` · `Kinetic_energy` · `Latex` · `List_of_balloon_uses` · `List_of_inflatable_manufactured_goods` · `Marine_biology` · `Marine_debris` · `Maryland` · `Michael_Faraday` · `Molecular_diffusion` · `Montgolfier_brothers` · `Mylar_balloon_(geometry)` · `Myocardial_infarction` · `Natural_rubber` · `Nature_reserve` · `Neoprene` · `New_Year's_Eve` · [[Newton's_laws_of_motion]] · `Nitrous_oxide` · `Nylon` · `Observation_balloon` · [[Oxygen]] · `Pig_bladder` · `Pink_Floyd_pigs` · `Plastic` · `Pneumatic_bladder` · `Polymer` · `Potential_energy` · `Practical_joke` · `Pride_parade` · `Proportionality_(mathematics)` · `Pump` · `Radiosonde` · `Rainforest_Alliance` · `Reader's_Digest` · `Recycling` · `Research_balloon` · `Reuse` · `Rockoon` · `Screen_printing` · `Solar_balloon` · `Speech_balloon` · `Sperm_whale` · `Stent` · `Stomach` · `São_Paulo` · `Tethered_balloon` · `Thomas_Hancock_(inventor)` · `Toy_balloon` · `Two-balloon_experiment` · `Uterus` · `Waste_management` · `Water` · `Water_balloon` · `Water_gun` · [[Wayback_Machine]] · `Weather_balloon` · `Wikisource` ## From the vault media library !Balloon thumb.png *Balloon — from the vault's own media holdings, placed 2026-07-09. MTN / Wikitube.io original · CC BY-SA 4.0.* <!-- LOCAL-MEDIA-PASS:END --> > **Room:** [[Helium]] · **Status:** ✅ shipped ## Overview A balloon is a flexible bag inflated with a gas — air, hot air, hydrogen, helium, or another lifting medium — whose envelope volume and contained-gas [[Density|density]] together govern its buoyancy. The first crewed flight, by the Montgolfier brothers in November 1783, used a hot-air balloon; ten days later Jacques Charles flew the first hydrogen balloon, establishing the two architectures still in use today. Balloons fall into three broad classes: toy and decorative balloons (latex or foil), aerostatic vehicles (hot-air sport balloons, gas balloons, blimps, and airships), and scientific or military aerostats (weather radiosondes, stratospheric research platforms, tethered surveillance balloons, and high-altitude pseudo-satellites). The [[Physics|physics]] is governed by Archimedes' principle: net lift equals (ρ_air − ρ_gas) · V · g, so envelope volume and the density contrast with surrounding air determine payload. Helium provides about 93% of hydrogen's lift while being nonflammable, which is why it dominates civil scientific and tethered applications; hot air, with a density contrast set by the ideal-gas law (ρ ∝ 1/T), trades lower lift for cheap, renewable buoyancy. As a balloon ascends, ambient pressure drops, the envelope expands, and either a relief valve vents gas or a superpressure design holds constant volume. Balloons are central to meteorology (~73,000 NWS radiosondes per year), atmospheric [[Science|science]], party and advertising markets, [[Leak|leak]]-testing pressure systems, and emerging stratospheric communications and remote-sensing platforms. ## See also - Room hub: [[Helium]] - p5.js Editor conventions: P5 JS EDITOR - Wiki root: MAIN --- *Scaffolded by `generative-microsim` from row 127 of the Helium sheet on 2026-05-14T12:25:28Z.* <!-- LOCAL-MEDIA-PASS:START --> <!-- CRAFT-LINK:START g12 --> *Built to the [[WT!P5_js_Microsim_Master_Class|p5.js Master Class]].* <!-- CRAFT-LINK:END --> ## Wikipedia : Wikitube **Strict pair:** [Wikipedia](https://en.wikipedia.org/wiki/Balloon) : [Wikitube](https://en.wikitube.io/wiki/Balloon) ## Previous hub tags Tree parents: [[Helium]] · [[Hydrogen]]. Legacy hubs: none. --- *Sources: 1 legacy note. Minted wave 1, 2026-07-30 (v1.6 order).*