Claude Code Plugins

Community-maintained marketplace

Feedback

|

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Camera Systems
description This skill covers camera implementation for ZX games. Triggers on "camera follow", "orbit camera", "third person", "first person", "screen shake", "camera lerp", "dead zone", "camera FOV", "side-scroller camera", "top-down camera". **Load references when:** - Full implementations → `examples/camera-examples.md` - Matrix math, lerp/slerp → `references/camera-math.md` - 2D patterns, parallax → `references/side-scroller-patterns.md` - Coordinate conventions → `zx-game-development/references/coordinate-conventions.md`
version 2.1.0

Camera Systems for Nethercore ZX

Implement cameras using ZX FFI. All camera state in static variables for rollback safety.

Coordinate Convention: Y-up, right-handed, -Z forward. When yaw=0, camera looks toward -Z.

Camera FFI

Function Purpose
camera_set(x,y,z, tx,ty,tz) Position + look-at
camera_fov(degrees) Field of view (default 60)
push_view_matrix(m0..m15) Custom 4x4 view matrix

Camera Types

Type Best For Complexity
Follow Platformers, racing Simple
Orbit Action-adventure, RPGs Medium
First-Person FPS, exploration Medium
Fixed Puzzle, cinematic Simple

Follow Camera (Core Pattern)

static mut CAM_X: f32 = 0.0;
static mut CAM_Y: f32 = 5.0;
static mut CAM_Z: f32 = 10.0;

fn update_follow_camera(tx: f32, ty: f32, tz: f32) {
    let dt = delta_time();
    let t = (5.0 * dt).min(1.0);  // Smoothing
    unsafe {
        CAM_X += (tx - CAM_X) * t;
        CAM_Y += (ty + 5.0 - CAM_Y) * t;  // Offset above
        CAM_Z += (tz + 10.0 - CAM_Z) * t; // Offset behind
    }
}

// In render():
camera_set(CAM_X, CAM_Y, CAM_Z, target_x, target_y, target_z);

Orbit Camera (Core Pattern)

static mut CAM_YAW: f32 = 0.0;
static mut CAM_PITCH: f32 = 20.0;
static mut CAM_DIST: f32 = 8.0;

fn update_orbit(player: u32) {
    let dt = delta_time();
    unsafe {
        CAM_YAW += right_stick_x(player) * 120.0 * dt;
        CAM_PITCH = (CAM_PITCH - right_stick_y(player) * 120.0 * dt)
            .clamp(-30.0, 60.0);
    }
}

fn get_orbit_pos(tx: f32, ty: f32, tz: f32) -> (f32, f32, f32) {
    unsafe {
        let yaw = CAM_YAW.to_radians();
        let pitch = CAM_PITCH.to_radians();
        (
            tx - CAM_DIST * yaw.sin() * pitch.cos(),
            ty + CAM_DIST * pitch.sin(),
            tz + CAM_DIST * yaw.cos() * pitch.cos(),
        )
    }
}

First-Person Camera (Core Pattern)

static mut LOOK_YAW: f32 = 0.0;
static mut LOOK_PITCH: f32 = 0.0;

fn update_first_person(player: u32) {
    let dt = delta_time();
    unsafe {
        LOOK_YAW += right_stick_x(player) * 90.0 * dt;
        LOOK_PITCH = (LOOK_PITCH - right_stick_y(player) * 90.0 * dt)
            .clamp(-85.0, 85.0);
    }
}

fn get_look_dir() -> (f32, f32, f32) {
    unsafe {
        let yaw = LOOK_YAW.to_radians();
        let pitch = LOOK_PITCH.to_radians();
        (-yaw.sin() * pitch.cos(), pitch.sin(), -yaw.cos() * pitch.cos())
    }
}

// In render():
let (dx, dy, dz) = get_look_dir();
camera_set(player_x, player_y + 1.6, player_z,
           player_x + dx, player_y + 1.6 + dy, player_z + dz);

Screen Shake

static mut SHAKE_TRAUMA: f32 = 0.0;

fn add_shake(amount: f32) { unsafe { SHAKE_TRAUMA = (SHAKE_TRAUMA + amount).min(1.0); } }
fn update_shake() { unsafe { SHAKE_TRAUMA = (SHAKE_TRAUMA - delta_time() * 2.0).max(0.0); } }

fn get_shake_offset() -> (f32, f32) {
    unsafe {
        let shake = SHAKE_TRAUMA * SHAKE_TRAUMA * 10.0;
        ((random_f32() - 0.5) * shake, (random_f32() - 0.5) * shake)
    }
}

Dead Zone

Prevents jitter when target is near camera center:

fn update_with_dead_zone(tx: f32, tz: f32) {
    let dx = tx - CAM_X;
    let dz = tz - (CAM_Z - OFFSET_Z);
    let dist = (dx*dx + dz*dz).sqrt();
    if dist > 2.0 {  // DEAD_ZONE
        let t = ((dist - 2.0) / dist) * 0.1;
        CAM_X += dx * t;
        CAM_Z += dz * t;
    }
}

Perspective Selection

Experience Best Perspective
Character action/story Third-Person
Immersive world First-Person
Precision platforming Side-Scroller
Vehicle/tactical Top-Down

Rollback Safety

All camera state uses static variables (auto-snapshotted). Use delta_time() for frame-rate independence, FFI random() for shake.