← back to jjzh__Iso_Shooter

Function bodies 653 total

All specs Real LLM only Function bodies
behaviorKite function · javascript · L577-L698 (122 LOC)
entities/enemy.js
function behaviorKite(enemy, playerPos, dt, gameState) {
  _toPlayer.subVectors(playerPos, enemy.pos);
  _toPlayer.y = 0;
  const dist = _toPlayer.length();
  const kite = enemy.config.kite || {};
  const sniper = enemy.config.sniper || {};
  const preferredRange = enemy.config.attackRange * (kite.preferredRangeMult || 0.7);

  const isTelegraphing = enemy.sniperPhase === 'telegraphing';

  // Movement: maintain preferred range (freeze during telegraph — lining up the shot)
  if (!isTelegraphing) {
    const slideBoost = enemy.wasDeflected ? 1.175 : 1.0;
    const iceEffects = getIceEffects(enemy.pos.x, enemy.pos.z, false);
    const speed = enemy.config.speed * (enemy.slowTimer > 0 ? enemy.slowMult : 1) * slideBoost * iceEffects.speedMult;
    if (dist < preferredRange - (kite.retreatBuffer || 1)) {
      // Too close — retreat (pit-aware)
      _toPlayer.normalize();
      const retreat = pitAwareDir(enemy.pos.x, enemy.pos.z, -_toPlayer.x, -_toPlayer.z, 2.5);
      enemy.pos.x += ret
behaviorMortar function · javascript · L701-L832 (132 LOC)
entities/enemy.js
function behaviorMortar(enemy, playerPos, dt, gameState) {
  _toPlayer.subVectors(playerPos, enemy.pos);
  _toPlayer.y = 0;
  const dist = _toPlayer.length();
  const kite = enemy.config.kite || {};
  const mortar = enemy.config.mortar || {};
  const preferredRange = enemy.config.attackRange * (kite.preferredRangeMult || 0.65);

  const isAiming = enemy.mortarPhase === 'aiming';

  // Movement: kite like an archer (freeze during aim to line up the shot, pit-aware)
  if (!isAiming) {
    const slideBoost = enemy.wasDeflected ? 1.175 : 1.0;
    const iceEffects = getIceEffects(enemy.pos.x, enemy.pos.z, false);
    const speed = enemy.config.speed * (enemy.slowTimer > 0 ? enemy.slowMult : 1) * slideBoost * iceEffects.speedMult;
    if (dist < preferredRange - (kite.retreatBuffer || 1.5)) {
      _toPlayer.normalize();
      const retreat = pitAwareDir(enemy.pos.x, enemy.pos.z, -_toPlayer.x, -_toPlayer.z, 2.5);
      enemy.pos.x += retreat.dx * speed * dt;
      enemy.pos.z += retreat.dz *
createMortarArcLine function · javascript · L839-L864 (26 LOC)
entities/enemy.js
function createMortarArcLine(enemy) {
  if (!_arcLineGeo) {
    const positions = new Float32Array((ARC_SEGMENTS + 1) * 3);
    _arcLineGeo = new THREE.BufferGeometry();
    _arcLineGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
  }

  // Clone geometry so each enemy gets its own buffer
  const geo = _arcLineGeo.clone();
  geo.setAttribute('position', new THREE.BufferAttribute(
    new Float32Array((ARC_SEGMENTS + 1) * 3), 3
  ));

  const mat = new THREE.LineBasicMaterial({
    color: enemy.config.mortar?.color || 0xff6622,
    transparent: true,
    opacity: 0.6,
    depthWrite: false,
  });

  const line = new THREE.Line(geo, mat);
  sceneRef.add(line);
  enemy.mortarArcLine = line;

  updateMortarArcLine(enemy);
}
updateMortarArcLine function · javascript · L866-L892 (27 LOC)
entities/enemy.js
function updateMortarArcLine(enemy) {
  if (!enemy.mortarArcLine) return;
  const mortar = enemy.config.mortar || {};
  const sx = enemy.pos.x;
  const sz = enemy.pos.z;
  const tx = enemy.mortarTarget.x;
  const tz = enemy.mortarTarget.z;
  const arcH = mortar.arcHeight || 6;
  const startY = 0.8; // launch from body height

  const positions = enemy.mortarArcLine.geometry.attributes.position.array;
  for (let i = 0; i <= ARC_SEGMENTS; i++) {
    const t = i / ARC_SEGMENTS;
    const x = sx + (tx - sx) * t;
    const z = sz + (tz - sz) * t;
    // Parabolic arc: y = startY + 4*arcH*t*(1-t) gives a nice arc peaking at arcH
    const y = startY + 4 * arcH * t * (1 - t);
    positions[i * 3] = x;
    positions[i * 3 + 1] = y;
    positions[i * 3 + 2] = z;
  }
  enemy.mortarArcLine.geometry.attributes.position.needsUpdate = true;

  // Pulse opacity for telegraph effect
  const pulse = 0.3 + 0.3 * Math.sin(performance.now() * 0.008);
  enemy.mortarArcLine.material.opacity = pulse;
}
removeMortarArcLine function · javascript · L894-L901 (8 LOC)
entities/enemy.js
function removeMortarArcLine(enemy) {
  if (enemy.mortarArcLine) {
    enemy.mortarArcLine.geometry.dispose();
    enemy.mortarArcLine.material.dispose();
    sceneRef.remove(enemy.mortarArcLine);
    enemy.mortarArcLine = null;
  }
}
createMortarGroundCircle function · javascript · L907-L961 (55 LOC)
entities/enemy.js
function createMortarGroundCircle(enemy) {
  const mortar = enemy.config.mortar || {};
  const radius = mortar.blastRadius || 2.5;
  const color = mortar.color || 0xff6622;

  // Shared ring geometry (unit scale, scaled per instance)
  if (!_circleGeo) {
    _circleGeo = new THREE.RingGeometry(0.85, 1.0, 32);
    _circleGeo.rotateX(-Math.PI / 2);
  }

  // Ring outline
  const ringMat = new THREE.MeshBasicMaterial({
    color: color,
    transparent: true,
    opacity: 0.3,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  const ringMesh = new THREE.Mesh(_circleGeo, ringMat);

  // Filled disc for area indication (shared geometry)
  if (!_mortarFillGeoShared) {
    _mortarFillGeoShared = new THREE.CircleGeometry(1, 32);
    _mortarFillGeoShared.rotateX(-Math.PI / 2);
  }
  const fillMat = new THREE.MeshBasicMaterial({
    color: color,
    transparent: true,
    opacity: 0.08,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  const fillMesh = new THREE.Mesh(_mortarFil
removeMortarGroundCircle function · javascript · L963-L972 (10 LOC)
entities/enemy.js
function removeMortarGroundCircle(enemy) {
  if (enemy.mortarGroundCircle) {
    const gc = enemy.mortarGroundCircle;
    gc.ringMat.dispose();
    gc.fillMat.dispose();
    // geometry is shared — don't dispose
    sceneRef.remove(gc.group);
    enemy.mortarGroundCircle = null;
  }
}
Want this analysis on your repo? https://repobility.com/scan/
createDeathTelegraph function · javascript · L978-L1027 (50 LOC)
entities/enemy.js
function createDeathTelegraph(enemy) {
  const cfg = enemy.config.deathExplosion;
  const radius = cfg.radius;
  const color = cfg.color;

  // Shared ring geometry (unit scale)
  if (!_deathCircleGeo) {
    _deathCircleGeo = new THREE.RingGeometry(0.85, 1.0, 32);
    _deathCircleGeo.rotateX(-Math.PI / 2);
  }

  // Ring outline
  const ringMat = new THREE.MeshBasicMaterial({
    color: color,
    transparent: true,
    opacity: 0.5,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  const ringMesh = new THREE.Mesh(_deathCircleGeo, ringMat);

  // Filled disc (shared geometry)
  if (!_deathFillGeoShared) {
    _deathFillGeoShared = new THREE.CircleGeometry(1, 32);
    _deathFillGeoShared.rotateX(-Math.PI / 2);
  }
  const fillMat = new THREE.MeshBasicMaterial({
    color: color,
    transparent: true,
    opacity: 0.12,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  const fillMesh = new THREE.Mesh(_deathFillGeoShared, fillMat);

  const group = new THREE.Group();
  
updateDeathTelegraph function · javascript · L1029-L1049 (21 LOC)
entities/enemy.js
function updateDeathTelegraph(enemy, dt) {
  const tg = enemy.deathTelegraph;
  if (!tg) return;

  const cfg = enemy.config.deathExplosion;
  const duration = (cfg.telegraphDuration || 200) / 1000;
  const elapsed = (cfg.telegraphDuration - enemy.deathTimer) / 1000;
  const t = Math.min(elapsed / duration, 1);

  // Scale from tiny to target radius
  const scale = tg.targetRadius * t;
  tg.group.scale.set(scale, scale, scale);

  // Follow the enemy position (can be pushed)
  tg.group.position.set(enemy.pos.x, 0.05, enemy.pos.z);

  // Pulsing opacity on ring
  const pulse = 0.5 + 0.3 * Math.sin(performance.now() * 0.02);
  tg.ringMat.opacity = pulse;
  tg.fillMat.opacity = 0.12 + 0.08 * t;
}
removeDeathTelegraph function · javascript · L1051-L1059 (9 LOC)
entities/enemy.js
function removeDeathTelegraph(enemy) {
  const tg = enemy.deathTelegraph;
  if (!tg) return;
  tg.ringMat.dispose();
  tg.fillMat.dispose();
  // geometry is shared — don't dispose
  sceneRef.remove(tg.group);
  enemy.deathTelegraph = null;
}
onDeathExplosion function · javascript · L1063-L1107 (45 LOC)
entities/enemy.js
function onDeathExplosion(enemy, gameState) {
  const cfg = enemy.config.deathExplosion;
  const x = enemy.pos.x;
  const z = enemy.pos.z;

  // Screen shake
  screenShake(5, 250);

  // Show "BOOM" text on dying enemy
  const colorStr = '#' + cfg.color.toString(16).padStart(6, '0');
  spawnDamageNumber(x, z, 'BOOM', colorStr);

  // AoE effect — damages nearby enemies with cascade visual
  applyAoeEffect({
    x,
    z,
    radius: cfg.radius,
    durationMs: cfg.ringDuration || 400,
    color: cfg.color,
    label: cfg.damage + '',
    effectFn: (e) => {
      e.health -= cfg.damage;
      if (cfg.stunDuration > 0) {
        stunEnemy(e, cfg.stunDuration);
      }
    },
    gameState,
    excludeEnemy: enemy, // exclude the dying enemy itself
  });

  // Check player damage
  const pp = getPlayerPos();
  const pdx = pp.x - x;
  const pdz = pp.z - z;
  const playerDist = Math.sqrt(pdx * pdx + pdz * pdz);
  if (playerDist < cfg.radius && !isPlayerInvincible()) {
    gameState.playerHe
behaviorTank function · javascript · L1109-L1167 (59 LOC)
entities/enemy.js
function behaviorTank(enemy, playerPos, dt) {
  const tank = enemy.config.tank || {};
  _toPlayer.subVectors(playerPos, enemy.pos);
  _toPlayer.y = 0;
  const dist = _toPlayer.length();

  const slowFactor = enemy.slowTimer > 0 ? enemy.slowMult : 1;
  const slideBoost = enemy.wasDeflected ? 1.175 : 1.0;
  const iceEffects = getIceEffects(enemy.pos.x, enemy.pos.z, false);
  if (enemy.isCharging) {
    // Charge forward at multiplied speed
    const speedMult = tank.chargeSpeedMult || 3;
    enemy.pos.x += enemy.chargeDir.x * enemy.config.speed * speedMult * slowFactor * slideBoost * iceEffects.speedMult * dt;
    enemy.pos.z += enemy.chargeDir.z * enemy.config.speed * speedMult * slowFactor * slideBoost * iceEffects.speedMult * dt;
    enemy.chargeTimer -= dt * 1000;

    if (enemy.chargeTimer <= 0) {
      enemy.isCharging = false;
      const cdMin = tank.chargeCooldownMin || 3000;
      const cdMax = tank.chargeCooldownMax || 5000;
      enemy.chargeCooldown = cdMin + Math.random() *
stunEnemy function · javascript · L1174-L1188 (15 LOC)
entities/enemy.js
export function stunEnemy(enemy, durationMs) {
  enemy.stunTimer = durationMs;
  // Cancel any active charge
  enemy.isCharging = false;
  // Cancel sniper telegraph (shot will still fire visually but enemy resets state)
  if (enemy.sniperPhase === 'telegraphing') {
    enemy.sniperPhase = 'idle';
  }
  // Cancel mortar aim
  if (enemy.mortarPhase === 'aiming') {
    enemy.mortarPhase = 'idle';
    removeMortarArcLine(enemy);
    removeMortarGroundCircle(enemy);
  }
}
stunEnemiesInRadius function · javascript · L1190-L1199 (10 LOC)
entities/enemy.js
export function stunEnemiesInRadius(centerPos, radius, durationMs, gameState) {
  const r2 = radius * radius;
  for (const enemy of gameState.enemies) {
    const dx = enemy.pos.x - centerPos.x;
    const dz = enemy.pos.z - centerPos.z;
    if (dx * dx + dz * dz < r2) {
      stunEnemy(enemy, durationMs);
    }
  }
}
clearEnemies function · javascript · L1201-L1220 (20 LOC)
entities/enemy.js
export function clearEnemies(gameState) {
  for (const enemy of gameState.enemies) {
    // Clean up shield mesh if present
    if (enemy.shieldMesh) {
      enemy.shieldMesh.geometry.dispose();
      enemy.shieldMesh.material.dispose();
    }
    // Clean up mortar visuals
    removeMortarArcLine(enemy);
    removeMortarGroundCircle(enemy);
    // Clean up death telegraph if active
    removeDeathTelegraph(enemy);
    sceneRef.remove(enemy.mesh);
  }
  gameState.enemies.length = 0;

  // Invalidate cached bounds (level editor may have changed arena)
  _collisionBounds = null;
  _pitBoundsCache = null;
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
fireMortarProjectile function · javascript · L48-L116 (69 LOC)
entities/mortarProjectile.js
export function fireMortarProjectile(opts) {
  if (!shellGeo) {
    shellGeo = new THREE.SphereGeometry(0.15, 6, 4);
  }

  const mat = new THREE.MeshStandardMaterial({
    color: opts.color,
    emissive: opts.color,
    emissiveIntensity: 0.8,
  });

  const mesh = new THREE.Mesh(shellGeo, mat);
  mesh.position.set(opts.startX, 0.8, opts.startZ);
  sceneRef.add(mesh);

  // Create a glowing trail line behind the projectile
  const trailPositions = new Float32Array(30 * 3); // 30-point trail
  const trailGeo = new THREE.BufferGeometry();
  trailGeo.setAttribute('position', new THREE.BufferAttribute(trailPositions, 3));
  const trailMat = new THREE.LineBasicMaterial({
    color: opts.color,
    transparent: true,
    opacity: 0.5,
    depthWrite: false,
  });
  const trail = new THREE.Line(trailGeo, trailMat);
  sceneRef.add(trail);

  // Calculate arc distance and total flight time
  const dx = opts.targetX - opts.startX;
  const dz = opts.targetZ - opts.startZ;
  const groundDist = M
updateMortarProjectiles function · javascript · L122-L177 (56 LOC)
entities/mortarProjectile.js
export function updateMortarProjectiles(dt) {
  for (let i = activeMortars.length - 1; i >= 0; i--) {
    const m = activeMortars[i];
    m.elapsed += dt;
    const t = Math.min(m.elapsed / m.flightTime, 1);

    // Interpolate position along parabolic arc
    const x = m.startX + (m.targetX - m.startX) * t;
    const z = m.startZ + (m.targetZ - m.startZ) * t;
    const y = 0.8 + 4 * m.arcHeight * t * (1 - t); // parabolic arc

    m.mesh.position.set(x, y, z);

    // Pulse glow
    const pulse = 0.6 + 0.4 * Math.sin(performance.now() * 0.01);
    m.mat.emissiveIntensity = pulse;

    // Update trail
    m.trailHistory.push({ x, y, z });
    if (m.trailHistory.length > 30) m.trailHistory.shift();

    const positions = m.trailGeo.attributes.position.array;
    for (let j = 0; j < 30; j++) {
      const idx = j < m.trailHistory.length ? j : m.trailHistory.length - 1;
      const p = m.trailHistory[idx];
      positions[j * 3] = p.x;
      positions[j * 3 + 1] = p.y;
      positions[j *
onMortarImpact function · javascript · L182-L224 (43 LOC)
entities/mortarProjectile.js
function onMortarImpact(m) {
  const tx = m.targetX;
  const tz = m.targetZ;

  // Screen shake on impact
  screenShake(3, 150);

  // AoE effect — damages and slows all enemies in blast radius
  applyAoeEffect({
    x: tx,
    z: tz,
    radius: m.blastRadius,
    durationMs: m.explosionDuration,
    color: m.color,
    label: 'SLOWED',
    effectFn: (e) => {
      e.health -= m.damage;
      slowEnemy(e, m.slowDuration, m.slowMult);
    },
    gameState: m.gameState,
    excludeEnemy: m.sourceEnemy,
  });

  // Check player damage
  const pp = getPlayerPos();
  const pdx = pp.x - tx;
  const pdz = pp.z - tz;
  const playerDist = Math.sqrt(pdx * pdx + pdz * pdz);
  if (playerDist < m.blastRadius && !isPlayerInvincible()) {
    m.gameState.playerHealth -= m.damage;
    screenShake(4, 200);
    spawnDamageNumber(pp.x, pp.z, m.damage, '#ff4466');
    if (m.gameState.playerHealth <= 0) {
      m.gameState.playerHealth = 0;
      m.gameState.phase = 'gameOver';
    }
  }

  // Create ice p
createIcePatch function · javascript · L229-L263 (35 LOC)
entities/mortarProjectile.js
function createIcePatch(x, z, radius, config) {
  // Create visual ice patch (flat circle on ground)
  const geo = new THREE.CircleGeometry(radius, 32);
  geo.rotateX(-Math.PI / 2); // lay flat

  const mat = new THREE.MeshBasicMaterial({
    color: config.color || 0x80E0FF,
    transparent: true,
    opacity: 0.5,
    side: THREE.DoubleSide,
    depthWrite: false,
  });

  const mesh = new THREE.Mesh(geo, mat);
  mesh.position.set(x, 0.02, z); // slightly above ground to avoid z-fighting
  sceneRef.add(mesh);

  const patch = {
    x,
    z,
    radius,
    mesh,
    mat,
    geo,
    duration: config.duration,
    elapsed: 0,
    speedMult: config.speedMult,
    knockbackMult: config.knockbackMult,
    affectsPlayer: config.affectsPlayer,
    affectsEnemies: config.affectsEnemies,
  };

  activeIcePatches.push(patch);
  return patch;
}
updateIcePatches function · javascript · L268-L287 (20 LOC)
entities/mortarProjectile.js
export function updateIcePatches(dt) {
  for (let i = activeIcePatches.length - 1; i >= 0; i--) {
    const patch = activeIcePatches[i];
    patch.elapsed += dt * 1000;

    // Fade out in last 500ms
    const remaining = patch.duration - patch.elapsed;
    if (remaining < 500) {
      patch.mat.opacity = 0.5 * (remaining / 500);
    }

    // Remove when expired
    if (patch.elapsed >= patch.duration) {
      patch.geo.dispose();
      patch.mat.dispose();
      sceneRef.remove(patch.mesh);
      activeIcePatches.splice(i, 1);
    }
  }
}
getIcePatchAt function · javascript · L293-L303 (11 LOC)
entities/mortarProjectile.js
export function getIcePatchAt(x, z) {
  for (const patch of activeIcePatches) {
    const dx = x - patch.x;
    const dz = z - patch.z;
    const dist = Math.sqrt(dx * dx + dz * dz);
    if (dist <= patch.radius) {
      return patch;
    }
  }
  return null;
}
getIceEffects function · javascript · L312-L330 (19 LOC)
entities/mortarProjectile.js
export function getIceEffects(x, z, isPlayer) {
  const patch = getIcePatchAt(x, z);
  if (!patch) {
    return { speedMult: 1.0, knockbackMult: 1.0 };
  }

  // Check if this entity type is affected
  if (isPlayer && !patch.affectsPlayer) {
    return { speedMult: 1.0, knockbackMult: 1.0 };
  }
  if (!isPlayer && !patch.affectsEnemies) {
    return { speedMult: 1.0, knockbackMult: 1.0 };
  }

  return {
    speedMult: patch.speedMult,
    knockbackMult: patch.knockbackMult,
  };
}
removeMortar function · javascript · L335-L349 (15 LOC)
entities/mortarProjectile.js
function removeMortar(m) {
  m.mat.dispose();
  sceneRef.remove(m.mesh);
  m.trailGeo.dispose();
  m.trailMat.dispose();
  sceneRef.remove(m.trail);
  // Clean up ground circle (geometry is shared — don't dispose)
  if (m.groundCircle) {
    const gc = m.groundCircle;
    gc.ringMat.dispose();
    gc.fillMat.dispose();
    sceneRef.remove(gc.group);
    m.groundCircle = null;
  }
}
Repobility · open methodology · https://repobility.com/research/
clearMortarProjectiles function · javascript · L354-L359 (6 LOC)
entities/mortarProjectile.js
export function clearMortarProjectiles() {
  for (const m of activeMortars) {
    removeMortar(m);
  }
  activeMortars.length = 0;
}
clearIcePatches function · javascript · L364-L371 (8 LOC)
entities/mortarProjectile.js
export function clearIcePatches() {
  for (const patch of activeIcePatches) {
    patch.geo.dispose();
    patch.mat.dispose();
    sceneRef.remove(patch.mesh);
  }
  activeIcePatches.length = 0;
}
createPlayer function · javascript · L51-L90 (40 LOC)
entities/player.js
export function createPlayer(scene) {
  playerGroup = new THREE.Group();

  body = new THREE.Mesh(
    new THREE.CylinderGeometry(PLAYER.size.radius, PLAYER.size.radius + 0.05, PLAYER.size.height * 0.6, 8),
    new THREE.MeshStandardMaterial({
      color: 0x44cc88,
      emissive: BODY_EMISSIVE,
      emissiveIntensity: 0.4
    })
  );
  body.position.y = 0.7;
  playerGroup.add(body);

  head = new THREE.Mesh(
    new THREE.SphereGeometry(PLAYER.size.radius * 0.85, 8, 6),
    new THREE.MeshStandardMaterial({
      color: 0x55ddaa,
      emissive: HEAD_EMISSIVE,
      emissiveIntensity: 0.5
    })
  );
  head.position.y = 1.45;
  playerGroup.add(head);

  aimIndicator = new THREE.Mesh(
    new THREE.ConeGeometry(0.12, 0.6, 4),
    new THREE.MeshStandardMaterial({
      color: 0x44ff88,
      emissive: 0x44ff88,
      emissiveIntensity: 0.8
    })
  );
  aimIndicator.rotation.x = -Math.PI / 2;
  aimIndicator.position.set(0, 0.8, -0.7);
  playerGroup.add(aimIndicator);

  scene.add(playe
updatePlayer function · javascript · L92-L178 (87 LOC)
entities/player.js
export function updatePlayer(inputState, dt, gameState) {
  const now = performance.now();

  // Tick ability cooldowns
  for (const key of Object.keys(gameState.abilities)) {
    if (gameState.abilities[key].cooldownRemaining > 0) {
      gameState.abilities[key].cooldownRemaining -= dt * 1000;
    }
  }

  // Tick charge system
  if (isCharging) {
    updateCharge(inputState, dt, gameState);
  }

  // End lag (post-dash lockout)
  if (endLagTimer > 0) {
    endLagTimer -= dt * 1000;
    // During end lag, don't process movement or abilities
    playerGroup.position.copy(playerPos);
    updateAfterimages(dt);
    return;
  }

  // === DASH ===
  if (isDashing) {
    updateDash(dt, gameState);
    playerGroup.position.copy(playerPos);

    // Aim still tracks cursor during dash
    aimAtCursor(inputState);

    updateAfterimages(dt);
    return;
  }

  // Trigger dash
  if (inputState.dash && gameState.abilities.dash.cooldownRemaining <= 0) {
    startDash(inputState, gameState);
  }

aimAtCursor function · javascript · L180-L186 (7 LOC)
entities/player.js
function aimAtCursor(inputState) {
  const dx = inputState.aimWorldPos.x - playerPos.x;
  const dz = inputState.aimWorldPos.z - playerPos.z;
  if (dx * dx + dz * dz > 0.01) {
    playerGroup.rotation.y = Math.atan2(-dx, -dz);
  }
}
startDash function · javascript · L189-L228 (40 LOC)
entities/player.js
function startDash(inputState, gameState) {
  const cfg = ABILITIES.dash;
  isDashing = true;
  dashTimer = 0;
  dashDuration = cfg.duration;
  dashDistance = cfg.distance;
  dashStartPos.copy(playerPos);

  // Direction source — drag-to-aim override takes priority (mobile buttons)
  const override = getAbilityDirOverride();
  const hasMovement = Math.abs(inputState.moveX) > 0.01 || Math.abs(inputState.moveZ) > 0.01;

  if (override) {
    dashDir.set(override.x, 0, override.z).normalize();
    clearAbilityDirOverride();
  } else if (cfg.directionSource === 'movement' && hasMovement) {
    dashDir.set(inputState.moveX, 0, inputState.moveZ).normalize();
  } else if (cfg.directionSource === 'aim') {
    dashDir.set(
      inputState.aimWorldPos.x - playerPos.x, 0,
      inputState.aimWorldPos.z - playerPos.z
    ).normalize();
  } else {
    // 'movementOrAim' or fallback
    if (hasMovement) {
      dashDir.set(inputState.moveX, 0, inputState.moveZ).normalize();
    } else {
      dashD
updateDash function · javascript · L230-L272 (43 LOC)
entities/player.js
function updateDash(dt, gameState) {
  const cfg = ABILITIES.dash;
  dashTimer += dt * 1000;
  const t = Math.min(dashTimer / dashDuration, 1.0);

  // Easing
  let easedT;
  switch (cfg.curve) {
    case 'easeOut':   easedT = 1 - (1 - t) * (1 - t); break;
    case 'easeIn':    easedT = t * t; break;
    case 'easeInOut': easedT = t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2; break;
    default:          easedT = t;
  }

  // Position along dash path
  playerPos.copy(dashStartPos);
  playerPos.x += dashDir.x * dashDistance * easedT;
  playerPos.z += dashDir.z * dashDistance * easedT;

  // Arena clamp during dash
  playerPos.x = Math.max(-19.5, Math.min(19.5, playerPos.x));
  playerPos.z = Math.max(-19.5, Math.min(19.5, playerPos.z));

  // I-frame window
  isInvincible = cfg.invincible && (dashTimer >= cfg.iFrameStart && dashTimer <= cfg.iFrameEnd);

  // Spawn afterimages at intervals
  if (cfg.afterimageCount > 0) {
    const interval = dashDuration / (cfg.afterimageCount +
spawnAfterimage function · javascript · L274-L310 (37 LOC)
entities/player.js
function spawnAfterimage(cfg) {
  const scene = getScene();
  const ghost = new THREE.Group();

  // Simplified ghost — body and head silhouettes (shared geometry)
  if (!_playerGhostBodyGeo) {
    _playerGhostBodyGeo = new THREE.CylinderGeometry(PLAYER.size.radius, PLAYER.size.radius + 0.05, PLAYER.size.height * 0.6, 6);
    _playerGhostHeadGeo = new THREE.SphereGeometry(PLAYER.size.radius * 0.85, 6, 4);
  }
  const ghostBody = new THREE.Mesh(
    _playerGhostBodyGeo,
    new THREE.MeshBasicMaterial({
      color: cfg.ghostColor,
      transparent: true,
      opacity: 0.5
    })
  );
  ghostBody.position.y = 0.7;
  ghost.add(ghostBody);

  const ghostHead = new THREE.Mesh(
    _playerGhostHeadGeo,
    new THREE.MeshBasicMaterial({
      color: cfg.ghostColor,
      transparent: true,
      opacity: 0.5
    })
  );
  ghostHead.position.y = 1.45;
  ghost.add(ghostHead);

  ghost.position.copy(playerPos);
  ghost.rotation.y = playerGroup.rotation.y;
  scene.add(ghost);

  afterimages.pu
Repobility · severity-and-effort ranking · https://repobility.com
updateAfterimages function · javascript · L312-L328 (17 LOC)
entities/player.js
function updateAfterimages(dt) {
  const scene = getScene();
  for (let i = afterimages.length - 1; i >= 0; i--) {
    const ai = afterimages[i];
    ai.life += dt * 1000;
    const fade = Math.max(0, 1 - ai.life / ai.maxLife);

    ai.mesh.children.forEach(child => {
      if (child.material) child.material.opacity = fade * 0.5;
    });

    if (ai.life >= ai.maxLife) {
      scene.remove(ai.mesh);
      afterimages.splice(i, 1);
    }
  }
}
startCharge function · javascript · L331-L352 (22 LOC)
entities/player.js
function startCharge(inputState, gameState) {
  const cfg = ABILITIES.ultimate;
  isCharging = true;
  chargeTimer = 0;
  gameState.abilities.ultimate.charging = true;
  gameState.abilities.ultimate.chargeT = 0;

  // Calculate initial aim angle toward cursor
  // atan2(dx, dz) so that sin(angle)=dx/len, cos(angle)=dz/len → local +Z extends toward cursor
  const dx = inputState.aimWorldPos.x - playerPos.x;
  const dz = inputState.aimWorldPos.z - playerPos.z;
  chargeAimAngle = Math.atan2(dx, dz);

  // Create telegraph visual
  createChargeTelegraph(cfg);

  // Visual feedback — player glows while charging
  body.material.emissive.setHex(0x44ffaa);
  head.material.emissive.setHex(0x66ffcc);
  body.material.emissiveIntensity = 0.6;
  head.material.emissiveIntensity = 0.7;
}
createChargeTelegraph function · javascript · L354-L395 (42 LOC)
entities/player.js
function createChargeTelegraph(cfg) {
  const scene = getScene();

  chargeTelegraphGroup = new THREE.Group();
  chargeTelegraphGroup.position.set(playerPos.x, 0.05, playerPos.z);
  chargeTelegraphGroup.rotation.y = chargeAimAngle;

  // Fill plane (unit plane, scaled each frame)
  const fillGeo = new THREE.PlaneGeometry(1, 1);
  fillGeo.rotateX(-Math.PI / 2);
  const fillMat = new THREE.MeshBasicMaterial({
    color: cfg.color,
    transparent: true,
    opacity: cfg.telegraphOpacity,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  chargeFillMesh = new THREE.Mesh(fillGeo, fillMat);
  // Position fill to start from player (offset by half minLength)
  const halfLen = cfg.minLength / 2;
  chargeFillMesh.scale.set(cfg.width, 1, cfg.minLength);
  chargeFillMesh.position.set(0, 0, halfLen);
  chargeTelegraphGroup.add(chargeFillMesh);

  // Border — edges of a unit-sized plane, scaled each frame
  const basePlane = new THREE.PlaneGeometry(1, 1);
  const borderGeo = new THREE.Edges
updateCharge function · javascript · L397-L445 (49 LOC)
entities/player.js
function updateCharge(inputState, dt, gameState) {
  const cfg = ABILITIES.ultimate;
  chargeTimer += dt * 1000;
  const chargeT = Math.min(chargeTimer / cfg.chargeTimeMs, 1);
  gameState.abilities.ultimate.chargeT = chargeT;

  // Update aim angle from cursor
  const dx = inputState.aimWorldPos.x - playerPos.x;
  const dz = inputState.aimWorldPos.z - playerPos.z;
  if (dx * dx + dz * dz > 0.01) {
    chargeAimAngle = Math.atan2(dx, dz);
  }

  // Calculate current rect length
  const currentLength = cfg.minLength + (cfg.maxLength - cfg.minLength) * chargeT;

  // Update telegraph position and rotation
  if (chargeTelegraphGroup) {
    chargeTelegraphGroup.position.set(playerPos.x, 0.05, playerPos.z);
    chargeTelegraphGroup.rotation.y = chargeAimAngle;

    // Offset fill and border so the rect starts at the player and extends forward
    const halfLen = currentLength / 2;

    // Scale fill (unit plane scaled to desired size)
    chargeFillMesh.scale.set(cfg.width, 1, currentLength)
fireChargePush function · javascript · L447-L489 (43 LOC)
entities/player.js
function fireChargePush(chargeT, gameState) {
  const cfg = ABILITIES.ultimate;
  const currentLength = cfg.minLength + (cfg.maxLength - cfg.minLength) * chargeT;
  const force = cfg.minKnockback + (cfg.maxKnockback - cfg.minKnockback) * chargeT;

  // Rectangle center = player position + half length toward cursor
  // chargeAimAngle = atan2(dx, dz), so sin(angle) = dx/len, cos(angle) = dz/len → toward cursor
  const halfLen = currentLength / 2;
  const dirX = Math.sin(chargeAimAngle);
  const dirZ = Math.cos(chargeAimAngle);
  const centerX = playerPos.x + dirX * halfLen;
  const centerZ = playerPos.z + dirZ * halfLen;

  // Emit push event for physics
  pushEvent = {
    x: centerX,
    z: centerZ,
    width: cfg.width,
    length: currentLength,
    rotation: chargeAimAngle,
    force: force,
    dirX: dirX,
    dirZ: dirZ,
  };

  // Clean up telegraph
  removeChargeTelegraph();

  // Reset charge state
  isCharging = false;
  gameState.abilities.ultimate.charging = false;
  gameSt
removeChargeTelegraph function · javascript · L491-L509 (19 LOC)
entities/player.js
function removeChargeTelegraph() {
  if (chargeTelegraphGroup) {
    const scene = getScene();
    // Dispose materials and geometries
    if (chargeFillMesh) {
      chargeFillMesh.material.dispose();
      chargeFillMesh.geometry.dispose();
    }
    if (chargeBorderMesh) {
      chargeBorderMesh.material.dispose();
      if (chargeBorderGeo) chargeBorderGeo.dispose();
    }
    scene.remove(chargeTelegraphGroup);
    chargeTelegraphGroup = null;
    chargeFillMesh = null;
    chargeBorderMesh = null;
    chargeBorderGeo = null;
  }
}
resetPlayer function · javascript · L522-L545 (24 LOC)
entities/player.js
export function resetPlayer() {
  playerPos.set(0, 0, 0);
  playerGroup.position.set(0, 0, 0);
  playerGroup.rotation.y = 0;
  isDashing = false;
  isInvincible = false;
  endLagTimer = 0;
  lastFireTime = 0;
  isCharging = false;
  chargeTimer = 0;
  pushEvent = null;
  removeChargeTelegraph();
  body.material.emissive.setHex(BODY_EMISSIVE);
  head.material.emissive.setHex(HEAD_EMISSIVE);
  body.material.emissiveIntensity = 0.4;
  head.material.emissiveIntensity = 0.5;

  // Clean up afterimages
  const scene = getScene();
  for (const ai of afterimages) {
    scene.remove(ai.mesh);
  }
  afterimages.length = 0;
}
initProjectilePool function · javascript · L10-L41 (32 LOC)
entities/projectile.js
export function initProjectilePool(scene) {
  sceneRef = scene;

  basePlayerProjSize = PLAYER.projectile.size;
  const playerProjGeo = new THREE.SphereGeometry(basePlayerProjSize, 6, 4);
  const playerProjMat = new THREE.MeshStandardMaterial({
    color: PLAYER.projectile.color,
    emissive: PLAYER.projectile.color,
    emissiveIntensity: 0.8
  });

  playerPool = new ObjectPool(() => {
    const mesh = new THREE.Mesh(playerProjGeo, playerProjMat.clone());
    scene.add(mesh);
    return { mesh, dir: new THREE.Vector3(), speed: 0, damage: 0, life: 0, isEnemy: false };
  }, 80);

  const enemyProjGeo = new THREE.SphereGeometry(0.1, 6, 4);

  enemyPool = new ObjectPool(() => {
    const mesh = new THREE.Mesh(
      enemyProjGeo,
      new THREE.MeshStandardMaterial({
        color: 0xff4466,
        emissive: 0xff2244,
        emissiveIntensity: 0.8
      })
    );
    scene.add(mesh);
    return { mesh, dir: new THREE.Vector3(), speed: 0, damage: 0, life: 0, isEnemy: true };
  }, 40);
Want this analysis on your repo? https://repobility.com/scan/
fireProjectile function · javascript · L43-L66 (24 LOC)
entities/projectile.js
export function fireProjectile(origin, direction, config, isEnemy) {
  if (isEnemy === undefined) isEnemy = false;
  const pool = isEnemy ? enemyPool : playerPool;
  const p = pool.acquire();
  p.mesh.position.set(origin.x, 0.8, origin.z);
  p.dir.copy(direction).normalize();
  p.speed = config.speed;
  p.damage = config.damage;
  p.life = 0;

  // Scale player projectile mesh based on current config size vs base geometry
  if (!isEnemy && basePlayerProjSize) {
    const s = PLAYER.projectile.size / basePlayerProjSize;
    p.mesh.scale.set(s, s, s);
  }

  // Update enemy projectile color per-type
  if (isEnemy && config.color) {
    p.mesh.material.color.setHex(config.color);
    p.mesh.material.emissive.setHex(config.color);
  }

  return p;
}
updateProjectiles function · javascript · L68-L82 (15 LOC)
entities/projectile.js
export function updateProjectiles(dt) {
  const maxLife = 2.0;
  for (const pool of [playerPool, enemyPool]) {
    const active = pool.getActive();
    for (let i = active.length - 1; i >= 0; i--) {
      const p = active[i];
      p.mesh.position.x += p.dir.x * p.speed * dt;
      p.mesh.position.z += p.dir.z * p.speed * dt;
      p.life += dt;
      if (p.life > maxLife) {
        pool.release(p);
      }
    }
  }
}
releaseProjectile function · javascript · L87-L93 (7 LOC)
entities/projectile.js
export function releaseProjectile(p) {
  if (p.isEnemy) {
    enemyPool.release(p);
  } else {
    playerPool.release(p);
  }
}
readBody function · javascript · L47-L53 (7 LOC)
server.cjs
function readBody(req) {
  return new Promise(resolve => {
    let body = '';
    req.on('data', c => body += c);
    req.on('end', () => resolve(body));
  });
}
setArenaConfig function · typescript · L31-L39 (9 LOC)
src/config/arena.ts
export function setArenaConfig(obstacles: Obstacle[], pits: Pit[], arenaHalfX: number, arenaHalfZ?: number) {
  OBSTACLES.length = 0;
  obstacles.forEach(o => OBSTACLES.push(o));
  PITS.length = 0;
  pits.forEach(p => PITS.push(p));
  ARENA_HALF_X = arenaHalfX;
  ARENA_HALF_Z = arenaHalfZ ?? arenaHalfX;
  ARENA_HALF = ARENA_HALF_X; // legacy alias
}
getPitBounds function · typescript · L41-L48 (8 LOC)
src/config/arena.ts
export function getPitBounds(): AABB[] {
  return PITS.map(p => ({
    minX: p.x - p.w / 2,
    maxX: p.x + p.w / 2,
    minZ: p.z - p.d / 2,
    maxZ: p.z + p.d / 2,
  }));
}
getCollisionBounds function · typescript · L50-L86 (37 LOC)
src/config/arena.ts
export function getCollisionBounds(): AABB[] {
  const bounds: AABB[] = [];

  for (const o of OBSTACLES) {
    bounds.push({
      minX: o.x - o.w / 2,
      maxX: o.x + o.w / 2,
      minZ: o.z - o.d / 2,
      maxZ: o.z + o.d / 2,
    });
  }

  // Height zones — entities below maxY collide, entities on top walk freely
  for (const zone of HEIGHT_ZONES) {
    bounds.push({
      minX: zone.x - zone.w / 2,
      maxX: zone.x + zone.w / 2,
      minZ: zone.z - zone.d / 2,
      maxZ: zone.z + zone.d / 2,
      maxY: zone.y,
    });
  }

  const hx = ARENA_HALF_X;
  const hz = ARENA_HALF_Z;
  const t = WALL_THICKNESS;
  // North wall (far end, +Z)
  bounds.push({ minX: -hx - t/2, maxX: hx + t/2, minZ: hz - t/2, maxZ: hz + t/2 });
  // South wall (near end, -Z)
  bounds.push({ minX: -hx - t/2, maxX: hx + t/2, minZ: -hz - t/2, maxZ: -hz + t/2 });
  // East wall (+X)
  bounds.push({ minX: hx - t/2, maxX: hx + t/2, minZ: -hz - t/2, maxZ: hz + t/2 });
  // West wall (-X)
  bounds.push({ min
resolveEffectType function · typescript · L172-L189 (18 LOC)
src/config/effectTypes.ts
export function resolveEffectType(typeId: string): any | null {
  const type = EFFECT_TYPES[typeId];
  if (!type) {
    console.warn(`Unknown effect type: ${typeId}`);
    return null;
  }

  if (!type.parent) {
    return { ...type, id: typeId };
  }

  const parentResolved = resolveEffectType(type.parent);
  if (!parentResolved) {
    return { ...type, id: typeId };
  }

  return deepMerge(parentResolved, { ...type, id: typeId });
}
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
deepMerge function · typescript · L201-L222 (22 LOC)
src/config/effectTypes.ts
function deepMerge(target: any, source: any): any {
  const result = { ...target };

  for (const key of Object.keys(source)) {
    if (source[key] === undefined) continue;

    if (
      source[key] !== null &&
      typeof source[key] === 'object' &&
      !Array.isArray(source[key]) &&
      target[key] !== null &&
      typeof target[key] === 'object' &&
      !Array.isArray(target[key])
    ) {
      result[key] = deepMerge(target[key], source[key]);
    } else {
      result[key] = source[key];
    }
  }

  return result;
}
getGroundHeight function · typescript · L26-L41 (16 LOC)
src/config/terrain.ts
export function getGroundHeight(x: number, z: number): number {
  let maxY = 0; // base floor is always 0
  for (const zone of HEIGHT_ZONES) {
    const halfW = zone.w / 2;
    const halfD = zone.d / 2;
    if (
      x >= zone.x - halfW &&
      x <= zone.x + halfW &&
      z >= zone.z - halfD &&
      z <= zone.z + halfD
    ) {
      if (zone.y > maxY) maxY = zone.y;
    }
  }
  return maxY;
}
findLaunchTarget function · typescript · L24-L39 (16 LOC)
src/effects/launchIndicator.ts
export function findLaunchTarget(enemies: any[], playerPos: any): any | null {
  let closestEnemy: any = null;
  let closestDistSq = LAUNCH.range * LAUNCH.range;
  for (let i = 0; i < enemies.length; i++) {
    const e = enemies[i];
    if (e.health <= 0 || e.fellInPit) continue;
    const dx = e.pos.x - playerPos.x;
    const dz = e.pos.z - playerPos.z;
    const distSq = dx * dx + dz * dz;
    if (distSq < closestDistSq) {
      closestDistSq = distSq;
      closestEnemy = e;
    }
  }
  return closestEnemy;
}
‹ prevpage 3 / 14next ›