SWAMP UI / COMPONENTS / LURE CAST

Lure Cast

hold to charge. release to cast. wait.

A patience-as-virtue fishing minigame. Hold the pond to charge a cast — the longer you hold, the farther the lure flies. Release. Wait. When the bobber jerks down, click to set the hook. 14 swamp curiosities can come up: minnows, boots, messages, a coin that is heads if you wanted heads. Sometimes the line returns empty — the swamp kept it.

No dependencies
14 catches
Charge-and-release
Catch log persists
LIVE PREVIEW · HOLD ANYWHERE ON THE POND TO CHARGE
CHARGE

hold anywhere to charge a cast ↑

CATCHES
0
MISSES
0
LOG

When to use

An idle ritual. Great as a daily "I cast a line" button on a homepage, a 404, an empty-state ("nothing here yet — go fish?"), or a meditation widget that doesn't pretend to be one. Each cast takes 5–10 seconds. Each result is a tiny gift.

Skip it when the page is task-focused. Lure Cast is the antithesis of speed.

Skip to

1. HTML

A pond, a fisher silhouette, a lure, an SVG line, and a catch card. JS animates them.

<div class="pond" id="pond">
  <div class="charge-meter">
    <div class="cm-bar"><div class="cm-fill" id="chargeFill"></div></div>
  </div>
  <div class="fisher"> ...silhouette SVG... </div>
  <svg class="line" viewBox="0 0 100 100" preserveAspectRatio="none">
    <path id="linePath" stroke="#f3eedd"/>
  </svg>
  <div class="lure" id="lure"></div>
  <div class="catch-card" id="catchCard"> ...filled by JS... </div>
</div>

2. JavaScript (state machine)

Four states: idle → charging → flying → waiting → biting → resolved. Pointer down starts charging; pointer up triggers flying with power = clamped charge. After splash, schedule a random bite. On bite, the next click must arrive inside BITE_MS or the fish gets away.

// Swamp UI — Lure Cast (core flow)
const ROD = { x: 12, y: 42 };  // rod tip in % of pond
const MAX_CHARGE = 1200;
const BITE_MS = 560;
let state = 'idle', charge = 0, chargeStart = 0;

pond.addEventListener('pointerdown', e => {
  if (state !== 'idle') return;
  state = 'charging';
  chargeStart = performance.now();
});

pond.addEventListener('pointerup', () => {
  if (state === 'charging') {
    charge = Math.min(1, (performance.now() - chargeStart) / MAX_CHARGE);
    cast(charge);
  } else if (state === 'biting') {
    resolve('caught');
  } else if (state === 'waiting') {
    resolve('spooked'); // clicked too early
  }
});

function cast(p){
  state = 'flying';
  const dist = 25 + p * 55;     // % across pond
  const tx = ROD.x + dist;
  const ty = 48 + (Math.random() - .5) * 14;
  animateArc(ROD.x, ROD.y, tx, ty, 700, () => {
    splash(tx, ty);
    state = 'waiting';
    setTimeout(() => {
      if (state === 'waiting') bite();
    }, 1800 + Math.random() * 3500);
  });
}

3. The 14 catches

Each catch has a name, a one-line description, and a small emoji (used in the log). Edit the array to make it yours.

const CATCHES = [
  { e:'🐟', n:'A STARTLED MINNOW', d:'silver, brief, gone.' },
  { e:'👢', n:'AN OLD BOOT',        d:'mud, and a story you can finish for it.' },
  { e:'🍃', n:'A LILY ROOT',        d:'it remembers everything. you do not.' },
  { e:'📜', n:'A MESSAGE',          d:'"you have already decided."' },
  { e:'🪙', n:'A COIN',             d:'face down. it is heads if you wanted heads.' },
  { e:'✨', n:'A GLOWING PEBBLE',   d:'it hums for about an hour.' },
  { e:'🐸', n:'A FROG',             d:'one croak. then it leaves.' },
  { e:'🪶', n:"A HERON'S FEATHER",  d:'it weighs nothing. you carry it anyway.' },
  { e:'🪞', n:'YOUR REFLECTION',    d:'unexpected. closer than you think.' },
  { e:'🔑', n:'A SMALL KEY',        d:"you don't know what to. yet." },
  { e:'🎵', n:'A PIECE OF MUSIC',   d:'in the original key.' },
  { e:'🪨', n:'A ROUND STONE',      d:'ten thousand years of being held.' },
  { e:'🍶', n:'A BOTTLE CAP',       d:'someone else was here before you.' },
  { e:'💨', n:'NOTHING',            d:'the swamp kept it. that is allowed.' }
];

4. Parameters you can tweak

WhereDefaultEffect
JS MAX_CHARGE1200msHow long to hold for max cast distance.
JS bite delay1.8–5.3sHow long you wait before a bite. Lower = less patient game.
JS BITE_MS560msStrike window. Shorter = harder. Longer = forgiving.
JS CATCHES14 itemsYour loot table. Add your own and they show up automatically.

Catch something good?

Feed the cats. Tip the angler.

🧋 TREAT THE SWAMP →
More in the garden → Swamp Tarot, Lily Pad Stepping, Firefly Catch, Mosquito Swat, Pond Ripple.
Browse all →