Everyone has that folder. The one stuffed with half-finished tutorials, abandoned side projects, and README files that promise more than they deliver. It is a graveyard of good intentions, and the only way out is to ship something — anything — that actually works.

That itch to finish is what drove the creation of LIAR, a browser game so small and so hostile that it fits inside a single 28KB HTML file. No frameworks. No image files. No sound assets. Just raw HTML5 Canvas, the Web Audio API, and a mean streak.

The Anti-Tutorial

Most learning projects die because they grow legs. You start with a canvas tutorial, add a movement script, then decide you need a tile editor, then an entity component system, then a Webpack config that takes eleven seconds to compile. Six weeks later you have a build pipeline and no game.

LIAR refuses that trap. It is a reaction game. A button tells you to TAP, HOLD, or DON'T. You act before a timer runs out. Early rounds establish trust. The text says TAP, you tap. The text says HOLD, you hold your finger down. It is simple, rhythmic, almost meditative.

Then round six arrives.

The Mechanics of Betrayal

Around round six, the game starts lying. A command flashes on screen — perhaps a violent, red, shaking TAP — and every reflex you built during the warm-up screams at you to hit the button. If you do, you lose. The red shake is not a glitch. It is a tell. An honest liar gives you a clue, and this game gives you exactly that: a visual grammar of deception.

The trick works because the foundation is honest. The early rounds teach you that color and motion carry meaning. When the palette suddenly shifts and the text trembles, the game is not cheating. It is signaling. You had the information. You either read it or you did not.

When you fail, the game insults you. That sting is deliberate. In a micro-game with no leaderboard and no persistent progression, humiliation is the currency of replayability. It closes the feedback loop. You do not lose because of lag or because a hitbox felt off. You lose because you trusted a shaking red word, and the game makes sure you sit with that mistake.

What 28KB Actually Means

Choosing to build inside a single 28KB HTML file is not just a novelty. It is a design constraint that forces hard decisions. There are no megabytes of sprite sheets to hide behind. No audio files to trigger. Everything visible is drawn frame-by-frame on an HTML5 Canvas. Everything audible comes from Web Audio oscillators.

If you have not worked with the Web Audio API directly, here is what that entails. Instead of loading a pre-recorded WAV or MP3, the code creates an AudioContext, attaches an oscillator node, selects a waveform — sine, square, sawtooth — and sets a frequency. A short beep for a correct input, a harsh buzz for a failure. Those tones are computed in real time by the browser. They cost nothing in file size and add no external network requests.

The same logic applies to the visuals. Canvas gives you an immediate-mode drawing surface. You clear the rectangle. You fill text. You set a transform or a shadow blur for the shake effect. There is no virtual DOM diffing, no React reconciliation, no dependency array to debug. The browser runs the code, and the pixels appear. For a game this focused, that directness is a feature, not a limitation.

Keeping the payload at 28KB also means the game loads almost instantly on a mobile browser, even on a shaky connection. It costs virtually nothing to host. The entire application is smaller than most website favicons. That matters if you are distributing through a shared link or embedding on a forum. There is no install friction. You visit the URL, and the lie is ready.

Fair Deception

Spending real time on the lying mechanic reveals a subtle truth about game design. Unfairness is only fun when it is legible. A random trap that kills the player without warning is bad design. A trap that vibrates, changes color, and breaks the established visual rhythm is a puzzle dressed as an ambush.

The red shaking text serves multiple purposes. It overrides the habitual response players developed in rounds one through five. It introduces an emotional beat — suspicion, hesitation, panic — in what was previously a reflex test. And most importantly, it makes failure feel owned. When you tap that red command and the insult appears, you know the fault is yours. The game gave you a tell. You failed to read it.

이것이 비겁한 공격과 정당한 승부의 차이입니다. LIAR는 당신의 얼굴을 때리고 싶어 하지만, 휘두르기 전에 먼저 무게를 싣습니다.

다듬기보다 출시를 우선시하기

게임은 거칩니다. 제작자 본인도 그렇게 말할 것입니다. 이 게임은 그들의 첫 완성작이며, 단순함은 완성을 위해 치른 대가였습니다. 개발자들이 실제 서비스에 적용되지도 않을 시스템에 대해 블로그를 쓰는 일이 빈번한 생태계에서, 이러한 정직함은 신선하게 다가옵니다. LIAR는 실제 URL로 존재합니다. 지금 바로 플레이할 수 있습니다. 모노레포를 헤맬 필요 없이 단일 파일로 소스 코드를 볼 수 있습니다.

개발자는 감히 이 게임을 시도해 볼 용기가 있는 사람들에게 두 가지를 알고 싶어 합니다. 첫째, 얼마나 오래 살아남는가? 둘째, 6라운드에서 첫 번째 거짓말이 터졌을 때, 그것이 공정하게 느껴지는가, 아니면 비겁하게 느껴지는가? 이것이 바로 던져야 할 올바른 질문입니다. 개발자는 거짓말을 버그가 아니라 조율이 필요한 메커니즘으로 다룹니다.

관심이 있다면, 개발자는 Canvas 드로잉 루프, Web Audio 오실레이터의 로직, 그리고 코드상에서 거짓말 메커니즘이 정확히 어떻게 구조화되어 있는지 다루는 심층 가이드를 작성하겠다고 제안했습니다. 단 하나의 HTML 파일 안에 전체 게임이 들어있는 사례가 매우 드물다는 점을 고려하면, 그 가이드는 튜토리얼 연옥(tutorial purgatory)에 갇힌 모든 이들에게 진정으로 유용할 것입니다.

진정한 교훈

게임을 만들기 위해 게임 엔진이 필요한 것은 아닙니다. 에셋을 위한 CDN도, 20페이지짜리 기획서도, 프레임워크 관리자의 허락도 필요하지 않습니다. 필요한 것은 경계(여기서는 28KB와 단일 파일)와 완성을 위한 이유입니다. 제약은 명확함을 만들어냅니다. 밑바탕이 되는 메커니즘이 탄탄하다면, 흔들리는 빨간색 글자 하나가 수천 개의 임포트된 스프라이트보다 더 기억에 남을 것입니다.

직접 LIAR를 플레이해 보세요: https://playliar.netlify.app/.
개발자의 원문 분석과 소스 맥락은 다음에서 읽을 수 있습니다: https://dev.to/shabbir_sesaifee_8fdc587/i-built-a-game-that-lies-to-you-in-a-single-28kb-html-file-no-framework-no-assets-4hnh.