Play it: itch.io | Source Code
- You leave a ghost of yourself replaying your movement 1.2 seconds behind you. Freeze it: solid platform. Teleport to it: you're where you were a moment ago.
- Use the mechanics to create mid-air platforms over voids, positions past sweeping lasers, ledges on the far side of gaps with no surface to jump from.
- Built in 14 days from concept to submission. Zero imported art assets. Every visual generated at runtime in code.
Design Intent
The echo replays exactly what you did, 1.2 seconds later. That rigidity is the entire puzzle space. You have to think ahead, because what you do now becomes a tool (or a problem) in a moment.
Two inputs. One system. Nothing exists outside it. Eight levels, each asking a different question of that same system.
Key Design Decisions
The echo is a transform replayer, not a physics object
The echo has no Rigidbody. It reads positions from a circular buffer and sets its transform directly. If the buffer recorded the player mid-air, the echo is mid-air. Not because of physics, just because that's what the buffer says.
This means the echo can help the player reach positions that are physically impossible to reach. A platform floating over a void. A spot past a sweeping laser. A ledge across a gap with no surface. Teleporting to any of those puts you somewhere no normal path could get you. That's the whole game.
The buffer is a fixed-size circular array
512 entries at 50Hz FixedUpdate. Write head advances every frame, wraps on overflow. The 1.2-second delay is just reading 60 frames behind the write head. Changing the delay means changing an index offset.
Each frame, the write head advances and wraps:
buffer[writeHead] = frame;
writeHead = (writeHead + 1) % bufferSize;
Reading at a delay is a single index calculation — no iteration, no search:
int index = (writeHead - delayFrames + bufferSize) % bufferSize;
The + bufferSize before the mod prevents negative indices when delayFrames > writeHead (early in the session, before the buffer fills). Changing the echo delay at runtime is a single integer:
delayFrames = Mathf.RoundToInt(echoDelaySeconds / Time.fixedDeltaTime);
At 50Hz with a 1.2s delay that's 60 frames. Adjust echoDelaySeconds and the read head just jumps to the new offset instantly — no restructuring, no copying. That's what makes dynamic delay trivial if the design ever calls for it.
Each entry is a value-type struct (position, velocity, facing, animation state), so the array stores data inline rather than heap pointers.
All visuals are procedural
Every visual in the game is generated at runtime from a single 1x1 white pixel sprite, scaled and tinted. The static charge hazard draws crackling arcs between emitter nodes using LineRenderers, jittering every 60ms. The trace laser raycasts each frame and stops at the first solid collider, drawing a three-layer line (white core, mid glow, soft bloom). Zone boundaries auto-position from BoxCollider2D bounds at Awake.
Zone System
The base game has two verbs: freeze and teleport. Zones modify what those verbs do.
Momentum Zone (cyan): Teleporting preserves your current speed but redirects it to match the echo's stored velocity direction. You bring the force, the echo aims it. This creates a two-step ritual: scout jump to plant a direction in the buffer, freeze at the angle you want, build speed, then teleport. The aim and the launch are separate actions.
Kinetic Freeze Zone (amber): Freezing the echo doesn't lock it in place. Instead it inherits the velocity it had at that replay frame and slides until it hits geometry. You deploy the echo like a projectile, then teleport to where it lands, or jump onto it for a ride!
Echo Split Zone (green): Freezing plants two echoes at different buffer offsets simultaneously. Two platforms from one input.
Each zone announces itself with a screen flash and a riddle that follows the player. Direct enough to point at the mechanic, vague enough not to spoil the solve.