The premise
Zanzlanz's video "How I released a game that has no assets" is a love letter to the sine wave. The question is simple: can a video game ship with no image files, no audio files, and no font files — generating everything at runtime from sine waves? The answer, demonstrated through the HTML5 game Crow Sign, is yes. The game is not just small; it is structurally small, because its assets are formulas rather than bitstreams.
This companion guide maps the techniques the video calls out, relates them to the CatGame engine, and then sketches a different way to render a game level: an oscilloscope renderer that would fit inside the existing Vulkan render graph. All method names and numbers in the next sections are taken from the video narration and transcript; a few isolated phrases are hard to verify without the source code and are flagged in the caveats section at the end.
Watch the original video on YouTubeWhy sine waves can be everything
The video starts with a single claim: any image, sound, or motion can be built by adding enough sine waves. In signal-processing terms this is Fourier synthesis — a signal is decomposed (or rebuilt) as a sum of sinusoids with different frequencies, amplitudes, and phases. The visual version is sometimes drawn as a chain of rotating circles: each circle is one harmonic, higher frequencies spin faster, and tracing the final circle's tip draws the target shape. This is exact for periodic signals and can approximate many shapes in two dimensions, but the video's "any image" is best read as "any image that can be represented by a synthesizable set of sinusoids," not a universal guarantee for arbitrary bitmaps.
"If you combine the right set of these sine waves, you can create a square. Or a triangle. Or a duck."
For game assets, the practical trick is to keep only the strongest harmonics. A planet becomes a low-frequency circle with a few higher-frequency bumps. A character becomes a small set of keyframe shapes, and the game morphs between them by interpolating the frequency coefficients, not the vertex positions. The video calls this morphing "fading between the frequencies that make up each keyframe." The main character, a crow, is a combination of these harmonic sets; rotating it to stand on the planet is done by changing the starting rotation of all harmonics, which the narrator dubs crotation (his own term, not a standard one).
tanh for an infinitely squished, M.C. Escher-like dial effect — and because tanh is built from sine and cosine, it still honors the theme.Audio and music from the same building block
The video notes that taking a recorded sound, running a Fourier Transform, and playing it back would be almost the same as shipping an MP3. So Crow Sign synthesizes sounds from scratch using Audio Worklets in the browser. Audio Worklets are a Web Audio API feature that let a web page run custom, low-latency sample-generation code on a dedicated audio thread, effectively turning the browser into a software synthesizer. The game uses them to generate waveform samples on demand rather than decoding them from a file. Walking, jumping, landing, the plane engine, and popping balloons are all synthesized from basic waveforms (sine, triangle, square, noise) with envelopes and pitch sweeps.
Music is generated the same way. The video claims the music is over 500 times smaller than looped MP3s, because it is stored as note/sequence data plus a small synthesizer rather than as compressed audio samples. This is the same trade-off tracked music (MOD, XM, S3M) made in the 1990s, but rebuilt with modern Web Audio primitives.
The JPEG wormhole and DCT
One of the most visually striking effects is a real-time JPEG compression shader used in the wormhole scene. The video describes it as: each block of pixels is converted to cosine waves using the Discrete Cosine Transform (DCT), and more and more of those frequency coefficients are discarded closer to the wormhole center. That is the quantization step of JPEG compression; a full JPEG encoder also adds color-space conversion and entropy coding, so the shader is using the DCT/quantization look rather than the complete file-format pipeline. The narrator connects this to the "bubbly sound" and ripple patterns you see in over-compressed MP3s and JPEGs.
The numbers the video reports
At the end of the video, the narrator gives a set of file-size comparisons for Crow Sign. These are internally relative numbers from the project, not absolute industry benchmarks, but they show the magnitude of the savings.
| Asset type | Sine approach | Reported baseline | Savings |
|---|---|---|---|
| Font | Harmonic cursive | Similar TrueType | ~0.5× |
| Sprites | Harmonic shapes | SVG or PNG | ~0.5× vs. SVG; ~1/7 vs. PNG |
| Sound effects | Synthesized | MP3 | ~37×; ~6.5× without NPC voice variations |
| Music | Generated loops | MP3 loops | ~500× |
| Total game | All of the above | Equivalent with assets | ~11× smaller; 455 KB |
These are silly comparisons in the narrator's own words — no one expects AAA games to shrink with sine waves — but they are a useful proof of what can happen when every asset is a tiny formula instead of a compressed file.
How this connects to the CatGame engine
The CatGame engine is built around a different scale and target: a C++20 Vulkan engine with a RenderGraph, deferred and forward passes, bindless textures, and ComputePipeline support. But the underlying idea is the same: keep the source data small and let the GPU turn it into pixels. We already do that in several places.
- Procedural tile geometry: The tile renderer post describes how level data is a flat
uint16_tgrid, not a mesh. The mesh is expanded at runtime from a palette, exactly the same shape-first mentality as Crow Sign's harmonic editor. - VFX instancing: The VFX pass fills an SSBO each frame with
ParticleInstanceDataand draws up to 65,536 particles in a handful of calls. The data is small and re-computed, not stored as animation frames. - GPU compute shaders: The engine already compiles and dispatches
.compshaders — for example,particle_update.compin the VFX pass andrmsnorm.compin cat_chat — so the compute infrastructure for a tile-to-trace conversion is already in place. The Vulkan ML compute post covers how that dispatch machinery was built. - Debug and primitive line rendering:
DebugLineRendereralready builds per-frame vertex buffers of 3D lines. An oscilloscope renderer would be a stylistic sibling: it draws the world as lines and vector traces instead of shaded surfaces.
The difference is mostly where the formulas live and what they produce. Crow Sign generates 2D vector art and audio in JavaScript and Web Audio. The CatGame engine can generate 3D geometry, particles, and full-screen post-processes in Vulkan compute and fragment shaders. The conceptual bridge is: data small, math big, output at runtime.
Concept: an oscilloscope renderer for CatGame levels
Here is a different way to render a game level that reuses the existing engine but adopts Crow Sign's "math as asset" philosophy. Instead of rasterizing shaded meshes, the OscilloscopeRenderPass treats the visible scene as a single continuous waveform and draws it the way an oscilloscope draws a signal: a bright electron beam tracing vector paths across a dark screen, with phosphor persistence and deflection blanking.
A naive trace of every edge would draw hidden lines on top of visible ones, so the pass needs a visibility strategy. The simplest option is to read the existing depth buffer and only emit trace samples for fragments that pass a depth test, giving an oscilloscope projection of the visible 3D surface. The stylized option is to ignore occlusion entirely and accept the "X-ray" wireframe look. The depth-aware version is closer to a real oscilloscope drawing a physical object; the non-depth version is closer to a vector-art style.
How it would plug into the existing engine
The render graph in engine/systems/render/graph/render_graph_presets.cpp already orders passes: shadow, primitive, vmesh, outline, vfx, debug lines, text. A new OscilloscopeRenderPass would be inserted after the world passes and before UI, or it could be a post-process that reads the GBuffer/depth and emits a trace image. Two implementation paths are possible:
uint16_t buffer) and the visible entity list from the camera cull pass. For each visible surface edge, emit a world-space line segment. This is conceptually a compute shader dispatch over tiles, similar to how VFX fills its SSBO.(x, y, 0) flags — where the beam should move without drawing. The output is a structured buffer of (position, blank, intensity) tuples, not a triangle list.Where the existing code fits
DebugLineRendereralready demonstrates how to allocate a per-frame mapped vertex buffer, fill it with 3D line endpoints, and draw with a small shader. The oscilloscope pass would reuse that buffer machinery but replace the vertex data with trace samples.ComputePipelineandassets/shaders/**/*.compare already part of the build. The tile-to-trace conversion and Fourier coefficient solve are natural compute-shader jobs.RenderGraphBuildercan express the pass ordering and image attachments. The pass would read depth/color as input and write to a transient oscilloscope target.- Bindless texture array could be ignored entirely: an oscilloscope mode does not need textured surfaces. That makes it a useful stress-test for the renderer's ability to run without the material pipeline.
main branch, not in the render graph, and has no associated compute shader. It is intended as a roadmap exploration and a possible VFX/debug tool, not a shipped feature.Mentions beyond the main pipeline
The video also mentions 32 animated harmonics for the airplane propeller and body; two circles for landing wheels; a speedometer, altimeter, and map as the plane HUD; and Audio Worklets as the browser audio thread primitive. The source of these details is the video's narration and auto-generated transcript; some proper names (e.g., crotation, sine language) are the narrator's own terms and should be treated as in-project coinages, not established technical terms.
Caveats and limitations
- The transcript used for this companion is machine-generated. Technical terms like Fourier, DCT, Audio Worklets, and the reported file-size numbers are attributed to the video, not independently verified from source code or benchmarks.
- The claim that hyperbolic tangent is "tangent rotated in the complex plane" is the video's informal explanation; the real relationship is that
tanh(z) = sinh(z)/cosh(z)and both connect to the complex exponential. It is still built from sine/cosine, which is the narrator's point. - The exact DCT/JPEG shader pipeline is not shown in the video. The description is the author's stated intent; the actual shader may use a different block size, color space, or quantization table.
- The oscilloscope renderer is a concept. Feasibility depends on trace budget, harmonic count, and the cost of compute solves per frame. The harmonic (epicycloid) variant is almost certainly the more expensive and more fragile path; a direct line-trace variant is the simpler first step.
Closing thought
Crow Sign is a useful reminder that "assets" can mean formulas. The CatGame engine already leans in that direction for tiles, particles, and compute effects. The oscilloscope renderer concept is one way to push the same idea into the renderer itself: a level drawn not by rasterizing triangles, but by tracing a mathematical path. Whether it ships as a debug visualization, an Easter-egg render mode, or a full level style, it is the kind of experiment that fits a project trying to keep data small and math visible.
