Cave Flyer Game — Free HTML CSS JS Snippet

Cave Flyer Game · Games · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Single hold-to-thrust control routed through one flag from a button, the keyboard, and a canvas tap — released on pointerup/cancel/leave so thrust never sticks
Gravity-vs-lift vertical physics: constant acceleration one way or the other with a clamped max velocity, for true hover-by-feathering feel
Procedural cave from recycled vertical slices with a bounded random-walk centre so the tunnel meanders smoothly
Continuously narrowing gap and rising scroll speed as functions of distance flown
Occasional stalactite/stalagmite obstacles jutting into the passage
Cheap collision testing only the single slice under the craft, against ceiling, floor and obstacle
Distance-based live scoring and a persisted best via localStorage with defensive try/catch
Delta-time scaled motion and polygon-traced cave walls, with no assets or dependencies

About this UI Snippet

Cave Flyer — One-Button Thrust Physics and a Procedural Scrolling Cave

Screenshot of the Cave Flyer Game snippet rendered live

The one-button "helicopter" game is a masterclass in doing the most with the least: a single input — hold to go up, release to go down — against an ever-narrowing tunnel. There's no simpler control scheme, which makes it the purest demonstration of hold-to-thrust physics and of the procedural, recycling terrain that an endless side-scroller needs. This snippet builds it on one HTML5 <canvas>: hold the button (or Space, or a tap on the game) to fire the craft's lift, release to let gravity take it, and thread a meandering cave that tightens and accelerates the further you fly.

Hold-to-thrust: gravity versus lift on one axis

The craft only moves vertically, driven by a single boolean. Every frame, if flying is true a negative (upward) LIFT acceleration is added to the velocity; if it's false a positive (downward) GRAV is added instead. The velocity is clamped to MAX_VY and integrated into the position. That's the entire control model — the craft is never *set* to a height, it's constantly accelerating one way or the other, so flying smoothly means feathering the button to hover, exactly like a real helicopter game. Because it's a single flag, the same input works from a hold button, the keyboard, and a press on the canvas without any extra logic.

One input, four surfaces

The flying flag is set true on pointerdown and false on pointerup/pointercancel/pointerleave — bound to the dedicated FLY button, to the canvas itself (so a tap anywhere on the game works), and to Space/↑ on the keyboard. Routing every surface through one setFly() call means the physics never knows or cares where the press came from, and releasing is handled everywhere so the thrust can't get stuck on.

A procedural cave built from recycled slices

The cave is a list of thin vertical *slices*, each storing a ceiling height and a floor height. makeSlice() meanders the cave's centre with a bounded random walk (so the tunnel curves naturally instead of jittering), narrows the vertical gap as distance grows, and occasionally juts a stalactite or stalagmite into the passage. As the world scrolls, slices that pass off the left edge are shifted out of the array and fresh ones pushed on the right — a constant, small number of slices in memory no matter how far you fly. The walls are drawn as two filled polygons traced along the slice tops and bottoms.

Collision, difficulty and persistence

Collision is cheap: only the single slice directly under the craft's fixed x-position is tested, against the ceiling, the floor, and any obstacle in that slice. Both the scroll speed and the cave's narrowing are continuous functions of distance, so the game gets relentlessly harder. The score is distance flown, shown live, and the best persists to localStorage; all motion is delta-time scaled for consistent speed across refresh rates.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS and JS into an AI assistant like Claude and ask it to explain the gravity-vs-lift one-axis physics, the single flying flag shared across button/keyboard/canvas, and the recycling random-walk cave. It is a strong base to extend: ask for collectible fuel or coins in the gap, a cave that occasionally forks into two paths, moving gates you must time, a parallax rock background, or a gentle screen shake on near-misses. You could also ask it to add a difficulty select that tunes gravity and the narrowing rate, or to port the loop into a React component using useRef and useEffect. Treat it as a working prototype to question and rebuild.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a mobile-friendly one-button cave-flying game on an HTML5 canvas in plain HTML, CSS and JavaScript — no frameworks.

Requirements:
- The craft moves only vertically and is controlled by a single hold input: while held, add an upward lift acceleration to its velocity each frame; while released, add a downward gravity acceleration. Clamp the velocity and integrate into position so the feel is analog (feather to hover), not fixed up/down speed.
- Route the single control through one boolean flag set true on press and false on release, bound to a dedicated hold button, to the canvas itself (tap anywhere), AND to Space/Up on the keyboard. Release on pointerup, pointercancel and pointerleave everywhere so thrust never sticks on.
- Generate the cave as a list of thin vertical slices, each with a ceiling and floor height. Meander the cave centre with a bounded random walk so the tunnel curves smoothly, and occasionally add a stalactite/stalagmite obstacle jutting into the gap. As the world scrolls, remove slices off the left and append new ones on the right so memory stays bounded.
- Test collision only against the single slice under the craft's fixed x — ceiling, floor and any obstacle. Make the scroll speed increase and the gap narrow continuously with distance flown.
- Use requestAnimationFrame with delta-time scaling. Score by distance, shown live, and persist the best in localStorage with defensive try/catch. Show start and game-over overlays, and draw the cave walls as filled polygons traced along the slice tops and bottoms.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Start flyingTap "Fly" to call startGame(), which generates the starting cave, places the craft mid-screen, and starts the delta-time loop. The craft immediately begins to fall under gravity.
  2. 2
    Hold to rise, release to fallHold the HOLD TO FLY button — or Space / ↑, or press anywhere on the game — to apply upward thrust; release to let gravity pull the craft down. The craft is always accelerating one way, so feather the button to hover level.
  3. 3
    Thread the caveKeep the craft between the ceiling and the floor. Touching either wall — or an obstacle jutting into the passage — ends the run instantly.
  4. 4
    Watch it narrowThe vertical gap shrinks and the scroll speed rises continuously with distance, so the later cave demands finer control than the open early stretch.
  5. 5
    Dodge the stalactitesOccasional stone spikes jut from the ceiling or floor into the gap. They only occupy one slice, so a small, well-timed altitude change slips past them.
  6. 6
    Beat your distanceThe score is distance flown, shown top-right, and persists in localStorage under cave-flyer-best. Tune GRAV, LIFT, the starting gap and its narrowing rate to change the difficulty.

Real-world uses

Common Use Cases

One-button touch game template
Hold-to-thrust is the minimal mobile control — a reusable template for any single-input game, and a clean example of routing one action through button, key and tap surfaces at once.
Teaching thrust physics and procedural terrain
Gravity-vs-lift integration and a recycling random-walk cave are compact references for two staples of side-scrollers: analog one-axis control and endless generated levels.
Starting point for a fuller flyer
The slice-based cave and thrust physics generalise to collectible fuel, gaps that fork, moving gates, or a parallax background, without touching the delta-time loop.
Instantly playable one-more-try game
A one-button endless flyer is learnable in a second and hard to put down — a strong embeddable demo for a games portal, blog, or app landing page.
Engaging empty-state or 404 filler
With no network dependency it starts instantly as an interactive distraction on an error or loading screen, like the Flap Dodge Game.
Canvas procedural-terrain reference
The random-walk cave centre, slice recycling and polygon-traced walls are directly reusable techniques for any endlessly generated side-scrolling canvas scene.

Got questions?

Frequently Asked Questions

The craft only moves on the vertical axis and is always accelerating: while the button is held, an upward lift acceleration is added to its velocity each frame; while released, a downward gravity acceleration is added instead. The velocity is clamped and integrated into position. Because it is continuous acceleration rather than a fixed up/down speed, tapping and feathering the button lets you hover and make fine adjustments — the same analog feel as a classic helicopter game.

All three surfaces call the same setFly() function that toggles one flying flag — true on press, false on release. The physics reads only that flag and has no idea where the input came from, so a hold button, a tap on the game area, and Space/Up all behave identically. Release is bound on pointerup, pointercancel and pointerleave everywhere, so the thrust can never get stuck on if a finger slides off.

The cave is a list of thin vertical slices, each with a ceiling and floor height. As the world scrolls, slices that move off the left edge are removed from the front of the array and new ones are appended at the right. This keeps a constant, small number of slices in memory regardless of how far you fly, and the new slices are generated on the fly by meandering the cave centre with a bounded random walk.

Two values scale continuously with distance flown: the scroll speed increases, so the cave rushes past faster, and the vertical gap between ceiling and floor shrinks toward a minimum, so there is less room to manoeuvre. Together they make the late cave demand much finer button control than the wide, slow opening stretch, which is what gives a one-button game a difficulty curve.

Yes. The best distance is stored in localStorage under cave-flyer-best and read on load, so it survives reloads and browser restarts on the same browser and origin. The read and write are wrapped in try/catch so the game still runs in sandboxed or private contexts where storage access can throw.