Function bodies 653 total
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 += retbehaviorMortar 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(_mortarFilremoveMortarGroundCircle 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.playerHebehaviorTank 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 = MupdateMortarProjectiles 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 pcreateIcePatch 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(playeupdatePlayer 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 {
dashDupdateDash 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.puRepobility · 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.EdgesupdateCharge 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;
gameStremoveChargeTelegraph 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({ minresolveEffectType 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;
}