// SPDX-License-Identifier: LCL-1.0 // Copyright (c) 2026 Markus Maiwald // Stewardship: Self Sovereign Society Foundation // // This file is part of the Nexus Commonwealth. // See legal/LICENSE_COMMONWEALTH.md for license terms. //! Rumpk HAL: Matrix Protocol (Rainmaker Logic) //! //! Implements a "Matrix" falling rain effect for the boot splash. //! Recedes into the background after a fixed lifetime. //! //! SAFETY: Uses a simple Xorshift PRNG. Animation state is global. const std = @import("std"); const fb = @import("framebuffer.zig"); // Config const FONT_W = 8; const FONT_H = 8; const COLS = fb.WIDTH / FONT_W; const LIFETIME_FRAMES = 150; // ~5 seconds at 30FPS (reduced for impact) // State // SAFETY(Matrix): Drops array is initialized by `init()` before use. // Initialized to `undefined` to save a 512B zero-sweep in BSS. var drops: [COLS]i32 = undefined; var frame_count: usize = 0; var is_active: bool = false; // Basic PRNG (Xorshift) var rng_state: u32 = 0xDEADBEEF; fn random() u32 { var x = rng_state; x ^= x << 13; x ^= x >> 17; x ^= x << 5; rng_state = x; return x; } pub fn init() void { is_active = true; frame_count = 0; // Initialize drops at random heights off-screen var i: usize = 0; while (i < COLS) : (i += 1) { drops[i] = -@as(i32, @intCast(random() % 100)); } } // Returns: TRUE if still animating, FALSE if finished (The Void) pub fn update() bool { if (!is_active) return false; // 1. Fade existing trails fb.fade_screen(15); // Fade speed // 2. Are we dying? frame_count += 1; const dying = (frame_count > LIFETIME_FRAMES); // 3. Update Drops var active_drops: usize = 0; var i: usize = 0; while (i < COLS) : (i += 1) { // Draw Head (Bright White/Green) const x = i * FONT_W; const y = drops[i]; if (y >= 0 and y < @as(i32, @intCast(fb.HEIGHT))) { // Draw a simple "pixel block" glyph // White tip fb.put_pixel(@intCast(x + 3), @intCast(y + 3), 0xFFFFFFFF); fb.put_pixel(@intCast(x + 4), @intCast(y + 3), 0xFFFFFFFF); fb.put_pixel(@intCast(x + 3), @intCast(y + 4), 0xFFFFFFFF); fb.put_pixel(@intCast(x + 4), @intCast(y + 4), 0xFFFFFFFF); // Green body follow if (y > 8) { fb.fill_rect(@intCast(x + 3), @intCast(y - 4), 2, 4, 0xFF00FF00); } } // Move down drops[i] += FONT_H; // Reset if off screen if (drops[i] > @as(i32, @intCast(fb.HEIGHT))) { if (!dying) { // Respawn at top drops[i] = -@as(i32, @intCast(random() % 50)); active_drops += 1; } else { // Do NOT respawn. Let it fall into the void. } } else { active_drops += 1; // It's still on screen } } // 4. Check for Total Extinction if (dying and active_drops == 0) { // Ensure pure black at the end fb.clear(0xFF000000); is_active = false; return false; // STOP THE GPU FLUSHING IF IDLE } return true; // Keep animating } // --- EXPORTS FOR NIM --- export fn matrix_init() void { init(); } export fn matrix_update() bool { return update(); }