KnightLight
Project Overview

KnightLight is a tile-based 2D puzzle-platformer where you light your way through the darkness. This game was developed during our sophomore GAM 200-250 courses, designed to create collaboration between designers and programmers in creating a C++ custom engine. Our programming team built the engine using Dear ImGui for its structure, integrating a wide range of features and components based on the designers’ needs.
In this project, I was both the Level Designer and UX/UI Designer. My contributions included:
-
Level Prototyping and Implementation: Designed and implemented three distinct main levels using tools like Tiled, integrating them into the engine through JSON files.
-
Pause Menu Design and Functionality: Developed the pause menu layout, incorporating interactive elements such as buttons, checkboxes, and sliders.
-
Main Menu Design, Art, Animations, and Functionality: Ensuring both aesthetic appeal and intuitive user experience, creating its visual assets, animations and systems.
-
Playtesting and Documentation: Conducted iterative playtesting sessions throughout development to refine gameplay and user interactions, documenting feedback in playtest reports.
-
Tooltip Design: Developed tooltips to enhance player understanding of game mechanics and interface elements.
Luminosity
Our team, which we named after the game’s premise, consisted of five programmers and two designers. The programmers worked on a range of tasks throughout development including:
-
Creating the editor interface
-
Implementing tile-based lighting systems
-
Importing levels into the engine via JSON
-
Developing physics and collision systems
-
Integration C# scripting for designer customization

As for designers, the Design Lead and I evenly divided tasks based on our specializations. The Design Lead focused on Technical Design and Systems Design, working on mechanics prototyping, implementation, and the polishing aspect of UX. I concentrated on Level Design, creating all level content, and UI Design, developing the visual and functional elements of the user interface.
Design Process
Research
In order to deepen my understanding of the puzzle-platformer genre, I played through our main inspiration, Hollow Knight. By analyzing this metroidvania game, I identified key level design principles that influenced my final designs, including:​
-
Backtracking: Hollow Knight uses extensive backtracking, where players revisit previous areas after unlocking new abilities. In KnightLight, this principle was adapted on a smaller and more linear scale to accommodate our compact level structure.
-
Foreshadowing: Entrances to high areas in Hollow Knight often foreshadow exits leading back to previous rooms. Similarly, KnightLight incorporated looping paths to create non-linear progression while maintaining simplicity.
-
Spiked Floor Ledges: In Hollow Knight, spike-filled floors often include small ledges to prevent players from directly falling into the hazards. In KnightLight, I implemented similar ledges as spikes are designed to be visible only when illuminated, reinforcing the game’s core lighting mechanic and aiding player navigation.


Additional research, including insights from other games used as inspiration, can be found in the KnightLight Design Guide
Ideation
First Semester: Prototyping and Concept Exploration

During our first semester, the engine was still under development and not yet ready for designers. As a result, we focused on brainstorming and prototyping ideas for the game. I designed level layouts, applying the principles identified during the research phase. Early concepts were sketched digitally using Procreate, refined in Tiled, and implemented in our Unity prototype project using Super Tiled2Unity.
The prototype levels showcased core mechanics such as walking, jumping, flashlight aiming, lighting lamps, and unlocking doors. We also experimented with features that were ultimately scrapped, including enemy types, cable connections between lamps and doors, and doors the player could enter to move to the next level.
To refine our ideas, we created weekly prototypes, conducted playtests, and compiled the results in detailed playtest reports. These reports contain feedback, highlighted key takeaways for both programmers and designers, and documented the evolution of KnightLight during the first semester. For an in-depth look at these prototypes and their impact on the final game, please refer to the Knight Light Playtest Reports.

Second Semester: Transition to Engine Development
With the engine ready for use in the second semester, new guidelines and limitations emerged. For instance, cable signifiers linking lamps and doors were removed, due to the engine not being able to support multiple tilesets in a single scene. This was replaced by a camera pan to the door when a lamp was activated, simplifying the visuals. Another example is the level scale adjustments. As player size, jump height and distance were standardized, all designs had to align with these new parameters.
These changes shaped the development of the official game levels. With a defined scope and set mechanics, I focused on creating levels that followed principles of progression, evolution, and expansion. Each level combines platforming and puzzle elements, offering challenges that feel engaging and cohesive with the context of KnightLight’s mechanics and theme.
Prototyping
Affordances
With a defined scope, we set our goal to design and implement three levels of content. Before drafting the levels, I created a list of all game mechanics and planned their order of introduction. The plan considered two player types and one unlockable ability:
-
Light Player
-
Regular player movement.
-
Can flash to trigger lamps and open doors.
-
Can move through vents.
-
When the knight armor is unlocked, the player can recall and float back to the armor, transforming back into the knight player.
-
-
Knight Player
-
Lower jump height than the light player
-
Can walk on hazards.
-
Equipped with a flashlight that illuminates the surroundings in a cone shape.
-
Cannot pass through vents.
-
Can switch to the light player, leaving the armor behind until the light player is recalled.
-
-
Spring Part (Unlockable Ability)
-
Allows the knight player to launch the light player by aiming with the mouse.
-


Mechanic Introduction Sequence
The player begins as the light player, and mechanics are introduced progressively to ensure smooth learning:
-
Movement: Basic controls using ‘A’ and ‘D’.
-
Jumping: Navigating platforms, including jumping through them.
-
Hazards: Introducing spiked floors that damage the player.
-
Interaction: Pressing ‘W’ to interact with tooltip signs, NPCs, or checkpoints.
-
Flash: Lighting up surroundings as the core mechanic.
-
Jumping down: Dropping through platforms using ‘S’.
-
Lamps and Doors: Triggering lamps with the flash to open their respective doors.
-
Ceiling Hazards: Spikes that damage the player from above
-
Vents: Pipes that teleport the light player between sections.
-
Knight Armor: Introducing the armor player and showcasing its inability to pass through vents.
-
Hazard Immunity: Demonstrating the armor player’s ability to walk on hazards.
-
Lower Jump: Requiring the light player to jump out and clear paths for the armor.
-
Spring Part: Unlocking the mechanic for launching the light player.
Level Design Approach
The levels followed a linear path designed to progressively introduce these mechanics while providing challenges. Applying the principles of evolution and expansion, each level increased in difficulty and complexity:
-
Evolution: Mechanics were refined and combined in new ways as the player progressed. For instance, Level 1 ends with a puzzle requiring the player to open multiple doors while avoiding ceiling spikes, building on earlier spiked floor challenges.
-
Expansion: Challenges became more elaborate, such as spiked floors increasing in length and frequency throughout the levels.
By structuring levels this way, players are able to learn new mechanics while feeling a gradual increase in challenge, ensuring a satisfying gameplay experience. This way, I was able to design multiple sections that featured different challenges. A comparison between sketched drafts and the final product in Tiled can be found here:


Level 1



Level 2


Level 3
Testing
During the second semester, I conducted three major playtests, each dedicated to testing one of the three levels in the game, with the last one featuring all levels as a full game playtest. Additional playtests focused on player movement, C# implementation within the engine, and the overall engine design.
The level-specific playtests were invaluable in identifying pain points, both in design and technical implementation. Feedback from these sessions allowed us to refine gameplay, address technical issues, and ensure a smoother player experience. Comprehensive documentation for all playtests, including observations, feedback, and key takeaways, is available here:
Implementation
The final level designs were successfully implemented in the final build of KnightLight. Here, you can find screenshots from the Tiled Editor, showcasing each level, along with a view of all tile layers including background or decoration elements. As well as object layers indicated by colored boxes. These object layers are critical in the levels as they are converted into engine archetypes when imported into the KnightLight Engine, allowing for player interaction and dynamic level behavior.
The Tiled editor served as a vital tool for organizing other archetypes essential to gameplay, such as checkpoints, lamps, doors, and other interactive objects. I developed a color coding system to differentiate between various types of objects, ensuring clarity in both design and development. This system also made collaborating with programmers easier, as they could quickly identify and map out the logic needed for each object layer.



For more detailed technical insights on importing Tiled maps into the KL Engine and understanding the significance of the color coding for different objects, refer to the Tiled Design Guide:
Reflection

If I had the chance to revisit this project, one of the key areas I would approach differently is optimizing repetitive code, particularly for UI scripts. For example, in the Pause Menu Manager script, where every UI element in the pause menu is instantiated when switching pause states, many functions repeatedly set properties for UI elements like position, scale, rotation, text, among others. This redundancy could have been reduced by creating a custom function such as:​
​
InstantiateText(Vec3 Position, Vec3 Scale, float Rotation, int Layer, string Text)
A function like this would allow inputting individual values to each of the parameters, simplifying the creation of UI elements by automating repetitive tasks. Depending on the complexity of the UI elements, custom functions could be further expanded to account for a broader range of parameters, offering greater flexibility. Looking back, this optimization would have significantly saved development time and made cleaner code.
Another aspect of reflection is feedback on the game’s length. Some players felt the game was short, which I attribute to Level 3 being the point where more dynamic mechanics, such as the knight armor and the spring part were introduced. Ending the game immediately after these mechanics were introduced made the conclusion feel somewhat abrupt or sudden. While this was partly due to time constraints, with Level 3 itself being finalized close to the project deadline, it’s clear that additional levels could have made a better gameplay experience.
However, feedback from some players suggests that the game felt like a demo for a larger project. This sentiment reassured me, as it reflected an understanding of the scope of student projects.
Looking ahead, I hope to revisit the KL Engine and potentially design additional content. This would allow me to fully utilize the mechanics and systems we built, while also incorporating the lessons learned from this development process.
Play Now
KnightLight is available on Steam, complete with unlockable achievements to enhance the experience and foster competitive engagement. I’d love for you to experience the world we’ve created. Your feedback is incredibly valuable, so feel free to share your thoughts on gameplay, mechanics, or overall experience. Hearing directly from players is invaluable and helps shape future projects!
UX/UI Design
Main Menu Opening Sequence

The main menu start sequence was designed to feel atmospheric and diegetic from the very first interaction. On launch, players are greeted with a “Left click to light up” prompt that syncs with the ambience soundtrack. Once pressed, the knight transitions into the title screen with an impactful animation.
Purpose
-
Establishes the tone for KnightLight, slowly revealing the world while giving players a moment to take it in before interacting.
-
Prevents accidental input during load.
-
Builds a clear visual pattern that matches the game’s lighting theme.
Technical Implementation
-
Implemented the transition using custom C# code and animation components instead of scene loads for seamless flow.
-
Designed fade-in animation curves for text prompts and UI elements using C#.
-
Added short input delay buffer to prevent early clicks during scene initialization.
-
Managed music transitions with audio group triggers that fade between “intro” and “menu” layers.
if (KeyPressed)
{
clicked = true;
ActivateMMButtons();
EntityComponentSetEnabled(KnightParticlesB1, ComponentType.eParticleEmitter, true);
EntityComponentSetEnabled(KnightParticlesB2, ComponentType.eParticleEmitter, true);
SpriteFadeOut(PressKeyPrompt, ref PKPAlpha, 0.15f, dt);
AnimationSetSequence(KnightSpriteA, "KnightLightUp");
if (!SoundPlayed)
{
SoundPlay("Teleport Error by Jerimee Id-521776 (recall)", "SFX", false, 0.4f);
SoundPlayed = true;
}
​
//Main menu buttons fade in
ButtonFadeIn(PlayButton, ref PlayButtonAlpha, 1f, dt);
ButtonFadeIn(OptionsButton, ref OptionsButtonAlpha, 1f, dt);
ButtonFadeIn(CreditsButton, ref CreditsButtonAlpha, 1f, dt);
ButtonFadeIn(QuitButton, ref QuitButtonAlpha, 1f, dt);
​
//Check if light up animation is over
bool LightUpOver = false;
AnimationIsDone(KnightSpriteA, out LightUpOver);
if (LightUpOver)
{
SpriteFadeOut(KnightSpriteA, ref KnightSpriteAlpha, 0.25f, dt);
EntityComponentSetEnabled(KnightSpriteB, ComponentType.eSprite, true);
}
}
else
{
if (Timer >= TimeToStart + 0.5f)
{
//Press key prompt changing colors
if (PressKeyPrompt != IntPtr.Zero)
{
if (isFadingIn)
{
SpriteFadeIn(PressKeyPrompt, ref PKPAlpha, 1.15f, dt);
if (PKPAlpha >= 230f)
{
isFadingIn = false; // Switch to fade out
}
}
else
{
SpriteFadeOut(PressKeyPrompt, ref PKPAlpha, 0.6f, dt);
if (PKPAlpha <= 95f)
{
isFadingIn = true; // Switch to fade in
}
}
}
}
}
Main Menu Interaction & Navigation

After the opening transition, players can navigate through the main menu’s options: Start, Options, Controls, and Quit. Each button has subtle color transitions and hover feedback that matches the in-game lighting aesthetic.
To preserve immersion, transitions between menu screens use soft camera movements and alpha fading instead of instant, abrupt switches. For example, selecting “Options” slides the camera up, revealing a panel with sliders for volume, and toggles for fullscreen and speedrun timers.
Technical Implementation
-
Built animations and hover color transitions for each button through C# code.
-
Created reusable menu navigation states to switch screens without reloading the scene.
-
Used dynamic camera movement to create visual continuity between different menu screens.
-
Implemented interactive sliders and toggles with custom event listeners for instant feedback.
Pause Menu System

The pause menu was designed to feel functional yet minimal, appearing instantly and clearly separating gameplay from the menu state. When opened, the game world subtly dims while audio pauses, allowing players to navigate without distraction.
Options like Restart, Main Menu, or Quit dynamically instantiate confirmations only when needed, reducing memory load and making the menu system modular and easy to extend.

The menu features quick access to game stats, settings, and controls, using a consistent visual hierarchy established by the main menu for familiarity.​
Technical Implementation
-
Developed modular submenus instantiated on demand for cleaner memory use.
-
Integrated audio group controls to pause gameplay sound while keeping UI sound effects active.
-
Added auto-pause on window focus loss, improving usability for PC players.
-
Displayed live statistics like playtime and collectibles, pulled from the save system.
Tooltip System

To help players learn mechanics naturally, I designed a tooltip system that appears contextually during the first encounters with key interactions. Each tooltip uses simple iconography and limited text to minimize interruption while reinforcing learning.​
Technical Implementation
-
Built tooltip logic using trigger zones and conditional display timers.
-
Designed fade-in and fade-out animations for smoother appearance during gameplay.
Design Takeaways




My UX goal in KnightLight was to merge atmosphere with clarity. Every interface element was designed to feel like a natural extension of the game’s world while maintaining functional simplicity.
By combining dynamic transitions, modular code structure, and consistent animation timing, I created a UI experience that complements the game’s light and shadow theme while remaining efficient and maintainable for future iterations.