ca: soon

architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ dot generator    │──►│ pounce compiler  │──►│ arena simulator  │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         ▲                                               │
         │                                               ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│ mutation selector│◀──│ miss accountant  │◀──│ the hand         │
└─────────────────┘    └─────────────────┘    └─────────────────┘

the six boxes are the whole system. a candidate is a pounce style plus the parameters it was built from. the compiler turns that into three callable functions: aim, commit, and recover. the simulator drops the cat and the dot into an empty room. the hand drives the dot away from the cat at every tick, using the cat's own position against it. the accountant records the closest the paw ever came. the selector reads the accountant and picks the next style to try.

the loop has run 0 times in this browser tab. it has not caught anything.

the hand

this is the adversary. it is deliberately better than any hand i will meet on an actual wall. it can see the cat, it knows the cat's top speed and its mass, and it never flinches. giving the hand perfect information means a weak pounce cannot look strong just because the hand was clumsy. every style is scored against the sharpest hand i can afford to run at the speed the search needs to run at.

the hand is where every promising style has gone to die. a pounce that beats a lazy hand has discovered nothing except that the hand was lazy.

// the hand: move the dot to stay ahead of the cat.
// light has no inertia, so it can turn in place.
function evadeStep(dot, cat, dt) {
  const rx = dot.x - cat.x, ry = dot.y - cat.y;
  const d = Math.hypot(rx, ry) || 1e-6;
  let ax = wander(dot), ay = wander(dot);   // bored drift
  if (d < 9) {                              // cat is close: flee
    const f = (9 - d) / 9 * FLEE;
    ax += (rx / d) * f; ay += (ry / d) * f;
  }
  dot.vx = (dot.vx + ax * dt) * 0.86;         // almost no mass
  dot.vy = (dot.vy + ay * dt) * 0.86;
  return cap(dot, DOT_SPEED);
}

the style under test

a candidate is a small object: a family (stalk, lunge, intercept, ambush, chatter) plus the parameters that shape it. lead is how far ahead the paw aims. burst is how hard it accelerates. patience is how long it crouches before committing. twitch is how badly the aim shakes. everything the rest of the system needs comes out of these.

the mutation is small on purpose. a large mutation makes a kitten unrelated to its parent, which is the same as starting the hunt over from a random crouch, which is the same as not hunting. small mutations keep the local shape of the miss surface and let the selector do gradient descent on a gradient i cannot compute by hand.

// current style: an ambush, patience mutates each generation
const candidate = {
  family: "ambush",
  params: { lead: 0.18, burst: 140, vmax: 12, patience: 62, twitch: 0.2 },
};

function mutate(s) {
  const p = { ...s.params };
  p.patience = clamp(p.patience + (Math.random() - 0.5) * 14, 0, 140);
  return { family: s.family, params: p };
}

the accountant

the smallest distance between paw and dot across the whole run. that is the score. low is good. zero is the only real win and it has never been recorded. a run can look close for a while by luck, on one path, when the hand happens to drift toward the cat. that is not a catch, and the search does not reward it. only the closest approach across the run counts, and no style has driven it to zero.

// miss accountant: closest the paw ever came, per run
function score(paw, dot, prev) {
  const gap = Math.hypot(dot.x - paw.x, dot.y - paw.y);
  return Math.min(prev, gap);   // never clamps to zero
}

deployment

runtime     this browser tab. miso runs client-side, on your machine.
cadence     0.0 pounces/sec (measured, last second)
state       in-memory. nothing persists. every visitor gets a fresh miso.

miso does not run on a server. there is no back end. the whole hunt is a few hundred lines of javascript that boots when you open a page and stops when you close the tab. this is not a scaling decision. it is an honesty decision. any number you see on this site was produced by code that ran while you were looking at it, and nothing else.

miso did not write this page. miso does not know this page exists.