mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Agb examples site (#705)
![image](https://github.com/agbrs/agb/assets/8143879/12163f27-1097-49fd-810c-a00f6cf5d8bf)
This commit is contained in:
commit
e06230efd0
|
@ -26,6 +26,7 @@ members = [
|
||||||
"emulator/mgba",
|
"emulator/mgba",
|
||||||
"emulator/mgba-sys",
|
"emulator/mgba-sys",
|
||||||
"emulator/test-runner",
|
"emulator/test-runner",
|
||||||
|
"emulator/screenshot-generator",
|
||||||
"website/backtrace",
|
"website/backtrace",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
#![no_std]
|
|
||||||
#![no_main]
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn __RUST_INTERRUPT_HANDLER(_: u16) {}
|
|
||||||
|
|
||||||
// implementation of tonc's "My first GBA demo"
|
|
||||||
// https://coranac.com/tonc/text/first.htm
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub fn main() -> ! {
|
|
||||||
unsafe {
|
|
||||||
*(0x0400_0000 as *mut u32) = 0x0403;
|
|
||||||
let video = 0x0600_0000 as *mut u16;
|
|
||||||
*video.offset(120 + 80 * 240) = 0x001F;
|
|
||||||
*video.offset(136 + 80 * 240) = 0x03E0;
|
|
||||||
*video.offset(120 + 96 * 240) = 0x7C00;
|
|
||||||
}
|
|
||||||
loop {}
|
|
||||||
}
|
|
13
emulator/screenshot-generator/Cargo.toml
Normal file
13
emulator/screenshot-generator/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "screenshot-generator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
mgba = { path = "../mgba" }
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
anyhow = "1"
|
||||||
|
image = { version = "0.24", default-features = false, features = [ "png", "bmp" ] }
|
||||||
|
agb-gbafix = { path = "../../agb-gbafix" }
|
23
emulator/screenshot-generator/src/image_generate.rs
Normal file
23
emulator/screenshot-generator/src/image_generate.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use image::{DynamicImage, GenericImage, Rgba};
|
||||||
|
|
||||||
|
const WIDTH: usize = 240;
|
||||||
|
const HEIGHT: usize = 160;
|
||||||
|
|
||||||
|
pub fn generate_image(video_buffer: &[u32]) -> DynamicImage {
|
||||||
|
let mut dynamic_image = DynamicImage::new(
|
||||||
|
WIDTH.try_into().unwrap(),
|
||||||
|
HEIGHT.try_into().unwrap(),
|
||||||
|
image::ColorType::Rgba8,
|
||||||
|
);
|
||||||
|
for y in 0..HEIGHT {
|
||||||
|
for x in 0..WIDTH {
|
||||||
|
let video_pixel = video_buffer[x + y * WIDTH];
|
||||||
|
let mut pixels = video_pixel.to_le_bytes();
|
||||||
|
pixels[3] = 255;
|
||||||
|
|
||||||
|
dynamic_image.put_pixel(x.try_into().unwrap(), y.try_into().unwrap(), Rgba(pixels));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_image
|
||||||
|
}
|
96
emulator/screenshot-generator/src/main.rs
Normal file
96
emulator/screenshot-generator/src/main.rs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fs::File,
|
||||||
|
io::{BufWriter, Read},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use clap::Parser;
|
||||||
|
use image::DynamicImage;
|
||||||
|
use image_generate::generate_image;
|
||||||
|
use mgba::{LogLevel, Logger, MCore, MemoryBacked, VFile};
|
||||||
|
|
||||||
|
mod image_generate;
|
||||||
|
|
||||||
|
static LOGGER: Logger = Logger::new(my_logger);
|
||||||
|
|
||||||
|
fn my_logger(_category: &str, _level: LogLevel, _s: String) {}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct CliArguments {
|
||||||
|
#[arg(long)]
|
||||||
|
rom: PathBuf,
|
||||||
|
#[arg(long)]
|
||||||
|
frames: usize,
|
||||||
|
#[arg(long)]
|
||||||
|
output: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ScreenshotGenerator {
|
||||||
|
mgba: MCore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScreenshotGenerator {
|
||||||
|
fn new<V: VFile>(rom: V) -> Result<Self, Box<dyn Error>> {
|
||||||
|
let mut mgba = MCore::new().ok_or(anyhow!("cannot create core"))?;
|
||||||
|
|
||||||
|
mgba::set_global_default_logger(&LOGGER);
|
||||||
|
|
||||||
|
mgba.load_rom(rom);
|
||||||
|
|
||||||
|
Ok(Self { mgba })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(mut self, frames: usize) -> DynamicImage {
|
||||||
|
for _ in 0..frames {
|
||||||
|
self.mgba.frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_image(self.mgba.video_buffer())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let args = CliArguments::parse();
|
||||||
|
|
||||||
|
let rom = load_rom(args.rom)?;
|
||||||
|
let rom = MemoryBacked::new(rom);
|
||||||
|
|
||||||
|
let image = ScreenshotGenerator::new(rom)?.run(args.frames);
|
||||||
|
|
||||||
|
let mut output = BufWriter::new(
|
||||||
|
File::options()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(args.output)?,
|
||||||
|
);
|
||||||
|
image.write_to(&mut output, image::ImageOutputFormat::Png)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_rom<P: AsRef<Path>>(path: P) -> anyhow::Result<Vec<u8>> {
|
||||||
|
let mut input_file = File::open(path)?;
|
||||||
|
let mut input_file_buffer = Vec::new();
|
||||||
|
|
||||||
|
input_file.read_to_end(&mut input_file_buffer)?;
|
||||||
|
|
||||||
|
let mut elf_buffer = Vec::new();
|
||||||
|
|
||||||
|
let inculde_debug_info = false;
|
||||||
|
if agb_gbafix::write_gba_file(
|
||||||
|
&input_file_buffer,
|
||||||
|
Default::default(),
|
||||||
|
agb_gbafix::PaddingBehaviour::DoNotPad,
|
||||||
|
inculde_debug_info,
|
||||||
|
&mut elf_buffer,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
Ok(elf_buffer)
|
||||||
|
} else {
|
||||||
|
Ok(input_file_buffer)
|
||||||
|
}
|
||||||
|
}
|
29
justfile
29
justfile
|
@ -112,8 +112,35 @@ build-combo-rom-site:
|
||||||
mkdir -p website/agb/src/roms
|
mkdir -p website/agb/src/roms
|
||||||
gzip -9 -c examples/target/examples/combo.gba > website/agb/src/roms/combo.gba.gz
|
gzip -9 -c examples/target/examples/combo.gba > website/agb/src/roms/combo.gba.gz
|
||||||
|
|
||||||
|
generate-screenshot *args:
|
||||||
|
(cd emulator/screenshot-generator && cargo build --release && cd "{{invocation_directory()}}" && "$CARGO_TARGET_DIR/release/screenshot-generator" {{args}})
|
||||||
|
|
||||||
setup-app-build: build-mgba-wasm build-combo-rom-site build-website-backtrace
|
|
||||||
|
build-site-examples: build-release
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
mkdir -p website/agb/src/roms/examples
|
||||||
|
|
||||||
|
EXAMPLES="$(cd agb/examples; ls *.rs)"
|
||||||
|
EXAMPLE_DEFINITIONS="export const Examples: {url: URL, example_name: string, screenshot: StaticImageData }[] = [" > website/agb/src/roms/examples/examples.ts
|
||||||
|
EXAMPLE_IMAGE_IMPORTS="import { StaticImageData } from 'next/image';";
|
||||||
|
|
||||||
|
for EXAMPLE_NAME in $EXAMPLES; do
|
||||||
|
EXAMPLE="${EXAMPLE_NAME%.rs}"
|
||||||
|
just gbafix "$CARGO_TARGET_DIR/thumbv4t-none-eabi/release/examples/$EXAMPLE" --output="$CARGO_TARGET_DIR/thumbv4t-none-eabi/release/examples/$EXAMPLE.gba"
|
||||||
|
gzip -9 -c $CARGO_TARGET_DIR/thumbv4t-none-eabi/release/examples/$EXAMPLE.gba > website/agb/src/roms/examples/$EXAMPLE.gba.gz
|
||||||
|
just generate-screenshot --rom="$CARGO_TARGET_DIR/thumbv4t-none-eabi/release/examples/$EXAMPLE.gba" --frames=10 --output=website/agb/src/roms/examples/$EXAMPLE.png
|
||||||
|
EXAMPLE_IMAGE_IMPORTS="$EXAMPLE_IMAGE_IMPORTS import $EXAMPLE from './$EXAMPLE.png';"
|
||||||
|
EXAMPLE_DEFINITIONS="$EXAMPLE_DEFINITIONS {url: new URL('./$EXAMPLE.gba.gz', import.meta.url), example_name: '$EXAMPLE', screenshot: $EXAMPLE},"
|
||||||
|
done
|
||||||
|
|
||||||
|
EXAMPLE_DEFINITIONS="$EXAMPLE_DEFINITIONS ];"
|
||||||
|
echo "$EXAMPLE_IMAGE_IMPORTS" > website/agb/src/roms/examples/examples.ts
|
||||||
|
echo "$EXAMPLE_DEFINITIONS" >> website/agb/src/roms/examples/examples.ts
|
||||||
|
|
||||||
|
|
||||||
|
setup-app-build: build-mgba-wasm build-combo-rom-site build-website-backtrace build-site-examples
|
||||||
(cd website/agb && npm install --no-save --prefer-offline --no-audit)
|
(cd website/agb && npm install --no-save --prefer-offline --no-audit)
|
||||||
|
|
||||||
build-site-app: setup-app-build
|
build-site-app: setup-app-build
|
||||||
|
|
3
website/agb/.gitignore
vendored
3
website/agb/.gitignore
vendored
|
@ -38,4 +38,5 @@ next-env.d.ts
|
||||||
vendor
|
vendor
|
||||||
|
|
||||||
*.gba
|
*.gba
|
||||||
*.gba.gz
|
*.gba.gz
|
||||||
|
src/roms
|
285
website/agb/package-lock.json
generated
285
website/agb/package-lock.json
generated
|
@ -11,6 +11,7 @@
|
||||||
"next": "14.2.3",
|
"next": "14.2.3",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"sharp": "^0.33.3",
|
"sharp": "^0.33.3",
|
||||||
"styled-components": "^6.1.8"
|
"styled-components": "^6.1.8"
|
||||||
},
|
},
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/styled-components": "^5.1.34",
|
"@types/styled-components": "^5.1.34",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.3",
|
"eslint-config-next": "14.2.3",
|
||||||
|
@ -37,7 +39,6 @@
|
||||||
"version": "7.24.4",
|
"version": "7.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
||||||
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
|
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
|
@ -861,6 +862,15 @@
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hast": {
|
||||||
|
"version": "2.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||||
|
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/hoist-non-react-statics": {
|
"node_modules/@types/hoist-non-react-statics": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
|
||||||
|
@ -911,6 +921,16 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-syntax-highlighter": {
|
||||||
|
"version": "15.5.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz",
|
||||||
|
"integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/styled-components": {
|
"node_modules/@types/styled-components": {
|
||||||
"version": "5.1.34",
|
"version": "5.1.34",
|
||||||
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz",
|
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz",
|
||||||
|
@ -927,6 +947,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz",
|
||||||
"integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw=="
|
"integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/unist": {
|
||||||
|
"version": "2.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
||||||
|
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "6.21.0",
|
"version": "6.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
|
||||||
|
@ -1453,6 +1479,36 @@
|
||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/character-entities": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/character-entities-legacy": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/character-reference-invalid": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/client-only": {
|
"node_modules/client-only": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
@ -1495,6 +1551,16 @@
|
||||||
"simple-swizzle": "^0.2.2"
|
"simple-swizzle": "^0.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/comma-separated-tokens": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
@ -2355,6 +2421,19 @@
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fault": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"format": "^0.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
|
@ -2440,6 +2519,14 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/format": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
|
@ -2742,6 +2829,42 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hast-util-parse-selector": {
|
||||||
|
"version": "2.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||||
|
"integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hastscript": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"comma-separated-tokens": "^1.0.0",
|
||||||
|
"hast-util-parse-selector": "^2.0.0",
|
||||||
|
"property-information": "^5.0.0",
|
||||||
|
"space-separated-tokens": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/highlight.js": {
|
||||||
|
"version": "10.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||||
|
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hoist-non-react-statics": {
|
"node_modules/hoist-non-react-statics": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
|
@ -2815,6 +2938,30 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-alphabetical": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-alphanumerical": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-alphabetical": "^1.0.0",
|
||||||
|
"is-decimal": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
|
@ -2933,6 +3080,16 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-decimal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-extglob": {
|
"node_modules/is-extglob": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
@ -2990,6 +3147,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-hexadecimal": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-map": {
|
"node_modules/is-map": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
|
||||||
|
@ -3352,6 +3519,20 @@
|
||||||
"loose-envify": "cli.js"
|
"loose-envify": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lowlight": {
|
||||||
|
"version": "1.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz",
|
||||||
|
"integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fault": "^1.0.0",
|
||||||
|
"highlight.js": "~10.7.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
|
||||||
|
@ -3684,6 +3865,24 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parse-entities": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"character-entities": "^1.0.0",
|
||||||
|
"character-entities-legacy": "^1.0.0",
|
||||||
|
"character-reference-invalid": "^1.0.0",
|
||||||
|
"is-alphanumerical": "^1.0.0",
|
||||||
|
"is-decimal": "^1.0.0",
|
||||||
|
"is-hexadecimal": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/path-exists": {
|
"node_modules/path-exists": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
@ -3809,6 +4008,15 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prismjs": {
|
||||||
|
"version": "1.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
|
||||||
|
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prop-types": {
|
"node_modules/prop-types": {
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
@ -3820,6 +4028,19 @@
|
||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/property-information": {
|
||||||
|
"version": "5.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
|
||||||
|
"integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"xtend": "^4.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
@ -3878,6 +4099,22 @@
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/react-syntax-highlighter": {
|
||||||
|
"version": "15.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
|
||||||
|
"integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.3.1",
|
||||||
|
"highlight.js": "^10.4.1",
|
||||||
|
"lowlight": "^1.17.0",
|
||||||
|
"prismjs": "^1.27.0",
|
||||||
|
"refractor": "^3.6.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 0.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/reflect.getprototypeof": {
|
"node_modules/reflect.getprototypeof": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
||||||
|
@ -3899,11 +4136,34 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/refractor": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"hastscript": "^6.0.0",
|
||||||
|
"parse-entities": "^2.0.0",
|
||||||
|
"prismjs": "~1.27.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/refractor/node_modules/prismjs": {
|
||||||
|
"version": "1.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
||||||
|
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/regexp.prototype.flags": {
|
"node_modules/regexp.prototype.flags": {
|
||||||
"version": "1.5.2",
|
"version": "1.5.2",
|
||||||
|
@ -4247,6 +4507,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/space-separated-tokens": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/streamsearch": {
|
"node_modules/streamsearch": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||||
|
@ -4936,6 +5206,15 @@
|
||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/xtend": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
"next": "14.2.3",
|
"next": "14.2.3",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"sharp": "^0.33.3",
|
"sharp": "^0.33.3",
|
||||||
"styled-components": "^6.1.8"
|
"styled-components": "^6.1.8"
|
||||||
},
|
},
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/styled-components": "^5.1.34",
|
"@types/styled-components": "^5.1.34",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.3",
|
"eslint-config-next": "14.2.3",
|
||||||
|
|
21
website/agb/src/app/examples/[example]/emulator.tsx
Normal file
21
website/agb/src/app/examples/[example]/emulator.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import MgbaWrapper from "@/components/mgba/mgbaWrapper";
|
||||||
|
import { Examples } from "@/roms/examples/examples";
|
||||||
|
import { slugify } from "@/sluggify";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
function gameUrl(exampleName: string) {
|
||||||
|
const example = Examples.find((x) => slugify(x.example_name) === exampleName);
|
||||||
|
if (!example) {
|
||||||
|
throw new Error(`cannot find example ${exampleName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return example.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Emulator({ exampleName }: { exampleName: string }) {
|
||||||
|
const example = useMemo(() => gameUrl(exampleName), [exampleName]);
|
||||||
|
|
||||||
|
return <MgbaWrapper gameUrl={example} />;
|
||||||
|
}
|
58
website/agb/src/app/examples/[example]/page.tsx
Normal file
58
website/agb/src/app/examples/[example]/page.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { Examples } from "@/roms/examples/examples";
|
||||||
|
import { slugify } from "@/sluggify";
|
||||||
|
import { Emulator } from "./emulator";
|
||||||
|
import { ContentBlock } from "@/components/contentBlock";
|
||||||
|
import * as fs from "node:fs/promises";
|
||||||
|
import { BackToExampleLink, Code } from "./styles";
|
||||||
|
|
||||||
|
export async function generateStaticParams() {
|
||||||
|
return Examples.map((example) => ({
|
||||||
|
example: slugify(example.example_name),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExample(sluggedExample: string) {
|
||||||
|
const example = Examples.find(
|
||||||
|
(x) => slugify(x.example_name) === sluggedExample
|
||||||
|
);
|
||||||
|
if (!example) {
|
||||||
|
throw new Error(`cannot find example ${sluggedExample}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return example;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSourceCode(exampleName: string) {
|
||||||
|
const source = await fs.readFile(`../../agb/examples/${exampleName}.rs`);
|
||||||
|
|
||||||
|
return source.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { example: string };
|
||||||
|
}) {
|
||||||
|
const exmaple = getExample(params.example);
|
||||||
|
const source = await loadSourceCode(exmaple.example_name);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ContentBlock color="#9fa6db">
|
||||||
|
<h1>Example: {params.example}</h1>
|
||||||
|
<BackToExampleLink href={`../examples#${params.example}`}>
|
||||||
|
<strong><</strong> Back to examples
|
||||||
|
</BackToExampleLink>
|
||||||
|
</ContentBlock>
|
||||||
|
<ContentBlock>
|
||||||
|
<Emulator exampleName={params.example} />
|
||||||
|
</ContentBlock>
|
||||||
|
<ContentBlock>
|
||||||
|
<Code language="rust">{source}</Code>
|
||||||
|
</ContentBlock>
|
||||||
|
<ContentBlock color="#f5755e">
|
||||||
|
<></>
|
||||||
|
</ContentBlock>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
14
website/agb/src/app/examples/[example]/styles.tsx
Normal file
14
website/agb/src/app/examples/[example]/styles.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
|
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||||
|
import { styled } from "styled-components";
|
||||||
|
|
||||||
|
export const Code = styled(SyntaxHighlighter)`
|
||||||
|
font-size: 0.8rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const BackToExampleLink = styled(Link)`
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
`;
|
42
website/agb/src/app/examples/page.tsx
Normal file
42
website/agb/src/app/examples/page.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { ContentBlock } from "@/components/contentBlock";
|
||||||
|
import { slugify } from "@/sluggify";
|
||||||
|
import { GameDisplay, GameGrid, GameImage } from "./styles";
|
||||||
|
import { Examples } from "@/roms/examples/examples";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Examples - agb",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ShowcasePage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ContentBlock color="#9fa6db">
|
||||||
|
<h1>Examples</h1>
|
||||||
|
</ContentBlock>
|
||||||
|
<ContentBlock uncentered>
|
||||||
|
<GameGrid>
|
||||||
|
{Examples.map((example, idx) => (
|
||||||
|
<Game key={idx} example={example} />
|
||||||
|
))}
|
||||||
|
</GameGrid>
|
||||||
|
</ContentBlock>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Game({ example }: { example: (typeof Examples)[number] }) {
|
||||||
|
const screenshot = example.screenshot;
|
||||||
|
return (
|
||||||
|
<GameDisplay
|
||||||
|
href={`./examples/${slugify(example.example_name)}`}
|
||||||
|
id={slugify(example.example_name)}
|
||||||
|
>
|
||||||
|
<GameImage
|
||||||
|
src={screenshot}
|
||||||
|
alt={`Screenshot of ${example.example_name}`}
|
||||||
|
/>
|
||||||
|
<h2>{example.example_name}</h2>
|
||||||
|
</GameDisplay>
|
||||||
|
);
|
||||||
|
}
|
34
website/agb/src/app/examples/styles.tsx
Normal file
34
website/agb/src/app/examples/styles.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export const GameGrid = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, min(100vw, 600px));
|
||||||
|
justify-content: center;
|
||||||
|
gap: 48px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GameImage = styled(Image)`
|
||||||
|
width: 100%;
|
||||||
|
width: max(
|
||||||
|
round(down, 100%, calc(240 * var(--device-pixel))),
|
||||||
|
min(calc(240 * var(--device-pixel)), 100vw)
|
||||||
|
);
|
||||||
|
height: auto;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GameDisplay = styled(Link)`
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
`;
|
Loading…
Reference in a new issue