Your First Game in 5 Minutes
What You'll Build
By the end of this tutorial, you'll have a working Rawframe game that spawns a rotating cube in the world. No prior game development experience needed — just a text editor and a Rawframe installation.
Step 1: Create the Place
Every game lives in a Place — a project folder with a place.json manifest. Create one:
my-first-game/
place.json
scripts/
server/
init.lua
Your place.json tells the engine about your game:
{
"name": "my-first-game",
"version": "1.0.0",
"title": "My First Game",
"author": "YourName",
"description": "A spinning cube to learn the basics.",
"scripts": {
"server": ["scripts/server/init.lua"]
}
}
Tip: You can also run
bash tools/create_game.sh MyFirstGame "YourName"to scaffold this automatically, or create a new Place in Rawframe Studio.
Step 2: Write Your First Script
Open scripts/server/init.lua and add:
-- Spawn a cube 5 units above the ground
local cube = entity.create("my_cube")
entity.set_position(cube, Vec3.new(0, 5, 0))
entity.set_mesh(cube, "primitive:cube")
-- Track rotation angle
local angle = 0
-- Rotate the cube every frame
hook.Add("Think", "SpinCube", function(dt)
angle = angle + dt * 90 -- 90 degrees per second
entity.set_rotation(cube, Quat.from_euler(0, angle, 0))
end)
print("My first game loaded!")
That's it — 10 lines of code. Let's break it down:
entity.create()spawns a new entity with a nameentity.set_position()places it in the world using aVec3entity.set_mesh()gives it a visual mesh (built-in primitives start withprimitive:)hook.Add("Think", ...)registers a function that runs every server tickQuat.from_euler()creates a rotation from pitch, yaw, and roll angles
Step 3: Run and Test
Start a local server with your game loaded:
./bin/rawframe_server -game my-first-game -port 27015
You should see My first game loaded! in the console output.
Now connect with the client:
./bin/rawframe_client -connect 127.0.0.1:27015
You'll see a cube floating in the air, spinning smoothly at 90 degrees per second.
Step 4: Add Networking
Let's make it interactive. When a player presses a key, the cube changes color. Add a client script at scripts/client/input.lua:
-- Client-side: detect key press and send to server
hook.Add("Think", "CheckInput", function()
if input.is_key_pressed("E") then
net.send("ChangeColor")
end
end)
Update your place.json to include the client script:
{
"scripts": {
"server": ["scripts/server/init.lua"],
"client": ["scripts/client/input.lua"]
}
}
Then handle the message on the server in init.lua:
-- Server-side: receive the message and change color
local colors = {
Vec3.new(1, 0, 0), -- red
Vec3.new(0, 1, 0), -- green
Vec3.new(0, 0, 1), -- blue
}
local color_index = 1
net.receive("ChangeColor", function(peer)
color_index = (color_index % #colors) + 1
entity.set_color(cube, colors[color_index])
end)
Now when any player presses E, the cube cycles through red, green, and blue.
What's Next?
You've just built a game with entity spawning, physics-driven updates, and client-server networking. From here, you can:
- Add physics — use
physics.set_body()to give entities rigidbodies - Build UI — the
ui.*API has 250+ functions for creating in-game interfaces - Create weapons — the
weapon.*API supports hitscan, projectile, and melee weapons - Store data —
storage.*provides per-game SQLite persistence - Skip the busywork — grab models, sounds, and ready-made systems from the Asset Store
Check out the API documentation for the full list of 583+ functions. When your game is ready, publish it on your own server or export it standalone.
Happy building!