mruby-portable

mruby-portable builds small Ruby games for the PlayStation Portable by combining mruby, SDL2, SDL_image, SDL_ttf, and PSPDEV inside Docker. Write game code in Ruby, run mrp build, and get an EBOOT.PBP.

日本語: mruby-portable は、Ruby で書いた小さなゲームを PSP 用の EBOOT.PBP にビルドするためのツールです。PSPDEV や mruby のクロスビルド環境は Docker イメージ内に閉じ込め、普段は mrp コマンドだけで扱えるようにしています。

Status

This is an early 0.1.x release for PSP homebrew experiments. The public Ruby API is intentionally small and focused on 2D drawing, text, images, input, and simple project packaging.

Requirements

  • Ruby 3.2 or newer
  • Docker
  • A PSP homebrew runtime or emulator that can run the generated EBOOT.PBP

The first image build downloads and compiles PSPDEV, mruby, SDL2, SDL_image, and SDL_ttf inside a local Docker image named mruby-portable-builder:<version>.

Installation

Install the released gem:

gem install mruby-portable

Or install from a checkout:

git clone https://github.com/saeki-mototsune/mruby-portable.git
cd mruby-portable
gem build mruby-portable.gemspec
gem install ./mruby-portable-*.gem

Quick Start

mrp doctor
mrp new my_game
cd my_game
mrp build

The output is written to dist/my_game/EBOOT.PBP. Project assets are copied beside it in dist/my_game/assets.

Commands

mrp new NAME                  # Create a new game project
mrp doctor                    # Check Docker and builder image availability
mrp image build               # Build the local Docker builder image
mrp build [PROJECT_DIR]       # Build a release EBOOT.PBP
mrp build --mode dev [DIR]    # Build with Ruby files kept external
mrp build --out DIR [DIR]     # Write output to a custom directory

Release builds embed Ruby code into EBOOT.PBP and copy assets beside it. Dev builds keep main.rb and lib/psp_game.rb as external files beside EBOOT.PBP, which is useful while iterating.

Project Config

Generated projects include mruby-portable.yml:

name: my_game
title: my_game
version: "01.00"
main: main.rb
assets: assets

# Optional XMB assets:
# icon: xmb/icon.png
# background: xmb/background.png
# preview: xmb/preview.png
# preview_video: xmb/preview.pmf

icon should be a 144x82 PNG. background and preview should be 480x272 PNG files. preview_video should be a PSP-compatible PMF file. mruby-portable copies these files into the build workspace and passes them to PSPDEV when creating EBOOT.PBP; it does not resize, convert, or generate PMF files.

Runtime API

Every generated project starts with main.rb. Use Game.run for the frame loop and Game.draw for drawable objects:

Game.background = Color.rgba(20, 24, 32, 255)

player = Rect.new(x: 220, y: 120, w: 24, h: 24, color: Color.rgba(255, 255, 255, 255))
speed = 120.0

Game.run do |dt|
  player.x -= speed * dt if Input.down?(:left)
  player.x += speed * dt if Input.down?(:right)

  Game.draw(player)
end

Images

Put .png, .jpg, or .jpeg files in your project's assets directory and draw them with Sprite:

player = Sprite.new("assets/player.jpg", x: 120, y: 80)

Game.run do |_dt|
  Game.draw(player)
end

Sprite#w and Sprite#h can scale the image. Sprite#original_w and Sprite#original_h report the loaded image size. For sprite sheets, set Sprite#src_rect to [x, y, w, h].

Text

Text uses the bundled Press Start 2P font by default:

label = Text.new("Hello PSP", x: 16, y: 16, color: Color.rgba(255, 255, 255, 255))

Game.run do |_dt|
  Game.draw(label)
end

For Japanese or other glyphs that Press Start 2P does not include, put a .ttf or .otf file in your project's assets directory and pass a custom Font:

font = Font.new("assets/fonts/NotoSansJP-Regular.ttf", size: 18)
label = Text.new("こんにちは", font: font, x: 16, y: 16, color: Color.rgba(255, 255, 255, 255))

Game.run do |_dt|
  Game.draw(label)
end

Text#text, Text#x, Text#y, and Text#color can be changed while the game is running. Text#w and Text#h report the rendered size.

Input

Use Input.down?, Input.pressed?, and Input.released? for PSP buttons:

Game.stop if Input.pressed?(:start)

The analog stick is available as normalized values from -1.0 to 1.0:

Game.run do |dt|
  x, y = Input.joystick
  player.x += x * speed * dt
  player.y += y * speed * dt
end

Input.joystick_x is negative to the left and positive to the right. Input.joystick_y is negative upward and positive downward. Small movement near the center is treated as 0.0.

Development

Run the Ruby test suite:

ruby -Ilib test/all.rb

Run the Docker smoke test when Docker is available:

MRUBY_PORTABLE_DOCKER_SMOKE=1 ruby -Ilib test/all.rb

Troubleshooting

  • mrp doctor reports Docker: missing: install or start Docker.
  • Builder image ...: missing: run mrp image build, or run mrp build and let it build the image automatically.
  • Missing XMB asset errors: check paths in mruby-portable.yml; paths are relative to the project directory.
  • Custom font text does not render as expected: make sure the font file contains the glyphs you are drawing.

License

mruby-portable is released under the MIT License. The bundled default font is Press Start 2P by CodeMan38, distributed under the SIL Open Font License 1.1 with its license files in templates/runtime/assets/mruby-portable/fonts.