05 Ledge

Climb an endless tower of ledges while the screen drifts upward. Hold jump longer to leap higher, and don't trust the orange ones.

Controls Arrows or A/D to run, Space / Up / W to jump (hold for higher). Touch: hold to jump and run toward your finger

992 / 1024 bytes · 32 to spare

The 992 bytes that ship
for(_=');`e._,16^.3,ter(p[0]down=e=()keyc.fillText( of g)for(let &&(0)32Math.n[4]]|p[Rect(	` · TAP TO Styl[1]0,onpoinlocalStorag_ledge1kg=[[13155],e,l,t,o,f,n,i,r,T,d,y=random,p=[],h=2,k=+||R==>hn>40||h>1)156,l=142,t=o=n=i=h=;ononup=>_Code]=_type<"u")R,up=mov>{T=0*_offsetX/a.clientWidth,(r=_buttons)R},setInval(=>{n++,"#0b0b10",	18;R=p[3887]|r,S=r?sign(T-e-4|:3968])-3765]`f=h?.6:.4+n/4e3+(l<80?.1*(80-l):,i+=f/1h||((e+2.2*S+%Ro>0t=-6o=,!Rt<-2t=-2),o--,t+=l+=t+fnn+=f,++,!ht>=0e-n[+8)%0<n[2]+8l+8>=nl+8-n<t+f+1l=n-8,t=o=6,n[3]!=1)`g=g.fil(>e<190e[4]<41`(d=g[g.length-1])>-20;)g.push([(d[+160*y+24%d-28-18*y,5y<ed of[)e[3]?"#ff9f43":"#b38cff",	e[-d,e,e[2],4`"#e9e7df",h<2	e,l,8,8),!hl>180h=1,n==k=max(k,0|i)),hh>1?"LEDGESTART":"FELLRETRY"^64),(0|i)+"  HI "+k^2}^)';G=/[-^-`]/.exec(_);)with(_.split(G))_=join(shift());eval(_)
Readable source
// LEDGE: climb auto-scrolling ledges. Hold jump = higher. Orange ledges crumble.
let R = Math.random, k = [], x, y, v, gr, dy, ls = [[130, 150, 50, 0, 0]], t, sc, pd, tx, q;
let dead = 2, best = +localStorage.ledge1k || 0;

// ledge = [x, y, width, crumbles, crumble timer]
// start / restart on any press
let go = () => dead && (t > 40 || dead > 1) && (ls = [[130, 150, 50, 0, 0]], x = 156, y = 142, v = gr = t = sc = dead = 0);

onkeydown = onkeyup = e => (k[e.keyCode] = e.type < 'keyu') && go();
// touch/mouse: buttons = held, tx = finger x
onpointerup = onpointerdown = onpointermove = e => {
  tx = e.offsetX * 320 / a.clientWidth;
  (pd = e.buttons) && go();
};

setInterval(() => {
  t++;
  c.fillStyle = '#0b0b10';
  c.fillRect(0, 0, 320, 180);

  // keys, or touch: run toward finger and jump while held
  let J = k[32] | k[38] | k[87] | pd;
  let dir = pd ? Math.sign(tx - x - 4 | 0) : (k[39] | k[68]) - (k[37] | k[65]);

  // scroll speed rises; extra push when player is high
  dy = dead ? .6 : .4 + t / 4000 + (y < 80 ? (80 - y) * .1 : 0);
  sc += dy / 10;
  if (!dead) {
    x = (x + dir * 2.2 + 320) % 320;
    if (J && gr > 0) v = -6.3, gr = 0;
    if (!J && v < -2) v = -2; // released early: short hop
    gr--;
    v += .3;
    y += v + dy;
  }
  for (let l of ls) {
    l[1] += dy;
    l[4] && l[4]++;
    // land from above (wraps horizontally)
    if (!dead && v >= 0 && (x - l[0] + 328) % 320 < l[2] + 8 && y + 8 >= l[1] && y + 8 - l[1] < v + dy + 1)
      y = l[1] - 8, v = 0, gr = 6, l[3] && !l[4] && (l[4] = 1);
  }
  ls = ls.filter(l => l[1] < 190 && l[4] < 41);
  // spawn: rise <= 46 (max jump 66), sideways gap <= 30 (air reach ~80)
  while ((q = ls[ls.length - 1])[1] > -20)
    ls.push([(q[0] + R() * 160 + 240) % 320, q[1] - 28 - R() * 18, 50, R() < .3, 0]);

  for (let l of ls)
    for (q of [0, 320])
      c.fillStyle = l[3] ? '#ff9f43' : '#b38cff',
      c.fillRect(l[0] - q, l[1], l[2], 4);

  c.fillStyle = '#e9e7df';
  if (dead < 2) c.fillRect(x, y, 8, 8);
  if (!dead && y > 180) {
    dead = 1; t = 0;
    localStorage.ledge1k = best = Math.max(best, sc | 0);
  }
  if (dead) c.fillText(dead > 1 ? 'LEDGE · TAP TO START' : 'FELL · TAP TO RETRY', 160, 64);
  c.fillText((sc | 0) + '  HI ' + best, 160, 20);
}, 16);