From eaa65e7b2ef49a0b70edb6b43fbc11b88fa19ab4 Mon Sep 17 00:00:00 2001 From: AI Agent Bot Date: Wed, 25 Feb 2026 02:09:35 -0600 Subject: [PATCH 1/4] feat: add GitHub Pages project website Single-page site with PSP XMB-inspired dark theme, smooth scroll navigation, and zero framework dependencies. Includes all 30 examples, 38 SDK module docs, architecture diagrams, and build tool reference. Co-Authored-By: Claude Opus 4.6 --- site/.nojekyll | 0 site/css/style.css | 987 +++++++++++++++++++++++++++++++++++++++++++ site/img/favicon.svg | 16 + site/index.html | 915 +++++++++++++++++++++++++++++++++++++++ site/js/main.js | 122 ++++++ 5 files changed, 2040 insertions(+) create mode 100644 site/.nojekyll create mode 100644 site/css/style.css create mode 100644 site/img/favicon.svg create mode 100644 site/index.html create mode 100644 site/js/main.js diff --git a/site/.nojekyll b/site/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/site/css/style.css b/site/css/style.css new file mode 100644 index 0000000..a7050cf --- /dev/null +++ b/site/css/style.css @@ -0,0 +1,987 @@ +/* ============================================ + rust-psp GitHub Pages — PSP XMB-inspired theme + ============================================ */ + +/* --- Reset & Base --- */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --bg-deep: #0a0a0f; + --bg-card: #12121a; + --bg-code: #1a1a2e; + --bg-hover: #1a1a28; + --accent-blue: #4a9eff; + --accent-purple: #7c5cff; + --accent-cyan: #00d4aa; + --text-primary: #e8e8f0; + --text-muted: #8888aa; + --text-dim: #555570; + --border-color: #2a2a3e; + --nav-height: 60px; + --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Source Code Pro', monospace; + --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; + --max-width: 1200px; + --section-padding: 100px 0; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: var(--nav-height); +} + +body { + font-family: var(--font-body); + background: var(--bg-deep); + color: var(--text-primary); + line-height: 1.6; + overflow-x: hidden; + -webkit-font-smoothing: antialiased; +} + +a { + color: var(--accent-blue); + text-decoration: none; + transition: color 0.2s; +} + +a:hover { + color: var(--accent-cyan); +} + +img { + max-width: 100%; +} + +/* --- Container --- */ +.container { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 24px; +} + +/* --- Navigation --- */ +.nav { + position: fixed; + top: 0; + left: 0; + right: 0; + height: var(--nav-height); + z-index: 1000; + transition: background 0.3s, box-shadow 0.3s; + background: transparent; +} + +.nav.scrolled { + background: rgba(10, 10, 15, 0.95); + box-shadow: 0 1px 20px rgba(0, 0, 0, 0.5); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} + +.nav-inner { + max-width: var(--max-width); + margin: 0 auto; + padding: 0 24px; + height: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.nav-logo { + font-family: var(--font-mono); + font-size: 1.2rem; + font-weight: 700; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 8px; +} + +.nav-logo .accent { + color: var(--accent-blue); +} + +.nav-links { + display: flex; + gap: 8px; + list-style: none; +} + +.nav-links a { + color: var(--text-muted); + font-size: 0.875rem; + padding: 6px 12px; + border-radius: 6px; + transition: color 0.2s, background 0.2s; +} + +.nav-links a:hover, +.nav-links a.active { + color: var(--text-primary); + background: rgba(74, 158, 255, 0.1); +} + +.nav-github { + display: flex; + align-items: center; + gap: 6px; + color: var(--text-muted); + font-size: 0.875rem; + padding: 6px 14px; + border: 1px solid var(--border-color); + border-radius: 8px; + transition: all 0.2s; +} + +.nav-github:hover { + color: var(--text-primary); + border-color: var(--accent-blue); + background: rgba(74, 158, 255, 0.08); +} + +.nav-github svg { + width: 18px; + height: 18px; + fill: currentColor; +} + +/* Hamburger */ +.hamburger { + display: none; + flex-direction: column; + gap: 5px; + background: none; + border: none; + cursor: pointer; + padding: 4px; +} + +.hamburger span { + display: block; + width: 24px; + height: 2px; + background: var(--text-muted); + transition: transform 0.3s, opacity 0.3s; +} + +.hamburger.open span:nth-child(1) { + transform: rotate(45deg) translate(5px, 5px); +} + +.hamburger.open span:nth-child(2) { + opacity: 0; +} + +.hamburger.open span:nth-child(3) { + transform: rotate(-45deg) translate(5px, -5px); +} + +/* --- Hero --- */ +.hero { + position: relative; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + padding: 120px 24px 80px; + overflow: hidden; +} + +.hero-bg { + position: absolute; + inset: 0; + background: + radial-gradient(ellipse 80% 60% at 50% 40%, rgba(74, 158, 255, 0.12) 0%, transparent 60%), + radial-gradient(ellipse 60% 50% at 30% 60%, rgba(124, 92, 255, 0.08) 0%, transparent 50%), + radial-gradient(ellipse 50% 40% at 70% 70%, rgba(0, 212, 170, 0.05) 0%, transparent 50%); + animation: heroShift 12s ease-in-out infinite alternate; +} + +@keyframes heroShift { + 0% { transform: scale(1) translate(0, 0); } + 50% { transform: scale(1.05) translate(-1%, 2%); } + 100% { transform: scale(1) translate(1%, -1%); } +} + +.hero-waves { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 200px; + overflow: hidden; +} + +.hero-waves svg { + position: absolute; + bottom: 0; + width: 200%; + height: 100%; +} + +.wave-1 { animation: waveDrift 8s ease-in-out infinite; opacity: 0.15; } +.wave-2 { animation: waveDrift 12s ease-in-out infinite reverse; opacity: 0.1; } + +@keyframes waveDrift { + 0%, 100% { transform: translateX(0); } + 50% { transform: translateX(-25%); } +} + +.hero-content { + position: relative; + z-index: 1; +} + +.hero h1 { + font-family: var(--font-mono); + font-size: clamp(3rem, 8vw, 5rem); + font-weight: 800; + letter-spacing: -2px; + margin-bottom: 16px; + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple), var(--accent-cyan)); + background-size: 200% 200%; + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: gradientText 6s ease-in-out infinite; +} + +@keyframes gradientText { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } +} + +.hero-tagline { + font-size: clamp(1.1rem, 2.5vw, 1.5rem); + color: var(--text-primary); + margin-bottom: 8px; + font-weight: 300; +} + +.hero-subtitle { + font-family: var(--font-mono); + font-size: 0.9rem; + color: var(--text-muted); + margin-bottom: 32px; +} + +.hero-stats { + display: flex; + justify-content: center; + gap: 16px; + margin-bottom: 40px; + flex-wrap: wrap; +} + +.stat-badge { + font-family: var(--font-mono); + font-size: 0.85rem; + padding: 8px 20px; + border-radius: 100px; + border: 1px solid var(--border-color); + background: rgba(18, 18, 26, 0.8); + color: var(--text-primary); +} + +.stat-badge .num { + color: var(--accent-cyan); + font-weight: 700; +} + +.hero-buttons { + display: flex; + justify-content: center; + gap: 16px; + flex-wrap: wrap; +} + +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 28px; + border-radius: 10px; + font-size: 0.95rem; + font-weight: 600; + transition: all 0.25s; + cursor: pointer; + border: none; +} + +.btn-primary { + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); + color: #fff; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(74, 158, 255, 0.3); + color: #fff; +} + +.btn-outline { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +.btn-outline:hover { + border-color: var(--accent-blue); + background: rgba(74, 158, 255, 0.08); + color: var(--text-primary); + transform: translateY(-2px); +} + +/* --- Sections --- */ +section { + padding: var(--section-padding); +} + +.section-header { + text-align: center; + margin-bottom: 60px; +} + +.section-header h2 { + font-family: var(--font-mono); + font-size: clamp(1.8rem, 4vw, 2.5rem); + font-weight: 700; + margin-bottom: 12px; +} + +.section-header h2 .accent { + color: var(--accent-blue); +} + +.section-header p { + color: var(--text-muted); + font-size: 1.05rem; + max-width: 600px; + margin: 0 auto; +} + +/* --- Scroll Animations --- */ +.fade-in { + opacity: 0; + transform: translateY(30px); + transition: opacity 0.6s ease-out, transform 0.6s ease-out; +} + +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* --- Features Grid --- */ +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + gap: 24px; +} + +.feature-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 32px; + transition: transform 0.25s, border-color 0.25s, box-shadow 0.25s; +} + +.feature-card:hover { + transform: translateY(-4px); + border-color: var(--accent-blue); + box-shadow: 0 8px 40px rgba(74, 158, 255, 0.08); +} + +.feature-icon { + font-size: 2rem; + margin-bottom: 16px; + display: block; + width: 48px; + height: 48px; + line-height: 48px; + text-align: center; + border-radius: 12px; + background: rgba(74, 158, 255, 0.1); +} + +.feature-card h3 { + font-family: var(--font-mono); + font-size: 1.05rem; + margin-bottom: 8px; +} + +.feature-card p { + color: var(--text-muted); + font-size: 0.9rem; + line-height: 1.5; +} + +/* --- Quick Start --- */ +.quickstart-steps { + max-width: 800px; + margin: 0 auto; +} + +.step { + margin-bottom: 40px; +} + +.step-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 12px; +} + +.step-num { + font-family: var(--font-mono); + font-size: 0.8rem; + font-weight: 700; + width: 28px; + height: 28px; + line-height: 28px; + text-align: center; + border-radius: 8px; + background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); + color: #fff; + flex-shrink: 0; +} + +.step h3 { + font-size: 1.05rem; +} + +.step p { + color: var(--text-muted); + font-size: 0.9rem; + margin-bottom: 12px; + padding-left: 40px; +} + +/* --- Code Blocks --- */ +pre { + background: var(--bg-code); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 20px 24px; + overflow-x: auto; + font-family: var(--font-mono); + font-size: 0.85rem; + line-height: 1.7; + margin-left: 40px; + position: relative; +} + +pre .lang-label { + position: absolute; + top: 8px; + right: 12px; + font-size: 0.7rem; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 1px; +} + +code { + font-family: var(--font-mono); +} + +/* Inline code */ +p code, li code, td code { + background: var(--bg-code); + padding: 2px 6px; + border-radius: 4px; + font-size: 0.85em; + color: var(--accent-cyan); +} + +/* Syntax highlighting */ +.kw { color: #c792ea; } /* keywords */ +.fn { color: #82aaff; } /* functions */ +.str { color: #c3e88d; } /* strings */ +.cm { color: #546e7a; } /* comments */ +.ty { color: #ffcb6b; } /* types */ +.mac { color: #89ddff; } /* macros */ +.num { color: #f78c6c; } /* numbers */ +.at { color: #ff5572; } /* attributes */ +.lf { color: #f07178; } /* lifetime */ + +/* --- Modules --- */ +.modules-section { + background: + linear-gradient(180deg, var(--bg-deep) 0%, rgba(18, 18, 26, 0.5) 50%, var(--bg-deep) 100%); +} + +.module-categories { + max-width: 900px; + margin: 0 auto; +} + +.module-category { + border: 1px solid var(--border-color); + border-radius: 12px; + margin-bottom: 12px; + overflow: hidden; + background: var(--bg-card); +} + +.module-category-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 24px; + cursor: pointer; + transition: background 0.2s; + user-select: none; +} + +.module-category-header:hover { + background: var(--bg-hover); +} + +.module-category-header h3 { + font-family: var(--font-mono); + font-size: 0.95rem; + display: flex; + align-items: center; + gap: 10px; +} + +.module-count { + font-size: 0.75rem; + color: var(--text-dim); + background: rgba(74, 158, 255, 0.1); + padding: 2px 8px; + border-radius: 100px; +} + +.module-chevron { + font-size: 0.8rem; + color: var(--text-dim); + transition: transform 0.3s; +} + +.module-category.open .module-chevron { + transform: rotate(180deg); +} + +.module-list { + display: none; + padding: 0 24px 16px; +} + +.module-category.open .module-list { + display: block; +} + +.module-item { + display: flex; + align-items: baseline; + gap: 12px; + padding: 8px 0; + border-top: 1px solid rgba(42, 42, 62, 0.5); +} + +.module-name { + font-family: var(--font-mono); + font-size: 0.85rem; + color: var(--accent-blue); + white-space: nowrap; + min-width: 120px; +} + +.module-desc { + color: var(--text-muted); + font-size: 0.85rem; +} + +.module-types { + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--text-dim); + margin-top: 2px; +} + +/* --- Examples Gallery --- */ +.filter-bar { + display: flex; + justify-content: center; + gap: 8px; + margin-bottom: 40px; + flex-wrap: wrap; +} + +.filter-btn { + font-family: var(--font-mono); + font-size: 0.8rem; + padding: 6px 16px; + border-radius: 100px; + border: 1px solid var(--border-color); + background: transparent; + color: var(--text-muted); + cursor: pointer; + transition: all 0.2s; +} + +.filter-btn:hover { + border-color: var(--accent-blue); + color: var(--text-primary); +} + +.filter-btn.active { + background: rgba(74, 158, 255, 0.15); + border-color: var(--accent-blue); + color: var(--accent-blue); +} + +.examples-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; +} + +.example-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 20px; + transition: transform 0.2s, border-color 0.2s; + display: flex; + flex-direction: column; +} + +.example-card:hover { + transform: translateY(-2px); + border-color: var(--accent-purple); +} + +.example-card.hidden { + display: none; +} + +.example-card h4 { + font-family: var(--font-mono); + font-size: 0.9rem; + margin-bottom: 6px; +} + +.example-tags { + display: flex; + gap: 6px; + margin-bottom: 8px; + flex-wrap: wrap; +} + +.example-tag { + font-family: var(--font-mono); + font-size: 0.65rem; + padding: 2px 8px; + border-radius: 4px; + background: rgba(124, 92, 255, 0.12); + color: var(--accent-purple); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.example-card p { + color: var(--text-muted); + font-size: 0.82rem; + line-height: 1.45; + flex: 1; +} + +.example-card .view-source { + display: inline-flex; + align-items: center; + gap: 4px; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--accent-blue); + margin-top: 12px; +} + +.example-card .view-source:hover { + color: var(--accent-cyan); +} + +/* --- Architecture --- */ +.arch-diagram { + max-width: 800px; + margin: 0 auto; +} + +.arch-block { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 32px; + margin-bottom: 32px; +} + +.arch-block h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 20px; + color: var(--accent-blue); +} + +.arch-flow { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 8px; + font-family: var(--font-mono); + font-size: 0.82rem; +} + +.arch-node { + padding: 10px 16px; + border: 1px solid var(--border-color); + border-radius: 8px; + background: var(--bg-code); + text-align: center; + white-space: nowrap; +} + +.arch-arrow { + color: var(--text-dim); + font-size: 1.1rem; +} + +.arch-layers { + display: flex; + flex-direction: column; + gap: 8px; +} + +.arch-layer { + display: flex; + align-items: center; + gap: 12px; + font-family: var(--font-mono); + font-size: 0.85rem; +} + +.arch-layer-bar { + flex: 1; + padding: 12px 16px; + border-radius: 8px; + text-align: center; +} + +.arch-layer-bar.l4 { + background: rgba(74, 158, 255, 0.15); + border: 1px solid rgba(74, 158, 255, 0.3); + color: var(--accent-blue); +} + +.arch-layer-bar.l3 { + background: rgba(124, 92, 255, 0.12); + border: 1px solid rgba(124, 92, 255, 0.25); + color: var(--accent-purple); +} + +.arch-layer-bar.l2 { + background: rgba(0, 212, 170, 0.1); + border: 1px solid rgba(0, 212, 170, 0.2); + color: var(--accent-cyan); +} + +.arch-layer-bar.l1 { + background: rgba(136, 136, 170, 0.08); + border: 1px solid rgba(136, 136, 170, 0.15); + color: var(--text-muted); +} + +/* --- Tools --- */ +.tools-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + gap: 24px; + max-width: 900px; + margin: 0 auto 40px; +} + +.tool-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + padding: 28px; +} + +.tool-card h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 8px; + color: var(--accent-cyan); +} + +.tool-card p { + color: var(--text-muted); + font-size: 0.88rem; + line-height: 1.5; +} + +.config-example { + max-width: 700px; + margin: 0 auto; +} + +.config-example h3 { + font-family: var(--font-mono); + font-size: 1rem; + margin-bottom: 12px; + text-align: center; +} + +.config-example pre { + margin-left: 0; +} + +/* --- Footer --- */ +.footer { + border-top: 1px solid var(--border-color); + padding: 48px 0; + text-align: center; +} + +.footer-links { + display: flex; + justify-content: center; + gap: 24px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.footer-links a { + color: var(--text-muted); + font-size: 0.85rem; +} + +.footer-links a:hover { + color: var(--accent-blue); +} + +.footer-meta { + color: var(--text-dim); + font-size: 0.8rem; + line-height: 1.8; +} + +.footer-meta .version { + font-family: var(--font-mono); + display: inline-block; + padding: 2px 10px; + border-radius: 4px; + background: rgba(74, 158, 255, 0.1); + color: var(--accent-blue); + font-size: 0.75rem; +} + +/* --- Responsive --- */ +@media (max-width: 768px) { + :root { + --section-padding: 60px 0; + --nav-height: 56px; + } + + .nav-links, + .nav-github-desktop { + display: none; + } + + .hamburger { + display: flex; + } + + .nav-mobile { + display: none; + position: fixed; + top: var(--nav-height); + left: 0; + right: 0; + bottom: 0; + background: rgba(10, 10, 15, 0.98); + backdrop-filter: blur(12px); + z-index: 999; + padding: 24px; + } + + .nav-mobile.open { + display: flex; + flex-direction: column; + gap: 4px; + } + + .nav-mobile a { + color: var(--text-muted); + font-size: 1.1rem; + padding: 14px 16px; + border-radius: 8px; + display: block; + transition: background 0.2s, color 0.2s; + } + + .nav-mobile a:hover, + .nav-mobile a.active { + background: rgba(74, 158, 255, 0.1); + color: var(--text-primary); + } + + .features-grid { + grid-template-columns: 1fr; + } + + .examples-grid { + grid-template-columns: 1fr; + } + + .tools-grid { + grid-template-columns: 1fr; + } + + pre { + margin-left: 0; + font-size: 0.8rem; + padding: 16px; + } + + .step p { + padding-left: 0; + } + + .arch-flow { + flex-direction: column; + } + + .hero-stats { + flex-direction: column; + align-items: center; + } +} + +@media (max-width: 480px) { + .hero h1 { + letter-spacing: -1px; + } + + .section-header { + margin-bottom: 40px; + } + + .feature-card { + padding: 24px; + } + + .module-category-header { + padding: 14px 16px; + } +} diff --git a/site/img/favicon.svg b/site/img/favicon.svg new file mode 100644 index 0000000..7f0bbde --- /dev/null +++ b/site/img/favicon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..5c51fd4 --- /dev/null +++ b/site/index.html @@ -0,0 +1,915 @@ + + + + + + rust-psp — A Modern Rust SDK for Sony PSP Homebrew + + + + + + + + + + + + + +
+
+
+ + + + + + + + +
+ +
+

rust-psp

+

A Modern Rust SDK for Sony PSP Homebrew Development

+

Edition 2024 · Safety Hardened · Kernel Mode Support

+ +
+ 829 Syscalls + 38 SDK Modules + 30 Examples +
+ + +
+
+ + +
+
+
+

Why rust-psp?

+

Everything you need to write modern, safe homebrew for the PSP.

+
+ +
+
+ 📡 +

Complete Syscall Coverage

+

829 bindings across 33 modules covering every PSP subsystem — graphics, audio, networking, I/O, threading, and more.

+
+
+ 🛡 +

Safe Rust Abstractions

+

38 high-level modules with RAII resource management, Result types, and zero panics in allocators or VRAM code.

+
+
+ 🔑 +

Kernel Mode Support

+

Privileged APIs for NAND flash, IR remote, ME coprocessor, syscall hooking, and hardware register I/O.

+
+
+ 🔧 +

Full Build Toolchain

+

cargo-psp wraps the entire pipeline: Rust source to ELF to PRX to EBOOT.PBP with a single command.

+
+
+ 📚 +

Experimental std Support

+

Use String, Vec, HashMap, and the full Rust standard library on PSP for familiar, productive development.

+
+
+ +

CI-Tested in Emulator

+

Automated integration tests run in PPSSPPHeadless via Docker, ensuring code works on real PSP hardware.

+
+
+
+
+ + +
+
+
+

Quick Start

+

Get from zero to running PSP homebrew in minutes.

+
+ +
+
+
+ 1 +

Install Prerequisites

+
+

You'll need Rust nightly and the source component for cross-compilation.

+
bash
+rustup default nightly
+rustup component add rust-src
+
+ +
+
+ 2 +

Install cargo-psp

+
+

Download a prebuilt binary from Releases, or build from source.

+
bash
+# From crates.io (or GitHub Releases for prebuilt binaries)
+cargo install cargo-psp
+
+ +
+
+ 3 +

Create a PSP Project

+
+

Set up a new Cargo project and write your first PSP module.

+
bash
+cargo new hello-psp && cd hello-psp
+

Add psp to your Cargo.toml, then write your entry point:

+
rust
+#![no_std]
+#![no_main]
+
+use psp;
+
+psp::module!("hello_psp", 1, 1);
+
+fn psp_main() {
+    psp::dprintln!("Hello from the PSP!");
+}
+
+ +
+
+ 4 +

Build

+
+

Build your project into an EBOOT.PBP that the PSP can run.

+
bash
+cargo +nightly psp --release
+# Output: target/mipsel-sony-psp/release/EBOOT.PBP
+
+ +
+
+ 5 +

Run

+
+

Copy the EBOOT.PBP to your PSP's ms0:/PSP/GAME/hello_psp/ folder, or open it in PPSSPP.

+
+
+
+
+ + +
+
+
+

SDK Modules

+

38 high-level modules organized by domain. Click a category to explore.

+
+ +
+ + +
+
+

System & Lifecycle 8

+ +
+
+
+ callback +
+
Exit callback registration and lifecycle management
+
setup_exit_callback, register_exit_callback
+
+
+
+ power +
+
CPU/bus clock control, battery info, power event callbacks
+
ClockFrequency, get_clock, set_clock, on_power_event
+
+
+
+ display +
+
Framebuffer configuration and VBlank synchronization
+
wait_vblank, set_framebuf, get_framebuf
+
+
+
+ time +
+
High-resolution timing with Instant, Duration, and DateTime
+
Instant, Duration, DateTime, FrameTimer
+
+
+
+ timer +
+
One-shot alarms and virtual timers with microsecond precision
+
Alarm, VTimer
+
+
+
+ dialog +
+
System message, confirm, and error dialogs via utility API
+
message_dialog, confirm_dialog, MessageDialogBuilder
+
+
+
+ system_param +
+
System parameter queries (language, timezone, date format)
+
SystemParamLanguage, SystemParamDateFormat
+
+
+
+ rtc +
+
Real-time clock with date/time arithmetic operations
+
RtcTime, get_current_tick
+
+
+
+
+ + +
+
+

Threading & Synchronization 2

+ +
+
+
+ thread +
+
Thread spawning with builder pattern, join handles, and sleep
+
ThreadBuilder, JoinHandle, spawn, sleep_ms
+
+
+
+ sync +
+
Spinlock mutex/rwlock, SPSC queue, semaphore, event flags
+
SpinMutex, SpinRwLock, SpscQueue, Semaphore, EventFlag
+
+
+
+
+ + +
+
+

Input 2

+ +
+
+
+ input +
+
Controller polling with press/release detection and analog deadzone
+
Controller, ButtonState, AnalogStick
+
+
+
+ osk +
+
On-screen keyboard for text input via system utility
+
show_osk, OskBuilder
+
+
+
+
+ + +
+
+

File I/O & Configuration 3

+ +
+
+
+ io +
+
RAII file handles, directory iteration, read/write helpers
+
File, ReadDir, read_to_vec, write_bytes
+
+
+
+ config +
+
Key-value store with typed values and binary RCFG persistence
+
Config, load, save
+
+
+
+ savedata +
+
Game save/load via PSP savedata utility with metadata
+
SaveDataBuilder, save, load
+
+
+
+
+ + +
+
+

Audio 3

+ +
+
+
+ audio +
+
RAII audio channel with reserve/output/release lifecycle
+
AudioChannel, reserve, output_blocking
+
+
+
+ audio_mixer +
+
Multi-channel PCM mixer with volume control
+
AudioMixer, MixerChannel
+
+
+
+ audiocodec +
+
Hardware audio codec access (MP3, AAC, ATRAC3)
+
AudioCodec
+
+
+
+
+ + +
+
+

Graphics & Rendering 5

+ +
+
+
+ framebuffer +
+
Double-buffered rendering with dirty rect tracking and layer compositing
+
DoubleBuffer, DirtyRect, LayerCompositor
+
+
+
+ gu_ext +
+
GU state snapshots, 2D setup helpers, and sprite batching
+
GuStateSnapshot, setup_2d, SpriteBatch
+
+
+
+ simd +
+
VFPU-accelerated Vec4/Mat4, easing functions, color operations
+
Vec4, Mat4, vec4_length, vec4_distance
+
+
+
+ image +
+
JPEG hardware decode and BMP 24/32-bit decode with auto-detection
+
decode_jpeg, decode_bmp, load_image
+
+
+
+ font +
+
System font rendering with VRAM glyph atlas and CLUT alpha ramp
+
FontLib, Font, FontRenderer, GlyphAtlas
+
+
+
+
+ + +
+
+

Networking 3

+ +
+
+
+ net +
+
WiFi connection, RAII TCP/UDP sockets, DNS resolution
+
TcpStream, UdpSocket, connect_ap, resolve_hostname
+
+
+
+ http +
+
High-level HTTP client with GET/POST and response parsing
+
HttpClient, HttpResponse
+
+
+
+ wlan +
+
WLAN chip status, power state, and MAC address queries
+
WlanStatus, is_available, status
+
+
+
+
+ + +
+
+

Hardware & Memory 4

+ +
+
+
+ dma +
+
DMA memory transfer and VRAM blitting
+
DmaResult, memcpy_dma, vram_blit_dma
+
+
+
+ cache +
+
Cached/uncached pointer wrappers and data cache helpers
+
CachedPtr, UncachedPtr, dcache_flush
+
+
+
+ mem +
+
Typed kernel memory partition allocators
+
Partition2Alloc, Partition3Alloc
+
+
+
+ usb +
+
USB bus control and RAII storage mode
+
UsbStorageMode, start_bus, is_connected
+
+
+
+
+ + +
+
+

Kernel-Only 3

+ +
+
+
+ me +
+
Media Engine coprocessor boot and task submission
+
MeExecutor, MeSharedState
+
+
+
+ hw +
+
Hardware register I/O for direct peripheral access
+
read_reg, write_reg
+
+
+
+ hook +
+
CFW syscall hooking for kernel module development
+
SyscallHook
+
+
+
+
+ +
+
+
+ + +
+
+
+

Example Gallery

+

30 working examples covering graphics, audio, networking, input, and more.

+
+ +
+ + + + + + + + + + + +
+ +
+ +
+

audio-tone

+
Audio
+

Generates and plays a 440Hz sine wave tone for 3 seconds using the PSP audio subsystem.

+ View Source → +
+ +
+

clock-speed

+
System
+

Reads and sets PSP CPU/bus clock frequencies to maximum speed.

+ View Source → +
+ +
+

config-save

+
Storage
+

Saves and loads key-value configuration settings with multiple data types to binary RCFG format.

+ View Source → +
+ +
+

cube

+
GraphicsMath
+

Renders a rotating 3D textured cube using the GU graphics engine with matrix transforms and depth testing.

+ View Source → +
+ +
+

embedded-graphics

+
GraphicsText
+

Draws shapes and text using the embedded-graphics library including triangles, rectangles, and circles.

+ View Source → +
+ +
+

file-io

+
Storage
+

Demonstrates basic file I/O operations writing and reading text files to the host filesystem.

+ View Source → +
+ +
+

fontdue-scrolltext

+
GraphicsText
+

Renders scrolling text with fontdue library using sine wave animation and VRAM sprite batching.

+ View Source → +
+ +
+

gu-background

+
Graphics
+

Basic GU graphics initialization and display setup showing a colored background.

+ View Source → +
+ +
+

gu-debug-print

+
GraphicsText
+

Uses GU debug print functionality to render text directly to the graphics display.

+ View Source → +
+ +
+

hello-world

+
System
+

Minimal example that prints a hello message to the debug output.

+ View Source → +
+ +
+

http-client

+
Networking
+

High-level HTTP GET requests via psp::http::HttpClient with WiFi connectivity.

+ View Source → +
+ +
+

input-analog

+
Input
+

Reads analog stick input with deadzone normalization and button press detection.

+ View Source → +
+ +
+

kernel-mode

+
KernelSystem
+

Demonstrates kernel-mode privileged APIs including ME clock, volatile memory, NAND flash, and hardware registers.

+ View Source → +
+ +
+

msg-dialog

+
GraphicsInput
+

Displays a message dialog box using the GU-rendered system dialog utility.

+ View Source → +
+ +
+

net-http

+
Networking
+

Connects via WiFi and performs HTTP GET requests using raw TCP sockets.

+ View Source → +
+ +
+

osk-input

+
InputText
+

Text input via on-screen keyboard (OSK) utility with both convenience function and builder pattern.

+ View Source → +
+ +
+

paint-mode

+
GraphicsInput
+

Simple drawing application with analog stick control and button-based tool selection.

+ View Source → +
+ +
+

rainbow

+
Graphics
+

Animated rainbow color transitions filling the screen via direct framebuffer manipulation.

+ View Source → +
+ +
+

ratatui

+
GraphicsText
+

Terminal UI rendering using ratatui library with styled text, borders, and layout widgets.

+ View Source → +
+ +
+

rtc-sysinfo

+
System
+

Reads RTC date/time with arithmetic and queries system parameters like language and timezone.

+ View Source → +
+ +
+

rust-std-hello-world

+
System
+

Uses Rust standard library with String, Vec, and format! macros in no_std PSP environment.

+ View Source → +
+ +
+

savedata

+
StorageGraphics
+

Saves and loads game data with metadata using the PSP savedata utility with GU rendering.

+ View Source → +
+ +
+

screenshot

+
GraphicsStorage
+

Captures the framebuffer as a BMP image and writes it to file.

+ View Source → +
+ +
+

system-font

+
GraphicsText
+

Renders system fonts with glyph atlas caching using PSP FontLib and FontRenderer API.

+ View Source → +
+ +
+

thread-sync

+
Threading
+

Spawns multiple threads sharing a SpinMutex counter with thread synchronization and join.

+ View Source → +
+ +
+

time

+
System
+

Reads and displays the current date and time from the PSP real-time clock.

+ View Source → +
+ +
+

timer-alarm

+
Threading
+

Sets one-shot alarm callbacks and virtual timers with microsecond precision time measurement.

+ View Source → +
+ +
+

vfpu-addition

+
Math
+

Performs integer addition using VFPU (Vector FPU) inline assembly with float conversion.

+ View Source → +
+ +
+

vfpu-context-switching

+
Math
+

Demonstrates VFPU context save/restore with matrix operations preserving register state.

+ View Source → +
+ +
+

wlan

+
NetworkingSystem
+

Queries WLAN chip status including power state, switch state, and MAC address.

+ View Source → +
+ +
+
+
+ + +
+
+
+

Architecture Overview

+

How rust-psp is structured and how your code becomes a PSP executable.

+
+ +
+
+

Two-Workspace Layout

+
+
Root Workspace
psp crate, examples, CI tests
Target: mipsel-sony-psp
+   &   +
cargo-psp Workspace
Build tools (cargo-psp, prxgen, etc.)
Target: host architecture
+
+
+ +
+

Build Pipeline

+
+
Rust Source
+ +
cargo build
+ +
ELF
+ +
prxgen
+ +
PRX
+ +
pack-pbp
+ +
EBOOT.PBP
+
+
+ +
+

PSP Crate Layer Cake

+
+
+
Your Code
+
+
+
SDK Modules (38 high-level APIs)
+
+
+
sys/ Bindings (829 syscall stubs via psp_extern!)
+
+
+
PSP OS Kernel (NID resolution at load time)
+
+
+
+ +
+

Module System

+

+ PSP executables require specific ELF sections: .rodata.sceModuleInfo for module metadata, + .lib.stub for import stubs, and .lib.ent for exports. The psp_extern! + macro generates syscall stubs with NIDs (Numeric IDs) — the first 4 bytes of SHA-1(function_name) + in little-endian — which the PSP OS resolves at load time. Module flags 0x0000 for user-mode, + 0x1000 for kernel-mode. +

+
+
+
+
+ + +
+
+
+

Build Tools

+

The cargo-psp suite handles every step from Rust source to PSP executable.

+
+ +
+
+

cargo-psp

+

The main build command. Wraps cargo build, invokes prxgen and pack-pbp automatically, and reads project metadata from Psp.toml. Supports --release, --features, and custom target directories.

+
+
+

prxgen

+

Converts a MIPS ELF binary into PSP's PRX (relocatable module) format. Processes import/export tables and fixes up relocations for the PSP loader.

+
+
+

pack-pbp

+

Creates PBP archives — the PSP's executable package format. Bundles the PRX with SFO metadata, optional icons (ICON0.PNG), backgrounds, and startup sounds.

+
+
+

mksfo

+

Generates SFO (System File Object) metadata files containing the game title, disc ID, firmware version requirements, and parental control level.

+
+
+

prxmin

+

Minimizes PRX files by stripping debug sections and unnecessary ELF data, reducing the final binary size for distribution.

+
+
+ +
+

Psp.toml Configuration

+
toml
+# Project metadata for pack-pbp
+[metadata]
+title = "My PSP Game"
+disc_id = "RUST00001"
+disc_version = "1.00"
+firmware_version = "6.60"
+
+# Optional assets
+icon0 = "assets/icon.png"
+pic1 = "assets/background.png"
+
+# Localized titles
+[metadata.titles]
+japanese = "PSPゲーム"
+english = "My PSP Game"
+
+
+
+ + + + + + + diff --git a/site/js/main.js b/site/js/main.js new file mode 100644 index 0000000..a972631 --- /dev/null +++ b/site/js/main.js @@ -0,0 +1,122 @@ +/* ============================================ + rust-psp GitHub Pages — Interactivity + ============================================ */ + +(function () { + 'use strict'; + + // --- Nav scroll effect --- + const nav = document.querySelector('.nav'); + function updateNav() { + nav.classList.toggle('scrolled', window.scrollY > 40); + } + window.addEventListener('scroll', updateNav, { passive: true }); + updateNav(); + + // --- Smooth scrolling for anchor links --- + document.querySelectorAll('a[href^="#"]').forEach(function (link) { + link.addEventListener('click', function (e) { + var target = document.querySelector(this.getAttribute('href')); + if (target) { + e.preventDefault(); + target.scrollIntoView({ behavior: 'smooth', block: 'start' }); + // Close mobile menu if open + closeMobileMenu(); + } + }); + }); + + // --- Active nav link highlighting --- + var sections = document.querySelectorAll('section[id]'); + var navLinks = document.querySelectorAll('.nav-links a, .nav-mobile a'); + + var sectionObserver = new IntersectionObserver( + function (entries) { + entries.forEach(function (entry) { + if (entry.isIntersecting) { + var id = entry.target.getAttribute('id'); + navLinks.forEach(function (link) { + link.classList.toggle( + 'active', + link.getAttribute('href') === '#' + id + ); + }); + } + }); + }, + { rootMargin: '-20% 0px -60% 0px' } + ); + + sections.forEach(function (section) { + sectionObserver.observe(section); + }); + + // --- Mobile hamburger menu --- + var hamburger = document.querySelector('.hamburger'); + var mobileMenu = document.querySelector('.nav-mobile'); + + function closeMobileMenu() { + if (hamburger && mobileMenu) { + hamburger.classList.remove('open'); + mobileMenu.classList.remove('open'); + document.body.style.overflow = ''; + } + } + + if (hamburger && mobileMenu) { + hamburger.addEventListener('click', function () { + var isOpen = hamburger.classList.toggle('open'); + mobileMenu.classList.toggle('open', isOpen); + document.body.style.overflow = isOpen ? 'hidden' : ''; + }); + } + + // --- Scroll-triggered fade-in animations --- + var fadeElements = document.querySelectorAll('.fade-in'); + var fadeObserver = new IntersectionObserver( + function (entries) { + entries.forEach(function (entry) { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + fadeObserver.unobserve(entry.target); + } + }); + }, + { threshold: 0.1, rootMargin: '0px 0px -40px 0px' } + ); + + fadeElements.forEach(function (el) { + fadeObserver.observe(el); + }); + + // --- Module category expand/collapse --- + document.querySelectorAll('.module-category-header').forEach(function (header) { + header.addEventListener('click', function () { + this.parentElement.classList.toggle('open'); + }); + }); + + // --- Example gallery tag filtering --- + var filterBtns = document.querySelectorAll('.filter-btn'); + var exampleCards = document.querySelectorAll('.example-card'); + + filterBtns.forEach(function (btn) { + btn.addEventListener('click', function () { + var tag = this.getAttribute('data-tag'); + + // Update active button + filterBtns.forEach(function (b) { b.classList.remove('active'); }); + this.classList.add('active'); + + // Filter cards + exampleCards.forEach(function (card) { + if (tag === 'all') { + card.classList.remove('hidden'); + } else { + var cardTags = card.getAttribute('data-tags'); + card.classList.toggle('hidden', !cardTags.includes(tag)); + } + }); + }); + }); +})(); From 0714f843a7fcfc0ffc76ac4251fe6c2d72fb4fd8 Mon Sep 17 00:00:00 2001 From: AI Review Agent Date: Wed, 25 Feb 2026 02:19:57 -0600 Subject: [PATCH 2/4] fix: address AI review bugs in GitHub Pages site - Fix DOMException crash from querySelector('#') on logo/back-to-top links by special-casing href="#" to scroll to top - Hide .nav-mobile on desktop with base display:none rule (was only styled inside mobile media query, causing duplicate nav on wide screens) - Add type="button" to hamburger menu button Co-Authored-By: Claude Opus 4.6 --- site/css/style.css | 5 +++++ site/index.html | 2 +- site/js/main.js | 10 ++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/site/css/style.css b/site/css/style.css index a7050cf..252ac0d 100644 --- a/site/css/style.css +++ b/site/css/style.css @@ -181,6 +181,11 @@ img { transform: rotate(-45deg) translate(5px, -5px); } +/* Mobile nav overlay (hidden by default, shown via JS on small screens) */ +.nav-mobile { + display: none; +} + /* --- Hero --- */ .hero { position: relative; diff --git a/site/index.html b/site/index.html index 5c51fd4..75a36b0 100644 --- a/site/index.html +++ b/site/index.html @@ -27,7 +27,7 @@ GitHub -