Build a Shift Game in Godot

Build and publish a 2D game where Shift flips gravity.

Introduction

30 Second Summary

A small game becomes memorable when one key changes what the player expects from the whole level. That surprise can make a short experience worth replaying.

In this project, you will build a one-level 2D game in Godot around the SHIFT theme for GitHub Game Off 2026. You will publish the project across GitHub for its source and itch.io for its playable browser build.

What You'll Build

You will play a browser level where the Shift key flips gravity on the way to a goal that reveals a win message.

By the end of this project, you'll have:

  • A playable 2D level where you move the player across the floor to reach a goal.
  • A gravity-flip mechanic that lets you land on the ceiling to clear an obstacle.
  • A public browser game you can share through itch.io, backed by a public GitHub repository where anyone can read the source.
  • Secret Mission: An optional challenge to push your game development skills further.

Are there any prerequisites?

You need a laptop, a free GitHub account, and an itch.io login. No previous game development experience is required because Step 1 covers installing Godot and opening the project.

Before We Start

A public game needs a computer with internet access. Missing access can stop the project before the first scene opens.

This readiness check confirms your browser access. It also separates public publishing from the time-limited jam entry.

In this step, get ready to:
  • Confirm your browser can reach both publishing services.
  • Check your publishing-account readiness.
  • Choose the route that matches the jam deadline.
Confirm your browser access

GitHub hosts the source code you publish later. itch.io hosts the playable browser build.

  • Press Cmd+Space on macOS or the Windows key on Windows to open your app search.
  • Type the name of the web browser installed on your computer.
  • Select the web browser from the search results.

You should see a browser window with an address bar.

You should see the GitHub homepage in one tab. You should see the itch.io homepage in the other tab.

Check your account readiness

Publishing needs a usable account on each service. This check shows whether you can sign in now or need to create an account during setup.

Your credentials stay inside each service's sign-in page, so they never enter the project.

  • Review the GitHub page header to determine whether your account is signed in.
  • Sign in with your existing GitHub account if the page shows you are signed out.
  • Open the GitHub account-creation path if you do not have an account.
  • Review the itch.io page header to determine whether your account is signed in.
  • Sign in with your existing itch.io account if the page shows you are signed out.
  • Open the itch.io account-creation path if you do not have an account.

That check removes the account surprise before setup begins. You now know which accounts are ready to use.

Choose your publishing route

GitHub Game Off 2026 entries close on December 1, 2026 at 13:37 PST. The timing determines whether the jam-entry route is available to you.

Before you compare the dates, do you think a closed jam prevents you from publishing the game publicly?

  • Compare your current date with the jam deadline.
  • Choose the jam-entry route if the deadline has not passed.
  • Choose the public-publishing-only route if the deadline has passed.

A closed jam removes the entry option. You can still publish the game on itch.io with its source code on GitHub.

Before your final access check, do you expect both publishing pages to reload successfully?

  • Refresh the GitHub tab to confirm your internet connection can reach the service.
  • Refresh the itch.io tab to confirm your internet connection can reach the service.

Both pages should reload without an access error. This confirms your computer can reach the services used to publish the finished project.

Your starting checks are complete. Next, you will set up the tools and create the empty game project.

Create Your Project and Repository

Before the game has a player, it needs a stable home. A public GitHub repository protects the project history from the first file.

The local side needs Godot 4.x plus a folder connected to that repository. This foundation keeps every later scene inside one project history.

In this step, get ready to:
  • Create a public repository with an initial README.
  • Prepare Git plus Godot 4.x.
  • Create the local Godot project inside the connected repository.
Create the public repository

A repository gives your game a public address. Its README becomes the first project description that visitors see.

  • Open the new repository page on GitHub in your browser.
  • Sign in to your GitHub account if prompted.
  • Select your personal account from the Owner menu.
  • Enter shift-key-game in the Repository name field.
  • Select Public as the repository visibility.
  • Select Add a README file.
  • Click Create repository.

Your project now has a public home. Its README.md gives visitors a clear front page.

  • Click Code above the repository file list.
  • Select HTTPS.
  • Copy the repository URL.
  • Record the copied URL here: https://github.com/YOUR-USERNAME/shift-key-game.git.

Why copy the HTTPS URL?

The URL identifies the exact repository that Git should copy. Cloning it also creates a remote named origin for later pushes.

Prepare the local tools

Git connects the local project folder to GitHub. Godot supplies the editor where you build the game.

  • Press Cmd+Space on macOS or the Windows key on Windows.
  • Type Terminal on macOS or PowerShell on Windows.
  • Press Enter to open the terminal.
  • Check whether Git is available by running this command:
git --version

What does this command do?

The command asks Git to print its installed version. A version response confirms that the terminal can find Git.

✔️ I see a Git version

Git is ready to create the local connection to your repository.

ⓧ Command not found

Git needs to be installed before the repository can be cloned. Choose the instructions for your computer.

macOS

macOS opens a system installation dialog after the next command. The download can take a few minutes.

  • Start the Xcode Command Line Tools installer by running this command:
xcode-select --install
What does this command do?

The command asks macOS to install its developer command-line tools. Those tools include Git.

  • Complete the installation using the macOS dialog.
  • Return to the terminal after the installation finishes.
  • Confirm that Git is available by running the version check again:
git --version
What should I see?

The terminal prints a Git version. This confirms the installation succeeded.

Windows

  • Open the official Git for Windows download page.
  • Download Git for Windows/x64 Setup.
  • Open the downloaded installer from your Downloads folder.
  • Complete the installer using its default selections.
  • Return to PowerShell after the installation finishes.
  • Confirm that Git is available by running this command:
git --version
What should I see?

PowerShell prints a Git version. This confirms the installation succeeded.

Git still unavailable?

Close the current terminal after installation. Open a fresh terminal so it can load the updated command path.

If the command still fails, help me diagnose why Git is unavailable.

Godot is self-contained on macOS and Windows. The standard build runs after you extract the download.

  • Press Cmd+Space on macOS or the Windows key on Windows.
  • Type Godot into the search bar.
  • Open the Godot result if one appears.
  • Choose the tab below that matches what you see.

✔️ I see Godot 4.x

Godot 4.x is ready. Keep the Project Manager open for the project creation step.

ⓧ I see an older version

The older editor can stay on your computer. Download the standard Godot 4.x build for this project.

macOS

  • Close the older Godot editor.
  • Open the official Godot download page for macOS.
  • Download the standard Godot Engine build.
  • Extract the downloaded archive in your Downloads folder.
  • Open the extracted Godot app from Finder.

The Project Manager now shows a Godot 4.x version.

Windows

  • Close the older Godot editor.
  • Open the official Godot download page for Windows.
  • Download the standard Godot Engine build for your computer.
  • Extract the downloaded archive in your Downloads folder.
  • Open the Godot executable from the extracted folder.

The Project Manager now shows a Godot 4.x version.

ⓧ Godot is not installed

Install the standard Godot 4.x build for your computer. No system-wide installer is required.

macOS

The Project Manager opens with a Godot 4.x version.

Windows

  • Open the official Godot download page for Windows.
  • Download the standard Godot Engine build for your computer.
  • Extract the downloaded archive in your Downloads folder.
  • Open the Godot executable from the extracted folder.

The Project Manager opens with a Godot 4.x version.

Godot still won't open?

Confirm that you extracted the archive before opening the app. Running the file from inside the archive can prevent it from starting correctly.

Check that you downloaded the standard build for your operating system. Help me troubleshoot why Godot 4 will not open.

Clone the repository and create the project

Cloning copies the README to your computer. It also initializes the local Git repository with the GitHub remote already attached.

  • Return to the terminal from the tool check.
  • Move to your Desktop by running the first command below. Clone the repository by running the second command:
cd ~/Desktop
git clone [[YOUR_REPO_URL="https://github.com/YOUR-USERNAME/shift-key-game.git"]]

What do these commands do?

  • The first command moves the terminal to your Desktop.
  • The second command creates the shift-key-game folder.
  • Git downloads the repository history plus README.md.
  • Git records the copied GitHub URL as origin.
  • Confirm that the cloned folder contains the README by running this command:
ls shift-key-game

What does this check prove?

The command lists the contents of the cloned folder. Seeing README.md proves that Git copied the repository to your Desktop.

You should see README.md in the terminal output.

Clone not completing?

Confirm that the URL ends with shift-key-game.git. Copy it again from the repository's Code menu if needed.

If Git reports that the destination already exists, inspect the existing shift-key-game folder before removing anything. Help me resolve this clone problem safely.

The Project Manager now needs to place the game files inside that cloned folder. This keeps the README beside the Godot project files.

  • Switch back to the Godot Project Manager.
  • Click Create in the top-left corner.
  • Enter Shift Key Game in the Project name field.
  • Click Browse beside the project path.
  • Select the shift-key-game folder on your Desktop.
  • Turn off Create Folder so Godot uses the cloned folder directly.

Why use Compatibility?

The finished game needs to run in a web browser. The Compatibility renderer supports web exports plus the 2D features used in this game.

  • Select Compatibility from the Renderer options.
  • Select Git under Version Control Metadata.
  • Click Create.

The folder warning can look alarming. You are choosing the cloned repository on purpose, so its README stays beside the game files.

  • Confirm that Godot can create the project in the non-empty folder.
  • Select 2D from the workspace switcher after the editor opens.

That's the foundation in place. The empty 2D workspace is open inside your connected project folder.

Before you run the final check, do you expect Git to recognize both the local project files plus the GitHub remote?

  • Return to the terminal.
  • Verify the local repository plus its remote connection by running these commands:
cd ~/Desktop/shift-key-game
git status
git remote -v

What do these checks prove?

  • The first command moves the terminal into the Godot project folder.
  • The git status command confirms that the folder is a local Git repository.
  • The git remote -v command displays the remote URLs used for fetches plus pushes.

Git reports the new Godot project files in the local repository. The remote list shows origin with your shift-key-game GitHub URL.

Your public repository now has a matching local Godot project. Next, you will build the player plus the floor inside this 2D workspace.

Build the Player and Floor

Your empty Godot project already has a home on GitHub. It now needs a playable scene that turns the editor canvas into a game.

A CharacterBody2D gives you a code-driven player. A StaticBody2D gives that player a solid surface to land on.

In this step, get ready to:
  • Build a framed level with a visible floor.
  • Create a player with artwork and collision.
  • Add horizontal movement and gravity.
Build the level surface

A scene tree separates each game object's responsibilities. Visual nodes draw the level while collision nodes define the solid geometry.

  • Click 2D Scene in the Scene dock.
  • Double-click the new root node in the Scene dock.
  • Enter Main as the node name.

The Main node now acts as the container for your complete level.

  • Select Main in the Scene dock.
  • Click Add Child Node at the top of the Scene dock.
  • Search for Camera2D in the dialog.
  • Select Camera2D from the results.
  • Click Create.
  • Set the camera's Position to X 480 and Y 270 in the Inspector.

The camera now centers the playable area around the floor and boundaries you are about to add.

  • Select Main in the Scene dock.
  • Click Add Child Node.
  • Search for StaticBody2D.
  • Select StaticBody2D from the results.
  • Click Create.
  • Rename the new node to Floor in the Scene dock.
  • Set the floor's Position to X 480 and Y 500.

The floor body now occupies the bottom of the camera frame. Its children provide the artwork and solid surface.

  • Select Floor in the Scene dock.
  • Click Add Child Node.
  • Search for Sprite2D.
  • Select Sprite2D from the results.
  • Click Create.
  • Rename the new node to Artwork.
  • Drag icon.svg from the FileSystem dock into the artwork's Texture property.
  • Set the artwork's Scale to X 7.5 and Y 0.625.

You can now see a wide floor across the bottom of the 2D viewport.

  • Select Floor in the Scene dock.
  • Click Add Child Node.
  • Search for CollisionShape2D.
  • Select CollisionShape2D from the results.
  • Click Create.
  • Assign a new RectangleShape2D through the Shape resource menu.
  • Set the rectangle's Size to X 960 and Y 80.

Why separate artwork and collision?

The Sprite2D controls what you see. The CollisionShape2D controls where physics bodies stop.

Keeping those jobs separate lets you change the game's appearance without changing its movement rules.

The boundary colliders are the fiddliest part because they stay invisible during normal play. Their positions form a ceiling plus two side walls around the camera frame.

  • Select Main in the Scene dock.
  • Click Add Child Node.
  • Search for StaticBody2D.
  • Select StaticBody2D from the results.
  • Click Create.
  • Rename the new node to WorldBounds.

The WorldBounds body groups the invisible surfaces that keep the player inside the level.

  • Select WorldBounds.
  • Click Add Child Node.
  • Search for CollisionShape2D.
  • Select CollisionShape2D from the results.
  • Click Create.
  • Rename the new node to CeilingBoundary.
  • Assign a new RectangleShape2D to its Shape property.
  • Set its Size to X 960 and Y 40.

The ceiling now has the correct dimensions. Its position places it above the player.

  • Set CeilingBoundary to X 480 and Y 20.
  • Add a fresh CollisionShape2D child to WorldBounds with the Add Child Node button.
  • Rename the new node to LeftBoundary.
  • Assign a new RectangleShape2D to its Shape property.
  • Set its Size to X 40 and Y 540.
  • Set LeftBoundary to X 20 and Y 270.

The left side of the level is now sealed. One matching collider closes the right side.

  • Add a fresh CollisionShape2D child to WorldBounds with the Add Child Node button.
  • Rename the new node to RightBoundary.
  • Assign a new RectangleShape2D to its Shape property.
  • Set its Size to X 40 and Y 540.
  • Set RightBoundary to X 940 and Y 270.

Your camera frame now contains a visible floor plus invisible collision boundaries on three sides.

  • Press Cmd+S on macOS or Ctrl+S on Windows.
  • Enter main.tscn if the Save Scene As dialog opens.
  • Click Save.
  • Press F6 to run the current scene.

You will see the wide floor across the lower part of the game window. The level now has a visible surface and a fixed camera frame.

Floor missing from the game window?

Check that Artwork is a child of Floor. Confirm that icon.svg appears in its Texture property.

Check that the floor is positioned at X 480 and Y 500. Help me diagnose why my floor is outside the Godot camera frame.

Create the moving player

A character body follows movement code instead of falling automatically. Its script must apply gravity before move_and_slide() resolves contact with the floor.

  • Stop the running scene with F8.
  • Select Main in the Scene dock.
  • Click Add Child Node.
  • Search for CharacterBody2D.
  • Select CharacterBody2D from the results.
  • Click Create.
  • Rename the new node to Player.
  • Set the player's Position to X 160 and Y 200.

The Player node now sits above the floor. Its starting height leaves enough space to make gravity visible.

  • Select Player.
  • Click Add Child Node.
  • Search for Sprite2D.
  • Select Sprite2D from the results.
  • Click Create.
  • Rename the new node to Artwork.
  • Drag icon.svg into the artwork's Texture property.
  • Set the artwork's Scale to X 0.25 and Y 0.25.

You can now see the player as a small square above the floor in the 2D viewport.

  • Select Player.
  • Click Add Child Node.
  • Search for CollisionShape2D.
  • Select CollisionShape2D from the results.
  • Click Create.
  • Assign a new RectangleShape2D to its Shape property.
  • Set the rectangle's Size to X 32 and Y 32.

The collision rectangle now matches the player's visible size. This gives the floor a precise shape to support.

  • Select Player in the Scene dock.
  • Click Attach Script above the scene tree.
  • Set the script path to res://player.gd.
  • Click Create.
  • Replace the generated script with this movement code:
extends CharacterBody2D

const SPEED = 300.0

func _physics_process(delta: float) -> void:
    # Add the project gravity while the player is airborne.
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Read horizontal input and update the player's speed.
    var direction := Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    # Move the player and resolve contact with solid bodies.
    move_and_slide()

What does this movement code do?

  • The SPEED constant controls the player's horizontal movement rate.
  • The get_gravity() call adds the project's gravity while the player is airborne.
  • The Input.get_axis() call reads the built-in left and right movement actions.
  • The move_and_slide() call moves the player while resolving contact with the floor and boundaries.
  • Save player.gd.
  • Save main.tscn.

Before you run the scene, do you expect the player to pass through the floor or settle on top of it?

  • Press F6 to run the current scene.

You will see the player fall from its starting position. It stops on top of the floor because both bodies have matching collision shapes.

That is your first physics loop working. The player now responds to gravity and lands on level geometry.

Player falling through the floor?

Confirm that each CollisionShape2D is a direct child of its physics body. Confirm that both shapes contain a RectangleShape2D resource.

Check the Debugger panel for a script problem. Help me find why my CharacterBody2D falls through a StaticBody2D floor.

✔️ Awesome, I've got everything!

Great. Double-check that you saved player.gd and main.tscn.

ⓧ I'd like to double check the full code

extends CharacterBody2D

const SPEED = 300.0

func _physics_process(delta: float) -> void:
    # Add the project gravity while the player is airborne.
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Read horizontal input and update the player's speed.
    var direction := Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    # Move the player and resolve contact with solid bodies.
    move_and_slide()
Test movement and landing

A working controller must prove two behaviors. The player needs to land on the floor and respond to horizontal input.

  • Stop the current test with F8.

Before you run the full project, predict where the player will stop after gravity takes over.

  • Click Run Project in the top-right editor toolbar.
  • Click Select when Godot asks for the main scene.
  • Double-click main.tscn in the file dialog.

You will see the player fall and settle on the floor. Godot now uses main.tscn as the project's starting scene.

  • Hold the Right Arrow key.

You will see the player move right while remaining on the floor.

  • Hold the Left Arrow key.

You will see the player move left without passing through the floor. The side boundaries keep it inside the level frame.

  • Release the movement key.

The player slows to a stop and remains supported by the floor. Your first playable level is running.

Player not moving sideways?

Confirm that player.gd is attached to Player. Check that the script uses ui_left and ui_right with matching capitalization.

Confirm that the running scene contains the scripted Player node. Help me troubleshoot why my Godot player lands but does not move horizontally.

  • Press F8 to stop the running game.

Your level now has a controllable player and solid world geometry. Next, you will make the Shift key reverse gravity and send the player toward the ceiling.

Add Shift Gravity

Your player can already cross the level. Gravity still pulls in only one direction.

This step turns Shift into your core mechanic. Godot's Input Map gives the key press a named action.

The player script reads that action to reverse gravity.

In this step, get ready to:
  • Bind the Shift key to a gravity-flip action.
  • Add a collidable ceiling above the player.
  • Reverse gravity each time you press Shift.
Bind Shift to the gravity flip

An input action separates the physical key from the behavior it triggers. This keeps the control editable without changing the movement logic.

  • In the Godot editor from earlier, click Project in the top menu.
  • Select Project Settings.
  • Select the Input Map tab.
  • Enter flip_gravity in the action field at the top.
  • Click Add.
  • Click the + button beside flip_gravity.
  • Press Shift while Listening for Input... is selected.
  • Click OK.

The flip_gravity row now shows Shift as its input event. Your core control is wired into Godot.

  • Click Close to return to your level.

Can't see the Shift binding?

Expand the flip_gravity row. Confirm that a keyboard event appears beneath it.

If the action is empty, use its + button again. Help me check my Godot Input Map action.

Build a ceiling collider

The upward fall needs a solid surface above the player. Duplicating the floor's StaticBody2D keeps its visible artwork aligned with its CollisionShape2D.

  • Select the floor body in the Scene dock.
  • Right-click the selected floor body.
  • Click Duplicate.

That shortcut preserves the collision setup you already proved. The Scene dock now contains a second copy of the floor body.

  • Right-click the duplicated body in the Scene dock.
  • Click Rename.
  • Enter Ceiling as the node name.
  • Drag the Ceiling body to the top edge of the level in the 2D viewport.

You can now see a horizontal surface above the player. Its copied collision shape moves with the artwork.

  • Save the main level scene.
  • Click the Play button in the top-right toolbar.

You should see the floor below the player. You should also see the new ceiling above it.

  • Stop the running scene with the Stop button.

Can't see the ceiling?

Confirm that you moved the duplicated StaticBody2D body. Moving only its artwork leaves the collision shape behind.

Keep the ceiling inside the camera or viewport framing from your main level. Help me position my ceiling and collision shape.

Reverse the player's gravity

A CharacterBody2D receives gravity through its movement script. A signed direction value lets the same gravity calculation point down or up.

The up_direction property tells move_and_slide() which side counts as the floor. It must stay opposite to the current gravity direction.

  • Switch back to the movement script attached to the player.
  • Add a numeric gravity-direction state beside the existing gravity value. Initialize it to 1 so gravity begins by pointing down.
  • Multiply the existing vertical gravity update by the gravity-direction state.
  • Save the player movement script.
  • Run the main level with the Play button.

The player should still fall downward. It should stop on the floor as before.

  • Stop the running scene with the Stop button.
  • Return to the player movement script.
  • Add a branch that uses Input.is_action_just_pressed() to detect flip_gravity.
  • Negate the gravity-direction state inside that branch so 1 becomes -1 after one press.
  • Update up_direction from the gravity-direction state before move_and_slide() runs.

How does the flip work?

  • A direction of 1 keeps the vertical force pointing down.
  • A direction of -1 reverses the vertical force so it points up.
  • Input.is_action_just_pressed() changes the direction once for each key press.
  • up_direction keeps collision handling aligned with the new direction.
  • Save the player movement script.

Before you test it, predict where the player will land after one press of Shift.

  • Run the main level with the Play button.
  • Press Shift once after the player lands on the floor.

You should see the player fall upward. It should stop when it reaches the ceiling.

  • Use your existing horizontal movement controls while the player rests on the ceiling.

The player should move sideways without passing through the ceiling.

  • Press Shift again.

The player should fall back down. It should land on the floor again.

You have just made the SHIFT theme playable. One key now changes how the whole level behaves.

Gravity not flipping correctly?

If Shift does nothing, confirm that the script checks flip_gravity with the same spelling used in the Input Map.

If the player moves upward without stopping, confirm that the ceiling body still contains its CollisionShape2D.

If the player reaches the ceiling but slides incorrectly, confirm that up_direction points opposite to gravity before move_and_slide() runs. Help me debug my gravity-flip movement.

Your level now has its defining mechanic. Next, you will turn that movement challenge into a complete level with an obstacle and a goal.

Create the Goal and Win State

Your gravity-flipping player now travels across the Godot level. The level still needs a reason to use that power.

One solid obstacle creates a route choice. A distant goal turns that choice into a finish line.

In this step, get ready to:
  • Build one solid obstacle that makes gravity flipping useful.
  • Add a visible goal with a hidden win message.
  • Connect the goal trigger to the win state.
Add the obstacle route

A StaticBody2D gives the obstacle a place in the physics world. A matching CollisionShape2D blocks the player.

A ColorRect makes that boundary visible.

  • Select the root node of your main level in the Scene dock.
  • Click Add Child Node at the top of the Scene dock.
  • Enter StaticBody2D in the search field.
  • Select StaticBody2D from the results.
  • Click Create.

You will see a new StaticBody2D beneath the level root in the Scene dock.

  • Rename the new node to Obstacle.
  • Move Obstacle into the middle section of the level.
  • Select Obstacle in the Scene dock.
  • Click Add Child Node.
  • Enter ColorRect in the search field.
  • Select ColorRect from the results.
  • Click Create.
  • Choose a contrasting color from the Color property in the Inspector.
  • Resize the rectangle into a vertical block that covers the lower route.

You should now see the obstacle in the level viewport. Leave enough space above it for the player to travel along the ceiling.

  • Center the ColorRect over the Obstacle origin.
  • Select Obstacle in the Scene dock.
  • Click Add Child Node.
  • Enter CollisionShape2D in the search field.
  • Select CollisionShape2D from the results.
  • Click Create.
  • Assign a new RectangleShape2D resource to the Shape property.
  • Resize the collision rectangle to match the visible obstacle.

Before you test the obstacle, predict whether the player can reach the space above it without flipping gravity.

  • Save the main level scene.
  • Click Run Project in the top toolbar.
  • Move the player into the lower side of the obstacle.

The player stops against the visible block. The open route remains reachable along the ceiling.

  • Press Shift to flip gravity.
  • Move through the open route above the obstacle.
  • Click Stop in the top toolbar.

That is your first level-design win. The gravity mechanic now solves a visible navigation problem.

Player passing through the obstacle?

Check that CollisionShape2D is a child of Obstacle. Confirm that its rectangle covers the same space as the visible ColorRect.

Make sure the collision shape is not disabled. Help me fix an obstacle the player can pass through in Godot.

Build the goal and win message

An Area2D detects bodies entering its collision region without becoming a solid wall. This makes it a useful finish trigger.

  • Select the root node of the main level in the Scene dock.
  • Click Add Child Node.
  • Enter Area2D in the search field.
  • Select Area2D from the results.
  • Click Create.
  • Rename the new node to Goal.
  • Move Goal beyond the obstacle near the far side of the level.
  • Leave clear space between Goal and the floor.
  • Select Goal in the Scene dock.
  • Click Add Child Node.
  • Enter ColorRect in the search field.
  • Select ColorRect from the results.
  • Click Create.
  • Choose a goal color that stands out from the obstacle.
  • Resize the goal artwork to about twice the player's width.
  • Center the goal artwork over the Goal origin.

You should see a distinct finish marker beyond the obstacle. Its location gives the level a clear direction.

  • Select Goal in the Scene dock.
  • Click Add Child Node.
  • Enter CollisionShape2D in the search field.
  • Select CollisionShape2D from the results.
  • Click Create.
  • Assign a new RectangleShape2D resource to the Shape property.
  • Resize the goal collision rectangle to match its artwork.
  • Confirm that Monitoring is enabled on Goal.

How does the goal detect the player?

The Goal area watches its collision region for physics bodies. The player's CharacterBody2D can trigger the goal without being blocked by it.

Keeping the goal clear of the floor prevents the floor body from entering its detection region.

  • Save the main level scene.
  • Click Run Project.
  • Travel past the obstacle.
  • Move the player through the goal artwork.

You should see the complete route in action. The player can pass through the goal because it acts as a trigger.

  • Click Stop in the top toolbar.

The finish marker now needs a visible response. A screen-space message gives the player immediate confirmation.

  • Select the root node of the main level in the Scene dock.
  • Click Add Child Node.
  • Enter CanvasLayer in the search field.
  • Select CanvasLayer from the results.
  • Click Create.
  • Rename the new node to WinMessage.

Why use a CanvasLayer?

A CanvasLayer draws its interface children independently from the level. The message stays fixed on the screen while the player moves through the world.

  • Select WinMessage in the Scene dock.
  • Click Add Child Node.
  • Enter Label in the search field.
  • Select Label from the results.
  • Click Create.
  • Enter YOU WIN in the Text property.

The win message is now visible in the level editor.

  • Resize the label until the full message has room.
  • Move the label near the center of the game viewport.
  • Select WinMessage in the Scene dock.
  • Disable the Visible property in the Inspector.
  • Save the main level scene.

The message is hidden in the editor. The goal event will reveal the entire WinMessage layer.

Connect the win state and play the level

A signal announces that an event occurred. The goal's signal can call the win layer's built-in display method.

This connection is a little fiddly because the signal sends one body argument. The show() method expects zero arguments.

  • Select Goal in the Scene dock.
  • Open the Signals tab beside the Inspector.
  • Double-click body_entered(body: Node2D).
  • Click Advanced in the connection window.
  • Select WinMessage as the receiver node.
  • Set Unbind Signal Arguments to 1.
  • Choose show() as the Receiver Method.
  • Click Connect.

What does this connection do?

  • The body_entered signal fires when the player enters the goal region.
  • The unbind setting drops the body argument before calling the receiver.
  • The show() method makes WinMessage visible.
  • Save the main level scene.

Before you play, do you expect the message to appear before the player touches the goal?

  • Click Run Project.

The level starts with YOU WIN hidden. The player can move normally from the starting position.

  • Move toward the obstacle.
  • Press Shift to take the open route.
  • Travel past the obstacle.
  • Enter the Goal region.

You will see YOU WIN near the center of the screen. Your one-level game now has a playable beginning plus a visible finish.

Win message not appearing?

Confirm that the goal's CollisionShape2D overlaps the player. Check that Monitoring remains enabled on Goal.

Open the goal's Signals tab to confirm that body_entered connects to show() on WinMessage. Help me diagnose my Godot goal trigger.

✔️ My level reaches the win state

Great. Save the main level scene with the working goal connection.

ⓧ I'd like to double check the scene

  • Confirm the main level contains the player plus the floor and ceiling.
  • Confirm Obstacle has visible artwork plus a matching CollisionShape2D.
  • Confirm Goal is an Area2D with visible artwork plus a matching CollisionShape2D.
  • Confirm WinMessage is a hidden CanvasLayer containing the YOU WIN label.
  • Confirm entering Goal reveals WinMessage.

Your game now has a complete challenge plus a clear win state. Next, you will export the finished level so other people can play it in a browser.

Publish Your Web Build

Your complete level now runs from start to finish in Godot 4.x. An editor-only game has no public address for players to visit.

A browser export packages the level as an HTML5 game. In this step, you will host that build on itch.io through a public game page.

In this step, get ready to:
  • Export the complete level as a browser build.
  • Package the exported files for itch.io.
  • Publish a public game page that runs the level in a browser.
Export the game for the web

Export templates turn your project resources into files that another platform can run. The Web template creates the browser version of your finished level.

  • Switch back to the Godot editor from earlier.
  • Select Editor from the top menu.
  • Select Manage Export Templates....

The template manager shows whether Web support is ready. The next action depends on the status shown for the Web template.

✔️ Web is installed

Web shows as installed in the template manager. Your editor already has the files needed to create the browser build.

  • Close the export template manager.

ⓧ Web is not installed

The template download is the slowest part of this export. Keep the manager open while its progress indicator is moving.

  • Select the checkbox beside the Web template.
  • Click Install Selected Templates.
  • Wait for the Web template to show as installed.
  • Close the export template manager.

That download completes the export pipeline. Godot can now package your level for a browser.

  • Select Project from the top menu.
  • Select Export.
  • Click Add... at the top of the export window.
  • Select Web as the export preset.

Why Keep the Web Defaults?

The default single-threaded Web export avoids the special server headers required by threaded builds. This makes the exported game compatible with more hosting platforms.

The Web preset also sizes the game canvas for the browser window. That behavior fits itch.io's browser player.

  • Click Export Project.
  • Select Desktop in the file picker.
  • Create a folder named shift-key-game-web on your Desktop.
  • Open the new shift-key-game-web folder.
  • Enter index.html as the export file name.
  • Click Save to create the Web build.

Godot writes index.html beside the supporting game files. Together, those files contain the complete playable level.

Before you test the export, do you expect the browser version to preserve the gravity flip and win state?

  • Close the export window.
  • Click the web test button between the stop button and the play-scene button in the editor toolbar.
  • Start the level in the browser.
  • Press Shift to flip gravity.
  • Reach the goal to complete the level.

You should see the player switch between the floor and ceiling. Reaching the goal should display the same win message you saw in the editor.

Browser Test Not Starting?

Confirm that the Web preset is selected in the export window. Check that the Web template shows as installed.

If the browser opens without the game, export again with the file name index.html. Help me troubleshoot my Godot Web export.

Package and upload the web build

This part is fiddly because itch.io needs a ZIP archive with index.html at its top level. Compress the files inside shift-key-game-web so the entry file stays in the correct place.

macOS

  • Press Cmd+Space to open system search.
  • Type Finder.
  • Press Enter to open Finder.
  • Select Desktop in the Finder sidebar.
  • Open the shift-key-game-web folder.

You should see index.html beside the supporting Web build files. These are the items that belong at the top level of the archive.

  • Press Cmd+A to select every exported file.
  • Control-click the selected files.
  • Choose Compress from the shortcut menu.
  • Rename Archive.zip to shift-key-game-web.zip.

Finder creates shift-key-game-web.zip inside the export folder. The archive now contains every file required by the game.

Windows

  • Press the Windows key to open system search.
  • Type File Explorer.
  • Press Enter to open File Explorer.
  • Select Desktop in the File Explorer sidebar.
  • Open the shift-key-game-web folder.

You should see index.html beside the supporting Web build files. These are the items that belong at the top level of the archive.

  • Press Ctrl+A to select every exported file.
  • Right-click the selected files.
  • Select Show more options.
  • Select Send to.
  • Select Compressed (zipped) folder.
  • Rename the new archive to shift-key-game-web.zip.

File Explorer creates shift-key-game-web.zip inside the export folder. The archive now contains every file required by the game.

  • Switch back to the browser from your Web test.
  • Go to itch.io.
  • Sign in to your itch.io account.
  • Click Dashboard in the top bar.
  • Click Create new game.
  • Enter Shift Key Game in the Title field.
  • Select HTML Game from the Kind Of Game list.
  • Upload shift-key-game-web.zip in the upload area.

Archive processing can pause the page briefly. Keep the page open until Embed options appears.

  • Select Click to launch in fullscreen under Embed options.
  • Click Save & view page.

You should see a private preview of the Shift Key Game page. Its launch area is connected to your uploaded browser build.

Upload Not Becoming Playable?

Open the archive to confirm that index.html sits at its top level. An extra shift-key-game-web folder inside the archive prevents itch.io from finding the entry file.

Confirm that the project uses HTML Game as its kind. Help me troubleshoot my itch.io Web upload.

Publish and test the public page

New itch.io pages start as private previews. Setting the page to Public gives your game a URL that signed-out players can visit.

  • Select Dashboard in the top bar.
  • Select your Shift Key Game project.
  • Open the project's edit page.
  • Find the Visibility section.
  • Select Public.
  • Click Save & view page.
  • Record your public game URL here: your public itch.io game URL.

Before you test the public link, do you expect the complete level to work for someone who is not signed in?

  • Open a private browser window from your browser menu.
  • Paste your public itch.io game URL into the address bar.
  • Press Enter to load the public page.
  • Click Launch game.
  • Move the player through the level.
  • Press Shift to flip gravity.
  • Reach the goal.

You should see the game run inside the browser from its public itch.io page. The gravity flip should work before the win message appears at the goal.

You made it public. Shift Key Game now has a shareable page where anyone can play the complete level.

Your browser build is live on itch.io. Next, you will publish the finished source to GitHub before checking whether the jam is still accepting entries.

Push and Submit Your Game

Your playable build is already live on itch.io. The final publishing gap is connecting that public game to its complete source.

Git records a snapshot of your complete Godot project. GitHub makes that source available to anyone.

The jam entry is a separate itch.io record. Its deadline determines whether you can create that final listing.

In this step, get ready to:
  • Commit the complete game project.
  • Push the source to your public GitHub repository.
  • Submit the itch.io page to GitHub Game Off 2026 while entries are open.
Push the complete project

A Git commit captures the project settings, scenes, scripts, and README at one point in time. Pushing that commit copies the snapshot to your public repository.

  • Record the full path of your existing project folder here: path/to/shift-key-game.
  • Return to the terminal you used to initialize the local repository.
  • Move into the existing project folder by running this command:
cd [[PROJECT_PATH="path/to/shift-key-game"]]

What does this command do?

  • The cd command moves the terminal into your existing shift-key-game folder.
  • The following Git commands now target the local repository connected to your public project.
  • Inspect the repository before staging anything by running this command:
git status

What does this command show?

  • Git lists project files that have changed since the previous commit.
  • New scene files or scripts appear as untracked until you stage them.

You should see the completed game files waiting to be included. Files ignored by the repository stay out of the list.

  • Stage the complete project and inspect the staged snapshot by running these commands:
git add .
git status

What do these commands do?

  • The first command stages new files plus changes inside the current project folder.
  • The second command shows which project files enter the next commit.

Your project settings, scenes, scripts, and README should now appear in the staged section.

  • Record the staged project as a Git commit by running this command:
git commit -m "Complete Shift Key Game"

What does this command do?

  • Git saves the staged project as a permanent snapshot in the local repository.
  • The commit message identifies this snapshot as the completed game.

The terminal reports the new commit plus a summary of the files it contains.

Commit not created?

If Git reports that no changes were staged, run the earlier staging command again. If Git reports that there is nothing new to commit, your complete project may already be recorded.

If Git asks for author details, follow its instructions before retrying. Help me diagnose why my completed Godot project is not creating a Git commit.

GitHub may open a browser sign-in during the push. Your credentials stay inside GitHub's sign-in flow.

  • Publish the current commit and configure its upstream branch by running this command:
git push --set-upstream origin HEAD

What does this command do?

  • Git sends the current branch to the remote repository named origin.
  • The upstream setting connects future pushes and pulls to the same remote branch.

That is the main publishing step complete. Your finished game source now has a public home.

Before you check itch.io, do you think publishing the source also creates a jam entry?

  • Return to the public shift-key-game repository in your browser.
  • Refresh the repository page.
  • Inspect the file list for your project settings, scenes, scripts, and README.

You should see the complete project instead of the initial README by itself. The source publication worked.

  • Return to the public itch.io game page from earlier.
  • Look for a GitHub Game Off 2026 entry link on the game page.

No jam entry link appears yet. Publishing source code completes the GitHub requirement without submitting the game to the jam.

Push not completing?

Confirm that the terminal is inside your existing shift-key-game folder. Check that the remote still points to your public repository.

Complete any browser authentication prompt before retrying the push. Help me troubleshoot this GitHub push.

Add the playable game link

A repository visitor needs a direct route from the source to the playable release. The README places that route on the repository's front page.

  • Return to the public Shift Key Game page on itch.io.
  • Copy its public URL from the browser address bar.
  • Record the URL here: your public itch.io game URL.

Why add the playable link?

The repository explains how the game was built. The itch.io link lets visitors test the finished result without exporting the project themselves.

  • Return to your public shift-key-game repository on GitHub.
  • Open README.md from the repository file list.
  • Click the pencil icon in the upper-right corner of the file view.
  • Add a heading named Play the Game at the bottom of the README.
  • Paste your public itch.io game URL below the new heading.
  • Click Preview above the README content.
  • Click Commit changes to save the README update.

GitHub records the README update as a new remote commit. The playable link now appears on the repository's front page.

  • Synchronize the README commit with your local repository by running this command in the project terminal:
git pull

What does this command do?

  • Git fetches the README commit from the configured upstream branch.
  • Git integrates that commit into the current local branch.
  • Click the itch.io URL in the rendered README.

Your public game page opens from the repository. The browser build should load with the same playable level you tested earlier.

README link not working?

Confirm that the copied URL includes the complete public itch.io address. Remove any extra spaces that became part of the link.

Open the link in a new browser tab to confirm the page is public. Help me fix the playable link in my README.

Submit before the deadline

GitHub Game Off 2026 accepts submissions until December 1, 2026, at 13:37 PST. The public game remains available after that deadline even when a new jam entry can no longer be created.

Before you check the jam page, predict whether its submission window is still open.

✔️ Submissions Are Open

  • Click Join Jam if the jam page presents that option.
  • Click Submit Your Project once you have joined.
  • Select your existing Shift Key Game project.
  • Complete every required submission question.
  • Describe your use of AI accurately in the relevant question.
  • Click Submit to create the entry.

Your dedicated jam submission page opens. This page is separate from the main itch.io project page.

  • Copy the jam submission page URL from the browser address bar.
  • Record the entry URL here: your GitHub Game Off 2026 entry URL.

What did the submission create?

The jam entry connects your existing game page to the Game Off listing. Players can reach the browser build from that entry.

  • Return to README.md in your GitHub repository.
  • Click the pencil icon in the upper-right corner of the file view.
  • Add a heading named Game Off 2026 Entry below the playable game link.
  • Paste your GitHub Game Off 2026 entry URL below the new heading.
  • Click Preview to inspect the rendered entry link.
  • Click Commit changes to save the jam link.
  • Synchronize the final README commit with your local repository by running this command:
git pull

What does this command do?

Git downloads the final README commit from GitHub. Your local branch now contains the jam entry link too.

  • Return to the Shift Key Game page on itch.io.
  • Open its link to the Game Off 2026 submission page.

The dedicated entry page opens with Shift Key Game connected to the jam. Your game is now listed as a submission.

Submission not appearing?

Confirm that you selected the existing public Shift Key Game project. Check that every required submission question has a response.

Return to the jam page to confirm the submission process completed. Help me troubleshoot my Game Off submission.

ⓧ Submissions Have Closed

The submission deadline has passed, so this project remains a public release without a new Game Off 2026 entry. Your GitHub source and playable itch.io page still satisfy the publishing goal.

  • Return to the Shift Key Game page on itch.io.
  • Start the browser game from its public page.
  • Confirm that the complete level still reaches the win message.

The game remains publicly playable after the jam window closes. Your README already identifies the itch.io page as the playable release.

Before the final sync check, what do you expect Git to report about your local project?

  • Check the local repository's final state by running this command:
git status

What should this confirm?

Git should report that the local branch matches its configured upstream. It should also report that no local project files are waiting to be committed.

  • Return to the public GitHub repository.
  • Confirm that the repository shows the complete project settings, scenes, scripts, and README.
  • Open the playable game link from the README.

The public itch.io page loads the browser game from your repository link. You can play the level through to the win message.

  • Open the Game Off entry link from the README if you submitted before the deadline.

The link opens the dedicated jam entry when one was created. Your source, playable build, and eligible submission now point to each other.

Final links not matching?

Compare each README link with the corresponding browser address. Confirm that the game link opens the main itch.io page.

If you submitted, confirm that the entry link opens the dedicated jam page. Help me verify my final publication links.

You have closed the publishing loop. Anyone can now play your gravity-flipping game and inspect the source behind it.

Secret mission

Run a Blind Player Journey Test

Send a first-time player from your public GitHub repository to the browser game without coaching. Compare their blind attempt with a guided replay to test whether the gravity flip is discoverable.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep sharing your finished game, pause local development, or remove every copy you control. The local files and public pages have no ongoing cost on the path you completed.

Resources you used:

  • Your local Godot project folder named shift-key-game.
  • Your public GitHub repository named shift-key-game.
  • Your public itch.io game page for Shift Key Game.
  • Your GitHub Game Off 2026 jam entry, if you submitted one before the deadline.

Keep everything running

No action is needed while you are sharing the game. This option preserves the playable browser build and its public source code.

  • Keep the local shift-key-game folder for future development.
  • Leave the shift-key-game repository public on GitHub.
  • Leave the Shift Key Game page public on itch.io.
  • Keep the jam entry published if you submitted one.

Pause - I'll come back to this later

Closing your local project pauses active development. Your public links remain available for anyone who wants to play the game or read its source.

  • Stop any running game session from the play controls in the Godot editor.
  • Close the Shift Key Game project in Godot.
  • Keep the local shift-key-game folder on your computer.
  • Leave the public shift-key-game repository unchanged on GitHub.
  • Leave the public Shift Key Game page unchanged on itch.io.

Your development environment is now paused. The browser game and source repository remain available through their existing links.

Delete - I don't want to use this again

Permanent deletion removes the playable page, public source, and local project. Take a moment to confirm that you no longer need the game files before continuing.

If you submitted a jam entry:

  • Return to the GitHub Game Off 2026 entry page for Shift Key Game on itch.io.
  • Open the controls for editing that submission.
  • Use the submission-removal control.
  • Confirm the removal when prompted.
  • Check your jam submissions to confirm the entry is absent.

Your game no longer appears as a GitHub Game Off 2026 entry.

Remove the public itch.io page:

  • Return to your Shift Key Game page on itch.io.
  • Use the page editing controls to reach its permanent project deletion area.
  • Start the permanent project deletion.
  • Confirm the deletion when prompted.
  • Visit the public itch.io URL stored in your README.

You should no longer be able to play Shift Key Game from that public URL.

Remove the public GitHub repository:

  • Return to the public shift-key-game repository on GitHub.
  • Use the repository settings to reach the permanent deletion area on its general page.
  • Start the permanent repository deletion.
  • Complete the repository confirmation shown on screen.
  • Visit the former repository URL.

You should no longer see the Shift Key Game source at that repository URL.

Remove the local project folder:

macOS

  • Use Finder to locate the folder named shift-key-game.
  • Move the shift-key-game folder to the Trash.
  • Review the Trash for any files you want to keep.
  • Empty the Trash.
  • Search for shift-key-game again in Finder.

You should no longer find the local project folder on your Mac.

Windows

  • Use File Explorer to locate the folder named shift-key-game.
  • Move the shift-key-game folder to the Recycle Bin.
  • Review the Recycle Bin for any files you want to keep.
  • Empty the Recycle Bin.
  • Search for shift-key-game again in File Explorer.

You should no longer find the local project folder on your Windows computer.

That completes the teardown. The playable page, public source, optional jam entry, and local project are now removed.

Nice Work!

Nice Work!

Mission complete! Your one-level Godot game now turns the Shift key into a gravity-flipping mechanic that anyone can play from its public itch.io page.

You've learned how to:

  • Build a complete 2D level with a movable player. The player can navigate an obstacle to reach a goal with a visible win message.
  • Use the Shift key as the core mechanic so the player can land on either the floor or ceiling.
  • Publish the browser-playable game on itch.io. Share its complete source through the public shift-key-game repository on GitHub. Add the jam entry when submissions are open.
  • Secret Mission: Complete an optional extension that pushes your finished game further.

Ready to quiz yourself?