Claude Code in Action: Building an Embedded Tetris Game with AI in Under 3 Hours

How to build an embedded Tetris game with Claude Code and LVGL in under 3 hours, from requirements to hardware.
A practical case study showing how Claude Code, combined with the LVGL graphics library, builds a runnable embedded Tetris game from scratch in under 3 hours. It covers the full workflow: requirements clarification, Workflow rule design, automatic compilation loops, and PC-to-hardware migration.
Starting from Scratch: Building a Real, Runnable Game with AI
In this advanced Claude Code case study, the author presents a compelling example: in under three hours, building a Tetris game from scratch with AI that runs on an embedded development board. This isn't a demo running in a browser — it's a complete project based on LVGL (a lightweight graphics library) that was successfully compiled and deployed to real hardware.
About LVGL: LVGL (Light and Versatile Graphics Library) is an open-source graphics library designed specifically for microcontrollers and embedded systems. It runs on as little as 64KB of Flash and 16KB of RAM, and supports a wide range of display devices, from simple monochrome OLEDs to high-resolution RGB screens. It offers a rich set of built-in widgets (buttons, lists, charts, animations, and more), is implemented in pure C, and is highly portable across platforms. LVGL was born in 2016, originally named LittlevGL, developed by Hungarian engineer Gábor Kiss-Vámosi. Today it has become one of the most widely used open-source frameworks in the embedded GUI field, officially integrated into the development ecosystems of chip vendors like STMicroelectronics and NXP.
LVGL's architecture borrows the concepts of the Object Tree and Style System from web frontend development — each UI element is abstracted into an lv_obj object, and style properties (color, margins, fonts) are applied through a CSS-like cascading mechanism, allowing developers to describe interface requirements in near-declarative UI semantics. The hierarchy of the object tree determines rendering order and event bubbling paths, while the cascading mechanism of the style system makes unified theme modification possible — modifying a parent object's style automatically propagates to all child objects, eliminating the need to adjust them one by one. This design philosophy shares the same lineage as React's component tree and Flutter's widget tree, only deeply trimmed for the extremely resource-constrained embedded environment: LVGL removes the virtual DOM diff algorithm and instead adopts a "Dirty Rectangle" mechanism that only redraws the areas of the screen that have changed, preserving the semantic development experience while compressing rendering overhead to the limit. The essence of the dirty rectangle mechanism is a spatial locality optimization — in each frame, only the rectangular regions where pixels have actually changed trigger a redraw, while the rest of the screen retains the frame buffer content from the previous frame. This is especially critical on microcontrollers with CPU clock speeds of only a few hundred MHz and no GPU acceleration, reducing actual draw calls to 5%~20% of a full-screen refresh.
This abstraction layer is crucial for AI involvement: AI can directly handle semantic descriptions like "create a score panel with rounded borders" and map them to specific LVGL API calls, without needing to understand low-level frame buffer operations or DMA transfer details — this is precisely the technical prerequisite for AI to be able to intervene efficiently in this case.
The entire project's initial environment was set up using an LVGL project created with UI Builder. After scaffolding was in place, the author handed over nearly all subsequent coding work to the AI. This division of labor — "humans build the framework, AI fills in the flesh" — is exactly the typical workflow of AI-assisted development today.

The Critical First Step: Clarifying Requirements Matters More Than Writing Code
Throughout the process, the author repeatedly emphasized one core insight — most of the time was spent communicating with the AI, while the actual coding time was surprisingly short. This is extremely valuable for developers new to AI programming.
This observation has deep roots in software engineering theory. Barry Boehm's research shows that if an error introduced during the requirements phase is only discovered after coding, the cost of fixing it can grow by a factor of 10 to 100. This principle, known as the "exponential growth law of defect fixing costs," is the crystallization of decades of industrial practice data, and has since been repeatedly confirmed by research from institutions like NIST. The essence of requirements clarification is transforming high-entropy (vague, ambiguous) natural language descriptions into low-entropy (structured, verifiable) specification documents — this process itself is the highest information-density stage of the entire project. From the perspective of information theory, a precise requirements specification is equivalent to greatly compressing the "constraint set" of the subsequent implementation space — the more precise the requirements, the smaller the state space the AI can explore during generation, and the smaller the semantic distance between output and expectation. In the language of Shannon's information theory: vague requirements have high uncertainty entropy, equivalent to allowing the AI to wander freely within a broad solution space; while precise requirements dramatically reduce this entropy, constraining the AI's generation path to a small neighborhood near the expected solution.
In the context of AI programming, this principle is further amplified: the AI's generative capability is extremely strong, but its direction is entirely determined by the initial specification. Vague input causes the AI to fill in a large number of "reasonable but unexpected" assumptions, and every erroneous assumption accepted by the AI gets amplified along the code generation path. It's worth noting that when facing ambiguity, large language models tend to choose the "default solution" that appears most frequently in the training data — for a classic game like Tetris, the AI is very likely to default to reproducing standard Nintendo rules (including the Super Rotation System and the classic NES line-clearing scoring algorithm). The Super Rotation System (SRS) is a modern rotation rule standardized by The Tetris Company in 2001, defining the "Wall Kick" offset sequences for each piece when its rotation is blocked by a wall or other pieces; while the NES scoring system calculates scores based on the number of lines cleared in a single move (1-4 lines) and the current level, with the specific formulas being: single clear 40×(level+1) points, double clear 100×(level+1) points, triple clear 300×(level+1) points, and quad clear (Tetris) 1200×(level+1) points. These are all implicit conventions the AI will automatically reproduce in the absence of clear instructions. If the developer has any custom requirements — such as different wall kick logic, custom piece shapes, or non-standard scoring rules — these must be explicitly stated during the requirements phase, otherwise these implicit assumptions will be deeply encoded into the implementation details, and the cost of changing them afterward will far exceed expectations.
When the project started, the requirements description was quite simple: "I need to write a Tetris game. Help me design a basic interface and easy-to-operate buttons." But Claude Code didn't immediately start writing code — instead, it first posed a series of questions for the author to answer one by one. The author specifically pointed out that the final implementation result was "completely strongly correlated" with these questions the AI asked — the more clearly the requirements-clarification stage was answered, the closer the output was to expectations. Therefore, having the AI proactively ask questions and output a structured plan before coding is essentially doing "requirements quality assurance" — the highest-leverage stage in an AI-native development workflow.
After the Q&A, the AI outputs a complete plan covering the overall architecture, visual design, and game layout. The value of this step lies in transforming vague ideas into structured, reviewable specification documents.

Workflow Rules: The Key to Making AI Self-Constrain
One highlight of this case is the author's introduction of custom Workflow rules. After adding workflow rules, the AI proactively evaluates whether the previously established plan has any issues, further investigates the existing code, and finally produces a more detailed and specific implementation plan.
Workflow rules are essentially "system-level constraints" on AI behavior, an advanced form of Prompt Engineering in engineering practice. Ordinary prompts describe "what to do," while Workflow rules define "how to do it" and "what to check after it's done." From the technical perspective of prompt engineering, Workflow rules are a kind of "Meta-Prompt" — they don't directly guide task execution, but rather define the behavioral protocol the AI must follow when executing any task. The concept of meta-prompts was first systematized around 2022 with the widespread adoption of GPT-3. Its core insight is: rather than repeatedly stating behavioral expectations in every conversation, it's better to encode these expectations as persistent higher-level constraints, so the model maintains consistent behavior throughout the session and even across sessions. In practice, meta-prompts are usually injected in the form of a System Prompt, with higher priority than a single user instruction, equivalent to setting up an un-overridable "constitutional-level constraint" in the model's decision-making process.
This is highly analogous to the concept of "Coding Standards" in software engineering: the standards themselves don't produce functional code, but they constrain how all functional code is produced, thereby ensuring overall consistency of quality and maintainability. A deeper analogy is the operating system's "system call specification" — applications don't need to understand kernel implementation details; they only need to follow the prescribed calling interface. Similarly, developers don't need to explain the workflow to the AI every time — they only need to define it once in the Workflow rules, and the AI will automatically follow it in all subsequent tasks.
From a more macro perspective, Workflow rules are a core component of the "AI Native development workflow." They enable different developers and different projects to share the same set of AI collaboration standards, rather than relying on verbal agreements or ad-hoc prompts every time. Teams can bring validated Workflow rule files into version control, iterating and optimizing the AI's behavioral specifications just like managing code — recording change history, conducting code reviews, and rolling back ineffective rules. This is the key path to transforming individual best practices into organization-level assets. Versioned management of rule files also brings another benefit: when the AI model is upgraded or switched, A/B testing can be used to compare the performance of old and new rules across different model versions, systematically finding the optimal rule set rather than starting from scratch each time.
The author particularly emphasized: after the plan is confirmed, it must be saved as a file. Turning the plan into a document not only serves as a reference benchmark for subsequent development, but also provides a stable reference point when the AI loses context or requires multiple iterations. Although the context windows of current mainstream large language models have expanded to hundreds of thousands or even millions of tokens, the model's attention weight for early information significantly decays under ultra-long contexts (the so-called "lost in the middle" problem, systematically quantified in a 2023 study by Stanford's Nelson Liu et al.: the model's recall rate for information located in the middle of the context can drop by 30%~50% compared to the beginning and end positions). External document anchors can effectively compensate for this shortcoming.
Subsequently, the AI began breaking down the task, creating a series of subtasks and coding them one by one.

Automatic Compilation Verification: The Power of the Closed Loop
Since the Workflow explicitly wrote in the rule "after modifying code, compile and verify," the AI automatically enters the compilation verification stage after finishing coding. When encountering errors, the AI automatically locates and fixes them, with no human intervention required throughout.
Writing "after modifying code, compile and verify" into the rules is equivalent to implanting the Continuous Integration (CI) philosophy of software engineering into the AI — every change must pass build verification before it's considered complete. Continuous Integration was first proposed by the Extreme Programming (XP) community in the late 1990s. Martin Fowler and Kent Beck systematized it into a set of engineering practices: each developer integrates their code into the main trunk at least once a day, and every integration is verified through automated builds and tests. The core idea is to distribute integration risk throughout the development process rather than concentrating it at the end of the project through high-frequency, small-batch integration verification, thereby avoiding "Integration Hell" — discovering a large number of incompatibility issues between modules only at the end of the project. The value of CI is further amplified in the context of AI programming: an AI can generate hundreds of lines of code in a single pass. Without an immediate verification mechanism, errors will accumulate layer by layer across multiple generation rounds, ultimately forming untraceable "error debt." Researchers call this phenomenon "Hallucination Propagation" — an erroneous assumption introduced by the AI in the first generation round becomes context input for the second round, then gets further "rationalized" and amplified, forming a self-reinforcing chain of errors.
In traditional CI workflows, this relies on independent toolchains like Jenkins or GitHub Actions; while in the AI programming context, internalizing CI logic as an AI behavioral constraint through Workflow rules achieves an atomic closed loop of "every code generation comes with its own verification." This automatic "code — compile — fix errors" loop is the watershed for AI programming to move from "generating code snippets" to "delivering runnable results." The AI is no longer just a code completion tool, but is capable of taking responsibility for its own output and continuously iterating until it passes verification. The value of this constraint lies in externalizing human engineers' best practices into reusable, transferable rule files.
The Separation Strategy Between PC Development and Embedded Deployment
The author adopted a pragmatic development strategy: first develop and debug on a PC away from the embedded environment, then compile and run on the development board once the game logic and interface are basically stable.
"Verify on PC first, deploy to hardware later" is an effective layered testing strategy in the embedded software development field, commonly called "Host-Target separated development" in industry. The debugging cost of embedded hardware is far higher than that of the PC environment: flashing firmware, connecting the debugger, checking serial logs — each step introduces additional time overhead; while on a PC, using a simulator (such as the SDL simulator officially provided by LVGL) allows verification of UI rendering and interaction logic at the millisecond level. In safety-critical fields like aviation and automotive, the Host-Target separation strategy is even explicitly required by certification standards like DO-178C and ISO 26262, its importance having been fully validated in embedded engineering practice long ago. These standards require that before software runs on target hardware, it must complete unit testing and integration testing in the Host environment to ensure that hardware-related defects don't contaminate verification conclusions at the software logic level — in other words, an institutionalized embodiment of the "separation of concerns" principle in the field of safety engineering.
SDL (Simple DirectMedia Layer) is a cross-platform multimedia abstraction library, originally developed by Sam Lantinga in 1998, widely used for cross-platform porting of games and multimedia applications. LVGL redirects graphics rendering to a PC window through the SDL backend — low-level drawing calls like lv_draw_sw_blend are redirected to SDL's Surface operations, and touch input is simulated through SDL's mouse events — allowing the same business code to switch between PC and embedded targets without modification. SDL itself adopts a HAL design philosophy similar to LVGL, shielding the graphics system differences between platforms like Windows GDI, Linux X11/Wayland, and macOS Cocoa through a unified API, which is the fundamental reason it can serve as LVGL's PC simulation backend. SDL's cross-platform capability comes from its Driver Abstraction Layer design: each platform's specific implementation is encapsulated as an independent "backend driver," dynamically bound at runtime through a function pointer table, with upper-layer API calls completely decoupled from the underlying implementation. This design pattern is architecturally identical to LVGL's Display Driver Interface (lv_disp_drv_t). This "Hardware Abstraction Layer" (HAL) design centralizes and isolates platform-related code, and the business logic layer is unaware of the underlying hardware — this is precisely the technical foundation that enables the Host-Target strategy to be implemented.
The value of this strategy multiplies with the introduction of AI programming: the AI generates code at an extremely high frequency. If flashing and verification were required every time, iteration efficiency would be greatly reduced. By incorporating PC-side verification into the AI's automatic closed loop, over 90% of errors can be eliminated before entering real hardware, and the embedded deployment stage only needs to handle platform-specific issues, greatly reducing debugging complexity.
The first-generation interface "didn't feel attractive enough," so the author had the AI continue optimizing. After a few rounds of iteration, the blocks no longer overlapped, and the interface gradually became clean.

Real Pitfalls in the Embedded Environment
The process of migrating from PC to the development board wasn't smooth sailing, and the problems it exposed are precisely the most valuable parts of AI programming in real engineering:
-
Font path issue: After deploying to the board, text wasn't displayed. The author told the AI "text isn't displayed" and pointed out the code location. Upon inspection, the AI found that the font path was written as a relative path — the UI Builder path was inconsistent with the actual Lubanite path, causing resource loading to fail. After correction, the text was restored to normal. The root cause of this type of problem is that embedded systems usually lack a mature file system abstraction layer: relative paths on the PC side rely on the operating system's current working directory (CWD) mechanism, while the file system mount points in embedded Linux or bare-metal environments are often fixed (such as
/mnt/or/data/), requiring the use of absolute paths or injecting the resource base address through compile-time macros. A more thorough solution is to convert font resources into C language arrays using tools likexxdorbin2cand compile them directly into the firmware, fundamentally eliminating the file system dependency — LVGL officially calls this type of inline resource a "Built-in Font." Its essence is storing the bitmap data of glyphs in the form ofconstarrays in the Flash read-only section, avoiding file system dependency while allowing the compiler to optimize it into efficient read-only access. The working principle ofbin2c-type tools is to read the binary file byte by byte and write it into a C array in the hexadecimal literal0xXXformat, combined with compiler directives like__attribute__((section(".rodata")))to locate the array in Flash's read-only data section, with address mapping completed by the Linker Script at program startup. This is one of the most typical "environment difference traps" in embedded porting. -
Manual intervention steps: The author chose to manually complete the step of copying the UI Builder directory into Lubanite before compiling. This also reminds us that AI-assisted development doesn't mean fully automatic — when it comes to critical operations like environment configuration and directory migration, human control remains necessary.
It's worth noting that Claude Code is fundamentally different from traditional code completion tools (such as GitHub Copilot) when handling such problems. Traditional completion tools make local predictions based on "cursor context," essentially performing greedy sampling in the conditional probability space of a statistical language model, and are helpless in the face of cross-file, cross-toolchain path errors; while the Agent-mode Claude Code has the capability to retrieve code, analyze error logs, locate root causes, and automatically fix them, able to handle the complexity of real engineering.
From an architectural perspective, the core of the Agent mode is the "Tool Use Loop": the model not only outputs text, but can also call predefined tools (file read/write, shell execution, code search, network requests, etc.), and dynamically adjust its next action based on the tool's return results — this is a "Perceive-Reason-Act" closed-loop architecture, conceptually sharing the same lineage as control loops in robotics. This architecture was first systematically described in the 2023 ReAct (Reasoning + Acting) paper, and was subsequently widely adopted in API designs like OpenAI's Function Calling and Anthropic's Tool Use. ReAct's core innovation is interweaving "Chain of Thought" reasoning with external tool calls in the same generation stream — the model first uses natural language to reason about what to do next (Reason), then actually executes it through structured tool calls (Act), and the real results returned by the tools become the input for the next round of reasoning, forming a "thought — action — observation" triple loop. The results of each round of tool calls are appended to the context, becoming the input for the model's next step of reasoning, thereby achieving layer-by-layer decomposition and solution of multi-step problems. The key breakthrough of this mechanism is: the model's reasoning process is no longer limited to static knowledge in the training data, but can obtain runtime dynamic information (such as actual compile error output) through tool calls, elevating debugging capability from "pattern matching" to "evidence-based reasoning." This mechanism enables the AI to independently handle multi-step problems like a junior engineer, rather than staying at the level of "giving suggestions." Cross-platform path differences and resource loading problems like these are often the easiest pitfalls to fall into in embedded development, and the AI, given clear error feedback and code localization, demonstrated decent debugging capabilities.
Practical Takeaways: The Right Way to Use AI Programming
Synthesizing the entire project, several experiences of great reference value for developers can be distilled:
- Communication quality determines output quality. Spending time on good requirements clarification is more important than rushing to have the AI write code. The investment in the requirements phase is the highest-return stage of the entire project — Boehm's Law tells us that eliminating a requirements defect at this stage is equivalent to eliminating dozens of code defects in the testing phase.
- Plans should be committed to files. A structured plan document is a stable anchor for multiple iterations, and the foundation for recovery when the AI's context window is saturated or the session is interrupted. Documents are specifications, specifications are constraints, and constraints are quality assurance.
- Use Workflow rules to constrain AI behavior. Explicitly defining rules like "must compile and verify after modifying," externalizing software engineering best practices into reusable constraint files, lets the AI form an automatic closed loop and greatly reduces manual intervention. Workflow rule files should be brought into version control and reviewed and iterated just like code.
- Layered development reduces complexity. Verifying logic in the PC environment first, then migrating to target hardware, can effectively isolate problems and fully leverage the AI's advantage of high-frequency iteration. HAL design and the Host-Target separation strategy are the technical guarantees of this workflow.
- Preserve the boundary of human judgment. Critical nodes like directory migration and environment compilation still require human control — AI-assisted development doesn't equal full automation. The core value of human engineers lies in judgment about system boundaries, environment dependencies, and business constraints — this tacit knowledge is currently still difficult to fully encode into the AI's behavioral rules.
This Tetris project of under three hours, though small in scale, completely demonstrates the full workflow of AI from requirements, design, coding, and compilation to cross-platform deployment and debugging. It proves that: as long as the workflow is well-designed, AI is already capable of handling real, hardware-oriented embedded development tasks. For embedded developers, perhaps the most important takeaway from this case is: AI is not just a tool for writing business logic. Combined with an appropriate abstraction layer (such as LVGL's HAL design) and engineering constraints (Workflow rules), it is already able to participate in complete engineering projects with hardware deliverables.
Key Takeaways
Key Takeaways
Related articles

Altman Warns of AI Monopoly Risk: A Few Companies Controlling AI Would Be Extremely Dangerous
OpenAI CEO Sam Altman warns that AI controlled by a few companies would be very dangerous. We analyze the real threats, his complex motivations, and paths to breaking AI monopoly.

The ISNAD Framework: Building a Trust Verification Layer for Multi-Agent AI Systems Using a Millennium-Old Scholarly Tradition
The ISNAD framework adapts Islamic chain-of-transmission verification to build a trust layer for multi-agent AI systems, focusing on claim verification over agent authentication to combat hallucinations and silent failures.

Is Formal Language Theory Still Relevant in NLP? Deep Reflections Behind a Course Selection Dilemma
Formal Languages vs. Programming Language Principles—which course matters more for computational linguistics and NLP? A deep analysis from Chomsky Hierarchy to Lambda calculus to modern LLM theory.