This skill should be used when the user asks about "debug panel", "F4 panel", "debug_register", "debug_watch", "sync test", "desync", "rollback debug", "--sync-test", "--p2p-test", "frame stepping", "time scale", "profiling", "debug group", "debugging ZX games", "inspect values", "live editing", or mentions debugging Nethercore ZX games, finding desyncs, testing multiplayer synchronization, or runtime value inspection.
/plugin marketplace add nethercore-systems/nethercore-ai-plugins/plugin install zx-dev@nethercore-ai-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
examples/debug-setup-rust.mdreferences/sync-test-checklist.mdDebug ZX games using the built-in inspection system and testing tools. Press F4 to open the debug panel during development.
The debug inspection system provides:
Reference nethercore/include/zx.rs lines 1370-1478 for complete FFI signatures.
Press F4 during gameplay to toggle the debug panel. The panel displays all registered values and provides interactive controls.
| Key | Action |
|---|---|
| F4 | Toggle debug panel |
| F5 | Pause/unpause game |
| F6 | Step one frame (while paused) |
| F7 | Decrease time scale |
| F8 | Increase time scale |
Register values during init() to make them editable in the F4 panel:
static mut PLAYER_SPEED: f32 = 5.0;
static mut GRAVITY: f32 = 25.0;
static mut GOD_MODE: u8 = 0;
static mut ENEMY_COUNT: i32 = 5;
#[no_mangle]
pub extern "C" fn init() {
unsafe {
// Basic registration
debug_register_f32(b"Speed".as_ptr(), 5, &PLAYER_SPEED);
debug_register_f32(b"Gravity".as_ptr(), 7, &GRAVITY);
debug_register_bool(b"God Mode".as_ptr(), 8, &GOD_MODE);
debug_register_i32(b"Enemies".as_ptr(), 7, &ENEMY_COUNT);
}
}
Use range variants for slider UI with min/max bounds:
static mut DIFFICULTY: i32 = 2;
static mut SPEED: f32 = 5.0;
fn init() {
unsafe {
debug_register_i32_range(b"Difficulty".as_ptr(), 10, &DIFFICULTY, 1, 5);
debug_register_f32_range(b"Speed".as_ptr(), 5, &SPEED, 0.0, 20.0);
}
}
Register vectors, colors, and rects:
static mut PLAYER_POS: [f32; 3] = [0.0, 0.0, 0.0];
static mut TINT_COLOR: [u8; 4] = [255, 255, 255, 255];
fn init() {
unsafe {
debug_register_vec3(b"Position".as_ptr(), 8, PLAYER_POS.as_ptr());
debug_register_color(b"Tint".as_ptr(), 4, TINT_COLOR.as_ptr());
}
}
Use watch functions to display values without allowing editing:
static mut FRAME_COUNT: u32 = 0;
static mut FPS: f32 = 0.0;
static mut PLAYER_VEL: [f32; 2] = [0.0, 0.0];
fn init() {
unsafe {
debug_watch_u32(b"Frame".as_ptr(), 5, &FRAME_COUNT);
debug_watch_f32(b"FPS".as_ptr(), 3, &FPS);
debug_watch_vec2(b"Velocity".as_ptr(), 8, PLAYER_VEL.as_ptr());
}
}
Group related values for a cleaner debug panel:
fn init() {
unsafe {
debug_group_begin(b"Player".as_ptr(), 6);
debug_register_vec3(b"Position".as_ptr(), 8, PLAYER_POS.as_ptr());
debug_register_f32(b"Health".as_ptr(), 6, &PLAYER_HEALTH);
debug_register_f32(b"Speed".as_ptr(), 5, &PLAYER_SPEED);
debug_group_end();
debug_group_begin(b"Physics".as_ptr(), 7);
debug_register_f32(b"Gravity".as_ptr(), 7, &GRAVITY);
debug_register_f32(b"Friction".as_ptr(), 8, &FRICTION);
debug_group_end();
debug_group_begin(b"Debug".as_ptr(), 5);
debug_register_bool(b"God Mode".as_ptr(), 8, &GOD_MODE);
debug_register_bool(b"Show Hitboxes".as_ptr(), 13, &SHOW_HITBOXES);
debug_group_end();
}
}
Groups are collapsible in the UI - click the header to expand/collapse.
Query debug state to respect pause/time scale:
fn update() {
unsafe {
// Skip update when paused via debug panel
if debug_is_paused() != 0 {
return;
}
// Apply time scale to delta_time
let dt = delta_time() * debug_get_time_scale();
// Use scaled dt for all time-based logic
PLAYER_VEL_Y += GRAVITY * dt;
PLAYER_X += PLAYER_VEL_X * dt;
}
}
Time Scale Values:
Test rollback determinism with CLI flags:
Runs two parallel simulations and compares state:
nether run --sync-test
This launches two game instances in parallel:
Desync causes:
random()delta_time()/tick_count()render() instead of update()Tests actual network rollback with two instances:
nether run --p2p-test
Creates a local two-player session:
Use this to verify:
static mut SHOW_HITBOXES: u8 = 0;
fn init() {
unsafe {
debug_register_bool(b"Hitboxes".as_ptr(), 8, &SHOW_HITBOXES);
}
}
fn render() {
unsafe {
if SHOW_HITBOXES != 0 {
// Draw wireframe boxes around collision volumes
for entity in entities.iter() {
draw_rect(
entity.x - entity.half_w,
entity.y - entity.half_h,
entity.half_w * 2.0,
entity.half_h * 2.0,
0x00FF0080, // Semi-transparent green
);
}
}
}
}
fn render() {
unsafe {
// Show frame counter and FPS
let frame = tick_count();
// Draw debug text at top-left
draw_text_str(&format!("Frame: {}", frame), 10.0, 10.0, 16.0, 0xFFFFFFFF);
}
}
Use time scale controls (F7/F8) to:
When --sync-test reports a desync:
random() call must happen in same orderAdd debug watches to narrow down which variable diverges first.
Rust helper functions in zx.rs:
// String-based helpers
debug_f32("speed", &SPEED); // debug_register_f32 wrapper
debug_i32("count", &COUNT); // debug_register_i32 wrapper
debug_bool("enabled", &ENABLED); // debug_register_bool wrapper
debug_group("Player"); // debug_group_begin wrapper
debug_group_close(); // debug_group_end wrapper
| Function | Type | UI Control |
|---|---|---|
debug_register_i8/i16/i32 | Signed integers | Number input |
debug_register_u8/u16/u32 | Unsigned integers | Number input |
debug_register_f32 | Float | Number input |
debug_register_bool | Boolean (u8) | Checkbox |
debug_register_*_range | Numbers | Slider |
debug_register_vec2/vec3 | Float arrays | Multi-input |
debug_register_rect | 4 i16 | Multi-input |
debug_register_color | 4 u8 RGBA | Color picker |
debug_register_fixed_* | Fixed-point | Decimal display |
init(), not per-frameexamples/debug-setup-rust.md - Complete Rust debug setupreferences/sync-test-checklist.md - Desync debugging checklistnethercore/include/zx.rs - Debug FFI (lines 1370-1478)nethercore/docs/book/src/api/debug.md - Full API referenceThis skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.