how it works
This guide walks through the two main parts of Shadow Match Studio: baking (creating puzzle levels in the editor) and playing (how the game runs for the player).
Part 1: Creating a Level (Shadow Match Studio)
Baking is the process of turning a 3D scene into a puzzle level. You set up your scene, point your camera at it, then the system takes a picture of the shadow and saves it so the game can use it later. Find the ShadowMatchLevelData scriptable object I provided under Scriptable Objects/Levels.
Overview of the baking workflow
Create a new level (or start a new capture on an existing level).
Capture the starting rotation — where the object begins when the player starts the puzzle.
Capture the target rotation — the exact rotation that counts as “correct” (the shadow the player must match).
Bake the shadow — take a snapshot of that shadow and save it as an image (sprite) attached to the level.
After that, the level is ready to be played. Optionally you can export a frame snapshot (a pixel-perfect .png of the frame area) for art or reference. More on this below after the steps!
Baking workflow (detailed steps)
Step 3: Bake the shadow
Optionally position the Shadow Catcher Quad so its Z lines up with the picture frame, and position the Captured Shadow Display Quad slightly in front of it (as described in the Inspector).
In the Inspector, click CAPTURE AND BAKE SHADOW.
What happens:
A save dialog appears — choose where to save the shadow image (e.g. a PNG in your project).
The system renders the shadow from the object (at the target rotation) onto the shadow catcher and saves it as an image.
That image is imported as a sprite and assigned to the level as the “target shadow” the player must match.
If your config uses it, a comparison texture is also baked (lower resolution) for pixel‑based matching at runtime. The comparison texture is an optimization. It's a lower resolution (less pixels) for your GPU to iterate over to check if there's a match. A match is determined via the ShadowMatchComparison.compute shader by
Camera position, rotation, and field of view from the current scene are saved to the level so the game uses the same view when playing.
The target rotation is stored on the level so the game knows the correct answer (for rotation‑based matching or for snapping on solve).
After this, the Inspector will show that the bake is complete. You can reset the workflow to create another level or run through the steps again.
I'm saving all this data into a scriptable object for a couple reasons. One, is so you can have everything you need to take it and start building your own level loading system. In case you wanted to solve multiple puzzles in a row. Eg. Solve -> Click next button -> new object in a new pose is loaded up. The second reason is because I plan to include this loading functionality in the next update.
Optional: Export frame snapshot feature
You can export a frame snapshot (e.g. via the component’s context menu: Export Frame Snapshot).
This takes a picture of the frame area (using the frame bounds and shadow light) and saves it as a PNG. The interactable object is automatically hidden for this shot.
This is very useful if you have an artist/ai to design a texture around the baked winning shadow because it's the exact size needed to assign back to a frame's canvas material to have the shadows line up perfectly. I'll put a quick example below using gemini's nano banana. Please note this is a "quick and dirty" example! I really advocate for hiring an artist on fiver as this is a fun challenge to design something backwards around an existing cut out and you're sure to get a nice result from them.


If you're interested in this ai-game dev flow, i've given gemini my frame export, told it to create a compelling environment around the silhouette. Then I've asked it to remove the silhouette (so i have two images from the bot). Then in photoshop, I've overlaid the frame export image on the second image from gemini without the silhouette. An artist could do this much better than me!
Resetting the workflow
Click RESET WORKFLOW in the Inspector to go back to Step 0. You’ll see CREATE NEW LEVEL and START NEW CAPTURE again. Use this when you want to start a new level or a fresh capture session.
Part 2: Playing the Game (Shadow Match System)
When the game runs, the Shadow Match System loads a level and lets the player rotate the object until their shadow matches the baked target.
Loading a level
When the game starts (or when a level is selected), the system loads the level data:
The target shadow image is shown on the picture frame (the “answer” silhouette).
The camera position, rotation, and field of view from the level are used so the player sees the same view you had in the studio.
The interactable object is set to its initial rotation (the one you captured in Step 1).
The correct rotation is stored for checking the win condition (and for snapping on solve).
The puzzle is not active yet; the player cannot rotate until the puzzle is started.
Starting the puzzle
Something in your game starts the puzzle (e.g. the player clicks “Play,” talks to an NPC, or enters a trigger. By default I have it start when you click the interactable object). That calls StartPuzzle() on the system.
When the puzzle starts:
The camera moves to the level’s saved position and angle (smooth transition).
The UI for the puzzle is shown (e.g. match percentage, reset, quit).
The object can be rotated by the player (mouse, touch, or controller, depending on your input setup).
If the level uses pixel comparison, the system sets up the shadow catcher and a small camera that looks at it, and prepares to compare the live shadow to the baked target image.
The puzzle is now active: the player’s goal is to rotate the object until the shadow matches the target.
Matching (how the game decides “correct”)
The game can use one of two ways to decide when the player has won (configured in the level or default config):
Rotation matching The game compares the object’s current rotation to the saved target rotation. When they’re close enough (within the required threshold), the puzzle is solved. This is more performant than the pixel comparison method, but not advised for when you have an object with multiple symmetries, nor when you want to show the pixel match % UI. (Eg. a cube can cast the same shadow at dozens of rotations).
Pixel comparison The game compares the individual pixels of the realtime shadow against the captured silhouette. This uses an ultra-performant compute shader that runs on the GPU.
In both cases, the UI can show a match percentage so the player gets feedback as they rotate.
In the ShadowMatchConfig, you can set a Required Match Percentage Amount. If this is 93%, that means when the player matches 93% of the winning rotation, the puzzle will transition into the solved state and the PuzzleSolved event will fire. We have this because shadow match puzzles are quite annoying to get perfectly and players will get frustrated if they have to get it exactly perfect!.
When the puzzle is solved
When the match condition is met:
The puzzle state becomes Solved.
The object locks so the player can’t rotate it further.
Optionally, the object snaps to the exact target rotation and a solve effect plays (if configured). A note on the "solve snap" as it's called - if your object has multiple symmetries, be cautious that the winning rotations must be defined by you in the level asset. That means you are manually rotating your object, finding its winning Euler's (Rotation field displayed in the Inspector) and entering them into the Target Rotations list in the corresponding level data.
Your game can react to the StateChanged event (e.g. play a sound, show “You did it!,” load the next level).
Quit button
Quit — The player leaves the puzzle (e.g. back to the main game). The system cleans up (hides UI, stops rotation, releases comparison resources) and returns to Idle. You will need to customize this functionality based on your unique project.
Code
If you're a developer, you can check out the scripts under /Scripts. There are public functions for you to call to suite your own development environment. To avoid merge conflicts with future updates I will do to this asset, be cognizant of how you're editing these scripts. To make your own scene, i recommend copy+pasting the demo scene and changing its name, then working off of that. Then, you always have a reference to the given version and will never have merge conflicts when I update the asset.
Summary
Baking
You've setup your scene to frame your puzzle. Shadow Match Studio gives you a new or updated level asset.
Playing
You've pressed play in unity after baking and clicked on the object. Shadow Match System lets you play your puzzle.
Last updated