Game project · USC Games · That Game Jam · Team of 5

Light as Wind

A dreamy pixel-art side-scroller across the ocean, toward a faraway sky. I was a designer and engineer on the team: I did the level design for three of the ten levels and built several of the physics, shader, and destruction systems the game runs on.

Gameplay from Level 03: hiding from the anglerfish. Every creature in the game is animated procedurally, with no skeletal rigs.

My role

Designer · Engineer

I did the level design for Levels 04, 06, and 10 — scene, route, and mechanics. Across the game I designed interaction mechanics, engineered gameplay logic and effects, and did QA and bug fixing.

On the engineering side I focused on how things feel when they move: paper caught by the wind, the swordfish’s swimming, the crab’s vine swing, and props that break apart. I also wrote the shader for the game’s “air walls”.

The project has a strict rule: every system’s logic lives in plain C# with no engine types, so it can move off Unity later, and every change is checked with data — probes, logs, and route bots — before screenshots.

Engine
Unity 6 / C# / HLSL
Team
5 students, USC Games
Platform
Windows (itch.io)
Status
Part I out now

The project’s foundation

Rendering & procedural animation

Light as Wind is built on two technical foundations: pixel art that holds up in a moving 3D perspective camera, and creatures animated entirely by code, without a single skeletal rig. The systems I built sit on top of them.

01

Custom render pipeline

The game moved off URP in stages to its own pipeline, built on an engine-agnostic frame graph in plain C# with Unity as just one backend. Each step was checked texel by texel against reference frames. Shader variants went from 603 to 36, and a full frame costs about 0.4–0.5 ms of GPU.

02

Pixel art in perspective

Each object snaps rigidly to the low-resolution texel grid, and its leftover sub-pixel offset is stored in the G-buffer and resolved at screen resolution, so silhouettes never crawl while the camera glides. Soft bounce light comes from 2.5D radiance cascades with world-pinned probes, at about 0.3 ms.

03

Procedural animation

No skeletal rigs anywhere: fish spines driven by travelling waves, XPBD and Verlet chains, jellyfish simulated in compute shaders, and Boids schools of over 5,000 fish drawn in a single call.

Level design

Levels I designed

Systems

Physics, shaders & destruction

05 highlights

01 · Simulation

Paper blown by the wind

Each sheet lifts by rotating about its downwind edge as a hinge, peels up to 34°, then lets go. In the air its velocity eases toward a target wind with an exponential chase, and a falling-leaf sway (±0.3 m, 2.1 s period) couples tilt to swing so the sheet leans into each turn.

Before the wind arrives, corners flutter on an underdamped spring. A wall constraint holds posters in front of the wall and slides them off its face, so they never pass through it.

Per gust
15–17 sheets, all off-screen in 0.22–2.33 s
Wall clipping
0.7–2.6 m → 0
The model is plain C# (System.Numerics, no engine types); Unity only draws it.

02 · Shader · Worley noise

The air wall: a dream sea’s skin

Invisible walls needed to read as part of the dream, not as a bug. The wall shows a drifting Voronoi / Worley web: lines are drawn by the true distance to the cell borders, so they stay one pixel wide and unbroken at any angle, each border in one of the plankton colours, with a few twinkling gold motes.

A hit sends a pair of rings running out that push the web aside, and bubbles drift off from the impact. The curtain appears only when you come close (1.8 m, full at 0.95 m). Brightness uses clean steps with no dithering, in portable HLSL on the project’s own headers.

03 · Game feel

The swordfish’s swim

The swordfish swims with a tuna-style spine wave, a mass-weighted recoil that makes the head swing against the tail like a real fish, and a tail-beat frequency set by the Strouhal number.

I worked on how it handles: no braking before it actually touches a wall (distance measured from the snout tip along its path), sliding along roofs and grassy slopes without bleeding speed, a dive between leaps, and quicker up/down turns.

04 · Simulation

The crab’s vine swing

The crab is a pendulum; the vine just follows its claw. Grabbing is measured in the picture plane, because pure 3D distance kept missing in a 2.5D game. The player can pump only in phase with the swing, and an energy cap (72° max) keeps long vines from flinging the crab out of frame.

Each vine is an 18-node Verlet rope with 8 constraint passes, water drag, and slow sway; the nodes below the claw are pushed out of the crab’s shell so it never clips.

Avg frame, Levels 7/8/9
6.4/7.7/8.5 → 1.7/2.6/2.7 ms
Frames over 16.7 ms
89/165/166 → 4/0/0

05 · Destruction

Cutting the level into pieces

Nothing in the game is an imported mesh, so destruction means cutting generated geometry. For Level 06’s collapsing tunnel, the cave roof breaks itself: vertices are welded and grouped into closed rocks with union-find, long rocks are clipped against random planes (Sutherland–Hodgman, all attributes interpolated), and each cut is capped with a fan so every fragment stays a closed solid.

The cut runs as a coroutine with a 4 ms per-frame budget, starting while the player is still 60 m away: 610 rocks become 169 fragments over 140–220 frames. Smaller props break with pre-cut pieces whose seams are shared between neighbours, and the shards skip the physics engine entirely — about 0.013 ms per frame.

Tunnel collapse
610 rocks → 169 fragments
Prop smash worst frame
14.6 → 3.3 ms