Development
Getting Started
Create games for Nethercore hardware
Making games for Nethercore means working within hardware-like constraints: fixed targets, documented limits, and deterministic execution. This guide covers ZX development. Support for Chroma and z is coming.
Prerequisites
Before you start, make sure you have:
- Rust installed (rustup.rs)
- A code editor (VS Code, Sublime, Vim, whatever you prefer)
- Basic programming knowledge (any language is fine)
- An Nethercore account for uploading games
Install the Nethercore SDK
Clone the Nethercore repository and build the development tools:
git clone https://github.com/nethercore-systems/nethercore.git
cd nethercore
cargo build --release This gives you the player, dev tools, and example games to learn from.
Create Your First Game
Create a new Rust library project:
cargo new --lib my-game
cd my-game Update Cargo.toml:
[package]
name = "my-game"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[profile.release]
opt-level = "s"
lto = true Understanding the Game Loop
Every Nethercore game exports three functions. Replace src/lib.rs with:
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_: &PanicInfo) -> ! { core::arch::wasm32::unreachable() }
// Import runtime functions
#[link(wasm_import_module = "env")]
extern "C" {
fn set_clear_color(color: u32);
fn draw_rect(x: f32, y: f32, w: f32, h: f32, color: u32);
fn button_pressed(player: u32, button: u32) -> u32;
}
static mut Y: f32 = 200.0;
#[no_mangle]
pub extern "C" fn init() {
unsafe { set_clear_color(0x1a1a2eFF); }
}
#[no_mangle]
pub extern "C" fn update() {
unsafe {
if button_pressed(0, 0) != 0 { Y -= 10.0; } // Up
if button_pressed(0, 1) != 0 { Y += 10.0; } // Down
}
}
#[no_mangle]
pub extern "C" fn render() {
unsafe { draw_rect(200.0, Y, 80.0, 80.0, 0xFF6B6BFF); }
} All game state lives in static mut variables — this enables automatic rollback netcode for online multiplayer!
Drawing Graphics
Nethercore provides 2D and 3D drawing APIs:
2D Drawing
// Draw rectangles and text
draw_rect(x, y, width, height, 0xFF0000FF); // Red
draw_text(b"Hello!".as_ptr(), 6, x, y, 24.0, 0xFFFFFFFF); 3D Graphics
// Set up camera
camera_set(0.0, 5.0, 10.0, 0.0, 0.0, 0.0);
// Create and draw a cube
let cube_handle = cube(1.0, 1.0, 1.0);
push_identity();
push_translate(0.0, 1.0, 0.0);
push_rotate_y(45.0);
draw_mesh(cube_handle); Handling Input
Check button states with the input API:
// Button constants
const BUTTON_A: u32 = 4;
const BUTTON_LEFT: u32 = 2;
// Check if A was just pressed this frame
if button_pressed(0, BUTTON_A) != 0 {
jump();
}
// Check if button is held down
if button_held(0, BUTTON_LEFT) != 0 {
player_x -= 5.0;
}
// Analog stick input (-1.0 to 1.0)
let stick_x = left_stick_x(0);
player_x += stick_x * 5.0; Adding Sound
Play sounds with simple procedural audio or loaded samples:
// Load PCM samples (22050 Hz, mono, i16)
let samples = generate_beep(); // Your audio data
let sfx = load_sound(samples.as_ptr(), (samples.len() * 2) as u32);
// Play with volume and stereo pan
play_sound(sfx, 0.8, 0.0); // volume=0.8, pan=center
// Or load from ROM assets
let jump = rom_sound(b"jump".as_ptr(), 4);
play_sound(jump, 1.0, -0.5); // pan left Build & Test
Compile your game to WebAssembly:
cargo build --target wasm32-unknown-unknown --release Run in the Nethercore player:
nether run target/wasm32-unknown-unknown/release/my_game.wasm Package for Release
Create an nether.toml manifest and package your game:
[game]
id = "my-game"
title = "My Game"
author = "Your Name"
version = "1.0.0" Build and pack:
nether build && nether pack Submit to the Archive
- Sign in to your account
- Go to your Dashboard
- Click "Upload New Game"
- Fill in the details (title, description, category)
- Upload your
.nczxROM file - Add an icon (512x512 PNG; optional) and screenshots (optional)
- Click "Publish"
Your game is now part of the Nethercore Archive — playable by anyone with the emulator.
Continue
Next Steps
Reference
Common Patterns
How do I implement game states (menu, playing, game over)?
enum GameState { Menu, Playing, GameOver }
static mut STATE: GameState = GameState::Menu;
pub extern "C" fn update() {
unsafe {
match STATE {
GameState::Menu => update_menu(),
GameState::Playing => update_game(),
GameState::GameOver => update_game_over(),
}
}
} How do I handle collision detection?
fn aabb_collision(a: &Rect, b: &Rect) -> bool {
a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y
}
if aabb_collision(&player.bounds(), &enemy.bounds()) {
player.take_damage();
} How do I save player progress?
// 8 save slots available, up to 64KB each
const SLOT: u32 = 0;
// Save bytes
let data: [u8; 8] = [level, score, /* ... */];
save_write(SLOT, data.as_ptr(), data.len() as u32);
// Load bytes
let mut data = [0u8; 8];
let size = save_read(SLOT, data.as_mut_ptr(), 8);
if size > 0 { /* data loaded */ } How does online multiplayer work?
// Multiplayer is AUTOMATIC! Just write rollback-safe code:
// 1. All state in static variables
static mut PLAYER1_X: f32 = 0.0;
static mut PLAYER2_X: f32 = 0.0;
// 2. Read inputs for each player
let p1_input = left_stick_x(0);
let p2_input = left_stick_x(1); // Works online!
// 3. Deterministic update (no random system calls)
PLAYER1_X += p1_input * SPEED;
PLAYER2_X += p2_input * SPEED;
// The runtime handles networking, rollback, and prediction! Ready to Build?
You now have everything you need to create your first game for Nethercore hardware.