RP6502-WEB¶
RP6502 - Web Player
Introduction¶
With the RP6502-WEB, you can put a playable game on the GitHub page of your project, upload it to itch.io, or put it on your blog. One click on the link starts the game in a web browser, with no download and no emulator to install.
The RP6502-WEB is the machine for the web. It is a Picocomputer hosted in a web browser, with sound, a keyboard, a mouse, and up to four gamepads. The browser can keep high scores and saved games between visits, as described in Saves.
A web player is the game, the emulator and a page, which rp6502_web()
builds into one zip. For GitHub Pages, a workflow
builds and publishes the web players of a repository on every push to
main, with a screenshot for the README. The same zip can be
uploaded to itch.io, and any web server that serves plain files can host its files.
The Files¶
A web player is four files, served together from one folder:
index.html, the page, with the settings for the program.rp6502.jsandrp6502.wasm, the emulator.The ROM, such as
game.rp6502.
rp6502.js and rp6502.wasm are in the web zip on the releases
page, with a
sample index.html and program, and they are always replaced as a
pair. In a CMake project, rp6502_web() builds all four files into a
zip, as described in Building with CMake. index.html is not tied to
a release: the index.html described here needs release 0.36 or later,
and it works with the rp6502.js and rp6502.wasm of every later
release. Any change to the settings is listed in the release notes.
The Page¶
This index.html plays game.rp6502, which is in the same folder.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
var CONFIG = {
title: 'My Game',
rom: 'game.rp6502',
db: 'username-mygame',
};
</script>
<script src="rp6502.js" onerror="document.body.textContent = 'Could not load rp6502.js'"></script>
</body>
</html>
The settings are in CONFIG. The rp6502.js script goes last in
<body>, after everything else on the page, and it builds the page
around the emulator from those settings.
A browser does not run a web player opened as a file, from a file://
address, because the ROM and the WebAssembly load only from a web server.
To try a page on your own computer, start a web server in its folder and
open http://localhost:8000.
python3 -m http.server 8000
Setting |
Example |
Description |
|---|---|---|
|
|
The name in the browser tab. Default |
|
|
The ROM, as a path from |
|
|
The arguments for the program, argv[1] and on. |
|
|
Files for the program, as paths from |
|
|
The name of the IndexedDB database for saves. See Saves. |
|
|
The color around the picture when the page and the canvas have
different shapes, as six hex digits, RRGGBB. Default |
|
|
Space around the game, in the |
|
|
How pixels are scaled: |
|
|
The |
|
|
When the program starts: |
|
|
A line of HTML under the game, with links under it. See Footer. |
|
|
The GitHub repository linked under the footer. |
A setting that is left out, or left blank, is off or takes its default.
For example, Microsoft BASIC loads and runs a program named as an
argument, and -c1 keeps the keyboard in capitals:
rom: 'basic.rp6502',
install: ['game.bas'],
args: ['-c1', ':GAME.BAS'],
Saves¶
A program keeps high scores and saved games in files on the SAVE:
drive, as described in Saves. In a browser, those
files are stored in an IndexedDB database, and db is the name of
that database. A browser holds one set of IndexedDB databases for each
web site. A site that holds the games of many people shares that set
among them, so there, name the database with your full user name and the
full project name, such as rumbledethumps-flappycoo. A site of your
own, such as a GitHub Pages site, <user>.github.io, holds only your
projects, so there the full project name is enough. With db blank,
saves last until the page closes.
Click to Play¶
A browser plays no sound on a page until the player clicks the page or presses a key. While there is no sound, the click-to-play overlay covers the game with a play button, so that the player knows to click it. The click turns the sound on and removes the overlay. Where the browser plays sound at once, there is no overlay.
The overlay is a <template> in index.html. The browser keeps the
HTML in a template without showing it. overlay names the template by
its id, and the one element in the template is placed over the game.
Everything about the overlay, from the words to the colors, is in
index.html. To add a simple overlay to the page above, put this
style in <head> and this template in <body>, before the scripts:
<style>
.overlay {
position: absolute; inset: 0; cursor: pointer;
display: grid; place-items: center;
background: rgba(0, 0, 0, .5); color: #fff;
font: 20px system-ui, sans-serif;
}
</style>
<template id="overlay">
<div class="overlay">▶ Click to play</div>
</template>
Then turn it on in CONFIG:
overlay: 'overlay',
The index.html in the web zip has a round play button in its overlay
template, with settings at the top of its style:
.overlay {
--y: 50%; /* height of the button, from the top */
--size: clamp(56px, 18vmin, 96px); /* width of the button */
--shade: rgba(0, 0, 0, .45); /* over the game */
--y: 70% moves the button lower, over an empty part of a title
screen.
run sets when the program starts:
always, the default: at once, under the overlay while there is no sound.onaudio: when there is sound, so the program starts from the beginning with sound.onclick: at a click on the overlay or a key press, even where the browser plays sound at once.
License Notices¶
With ?credits at the end of its address, such as
https://example.com/game/?credits, the page shows the license notices
of the components in rp6502.js and rp6502.wasm.
Building with CMake¶
In a CMake project, rp6502_web() packages a ROM with the emulator and
a page into a zip, ready to upload. This line builds web/game.zip in
the build folder from the ROM of the game target, with the page from
the web zip and the emulator of the latest release:
rp6502_web(game)
The same files are unpacked next to it in web/game/. CONFIG sets
settings of the page, as JavaScript, with a comma after each one:
rp6502_web(game CONFIG [[
title: 'My Game',
footer: 'Arrows to move, Space to fire.',
]])
The settings replace the same settings in the page, and the others are
added. rom is always the ROM of the target, and github is the
GitHub repository that the git remote of the project names, unless
CONFIG names another. PAGE gives a page of
your own, and OUTPUT names the zip, so one ROM can be packaged for
several sites:
rp6502_web(game OUTPUT pages.zip PAGE web/pages.html)
rp6502_web(game OUTPUT arcade.zip PAGE web/arcade)
A file after PAGE is stored in the zip as index.html. A folder is
copied into the zip with its subfolders, and an index.html at its
root is the page. EMULATOR names the web zip that rp6502.js and
rp6502.wasm come from, in the forms of Fetching BASIC and the
Emulator:
rp6502_web(game EMULATOR v0.36)
In VS Code, choose “RP6502-WEB” in the Run and Debug side panel and press F5. The project is built, and the browser opens a page with a link to every web player in the build folder.
GitHub Pages¶
GitHub Pages publishes web pages from a GitHub repository, so a link in
the README of a game can open a web player for it. The players are named
in the markdown of the repository, and a workflow from
picocomputer/.github builds
each one with rp6502_web() and publishes it on every push to
main.
On GitHub, open Settings > Pages, and set Source to GitHub Actions.
Put this comment above the play link in
README.md, or in any other markdown file of the repository. GitHub does not show it.<!-- rp6502 preset: cc65/Release publish: game.zip --> [Play My Game](https://username.github.io/mygame/game/)
Add
.github/workflows/web.yml:name: Web on: push: branches: [main] workflow_dispatch: inputs: source: description: Branch, tag or commit to build emulator: description: Emulator, such as v0.36 jobs: web: uses: picocomputer/.github/.github/workflows/web.yml@main with: source: ${{ inputs.source }} emulator: ${{ inputs.emulator }} permissions: contents: read pages: write id-token: write
Push. Each player is at
https://<user>.github.io/<repository>/<name>/, where<name>is the zip without.zip, andhttps://<user>.github.io/<repository>/lists them.
A repository can have a comment for each of its zips, such as one for each example in a collection. Each line of a comment is a key and a value:
Key |
Description |
|---|---|
|
The CMake preset that builds the zip, such as |
|
The zip that |
|
The folder of the CMake project, when it is not the root of the repository. |
|
The number of frames, 60 a second, that the program runs before the screenshot. Default 120. |
The workflow also runs each ROM in the emulator and publishes the screen
at <name>/screenshot.png, 640 pixels wide, so that a README can show
a current picture of the program with no image in the repository.
frames sets how long the program runs first, such as until its title
screen. The program gets the same random numbers on every run, so the
same frames gives the same picture. This comment and link show the
screenshot:
<!-- rp6502
preset: llvm-mos/Release
publish: flappycoo.zip
-->
[](https://rumbledethumps.github.io/flappycoo/flappycoo/)
“Run workflow” on the Actions tab of the repository runs the workflow by
hand. source builds another branch, tag or commit of the repository,
and emulator replaces the EMULATOR of every rp6502_web(), in
the forms of Fetching BASIC and the Emulator. A commit
of the emulator is for testing: it comes from the CI build of that
commit, which is kept for 90 days, and the build of a pull request is the
pull request merged with main.
Other Web Servers¶
Any web server that serves plain files can host a web player: copy the
files of the zip into one folder. rp6502.wasm is loaded from the
folder of rp6502.js, and the ROM is loaded from a path relative to
index.html.
On itch.io, the zip is uploaded as it is, to a project of the HTML kind,
and marked to be played in the browser. itch.io serves the games of many
people from one site, so name db as described in Saves.
A web player can be shown inside another page with an <iframe>:
<iframe src="game/index.html" width="640" height="480"
allow="autoplay; fullscreen; gamepad"></iframe>
The game on the home page of this site is a web player in
an <iframe>.