diff --git a/404.html b/404.html index 7d3cb00..c511feb 100644 --- a/404.html +++ b/404.html @@ -36,10 +36,10 @@ })(); gbdev.io - +

404

That's a Four-Oh-Four.
Take me home
- + diff --git a/assets/1.html-7f6467c5.js b/assets/1.html-172d4022.js similarity index 99% rename from assets/1.html-7f6467c5.js rename to assets/1.html-172d4022.js index c80c69b..a7a8e9d 100644 --- a/assets/1.html-7f6467c5.js +++ b/assets/1.html-172d4022.js @@ -1 +1 @@ -import{_ as n,r,o as i,c as s,a as t,b as e,d,e as o}from"./app-19015fbd.js";const h={},l=o('

The Gbdev Digest #1 - 2021 Recap

Written by avivace, on behalf of the gbdev org. Originally published on "getrevue" on the 21st of February, 2022.

Hey all and welcome to the first Issue of the new gbdev curated digest! Our idea is to prepare a collection of curated news about what is happening in our community, with a particular focus on our Open Source projects. Whatever you are interested in what’s happening the gbdev scene, new homebrew, tools, and documentation releases, find stuff where you can contribute with code or provide feedback, this newsletter is for you!

About us and our commitment to OSS

The following is a quick clarification since this is the first issue of the Gbdev Digest. Feel free to shamelessly skip it.

This newsletter is curated by the team behind the gbdev.io community, with a lot of help from members of other smaller communities and groups. We are directly involved with the development and maintaining of a lot of projects (e.g. Pan Docs, RGBDS, and Homebrew Hub), but of course not with everything that will be mentioned in this newsletter.

The gbdev initiative promotes the development of tools, documentation and homebrew games. We also push research and emulation efforts while trying to keep everything as accessible as possible to everyone, no matter the technical background. Another big commitment is the archiving one: we are working on salvaging old and unavailable content, creating a digital memory of a scene that is now three decades old.

Since our inception in 2015, open source and free software values are at the core of our commitment. We release everything we work on under OSS licenses (or in the Public Domain), maintaining a strong non-profit approach. Even if we reshare and give exposure to commercial products related to gbdev, we don’t get any cash from any of the involved companies and we don’t sponsor or endorse any particular release or publisher. No referral links are ever shared through our channels.

Our expenses are entirely sustained by voluntary contributions (for which donators don’t get any benefit) and sponsorships (such as the DigitalOcean one). Everything is tracked trasparently on our OpenCollective.

While a core team of maintainers is behind every project, we welcome any type of contribution, from feedback to participation in Request For Comments threads. Check the bottom of this page to learn how to join our community.

Best year yet, for the 4th year in a row

2021 was a huge success for gbdev. The Game Boy scene was never this alive and flourishing, with an unprecedented number of releases. From the incredible gbcompo21 (for which we are preparing a dedicated issue of this newsletter) to the number of new releases of our projects, we enjoyed the most traffic we ever saw, for the fourth year in a row.

New guide on choosing development tools

We finished revamping a quite comprehensive guide on how to choose tools for Game Boy, giving an overview on the different available approaches to developing homebrews for the grey brick.

https://gbdev.io/guides/tools.html

Homebrew Hub 2.0

Homebrew Hub is a community-led attempt to collect, archive and preserve every unofficial game and homebrew released for Game Boy produced through decades of passionate work. Every entry , with its metadata and related assets is exposed through an API available to everyone.

We started a complete rewrite of the backend and the frontend software behind Homebrew Hub. Originally built with Express in 2016 the codebase started to show its age… The new backend, powered by Django, will offer a full Restful API to access all the games, assets, metadata and ROMs we have in the JSON database. The new frontend is powered by the binjgb emulator, running in the browser via WebAssembly. This will bring better emulation accuracy and more features!

New games on the Homebrew Hub database

The Homebrew Hub database is community maintained. Everyone can contribute adding a game or writing a scraper to mass-import games on the website.

In parallel to the rewrite, a lot of stuff is happening on the database, too:

New CI scripts are now in place to detect potentially duplicated entries, calculating checksums of assets. The pipeline will now run on Pull Requests and also validate the submitted metadata and the referenced files, to aid contributors.

The following new entries have been added: Crystal Lake, Grub Glide, Labirinth, Bannerprint and Europa Rescue (thanks to N•I•L, v666, reini1305, Exetric and godai78).

All the 20 shortlisted entries from the GB Competition 2021 were also added and are ready to play.

dag7dev worked on new scrapers, cleaned up a bunch of entries metadata and merged some duplicates. Hundreds of new homebrews are now available thanks to his work!

A new game metadata schema is in preparation, enabling game translations and specific tags for hardware support (e.g. gb-printer, gb-camera, ..).

The total number of games is now 748! Go play with them!

New RGBDS website and documentation

RGBDS is the standard toolchain for developing homebrew Game Boy programs in Assembly. First released in 1997, it’s now enjoying renewed community attention.

A new version of the RGBDS website, providing downloads, build instructions and full documentation is now work in progress.

From a statically built HTML version we are migrating to a solution based on Docusaurus, a documentation framework powered by React.

RGBGFX rewrite incoming

The rgbgfx program, part of the RGBDS suite, converts PNG images into the Nintendo Game Boy’s planar tile format.

A new version is being rewritten in modern C++17, enabling a series of improvements such as better error messages (more explicit), proper transparency support, explicit palette specification and proper 8×16 support.

GBDK 4.0.5 and 4.0.6

GBDK is a C compiler, assembler, linker and set of libraries for the Z80 like Nintendo Gameboy.

Our friends over at the GBDK team worked on a big release, the first adding more targets to the toolchain: GBDK can now compile to Sega Master System/Sega Game Gear and the Analogue Pocket.

4.0.6 shipped support for the Mega Duck, too!

Other notable features added in 2021 were:

More information can be found in the release notes.

GBDK Tutorials

For a long time now the main GBDK tutorials online have been mostly outdated and based on the 20 year old version GBDK but this is now changing: Larold is working on a series of tutorials where they break down the Game Boy game creation process into multiple high-level steps.

https://laroldsjubilantjunkyard.com/tutorials/

GB Studio 3 is out

GB Studio is a quick and easy to use drag and drop retro game creator for the Game Boy. No programming required. Here are some of the highlights from the new release:

',45),c={href:"https://gbstudiocentral.com/news/gb-studio-3-0-released",target:"_blank",rel:"noopener noreferrer"},u=o('

Contributions to other (non-gbdev) projects

mdbook is the wonderful Rust tool we use to render Pan Docs. Apart from overloading it with custom features, we also contribute upstream.

ISSOtm recently prepared a PR to add a feature for generating sitemaps, which we hope will get some attention from the upstream maintainers soon.

https://github.com/rust-lang/mdBook/pull/1618

Wrapping up and feedback

Thanks for reading! That’s all for this issue. We hope you’re having fun developing or playing games for Game Boy. As always, your contributions to our initiatives are appreciated. You’re welcome to browse around our GitHub organisation or join our Discord server to see what everyone is working on.

If you still want more gbdev, our Twitter feed provides a curated (and frequent) collection of new releases, WIP content and news about our projects.

If you have any feedback, want to send us some gbdev links or comment on any of the topics brought up in this issue (or on the newsletter itself) feel free to reach us.

Next Issue

This digest won’t try to respect an actual schedule but will rather go online when enough quality content is ready. On the next issue, we will continue to shed some light on the incredible accomplishments we made in 2021, such as the GB Competition 2021, showing you how some games enjoyed continued support and physical releases. We will also tell you how we managed to make Pan Docs this good and what’s new in the latest RGBDS releases.

If you’d like to send us some gbdev content you found interesting and you think would fit this newsletter, feel free to reach out.

Special thanks to bbbbbr, ISSOtm, toxa and Emi Paternostro.

',12);function p(m,b){const a=r("ExternalLinkIcon");return i(),s("div",null,[l,t("p",null,[e("You can learn more from the "),t("a",c,[e("dedicated article"),d(a)]),e(" on GB Studio Central.")]),u])}const w=n(h,[["render",p],["__file","1.html.vue"]]);export{w as default}; +import{_ as n,r,o as i,c as s,a as t,b as e,d,e as o}from"./app-821120ad.js";const h={},l=o('

The Gbdev Digest #1 - 2021 Recap

Written by avivace, on behalf of the gbdev org. Originally published on "getrevue" on the 21st of February, 2022.

Hey all and welcome to the first Issue of the new gbdev curated digest! Our idea is to prepare a collection of curated news about what is happening in our community, with a particular focus on our Open Source projects. Whatever you are interested in what’s happening the gbdev scene, new homebrew, tools, and documentation releases, find stuff where you can contribute with code or provide feedback, this newsletter is for you!

About us and our commitment to OSS

The following is a quick clarification since this is the first issue of the Gbdev Digest. Feel free to shamelessly skip it.

This newsletter is curated by the team behind the gbdev.io community, with a lot of help from members of other smaller communities and groups. We are directly involved with the development and maintaining of a lot of projects (e.g. Pan Docs, RGBDS, and Homebrew Hub), but of course not with everything that will be mentioned in this newsletter.

The gbdev initiative promotes the development of tools, documentation and homebrew games. We also push research and emulation efforts while trying to keep everything as accessible as possible to everyone, no matter the technical background. Another big commitment is the archiving one: we are working on salvaging old and unavailable content, creating a digital memory of a scene that is now three decades old.

Since our inception in 2015, open source and free software values are at the core of our commitment. We release everything we work on under OSS licenses (or in the Public Domain), maintaining a strong non-profit approach. Even if we reshare and give exposure to commercial products related to gbdev, we don’t get any cash from any of the involved companies and we don’t sponsor or endorse any particular release or publisher. No referral links are ever shared through our channels.

Our expenses are entirely sustained by voluntary contributions (for which donators don’t get any benefit) and sponsorships (such as the DigitalOcean one). Everything is tracked trasparently on our OpenCollective.

While a core team of maintainers is behind every project, we welcome any type of contribution, from feedback to participation in Request For Comments threads. Check the bottom of this page to learn how to join our community.

Best year yet, for the 4th year in a row

2021 was a huge success for gbdev. The Game Boy scene was never this alive and flourishing, with an unprecedented number of releases. From the incredible gbcompo21 (for which we are preparing a dedicated issue of this newsletter) to the number of new releases of our projects, we enjoyed the most traffic we ever saw, for the fourth year in a row.

New guide on choosing development tools

We finished revamping a quite comprehensive guide on how to choose tools for Game Boy, giving an overview on the different available approaches to developing homebrews for the grey brick.

https://gbdev.io/guides/tools.html

Homebrew Hub 2.0

Homebrew Hub is a community-led attempt to collect, archive and preserve every unofficial game and homebrew released for Game Boy produced through decades of passionate work. Every entry , with its metadata and related assets is exposed through an API available to everyone.

We started a complete rewrite of the backend and the frontend software behind Homebrew Hub. Originally built with Express in 2016 the codebase started to show its age… The new backend, powered by Django, will offer a full Restful API to access all the games, assets, metadata and ROMs we have in the JSON database. The new frontend is powered by the binjgb emulator, running in the browser via WebAssembly. This will bring better emulation accuracy and more features!

New games on the Homebrew Hub database

The Homebrew Hub database is community maintained. Everyone can contribute adding a game or writing a scraper to mass-import games on the website.

In parallel to the rewrite, a lot of stuff is happening on the database, too:

New CI scripts are now in place to detect potentially duplicated entries, calculating checksums of assets. The pipeline will now run on Pull Requests and also validate the submitted metadata and the referenced files, to aid contributors.

The following new entries have been added: Crystal Lake, Grub Glide, Labirinth, Bannerprint and Europa Rescue (thanks to N•I•L, v666, reini1305, Exetric and godai78).

All the 20 shortlisted entries from the GB Competition 2021 were also added and are ready to play.

dag7dev worked on new scrapers, cleaned up a bunch of entries metadata and merged some duplicates. Hundreds of new homebrews are now available thanks to his work!

A new game metadata schema is in preparation, enabling game translations and specific tags for hardware support (e.g. gb-printer, gb-camera, ..).

The total number of games is now 748! Go play with them!

New RGBDS website and documentation

RGBDS is the standard toolchain for developing homebrew Game Boy programs in Assembly. First released in 1997, it’s now enjoying renewed community attention.

A new version of the RGBDS website, providing downloads, build instructions and full documentation is now work in progress.

From a statically built HTML version we are migrating to a solution based on Docusaurus, a documentation framework powered by React.

RGBGFX rewrite incoming

The rgbgfx program, part of the RGBDS suite, converts PNG images into the Nintendo Game Boy’s planar tile format.

A new version is being rewritten in modern C++17, enabling a series of improvements such as better error messages (more explicit), proper transparency support, explicit palette specification and proper 8×16 support.

GBDK 4.0.5 and 4.0.6

GBDK is a C compiler, assembler, linker and set of libraries for the Z80 like Nintendo Gameboy.

Our friends over at the GBDK team worked on a big release, the first adding more targets to the toolchain: GBDK can now compile to Sega Master System/Sega Game Gear and the Analogue Pocket.

4.0.6 shipped support for the Mega Duck, too!

Other notable features added in 2021 were:

More information can be found in the release notes.

GBDK Tutorials

For a long time now the main GBDK tutorials online have been mostly outdated and based on the 20 year old version GBDK but this is now changing: Larold is working on a series of tutorials where they break down the Game Boy game creation process into multiple high-level steps.

https://laroldsjubilantjunkyard.com/tutorials/

GB Studio 3 is out

GB Studio is a quick and easy to use drag and drop retro game creator for the Game Boy. No programming required. Here are some of the highlights from the new release:

',45),c={href:"https://gbstudiocentral.com/news/gb-studio-3-0-released",target:"_blank",rel:"noopener noreferrer"},u=o('

Contributions to other (non-gbdev) projects

mdbook is the wonderful Rust tool we use to render Pan Docs. Apart from overloading it with custom features, we also contribute upstream.

ISSOtm recently prepared a PR to add a feature for generating sitemaps, which we hope will get some attention from the upstream maintainers soon.

https://github.com/rust-lang/mdBook/pull/1618

Wrapping up and feedback

Thanks for reading! That’s all for this issue. We hope you’re having fun developing or playing games for Game Boy. As always, your contributions to our initiatives are appreciated. You’re welcome to browse around our GitHub organisation or join our Discord server to see what everyone is working on.

If you still want more gbdev, our Twitter feed provides a curated (and frequent) collection of new releases, WIP content and news about our projects.

If you have any feedback, want to send us some gbdev links or comment on any of the topics brought up in this issue (or on the newsletter itself) feel free to reach us.

Next Issue

This digest won’t try to respect an actual schedule but will rather go online when enough quality content is ready. On the next issue, we will continue to shed some light on the incredible accomplishments we made in 2021, such as the GB Competition 2021, showing you how some games enjoyed continued support and physical releases. We will also tell you how we managed to make Pan Docs this good and what’s new in the latest RGBDS releases.

If you’d like to send us some gbdev content you found interesting and you think would fit this newsletter, feel free to reach out.

Special thanks to bbbbbr, ISSOtm, toxa and Emi Paternostro.

',12);function p(m,b){const a=r("ExternalLinkIcon");return i(),s("div",null,[l,t("p",null,[e("You can learn more from the "),t("a",c,[e("dedicated article"),d(a)]),e(" on GB Studio Central.")]),u])}const w=n(h,[["render",p],["__file","1.html.vue"]]);export{w as default}; diff --git a/assets/2023-11-04-sc.html-53a290fa.js b/assets/2023-11-04-sc.html-a4eac1f3.js similarity index 98% rename from assets/2023-11-04-sc.html-53a290fa.js rename to assets/2023-11-04-sc.html-a4eac1f3.js index 0c6b0dd..29057f4 100644 --- a/assets/2023-11-04-sc.html-53a290fa.js +++ b/assets/2023-11-04-sc.html-a4eac1f3.js @@ -1 +1 @@ -import{_ as e,o as i,c as t,e as o}from"./app-19015fbd.js";const a={},l=o('

Steering Committee - November 2023

Written by avivace.

November 4th, 2023. 15:00 — 17:30 UTC. Discord VC.

Invited

Moderators, Staff, Experts, Outreach, RGBDS maintainers.

Partecipants

PinoBatch, avivace, ISSO, Calindro, Duo, nitro2k01, QuangDX, superdisk, kva64, Sylvie, Sanqui

About those meetings

Participants were asked to fill in discussion points beforehand. The results of these discussions (decisions, suggestions, comments, etc.) are reported as subitems.

Discussion points marked * were not brought up due to lack of time.

Anyone can reach out in #meta on the Discord server to comment/discuss on any of the points reported here.

Minutes
',13),n=[l];function s(r,h){return i(),t("div",null,n)}const c=e(a,[["render",s],["__file","2023-11-04-sc.html.vue"]]);export{c as default}; +import{_ as e,o as i,c as t,e as o}from"./app-821120ad.js";const a={},l=o('

Steering Committee - November 2023

Written by avivace.

November 4th, 2023. 15:00 — 17:30 UTC. Discord VC.

Invited

Moderators, Staff, Experts, Outreach, RGBDS maintainers.

Partecipants

PinoBatch, avivace, ISSO, Calindro, Duo, nitro2k01, QuangDX, superdisk, kva64, Sylvie, Sanqui

About those meetings

Participants were asked to fill in discussion points beforehand. The results of these discussions (decisions, suggestions, comments, etc.) are reported as subitems.

Discussion points marked * were not brought up due to lack of time.

Anyone can reach out in #meta on the Discord server to comment/discuss on any of the points reported here.

Minutes
',13),n=[l];function s(r,h){return i(),t("div",null,n)}const c=e(a,[["render",s],["__file","2023-11-04-sc.html.vue"]]);export{c as default}; diff --git a/assets/2024-03-10-sc2.html-6d8fd61f.js b/assets/2024-03-10-sc2.html-004e84d0.js similarity index 98% rename from assets/2024-03-10-sc2.html-6d8fd61f.js rename to assets/2024-03-10-sc2.html-004e84d0.js index 0894100..6f996c4 100644 --- a/assets/2024-03-10-sc2.html-6d8fd61f.js +++ b/assets/2024-03-10-sc2.html-004e84d0.js @@ -1 +1 @@ -import{_ as n,r as s,o as a,c as r,a as e,b as t,d as o,e as l}from"./app-19015fbd.js";const u={},c=l('

Steering Committee - March 2024

Minutes curated by Sanqui and avivace


Participants: avivace, Sanqui, Calindro, superdisk, ISSOtm, nitro, Pino, asie, tobias, DUO, Sylvie, kva

Where: Discord gbdev, #sc-meeting voice channel

When: March 10th 2024, 6:30 PM - 8:00 PM CET (UTC +1)

',6),d={href:"https://gbdev.io/meetings/2023-11-04-sc.html",target:"_blank",rel:"noopener noreferrer"},h=l('

Discussion points are ordered by priority.


Updates

avivace:


Discussion

nitro2k01

',8),m=e("li",null,[t("Problems "),e("ul",null,[e("li",null,"Not mobile friendly"),e("li",null,"People don’t want to make another account -> offer login using Discord or GitHub")])],-1),g=e("li",null,[t("When/if migrating to a new system, what do with old posts? "),e("ul",null,[e("li",null,"Migrate to new? (lose URLs)"),e("li",null,"Set old in read-only")])],-1),p=e("li",null,"Threads on Discord <-> Forum ?",-1),_=e("li",null,"Leave it the way it is",-1),b=e("li",null,"Could switch forum systems",-1),f=e("li",null,"Discourse is very popular, but JS heavy",-1),v=e("li",null,"Migrate to nesdev as they would be willing to help",-1),w={href:"https://forum.gbadev.net/",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"Recycling logins may make the forum more attractive (e.g. nesdev or gbadev may have users overlap)")],-1),y=e("p",null,"ISSOtm:",-1),S={href:"https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html",target:"_blank",rel:"noopener noreferrer"},x=e("ul",null,[e("li",null,"Projects are complex and “unapproachable”"),e("li",null,"Adding examples to CONTRIBUTING.md?"),e("li",null,"Which projects don’t have CONTRIBUTING.md?"),e("li",null,"Write down what is expected of a maintainer!"),e("li",null,"Finding some time to write down the “vision” Isso has for the Rust port (what needs to be done, how, etc.)")],-1),C=e("li",null,[t("Prioritization, among and within… "),e("ul",null,[e("li",null,"gb-asm-tutorial (1)"),e("li",null,"Pan Docs (2)"),e("li",null,"rsgbds (RGBDS on “life support” with Sylvie maintaining) (last)")])],-1),T=e("li",null,[t("Next meeting: "),e("ul",null,[e("li",null,"Moving projects to SourceHut?")])],-1),D=l("

avivace

kva64

",4);function I(R,M){const i=s("ExternalLinkIcon");return a(),r("div",null,[c,e("p",null,[e("a",d,[t("Last meeting minutes"),o(i)])]),h,e("ul",null,[e("li",null,[t("Future of the forums "),e("ul",null,[m,g,p,e("li",null,[t("Options "),e("ul",null,[_,b,f,v,e("li",null,[t("Migrate to "),e("a",w,[t("https://forum.gbadev.net/"),o(i)]),t(", which uses Flaskbb "),k])])])])])]),y,e("ul",null,[e("li",null,[t("RGBDS (and other projects?): onboarding friction ("),e("a",S,[t("https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html"),o(i)]),t(" for inspiration) "),x]),C,T]),D])}const P=n(u,[["render",I],["__file","2024-03-10-sc2.html.vue"]]);export{P as default}; +import{_ as n,r as s,o as a,c as r,a as e,b as t,d as o,e as l}from"./app-821120ad.js";const u={},c=l('

Steering Committee - March 2024

Minutes curated by Sanqui and avivace


Participants: avivace, Sanqui, Calindro, superdisk, ISSOtm, nitro, Pino, asie, tobias, DUO, Sylvie, kva

Where: Discord gbdev, #sc-meeting voice channel

When: March 10th 2024, 6:30 PM - 8:00 PM CET (UTC +1)

',6),d={href:"https://gbdev.io/meetings/2023-11-04-sc.html",target:"_blank",rel:"noopener noreferrer"},h=l('

Discussion points are ordered by priority.


Updates

avivace:


Discussion

nitro2k01

',8),m=e("li",null,[t("Problems "),e("ul",null,[e("li",null,"Not mobile friendly"),e("li",null,"People don’t want to make another account -> offer login using Discord or GitHub")])],-1),g=e("li",null,[t("When/if migrating to a new system, what do with old posts? "),e("ul",null,[e("li",null,"Migrate to new? (lose URLs)"),e("li",null,"Set old in read-only")])],-1),p=e("li",null,"Threads on Discord <-> Forum ?",-1),_=e("li",null,"Leave it the way it is",-1),b=e("li",null,"Could switch forum systems",-1),f=e("li",null,"Discourse is very popular, but JS heavy",-1),v=e("li",null,"Migrate to nesdev as they would be willing to help",-1),w={href:"https://forum.gbadev.net/",target:"_blank",rel:"noopener noreferrer"},k=e("ul",null,[e("li",null,"Recycling logins may make the forum more attractive (e.g. nesdev or gbadev may have users overlap)")],-1),y=e("p",null,"ISSOtm:",-1),S={href:"https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html",target:"_blank",rel:"noopener noreferrer"},x=e("ul",null,[e("li",null,"Projects are complex and “unapproachable”"),e("li",null,"Adding examples to CONTRIBUTING.md?"),e("li",null,"Which projects don’t have CONTRIBUTING.md?"),e("li",null,"Write down what is expected of a maintainer!"),e("li",null,"Finding some time to write down the “vision” Isso has for the Rust port (what needs to be done, how, etc.)")],-1),C=e("li",null,[t("Prioritization, among and within… "),e("ul",null,[e("li",null,"gb-asm-tutorial (1)"),e("li",null,"Pan Docs (2)"),e("li",null,"rsgbds (RGBDS on “life support” with Sylvie maintaining) (last)")])],-1),T=e("li",null,[t("Next meeting: "),e("ul",null,[e("li",null,"Moving projects to SourceHut?")])],-1),D=l("

avivace

kva64

",4);function I(R,M){const i=s("ExternalLinkIcon");return a(),r("div",null,[c,e("p",null,[e("a",d,[t("Last meeting minutes"),o(i)])]),h,e("ul",null,[e("li",null,[t("Future of the forums "),e("ul",null,[m,g,p,e("li",null,[t("Options "),e("ul",null,[_,b,f,v,e("li",null,[t("Migrate to "),e("a",w,[t("https://forum.gbadev.net/"),o(i)]),t(", which uses Flaskbb "),k])])])])])]),y,e("ul",null,[e("li",null,[t("RGBDS (and other projects?): onboarding friction ("),e("a",S,[t("https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html"),o(i)]),t(" for inspiration) "),x]),C,T]),D])}const P=n(u,[["render",I],["__file","2024-03-10-sc2.html.vue"]]);export{P as default}; diff --git a/assets/404.html-8084ca77.js b/assets/404.html-c2a57a37.js similarity index 63% rename from assets/404.html-8084ca77.js rename to assets/404.html-c2a57a37.js index 6b3e5b1..026fb29 100644 --- a/assets/404.html-8084ca77.js +++ b/assets/404.html-c2a57a37.js @@ -1 +1 @@ -import{_ as e,o as c,c as t}from"./app-19015fbd.js";const _={};function o(r,n){return c(),t("div")}const a=e(_,[["render",o],["__file","404.html.vue"]]);export{a as default}; +import{_ as e,o as c,c as t}from"./app-821120ad.js";const _={};function o(r,n){return c(),t("div")}const a=e(_,[["render",o],["__file","404.html.vue"]]);export{a as default}; diff --git a/assets/app-19015fbd.js b/assets/app-821120ad.js similarity index 99% rename from assets/app-19015fbd.js rename to assets/app-821120ad.js index 1a275b9..1027af5 100644 --- a/assets/app-19015fbd.js +++ b/assets/app-821120ad.js @@ -1,4 +1,4 @@ -const Xl="modulepreload",ea=function(e){return"/"+e},Yo={},ie=function(t,n,r){if(!n||n.length===0)return t();const o=document.getElementsByTagName("link");return Promise.all(n.map(s=>{if(s=ea(s),s in Yo)return;Yo[s]=!0;const i=s.endsWith(".css"),l=i?'[rel="stylesheet"]':"";if(!!r)for(let u=o.length-1;u>=0;u--){const f=o[u];if(f.href===s&&(!i||f.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${s}"]${l}`))return;const c=document.createElement("link");if(c.rel=i?"stylesheet":Xl,i||(c.as="script",c.crossOrigin=""),c.href=s,document.head.appendChild(c),i)return new Promise((u,f)=>{c.addEventListener("load",u),c.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${s}`)))})})).then(()=>t()).catch(s=>{const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=s,window.dispatchEvent(i),!i.defaultPrevented)throw s})};function po(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;o!!n[o.toLowerCase()]:o=>!!n[o]}const Ee={},nn=[],ot=()=>{},ta=()=>!1,na=/^on[^a-z]/,Hn=e=>na.test(e),mo=e=>e.startsWith("onUpdate:"),Oe=Object.assign,go=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},ra=Object.prototype.hasOwnProperty,fe=(e,t)=>ra.call(e,t),J=Array.isArray,rn=e=>Er(e)==="[object Map]",pi=e=>Er(e)==="[object Set]",se=e=>typeof e=="function",pe=e=>typeof e=="string",vo=e=>typeof e=="symbol",we=e=>e!==null&&typeof e=="object",mi=e=>we(e)&&se(e.then)&&se(e.catch),gi=Object.prototype.toString,Er=e=>gi.call(e),oa=e=>Er(e).slice(8,-1),vi=e=>Er(e)==="[object Object]",_o=e=>pe(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Ln=po(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),wr=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},sa=/-(\w)/g,ft=wr(e=>e.replace(sa,(t,n)=>n?n.toUpperCase():"")),ia=/\B([A-Z])/g,Yt=wr(e=>e.replace(ia,"-$1").toLowerCase()),Cr=wr(e=>e.charAt(0).toUpperCase()+e.slice(1)),Nr=wr(e=>e?`on${Cr(e)}`:""),An=(e,t)=>!Object.is(e,t),Dr=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},la=e=>{const t=parseFloat(e);return isNaN(t)?e:t},aa=e=>{const t=pe(e)?Number(e):NaN;return isNaN(t)?e:t};let Jo;const Qr=()=>Jo||(Jo=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Bn(e){if(J(e)){const t={};for(let n=0;n{if(n){const r=n.split(ua);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function qe(e){let t="";if(pe(e))t=e;else if(J(e))for(let n=0;npe(e)?e:e==null?"":J(e)||we(e)&&(e.toString===gi||!se(e.toString))?JSON.stringify(e,bi,2):String(e),bi=(e,t)=>t&&t.__v_isRef?bi(e,t.value):rn(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,o])=>(n[`${r} =>`]=o,n),{})}:pi(t)?{[`Set(${t.size})`]:[...t.values()]}:we(t)&&!J(t)&&!vi(t)?String(t):t;let Ge;class ma{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Ge,!t&&Ge&&(this.index=(Ge.scopes||(Ge.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=Ge;try{return Ge=this,t()}finally{Ge=n}}}on(){Ge=this}off(){Ge=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},Ei=e=>(e.w&It)>0,wi=e=>(e.n&It)>0,_a=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(u==="length"||u>=a)&&l.push(c)})}else switch(n!==void 0&&l.push(i.get(n)),t){case"add":J(e)?_o(n)&&l.push(i.get("length")):(l.push(i.get(qt)),rn(e)&&l.push(i.get(Xr)));break;case"delete":J(e)||(l.push(i.get(qt)),rn(e)&&l.push(i.get(Xr)));break;case"set":rn(e)&&l.push(i.get(qt));break}if(l.length===1)l[0]&&eo(l[0]);else{const a=[];for(const c of l)c&&a.push(...c);eo(bo(a))}}function eo(e,t){const n=J(e)?e:[...e];for(const r of n)r.computed&&Zo(r);for(const r of n)r.computed||Zo(r)}function Zo(e,t){(e!==nt||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function ya(e,t){var n;return(n=ar.get(e))==null?void 0:n.get(t)}const Ea=po("__proto__,__v_isRef,__isVue"),Li=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(vo)),wa=Eo(),Ca=Eo(!1,!0),xa=Eo(!0),Xo=La();function La(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=de(this);for(let s=0,i=this.length;s{e[t]=function(...n){mn();const r=de(this)[t].apply(this,n);return gn(),r}}),e}function Ta(e){const t=de(this);return We(t,"has",e),t.hasOwnProperty(e)}function Eo(e=!1,t=!1){return function(r,o,s){if(o==="__v_isReactive")return!e;if(o==="__v_isReadonly")return e;if(o==="__v_isShallow")return t;if(o==="__v_raw"&&s===(e?t?ja:Oi:t?ki:Si).get(r))return r;const i=J(r);if(!e){if(i&&fe(Xo,o))return Reflect.get(Xo,o,s);if(o==="hasOwnProperty")return Ta}const l=Reflect.get(r,o,s);return(vo(o)?Li.has(o):Ea(o))||(e||We(r,"get",o),t)?l:Me(l)?i&&_o(o)?l:l.value:we(l)?e?zn(l):Fn(l):l}}const Pa=Ti(),Sa=Ti(!0);function Ti(e=!1){return function(n,r,o,s){let i=n[r];if(an(i)&&Me(i)&&!Me(o))return!1;if(!e&&(!cr(o)&&!an(o)&&(i=de(i),o=de(o)),!J(n)&&Me(i)&&!Me(o)))return i.value=o,!0;const l=J(n)&&_o(r)?Number(r)e,xr=e=>Reflect.getPrototypeOf(e);function Wn(e,t,n=!1,r=!1){e=e.__v_raw;const o=de(e),s=de(t);n||(t!==s&&We(o,"get",t),We(o,"get",s));const{has:i}=xr(o),l=r?wo:n?Lo:Rn;if(i.call(o,t))return l(e.get(t));if(i.call(o,s))return l(e.get(s));e!==o&&e.get(t)}function Kn(e,t=!1){const n=this.__v_raw,r=de(n),o=de(e);return t||(e!==o&&We(r,"has",e),We(r,"has",o)),e===o?n.has(e):n.has(e)||n.has(o)}function Gn(e,t=!1){return e=e.__v_raw,!t&&We(de(e),"iterate",qt),Reflect.get(e,"size",e)}function es(e){e=de(e);const t=de(this);return xr(t).has.call(t,e)||(t.add(e),_t(t,"add",e,e)),this}function ts(e,t){t=de(t);const n=de(this),{has:r,get:o}=xr(n);let s=r.call(n,e);s||(e=de(e),s=r.call(n,e));const i=o.call(n,e);return n.set(e,t),s?An(t,i)&&_t(n,"set",e,t):_t(n,"add",e,t),this}function ns(e){const t=de(this),{has:n,get:r}=xr(t);let o=n.call(t,e);o||(e=de(e),o=n.call(t,e)),r&&r.call(t,e);const s=t.delete(e);return o&&_t(t,"delete",e,void 0),s}function rs(){const e=de(this),t=e.size!==0,n=e.clear();return t&&_t(e,"clear",void 0,void 0),n}function Yn(e,t){return function(r,o){const s=this,i=s.__v_raw,l=de(i),a=t?wo:e?Lo:Rn;return!e&&We(l,"iterate",qt),i.forEach((c,u)=>r.call(o,a(c),a(u),s))}}function Jn(e,t,n){return function(...r){const o=this.__v_raw,s=de(o),i=rn(s),l=e==="entries"||e===Symbol.iterator&&i,a=e==="keys"&&i,c=o[e](...r),u=n?wo:t?Lo:Rn;return!t&&We(s,"iterate",a?Xr:qt),{next(){const{value:f,done:h}=c.next();return h?{value:f,done:h}:{value:l?[u(f[0]),u(f[1])]:u(f),done:h}},[Symbol.iterator](){return this}}}}function xt(e){return function(...t){return e==="delete"?!1:this}}function $a(){const e={get(s){return Wn(this,s)},get size(){return Gn(this)},has:Kn,add:es,set:ts,delete:ns,clear:rs,forEach:Yn(!1,!1)},t={get(s){return Wn(this,s,!1,!0)},get size(){return Gn(this)},has:Kn,add:es,set:ts,delete:ns,clear:rs,forEach:Yn(!1,!0)},n={get(s){return Wn(this,s,!0)},get size(){return Gn(this,!0)},has(s){return Kn.call(this,s,!0)},add:xt("add"),set:xt("set"),delete:xt("delete"),clear:xt("clear"),forEach:Yn(!0,!1)},r={get(s){return Wn(this,s,!0,!0)},get size(){return Gn(this,!0)},has(s){return Kn.call(this,s,!0)},add:xt("add"),set:xt("set"),delete:xt("delete"),clear:xt("clear"),forEach:Yn(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(s=>{e[s]=Jn(s,!1,!1),n[s]=Jn(s,!0,!1),t[s]=Jn(s,!1,!0),r[s]=Jn(s,!0,!0)}),[e,n,t,r]}const[Ma,Na,Da,Ha]=$a();function Co(e,t){const n=t?e?Ha:Da:e?Na:Ma;return(r,o,s)=>o==="__v_isReactive"?!e:o==="__v_isReadonly"?e:o==="__v_raw"?r:Reflect.get(fe(n,o)&&o in r?n:r,o,s)}const Ba={get:Co(!1,!1)},Fa={get:Co(!1,!0)},za={get:Co(!0,!1)},Si=new WeakMap,ki=new WeakMap,Oi=new WeakMap,ja=new WeakMap;function Va(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Ua(e){return e.__v_skip||!Object.isExtensible(e)?0:Va(oa(e))}function Fn(e){return an(e)?e:xo(e,!1,Pi,Ba,Si)}function Ai(e){return xo(e,!1,Ia,Fa,ki)}function zn(e){return xo(e,!0,Ra,za,Oi)}function xo(e,t,n,r,o){if(!we(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const s=o.get(e);if(s)return s;const i=Ua(e);if(i===0)return e;const l=new Proxy(e,i===2?r:n);return o.set(e,l),l}function on(e){return an(e)?on(e.__v_raw):!!(e&&e.__v_isReactive)}function an(e){return!!(e&&e.__v_isReadonly)}function cr(e){return!!(e&&e.__v_isShallow)}function Ri(e){return on(e)||an(e)}function de(e){const t=e&&e.__v_raw;return t?de(t):e}function Ii(e){return lr(e,"__v_skip",!0),e}const Rn=e=>we(e)?Fn(e):e,Lo=e=>we(e)?zn(e):e;function $i(e){At&&nt&&(e=de(e),xi(e.dep||(e.dep=bo())))}function Mi(e,t){e=de(e);const n=e.dep;n&&eo(n)}function Me(e){return!!(e&&e.__v_isRef===!0)}function Ce(e){return Ni(e,!1)}function To(e){return Ni(e,!0)}function Ni(e,t){return Me(e)?e:new qa(e,t)}class qa{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:de(t),this._value=n?t:Rn(t)}get value(){return $i(this),this._value}set value(t){const n=this.__v_isShallow||cr(t)||an(t);t=n?t:de(t),An(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:Rn(t),Mi(this))}}function Z(e){return Me(e)?e.value:e}const Wa={get:(e,t,n)=>Z(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return Me(o)&&!Me(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function Di(e){return on(e)?e:new Proxy(e,Wa)}function Po(e){const t=J(e)?new Array(e.length):{};for(const n in e)t[n]=Ga(e,n);return t}class Ka{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return ya(de(this._object),this._key)}}function Ga(e,t,n){const r=e[t];return Me(r)?r:new Ka(e,t,n)}class Ya{constructor(t,n,r,o){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new yo(t,()=>{this._dirty||(this._dirty=!0,Mi(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!o,this.__v_isReadonly=r}get value(){const t=de(this);return $i(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function Ja(e,t,n=!1){let r,o;const s=se(e);return s?(r=e,o=ot):(r=e.get,o=e.set),new Ya(r,o,s||!o,n)}function Rt(e,t,n,r){let o;try{o=r?e(...r):e()}catch(s){jn(s,t,n)}return o}function Ze(e,t,n,r){if(se(e)){const s=Rt(e,t,n,r);return s&&mi(s)&&s.catch(i=>{jn(i,t,n)}),s}const o=[];for(let s=0;s>>1;$n(Fe[r])ct&&Fe.splice(t,1)}function ec(e){J(e)?sn.push(...e):(!mt||!mt.includes(e,e.allowRecurse?zt+1:zt))&&sn.push(e),Bi()}function os(e,t=In?ct+1:0){for(;t$n(n)-$n(r)),zt=0;zte.id==null?1/0:e.id,tc=(e,t)=>{const n=$n(e)-$n(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Fi(e){to=!1,In=!0,Fe.sort(tc);const t=ot;try{for(ct=0;ctpe(g)?g.trim():g)),f&&(o=n.map(la))}let l,a=r[l=Nr(t)]||r[l=Nr(ft(t))];!a&&s&&(a=r[l=Nr(Yt(t))]),a&&Ze(a,e,6,o);const c=r[l+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ze(c,e,6,o)}}function zi(e,t,n=!1){const r=t.emitsCache,o=r.get(e);if(o!==void 0)return o;const s=e.emits;let i={},l=!1;if(!se(e)){const a=c=>{const u=zi(c,t,!0);u&&(l=!0,Oe(i,u))};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!s&&!l?(we(e)&&r.set(e,null),null):(J(s)?s.forEach(a=>i[a]=null):Oe(i,s),we(e)&&r.set(e,i),i)}function Pr(e,t){return!e||!Hn(t)?!1:(t=t.slice(2).replace(/Once$/,""),fe(e,t[0].toLowerCase()+t.slice(1))||fe(e,Yt(t))||fe(e,t))}let De=null,ji=null;function fr(e){const t=De;return De=e,ji=e&&e.type.__scopeId||null,t}function $e(e,t=De,n){if(!t||e._n)return e;const r=(...o)=>{r._d&&gs(-1);const s=fr(t);let i;try{i=e(...o)}finally{fr(s),r._d&&gs(1)}return i};return r._n=!0,r._c=!0,r._d=!0,r}function Hr(e){const{type:t,vnode:n,proxy:r,withProxy:o,props:s,propsOptions:[i],slots:l,attrs:a,emit:c,render:u,renderCache:f,data:h,setupState:g,ctx:y,inheritAttrs:w}=e;let T,v;const b=fr(e);try{if(n.shapeFlag&4){const k=o||r;T=tt(u.call(k,k,f,s,g,h,y)),v=a}else{const k=t;T=tt(k.length>1?k(s,{attrs:a,slots:l,emit:c}):k(s,null)),v=t.props?a:rc(a)}}catch(k){Sn.length=0,jn(k,e,1),T=ee(Ye)}let O=T;if(v&&w!==!1){const k=Object.keys(v),{shapeFlag:q}=O;k.length&&q&7&&(i&&k.some(mo)&&(v=oc(v,i)),O=Mt(O,v))}return n.dirs&&(O=Mt(O),O.dirs=O.dirs?O.dirs.concat(n.dirs):n.dirs),n.transition&&(O.transition=n.transition),T=O,fr(b),T}const rc=e=>{let t;for(const n in e)(n==="class"||n==="style"||Hn(n))&&((t||(t={}))[n]=e[n]);return t},oc=(e,t)=>{const n={};for(const r in e)(!mo(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function sc(e,t,n){const{props:r,children:o,component:s}=e,{props:i,children:l,patchFlag:a}=t,c=s.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&a>=0){if(a&1024)return!0;if(a&16)return r?ss(r,i,c):!!i;if(a&8){const u=t.dynamicProps;for(let f=0;fe.__isSuspense;function Vi(e,t){t&&t.pendingBranch?J(e)?t.effects.push(...e):t.effects.push(e):ec(e)}function Ui(e,t){return ko(e,null,t)}const Qn={};function ut(e,t,n){return ko(e,t,n)}function ko(e,t,{immediate:n,deep:r,flush:o,onTrack:s,onTrigger:i}=Ee){var l;const a=yi()===((l=Ae)==null?void 0:l.scope)?Ae:null;let c,u=!1,f=!1;if(Me(e)?(c=()=>e.value,u=cr(e)):on(e)?(c=()=>e,r=!0):J(e)?(f=!0,u=e.some(k=>on(k)||cr(k)),c=()=>e.map(k=>{if(Me(k))return k.value;if(on(k))return Ut(k);if(se(k))return Rt(k,a,2)})):se(e)?t?c=()=>Rt(e,a,2):c=()=>{if(!(a&&a.isUnmounted))return h&&h(),Ze(e,a,3,[g])}:c=ot,t&&r){const k=c;c=()=>Ut(k())}let h,g=k=>{h=b.onStop=()=>{Rt(k,a,4)}},y;if(fn)if(g=ot,t?n&&Ze(t,a,3,[c(),f?[]:void 0,g]):c(),o==="sync"){const k=nu();y=k.__watcherHandles||(k.__watcherHandles=[])}else return ot;let w=f?new Array(e.length).fill(Qn):Qn;const T=()=>{if(b.active)if(t){const k=b.run();(r||u||(f?k.some((q,X)=>An(q,w[X])):An(k,w)))&&(h&&h(),Ze(t,a,3,[k,w===Qn?void 0:f&&w[0]===Qn?[]:w,g]),w=k)}else b.run()};T.allowRecurse=!!t;let v;o==="sync"?v=T:o==="post"?v=()=>Ue(T,a&&a.suspense):(T.pre=!0,a&&(T.id=a.uid),v=()=>Tr(T));const b=new yo(c,v);t?n?T():w=b.run():o==="post"?Ue(b.run.bind(b),a&&a.suspense):b.run();const O=()=>{b.stop(),a&&a.scope&&go(a.scope.effects,b)};return y&&y.push(O),O}function ac(e,t,n){const r=this.proxy,o=pe(e)?e.includes(".")?qi(r,e):()=>r[e]:e.bind(r,r);let s;se(t)?s=t:(s=t.handler,n=t);const i=Ae;un(this);const l=ko(o,s.bind(r),n);return i?un(i):Kt(),l}function qi(e,t){const n=t.split(".");return()=>{let r=e;for(let o=0;o{Ut(n,t)});else if(vi(e))for(const n in e)Ut(e[n],t);return e}function dr(e,t){const n=De;if(n===null)return e;const r=Rr(n)||n.proxy,o=e.dirs||(e.dirs=[]);for(let s=0;s{e.isMounted=!0}),kr(()=>{e.isUnmounting=!0}),e}const Je=[Function,Array],Wi={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Je,onEnter:Je,onAfterEnter:Je,onEnterCancelled:Je,onBeforeLeave:Je,onLeave:Je,onAfterLeave:Je,onLeaveCancelled:Je,onBeforeAppear:Je,onAppear:Je,onAfterAppear:Je,onAppearCancelled:Je},uc={name:"BaseTransition",props:Wi,setup(e,{slots:t}){const n=al(),r=cc();let o;return()=>{const s=t.default&&Gi(t.default(),!0);if(!s||!s.length)return;let i=s[0];if(s.length>1){for(const w of s)if(w.type!==Ye){i=w;break}}const l=de(e),{mode:a}=l;if(r.isLeaving)return Br(i);const c=is(i);if(!c)return Br(i);const u=no(c,l,r,n);ro(c,u);const f=n.subTree,h=f&&is(f);let g=!1;const{getTransitionKey:y}=c.type;if(y){const w=y();o===void 0?o=w:w!==o&&(o=w,g=!0)}if(h&&h.type!==Ye&&(!jt(c,h)||g)){const w=no(h,l,r,n);if(ro(h,w),a==="out-in")return r.isLeaving=!0,w.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},Br(i);a==="in-out"&&c.type!==Ye&&(w.delayLeave=(T,v,b)=>{const O=Ki(r,h);O[String(h.key)]=h,T._leaveCb=()=>{v(),T._leaveCb=void 0,delete u.delayedLeave},u.delayedLeave=b})}return i}}},fc=uc;function Ki(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function no(e,t,n,r){const{appear:o,mode:s,persisted:i=!1,onBeforeEnter:l,onEnter:a,onAfterEnter:c,onEnterCancelled:u,onBeforeLeave:f,onLeave:h,onAfterLeave:g,onLeaveCancelled:y,onBeforeAppear:w,onAppear:T,onAfterAppear:v,onAppearCancelled:b}=t,O=String(e.key),k=Ki(n,e),q=(m,z)=>{m&&Ze(m,r,9,z)},X=(m,z)=>{const D=z[1];q(m,z),J(m)?m.every(K=>K.length<=1)&&D():m.length<=1&&D()},N={mode:s,persisted:i,beforeEnter(m){let z=l;if(!n.isMounted)if(o)z=w||l;else return;m._leaveCb&&m._leaveCb(!0);const D=k[O];D&&jt(e,D)&&D.el._leaveCb&&D.el._leaveCb(),q(z,[m])},enter(m){let z=a,D=c,K=u;if(!n.isMounted)if(o)z=T||a,D=v||c,K=b||u;else return;let L=!1;const R=m._enterCb=I=>{L||(L=!0,I?q(K,[m]):q(D,[m]),N.delayedLeave&&N.delayedLeave(),m._enterCb=void 0)};z?X(z,[m,R]):R()},leave(m,z){const D=String(e.key);if(m._enterCb&&m._enterCb(!0),n.isUnmounting)return z();q(f,[m]);let K=!1;const L=m._leaveCb=R=>{K||(K=!0,z(),R?q(y,[m]):q(g,[m]),m._leaveCb=void 0,k[D]===e&&delete k[D])};k[D]=e,h?X(h,[m,L]):L()},clone(m){return no(m,t,n,r)}};return N}function Br(e){if(Vn(e))return e=Mt(e),e.children=null,e}function is(e){return Vn(e)?e.children?e.children[0]:void 0:e}function ro(e,t){e.shapeFlag&6&&e.component?ro(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Gi(e,t=!1,n){let r=[],o=0;for(let s=0;s1)for(let s=0;sOe({name:e.name},t,{setup:e}))():e}const ln=e=>!!e.type.__asyncLoader;function Se(e){se(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:o=200,timeout:s,suspensible:i=!0,onError:l}=e;let a=null,c,u=0;const f=()=>(u++,a=null,h()),h=()=>{let g;return a||(g=a=t().catch(y=>{if(y=y instanceof Error?y:new Error(String(y)),l)return new Promise((w,T)=>{l(y,()=>w(f()),()=>T(y),u+1)});throw y}).then(y=>g!==a&&a?a:(y&&(y.__esModule||y[Symbol.toStringTag]==="Module")&&(y=y.default),c=y,y)))};return he({name:"AsyncComponentWrapper",__asyncLoader:h,get __asyncResolved(){return c},setup(){const g=Ae;if(c)return()=>Fr(c,g);const y=b=>{a=null,jn(b,g,13,!r)};if(i&&g.suspense||fn)return h().then(b=>()=>Fr(b,g)).catch(b=>(y(b),()=>r?ee(r,{error:b}):null));const w=Ce(!1),T=Ce(),v=Ce(!!o);return o&&setTimeout(()=>{v.value=!1},o),s!=null&&setTimeout(()=>{if(!w.value&&!T.value){const b=new Error(`Async component timed out after ${s}ms.`);y(b),T.value=b}},s),h().then(()=>{w.value=!0,g.parent&&Vn(g.parent.vnode)&&Tr(g.parent.update)}).catch(b=>{y(b),T.value=b}),()=>{if(w.value&&c)return Fr(c,g);if(T.value&&r)return ee(r,{error:T.value});if(n&&!v.value)return ee(n)}}})}function Fr(e,t){const{ref:n,props:r,children:o,ce:s}=t.vnode,i=ee(e,r,o);return i.ref=n,i.ce=s,delete t.vnode.ce,i}const Vn=e=>e.type.__isKeepAlive;function dc(e,t){Yi(e,"a",t)}function hc(e,t){Yi(e,"da",t)}function Yi(e,t,n=Ae){const r=e.__wdc||(e.__wdc=()=>{let o=n;for(;o;){if(o.isDeactivated)return;o=o.parent}return e()});if(Sr(t,r,n),n){let o=n.parent;for(;o&&o.parent;)Vn(o.parent.vnode)&&pc(r,t,n,o),o=o.parent}}function pc(e,t,n,r){const o=Sr(t,e,r,!0);Or(()=>{go(r[t],o)},n)}function Sr(e,t,n=Ae,r=!1){if(n){const o=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...i)=>{if(n.isUnmounted)return;mn(),un(n);const l=Ze(t,n,e,i);return Kt(),gn(),l});return r?o.unshift(s):o.push(s),s}}const Et=e=>(t,n=Ae)=>(!fn||e==="sp")&&Sr(e,(...r)=>t(...r),n),mc=Et("bm"),Xe=Et("m"),gc=Et("bu"),vc=Et("u"),kr=Et("bum"),Or=Et("um"),_c=Et("sp"),bc=Et("rtg"),yc=Et("rtc");function Ec(e,t=Ae){Sr("ec",e,t)}const Ji="components";function bt(e,t){return Cc(Ji,e,!0,t)||e}const wc=Symbol.for("v-ndc");function Cc(e,t,n=!0,r=!1){const o=De||Ae;if(o){const s=o.type;if(e===Ji){const l=Xc(s,!1);if(l&&(l===t||l===ft(t)||l===Cr(ft(t))))return s}const i=ls(o[e]||s[e],t)||ls(o.appContext[e],t);return!i&&r?s:i}}function ls(e,t){return e&&(e[t]||e[ft(t)]||e[Cr(ft(t))])}function $t(e,t,n,r){let o;const s=n&&n[r];if(J(e)||pe(e)){o=new Array(e.length);for(let i=0,l=e.length;it(i,l,void 0,s&&s[l]));else{const i=Object.keys(e);o=new Array(i.length);for(let l=0,a=i.length;lgr(t)?!(t.type===Ye||t.type===ye&&!Qi(t.children)):!0)?e:null}const oo=e=>e?cl(e)?Rr(e)||e.proxy:oo(e.parent):null,Tn=Oe(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>oo(e.parent),$root:e=>oo(e.root),$emit:e=>e.emit,$options:e=>Oo(e),$forceUpdate:e=>e.f||(e.f=()=>Tr(e.update)),$nextTick:e=>e.n||(e.n=Lr.bind(e.proxy)),$watch:e=>ac.bind(e)}),zr=(e,t)=>e!==Ee&&!e.__isScriptSetup&&fe(e,t),xc={get({_:e},t){const{ctx:n,setupState:r,data:o,props:s,accessCache:i,type:l,appContext:a}=e;let c;if(t[0]!=="$"){const g=i[t];if(g!==void 0)switch(g){case 1:return r[t];case 2:return o[t];case 4:return n[t];case 3:return s[t]}else{if(zr(r,t))return i[t]=1,r[t];if(o!==Ee&&fe(o,t))return i[t]=2,o[t];if((c=e.propsOptions[0])&&fe(c,t))return i[t]=3,s[t];if(n!==Ee&&fe(n,t))return i[t]=4,n[t];so&&(i[t]=0)}}const u=Tn[t];let f,h;if(u)return t==="$attrs"&&We(e,"get",t),u(e);if((f=l.__cssModules)&&(f=f[t]))return f;if(n!==Ee&&fe(n,t))return i[t]=4,n[t];if(h=a.config.globalProperties,fe(h,t))return h[t]},set({_:e},t,n){const{data:r,setupState:o,ctx:s}=e;return zr(o,t)?(o[t]=n,!0):r!==Ee&&fe(r,t)?(r[t]=n,!0):fe(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:s}},i){let l;return!!n[i]||e!==Ee&&fe(e,i)||zr(t,i)||(l=s[0])&&fe(l,i)||fe(r,i)||fe(Tn,i)||fe(o.config.globalProperties,i)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:fe(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function as(e){return J(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let so=!0;function Lc(e){const t=Oo(e),n=e.proxy,r=e.ctx;so=!1,t.beforeCreate&&cs(t.beforeCreate,e,"bc");const{data:o,computed:s,methods:i,watch:l,provide:a,inject:c,created:u,beforeMount:f,mounted:h,beforeUpdate:g,updated:y,activated:w,deactivated:T,beforeDestroy:v,beforeUnmount:b,destroyed:O,unmounted:k,render:q,renderTracked:X,renderTriggered:N,errorCaptured:m,serverPrefetch:z,expose:D,inheritAttrs:K,components:L,directives:R,filters:I}=t;if(c&&Tc(c,r,null),i)for(const ne in i){const re=i[ne];se(re)&&(r[ne]=re.bind(n))}if(o){const ne=o.call(n,n);we(ne)&&(e.data=Fn(ne))}if(so=!0,s)for(const ne in s){const re=s[ne],He=se(re)?re.bind(n,n):se(re.get)?re.get.bind(n,n):ot,Ne=!se(re)&&se(re.set)?re.set.bind(n):ot,Ve=j({get:He,set:Ne});Object.defineProperty(r,ne,{enumerable:!0,configurable:!0,get:()=>Ve.value,set:Be=>Ve.value=Be})}if(l)for(const ne in l)Zi(l[ne],r,n,ne);if(a){const ne=se(a)?a.call(n):a;Reflect.ownKeys(ne).forEach(re=>{Wt(re,ne[re])})}u&&cs(u,e,"c");function V(ne,re){J(re)?re.forEach(He=>ne(He.bind(n))):re&&ne(re.bind(n))}if(V(mc,f),V(Xe,h),V(gc,g),V(vc,y),V(dc,w),V(hc,T),V(Ec,m),V(yc,X),V(bc,N),V(kr,b),V(Or,k),V(_c,z),J(D))if(D.length){const ne=e.exposed||(e.exposed={});D.forEach(re=>{Object.defineProperty(ne,re,{get:()=>n[re],set:He=>n[re]=He})})}else e.exposed||(e.exposed={});q&&e.render===ot&&(e.render=q),K!=null&&(e.inheritAttrs=K),L&&(e.components=L),R&&(e.directives=R)}function Tc(e,t,n=ot){J(e)&&(e=io(e));for(const r in e){const o=e[r];let s;we(o)?"default"in o?s=ke(o.from||r,o.default,!0):s=ke(o.from||r):s=ke(o),Me(s)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>s.value,set:i=>s.value=i}):t[r]=s}}function cs(e,t,n){Ze(J(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Zi(e,t,n,r){const o=r.includes(".")?qi(n,r):()=>n[r];if(pe(e)){const s=t[e];se(s)&&ut(o,s)}else if(se(e))ut(o,e.bind(n));else if(we(e))if(J(e))e.forEach(s=>Zi(s,t,n,r));else{const s=se(e.handler)?e.handler.bind(n):t[e.handler];se(s)&&ut(o,s,e)}}function Oo(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:o,optionsCache:s,config:{optionMergeStrategies:i}}=e.appContext,l=s.get(t);let a;return l?a=l:!o.length&&!n&&!r?a=t:(a={},o.length&&o.forEach(c=>hr(a,c,i,!0)),hr(a,t,i)),we(t)&&s.set(t,a),a}function hr(e,t,n,r=!1){const{mixins:o,extends:s}=t;s&&hr(e,s,n,!0),o&&o.forEach(i=>hr(e,i,n,!0));for(const i in t)if(!(r&&i==="expose")){const l=Pc[i]||n&&n[i];e[i]=l?l(e[i],t[i]):t[i]}return e}const Pc={data:us,props:fs,emits:fs,methods:xn,computed:xn,beforeCreate:ze,created:ze,beforeMount:ze,mounted:ze,beforeUpdate:ze,updated:ze,beforeDestroy:ze,beforeUnmount:ze,destroyed:ze,unmounted:ze,activated:ze,deactivated:ze,errorCaptured:ze,serverPrefetch:ze,components:xn,directives:xn,watch:kc,provide:us,inject:Sc};function us(e,t){return t?e?function(){return Oe(se(e)?e.call(this,this):e,se(t)?t.call(this,this):t)}:t:e}function Sc(e,t){return xn(io(e),io(t))}function io(e){if(J(e)){const t={};for(let n=0;n1)return n&&se(t)?t.call(r&&r.proxy):t}}function Rc(e,t,n,r=!1){const o={},s={};lr(s,Ar,1),e.propsDefaults=Object.create(null),el(e,t,o,s);for(const i in e.propsOptions[0])i in o||(o[i]=void 0);n?e.props=r?o:Ai(o):e.type.props?e.props=o:e.props=s,e.attrs=s}function Ic(e,t,n,r){const{props:o,attrs:s,vnode:{patchFlag:i}}=e,l=de(o),[a]=e.propsOptions;let c=!1;if((r||i>0)&&!(i&16)){if(i&8){const u=e.vnode.dynamicProps;for(let f=0;f{a=!0;const[h,g]=tl(f,t,!0);Oe(i,h),g&&l.push(...g)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!s&&!a)return we(e)&&r.set(e,nn),nn;if(J(s))for(let u=0;u-1,g[1]=w<0||y-1||fe(g,"default"))&&l.push(f)}}}const c=[i,l];return we(e)&&r.set(e,c),c}function ds(e){return e[0]!=="$"}function hs(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function ps(e,t){return hs(e)===hs(t)}function ms(e,t){return J(t)?t.findIndex(n=>ps(n,e)):se(t)&&ps(t,e)?0:-1}const nl=e=>e[0]==="_"||e==="$stable",Ao=e=>J(e)?e.map(tt):[tt(e)],$c=(e,t,n)=>{if(t._n)return t;const r=$e((...o)=>Ao(t(...o)),n);return r._c=!1,r},rl=(e,t,n)=>{const r=e._ctx;for(const o in e){if(nl(o))continue;const s=e[o];if(se(s))t[o]=$c(o,s,r);else if(s!=null){const i=Ao(s);t[o]=()=>i}}},ol=(e,t)=>{const n=Ao(t);e.slots.default=()=>n},Mc=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=de(t),lr(t,"_",n)):rl(t,e.slots={})}else e.slots={},t&&ol(e,t);lr(e.slots,Ar,1)},Nc=(e,t,n)=>{const{vnode:r,slots:o}=e;let s=!0,i=Ee;if(r.shapeFlag&32){const l=t._;l?n&&l===1?s=!1:(Oe(o,t),!n&&l===1&&delete o._):(s=!t.$stable,rl(t,o)),i=t}else t&&(ol(e,t),i={default:1});if(s)for(const l in o)!nl(l)&&!(l in i)&&delete o[l]};function mr(e,t,n,r,o=!1){if(J(e)){e.forEach((h,g)=>mr(h,t&&(J(t)?t[g]:t),n,r,o));return}if(ln(r)&&!o)return;const s=r.shapeFlag&4?Rr(r.component)||r.component.proxy:r.el,i=o?null:s,{i:l,r:a}=e,c=t&&t.r,u=l.refs===Ee?l.refs={}:l.refs,f=l.setupState;if(c!=null&&c!==a&&(pe(c)?(u[c]=null,fe(f,c)&&(f[c]=null)):Me(c)&&(c.value=null)),se(a))Rt(a,l,12,[i,u]);else{const h=pe(a),g=Me(a);if(h||g){const y=()=>{if(e.f){const w=h?fe(f,a)?f[a]:u[a]:a.value;o?J(w)&&go(w,s):J(w)?w.includes(s)||w.push(s):h?(u[a]=[s],fe(f,a)&&(f[a]=u[a])):(a.value=[s],e.k&&(u[e.k]=a.value))}else h?(u[a]=i,fe(f,a)&&(f[a]=i)):g&&(a.value=i,e.k&&(u[e.k]=i))};i?(y.id=-1,Ue(y,n)):y()}}}let Lt=!1;const Zn=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",Xn=e=>e.nodeType===8;function Dc(e){const{mt:t,p:n,o:{patchProp:r,createText:o,nextSibling:s,parentNode:i,remove:l,insert:a,createComment:c}}=e,u=(v,b)=>{if(!b.hasChildNodes()){n(null,v,b),ur(),b._vnode=v;return}Lt=!1,f(b.firstChild,v,null,null,null),ur(),b._vnode=v,Lt&&console.error("Hydration completed but contains mismatches.")},f=(v,b,O,k,q,X=!1)=>{const N=Xn(v)&&v.data==="[",m=()=>w(v,b,O,k,q,N),{type:z,ref:D,shapeFlag:K,patchFlag:L}=b;let R=v.nodeType;b.el=v,L===-2&&(X=!1,b.dynamicChildren=null);let I=null;switch(z){case cn:R!==3?b.children===""?(a(b.el=o(""),i(v),v),I=v):I=m():(v.data!==b.children&&(Lt=!0,v.data=b.children),I=s(v));break;case Ye:R!==8||N?I=m():I=s(v);break;case Pn:if(N&&(v=s(v),R=v.nodeType),R===1||R===3){I=v;const le=!b.children.length;for(let V=0;V{X=X||!!b.dynamicChildren;const{type:N,props:m,patchFlag:z,shapeFlag:D,dirs:K}=b,L=N==="input"&&K||N==="option";if(L||z!==-1){if(K&&at(b,null,O,"created"),m)if(L||!X||z&48)for(const I in m)(L&&I.endsWith("value")||Hn(I)&&!Ln(I))&&r(v,I,null,m[I],!1,void 0,O);else m.onClick&&r(v,"onClick",null,m.onClick,!1,void 0,O);let R;if((R=m&&m.onVnodeBeforeMount)&&Qe(R,O,b),K&&at(b,null,O,"beforeMount"),((R=m&&m.onVnodeMounted)||K)&&Vi(()=>{R&&Qe(R,O,b),K&&at(b,null,O,"mounted")},k),D&16&&!(m&&(m.innerHTML||m.textContent))){let I=g(v.firstChild,b,v,O,k,q,X);for(;I;){Lt=!0;const le=I;I=I.nextSibling,l(le)}}else D&8&&v.textContent!==b.children&&(Lt=!0,v.textContent=b.children)}return v.nextSibling},g=(v,b,O,k,q,X,N)=>{N=N||!!b.dynamicChildren;const m=b.children,z=m.length;for(let D=0;D{const{slotScopeIds:N}=b;N&&(q=q?q.concat(N):N);const m=i(v),z=g(s(v),b,m,O,k,q,X);return z&&Xn(z)&&z.data==="]"?s(b.anchor=z):(Lt=!0,a(b.anchor=c("]"),m,z),z)},w=(v,b,O,k,q,X)=>{if(Lt=!0,b.el=null,X){const z=T(v);for(;;){const D=s(v);if(D&&D!==z)l(D);else break}}const N=s(v),m=i(v);return l(v),n(null,b,m,N,O,k,Zn(m),q),N},T=v=>{let b=0;for(;v;)if(v=s(v),v&&Xn(v)&&(v.data==="["&&b++,v.data==="]")){if(b===0)return s(v);b--}return v};return[u,f]}const Ue=Vi;function Hc(e){return Bc(e,Dc)}function Bc(e,t){const n=Qr();n.__VUE__=!0;const{insert:r,remove:o,patchProp:s,createElement:i,createText:l,createComment:a,setText:c,setElementText:u,parentNode:f,nextSibling:h,setScopeId:g=ot,insertStaticContent:y}=e,w=(d,p,_,E=null,x=null,P=null,H=!1,A=null,M=!!p.dynamicChildren)=>{if(d===p)return;d&&!jt(d,p)&&(E=C(d),Be(d,x,P,!0),d=null),p.patchFlag===-2&&(M=!1,p.dynamicChildren=null);const{type:S,ref:G,shapeFlag:U}=p;switch(S){case cn:T(d,p,_,E);break;case Ye:v(d,p,_,E);break;case Pn:d==null&&b(p,_,E,H);break;case ye:L(d,p,_,E,x,P,H,A,M);break;default:U&1?q(d,p,_,E,x,P,H,A,M):U&6?R(d,p,_,E,x,P,H,A,M):(U&64||U&128)&&S.process(d,p,_,E,x,P,H,A,M,$)}G!=null&&x&&mr(G,d&&d.ref,P,p||d,!p)},T=(d,p,_,E)=>{if(d==null)r(p.el=l(p.children),_,E);else{const x=p.el=d.el;p.children!==d.children&&c(x,p.children)}},v=(d,p,_,E)=>{d==null?r(p.el=a(p.children||""),_,E):p.el=d.el},b=(d,p,_,E)=>{[d.el,d.anchor]=y(d.children,p,_,E,d.el,d.anchor)},O=({el:d,anchor:p},_,E)=>{let x;for(;d&&d!==p;)x=h(d),r(d,_,E),d=x;r(p,_,E)},k=({el:d,anchor:p})=>{let _;for(;d&&d!==p;)_=h(d),o(d),d=_;o(p)},q=(d,p,_,E,x,P,H,A,M)=>{H=H||p.type==="svg",d==null?X(p,_,E,x,P,H,A,M):z(d,p,x,P,H,A,M)},X=(d,p,_,E,x,P,H,A)=>{let M,S;const{type:G,props:U,shapeFlag:Y,transition:te,dirs:ae}=d;if(M=d.el=i(d.type,P,U&&U.is,U),Y&8?u(M,d.children):Y&16&&m(d.children,M,null,E,x,P&&G!=="foreignObject",H,A),ae&&at(d,null,E,"created"),N(M,d,d.scopeId,H,E),U){for(const ge in U)ge!=="value"&&!Ln(ge)&&s(M,ge,null,U[ge],P,d.children,E,x,Ie);"value"in U&&s(M,"value",null,U.value),(S=U.onVnodeBeforeMount)&&Qe(S,E,d)}ae&&at(d,null,E,"beforeMount");const _e=(!x||x&&!x.pendingBranch)&&te&&!te.persisted;_e&&te.beforeEnter(M),r(M,p,_),((S=U&&U.onVnodeMounted)||_e||ae)&&Ue(()=>{S&&Qe(S,E,d),_e&&te.enter(M),ae&&at(d,null,E,"mounted")},x)},N=(d,p,_,E,x)=>{if(_&&g(d,_),E)for(let P=0;P{for(let S=M;S{const A=p.el=d.el;let{patchFlag:M,dynamicChildren:S,dirs:G}=p;M|=d.patchFlag&16;const U=d.props||Ee,Y=p.props||Ee;let te;_&&Dt(_,!1),(te=Y.onVnodeBeforeUpdate)&&Qe(te,_,p,d),G&&at(p,d,_,"beforeUpdate"),_&&Dt(_,!0);const ae=x&&p.type!=="foreignObject";if(S?D(d.dynamicChildren,S,A,_,E,ae,P):H||re(d,p,A,null,_,E,ae,P,!1),M>0){if(M&16)K(A,p,U,Y,_,E,x);else if(M&2&&U.class!==Y.class&&s(A,"class",null,Y.class,x),M&4&&s(A,"style",U.style,Y.style,x),M&8){const _e=p.dynamicProps;for(let ge=0;ge<_e.length;ge++){const Pe=_e[ge],et=U[Pe],Qt=Y[Pe];(Qt!==et||Pe==="value")&&s(A,Pe,et,Qt,x,d.children,_,E,Ie)}}M&1&&d.children!==p.children&&u(A,p.children)}else!H&&S==null&&K(A,p,U,Y,_,E,x);((te=Y.onVnodeUpdated)||G)&&Ue(()=>{te&&Qe(te,_,p,d),G&&at(p,d,_,"updated")},E)},D=(d,p,_,E,x,P,H)=>{for(let A=0;A{if(_!==E){if(_!==Ee)for(const A in _)!Ln(A)&&!(A in E)&&s(d,A,_[A],null,H,p.children,x,P,Ie);for(const A in E){if(Ln(A))continue;const M=E[A],S=_[A];M!==S&&A!=="value"&&s(d,A,S,M,H,p.children,x,P,Ie)}"value"in E&&s(d,"value",_.value,E.value)}},L=(d,p,_,E,x,P,H,A,M)=>{const S=p.el=d?d.el:l(""),G=p.anchor=d?d.anchor:l("");let{patchFlag:U,dynamicChildren:Y,slotScopeIds:te}=p;te&&(A=A?A.concat(te):te),d==null?(r(S,_,E),r(G,_,E),m(p.children,_,G,x,P,H,A,M)):U>0&&U&64&&Y&&d.dynamicChildren?(D(d.dynamicChildren,Y,_,x,P,H,A),(p.key!=null||x&&p===x.subTree)&&sl(d,p,!0)):re(d,p,_,G,x,P,H,A,M)},R=(d,p,_,E,x,P,H,A,M)=>{p.slotScopeIds=A,d==null?p.shapeFlag&512?x.ctx.activate(p,_,E,H,M):I(p,_,E,x,P,H,M):le(d,p,M)},I=(d,p,_,E,x,P,H)=>{const A=d.component=Gc(d,E,x);if(Vn(d)&&(A.ctx.renderer=$),Yc(A),A.asyncDep){if(x&&x.registerDep(A,V),!d.el){const M=A.subTree=ee(Ye);v(null,M,p,_)}return}V(A,d,p,_,x,P,H)},le=(d,p,_)=>{const E=p.component=d.component;if(sc(d,p,_))if(E.asyncDep&&!E.asyncResolved){ne(E,p,_);return}else E.next=p,Xa(E.update),E.update();else p.el=d.el,E.vnode=p},V=(d,p,_,E,x,P,H)=>{const A=()=>{if(d.isMounted){let{next:G,bu:U,u:Y,parent:te,vnode:ae}=d,_e=G,ge;Dt(d,!1),G?(G.el=ae.el,ne(d,G,H)):G=ae,U&&Dr(U),(ge=G.props&&G.props.onVnodeBeforeUpdate)&&Qe(ge,te,G,ae),Dt(d,!0);const Pe=Hr(d),et=d.subTree;d.subTree=Pe,w(et,Pe,f(et.el),C(et),d,x,P),G.el=Pe.el,_e===null&&ic(d,Pe.el),Y&&Ue(Y,x),(ge=G.props&&G.props.onVnodeUpdated)&&Ue(()=>Qe(ge,te,G,ae),x)}else{let G;const{el:U,props:Y}=p,{bm:te,m:ae,parent:_e}=d,ge=ln(p);if(Dt(d,!1),te&&Dr(te),!ge&&(G=Y&&Y.onVnodeBeforeMount)&&Qe(G,_e,p),Dt(d,!0),U&&ce){const Pe=()=>{d.subTree=Hr(d),ce(U,d.subTree,d,x,null)};ge?p.type.__asyncLoader().then(()=>!d.isUnmounted&&Pe()):Pe()}else{const Pe=d.subTree=Hr(d);w(null,Pe,_,E,d,x,P),p.el=Pe.el}if(ae&&Ue(ae,x),!ge&&(G=Y&&Y.onVnodeMounted)){const Pe=p;Ue(()=>Qe(G,_e,Pe),x)}(p.shapeFlag&256||_e&&ln(_e.vnode)&&_e.vnode.shapeFlag&256)&&d.a&&Ue(d.a,x),d.isMounted=!0,p=_=E=null}},M=d.effect=new yo(A,()=>Tr(S),d.scope),S=d.update=()=>M.run();S.id=d.uid,Dt(d,!0),S()},ne=(d,p,_)=>{p.component=d;const E=d.vnode.props;d.vnode=p,d.next=null,Ic(d,p.props,E,_),Nc(d,p.children,_),mn(),os(),gn()},re=(d,p,_,E,x,P,H,A,M=!1)=>{const S=d&&d.children,G=d?d.shapeFlag:0,U=p.children,{patchFlag:Y,shapeFlag:te}=p;if(Y>0){if(Y&128){Ne(S,U,_,E,x,P,H,A,M);return}else if(Y&256){He(S,U,_,E,x,P,H,A,M);return}}te&8?(G&16&&Ie(S,x,P),U!==S&&u(_,U)):G&16?te&16?Ne(S,U,_,E,x,P,H,A,M):Ie(S,x,P,!0):(G&8&&u(_,""),te&16&&m(U,_,E,x,P,H,A,M))},He=(d,p,_,E,x,P,H,A,M)=>{d=d||nn,p=p||nn;const S=d.length,G=p.length,U=Math.min(S,G);let Y;for(Y=0;YG?Ie(d,x,P,!0,!1,U):m(p,_,E,x,P,H,A,M,U)},Ne=(d,p,_,E,x,P,H,A,M)=>{let S=0;const G=p.length;let U=d.length-1,Y=G-1;for(;S<=U&&S<=Y;){const te=d[S],ae=p[S]=M?St(p[S]):tt(p[S]);if(jt(te,ae))w(te,ae,_,null,x,P,H,A,M);else break;S++}for(;S<=U&&S<=Y;){const te=d[U],ae=p[Y]=M?St(p[Y]):tt(p[Y]);if(jt(te,ae))w(te,ae,_,null,x,P,H,A,M);else break;U--,Y--}if(S>U){if(S<=Y){const te=Y+1,ae=teY)for(;S<=U;)Be(d[S],x,P,!0),S++;else{const te=S,ae=S,_e=new Map;for(S=ae;S<=Y;S++){const Ke=p[S]=M?St(p[S]):tt(p[S]);Ke.key!=null&&_e.set(Ke.key,S)}let ge,Pe=0;const et=Y-ae+1;let Qt=!1,Wo=0;const _n=new Array(et);for(S=0;S=et){Be(Ke,x,P,!0);continue}let lt;if(Ke.key!=null)lt=_e.get(Ke.key);else for(ge=ae;ge<=Y;ge++)if(_n[ge-ae]===0&&jt(Ke,p[ge])){lt=ge;break}lt===void 0?Be(Ke,x,P,!0):(_n[lt-ae]=S+1,lt>=Wo?Wo=lt:Qt=!0,w(Ke,p[lt],_,null,x,P,H,A,M),Pe++)}const Ko=Qt?Fc(_n):nn;for(ge=Ko.length-1,S=et-1;S>=0;S--){const Ke=ae+S,lt=p[Ke],Go=Ke+1{const{el:P,type:H,transition:A,children:M,shapeFlag:S}=d;if(S&6){Ve(d.component.subTree,p,_,E);return}if(S&128){d.suspense.move(p,_,E);return}if(S&64){H.move(d,p,_,$);return}if(H===ye){r(P,p,_);for(let U=0;UA.enter(P),x);else{const{leave:U,delayLeave:Y,afterLeave:te}=A,ae=()=>r(P,p,_),_e=()=>{U(P,()=>{ae(),te&&te()})};Y?Y(P,ae,_e):_e()}else r(P,p,_)},Be=(d,p,_,E=!1,x=!1)=>{const{type:P,props:H,ref:A,children:M,dynamicChildren:S,shapeFlag:G,patchFlag:U,dirs:Y}=d;if(A!=null&&mr(A,null,_,d,!0),G&256){p.ctx.deactivate(d);return}const te=G&1&&Y,ae=!ln(d);let _e;if(ae&&(_e=H&&H.onVnodeBeforeUnmount)&&Qe(_e,p,d),G&6)it(d.component,_,E);else{if(G&128){d.suspense.unmount(_,E);return}te&&at(d,null,p,"beforeUnmount"),G&64?d.type.remove(d,p,_,x,$,E):S&&(P!==ye||U>0&&U&64)?Ie(S,p,_,!1,!0):(P===ye&&U&384||!x&&G&16)&&Ie(M,p,_),E&&wt(d)}(ae&&(_e=H&&H.onVnodeUnmounted)||te)&&Ue(()=>{_e&&Qe(_e,p,d),te&&at(d,null,p,"unmounted")},_)},wt=d=>{const{type:p,el:_,anchor:E,transition:x}=d;if(p===ye){Ct(_,E);return}if(p===Pn){k(d);return}const P=()=>{o(_),x&&!x.persisted&&x.afterLeave&&x.afterLeave()};if(d.shapeFlag&1&&x&&!x.persisted){const{leave:H,delayLeave:A}=x,M=()=>H(_,P);A?A(d.el,P,M):M()}else P()},Ct=(d,p)=>{let _;for(;d!==p;)_=h(d),o(d),d=_;o(p)},it=(d,p,_)=>{const{bum:E,scope:x,update:P,subTree:H,um:A}=d;E&&Dr(E),x.stop(),P&&(P.active=!1,Be(H,d,p,_)),A&&Ue(A,p),Ue(()=>{d.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&d.asyncDep&&!d.asyncResolved&&d.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},Ie=(d,p,_,E=!1,x=!1,P=0)=>{for(let H=P;Hd.shapeFlag&6?C(d.component.subTree):d.shapeFlag&128?d.suspense.next():h(d.anchor||d.el),F=(d,p,_)=>{d==null?p._vnode&&Be(p._vnode,null,null,!0):w(p._vnode||null,d,p,null,null,null,_),os(),ur(),p._vnode=d},$={p:w,um:Be,m:Ve,r:wt,mt:I,mc:m,pc:re,pbc:D,n:C,o:e};let W,ce;return t&&([W,ce]=t($)),{render:F,hydrate:W,createApp:Ac(F,W)}}function Dt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function sl(e,t,n=!1){const r=e.children,o=t.children;if(J(r)&&J(o))for(let s=0;s>1,e[n[l]]0&&(t[r]=n[s-1]),n[s]=r)}}for(s=n.length,i=n[s-1];s-- >0;)n[s]=i,i=t[i];return n}const zc=e=>e.__isTeleport,ye=Symbol.for("v-fgt"),cn=Symbol.for("v-txt"),Ye=Symbol.for("v-cmt"),Pn=Symbol.for("v-stc"),Sn=[];let rt=null;function B(e=!1){Sn.push(rt=e?null:[])}function jc(){Sn.pop(),rt=Sn[Sn.length-1]||null}let Mn=1;function gs(e){Mn+=e}function il(e){return e.dynamicChildren=Mn>0?rt||nn:null,jc(),Mn>0&&rt&&rt.push(e),e}function Q(e,t,n,r,o,s){return il(oe(e,t,n,r,o,s,!0))}function Le(e,t,n,r,o){return il(ee(e,t,n,r,o,!0))}function gr(e){return e?e.__v_isVNode===!0:!1}function jt(e,t){return e.type===t.type&&e.key===t.key}const Ar="__vInternal",ll=({key:e})=>e??null,sr=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?pe(e)||Me(e)||se(e)?{i:De,r:e,k:t,f:!!n}:e:null);function oe(e,t=null,n=null,r=0,o=null,s=e===ye?0:1,i=!1,l=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&ll(t),ref:t&&sr(t),scopeId:ji,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:s,patchFlag:r,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:De};return l?(Ro(a,n),s&128&&e.normalize(a)):n&&(a.shapeFlag|=pe(n)?8:16),Mn>0&&!i&&rt&&(a.patchFlag>0||s&6)&&a.patchFlag!==32&&rt.push(a),a}const ee=Vc;function Vc(e,t=null,n=null,r=0,o=null,s=!1){if((!e||e===wc)&&(e=Ye),gr(e)){const l=Mt(e,t,!0);return n&&Ro(l,n),Mn>0&&!s&&rt&&(l.shapeFlag&6?rt[rt.indexOf(e)]=l:rt.push(l)),l.patchFlag|=-2,l}if(eu(e)&&(e=e.__vccOpts),t){t=Uc(t);let{class:l,style:a}=t;l&&!pe(l)&&(t.class=qe(l)),we(a)&&(Ri(a)&&!J(a)&&(a=Oe({},a)),t.style=Bn(a))}const i=pe(e)?1:lc(e)?128:zc(e)?64:we(e)?4:se(e)?2:0;return oe(e,t,n,r,o,i,s,!0)}function Uc(e){return e?Ri(e)||Ar in e?Oe({},e):e:null}function Mt(e,t,n=!1){const{props:r,ref:o,patchFlag:s,children:i}=e,l=t?ao(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&ll(l),ref:t&&t.ref?n&&o?J(o)?o.concat(sr(t)):[o,sr(t)]:sr(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:i,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ye?s===-1?16:s|16:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Mt(e.ssContent),ssFallback:e.ssFallback&&Mt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function yt(e=" ",t=0){return ee(cn,null,e,t)}function qc(e,t){const n=ee(Pn,null,e);return n.staticCount=t,n}function Te(e="",t=!1){return t?(B(),Le(Ye,null,e)):ee(Ye,null,e)}function tt(e){return e==null||typeof e=="boolean"?ee(Ye):J(e)?ee(ye,null,e.slice()):typeof e=="object"?St(e):ee(cn,null,String(e))}function St(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Mt(e)}function Ro(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(J(t))n=16;else if(typeof t=="object")if(r&65){const o=t.default;o&&(o._c&&(o._d=!1),Ro(e,o()),o._c&&(o._d=!0));return}else{n=32;const o=t._;!o&&!(Ar in t)?t._ctx=De:o===3&&De&&(De.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else se(t)?(t={default:t,_ctx:De},n=32):(t=String(t),r&64?(n=16,t=[yt(t)]):n=8);e.children=t,e.shapeFlag|=n}function ao(...e){const t={};for(let n=0;nAe||De;let Io,Zt,vs="__VUE_INSTANCE_SETTERS__";(Zt=Qr()[vs])||(Zt=Qr()[vs]=[]),Zt.push(e=>Ae=e),Io=e=>{Zt.length>1?Zt.forEach(t=>t(e)):Zt[0](e)};const un=e=>{Io(e),e.scope.on()},Kt=()=>{Ae&&Ae.scope.off(),Io(null)};function cl(e){return e.vnode.shapeFlag&4}let fn=!1;function Yc(e,t=!1){fn=t;const{props:n,children:r}=e.vnode,o=cl(e);Rc(e,n,o,t),Mc(e,r);const s=o?Jc(e,t):void 0;return fn=!1,s}function Jc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Ii(new Proxy(e.ctx,xc));const{setup:r}=n;if(r){const o=e.setupContext=r.length>1?Zc(e):null;un(e),mn();const s=Rt(r,e,0,[e.props,o]);if(gn(),Kt(),mi(s)){if(s.then(Kt,Kt),t)return s.then(i=>{_s(e,i,t)}).catch(i=>{jn(i,e,0)});e.asyncDep=s}else _s(e,s,t)}else ul(e,t)}function _s(e,t,n){se(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:we(t)&&(e.setupState=Di(t)),ul(e,n)}let bs;function ul(e,t,n){const r=e.type;if(!e.render){if(!t&&bs&&!r.render){const o=r.template||Oo(e).template;if(o){const{isCustomElement:s,compilerOptions:i}=e.appContext.config,{delimiters:l,compilerOptions:a}=r,c=Oe(Oe({isCustomElement:s,delimiters:l},i),a);r.render=bs(o,c)}}e.render=r.render||ot}un(e),mn(),Lc(e),gn(),Kt()}function Qc(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return We(e,"get","$attrs"),t[n]}}))}function Zc(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Qc(e)},slots:e.slots,emit:e.emit,expose:t}}function Rr(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Di(Ii(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Tn)return Tn[n](e)},has(t,n){return n in t||n in Tn}}))}function Xc(e,t=!0){return se(e)?e.displayName||e.name:e.name||t&&e.__name}function eu(e){return se(e)&&"__vccOpts"in e}const j=(e,t)=>Ja(e,t,fn);function ve(e,t,n){const r=arguments.length;return r===2?we(t)&&!J(t)?gr(t)?ee(e,null,[t]):ee(e,t):ee(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&gr(n)&&(n=[n]),ee(e,t,n))}const tu=Symbol.for("v-scx"),nu=()=>ke(tu),ru="3.3.4",ou="http://www.w3.org/2000/svg",Vt=typeof document<"u"?document:null,ys=Vt&&Vt.createElement("template"),su={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t?Vt.createElementNS(ou,e):Vt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>Vt.createTextNode(e),createComment:e=>Vt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Vt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const i=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{ys.innerHTML=r?`${e}`:e;const l=ys.content;if(r){const a=l.firstChild;for(;a.firstChild;)l.appendChild(a.firstChild);l.removeChild(a)}t.insertBefore(l,n)}return[i?i.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function iu(e,t,n){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function lu(e,t,n){const r=e.style,o=pe(n);if(n&&!o){if(t&&!pe(t))for(const s in t)n[s]==null&&co(r,s,"");for(const s in n)co(r,s,n[s])}else{const s=r.display;o?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=s)}}const Es=/\s*!important$/;function co(e,t,n){if(J(n))n.forEach(r=>co(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=au(e,t);Es.test(n)?e.setProperty(Yt(r),n.replace(Es,""),"important"):e[r]=n}}const ws=["Webkit","Moz","ms"],jr={};function au(e,t){const n=jr[t];if(n)return n;let r=ft(t);if(r!=="filter"&&r in e)return jr[t]=r;r=Cr(r);for(let o=0;oVr||(mu.then(()=>Vr=0),Vr=Date.now());function vu(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ze(_u(r,n.value),t,5,[r])};return n.value=e,n.attached=gu(),n}function _u(e,t){if(J(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const Ls=/^on[a-z]/,bu=(e,t,n,r,o=!1,s,i,l,a)=>{t==="class"?iu(e,r,o):t==="style"?lu(e,n,r):Hn(t)?mo(t)||hu(e,t,n,r,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):yu(e,t,r,o))?uu(e,t,r,s,i,l,a):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),cu(e,t,r,o))};function yu(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Ls.test(t)&&se(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Ls.test(t)&&pe(n)?!1:t in e}const Tt="transition",bn="animation",Un=(e,{slots:t})=>ve(fc,Eu(e),t);Un.displayName="Transition";const fl={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Un.props=Oe({},Wi,fl);const Ht=(e,t=[])=>{J(e)?e.forEach(n=>n(...t)):e&&e(...t)},Ts=e=>e?J(e)?e.some(t=>t.length>1):e.length>1:!1;function Eu(e){const t={};for(const L in e)L in fl||(t[L]=e[L]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:a=s,appearActiveClass:c=i,appearToClass:u=l,leaveFromClass:f=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:g=`${n}-leave-to`}=e,y=wu(o),w=y&&y[0],T=y&&y[1],{onBeforeEnter:v,onEnter:b,onEnterCancelled:O,onLeave:k,onLeaveCancelled:q,onBeforeAppear:X=v,onAppear:N=b,onAppearCancelled:m=O}=t,z=(L,R,I)=>{Bt(L,R?u:l),Bt(L,R?c:i),I&&I()},D=(L,R)=>{L._isLeaving=!1,Bt(L,f),Bt(L,g),Bt(L,h),R&&R()},K=L=>(R,I)=>{const le=L?N:b,V=()=>z(R,L,I);Ht(le,[R,V]),Ps(()=>{Bt(R,L?a:s),Pt(R,L?u:l),Ts(le)||Ss(R,r,w,V)})};return Oe(t,{onBeforeEnter(L){Ht(v,[L]),Pt(L,s),Pt(L,i)},onBeforeAppear(L){Ht(X,[L]),Pt(L,a),Pt(L,c)},onEnter:K(!1),onAppear:K(!0),onLeave(L,R){L._isLeaving=!0;const I=()=>D(L,R);Pt(L,f),Lu(),Pt(L,h),Ps(()=>{L._isLeaving&&(Bt(L,f),Pt(L,g),Ts(k)||Ss(L,r,T,I))}),Ht(k,[L,I])},onEnterCancelled(L){z(L,!1),Ht(O,[L])},onAppearCancelled(L){z(L,!0),Ht(m,[L])},onLeaveCancelled(L){D(L),Ht(q,[L])}})}function wu(e){if(e==null)return null;if(we(e))return[Ur(e.enter),Ur(e.leave)];{const t=Ur(e);return[t,t]}}function Ur(e){return aa(e)}function Pt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function Bt(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function Ps(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Cu=0;function Ss(e,t,n,r){const o=e._endId=++Cu,s=()=>{o===e._endId&&r()};if(n)return setTimeout(s,n);const{type:i,timeout:l,propCount:a}=xu(e,t);if(!i)return r();const c=i+"end";let u=0;const f=()=>{e.removeEventListener(c,h),s()},h=g=>{g.target===e&&++u>=a&&f()};setTimeout(()=>{u(n[y]||"").split(", "),o=r(`${Tt}Delay`),s=r(`${Tt}Duration`),i=ks(o,s),l=r(`${bn}Delay`),a=r(`${bn}Duration`),c=ks(l,a);let u=null,f=0,h=0;t===Tt?i>0&&(u=Tt,f=i,h=s.length):t===bn?c>0&&(u=bn,f=c,h=a.length):(f=Math.max(i,c),u=f>0?i>c?Tt:bn:null,h=u?u===Tt?s.length:a.length:0);const g=u===Tt&&/\b(transform|all)(,|$)/.test(r(`${Tt}Property`).toString());return{type:u,timeout:f,propCount:h,hasTransform:g}}function ks(e,t){for(;e.lengthOs(n)+Os(e[r])))}function Os(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function Lu(){return document.body.offsetHeight}const Tu={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Pu=(e,t)=>n=>{if(!("key"in n))return;const r=Yt(n.key);if(t.some(o=>o===r||Tu[o]===r))return e(n)},vr={beforeMount(e,{value:t},{transition:n}){e._vod=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):yn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),yn(e,!0),r.enter(e)):r.leave(e,()=>{yn(e,!1)}):yn(e,t))},beforeUnmount(e,{value:t}){yn(e,t)}};function yn(e,t){e.style.display=t?e._vod:"none"}const Su=Oe({patchProp:bu},su);let qr,As=!1;function ku(){return qr=As?qr:Hc(Su),As=!0,qr}const Ou=(...e)=>{const t=ku().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=Au(r);if(o)return n(o,!0,o instanceof SVGElement)},t};function Au(e){return pe(e)?document.querySelector(e):e}const Ru={"v-8daa1a0e":()=>ie(()=>import("./index.html-73be7817.js"),[]).then(({data:e})=>e),"v-5c4d59a8":()=>ie(()=>import("./chat.html-ea257c93.js"),[]).then(({data:e})=>e),"v-6ce48554":()=>ie(()=>import("./contributing.html-9be653e8.js"),[]).then(({data:e})=>e),"v-0100cb31":()=>ie(()=>import("./donate.html-b400e680.js"),[]).then(({data:e})=>e),"v-f2255364":()=>ie(()=>import("./gbcompo21.html-99aaee71.js"),[]).then(({data:e})=>e),"v-eb51f0e8":()=>ie(()=>import("./gbcompo23.html-a81692eb.js"),[]).then(({data:e})=>e),"v-45972830":()=>ie(()=>import("./meetings.html-51bd8c78.js"),[]).then(({data:e})=>e),"v-097038b2":()=>ie(()=>import("./newsletter.html-265eba04.js"),[]).then(({data:e})=>e),"v-6c436918":()=>ie(()=>import("./privacypolicy.html-c130ba76.js"),[]).then(({data:e})=>e),"v-68dc5d0d":()=>ie(()=>import("./resources.html-6f26efe6.js"),[]).then(({data:e})=>e),"v-81096038":()=>ie(()=>import("./asmstyle.html-f84bdcf1.js"),[]).then(({data:e})=>e),"v-2cfc1b4c":()=>ie(()=>import("./deadcscroll.html-cf90a12f.js"),[]).then(({data:e})=>e),"v-01eed7fd":()=>ie(()=>import("./dma_hijacking.html-3c0726e8.js"),[]).then(({data:e})=>e),"v-2db785a7":()=>ie(()=>import("./lyc_timing.html-7f10ac5d.js"),[]).then(({data:e})=>e),"v-28ddd31d":()=>ie(()=>import("./sgb_border.html-bc8bc6ba.js"),[]).then(({data:e})=>e),"v-3d89621d":()=>ie(()=>import("./tools.html-e21b5d86.js"),[]).then(({data:e})=>e),"v-5f5d6e7d":()=>ie(()=>import("./2023-11-04-sc.html-73e957ae.js"),[]).then(({data:e})=>e),"v-3066264a":()=>ie(()=>import("./2024-03-10-sc2.html-2f212aef.js"),[]).then(({data:e})=>e),"v-1c0cbf85":()=>ie(()=>import("./1.html-19f9b6b9.js"),[]).then(({data:e})=>e),"v-3706649a":()=>ie(()=>import("./404.html-60b35caa.js"),[]).then(({data:e})=>e)},Iu=JSON.parse(`{"base":"/","lang":"en-US","title":"gbdev.io","description":"game boy development scene","head":[["script",{},"\\n var _paq = window._paq = window._paq || [];\\n /* tracker methods like \\"setCustomDimension\\" should be called before \\"trackPageView\\" */\\n _paq.push(['trackPageView']);\\n _paq.push(['enableLinkTracking']);\\n (function() {\\n var u=\\"//stats.gbdev.io/\\";\\n _paq.push(['setTrackerUrl', u+'matomo.php']);\\n _paq.push(['setSiteId', '1']);\\n var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];\\n g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);\\n })();\\n "],["link",{"rel":"icon","type":"image/png","sizes":"32x32","href":"/favicons/favicon-32x32.png"}],["link",{"rel":"icon","type":"image/png","sizes":"16x16","href":"/favicons/favicon-16x16.png"}],["meta",{"property":"og:site_name","content":"gbdev.io"}],["meta",{"name":"twitter:card","content":"summary"}],["meta",{"name":"twitter:site","content":"@gbdev0"}],["meta",{"name":"og:image","content":"https://gbdev.io/images/gbinternals.png"}]],"locales":{}}`);var $u=([e,t,n])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,n]),Mu=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=$u(r);t.has(o)||(t.add(o),n.push(r))}),n},qn=e=>/^(https?:)?\/\//.test(e),Nu=e=>/^mailto:/.test(e),Du=e=>/^tel:/.test(e),$o=e=>Object.prototype.toString.call(e)==="[object Object]",dl=e=>e[e.length-1]==="/"?e.slice(0,-1):e,hl=e=>e[0]==="/"?e.slice(1):e,pl=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const s=o.split("/").length-r.split("/").length;return s!==0?s:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"};const ml={"v-8daa1a0e":Se(()=>ie(()=>import("./index.html-3102c219.js"),[])),"v-5c4d59a8":Se(()=>ie(()=>import("./chat.html-243153ed.js"),[])),"v-6ce48554":Se(()=>ie(()=>import("./contributing.html-460f065c.js"),[])),"v-0100cb31":Se(()=>ie(()=>import("./donate.html-ade8e922.js"),[])),"v-f2255364":Se(()=>ie(()=>import("./gbcompo21.html-dc2cba05.js"),[])),"v-eb51f0e8":Se(()=>ie(()=>import("./gbcompo23.html-b56bd135.js"),[])),"v-45972830":Se(()=>ie(()=>import("./meetings.html-ac085808.js"),[])),"v-097038b2":Se(()=>ie(()=>import("./newsletter.html-9902ee4e.js"),[])),"v-6c436918":Se(()=>ie(()=>import("./privacypolicy.html-0bfa63bd.js"),[])),"v-68dc5d0d":Se(()=>ie(()=>import("./resources.html-5ebeee12.js"),[])),"v-81096038":Se(()=>ie(()=>import("./asmstyle.html-74b27b35.js"),[])),"v-2cfc1b4c":Se(()=>ie(()=>import("./deadcscroll.html-b652ecd6.js"),[])),"v-01eed7fd":Se(()=>ie(()=>import("./dma_hijacking.html-e111a616.js"),[])),"v-2db785a7":Se(()=>ie(()=>import("./lyc_timing.html-8835a7cd.js"),[])),"v-28ddd31d":Se(()=>ie(()=>import("./sgb_border.html-29f3ff42.js"),[])),"v-3d89621d":Se(()=>ie(()=>import("./tools.html-e2d74e0f.js"),[])),"v-5f5d6e7d":Se(()=>ie(()=>import("./2023-11-04-sc.html-53a290fa.js"),[])),"v-3066264a":Se(()=>ie(()=>import("./2024-03-10-sc2.html-6d8fd61f.js"),[])),"v-1c0cbf85":Se(()=>ie(()=>import("./1.html-7f6467c5.js"),[])),"v-3706649a":Se(()=>ie(()=>import("./404.html-8084ca77.js"),[]))};var Hu=Symbol(""),Bu=Ce(Ru),gl=zn({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),kt=Ce(gl),Gt=()=>kt,vl=Symbol(""),gt=()=>{const e=ke(vl);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},_l=Symbol(""),Fu=()=>{const e=ke(_l);if(!e)throw new Error("usePageHead() is called without provider.");return e},zu=Symbol(""),bl=Symbol(""),ju=()=>{const e=ke(bl);if(!e)throw new Error("usePageLang() is called without provider.");return e},yl=Symbol(""),Vu=()=>{const e=ke(yl);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Mo=Symbol(""),Ir=()=>{const e=ke(Mo);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},tn=Ce(Iu),El=()=>tn,wl=Symbol(""),No=()=>{const e=ke(wl);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Uu=Symbol(""),qu="Layout",Wu="NotFound",ht=Fn({resolveLayouts:e=>e.reduce((t,n)=>({...t,...n.layouts}),{}),resolvePageData:async e=>{const t=Bu.value[e];return await(t==null?void 0:t())??gl},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,n)=>{const r=pe(t.description)?t.description:n.description,o=[...J(t.head)?t.head:[],...n.head,["title",{},e],["meta",{name:"description",content:r}]];return Mu(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(n=>!!n).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let n;if(e.path){const r=e.frontmatter.layout;pe(r)?n=r:n=qu}else n=Wu;return t[n]},resolveRouteLocale:(e,t)=>pl(e,t),resolveSiteLocaleData:(e,t)=>({...e,...e.locales[t]})}),Do=he({name:"ClientOnly",setup(e,t){const n=Ce(!1);return Xe(()=>{n.value=!0}),()=>{var r,o;return n.value?(o=(r=t.slots).default)==null?void 0:o.call(r):null}}}),Ku=he({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Gt(),n=j(()=>ml[e.pageKey||t.value.key]);return()=>n.value?ve(n.value):ve("div","404 Not Found")}}),Nt=(e={})=>e,Ho=e=>qn(e)?e:`/${hl(e)}`;function Cl(e,t,n){var r,o,s;t===void 0&&(t=50),n===void 0&&(n={});var i=(r=n.isImmediate)!=null&&r,l=(o=n.callback)!=null&&o,a=n.maxWait,c=Date.now(),u=[];function f(){if(a!==void 0){var g=Date.now()-c;if(g+t>=a)return a-g}return t}var h=function(){var g=[].slice.call(arguments),y=this;return new Promise(function(w,T){var v=i&&s===void 0;if(s!==void 0&&clearTimeout(s),s=setTimeout(function(){if(s=void 0,c=Date.now(),!i){var O=e.apply(y,g);l&&l(O),u.forEach(function(k){return(0,k.resolve)(O)}),u=[]}},f()),v){var b=e.apply(y,g);return l&&l(b),w(b)}u.push({resolve:w,reject:T})})};return h.cancel=function(g){s!==void 0&&clearTimeout(s),u.forEach(function(y){return(0,y.reject)(g)}),u=[]},h}/*! +const Xl="modulepreload",ea=function(e){return"/"+e},Yo={},ie=function(t,n,r){if(!n||n.length===0)return t();const o=document.getElementsByTagName("link");return Promise.all(n.map(s=>{if(s=ea(s),s in Yo)return;Yo[s]=!0;const i=s.endsWith(".css"),l=i?'[rel="stylesheet"]':"";if(!!r)for(let u=o.length-1;u>=0;u--){const f=o[u];if(f.href===s&&(!i||f.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${s}"]${l}`))return;const c=document.createElement("link");if(c.rel=i?"stylesheet":Xl,i||(c.as="script",c.crossOrigin=""),c.href=s,document.head.appendChild(c),i)return new Promise((u,f)=>{c.addEventListener("load",u),c.addEventListener("error",()=>f(new Error(`Unable to preload CSS for ${s}`)))})})).then(()=>t()).catch(s=>{const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=s,window.dispatchEvent(i),!i.defaultPrevented)throw s})};function po(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;o!!n[o.toLowerCase()]:o=>!!n[o]}const Ee={},nn=[],ot=()=>{},ta=()=>!1,na=/^on[^a-z]/,Hn=e=>na.test(e),mo=e=>e.startsWith("onUpdate:"),Oe=Object.assign,go=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},ra=Object.prototype.hasOwnProperty,fe=(e,t)=>ra.call(e,t),J=Array.isArray,rn=e=>Er(e)==="[object Map]",pi=e=>Er(e)==="[object Set]",se=e=>typeof e=="function",pe=e=>typeof e=="string",vo=e=>typeof e=="symbol",we=e=>e!==null&&typeof e=="object",mi=e=>we(e)&&se(e.then)&&se(e.catch),gi=Object.prototype.toString,Er=e=>gi.call(e),oa=e=>Er(e).slice(8,-1),vi=e=>Er(e)==="[object Object]",_o=e=>pe(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Ln=po(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),wr=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},sa=/-(\w)/g,ft=wr(e=>e.replace(sa,(t,n)=>n?n.toUpperCase():"")),ia=/\B([A-Z])/g,Yt=wr(e=>e.replace(ia,"-$1").toLowerCase()),Cr=wr(e=>e.charAt(0).toUpperCase()+e.slice(1)),Nr=wr(e=>e?`on${Cr(e)}`:""),An=(e,t)=>!Object.is(e,t),Dr=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},la=e=>{const t=parseFloat(e);return isNaN(t)?e:t},aa=e=>{const t=pe(e)?Number(e):NaN;return isNaN(t)?e:t};let Jo;const Qr=()=>Jo||(Jo=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function Bn(e){if(J(e)){const t={};for(let n=0;n{if(n){const r=n.split(ua);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t}function qe(e){let t="";if(pe(e))t=e;else if(J(e))for(let n=0;npe(e)?e:e==null?"":J(e)||we(e)&&(e.toString===gi||!se(e.toString))?JSON.stringify(e,bi,2):String(e),bi=(e,t)=>t&&t.__v_isRef?bi(e,t.value):rn(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[r,o])=>(n[`${r} =>`]=o,n),{})}:pi(t)?{[`Set(${t.size})`]:[...t.values()]}:we(t)&&!J(t)&&!vi(t)?String(t):t;let Ge;class ma{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Ge,!t&&Ge&&(this.index=(Ge.scopes||(Ge.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=Ge;try{return Ge=this,t()}finally{Ge=n}}}on(){Ge=this}off(){Ge=this.parent}stop(t){if(this._active){let n,r;for(n=0,r=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},Ei=e=>(e.w&It)>0,wi=e=>(e.n&It)>0,_a=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let r=0;r{(u==="length"||u>=a)&&l.push(c)})}else switch(n!==void 0&&l.push(i.get(n)),t){case"add":J(e)?_o(n)&&l.push(i.get("length")):(l.push(i.get(qt)),rn(e)&&l.push(i.get(Xr)));break;case"delete":J(e)||(l.push(i.get(qt)),rn(e)&&l.push(i.get(Xr)));break;case"set":rn(e)&&l.push(i.get(qt));break}if(l.length===1)l[0]&&eo(l[0]);else{const a=[];for(const c of l)c&&a.push(...c);eo(bo(a))}}function eo(e,t){const n=J(e)?e:[...e];for(const r of n)r.computed&&Zo(r);for(const r of n)r.computed||Zo(r)}function Zo(e,t){(e!==nt||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function ya(e,t){var n;return(n=ar.get(e))==null?void 0:n.get(t)}const Ea=po("__proto__,__v_isRef,__isVue"),Li=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(vo)),wa=Eo(),Ca=Eo(!1,!0),xa=Eo(!0),Xo=La();function La(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const r=de(this);for(let s=0,i=this.length;s{e[t]=function(...n){mn();const r=de(this)[t].apply(this,n);return gn(),r}}),e}function Ta(e){const t=de(this);return We(t,"has",e),t.hasOwnProperty(e)}function Eo(e=!1,t=!1){return function(r,o,s){if(o==="__v_isReactive")return!e;if(o==="__v_isReadonly")return e;if(o==="__v_isShallow")return t;if(o==="__v_raw"&&s===(e?t?ja:Oi:t?ki:Si).get(r))return r;const i=J(r);if(!e){if(i&&fe(Xo,o))return Reflect.get(Xo,o,s);if(o==="hasOwnProperty")return Ta}const l=Reflect.get(r,o,s);return(vo(o)?Li.has(o):Ea(o))||(e||We(r,"get",o),t)?l:Me(l)?i&&_o(o)?l:l.value:we(l)?e?zn(l):Fn(l):l}}const Pa=Ti(),Sa=Ti(!0);function Ti(e=!1){return function(n,r,o,s){let i=n[r];if(an(i)&&Me(i)&&!Me(o))return!1;if(!e&&(!cr(o)&&!an(o)&&(i=de(i),o=de(o)),!J(n)&&Me(i)&&!Me(o)))return i.value=o,!0;const l=J(n)&&_o(r)?Number(r)e,xr=e=>Reflect.getPrototypeOf(e);function Wn(e,t,n=!1,r=!1){e=e.__v_raw;const o=de(e),s=de(t);n||(t!==s&&We(o,"get",t),We(o,"get",s));const{has:i}=xr(o),l=r?wo:n?Lo:Rn;if(i.call(o,t))return l(e.get(t));if(i.call(o,s))return l(e.get(s));e!==o&&e.get(t)}function Kn(e,t=!1){const n=this.__v_raw,r=de(n),o=de(e);return t||(e!==o&&We(r,"has",e),We(r,"has",o)),e===o?n.has(e):n.has(e)||n.has(o)}function Gn(e,t=!1){return e=e.__v_raw,!t&&We(de(e),"iterate",qt),Reflect.get(e,"size",e)}function es(e){e=de(e);const t=de(this);return xr(t).has.call(t,e)||(t.add(e),_t(t,"add",e,e)),this}function ts(e,t){t=de(t);const n=de(this),{has:r,get:o}=xr(n);let s=r.call(n,e);s||(e=de(e),s=r.call(n,e));const i=o.call(n,e);return n.set(e,t),s?An(t,i)&&_t(n,"set",e,t):_t(n,"add",e,t),this}function ns(e){const t=de(this),{has:n,get:r}=xr(t);let o=n.call(t,e);o||(e=de(e),o=n.call(t,e)),r&&r.call(t,e);const s=t.delete(e);return o&&_t(t,"delete",e,void 0),s}function rs(){const e=de(this),t=e.size!==0,n=e.clear();return t&&_t(e,"clear",void 0,void 0),n}function Yn(e,t){return function(r,o){const s=this,i=s.__v_raw,l=de(i),a=t?wo:e?Lo:Rn;return!e&&We(l,"iterate",qt),i.forEach((c,u)=>r.call(o,a(c),a(u),s))}}function Jn(e,t,n){return function(...r){const o=this.__v_raw,s=de(o),i=rn(s),l=e==="entries"||e===Symbol.iterator&&i,a=e==="keys"&&i,c=o[e](...r),u=n?wo:t?Lo:Rn;return!t&&We(s,"iterate",a?Xr:qt),{next(){const{value:f,done:h}=c.next();return h?{value:f,done:h}:{value:l?[u(f[0]),u(f[1])]:u(f),done:h}},[Symbol.iterator](){return this}}}}function xt(e){return function(...t){return e==="delete"?!1:this}}function $a(){const e={get(s){return Wn(this,s)},get size(){return Gn(this)},has:Kn,add:es,set:ts,delete:ns,clear:rs,forEach:Yn(!1,!1)},t={get(s){return Wn(this,s,!1,!0)},get size(){return Gn(this)},has:Kn,add:es,set:ts,delete:ns,clear:rs,forEach:Yn(!1,!0)},n={get(s){return Wn(this,s,!0)},get size(){return Gn(this,!0)},has(s){return Kn.call(this,s,!0)},add:xt("add"),set:xt("set"),delete:xt("delete"),clear:xt("clear"),forEach:Yn(!0,!1)},r={get(s){return Wn(this,s,!0,!0)},get size(){return Gn(this,!0)},has(s){return Kn.call(this,s,!0)},add:xt("add"),set:xt("set"),delete:xt("delete"),clear:xt("clear"),forEach:Yn(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(s=>{e[s]=Jn(s,!1,!1),n[s]=Jn(s,!0,!1),t[s]=Jn(s,!1,!0),r[s]=Jn(s,!0,!0)}),[e,n,t,r]}const[Ma,Na,Da,Ha]=$a();function Co(e,t){const n=t?e?Ha:Da:e?Na:Ma;return(r,o,s)=>o==="__v_isReactive"?!e:o==="__v_isReadonly"?e:o==="__v_raw"?r:Reflect.get(fe(n,o)&&o in r?n:r,o,s)}const Ba={get:Co(!1,!1)},Fa={get:Co(!1,!0)},za={get:Co(!0,!1)},Si=new WeakMap,ki=new WeakMap,Oi=new WeakMap,ja=new WeakMap;function Va(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Ua(e){return e.__v_skip||!Object.isExtensible(e)?0:Va(oa(e))}function Fn(e){return an(e)?e:xo(e,!1,Pi,Ba,Si)}function Ai(e){return xo(e,!1,Ia,Fa,ki)}function zn(e){return xo(e,!0,Ra,za,Oi)}function xo(e,t,n,r,o){if(!we(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const s=o.get(e);if(s)return s;const i=Ua(e);if(i===0)return e;const l=new Proxy(e,i===2?r:n);return o.set(e,l),l}function on(e){return an(e)?on(e.__v_raw):!!(e&&e.__v_isReactive)}function an(e){return!!(e&&e.__v_isReadonly)}function cr(e){return!!(e&&e.__v_isShallow)}function Ri(e){return on(e)||an(e)}function de(e){const t=e&&e.__v_raw;return t?de(t):e}function Ii(e){return lr(e,"__v_skip",!0),e}const Rn=e=>we(e)?Fn(e):e,Lo=e=>we(e)?zn(e):e;function $i(e){At&&nt&&(e=de(e),xi(e.dep||(e.dep=bo())))}function Mi(e,t){e=de(e);const n=e.dep;n&&eo(n)}function Me(e){return!!(e&&e.__v_isRef===!0)}function Ce(e){return Ni(e,!1)}function To(e){return Ni(e,!0)}function Ni(e,t){return Me(e)?e:new qa(e,t)}class qa{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:de(t),this._value=n?t:Rn(t)}get value(){return $i(this),this._value}set value(t){const n=this.__v_isShallow||cr(t)||an(t);t=n?t:de(t),An(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:Rn(t),Mi(this))}}function Z(e){return Me(e)?e.value:e}const Wa={get:(e,t,n)=>Z(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return Me(o)&&!Me(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function Di(e){return on(e)?e:new Proxy(e,Wa)}function Po(e){const t=J(e)?new Array(e.length):{};for(const n in e)t[n]=Ga(e,n);return t}class Ka{constructor(t,n,r){this._object=t,this._key=n,this._defaultValue=r,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return ya(de(this._object),this._key)}}function Ga(e,t,n){const r=e[t];return Me(r)?r:new Ka(e,t,n)}class Ya{constructor(t,n,r,o){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new yo(t,()=>{this._dirty||(this._dirty=!0,Mi(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!o,this.__v_isReadonly=r}get value(){const t=de(this);return $i(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function Ja(e,t,n=!1){let r,o;const s=se(e);return s?(r=e,o=ot):(r=e.get,o=e.set),new Ya(r,o,s||!o,n)}function Rt(e,t,n,r){let o;try{o=r?e(...r):e()}catch(s){jn(s,t,n)}return o}function Ze(e,t,n,r){if(se(e)){const s=Rt(e,t,n,r);return s&&mi(s)&&s.catch(i=>{jn(i,t,n)}),s}const o=[];for(let s=0;s>>1;$n(Fe[r])ct&&Fe.splice(t,1)}function ec(e){J(e)?sn.push(...e):(!mt||!mt.includes(e,e.allowRecurse?zt+1:zt))&&sn.push(e),Bi()}function os(e,t=In?ct+1:0){for(;t$n(n)-$n(r)),zt=0;zte.id==null?1/0:e.id,tc=(e,t)=>{const n=$n(e)-$n(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Fi(e){to=!1,In=!0,Fe.sort(tc);const t=ot;try{for(ct=0;ctpe(g)?g.trim():g)),f&&(o=n.map(la))}let l,a=r[l=Nr(t)]||r[l=Nr(ft(t))];!a&&s&&(a=r[l=Nr(Yt(t))]),a&&Ze(a,e,6,o);const c=r[l+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[l])return;e.emitted[l]=!0,Ze(c,e,6,o)}}function zi(e,t,n=!1){const r=t.emitsCache,o=r.get(e);if(o!==void 0)return o;const s=e.emits;let i={},l=!1;if(!se(e)){const a=c=>{const u=zi(c,t,!0);u&&(l=!0,Oe(i,u))};!n&&t.mixins.length&&t.mixins.forEach(a),e.extends&&a(e.extends),e.mixins&&e.mixins.forEach(a)}return!s&&!l?(we(e)&&r.set(e,null),null):(J(s)?s.forEach(a=>i[a]=null):Oe(i,s),we(e)&&r.set(e,i),i)}function Pr(e,t){return!e||!Hn(t)?!1:(t=t.slice(2).replace(/Once$/,""),fe(e,t[0].toLowerCase()+t.slice(1))||fe(e,Yt(t))||fe(e,t))}let De=null,ji=null;function fr(e){const t=De;return De=e,ji=e&&e.type.__scopeId||null,t}function $e(e,t=De,n){if(!t||e._n)return e;const r=(...o)=>{r._d&&gs(-1);const s=fr(t);let i;try{i=e(...o)}finally{fr(s),r._d&&gs(1)}return i};return r._n=!0,r._c=!0,r._d=!0,r}function Hr(e){const{type:t,vnode:n,proxy:r,withProxy:o,props:s,propsOptions:[i],slots:l,attrs:a,emit:c,render:u,renderCache:f,data:h,setupState:g,ctx:y,inheritAttrs:w}=e;let T,v;const b=fr(e);try{if(n.shapeFlag&4){const k=o||r;T=tt(u.call(k,k,f,s,g,h,y)),v=a}else{const k=t;T=tt(k.length>1?k(s,{attrs:a,slots:l,emit:c}):k(s,null)),v=t.props?a:rc(a)}}catch(k){Sn.length=0,jn(k,e,1),T=ee(Ye)}let O=T;if(v&&w!==!1){const k=Object.keys(v),{shapeFlag:q}=O;k.length&&q&7&&(i&&k.some(mo)&&(v=oc(v,i)),O=Mt(O,v))}return n.dirs&&(O=Mt(O),O.dirs=O.dirs?O.dirs.concat(n.dirs):n.dirs),n.transition&&(O.transition=n.transition),T=O,fr(b),T}const rc=e=>{let t;for(const n in e)(n==="class"||n==="style"||Hn(n))&&((t||(t={}))[n]=e[n]);return t},oc=(e,t)=>{const n={};for(const r in e)(!mo(r)||!(r.slice(9)in t))&&(n[r]=e[r]);return n};function sc(e,t,n){const{props:r,children:o,component:s}=e,{props:i,children:l,patchFlag:a}=t,c=s.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&a>=0){if(a&1024)return!0;if(a&16)return r?ss(r,i,c):!!i;if(a&8){const u=t.dynamicProps;for(let f=0;fe.__isSuspense;function Vi(e,t){t&&t.pendingBranch?J(e)?t.effects.push(...e):t.effects.push(e):ec(e)}function Ui(e,t){return ko(e,null,t)}const Qn={};function ut(e,t,n){return ko(e,t,n)}function ko(e,t,{immediate:n,deep:r,flush:o,onTrack:s,onTrigger:i}=Ee){var l;const a=yi()===((l=Ae)==null?void 0:l.scope)?Ae:null;let c,u=!1,f=!1;if(Me(e)?(c=()=>e.value,u=cr(e)):on(e)?(c=()=>e,r=!0):J(e)?(f=!0,u=e.some(k=>on(k)||cr(k)),c=()=>e.map(k=>{if(Me(k))return k.value;if(on(k))return Ut(k);if(se(k))return Rt(k,a,2)})):se(e)?t?c=()=>Rt(e,a,2):c=()=>{if(!(a&&a.isUnmounted))return h&&h(),Ze(e,a,3,[g])}:c=ot,t&&r){const k=c;c=()=>Ut(k())}let h,g=k=>{h=b.onStop=()=>{Rt(k,a,4)}},y;if(fn)if(g=ot,t?n&&Ze(t,a,3,[c(),f?[]:void 0,g]):c(),o==="sync"){const k=nu();y=k.__watcherHandles||(k.__watcherHandles=[])}else return ot;let w=f?new Array(e.length).fill(Qn):Qn;const T=()=>{if(b.active)if(t){const k=b.run();(r||u||(f?k.some((q,X)=>An(q,w[X])):An(k,w)))&&(h&&h(),Ze(t,a,3,[k,w===Qn?void 0:f&&w[0]===Qn?[]:w,g]),w=k)}else b.run()};T.allowRecurse=!!t;let v;o==="sync"?v=T:o==="post"?v=()=>Ue(T,a&&a.suspense):(T.pre=!0,a&&(T.id=a.uid),v=()=>Tr(T));const b=new yo(c,v);t?n?T():w=b.run():o==="post"?Ue(b.run.bind(b),a&&a.suspense):b.run();const O=()=>{b.stop(),a&&a.scope&&go(a.scope.effects,b)};return y&&y.push(O),O}function ac(e,t,n){const r=this.proxy,o=pe(e)?e.includes(".")?qi(r,e):()=>r[e]:e.bind(r,r);let s;se(t)?s=t:(s=t.handler,n=t);const i=Ae;un(this);const l=ko(o,s.bind(r),n);return i?un(i):Kt(),l}function qi(e,t){const n=t.split(".");return()=>{let r=e;for(let o=0;o{Ut(n,t)});else if(vi(e))for(const n in e)Ut(e[n],t);return e}function dr(e,t){const n=De;if(n===null)return e;const r=Rr(n)||n.proxy,o=e.dirs||(e.dirs=[]);for(let s=0;s{e.isMounted=!0}),kr(()=>{e.isUnmounting=!0}),e}const Je=[Function,Array],Wi={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Je,onEnter:Je,onAfterEnter:Je,onEnterCancelled:Je,onBeforeLeave:Je,onLeave:Je,onAfterLeave:Je,onLeaveCancelled:Je,onBeforeAppear:Je,onAppear:Je,onAfterAppear:Je,onAppearCancelled:Je},uc={name:"BaseTransition",props:Wi,setup(e,{slots:t}){const n=al(),r=cc();let o;return()=>{const s=t.default&&Gi(t.default(),!0);if(!s||!s.length)return;let i=s[0];if(s.length>1){for(const w of s)if(w.type!==Ye){i=w;break}}const l=de(e),{mode:a}=l;if(r.isLeaving)return Br(i);const c=is(i);if(!c)return Br(i);const u=no(c,l,r,n);ro(c,u);const f=n.subTree,h=f&&is(f);let g=!1;const{getTransitionKey:y}=c.type;if(y){const w=y();o===void 0?o=w:w!==o&&(o=w,g=!0)}if(h&&h.type!==Ye&&(!jt(c,h)||g)){const w=no(h,l,r,n);if(ro(h,w),a==="out-in")return r.isLeaving=!0,w.afterLeave=()=>{r.isLeaving=!1,n.update.active!==!1&&n.update()},Br(i);a==="in-out"&&c.type!==Ye&&(w.delayLeave=(T,v,b)=>{const O=Ki(r,h);O[String(h.key)]=h,T._leaveCb=()=>{v(),T._leaveCb=void 0,delete u.delayedLeave},u.delayedLeave=b})}return i}}},fc=uc;function Ki(e,t){const{leavingVNodes:n}=e;let r=n.get(t.type);return r||(r=Object.create(null),n.set(t.type,r)),r}function no(e,t,n,r){const{appear:o,mode:s,persisted:i=!1,onBeforeEnter:l,onEnter:a,onAfterEnter:c,onEnterCancelled:u,onBeforeLeave:f,onLeave:h,onAfterLeave:g,onLeaveCancelled:y,onBeforeAppear:w,onAppear:T,onAfterAppear:v,onAppearCancelled:b}=t,O=String(e.key),k=Ki(n,e),q=(m,z)=>{m&&Ze(m,r,9,z)},X=(m,z)=>{const D=z[1];q(m,z),J(m)?m.every(K=>K.length<=1)&&D():m.length<=1&&D()},N={mode:s,persisted:i,beforeEnter(m){let z=l;if(!n.isMounted)if(o)z=w||l;else return;m._leaveCb&&m._leaveCb(!0);const D=k[O];D&&jt(e,D)&&D.el._leaveCb&&D.el._leaveCb(),q(z,[m])},enter(m){let z=a,D=c,K=u;if(!n.isMounted)if(o)z=T||a,D=v||c,K=b||u;else return;let L=!1;const R=m._enterCb=I=>{L||(L=!0,I?q(K,[m]):q(D,[m]),N.delayedLeave&&N.delayedLeave(),m._enterCb=void 0)};z?X(z,[m,R]):R()},leave(m,z){const D=String(e.key);if(m._enterCb&&m._enterCb(!0),n.isUnmounting)return z();q(f,[m]);let K=!1;const L=m._leaveCb=R=>{K||(K=!0,z(),R?q(y,[m]):q(g,[m]),m._leaveCb=void 0,k[D]===e&&delete k[D])};k[D]=e,h?X(h,[m,L]):L()},clone(m){return no(m,t,n,r)}};return N}function Br(e){if(Vn(e))return e=Mt(e),e.children=null,e}function is(e){return Vn(e)?e.children?e.children[0]:void 0:e}function ro(e,t){e.shapeFlag&6&&e.component?ro(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Gi(e,t=!1,n){let r=[],o=0;for(let s=0;s1)for(let s=0;sOe({name:e.name},t,{setup:e}))():e}const ln=e=>!!e.type.__asyncLoader;function Se(e){se(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:r,delay:o=200,timeout:s,suspensible:i=!0,onError:l}=e;let a=null,c,u=0;const f=()=>(u++,a=null,h()),h=()=>{let g;return a||(g=a=t().catch(y=>{if(y=y instanceof Error?y:new Error(String(y)),l)return new Promise((w,T)=>{l(y,()=>w(f()),()=>T(y),u+1)});throw y}).then(y=>g!==a&&a?a:(y&&(y.__esModule||y[Symbol.toStringTag]==="Module")&&(y=y.default),c=y,y)))};return he({name:"AsyncComponentWrapper",__asyncLoader:h,get __asyncResolved(){return c},setup(){const g=Ae;if(c)return()=>Fr(c,g);const y=b=>{a=null,jn(b,g,13,!r)};if(i&&g.suspense||fn)return h().then(b=>()=>Fr(b,g)).catch(b=>(y(b),()=>r?ee(r,{error:b}):null));const w=Ce(!1),T=Ce(),v=Ce(!!o);return o&&setTimeout(()=>{v.value=!1},o),s!=null&&setTimeout(()=>{if(!w.value&&!T.value){const b=new Error(`Async component timed out after ${s}ms.`);y(b),T.value=b}},s),h().then(()=>{w.value=!0,g.parent&&Vn(g.parent.vnode)&&Tr(g.parent.update)}).catch(b=>{y(b),T.value=b}),()=>{if(w.value&&c)return Fr(c,g);if(T.value&&r)return ee(r,{error:T.value});if(n&&!v.value)return ee(n)}}})}function Fr(e,t){const{ref:n,props:r,children:o,ce:s}=t.vnode,i=ee(e,r,o);return i.ref=n,i.ce=s,delete t.vnode.ce,i}const Vn=e=>e.type.__isKeepAlive;function dc(e,t){Yi(e,"a",t)}function hc(e,t){Yi(e,"da",t)}function Yi(e,t,n=Ae){const r=e.__wdc||(e.__wdc=()=>{let o=n;for(;o;){if(o.isDeactivated)return;o=o.parent}return e()});if(Sr(t,r,n),n){let o=n.parent;for(;o&&o.parent;)Vn(o.parent.vnode)&&pc(r,t,n,o),o=o.parent}}function pc(e,t,n,r){const o=Sr(t,e,r,!0);Or(()=>{go(r[t],o)},n)}function Sr(e,t,n=Ae,r=!1){if(n){const o=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...i)=>{if(n.isUnmounted)return;mn(),un(n);const l=Ze(t,n,e,i);return Kt(),gn(),l});return r?o.unshift(s):o.push(s),s}}const Et=e=>(t,n=Ae)=>(!fn||e==="sp")&&Sr(e,(...r)=>t(...r),n),mc=Et("bm"),Xe=Et("m"),gc=Et("bu"),vc=Et("u"),kr=Et("bum"),Or=Et("um"),_c=Et("sp"),bc=Et("rtg"),yc=Et("rtc");function Ec(e,t=Ae){Sr("ec",e,t)}const Ji="components";function bt(e,t){return Cc(Ji,e,!0,t)||e}const wc=Symbol.for("v-ndc");function Cc(e,t,n=!0,r=!1){const o=De||Ae;if(o){const s=o.type;if(e===Ji){const l=Xc(s,!1);if(l&&(l===t||l===ft(t)||l===Cr(ft(t))))return s}const i=ls(o[e]||s[e],t)||ls(o.appContext[e],t);return!i&&r?s:i}}function ls(e,t){return e&&(e[t]||e[ft(t)]||e[Cr(ft(t))])}function $t(e,t,n,r){let o;const s=n&&n[r];if(J(e)||pe(e)){o=new Array(e.length);for(let i=0,l=e.length;it(i,l,void 0,s&&s[l]));else{const i=Object.keys(e);o=new Array(i.length);for(let l=0,a=i.length;lgr(t)?!(t.type===Ye||t.type===ye&&!Qi(t.children)):!0)?e:null}const oo=e=>e?cl(e)?Rr(e)||e.proxy:oo(e.parent):null,Tn=Oe(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>oo(e.parent),$root:e=>oo(e.root),$emit:e=>e.emit,$options:e=>Oo(e),$forceUpdate:e=>e.f||(e.f=()=>Tr(e.update)),$nextTick:e=>e.n||(e.n=Lr.bind(e.proxy)),$watch:e=>ac.bind(e)}),zr=(e,t)=>e!==Ee&&!e.__isScriptSetup&&fe(e,t),xc={get({_:e},t){const{ctx:n,setupState:r,data:o,props:s,accessCache:i,type:l,appContext:a}=e;let c;if(t[0]!=="$"){const g=i[t];if(g!==void 0)switch(g){case 1:return r[t];case 2:return o[t];case 4:return n[t];case 3:return s[t]}else{if(zr(r,t))return i[t]=1,r[t];if(o!==Ee&&fe(o,t))return i[t]=2,o[t];if((c=e.propsOptions[0])&&fe(c,t))return i[t]=3,s[t];if(n!==Ee&&fe(n,t))return i[t]=4,n[t];so&&(i[t]=0)}}const u=Tn[t];let f,h;if(u)return t==="$attrs"&&We(e,"get",t),u(e);if((f=l.__cssModules)&&(f=f[t]))return f;if(n!==Ee&&fe(n,t))return i[t]=4,n[t];if(h=a.config.globalProperties,fe(h,t))return h[t]},set({_:e},t,n){const{data:r,setupState:o,ctx:s}=e;return zr(o,t)?(o[t]=n,!0):r!==Ee&&fe(r,t)?(r[t]=n,!0):fe(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:s}},i){let l;return!!n[i]||e!==Ee&&fe(e,i)||zr(t,i)||(l=s[0])&&fe(l,i)||fe(r,i)||fe(Tn,i)||fe(o.config.globalProperties,i)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:fe(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function as(e){return J(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}let so=!0;function Lc(e){const t=Oo(e),n=e.proxy,r=e.ctx;so=!1,t.beforeCreate&&cs(t.beforeCreate,e,"bc");const{data:o,computed:s,methods:i,watch:l,provide:a,inject:c,created:u,beforeMount:f,mounted:h,beforeUpdate:g,updated:y,activated:w,deactivated:T,beforeDestroy:v,beforeUnmount:b,destroyed:O,unmounted:k,render:q,renderTracked:X,renderTriggered:N,errorCaptured:m,serverPrefetch:z,expose:D,inheritAttrs:K,components:L,directives:R,filters:I}=t;if(c&&Tc(c,r,null),i)for(const ne in i){const re=i[ne];se(re)&&(r[ne]=re.bind(n))}if(o){const ne=o.call(n,n);we(ne)&&(e.data=Fn(ne))}if(so=!0,s)for(const ne in s){const re=s[ne],He=se(re)?re.bind(n,n):se(re.get)?re.get.bind(n,n):ot,Ne=!se(re)&&se(re.set)?re.set.bind(n):ot,Ve=j({get:He,set:Ne});Object.defineProperty(r,ne,{enumerable:!0,configurable:!0,get:()=>Ve.value,set:Be=>Ve.value=Be})}if(l)for(const ne in l)Zi(l[ne],r,n,ne);if(a){const ne=se(a)?a.call(n):a;Reflect.ownKeys(ne).forEach(re=>{Wt(re,ne[re])})}u&&cs(u,e,"c");function V(ne,re){J(re)?re.forEach(He=>ne(He.bind(n))):re&&ne(re.bind(n))}if(V(mc,f),V(Xe,h),V(gc,g),V(vc,y),V(dc,w),V(hc,T),V(Ec,m),V(yc,X),V(bc,N),V(kr,b),V(Or,k),V(_c,z),J(D))if(D.length){const ne=e.exposed||(e.exposed={});D.forEach(re=>{Object.defineProperty(ne,re,{get:()=>n[re],set:He=>n[re]=He})})}else e.exposed||(e.exposed={});q&&e.render===ot&&(e.render=q),K!=null&&(e.inheritAttrs=K),L&&(e.components=L),R&&(e.directives=R)}function Tc(e,t,n=ot){J(e)&&(e=io(e));for(const r in e){const o=e[r];let s;we(o)?"default"in o?s=ke(o.from||r,o.default,!0):s=ke(o.from||r):s=ke(o),Me(s)?Object.defineProperty(t,r,{enumerable:!0,configurable:!0,get:()=>s.value,set:i=>s.value=i}):t[r]=s}}function cs(e,t,n){Ze(J(e)?e.map(r=>r.bind(t.proxy)):e.bind(t.proxy),t,n)}function Zi(e,t,n,r){const o=r.includes(".")?qi(n,r):()=>n[r];if(pe(e)){const s=t[e];se(s)&&ut(o,s)}else if(se(e))ut(o,e.bind(n));else if(we(e))if(J(e))e.forEach(s=>Zi(s,t,n,r));else{const s=se(e.handler)?e.handler.bind(n):t[e.handler];se(s)&&ut(o,s,e)}}function Oo(e){const t=e.type,{mixins:n,extends:r}=t,{mixins:o,optionsCache:s,config:{optionMergeStrategies:i}}=e.appContext,l=s.get(t);let a;return l?a=l:!o.length&&!n&&!r?a=t:(a={},o.length&&o.forEach(c=>hr(a,c,i,!0)),hr(a,t,i)),we(t)&&s.set(t,a),a}function hr(e,t,n,r=!1){const{mixins:o,extends:s}=t;s&&hr(e,s,n,!0),o&&o.forEach(i=>hr(e,i,n,!0));for(const i in t)if(!(r&&i==="expose")){const l=Pc[i]||n&&n[i];e[i]=l?l(e[i],t[i]):t[i]}return e}const Pc={data:us,props:fs,emits:fs,methods:xn,computed:xn,beforeCreate:ze,created:ze,beforeMount:ze,mounted:ze,beforeUpdate:ze,updated:ze,beforeDestroy:ze,beforeUnmount:ze,destroyed:ze,unmounted:ze,activated:ze,deactivated:ze,errorCaptured:ze,serverPrefetch:ze,components:xn,directives:xn,watch:kc,provide:us,inject:Sc};function us(e,t){return t?e?function(){return Oe(se(e)?e.call(this,this):e,se(t)?t.call(this,this):t)}:t:e}function Sc(e,t){return xn(io(e),io(t))}function io(e){if(J(e)){const t={};for(let n=0;n1)return n&&se(t)?t.call(r&&r.proxy):t}}function Rc(e,t,n,r=!1){const o={},s={};lr(s,Ar,1),e.propsDefaults=Object.create(null),el(e,t,o,s);for(const i in e.propsOptions[0])i in o||(o[i]=void 0);n?e.props=r?o:Ai(o):e.type.props?e.props=o:e.props=s,e.attrs=s}function Ic(e,t,n,r){const{props:o,attrs:s,vnode:{patchFlag:i}}=e,l=de(o),[a]=e.propsOptions;let c=!1;if((r||i>0)&&!(i&16)){if(i&8){const u=e.vnode.dynamicProps;for(let f=0;f{a=!0;const[h,g]=tl(f,t,!0);Oe(i,h),g&&l.push(...g)};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}if(!s&&!a)return we(e)&&r.set(e,nn),nn;if(J(s))for(let u=0;u-1,g[1]=w<0||y-1||fe(g,"default"))&&l.push(f)}}}const c=[i,l];return we(e)&&r.set(e,c),c}function ds(e){return e[0]!=="$"}function hs(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function ps(e,t){return hs(e)===hs(t)}function ms(e,t){return J(t)?t.findIndex(n=>ps(n,e)):se(t)&&ps(t,e)?0:-1}const nl=e=>e[0]==="_"||e==="$stable",Ao=e=>J(e)?e.map(tt):[tt(e)],$c=(e,t,n)=>{if(t._n)return t;const r=$e((...o)=>Ao(t(...o)),n);return r._c=!1,r},rl=(e,t,n)=>{const r=e._ctx;for(const o in e){if(nl(o))continue;const s=e[o];if(se(s))t[o]=$c(o,s,r);else if(s!=null){const i=Ao(s);t[o]=()=>i}}},ol=(e,t)=>{const n=Ao(t);e.slots.default=()=>n},Mc=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=de(t),lr(t,"_",n)):rl(t,e.slots={})}else e.slots={},t&&ol(e,t);lr(e.slots,Ar,1)},Nc=(e,t,n)=>{const{vnode:r,slots:o}=e;let s=!0,i=Ee;if(r.shapeFlag&32){const l=t._;l?n&&l===1?s=!1:(Oe(o,t),!n&&l===1&&delete o._):(s=!t.$stable,rl(t,o)),i=t}else t&&(ol(e,t),i={default:1});if(s)for(const l in o)!nl(l)&&!(l in i)&&delete o[l]};function mr(e,t,n,r,o=!1){if(J(e)){e.forEach((h,g)=>mr(h,t&&(J(t)?t[g]:t),n,r,o));return}if(ln(r)&&!o)return;const s=r.shapeFlag&4?Rr(r.component)||r.component.proxy:r.el,i=o?null:s,{i:l,r:a}=e,c=t&&t.r,u=l.refs===Ee?l.refs={}:l.refs,f=l.setupState;if(c!=null&&c!==a&&(pe(c)?(u[c]=null,fe(f,c)&&(f[c]=null)):Me(c)&&(c.value=null)),se(a))Rt(a,l,12,[i,u]);else{const h=pe(a),g=Me(a);if(h||g){const y=()=>{if(e.f){const w=h?fe(f,a)?f[a]:u[a]:a.value;o?J(w)&&go(w,s):J(w)?w.includes(s)||w.push(s):h?(u[a]=[s],fe(f,a)&&(f[a]=u[a])):(a.value=[s],e.k&&(u[e.k]=a.value))}else h?(u[a]=i,fe(f,a)&&(f[a]=i)):g&&(a.value=i,e.k&&(u[e.k]=i))};i?(y.id=-1,Ue(y,n)):y()}}}let Lt=!1;const Zn=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",Xn=e=>e.nodeType===8;function Dc(e){const{mt:t,p:n,o:{patchProp:r,createText:o,nextSibling:s,parentNode:i,remove:l,insert:a,createComment:c}}=e,u=(v,b)=>{if(!b.hasChildNodes()){n(null,v,b),ur(),b._vnode=v;return}Lt=!1,f(b.firstChild,v,null,null,null),ur(),b._vnode=v,Lt&&console.error("Hydration completed but contains mismatches.")},f=(v,b,O,k,q,X=!1)=>{const N=Xn(v)&&v.data==="[",m=()=>w(v,b,O,k,q,N),{type:z,ref:D,shapeFlag:K,patchFlag:L}=b;let R=v.nodeType;b.el=v,L===-2&&(X=!1,b.dynamicChildren=null);let I=null;switch(z){case cn:R!==3?b.children===""?(a(b.el=o(""),i(v),v),I=v):I=m():(v.data!==b.children&&(Lt=!0,v.data=b.children),I=s(v));break;case Ye:R!==8||N?I=m():I=s(v);break;case Pn:if(N&&(v=s(v),R=v.nodeType),R===1||R===3){I=v;const le=!b.children.length;for(let V=0;V{X=X||!!b.dynamicChildren;const{type:N,props:m,patchFlag:z,shapeFlag:D,dirs:K}=b,L=N==="input"&&K||N==="option";if(L||z!==-1){if(K&&at(b,null,O,"created"),m)if(L||!X||z&48)for(const I in m)(L&&I.endsWith("value")||Hn(I)&&!Ln(I))&&r(v,I,null,m[I],!1,void 0,O);else m.onClick&&r(v,"onClick",null,m.onClick,!1,void 0,O);let R;if((R=m&&m.onVnodeBeforeMount)&&Qe(R,O,b),K&&at(b,null,O,"beforeMount"),((R=m&&m.onVnodeMounted)||K)&&Vi(()=>{R&&Qe(R,O,b),K&&at(b,null,O,"mounted")},k),D&16&&!(m&&(m.innerHTML||m.textContent))){let I=g(v.firstChild,b,v,O,k,q,X);for(;I;){Lt=!0;const le=I;I=I.nextSibling,l(le)}}else D&8&&v.textContent!==b.children&&(Lt=!0,v.textContent=b.children)}return v.nextSibling},g=(v,b,O,k,q,X,N)=>{N=N||!!b.dynamicChildren;const m=b.children,z=m.length;for(let D=0;D{const{slotScopeIds:N}=b;N&&(q=q?q.concat(N):N);const m=i(v),z=g(s(v),b,m,O,k,q,X);return z&&Xn(z)&&z.data==="]"?s(b.anchor=z):(Lt=!0,a(b.anchor=c("]"),m,z),z)},w=(v,b,O,k,q,X)=>{if(Lt=!0,b.el=null,X){const z=T(v);for(;;){const D=s(v);if(D&&D!==z)l(D);else break}}const N=s(v),m=i(v);return l(v),n(null,b,m,N,O,k,Zn(m),q),N},T=v=>{let b=0;for(;v;)if(v=s(v),v&&Xn(v)&&(v.data==="["&&b++,v.data==="]")){if(b===0)return s(v);b--}return v};return[u,f]}const Ue=Vi;function Hc(e){return Bc(e,Dc)}function Bc(e,t){const n=Qr();n.__VUE__=!0;const{insert:r,remove:o,patchProp:s,createElement:i,createText:l,createComment:a,setText:c,setElementText:u,parentNode:f,nextSibling:h,setScopeId:g=ot,insertStaticContent:y}=e,w=(d,p,_,E=null,x=null,P=null,H=!1,A=null,M=!!p.dynamicChildren)=>{if(d===p)return;d&&!jt(d,p)&&(E=C(d),Be(d,x,P,!0),d=null),p.patchFlag===-2&&(M=!1,p.dynamicChildren=null);const{type:S,ref:G,shapeFlag:U}=p;switch(S){case cn:T(d,p,_,E);break;case Ye:v(d,p,_,E);break;case Pn:d==null&&b(p,_,E,H);break;case ye:L(d,p,_,E,x,P,H,A,M);break;default:U&1?q(d,p,_,E,x,P,H,A,M):U&6?R(d,p,_,E,x,P,H,A,M):(U&64||U&128)&&S.process(d,p,_,E,x,P,H,A,M,$)}G!=null&&x&&mr(G,d&&d.ref,P,p||d,!p)},T=(d,p,_,E)=>{if(d==null)r(p.el=l(p.children),_,E);else{const x=p.el=d.el;p.children!==d.children&&c(x,p.children)}},v=(d,p,_,E)=>{d==null?r(p.el=a(p.children||""),_,E):p.el=d.el},b=(d,p,_,E)=>{[d.el,d.anchor]=y(d.children,p,_,E,d.el,d.anchor)},O=({el:d,anchor:p},_,E)=>{let x;for(;d&&d!==p;)x=h(d),r(d,_,E),d=x;r(p,_,E)},k=({el:d,anchor:p})=>{let _;for(;d&&d!==p;)_=h(d),o(d),d=_;o(p)},q=(d,p,_,E,x,P,H,A,M)=>{H=H||p.type==="svg",d==null?X(p,_,E,x,P,H,A,M):z(d,p,x,P,H,A,M)},X=(d,p,_,E,x,P,H,A)=>{let M,S;const{type:G,props:U,shapeFlag:Y,transition:te,dirs:ae}=d;if(M=d.el=i(d.type,P,U&&U.is,U),Y&8?u(M,d.children):Y&16&&m(d.children,M,null,E,x,P&&G!=="foreignObject",H,A),ae&&at(d,null,E,"created"),N(M,d,d.scopeId,H,E),U){for(const ge in U)ge!=="value"&&!Ln(ge)&&s(M,ge,null,U[ge],P,d.children,E,x,Ie);"value"in U&&s(M,"value",null,U.value),(S=U.onVnodeBeforeMount)&&Qe(S,E,d)}ae&&at(d,null,E,"beforeMount");const _e=(!x||x&&!x.pendingBranch)&&te&&!te.persisted;_e&&te.beforeEnter(M),r(M,p,_),((S=U&&U.onVnodeMounted)||_e||ae)&&Ue(()=>{S&&Qe(S,E,d),_e&&te.enter(M),ae&&at(d,null,E,"mounted")},x)},N=(d,p,_,E,x)=>{if(_&&g(d,_),E)for(let P=0;P{for(let S=M;S{const A=p.el=d.el;let{patchFlag:M,dynamicChildren:S,dirs:G}=p;M|=d.patchFlag&16;const U=d.props||Ee,Y=p.props||Ee;let te;_&&Dt(_,!1),(te=Y.onVnodeBeforeUpdate)&&Qe(te,_,p,d),G&&at(p,d,_,"beforeUpdate"),_&&Dt(_,!0);const ae=x&&p.type!=="foreignObject";if(S?D(d.dynamicChildren,S,A,_,E,ae,P):H||re(d,p,A,null,_,E,ae,P,!1),M>0){if(M&16)K(A,p,U,Y,_,E,x);else if(M&2&&U.class!==Y.class&&s(A,"class",null,Y.class,x),M&4&&s(A,"style",U.style,Y.style,x),M&8){const _e=p.dynamicProps;for(let ge=0;ge<_e.length;ge++){const Pe=_e[ge],et=U[Pe],Qt=Y[Pe];(Qt!==et||Pe==="value")&&s(A,Pe,et,Qt,x,d.children,_,E,Ie)}}M&1&&d.children!==p.children&&u(A,p.children)}else!H&&S==null&&K(A,p,U,Y,_,E,x);((te=Y.onVnodeUpdated)||G)&&Ue(()=>{te&&Qe(te,_,p,d),G&&at(p,d,_,"updated")},E)},D=(d,p,_,E,x,P,H)=>{for(let A=0;A{if(_!==E){if(_!==Ee)for(const A in _)!Ln(A)&&!(A in E)&&s(d,A,_[A],null,H,p.children,x,P,Ie);for(const A in E){if(Ln(A))continue;const M=E[A],S=_[A];M!==S&&A!=="value"&&s(d,A,S,M,H,p.children,x,P,Ie)}"value"in E&&s(d,"value",_.value,E.value)}},L=(d,p,_,E,x,P,H,A,M)=>{const S=p.el=d?d.el:l(""),G=p.anchor=d?d.anchor:l("");let{patchFlag:U,dynamicChildren:Y,slotScopeIds:te}=p;te&&(A=A?A.concat(te):te),d==null?(r(S,_,E),r(G,_,E),m(p.children,_,G,x,P,H,A,M)):U>0&&U&64&&Y&&d.dynamicChildren?(D(d.dynamicChildren,Y,_,x,P,H,A),(p.key!=null||x&&p===x.subTree)&&sl(d,p,!0)):re(d,p,_,G,x,P,H,A,M)},R=(d,p,_,E,x,P,H,A,M)=>{p.slotScopeIds=A,d==null?p.shapeFlag&512?x.ctx.activate(p,_,E,H,M):I(p,_,E,x,P,H,M):le(d,p,M)},I=(d,p,_,E,x,P,H)=>{const A=d.component=Gc(d,E,x);if(Vn(d)&&(A.ctx.renderer=$),Yc(A),A.asyncDep){if(x&&x.registerDep(A,V),!d.el){const M=A.subTree=ee(Ye);v(null,M,p,_)}return}V(A,d,p,_,x,P,H)},le=(d,p,_)=>{const E=p.component=d.component;if(sc(d,p,_))if(E.asyncDep&&!E.asyncResolved){ne(E,p,_);return}else E.next=p,Xa(E.update),E.update();else p.el=d.el,E.vnode=p},V=(d,p,_,E,x,P,H)=>{const A=()=>{if(d.isMounted){let{next:G,bu:U,u:Y,parent:te,vnode:ae}=d,_e=G,ge;Dt(d,!1),G?(G.el=ae.el,ne(d,G,H)):G=ae,U&&Dr(U),(ge=G.props&&G.props.onVnodeBeforeUpdate)&&Qe(ge,te,G,ae),Dt(d,!0);const Pe=Hr(d),et=d.subTree;d.subTree=Pe,w(et,Pe,f(et.el),C(et),d,x,P),G.el=Pe.el,_e===null&&ic(d,Pe.el),Y&&Ue(Y,x),(ge=G.props&&G.props.onVnodeUpdated)&&Ue(()=>Qe(ge,te,G,ae),x)}else{let G;const{el:U,props:Y}=p,{bm:te,m:ae,parent:_e}=d,ge=ln(p);if(Dt(d,!1),te&&Dr(te),!ge&&(G=Y&&Y.onVnodeBeforeMount)&&Qe(G,_e,p),Dt(d,!0),U&&ce){const Pe=()=>{d.subTree=Hr(d),ce(U,d.subTree,d,x,null)};ge?p.type.__asyncLoader().then(()=>!d.isUnmounted&&Pe()):Pe()}else{const Pe=d.subTree=Hr(d);w(null,Pe,_,E,d,x,P),p.el=Pe.el}if(ae&&Ue(ae,x),!ge&&(G=Y&&Y.onVnodeMounted)){const Pe=p;Ue(()=>Qe(G,_e,Pe),x)}(p.shapeFlag&256||_e&&ln(_e.vnode)&&_e.vnode.shapeFlag&256)&&d.a&&Ue(d.a,x),d.isMounted=!0,p=_=E=null}},M=d.effect=new yo(A,()=>Tr(S),d.scope),S=d.update=()=>M.run();S.id=d.uid,Dt(d,!0),S()},ne=(d,p,_)=>{p.component=d;const E=d.vnode.props;d.vnode=p,d.next=null,Ic(d,p.props,E,_),Nc(d,p.children,_),mn(),os(),gn()},re=(d,p,_,E,x,P,H,A,M=!1)=>{const S=d&&d.children,G=d?d.shapeFlag:0,U=p.children,{patchFlag:Y,shapeFlag:te}=p;if(Y>0){if(Y&128){Ne(S,U,_,E,x,P,H,A,M);return}else if(Y&256){He(S,U,_,E,x,P,H,A,M);return}}te&8?(G&16&&Ie(S,x,P),U!==S&&u(_,U)):G&16?te&16?Ne(S,U,_,E,x,P,H,A,M):Ie(S,x,P,!0):(G&8&&u(_,""),te&16&&m(U,_,E,x,P,H,A,M))},He=(d,p,_,E,x,P,H,A,M)=>{d=d||nn,p=p||nn;const S=d.length,G=p.length,U=Math.min(S,G);let Y;for(Y=0;YG?Ie(d,x,P,!0,!1,U):m(p,_,E,x,P,H,A,M,U)},Ne=(d,p,_,E,x,P,H,A,M)=>{let S=0;const G=p.length;let U=d.length-1,Y=G-1;for(;S<=U&&S<=Y;){const te=d[S],ae=p[S]=M?St(p[S]):tt(p[S]);if(jt(te,ae))w(te,ae,_,null,x,P,H,A,M);else break;S++}for(;S<=U&&S<=Y;){const te=d[U],ae=p[Y]=M?St(p[Y]):tt(p[Y]);if(jt(te,ae))w(te,ae,_,null,x,P,H,A,M);else break;U--,Y--}if(S>U){if(S<=Y){const te=Y+1,ae=teY)for(;S<=U;)Be(d[S],x,P,!0),S++;else{const te=S,ae=S,_e=new Map;for(S=ae;S<=Y;S++){const Ke=p[S]=M?St(p[S]):tt(p[S]);Ke.key!=null&&_e.set(Ke.key,S)}let ge,Pe=0;const et=Y-ae+1;let Qt=!1,Wo=0;const _n=new Array(et);for(S=0;S=et){Be(Ke,x,P,!0);continue}let lt;if(Ke.key!=null)lt=_e.get(Ke.key);else for(ge=ae;ge<=Y;ge++)if(_n[ge-ae]===0&&jt(Ke,p[ge])){lt=ge;break}lt===void 0?Be(Ke,x,P,!0):(_n[lt-ae]=S+1,lt>=Wo?Wo=lt:Qt=!0,w(Ke,p[lt],_,null,x,P,H,A,M),Pe++)}const Ko=Qt?Fc(_n):nn;for(ge=Ko.length-1,S=et-1;S>=0;S--){const Ke=ae+S,lt=p[Ke],Go=Ke+1{const{el:P,type:H,transition:A,children:M,shapeFlag:S}=d;if(S&6){Ve(d.component.subTree,p,_,E);return}if(S&128){d.suspense.move(p,_,E);return}if(S&64){H.move(d,p,_,$);return}if(H===ye){r(P,p,_);for(let U=0;UA.enter(P),x);else{const{leave:U,delayLeave:Y,afterLeave:te}=A,ae=()=>r(P,p,_),_e=()=>{U(P,()=>{ae(),te&&te()})};Y?Y(P,ae,_e):_e()}else r(P,p,_)},Be=(d,p,_,E=!1,x=!1)=>{const{type:P,props:H,ref:A,children:M,dynamicChildren:S,shapeFlag:G,patchFlag:U,dirs:Y}=d;if(A!=null&&mr(A,null,_,d,!0),G&256){p.ctx.deactivate(d);return}const te=G&1&&Y,ae=!ln(d);let _e;if(ae&&(_e=H&&H.onVnodeBeforeUnmount)&&Qe(_e,p,d),G&6)it(d.component,_,E);else{if(G&128){d.suspense.unmount(_,E);return}te&&at(d,null,p,"beforeUnmount"),G&64?d.type.remove(d,p,_,x,$,E):S&&(P!==ye||U>0&&U&64)?Ie(S,p,_,!1,!0):(P===ye&&U&384||!x&&G&16)&&Ie(M,p,_),E&&wt(d)}(ae&&(_e=H&&H.onVnodeUnmounted)||te)&&Ue(()=>{_e&&Qe(_e,p,d),te&&at(d,null,p,"unmounted")},_)},wt=d=>{const{type:p,el:_,anchor:E,transition:x}=d;if(p===ye){Ct(_,E);return}if(p===Pn){k(d);return}const P=()=>{o(_),x&&!x.persisted&&x.afterLeave&&x.afterLeave()};if(d.shapeFlag&1&&x&&!x.persisted){const{leave:H,delayLeave:A}=x,M=()=>H(_,P);A?A(d.el,P,M):M()}else P()},Ct=(d,p)=>{let _;for(;d!==p;)_=h(d),o(d),d=_;o(p)},it=(d,p,_)=>{const{bum:E,scope:x,update:P,subTree:H,um:A}=d;E&&Dr(E),x.stop(),P&&(P.active=!1,Be(H,d,p,_)),A&&Ue(A,p),Ue(()=>{d.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&d.asyncDep&&!d.asyncResolved&&d.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},Ie=(d,p,_,E=!1,x=!1,P=0)=>{for(let H=P;Hd.shapeFlag&6?C(d.component.subTree):d.shapeFlag&128?d.suspense.next():h(d.anchor||d.el),F=(d,p,_)=>{d==null?p._vnode&&Be(p._vnode,null,null,!0):w(p._vnode||null,d,p,null,null,null,_),os(),ur(),p._vnode=d},$={p:w,um:Be,m:Ve,r:wt,mt:I,mc:m,pc:re,pbc:D,n:C,o:e};let W,ce;return t&&([W,ce]=t($)),{render:F,hydrate:W,createApp:Ac(F,W)}}function Dt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function sl(e,t,n=!1){const r=e.children,o=t.children;if(J(r)&&J(o))for(let s=0;s>1,e[n[l]]0&&(t[r]=n[s-1]),n[s]=r)}}for(s=n.length,i=n[s-1];s-- >0;)n[s]=i,i=t[i];return n}const zc=e=>e.__isTeleport,ye=Symbol.for("v-fgt"),cn=Symbol.for("v-txt"),Ye=Symbol.for("v-cmt"),Pn=Symbol.for("v-stc"),Sn=[];let rt=null;function B(e=!1){Sn.push(rt=e?null:[])}function jc(){Sn.pop(),rt=Sn[Sn.length-1]||null}let Mn=1;function gs(e){Mn+=e}function il(e){return e.dynamicChildren=Mn>0?rt||nn:null,jc(),Mn>0&&rt&&rt.push(e),e}function Q(e,t,n,r,o,s){return il(oe(e,t,n,r,o,s,!0))}function Le(e,t,n,r,o){return il(ee(e,t,n,r,o,!0))}function gr(e){return e?e.__v_isVNode===!0:!1}function jt(e,t){return e.type===t.type&&e.key===t.key}const Ar="__vInternal",ll=({key:e})=>e??null,sr=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?pe(e)||Me(e)||se(e)?{i:De,r:e,k:t,f:!!n}:e:null);function oe(e,t=null,n=null,r=0,o=null,s=e===ye?0:1,i=!1,l=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&ll(t),ref:t&&sr(t),scopeId:ji,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:s,patchFlag:r,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:De};return l?(Ro(a,n),s&128&&e.normalize(a)):n&&(a.shapeFlag|=pe(n)?8:16),Mn>0&&!i&&rt&&(a.patchFlag>0||s&6)&&a.patchFlag!==32&&rt.push(a),a}const ee=Vc;function Vc(e,t=null,n=null,r=0,o=null,s=!1){if((!e||e===wc)&&(e=Ye),gr(e)){const l=Mt(e,t,!0);return n&&Ro(l,n),Mn>0&&!s&&rt&&(l.shapeFlag&6?rt[rt.indexOf(e)]=l:rt.push(l)),l.patchFlag|=-2,l}if(eu(e)&&(e=e.__vccOpts),t){t=Uc(t);let{class:l,style:a}=t;l&&!pe(l)&&(t.class=qe(l)),we(a)&&(Ri(a)&&!J(a)&&(a=Oe({},a)),t.style=Bn(a))}const i=pe(e)?1:lc(e)?128:zc(e)?64:we(e)?4:se(e)?2:0;return oe(e,t,n,r,o,i,s,!0)}function Uc(e){return e?Ri(e)||Ar in e?Oe({},e):e:null}function Mt(e,t,n=!1){const{props:r,ref:o,patchFlag:s,children:i}=e,l=t?ao(r||{},t):r;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:l,key:l&&ll(l),ref:t&&t.ref?n&&o?J(o)?o.concat(sr(t)):[o,sr(t)]:sr(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:i,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ye?s===-1?16:s|16:s,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Mt(e.ssContent),ssFallback:e.ssFallback&&Mt(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function yt(e=" ",t=0){return ee(cn,null,e,t)}function qc(e,t){const n=ee(Pn,null,e);return n.staticCount=t,n}function Te(e="",t=!1){return t?(B(),Le(Ye,null,e)):ee(Ye,null,e)}function tt(e){return e==null||typeof e=="boolean"?ee(Ye):J(e)?ee(ye,null,e.slice()):typeof e=="object"?St(e):ee(cn,null,String(e))}function St(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Mt(e)}function Ro(e,t){let n=0;const{shapeFlag:r}=e;if(t==null)t=null;else if(J(t))n=16;else if(typeof t=="object")if(r&65){const o=t.default;o&&(o._c&&(o._d=!1),Ro(e,o()),o._c&&(o._d=!0));return}else{n=32;const o=t._;!o&&!(Ar in t)?t._ctx=De:o===3&&De&&(De.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else se(t)?(t={default:t,_ctx:De},n=32):(t=String(t),r&64?(n=16,t=[yt(t)]):n=8);e.children=t,e.shapeFlag|=n}function ao(...e){const t={};for(let n=0;nAe||De;let Io,Zt,vs="__VUE_INSTANCE_SETTERS__";(Zt=Qr()[vs])||(Zt=Qr()[vs]=[]),Zt.push(e=>Ae=e),Io=e=>{Zt.length>1?Zt.forEach(t=>t(e)):Zt[0](e)};const un=e=>{Io(e),e.scope.on()},Kt=()=>{Ae&&Ae.scope.off(),Io(null)};function cl(e){return e.vnode.shapeFlag&4}let fn=!1;function Yc(e,t=!1){fn=t;const{props:n,children:r}=e.vnode,o=cl(e);Rc(e,n,o,t),Mc(e,r);const s=o?Jc(e,t):void 0;return fn=!1,s}function Jc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Ii(new Proxy(e.ctx,xc));const{setup:r}=n;if(r){const o=e.setupContext=r.length>1?Zc(e):null;un(e),mn();const s=Rt(r,e,0,[e.props,o]);if(gn(),Kt(),mi(s)){if(s.then(Kt,Kt),t)return s.then(i=>{_s(e,i,t)}).catch(i=>{jn(i,e,0)});e.asyncDep=s}else _s(e,s,t)}else ul(e,t)}function _s(e,t,n){se(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:we(t)&&(e.setupState=Di(t)),ul(e,n)}let bs;function ul(e,t,n){const r=e.type;if(!e.render){if(!t&&bs&&!r.render){const o=r.template||Oo(e).template;if(o){const{isCustomElement:s,compilerOptions:i}=e.appContext.config,{delimiters:l,compilerOptions:a}=r,c=Oe(Oe({isCustomElement:s,delimiters:l},i),a);r.render=bs(o,c)}}e.render=r.render||ot}un(e),mn(),Lc(e),gn(),Kt()}function Qc(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return We(e,"get","$attrs"),t[n]}}))}function Zc(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Qc(e)},slots:e.slots,emit:e.emit,expose:t}}function Rr(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Di(Ii(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Tn)return Tn[n](e)},has(t,n){return n in t||n in Tn}}))}function Xc(e,t=!0){return se(e)?e.displayName||e.name:e.name||t&&e.__name}function eu(e){return se(e)&&"__vccOpts"in e}const j=(e,t)=>Ja(e,t,fn);function ve(e,t,n){const r=arguments.length;return r===2?we(t)&&!J(t)?gr(t)?ee(e,null,[t]):ee(e,t):ee(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):r===3&&gr(n)&&(n=[n]),ee(e,t,n))}const tu=Symbol.for("v-scx"),nu=()=>ke(tu),ru="3.3.4",ou="http://www.w3.org/2000/svg",Vt=typeof document<"u"?document:null,ys=Vt&&Vt.createElement("template"),su={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t?Vt.createElementNS(ou,e):Vt.createElement(e,n?{is:n}:void 0);return e==="select"&&r&&r.multiple!=null&&o.setAttribute("multiple",r.multiple),o},createText:e=>Vt.createTextNode(e),createComment:e=>Vt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Vt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,r,o,s){const i=n?n.previousSibling:t.lastChild;if(o&&(o===s||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===s||!(o=o.nextSibling)););else{ys.innerHTML=r?`${e}`:e;const l=ys.content;if(r){const a=l.firstChild;for(;a.firstChild;)l.appendChild(a.firstChild);l.removeChild(a)}t.insertBefore(l,n)}return[i?i.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function iu(e,t,n){const r=e._vtc;r&&(t=(t?[t,...r]:[...r]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function lu(e,t,n){const r=e.style,o=pe(n);if(n&&!o){if(t&&!pe(t))for(const s in t)n[s]==null&&co(r,s,"");for(const s in n)co(r,s,n[s])}else{const s=r.display;o?t!==n&&(r.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(r.display=s)}}const Es=/\s*!important$/;function co(e,t,n){if(J(n))n.forEach(r=>co(e,t,r));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const r=au(e,t);Es.test(n)?e.setProperty(Yt(r),n.replace(Es,""),"important"):e[r]=n}}const ws=["Webkit","Moz","ms"],jr={};function au(e,t){const n=jr[t];if(n)return n;let r=ft(t);if(r!=="filter"&&r in e)return jr[t]=r;r=Cr(r);for(let o=0;oVr||(mu.then(()=>Vr=0),Vr=Date.now());function vu(e,t){const n=r=>{if(!r._vts)r._vts=Date.now();else if(r._vts<=n.attached)return;Ze(_u(r,n.value),t,5,[r])};return n.value=e,n.attached=gu(),n}function _u(e,t){if(J(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(r=>o=>!o._stopped&&r&&r(o))}else return t}const Ls=/^on[a-z]/,bu=(e,t,n,r,o=!1,s,i,l,a)=>{t==="class"?iu(e,r,o):t==="style"?lu(e,n,r):Hn(t)?mo(t)||hu(e,t,n,r,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):yu(e,t,r,o))?uu(e,t,r,s,i,l,a):(t==="true-value"?e._trueValue=r:t==="false-value"&&(e._falseValue=r),cu(e,t,r,o))};function yu(e,t,n,r){return r?!!(t==="innerHTML"||t==="textContent"||t in e&&Ls.test(t)&&se(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Ls.test(t)&&pe(n)?!1:t in e}const Tt="transition",bn="animation",Un=(e,{slots:t})=>ve(fc,Eu(e),t);Un.displayName="Transition";const fl={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Un.props=Oe({},Wi,fl);const Ht=(e,t=[])=>{J(e)?e.forEach(n=>n(...t)):e&&e(...t)},Ts=e=>e?J(e)?e.some(t=>t.length>1):e.length>1:!1;function Eu(e){const t={};for(const L in e)L in fl||(t[L]=e[L]);if(e.css===!1)return t;const{name:n="v",type:r,duration:o,enterFromClass:s=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:a=s,appearActiveClass:c=i,appearToClass:u=l,leaveFromClass:f=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:g=`${n}-leave-to`}=e,y=wu(o),w=y&&y[0],T=y&&y[1],{onBeforeEnter:v,onEnter:b,onEnterCancelled:O,onLeave:k,onLeaveCancelled:q,onBeforeAppear:X=v,onAppear:N=b,onAppearCancelled:m=O}=t,z=(L,R,I)=>{Bt(L,R?u:l),Bt(L,R?c:i),I&&I()},D=(L,R)=>{L._isLeaving=!1,Bt(L,f),Bt(L,g),Bt(L,h),R&&R()},K=L=>(R,I)=>{const le=L?N:b,V=()=>z(R,L,I);Ht(le,[R,V]),Ps(()=>{Bt(R,L?a:s),Pt(R,L?u:l),Ts(le)||Ss(R,r,w,V)})};return Oe(t,{onBeforeEnter(L){Ht(v,[L]),Pt(L,s),Pt(L,i)},onBeforeAppear(L){Ht(X,[L]),Pt(L,a),Pt(L,c)},onEnter:K(!1),onAppear:K(!0),onLeave(L,R){L._isLeaving=!0;const I=()=>D(L,R);Pt(L,f),Lu(),Pt(L,h),Ps(()=>{L._isLeaving&&(Bt(L,f),Pt(L,g),Ts(k)||Ss(L,r,T,I))}),Ht(k,[L,I])},onEnterCancelled(L){z(L,!1),Ht(O,[L])},onAppearCancelled(L){z(L,!0),Ht(m,[L])},onLeaveCancelled(L){D(L),Ht(q,[L])}})}function wu(e){if(e==null)return null;if(we(e))return[Ur(e.enter),Ur(e.leave)];{const t=Ur(e);return[t,t]}}function Ur(e){return aa(e)}function Pt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function Bt(e,t){t.split(/\s+/).forEach(r=>r&&e.classList.remove(r));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function Ps(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Cu=0;function Ss(e,t,n,r){const o=e._endId=++Cu,s=()=>{o===e._endId&&r()};if(n)return setTimeout(s,n);const{type:i,timeout:l,propCount:a}=xu(e,t);if(!i)return r();const c=i+"end";let u=0;const f=()=>{e.removeEventListener(c,h),s()},h=g=>{g.target===e&&++u>=a&&f()};setTimeout(()=>{u(n[y]||"").split(", "),o=r(`${Tt}Delay`),s=r(`${Tt}Duration`),i=ks(o,s),l=r(`${bn}Delay`),a=r(`${bn}Duration`),c=ks(l,a);let u=null,f=0,h=0;t===Tt?i>0&&(u=Tt,f=i,h=s.length):t===bn?c>0&&(u=bn,f=c,h=a.length):(f=Math.max(i,c),u=f>0?i>c?Tt:bn:null,h=u?u===Tt?s.length:a.length:0);const g=u===Tt&&/\b(transform|all)(,|$)/.test(r(`${Tt}Property`).toString());return{type:u,timeout:f,propCount:h,hasTransform:g}}function ks(e,t){for(;e.lengthOs(n)+Os(e[r])))}function Os(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function Lu(){return document.body.offsetHeight}const Tu={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Pu=(e,t)=>n=>{if(!("key"in n))return;const r=Yt(n.key);if(t.some(o=>o===r||Tu[o]===r))return e(n)},vr={beforeMount(e,{value:t},{transition:n}){e._vod=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):yn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),yn(e,!0),r.enter(e)):r.leave(e,()=>{yn(e,!1)}):yn(e,t))},beforeUnmount(e,{value:t}){yn(e,t)}};function yn(e,t){e.style.display=t?e._vod:"none"}const Su=Oe({patchProp:bu},su);let qr,As=!1;function ku(){return qr=As?qr:Hc(Su),As=!0,qr}const Ou=(...e)=>{const t=ku().createApp(...e),{mount:n}=t;return t.mount=r=>{const o=Au(r);if(o)return n(o,!0,o instanceof SVGElement)},t};function Au(e){return pe(e)?document.querySelector(e):e}const Ru={"v-8daa1a0e":()=>ie(()=>import("./index.html-73be7817.js"),[]).then(({data:e})=>e),"v-5c4d59a8":()=>ie(()=>import("./chat.html-ea257c93.js"),[]).then(({data:e})=>e),"v-6ce48554":()=>ie(()=>import("./contributing.html-9be653e8.js"),[]).then(({data:e})=>e),"v-0100cb31":()=>ie(()=>import("./donate.html-b400e680.js"),[]).then(({data:e})=>e),"v-f2255364":()=>ie(()=>import("./gbcompo21.html-99aaee71.js"),[]).then(({data:e})=>e),"v-eb51f0e8":()=>ie(()=>import("./gbcompo23.html-a81692eb.js"),[]).then(({data:e})=>e),"v-45972830":()=>ie(()=>import("./meetings.html-51bd8c78.js"),[]).then(({data:e})=>e),"v-097038b2":()=>ie(()=>import("./newsletter.html-265eba04.js"),[]).then(({data:e})=>e),"v-6c436918":()=>ie(()=>import("./privacypolicy.html-c130ba76.js"),[]).then(({data:e})=>e),"v-68dc5d0d":()=>ie(()=>import("./resources.html-6f26efe6.js"),[]).then(({data:e})=>e),"v-81096038":()=>ie(()=>import("./asmstyle.html-f84bdcf1.js"),[]).then(({data:e})=>e),"v-2cfc1b4c":()=>ie(()=>import("./deadcscroll.html-cf90a12f.js"),[]).then(({data:e})=>e),"v-01eed7fd":()=>ie(()=>import("./dma_hijacking.html-3c0726e8.js"),[]).then(({data:e})=>e),"v-2db785a7":()=>ie(()=>import("./lyc_timing.html-7f10ac5d.js"),[]).then(({data:e})=>e),"v-28ddd31d":()=>ie(()=>import("./sgb_border.html-bc8bc6ba.js"),[]).then(({data:e})=>e),"v-3d89621d":()=>ie(()=>import("./tools.html-e21b5d86.js"),[]).then(({data:e})=>e),"v-5f5d6e7d":()=>ie(()=>import("./2023-11-04-sc.html-73e957ae.js"),[]).then(({data:e})=>e),"v-3066264a":()=>ie(()=>import("./2024-03-10-sc2.html-2f212aef.js"),[]).then(({data:e})=>e),"v-1c0cbf85":()=>ie(()=>import("./1.html-19f9b6b9.js"),[]).then(({data:e})=>e),"v-3706649a":()=>ie(()=>import("./404.html-60b35caa.js"),[]).then(({data:e})=>e)},Iu=JSON.parse(`{"base":"/","lang":"en-US","title":"gbdev.io","description":"game boy development scene","head":[["script",{},"\\n var _paq = window._paq = window._paq || [];\\n /* tracker methods like \\"setCustomDimension\\" should be called before \\"trackPageView\\" */\\n _paq.push(['trackPageView']);\\n _paq.push(['enableLinkTracking']);\\n (function() {\\n var u=\\"//stats.gbdev.io/\\";\\n _paq.push(['setTrackerUrl', u+'matomo.php']);\\n _paq.push(['setSiteId', '1']);\\n var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];\\n g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);\\n })();\\n "],["link",{"rel":"icon","type":"image/png","sizes":"32x32","href":"/favicons/favicon-32x32.png"}],["link",{"rel":"icon","type":"image/png","sizes":"16x16","href":"/favicons/favicon-16x16.png"}],["meta",{"property":"og:site_name","content":"gbdev.io"}],["meta",{"name":"twitter:card","content":"summary"}],["meta",{"name":"twitter:site","content":"@gbdev0"}],["meta",{"name":"og:image","content":"https://gbdev.io/images/gbinternals.png"}]],"locales":{}}`);var $u=([e,t,n])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,n]),Mu=e=>{const t=new Set,n=[];return e.forEach(r=>{const o=$u(r);t.has(o)||(t.add(o),n.push(r))}),n},qn=e=>/^(https?:)?\/\//.test(e),Nu=e=>/^mailto:/.test(e),Du=e=>/^tel:/.test(e),$o=e=>Object.prototype.toString.call(e)==="[object Object]",dl=e=>e[e.length-1]==="/"?e.slice(0,-1):e,hl=e=>e[0]==="/"?e.slice(1):e,pl=(e,t)=>{const n=Object.keys(e).sort((r,o)=>{const s=o.split("/").length-r.split("/").length;return s!==0?s:o.length-r.length});for(const r of n)if(t.startsWith(r))return r;return"/"};const ml={"v-8daa1a0e":Se(()=>ie(()=>import("./index.html-e90463f4.js"),[])),"v-5c4d59a8":Se(()=>ie(()=>import("./chat.html-435caf64.js"),[])),"v-6ce48554":Se(()=>ie(()=>import("./contributing.html-c7c45a02.js"),[])),"v-0100cb31":Se(()=>ie(()=>import("./donate.html-721556c4.js"),[])),"v-f2255364":Se(()=>ie(()=>import("./gbcompo21.html-30e84a39.js"),[])),"v-eb51f0e8":Se(()=>ie(()=>import("./gbcompo23.html-0396efa9.js"),[])),"v-45972830":Se(()=>ie(()=>import("./meetings.html-1272f640.js"),[])),"v-097038b2":Se(()=>ie(()=>import("./newsletter.html-579cb2e7.js"),[])),"v-6c436918":Se(()=>ie(()=>import("./privacypolicy.html-b74fe81b.js"),[])),"v-68dc5d0d":Se(()=>ie(()=>import("./resources.html-7fa92572.js"),[])),"v-81096038":Se(()=>ie(()=>import("./asmstyle.html-90ec72c6.js"),[])),"v-2cfc1b4c":Se(()=>ie(()=>import("./deadcscroll.html-fd3e6a11.js"),[])),"v-01eed7fd":Se(()=>ie(()=>import("./dma_hijacking.html-8813f285.js"),[])),"v-2db785a7":Se(()=>ie(()=>import("./lyc_timing.html-da2e2b9d.js"),[])),"v-28ddd31d":Se(()=>ie(()=>import("./sgb_border.html-41de5f86.js"),[])),"v-3d89621d":Se(()=>ie(()=>import("./tools.html-c48ffccf.js"),[])),"v-5f5d6e7d":Se(()=>ie(()=>import("./2023-11-04-sc.html-a4eac1f3.js"),[])),"v-3066264a":Se(()=>ie(()=>import("./2024-03-10-sc2.html-004e84d0.js"),[])),"v-1c0cbf85":Se(()=>ie(()=>import("./1.html-172d4022.js"),[])),"v-3706649a":Se(()=>ie(()=>import("./404.html-c2a57a37.js"),[]))};var Hu=Symbol(""),Bu=Ce(Ru),gl=zn({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),kt=Ce(gl),Gt=()=>kt,vl=Symbol(""),gt=()=>{const e=ke(vl);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},_l=Symbol(""),Fu=()=>{const e=ke(_l);if(!e)throw new Error("usePageHead() is called without provider.");return e},zu=Symbol(""),bl=Symbol(""),ju=()=>{const e=ke(bl);if(!e)throw new Error("usePageLang() is called without provider.");return e},yl=Symbol(""),Vu=()=>{const e=ke(yl);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Mo=Symbol(""),Ir=()=>{const e=ke(Mo);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},tn=Ce(Iu),El=()=>tn,wl=Symbol(""),No=()=>{const e=ke(wl);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Uu=Symbol(""),qu="Layout",Wu="NotFound",ht=Fn({resolveLayouts:e=>e.reduce((t,n)=>({...t,...n.layouts}),{}),resolvePageData:async e=>{const t=Bu.value[e];return await(t==null?void 0:t())??gl},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,n)=>{const r=pe(t.description)?t.description:n.description,o=[...J(t.head)?t.head:[],...n.head,["title",{},e],["meta",{name:"description",content:r}]];return Mu(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(n=>!!n).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let n;if(e.path){const r=e.frontmatter.layout;pe(r)?n=r:n=qu}else n=Wu;return t[n]},resolveRouteLocale:(e,t)=>pl(e,t),resolveSiteLocaleData:(e,t)=>({...e,...e.locales[t]})}),Do=he({name:"ClientOnly",setup(e,t){const n=Ce(!1);return Xe(()=>{n.value=!0}),()=>{var r,o;return n.value?(o=(r=t.slots).default)==null?void 0:o.call(r):null}}}),Ku=he({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Gt(),n=j(()=>ml[e.pageKey||t.value.key]);return()=>n.value?ve(n.value):ve("div","404 Not Found")}}),Nt=(e={})=>e,Ho=e=>qn(e)?e:`/${hl(e)}`;function Cl(e,t,n){var r,o,s;t===void 0&&(t=50),n===void 0&&(n={});var i=(r=n.isImmediate)!=null&&r,l=(o=n.callback)!=null&&o,a=n.maxWait,c=Date.now(),u=[];function f(){if(a!==void 0){var g=Date.now()-c;if(g+t>=a)return a-g}return t}var h=function(){var g=[].slice.call(arguments),y=this;return new Promise(function(w,T){var v=i&&s===void 0;if(s!==void 0&&clearTimeout(s),s=setTimeout(function(){if(s=void 0,c=Date.now(),!i){var O=e.apply(y,g);l&&l(O),u.forEach(function(k){return(0,k.resolve)(O)}),u=[]}},f()),v){var b=e.apply(y,g);return l&&l(b),w(b)}u.push({resolve:w,reject:T})})};return h.cancel=function(g){s!==void 0&&clearTimeout(s),u.forEach(function(y){return(0,y.reject)(g)}),u=[]},h}/*! * vue-router v4.2.4 * (c) 2023 Eduardo San Martin Morote * @license MIT diff --git a/assets/asmstyle.html-74b27b35.js b/assets/asmstyle.html-90ec72c6.js similarity index 99% rename from assets/asmstyle.html-74b27b35.js rename to assets/asmstyle.html-90ec72c6.js index 8d7b6a0..1d0d4d6 100644 --- a/assets/asmstyle.html-74b27b35.js +++ b/assets/asmstyle.html-90ec72c6.js @@ -1 +1 @@ -import{_ as a,r,o as i,c as l,a as e,b as t,d as n,e as s}from"./app-19015fbd.js";const d={},c=e("h1",{id:"game-boy-asm-style-guide",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-asm-style-guide","aria-hidden":"true"},"#"),t(" Game Boy ASM style guide")],-1),h={href:"https://github.com/ISSOtm/",target:"_blank",rel:"noopener noreferrer"},u=e("hr",null,null,-1),b=e("p",null,"This style guide aims to formalize a style that most Game Boy ASM programmers agree on, and provide a good baseline for new programmers just starting in this field. (If that's you, welcome! 😄)",-1),p={href:"https://github.com/torvalds/linux/blob/master/Documentation/process/coding-style.rst",target:"_blank",rel:"noopener noreferrer"},g=e("blockquote",null,[e("p",null,[t("Coding style is very personal, and I won't "),e("strong",null,"force"),t(" my views on anybody, but this is what goes for anything that I have to be able to maintain, and I'd prefer it for most other things too. Please at least consider the points made here.")])],-1),_=e("p",null,"Many people follow alternate style guides, and that's fine; but if you're starting to code in ASM, a clean style goes a long way to keep your code organized. Again: you don't have to do everything listed here, but please at least consider the reasons behind each bullet point.",-1),f={href:"https://github.com/gbdev/gbdev.github.io",target:"_blank",rel:"noopener noreferrer"},m={href:"https://gbdev.io/chat",target:"_blank",rel:"noopener noreferrer"},y=e("h2",{id:"naming",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#naming","aria-hidden":"true"},"#"),t(" Naming")],-1),v={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#SYMBOLS",target:"_blank",rel:"noopener noreferrer"},k=e("blockquote",null,[e("p",null,"Symbol names can contain letters, numbers, underscores ‘_’, hashes ‘#’ and at signs ‘@’. However, they must begin with either a letter, or an underscore.")],-1),w=e("p",null,"However, naming conventions make code easier to read, since they help convey the different semantics between each symbol's name.",-1),A=s("
  • Labels use PascalCase: DrawNPCs, GetOffsetFromCamera.

  • Labels in RAM (VRAM, SRAM, WRAM, HRAM; you shouldn't be using Echo RAM or OAM) use the same convention but are prefixed with the initial of the RAM they're in, in lowercase: wCameraOffsetBuffer, hVBlankFlag, vTilesetTiles, sSaveFileChecksum. Rationale: to know in which memory type the label is; this is important because VRAM and SRAM have special access precautions and HRAM can (should (must)) be accessed using the ldh instruction.

  • Local labels use camelCase, regardless of memory type: .waitVRAM, wPlayer.xCoord.

  • Macro names use snake_case: wait_vram, end_struct.

  • ",4),M=e("p",null,[t("Constants use CAPS_SNAKE: "),e("code",null,"NB_NPCS"),t(", "),e("code",null,"OVERWORLD_STATE_LOAD_MAP"),t(".")],-1),R={href:"https://github.com/gbdev/hardware.inc/blob/master/hardware.inc",target:"_blank",rel:"noopener noreferrer"},S=e("code",null,"rXXX",-1),O=e("h2",{id:"best-practices",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#best-practices","aria-hidden":"true"},"#"),t(" Best practices")],-1),B=e("p",null,"Avoid hardcoding things. This means:",-1),x=e("li",null,[e("p",null,[t("No magic numbers. "),e("code",null,"ld a, CURSOR_SPEED"),t(" is much more obvious than "),e("code",null,"ld a, 5"),t(". In addition, if you ever change your mind and decide to change the cursor speed, you will only need to do so in one location ("),e("code",null,"CURSOR_SPEED equ 5"),t(" → "),e("code",null,"CURSOR_SPEED equ 4"),t(") instead of at every location you're using it, potentially missing some.")])],-1),C=e("strong",null,"absolutely necessary",-1),N={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#BANK",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"SECTION",-1),L={href:"https://gbdev.io/pandocs/#_0100-0103-entry-point",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/GreenAndEievui/vuibui-engine/blob/206fd814e67da2cebbeca7d011a5537fef22a29c/src/main.asm#L6",target:"_blank",rel:"noopener noreferrer"},T={href:"https://gbdev.io/pandocs/#jump-vectors-in-first-rom-bank",target:"_blank",rel:"noopener noreferrer"},G=e("code",null,"rst",-1),q={href:"https://github.com/gbdev/rgbds/issues/244",target:"_blank",rel:"noopener noreferrer"},D={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Section_Fragments",target:"_blank",rel:"noopener noreferrer"},P=e("code",null,"SECTION FRAGMENT",-1),z=e("code",null,"BANK[]",-1),H=e("code",null,'assert BANK("Section A") == BANK("Section B")',-1),V={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#ALIGN",target:"_blank",rel:"noopener noreferrer"},j=e("code",null,"ALIGN[]",-1),K={href:"https://gbdev.io/pandocs/#lcd-oam-dma-transfers",target:"_blank",rel:"noopener noreferrer"},U=e("code",null,'SECTION "Shadow OAM", WRAM0,ALIGN[8]',-1),F=e("code",null,'SECTION "Shadow OAM", WRAM0[$C000]',-1),W={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#SYMBOLS",target:"_blank",rel:"noopener noreferrer"},X={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Declaring_variables_in_a_RAM_section",target:"_blank",rel:"noopener noreferrer"},Y=e("code",null,"ds",-1),$={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#EQU",target:"_blank",rel:"noopener noreferrer"},Z=e("code",null,"equ",-1),Q=e("li",null,"Removing, adding, or changing the size of a variable that isn't the last one doesn't require updating every variable after it.",-1),J=e("li",null,[t("The size of each variable is obvious ("),e("code",null,"ds 4"),t(") instead of having to be calculated from the addresses.")],-1),ee=e("li",null,[e("code",null,"equ"),t(" allocation is equivalent to hardcoding section addresses (see above), whereas labels are placed automatically by RGBLINK.")],-1),te={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Other_functions",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"BANK()",-1),ne={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgblink.1#m",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"map",-1),ae=e("code",null,"sym",-1),re=e("li",null,[e("p",null,"If a file gets too big, you should split it. Files too large are harder to read and navigate. However, the splitting should stay coherent and consistent; having to jump around files constantly is equally as hard to read and navigate.")],-1),ie={href:"https://gbdev.io/pandocs/#no-mbc",target:"_blank",rel:"noopener noreferrer"},le={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#ROMX",target:"_blank",rel:"noopener noreferrer"},de=e("code",null,"ROMX",-1),ce=e("code",null,"ROM0",-1),he={href:"https://github.com/pret/pokecrystal/blob/35219230960f0dc85c0cb6a5723877b247609e46/macros/rst.asm#L1-L5",target:"_blank",rel:"noopener noreferrer"},ue=e("code",null,"farcall",-1),be={href:"https://en.wikipedia.org/wiki/Spaghetti_code",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://bgb.bircd.org",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"Also, a lot of the time, variables need to get initialized to values other than 0, so clearing RAM is actually counter-productive in these cases.",-1),_e=e("h2",{id:"recommendations",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#recommendations","aria-hidden":"true"},"#"),t(" Recommendations")],-1),fe=e("p",null,`The difference between these and the "best practices" above is that these are more subjective, but they're still worth talking about here.`,-1),me={href:"https://github.com/pinobatch/libbet/blob/cabe48bc4042338b9975cb32c2dbd0ee6640f31e/src/main.z80#L206-L231",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://github.com/BlitterObjectBob/DeadCScroll/blob/9834372eb0d56e8b9a8cdcaae4b8aecb6d402266/DeadCScroll.asm#L410-L422",target:"_blank",rel:"noopener noreferrer"},ve=s("
  • Please use the .asm (or .s) file extensions, not .z80. The GB CPU isn't a Z80, so syntax highlighters get it mostly right, but not quite. And it helps spreading the false idea that the GB CPU is a Z80. 😢

  • Compressing data is useful for several reasons; however, it's not necessary in a lot of cases nowadays, so you may want to only look at it after more high-priority aspects.

  • Avoid abusing macros. Macros tend to make code opaque and hard to read for people trying to help you, in addition to having side effects and sometimes leading to very inefficient code.

  • Never let the hardware draw a corrupted frame even if it's just one frame. If it's noticeable by squinting a bit, it must go.

  • ",4),ke={href:"https://www.gnu.org/software/make/manual/html_node/",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/ISSOtm/gb-starter-kit",target:"_blank",rel:"noopener noreferrer"};function Me(Re,Se){const o=r("ExternalLinkIcon");return i(),l("div",null,[c,e("p",null,[t("Written by "),e("a",h,[t("ISSOtm"),n(o)])]),u,b,e("p",null,[t("To quote the "),e("a",p,[t("Linux kernel style guide"),n(o)]),t(":")]),g,_,e("p",null,[t("Oh, by the way, you're free to "),e("a",f,[t("contribute to this document"),n(o)]),t(" and/or "),e("a",m,[t("chat with us about it"),n(o)]),t("!")]),y,e("p",null,[e("a",v,[t("RGBASM accepts a lot of symbol names"),n(o)]),t(":")]),k,w,e("ul",null,[A,e("li",null,[M,e("p",null,[t("Exception: constants that are used like labels should follow the label naming conventions. For example, see "),e("a",R,[t("hardware.inc"),n(o)]),t("'s "),S,t(" constants.")])])]),O,e("ul",null,[e("li",null,[B,e("ul",null,[x,e("li",null,[e("p",null,[t("Unless "),C,t(", don't "),e("a",N,[t("force a "),I,t("'s bank"),n(o)]),t(" or address. This puts the burden of managing ROM space on you, instead of offloading the job to RGBLINK, which performs very well in typical cases. Exceptions:")]),e("ul",null,[e("li",null,[t("Your ROM's entry point "),e("a",L,[t("must be at $0100"),n(o)]),t(", however the jump does not have to be to $0150 ("),e("a",E,[t("example"),n(o)]),t(").")]),e("li",null,[e("a",T,[G,t(" vectors and interrupt handlers"),n(o)]),t(" obviously need to be at the corresponding locations.")]),e("li",null,[e("a",q,[t("RGBDS presently does not allow forcing different sections to be in the same bank"),n(o)]),t(". If you need to do so, the ideal fix is to merge the two sections together (either by moving the code, or using "),e("a",D,[P,n(o)]),t("), but if that option is unavailable, the only alternative is to explicitly declare them with the same "),z,t(" attribute. (In which case it's advisable to add an "),H,t(" line.)")])]),e("p",null,[t("If you need some alignment, prefer "),e("a",V,[j,n(o)]),t(" to forcing the address. A typical example is "),e("a",K,[t("OAM DMA"),n(o)]),t("; for that, prefer "),U,t(" over e.g. "),F,t(".")])])])]),e("li",null,[e("p",null,[t("Allocate space for your variables using "),e("a",W,[t("labels"),n(o)]),t(" + "),e("a",X,[Y,t(" & co"),n(o)]),t(" instead of "),e("a",$,[Z,n(o)]),t(". This has several benefits:")]),e("ul",null,[Q,J,ee,e("li",null,[t("Labels support "),e("a",te,[oe,n(o)]),t(" and many cool other features!")]),e("li",null,[t("Labels are output in "),e("a",ne,[se,t(" and "),ae,n(o)]),t(" files.")])])]),re,e("li",null,[e("p",null,[e("a",ie,[t("Unless you're making a 32k ROM"),n(o)]),t(", put things in "),e("a",le,[de,n(o)]),t(" by default. "),ce,t(" space is precious, and can deplete quickly; and when you run out, it's difficult to move things to ROMX.")]),e("p",null,[t("However, if you have code in ROM bank A refer to code or data in ROM bank B, then either should probably be moved to ROM0, or both be placed in the same bank (options for that are mentioned further above). "),e("a",he,[ue,n(o)]),t(" is a good way to make your code really "),e("a",be,[t("spaghetti"),n(o)]),t(".")])]),e("li",null,[e("p",null,[t("Don't clear RAM at init! Good debugging emulators will warn you when you're reading uninitialized RAM ("),e("a",pe,[t("BGB"),n(o)]),t(" has one in the option's Exceptions tab, for example), which will let you know that you forgot to initialize a variable. Clearing RAM does not fix most of these bugs, but silences the helpful warnings.")]),ge])]),_e,fe,e("ul",null,[e("li",null,[e("p",null,[t('Historically, RGBDS has required label definitions to begin at "column 1" (i.e. no whitespace before them on their line). However, later versions (with full support added in 0.5.0) allow '),e("a",me,[t("indenting labels"),n(o)]),t(", for example to make loops stand out like in higher-level languages. However, "),e("a",ye,[t("a lot of people don't do this"),n(o)]),t(", so it's up to you.")])]),ve,e("li",null,[e("p",null,[e("a",ke,[t("Makefiles are bae"),n(o)]),t("; they speed up build time by not re-processing what hasn't changed, and they can automate a lot of tedium. Writing a good Makefile can be quite daunting, but "),e("a",we,[t("gb-boilerplate"),n(o)]),t(" and "),e("a",Ae,[t("gb-starter-kit"),n(o)]),t(" can help you get started faster.")])])])])}const Be=a(d,[["render",Me],["__file","asmstyle.html.vue"]]);export{Be as default}; +import{_ as a,r,o as i,c as l,a as e,b as t,d as n,e as s}from"./app-821120ad.js";const d={},c=e("h1",{id:"game-boy-asm-style-guide",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-asm-style-guide","aria-hidden":"true"},"#"),t(" Game Boy ASM style guide")],-1),h={href:"https://github.com/ISSOtm/",target:"_blank",rel:"noopener noreferrer"},u=e("hr",null,null,-1),b=e("p",null,"This style guide aims to formalize a style that most Game Boy ASM programmers agree on, and provide a good baseline for new programmers just starting in this field. (If that's you, welcome! 😄)",-1),p={href:"https://github.com/torvalds/linux/blob/master/Documentation/process/coding-style.rst",target:"_blank",rel:"noopener noreferrer"},g=e("blockquote",null,[e("p",null,[t("Coding style is very personal, and I won't "),e("strong",null,"force"),t(" my views on anybody, but this is what goes for anything that I have to be able to maintain, and I'd prefer it for most other things too. Please at least consider the points made here.")])],-1),_=e("p",null,"Many people follow alternate style guides, and that's fine; but if you're starting to code in ASM, a clean style goes a long way to keep your code organized. Again: you don't have to do everything listed here, but please at least consider the reasons behind each bullet point.",-1),f={href:"https://github.com/gbdev/gbdev.github.io",target:"_blank",rel:"noopener noreferrer"},m={href:"https://gbdev.io/chat",target:"_blank",rel:"noopener noreferrer"},y=e("h2",{id:"naming",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#naming","aria-hidden":"true"},"#"),t(" Naming")],-1),v={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#SYMBOLS",target:"_blank",rel:"noopener noreferrer"},k=e("blockquote",null,[e("p",null,"Symbol names can contain letters, numbers, underscores ‘_’, hashes ‘#’ and at signs ‘@’. However, they must begin with either a letter, or an underscore.")],-1),w=e("p",null,"However, naming conventions make code easier to read, since they help convey the different semantics between each symbol's name.",-1),A=s("
  • Labels use PascalCase: DrawNPCs, GetOffsetFromCamera.

  • Labels in RAM (VRAM, SRAM, WRAM, HRAM; you shouldn't be using Echo RAM or OAM) use the same convention but are prefixed with the initial of the RAM they're in, in lowercase: wCameraOffsetBuffer, hVBlankFlag, vTilesetTiles, sSaveFileChecksum. Rationale: to know in which memory type the label is; this is important because VRAM and SRAM have special access precautions and HRAM can (should (must)) be accessed using the ldh instruction.

  • Local labels use camelCase, regardless of memory type: .waitVRAM, wPlayer.xCoord.

  • Macro names use snake_case: wait_vram, end_struct.

  • ",4),M=e("p",null,[t("Constants use CAPS_SNAKE: "),e("code",null,"NB_NPCS"),t(", "),e("code",null,"OVERWORLD_STATE_LOAD_MAP"),t(".")],-1),R={href:"https://github.com/gbdev/hardware.inc/blob/master/hardware.inc",target:"_blank",rel:"noopener noreferrer"},S=e("code",null,"rXXX",-1),O=e("h2",{id:"best-practices",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#best-practices","aria-hidden":"true"},"#"),t(" Best practices")],-1),B=e("p",null,"Avoid hardcoding things. This means:",-1),x=e("li",null,[e("p",null,[t("No magic numbers. "),e("code",null,"ld a, CURSOR_SPEED"),t(" is much more obvious than "),e("code",null,"ld a, 5"),t(". In addition, if you ever change your mind and decide to change the cursor speed, you will only need to do so in one location ("),e("code",null,"CURSOR_SPEED equ 5"),t(" → "),e("code",null,"CURSOR_SPEED equ 4"),t(") instead of at every location you're using it, potentially missing some.")])],-1),C=e("strong",null,"absolutely necessary",-1),N={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#BANK",target:"_blank",rel:"noopener noreferrer"},I=e("code",null,"SECTION",-1),L={href:"https://gbdev.io/pandocs/#_0100-0103-entry-point",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/GreenAndEievui/vuibui-engine/blob/206fd814e67da2cebbeca7d011a5537fef22a29c/src/main.asm#L6",target:"_blank",rel:"noopener noreferrer"},T={href:"https://gbdev.io/pandocs/#jump-vectors-in-first-rom-bank",target:"_blank",rel:"noopener noreferrer"},G=e("code",null,"rst",-1),q={href:"https://github.com/gbdev/rgbds/issues/244",target:"_blank",rel:"noopener noreferrer"},D={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Section_Fragments",target:"_blank",rel:"noopener noreferrer"},P=e("code",null,"SECTION FRAGMENT",-1),z=e("code",null,"BANK[]",-1),H=e("code",null,'assert BANK("Section A") == BANK("Section B")',-1),V={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#ALIGN",target:"_blank",rel:"noopener noreferrer"},j=e("code",null,"ALIGN[]",-1),K={href:"https://gbdev.io/pandocs/#lcd-oam-dma-transfers",target:"_blank",rel:"noopener noreferrer"},U=e("code",null,'SECTION "Shadow OAM", WRAM0,ALIGN[8]',-1),F=e("code",null,'SECTION "Shadow OAM", WRAM0[$C000]',-1),W={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#SYMBOLS",target:"_blank",rel:"noopener noreferrer"},X={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Declaring_variables_in_a_RAM_section",target:"_blank",rel:"noopener noreferrer"},Y=e("code",null,"ds",-1),$={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#EQU",target:"_blank",rel:"noopener noreferrer"},Z=e("code",null,"equ",-1),Q=e("li",null,"Removing, adding, or changing the size of a variable that isn't the last one doesn't require updating every variable after it.",-1),J=e("li",null,[t("The size of each variable is obvious ("),e("code",null,"ds 4"),t(") instead of having to be calculated from the addresses.")],-1),ee=e("li",null,[e("code",null,"equ"),t(" allocation is equivalent to hardcoding section addresses (see above), whereas labels are placed automatically by RGBLINK.")],-1),te={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#Other_functions",target:"_blank",rel:"noopener noreferrer"},oe=e("code",null,"BANK()",-1),ne={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgblink.1#m",target:"_blank",rel:"noopener noreferrer"},se=e("code",null,"map",-1),ae=e("code",null,"sym",-1),re=e("li",null,[e("p",null,"If a file gets too big, you should split it. Files too large are harder to read and navigate. However, the splitting should stay coherent and consistent; having to jump around files constantly is equally as hard to read and navigate.")],-1),ie={href:"https://gbdev.io/pandocs/#no-mbc",target:"_blank",rel:"noopener noreferrer"},le={href:"https://rgbds.gbdev.io/docs/v0.4.2/rgbasm.5#ROMX",target:"_blank",rel:"noopener noreferrer"},de=e("code",null,"ROMX",-1),ce=e("code",null,"ROM0",-1),he={href:"https://github.com/pret/pokecrystal/blob/35219230960f0dc85c0cb6a5723877b247609e46/macros/rst.asm#L1-L5",target:"_blank",rel:"noopener noreferrer"},ue=e("code",null,"farcall",-1),be={href:"https://en.wikipedia.org/wiki/Spaghetti_code",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://bgb.bircd.org",target:"_blank",rel:"noopener noreferrer"},ge=e("p",null,"Also, a lot of the time, variables need to get initialized to values other than 0, so clearing RAM is actually counter-productive in these cases.",-1),_e=e("h2",{id:"recommendations",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#recommendations","aria-hidden":"true"},"#"),t(" Recommendations")],-1),fe=e("p",null,`The difference between these and the "best practices" above is that these are more subjective, but they're still worth talking about here.`,-1),me={href:"https://github.com/pinobatch/libbet/blob/cabe48bc4042338b9975cb32c2dbd0ee6640f31e/src/main.z80#L206-L231",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://github.com/BlitterObjectBob/DeadCScroll/blob/9834372eb0d56e8b9a8cdcaae4b8aecb6d402266/DeadCScroll.asm#L410-L422",target:"_blank",rel:"noopener noreferrer"},ve=s("
  • Please use the .asm (or .s) file extensions, not .z80. The GB CPU isn't a Z80, so syntax highlighters get it mostly right, but not quite. And it helps spreading the false idea that the GB CPU is a Z80. 😢

  • Compressing data is useful for several reasons; however, it's not necessary in a lot of cases nowadays, so you may want to only look at it after more high-priority aspects.

  • Avoid abusing macros. Macros tend to make code opaque and hard to read for people trying to help you, in addition to having side effects and sometimes leading to very inefficient code.

  • Never let the hardware draw a corrupted frame even if it's just one frame. If it's noticeable by squinting a bit, it must go.

  • ",4),ke={href:"https://www.gnu.org/software/make/manual/html_node/",target:"_blank",rel:"noopener noreferrer"},we={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://github.com/ISSOtm/gb-starter-kit",target:"_blank",rel:"noopener noreferrer"};function Me(Re,Se){const o=r("ExternalLinkIcon");return i(),l("div",null,[c,e("p",null,[t("Written by "),e("a",h,[t("ISSOtm"),n(o)])]),u,b,e("p",null,[t("To quote the "),e("a",p,[t("Linux kernel style guide"),n(o)]),t(":")]),g,_,e("p",null,[t("Oh, by the way, you're free to "),e("a",f,[t("contribute to this document"),n(o)]),t(" and/or "),e("a",m,[t("chat with us about it"),n(o)]),t("!")]),y,e("p",null,[e("a",v,[t("RGBASM accepts a lot of symbol names"),n(o)]),t(":")]),k,w,e("ul",null,[A,e("li",null,[M,e("p",null,[t("Exception: constants that are used like labels should follow the label naming conventions. For example, see "),e("a",R,[t("hardware.inc"),n(o)]),t("'s "),S,t(" constants.")])])]),O,e("ul",null,[e("li",null,[B,e("ul",null,[x,e("li",null,[e("p",null,[t("Unless "),C,t(", don't "),e("a",N,[t("force a "),I,t("'s bank"),n(o)]),t(" or address. This puts the burden of managing ROM space on you, instead of offloading the job to RGBLINK, which performs very well in typical cases. Exceptions:")]),e("ul",null,[e("li",null,[t("Your ROM's entry point "),e("a",L,[t("must be at $0100"),n(o)]),t(", however the jump does not have to be to $0150 ("),e("a",E,[t("example"),n(o)]),t(").")]),e("li",null,[e("a",T,[G,t(" vectors and interrupt handlers"),n(o)]),t(" obviously need to be at the corresponding locations.")]),e("li",null,[e("a",q,[t("RGBDS presently does not allow forcing different sections to be in the same bank"),n(o)]),t(". If you need to do so, the ideal fix is to merge the two sections together (either by moving the code, or using "),e("a",D,[P,n(o)]),t("), but if that option is unavailable, the only alternative is to explicitly declare them with the same "),z,t(" attribute. (In which case it's advisable to add an "),H,t(" line.)")])]),e("p",null,[t("If you need some alignment, prefer "),e("a",V,[j,n(o)]),t(" to forcing the address. A typical example is "),e("a",K,[t("OAM DMA"),n(o)]),t("; for that, prefer "),U,t(" over e.g. "),F,t(".")])])])]),e("li",null,[e("p",null,[t("Allocate space for your variables using "),e("a",W,[t("labels"),n(o)]),t(" + "),e("a",X,[Y,t(" & co"),n(o)]),t(" instead of "),e("a",$,[Z,n(o)]),t(". This has several benefits:")]),e("ul",null,[Q,J,ee,e("li",null,[t("Labels support "),e("a",te,[oe,n(o)]),t(" and many cool other features!")]),e("li",null,[t("Labels are output in "),e("a",ne,[se,t(" and "),ae,n(o)]),t(" files.")])])]),re,e("li",null,[e("p",null,[e("a",ie,[t("Unless you're making a 32k ROM"),n(o)]),t(", put things in "),e("a",le,[de,n(o)]),t(" by default. "),ce,t(" space is precious, and can deplete quickly; and when you run out, it's difficult to move things to ROMX.")]),e("p",null,[t("However, if you have code in ROM bank A refer to code or data in ROM bank B, then either should probably be moved to ROM0, or both be placed in the same bank (options for that are mentioned further above). "),e("a",he,[ue,n(o)]),t(" is a good way to make your code really "),e("a",be,[t("spaghetti"),n(o)]),t(".")])]),e("li",null,[e("p",null,[t("Don't clear RAM at init! Good debugging emulators will warn you when you're reading uninitialized RAM ("),e("a",pe,[t("BGB"),n(o)]),t(" has one in the option's Exceptions tab, for example), which will let you know that you forgot to initialize a variable. Clearing RAM does not fix most of these bugs, but silences the helpful warnings.")]),ge])]),_e,fe,e("ul",null,[e("li",null,[e("p",null,[t('Historically, RGBDS has required label definitions to begin at "column 1" (i.e. no whitespace before them on their line). However, later versions (with full support added in 0.5.0) allow '),e("a",me,[t("indenting labels"),n(o)]),t(", for example to make loops stand out like in higher-level languages. However, "),e("a",ye,[t("a lot of people don't do this"),n(o)]),t(", so it's up to you.")])]),ve,e("li",null,[e("p",null,[e("a",ke,[t("Makefiles are bae"),n(o)]),t("; they speed up build time by not re-processing what hasn't changed, and they can automate a lot of tedium. Writing a good Makefile can be quite daunting, but "),e("a",we,[t("gb-boilerplate"),n(o)]),t(" and "),e("a",Ae,[t("gb-starter-kit"),n(o)]),t(" can help you get started faster.")])])])])}const Be=a(d,[["render",Me],["__file","asmstyle.html.vue"]]);export{Be as default}; diff --git a/assets/chat.html-243153ed.js b/assets/chat.html-435caf64.js similarity index 95% rename from assets/chat.html-243153ed.js rename to assets/chat.html-435caf64.js index be873ee..4e69ddb 100644 --- a/assets/chat.html-243153ed.js +++ b/assets/chat.html-435caf64.js @@ -1 +1 @@ -import{_ as r,r as a,o as c,c as s,a as e,b as o,d as n,e as d}from"./app-19015fbd.js";const l={},i=e("h1",{id:"community-channels",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#community-channels","aria-hidden":"true"},"#"),o(" Community channels")],-1),h=e("p",null,"Join our community on the following channels. Before posting, read the rules and the FAQ (usually in the welcome threads or in the signup).",-1),_={href:"https://discord.gg/RjJKA8wrD4",target:"_blank",rel:"noopener noreferrer"},g={href:"https://web.libera.chat/#gbdev",target:"_blank",rel:"noopener noreferrer"},u=e("code",null,"#gbdev",-1),b=d("
    • #gbdev-ot, #gbdev-hw,#gbdev-meta, #gbdev-asm,#gbdev-gfx, #gbdev-emudev and #gbdev-research are also available.
    ",1),m={href:"https://gbdev.gg8.se/forums/",target:"_blank",rel:"noopener noreferrer"},f={href:"https://gbdev.gg8.se/wiki/",target:"_blank",rel:"noopener noreferrer"};function p(v,k){const t=a("ExternalLinkIcon");return c(),s("div",null,[i,h,e("ul",null,[e("li",null,[e("a",_,[o("Discord Server"),n(t)]),o(".")]),e("li",null,[o("IRC: "),e("a",g,[u,o(" on Libera.chat"),n(t)]),o(". "),b]),e("li",null,[o("Forum: "),e("a",m,[o("https://gbdev.gg8.se/forums"),n(t)])]),e("li",null,[o("Wiki: "),e("a",f,[o("https://gbdev.gg8.se/wiki"),n(t)])])])])}const w=r(l,[["render",p],["__file","chat.html.vue"]]);export{w as default}; +import{_ as r,r as a,o as c,c as s,a as e,b as o,d as n,e as d}from"./app-821120ad.js";const l={},i=e("h1",{id:"community-channels",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#community-channels","aria-hidden":"true"},"#"),o(" Community channels")],-1),h=e("p",null,"Join our community on the following channels. Before posting, read the rules and the FAQ (usually in the welcome threads or in the signup).",-1),_={href:"https://discord.gg/RjJKA8wrD4",target:"_blank",rel:"noopener noreferrer"},g={href:"https://web.libera.chat/#gbdev",target:"_blank",rel:"noopener noreferrer"},u=e("code",null,"#gbdev",-1),b=d("
    • #gbdev-ot, #gbdev-hw,#gbdev-meta, #gbdev-asm,#gbdev-gfx, #gbdev-emudev and #gbdev-research are also available.
    ",1),m={href:"https://gbdev.gg8.se/forums/",target:"_blank",rel:"noopener noreferrer"},f={href:"https://gbdev.gg8.se/wiki/",target:"_blank",rel:"noopener noreferrer"};function p(v,k){const t=a("ExternalLinkIcon");return c(),s("div",null,[i,h,e("ul",null,[e("li",null,[e("a",_,[o("Discord Server"),n(t)]),o(".")]),e("li",null,[o("IRC: "),e("a",g,[u,o(" on Libera.chat"),n(t)]),o(". "),b]),e("li",null,[o("Forum: "),e("a",m,[o("https://gbdev.gg8.se/forums"),n(t)])]),e("li",null,[o("Wiki: "),e("a",f,[o("https://gbdev.gg8.se/wiki"),n(t)])])])])}const w=r(l,[["render",p],["__file","chat.html.vue"]]);export{w as default}; diff --git a/assets/contributing.html-460f065c.js b/assets/contributing.html-c7c45a02.js similarity index 99% rename from assets/contributing.html-460f065c.js rename to assets/contributing.html-c7c45a02.js index 62530a2..0d5c9c9 100644 --- a/assets/contributing.html-460f065c.js +++ b/assets/contributing.html-c7c45a02.js @@ -1 +1 @@ -import{_ as a,r,o as i,c as s,a as e,b as t,d as n,e as l}from"./app-19015fbd.js";const h={},d=e("h1",{id:"contribution-guidelines",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contribution-guidelines","aria-hidden":"true"},"#"),t(" Contribution guidelines")],-1),c={href:"https://github.com/gbdev/",target:"_blank",rel:"noopener noreferrer"},u=e("strong",null,"gbdev",-1),p=e("h2",{id:"general",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#general","aria-hidden":"true"},"#"),t(" General")],-1),b={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},f=e("h2",{id:"issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#issues","aria-hidden":"true"},"#"),t(" Issues")],-1),m=e("li",null,"Provide an example to reproduce the problem in isolation. This should include no private code. The example should be self-runnable. If a snippet is too small, create a repository.",-1),g=e("li",null,"Unless the problem is visual, do not include screenshots. They are not helpful.",-1),_=e("li",null,"Please be patient. You are probably frustrated by your problem - the maintainers are likely not aware of your workflow.",-1),y=e("li",null,"Be grateful for any help you are getting and follow through. The maintainers are likely giving you support for free.",-1),v={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},w=e("li",null,[t("Include context and any information useful to understand the situation. Don't be scared about doing something wrong or "),e("em",null,"not good enough"),t(", maintainers will follow up if needed.")],-1),k=l('

    Pull Requests

    • Keep titles and commit messages brief and concise.
    • If the PR is not self-explanatory, add brief description of what has been done and implementation choices (if any).
    • Keep the work in the branch focused and directed at accomplishing only what you are describing in the PR. Ideally a PR should address a single issue (or a set of assimilable ones).
    • PRs require commitment and they are an investment by the (volunteer) maintainers. If you don't have time or abandon the PR after reviews have been left and additional changes are needed, other maintainers may take over to make sure the PR can move forward and the work is not lost.
    • Maintainers may chime in and commit to your feature branch on minor fixes (or suggestions agreed upon).
    • Don't be scared of opening more PRs for the same task, if they can be logically divided. The smaller the changes, the faster they can get reviewed and eventually merged.
    • When adding new features, think about tests and possibly updating documentation. Think about other parts of the project which may be affected by the change.
    • Document trade-offs, risks, implementation and design choices, if any.

    Maintainers workflow

    • Tests and pipelines must pass. If they failed because of something unrelated to the PR (e.g. a link died in the meantime), mention it in the PR thread.
    • If the solution is "sub-optimal" (but still better than the actual implementation) and there are clear possible improvements, mention them and try to collaborate with the contributor, but ultimately prefer merging something sub-optimal than keeping the content stale/inactive. An issue can be opened (or kept opened) to report this situation.

    For disruptive PRs:

    • Wait for 2* maintainers approval
    • Every week of inactivity/staleness, ping maintainers
    • After 5 weeks from last activity, PR is merge-able with only 1 maintainer approval

    For non-disruptive PRs:

    • Wait for 1 maintainer approval and merge it after 5 days
    • If a maintainer wants to put a veto and to make the PR wait for his/her input after the mentioned period, the "veto" label can be used

    *if there are at least 2 active maintainers, otherwise 1.

    References

    ',10),R={href:"https://nitter.net/matteocollina/status/1359087694375174145",target:"_blank",rel:"noopener noreferrer"},x=e("h2",{id:"where-can-i-help",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#where-can-i-help","aria-hidden":"true"},"#"),t(" Where can I help?")],-1),T=e("p",null,"Here's a list of the project in most need of help:",-1),I=e("h3",{id:"gb-asm-tutorial",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gb-asm-tutorial","aria-hidden":"true"},"#"),t(" GB ASM Tutorial")],-1),P=e("p",null,"If you're confident in writing assembly, we need contributors in helping us write, proofread and suggest improvements for new lessons in the tutorial.",-1),B=e("p",null,"Technologies and tools: Assembly, RGBDS, Rust, mdBook.",-1),A={href:"https://gbdev.io/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/gbdev/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},q=e("h3",{id:"pan-docs",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#pan-docs","aria-hidden":"true"},"#"),t(" Pan Docs")],-1),D=e("p",null,"The single, most comprehensive technical reference to Game Boy available to the public. Here, you can help adding new content, proof reading, fixing typos, preparing updated versions of figures or port new content from old resources.",-1),G=e("p",null,"Technologies and tools: Markdown, Rust, Python, mdBook.",-1),N={href:"https://gbdev.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/gbdev/pandocs",target:"_blank",rel:"noopener noreferrer"},C={href:"https://github.com/gbdev/pandocs/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest",target:"_blank",rel:"noopener noreferrer"},j=e("h3",{id:"rgbds",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#rgbds","aria-hidden":"true"},"#"),t(" RGBDS")],-1),E=e("p",null,"The de-facto standard assembly toolchain for the Nintendo Game Boy & Game Boy Color.",-1),V=e("p",null,"Technologies and tools: C, C++, Assembly, Rust",-1),F={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},M={href:"https://github.com/gbdev/rgbds",target:"_blank",rel:"noopener noreferrer"},O={href:"https://github.com/gbdev/rgbds/issues?q=is%3Aissue+is%3Aopen+label%3Ahacktoberfest",target:"_blank",rel:"noopener noreferrer"},W=e("h3",{id:"homebrew-hub",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrew-hub","aria-hidden":"true"},"#"),t(" Homebrew Hub")],-1),J=e("p",null,"A community-led attempt to collect, archive and save every unofficial game, homebrew, patch, hackrom for Game Boy produced by the community through decades of passionate work.",-1),K=e("p",null,"Technologies and tools:",-1),L=e("ul",null,[e("li",null,"Frontend: Vue JS 3, Nuxt 3"),e("li",null,"Backend: Django REST")],-1),U={href:"https://hh.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},z={href:"https://github.com/gbdev/homebrewhub",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/gbdev/virens",target:"_blank",rel:"noopener noreferrer"},Q=e("h3",{id:"homebrew-hub-database",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrew-hub-database","aria-hidden":"true"},"#"),t(" Homebrew Hub Database")],-1),X=e("p",null,"This is the database of games powering the main Homebrew Hub project. Find a game (we have a lot to add!) and add it with a Pull Request. Or - even better - write scrapers to dump entire sources and add them to our repository!",-1),Z=e("p",null,"Technologies and tools: JSON Schema, Python, Javascript, BeautifulSoup",-1),$={href:"https://hh.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},ee={href:"https://github.com/gbdev/database",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/gbdev/database/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest",target:"_blank",rel:"noopener noreferrer"};function oe(ne,ae){const o=r("ExternalLinkIcon");return i(),s("div",null,[d,e("p",null,[t("These base guidelines (if not specified otherwise) apply to every repository under the "),e("a",c,[u,n(o)]),t(" github organisation. The specific CONTRIBUTING rules of the repository in object also apply. In case of conflicts, those last ones have the priority.")]),p,e("ul",null,[e("li",null,[t("If you are unsure about anything or need guidance, you can always reach out the maintainers on "),e("a",b,[t("Discord or IRC"),n(o)]),t(".")])]),f,e("ul",null,[m,g,_,y,e("li",null,[t("Informal conversations are great (e.g. on Discord), but once a problem, feature request etc is outlined, opening an issue formalizing it is the most important thing you can do to help this information flow. "),e("ul",null,[e("li",null,[t("Open an issue in the related repository. If you don't know where it's better suited, "),e("a",v,[t("ask for help"),n(o)]),t(".")]),w])])]),k,e("p",null,[e("a",R,[t("1"),n(o)])]),x,T,I,P,B,e("p",null,[e("a",A,[t("Homepage"),n(o)]),t(" - "),e("a",H,[t("Repository"),n(o)])]),q,D,G,e("p",null,[e("a",N,[t("Homepage"),n(o)]),t(" - "),e("a",S,[t("Repository"),n(o)]),t(" - "),e("a",C,[t("Beginner issues"),n(o)])]),j,E,V,e("p",null,[e("a",F,[t("Homepage"),n(o)]),t(" - "),e("a",M,[t("Repository"),n(o)]),t(" - "),e("a",O,[t("Beginner issues"),n(o)])]),W,J,K,L,e("p",null,[e("a",U,[t("Homepage"),n(o)]),t(" - "),e("a",z,[t("Repository (backend)"),n(o)]),t(" - "),e("a",Y,[t("Repository (frontend)"),n(o)])]),Q,X,Z,e("p",null,[e("a",$,[t("Homepage"),n(o)]),t(" - "),e("a",ee,[t("Repository"),n(o)]),t(" - "),e("a",te,[t("Beginner issues"),n(o)])])])}const ie=a(h,[["render",oe],["__file","contributing.html.vue"]]);export{ie as default}; +import{_ as a,r,o as i,c as s,a as e,b as t,d as n,e as l}from"./app-821120ad.js";const h={},d=e("h1",{id:"contribution-guidelines",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#contribution-guidelines","aria-hidden":"true"},"#"),t(" Contribution guidelines")],-1),c={href:"https://github.com/gbdev/",target:"_blank",rel:"noopener noreferrer"},u=e("strong",null,"gbdev",-1),p=e("h2",{id:"general",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#general","aria-hidden":"true"},"#"),t(" General")],-1),b={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},f=e("h2",{id:"issues",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#issues","aria-hidden":"true"},"#"),t(" Issues")],-1),m=e("li",null,"Provide an example to reproduce the problem in isolation. This should include no private code. The example should be self-runnable. If a snippet is too small, create a repository.",-1),g=e("li",null,"Unless the problem is visual, do not include screenshots. They are not helpful.",-1),_=e("li",null,"Please be patient. You are probably frustrated by your problem - the maintainers are likely not aware of your workflow.",-1),y=e("li",null,"Be grateful for any help you are getting and follow through. The maintainers are likely giving you support for free.",-1),v={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},w=e("li",null,[t("Include context and any information useful to understand the situation. Don't be scared about doing something wrong or "),e("em",null,"not good enough"),t(", maintainers will follow up if needed.")],-1),k=l('

    Pull Requests

    • Keep titles and commit messages brief and concise.
    • If the PR is not self-explanatory, add brief description of what has been done and implementation choices (if any).
    • Keep the work in the branch focused and directed at accomplishing only what you are describing in the PR. Ideally a PR should address a single issue (or a set of assimilable ones).
    • PRs require commitment and they are an investment by the (volunteer) maintainers. If you don't have time or abandon the PR after reviews have been left and additional changes are needed, other maintainers may take over to make sure the PR can move forward and the work is not lost.
    • Maintainers may chime in and commit to your feature branch on minor fixes (or suggestions agreed upon).
    • Don't be scared of opening more PRs for the same task, if they can be logically divided. The smaller the changes, the faster they can get reviewed and eventually merged.
    • When adding new features, think about tests and possibly updating documentation. Think about other parts of the project which may be affected by the change.
    • Document trade-offs, risks, implementation and design choices, if any.

    Maintainers workflow

    • Tests and pipelines must pass. If they failed because of something unrelated to the PR (e.g. a link died in the meantime), mention it in the PR thread.
    • If the solution is "sub-optimal" (but still better than the actual implementation) and there are clear possible improvements, mention them and try to collaborate with the contributor, but ultimately prefer merging something sub-optimal than keeping the content stale/inactive. An issue can be opened (or kept opened) to report this situation.

    For disruptive PRs:

    • Wait for 2* maintainers approval
    • Every week of inactivity/staleness, ping maintainers
    • After 5 weeks from last activity, PR is merge-able with only 1 maintainer approval

    For non-disruptive PRs:

    • Wait for 1 maintainer approval and merge it after 5 days
    • If a maintainer wants to put a veto and to make the PR wait for his/her input after the mentioned period, the "veto" label can be used

    *if there are at least 2 active maintainers, otherwise 1.

    References

    ',10),R={href:"https://nitter.net/matteocollina/status/1359087694375174145",target:"_blank",rel:"noopener noreferrer"},x=e("h2",{id:"where-can-i-help",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#where-can-i-help","aria-hidden":"true"},"#"),t(" Where can I help?")],-1),T=e("p",null,"Here's a list of the project in most need of help:",-1),I=e("h3",{id:"gb-asm-tutorial",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gb-asm-tutorial","aria-hidden":"true"},"#"),t(" GB ASM Tutorial")],-1),P=e("p",null,"If you're confident in writing assembly, we need contributors in helping us write, proofread and suggest improvements for new lessons in the tutorial.",-1),B=e("p",null,"Technologies and tools: Assembly, RGBDS, Rust, mdBook.",-1),A={href:"https://gbdev.io/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},H={href:"https://github.com/gbdev/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},q=e("h3",{id:"pan-docs",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#pan-docs","aria-hidden":"true"},"#"),t(" Pan Docs")],-1),D=e("p",null,"The single, most comprehensive technical reference to Game Boy available to the public. Here, you can help adding new content, proof reading, fixing typos, preparing updated versions of figures or port new content from old resources.",-1),G=e("p",null,"Technologies and tools: Markdown, Rust, Python, mdBook.",-1),N={href:"https://gbdev.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},S={href:"https://github.com/gbdev/pandocs",target:"_blank",rel:"noopener noreferrer"},C={href:"https://github.com/gbdev/pandocs/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest",target:"_blank",rel:"noopener noreferrer"},j=e("h3",{id:"rgbds",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#rgbds","aria-hidden":"true"},"#"),t(" RGBDS")],-1),E=e("p",null,"The de-facto standard assembly toolchain for the Nintendo Game Boy & Game Boy Color.",-1),V=e("p",null,"Technologies and tools: C, C++, Assembly, Rust",-1),F={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},M={href:"https://github.com/gbdev/rgbds",target:"_blank",rel:"noopener noreferrer"},O={href:"https://github.com/gbdev/rgbds/issues?q=is%3Aissue+is%3Aopen+label%3Ahacktoberfest",target:"_blank",rel:"noopener noreferrer"},W=e("h3",{id:"homebrew-hub",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrew-hub","aria-hidden":"true"},"#"),t(" Homebrew Hub")],-1),J=e("p",null,"A community-led attempt to collect, archive and save every unofficial game, homebrew, patch, hackrom for Game Boy produced by the community through decades of passionate work.",-1),K=e("p",null,"Technologies and tools:",-1),L=e("ul",null,[e("li",null,"Frontend: Vue JS 3, Nuxt 3"),e("li",null,"Backend: Django REST")],-1),U={href:"https://hh.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},z={href:"https://github.com/gbdev/homebrewhub",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://github.com/gbdev/virens",target:"_blank",rel:"noopener noreferrer"},Q=e("h3",{id:"homebrew-hub-database",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrew-hub-database","aria-hidden":"true"},"#"),t(" Homebrew Hub Database")],-1),X=e("p",null,"This is the database of games powering the main Homebrew Hub project. Find a game (we have a lot to add!) and add it with a Pull Request. Or - even better - write scrapers to dump entire sources and add them to our repository!",-1),Z=e("p",null,"Technologies and tools: JSON Schema, Python, Javascript, BeautifulSoup",-1),$={href:"https://hh.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},ee={href:"https://github.com/gbdev/database",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/gbdev/database/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest",target:"_blank",rel:"noopener noreferrer"};function oe(ne,ae){const o=r("ExternalLinkIcon");return i(),s("div",null,[d,e("p",null,[t("These base guidelines (if not specified otherwise) apply to every repository under the "),e("a",c,[u,n(o)]),t(" github organisation. The specific CONTRIBUTING rules of the repository in object also apply. In case of conflicts, those last ones have the priority.")]),p,e("ul",null,[e("li",null,[t("If you are unsure about anything or need guidance, you can always reach out the maintainers on "),e("a",b,[t("Discord or IRC"),n(o)]),t(".")])]),f,e("ul",null,[m,g,_,y,e("li",null,[t("Informal conversations are great (e.g. on Discord), but once a problem, feature request etc is outlined, opening an issue formalizing it is the most important thing you can do to help this information flow. "),e("ul",null,[e("li",null,[t("Open an issue in the related repository. If you don't know where it's better suited, "),e("a",v,[t("ask for help"),n(o)]),t(".")]),w])])]),k,e("p",null,[e("a",R,[t("1"),n(o)])]),x,T,I,P,B,e("p",null,[e("a",A,[t("Homepage"),n(o)]),t(" - "),e("a",H,[t("Repository"),n(o)])]),q,D,G,e("p",null,[e("a",N,[t("Homepage"),n(o)]),t(" - "),e("a",S,[t("Repository"),n(o)]),t(" - "),e("a",C,[t("Beginner issues"),n(o)])]),j,E,V,e("p",null,[e("a",F,[t("Homepage"),n(o)]),t(" - "),e("a",M,[t("Repository"),n(o)]),t(" - "),e("a",O,[t("Beginner issues"),n(o)])]),W,J,K,L,e("p",null,[e("a",U,[t("Homepage"),n(o)]),t(" - "),e("a",z,[t("Repository (backend)"),n(o)]),t(" - "),e("a",Y,[t("Repository (frontend)"),n(o)])]),Q,X,Z,e("p",null,[e("a",$,[t("Homepage"),n(o)]),t(" - "),e("a",ee,[t("Repository"),n(o)]),t(" - "),e("a",te,[t("Beginner issues"),n(o)])])])}const ie=a(h,[["render",oe],["__file","contributing.html.vue"]]);export{ie as default}; diff --git a/assets/deadcscroll.html-b652ecd6.js b/assets/deadcscroll.html-fd3e6a11.js similarity index 99% rename from assets/deadcscroll.html-b652ecd6.js rename to assets/deadcscroll.html-fd3e6a11.js index 801a50a..72c3e03 100644 --- a/assets/deadcscroll.html-b652ecd6.js +++ b/assets/deadcscroll.html-fd3e6a11.js @@ -1,4 +1,4 @@ -import{_ as i,r as o,o as r,c as l,a as t,b as e,d as n,e as s}from"./app-19015fbd.js";const d="/deadcscroll/gif//xsine.gif",h="/deadcscroll/gif//ysine.gif",c="/deadcscroll/gif//xysine.gif",u="/deadcscroll/gif//smearon.gif",f="/deadcscroll/gif//smearoff.gif",p="/deadcscroll/gif//rollon.gif",m="/deadcscroll/gif//rolloff.gif",b={},g=t("h1",{id:"dead-c-scroll",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#dead-c-scroll","aria-hidden":"true"},"#"),e(" Dead C Scroll")],-1),v=t("p",null,"Written by Bob.",-1),w=t("hr",null,null,-1),y=t("p",null,"An assembly tutorial for Game Boy showing how the scroll registers can be exploited to create some nice and interesting effects.",-1),k={href:"https://github.com/gbdev/gbdev.github.io/tree/dev/website/.vuepress/public/deadcscroll",target:"_blank",rel:"noopener noreferrer"},x=s(`

    Introducing the registers

    SCY ($FF42)/SCX ($FF43)

    The SCY/SCX registers have a simple purpose: specify the coordinate of the screen's top-left pixel (or view, if you prefer) somewhere on the 256x256 pixel background map. This is really handy for certain kinds of games like platformers or top-down racing games (though there are LOTS of other kinds of games that benefit from this) where the view is the 'camera' and its position is set once per frame.

    When you don't require scrolling, and when your cart boots, SCY/SCX is typically set to 0,0. When a screen is displayed, it appears normally even though you only set the values once. This is because as the screen draws, the PPU automatically adds the value in LY ($FF44) to the value in SCY in order to know what row of pixels to draw.

    SCY value (set once)
    +import{_ as i,r as o,o as r,c as l,a as t,b as e,d as n,e as s}from"./app-821120ad.js";const d="/deadcscroll/gif//xsine.gif",h="/deadcscroll/gif//ysine.gif",c="/deadcscroll/gif//xysine.gif",u="/deadcscroll/gif//smearon.gif",f="/deadcscroll/gif//smearoff.gif",p="/deadcscroll/gif//rollon.gif",m="/deadcscroll/gif//rolloff.gif",b={},g=t("h1",{id:"dead-c-scroll",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#dead-c-scroll","aria-hidden":"true"},"#"),e(" Dead C Scroll")],-1),v=t("p",null,"Written by Bob.",-1),w=t("hr",null,null,-1),y=t("p",null,"An assembly tutorial for Game Boy showing how the scroll registers can be exploited to create some nice and interesting effects.",-1),k={href:"https://github.com/gbdev/gbdev.github.io/tree/dev/website/.vuepress/public/deadcscroll",target:"_blank",rel:"noopener noreferrer"},x=s(`

    Introducing the registers

    SCY ($FF42)/SCX ($FF43)

    The SCY/SCX registers have a simple purpose: specify the coordinate of the screen's top-left pixel (or view, if you prefer) somewhere on the 256x256 pixel background map. This is really handy for certain kinds of games like platformers or top-down racing games (though there are LOTS of other kinds of games that benefit from this) where the view is the 'camera' and its position is set once per frame.

    When you don't require scrolling, and when your cart boots, SCY/SCX is typically set to 0,0. When a screen is displayed, it appears normally even though you only set the values once. This is because as the screen draws, the PPU automatically adds the value in LY ($FF44) to the value in SCY in order to know what row of pixels to draw.

    SCY value (set once)
     │
     │      screen
     │     ┌───────┐
    diff --git a/assets/dma_hijacking.html-e111a616.js b/assets/dma_hijacking.html-8813f285.js
    similarity index 99%
    rename from assets/dma_hijacking.html-e111a616.js
    rename to assets/dma_hijacking.html-8813f285.js
    index 748bdc5..584ef8b 100644
    --- a/assets/dma_hijacking.html-e111a616.js
    +++ b/assets/dma_hijacking.html-8813f285.js
    @@ -1,4 +1,4 @@
    -import{_ as s,r as o,o as r,c as d,a as i,b as e,d as n,e as a}from"./app-19015fbd.js";const l={},c=i("h1",{id:"dma-hijacking",tabindex:"-1"},[i("a",{class:"header-anchor",href:"#dma-hijacking","aria-hidden":"true"},"#"),e(" DMA Hijacking")],-1),h={href:"https://github.com/ISSOtm",target:"_blank",rel:"noopener noreferrer"},u=a('

    TARGET AUDIENCE

    Unlike most resources here, this guide is not very useful to developers or even ROM hackers, but rather to glitch-hunters and exploit developers.


    What is it?

    OAM DMA hijacking is a simple technique that allows you to run custom code in most GB/SGB/CGB games, provided you have an ACE exploit.

    One would be quick to point out that if you have an ACE exploit, you can already execute custom code. So then, what is the point? It's that code ran through DMA Hijacking will be run on every game frame (for most games, at least).

    How is it done?

    ',6),m={href:"https://gbdev.io/pandocs/OAM",target:"_blank",rel:"noopener noreferrer"},p=i("em",null,"OAM DMA",-1),v={href:"https://gbdev.io/pandocs/OAM_DMA_Transfer",target:"_blank",rel:"noopener noreferrer"},b={href:"https://gbdev.io/pandocs/Rendering#objects",target:"_blank",rel:"noopener noreferrer"},g=i("p",null,[e("Interestingly, most games only copy the routine when starting up, and then execute it on every subsequent frame. But, "),i("em",null,"if we modified that routine while the game is running"),e(", then the game will happily run the customized routine!")],-1),f=i("h3",{id:"patching-the-code",tabindex:"-1"},[i("a",{class:"header-anchor",href:"#patching-the-code","aria-hidden":"true"},"#"),e(" Patching the code")],-1),w={href:"https://rgbds.gbdev.io/docs/rgbasm.5",target:"_blank",rel:"noopener noreferrer"},y={href:"https://github.com/gbdev/hardware.inc",target:"_blank",rel:"noopener noreferrer"},k=i("code",null,"hardware.inc",-1),A=a(`
        ld a, HIGH(OAMBuffer)
    +import{_ as s,r as o,o as r,c as d,a as i,b as e,d as n,e as a}from"./app-821120ad.js";const l={},c=i("h1",{id:"dma-hijacking",tabindex:"-1"},[i("a",{class:"header-anchor",href:"#dma-hijacking","aria-hidden":"true"},"#"),e(" DMA Hijacking")],-1),h={href:"https://github.com/ISSOtm",target:"_blank",rel:"noopener noreferrer"},u=a('

    TARGET AUDIENCE

    Unlike most resources here, this guide is not very useful to developers or even ROM hackers, but rather to glitch-hunters and exploit developers.


    What is it?

    OAM DMA hijacking is a simple technique that allows you to run custom code in most GB/SGB/CGB games, provided you have an ACE exploit.

    One would be quick to point out that if you have an ACE exploit, you can already execute custom code. So then, what is the point? It's that code ran through DMA Hijacking will be run on every game frame (for most games, at least).

    How is it done?

    ',6),m={href:"https://gbdev.io/pandocs/OAM",target:"_blank",rel:"noopener noreferrer"},p=i("em",null,"OAM DMA",-1),v={href:"https://gbdev.io/pandocs/OAM_DMA_Transfer",target:"_blank",rel:"noopener noreferrer"},b={href:"https://gbdev.io/pandocs/Rendering#objects",target:"_blank",rel:"noopener noreferrer"},g=i("p",null,[e("Interestingly, most games only copy the routine when starting up, and then execute it on every subsequent frame. But, "),i("em",null,"if we modified that routine while the game is running"),e(", then the game will happily run the customized routine!")],-1),f=i("h3",{id:"patching-the-code",tabindex:"-1"},[i("a",{class:"header-anchor",href:"#patching-the-code","aria-hidden":"true"},"#"),e(" Patching the code")],-1),w={href:"https://rgbds.gbdev.io/docs/rgbasm.5",target:"_blank",rel:"noopener noreferrer"},y={href:"https://github.com/gbdev/hardware.inc",target:"_blank",rel:"noopener noreferrer"},k=i("code",null,"hardware.inc",-1),A=a(`
        ld a, HIGH(OAMBuffer)
         ldh [rDMA], a  ; $FF46
         ld a, 40
     DMALoop:
    diff --git a/assets/donate.html-ade8e922.js b/assets/donate.html-721556c4.js
    similarity index 98%
    rename from assets/donate.html-ade8e922.js
    rename to assets/donate.html-721556c4.js
    index 739ed53..24f5f3b 100644
    --- a/assets/donate.html-ade8e922.js
    +++ b/assets/donate.html-721556c4.js
    @@ -1 +1 @@
    -import{_ as s,r,o as i,c,a as o,b as e,d as n,e as a}from"./app-19015fbd.js";const l={},d=o("h1",{id:"donations-and-bounties",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#donations-and-bounties","aria-hidden":"true"},"#"),e(" Donations and bounties")],-1),h=o("h2",{id:"donate",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#donate","aria-hidden":"true"},"#"),e(" Donate")],-1),u={href:"https://opencollective.com/gbdev",target:"_blank",rel:"noopener noreferrer"},p={href:"https://github.com/sponsors/gbdev",target:"_blank",rel:"noopener noreferrer"},b={class:"custom-container tip"},m=o("p",{class:"custom-container-title"},"WHY OPENCOLLECTIVE",-1),f={href:"https://github.com/gbdev",target:"_blank",rel:"noopener noreferrer"},g=o("em",null,"informal",-1),_={href:"https://www.oscollective.org/",target:"_blank",rel:"noopener noreferrer"},y={href:"https://thesocialchangeagency.org/blog/what-is-fiscal-hosting/",target:"_blank",rel:"noopener noreferrer"},v={href:"https://opencollective.com/gbdev/projects",target:"_blank",rel:"noopener noreferrer"},w=a('

    Donations are subject to a 10% fee from our Open Collective host (Open Source Collective) plus a variable fee from the payment processor (Wise).

    Money collected on GitHub sponsors are paid out by GitHub to our Open Collective at the end of each month.

    What do we spend the money on?

    We mostly use the money to:

    • Organize events (such as the gbcompo21) and give prizes,
    • Fund maintainers and contributors to our repositories,
    • Put bounties on issues on our repositories,
    • Donate back to some of the packages we use,
    • Pay servers and domains.
    ',5),k={href:"https://opencollective.com/gbdev",target:"_blank",rel:"noopener noreferrer"},x=a('

    Sponsoring

    If you have a company and you are interested in being highlighted on some of our webpages and channels, we have sponsorship tiers starting at 50$/month. Get in touch at sponsors@gbdev.io to understand if this could be for you. We are interested in hearing how our software is helping your business etc.

    Sponsorships are evaluated on a case-to-case basis and only be accepted if we feel like our core values are compatible and the relationship can last in the long term with beneficial effect for both parties.

    Bounties

    Sometimes, we may assign a bounty to an Issue. Labels such as bounty-25$, bounty-50$, bounty-100$ are used to specify the amount. If you wish to work on a issue with a bounty attached, it's a good measure to comment on the issue asking for it to be assigned to you*.

    If you send a Pull Request fixing that issue and this work gets merged, you will be able to claim this issue.

    Bounties are paid from our OpenCollective: submit an expense mentioning the Issue you worked on and make sure to use your GitHub email (or the one you authored the git commit with) when creating an account on OpenCollective. Wire transfers and PayPal are supported**.

    Details are generally verified in 24-48 hours. Payments are then processed by our Open Collective host a couple of times per week.

    TAX CONSIDERATIONS

    Make sure to check the tax regulations of your country and properly declare the bounties received. We're not tax consultants and we cannot help with that.

    * In case of inactivity we may remove the assignment to you or let someone else who submitted a PR claim the bounty.

    ** Our Open Collective host uses Wise as the payment processor so the countries supported for the bank transfers depends on them.

    ',11);function O(C,I){const t=r("ExternalLinkIcon");return i(),c("div",null,[d,h,o("p",null,[e("You can donate on our "),o("a",u,[e("Open Collective"),n(t)]),e(" or on "),o("a",p,[e("GitHub sponsors"),n(t)]),e(". You can send a one-time donation of any amount or join the collective as backer, donating monthly.")]),o("div",b,[m,o("p",null,[e("The "),o("a",f,[e("gbdev"),n(t)]),e(" organisation is an "),g,e(" collective of individuals. As such, we are not able to hold any fund in our accounts. Instead, the US based non-profit "),o("a",_,[e("Open Source Collective"),n(t)]),e(" is our "),o("a",y,[e("fiscal host"),n(t)]),e(", providing us the financial and legal infrastructure to receive donations and spend money.")])]),o("p",null,[e("It's also possible to donate specifically "),o("a",v,[e("towards a project"),n(t)]),e(" under our umbrella. We'll do our best to honour this preference.")]),w,o("p",null,[e("Expenses are tracked "),o("a",k,[e("here"),n(t)]),e(".")]),x])}const W=s(l,[["render",O],["__file","donate.html.vue"]]);export{W as default}; +import{_ as s,r,o as i,c,a as o,b as e,d as n,e as a}from"./app-821120ad.js";const l={},d=o("h1",{id:"donations-and-bounties",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#donations-and-bounties","aria-hidden":"true"},"#"),e(" Donations and bounties")],-1),h=o("h2",{id:"donate",tabindex:"-1"},[o("a",{class:"header-anchor",href:"#donate","aria-hidden":"true"},"#"),e(" Donate")],-1),u={href:"https://opencollective.com/gbdev",target:"_blank",rel:"noopener noreferrer"},p={href:"https://github.com/sponsors/gbdev",target:"_blank",rel:"noopener noreferrer"},b={class:"custom-container tip"},m=o("p",{class:"custom-container-title"},"WHY OPENCOLLECTIVE",-1),f={href:"https://github.com/gbdev",target:"_blank",rel:"noopener noreferrer"},g=o("em",null,"informal",-1),_={href:"https://www.oscollective.org/",target:"_blank",rel:"noopener noreferrer"},y={href:"https://thesocialchangeagency.org/blog/what-is-fiscal-hosting/",target:"_blank",rel:"noopener noreferrer"},v={href:"https://opencollective.com/gbdev/projects",target:"_blank",rel:"noopener noreferrer"},w=a('

    Donations are subject to a 10% fee from our Open Collective host (Open Source Collective) plus a variable fee from the payment processor (Wise).

    Money collected on GitHub sponsors are paid out by GitHub to our Open Collective at the end of each month.

    What do we spend the money on?

    We mostly use the money to:

    • Organize events (such as the gbcompo21) and give prizes,
    • Fund maintainers and contributors to our repositories,
    • Put bounties on issues on our repositories,
    • Donate back to some of the packages we use,
    • Pay servers and domains.
    ',5),k={href:"https://opencollective.com/gbdev",target:"_blank",rel:"noopener noreferrer"},x=a('

    Sponsoring

    If you have a company and you are interested in being highlighted on some of our webpages and channels, we have sponsorship tiers starting at 50$/month. Get in touch at sponsors@gbdev.io to understand if this could be for you. We are interested in hearing how our software is helping your business etc.

    Sponsorships are evaluated on a case-to-case basis and only be accepted if we feel like our core values are compatible and the relationship can last in the long term with beneficial effect for both parties.

    Bounties

    Sometimes, we may assign a bounty to an Issue. Labels such as bounty-25$, bounty-50$, bounty-100$ are used to specify the amount. If you wish to work on a issue with a bounty attached, it's a good measure to comment on the issue asking for it to be assigned to you*.

    If you send a Pull Request fixing that issue and this work gets merged, you will be able to claim this issue.

    Bounties are paid from our OpenCollective: submit an expense mentioning the Issue you worked on and make sure to use your GitHub email (or the one you authored the git commit with) when creating an account on OpenCollective. Wire transfers and PayPal are supported**.

    Details are generally verified in 24-48 hours. Payments are then processed by our Open Collective host a couple of times per week.

    TAX CONSIDERATIONS

    Make sure to check the tax regulations of your country and properly declare the bounties received. We're not tax consultants and we cannot help with that.

    * In case of inactivity we may remove the assignment to you or let someone else who submitted a PR claim the bounty.

    ** Our Open Collective host uses Wise as the payment processor so the countries supported for the bank transfers depends on them.

    ',11);function O(C,I){const t=r("ExternalLinkIcon");return i(),c("div",null,[d,h,o("p",null,[e("You can donate on our "),o("a",u,[e("Open Collective"),n(t)]),e(" or on "),o("a",p,[e("GitHub sponsors"),n(t)]),e(". You can send a one-time donation of any amount or join the collective as backer, donating monthly.")]),o("div",b,[m,o("p",null,[e("The "),o("a",f,[e("gbdev"),n(t)]),e(" organisation is an "),g,e(" collective of individuals. As such, we are not able to hold any fund in our accounts. Instead, the US based non-profit "),o("a",_,[e("Open Source Collective"),n(t)]),e(" is our "),o("a",y,[e("fiscal host"),n(t)]),e(", providing us the financial and legal infrastructure to receive donations and spend money.")])]),o("p",null,[e("It's also possible to donate specifically "),o("a",v,[e("towards a project"),n(t)]),e(" under our umbrella. We'll do our best to honour this preference.")]),w,o("p",null,[e("Expenses are tracked "),o("a",k,[e("here"),n(t)]),e(".")]),x])}const W=s(l,[["render",O],["__file","donate.html.vue"]]);export{W as default}; diff --git a/assets/gbcompo21.html-dc2cba05.js b/assets/gbcompo21.html-30e84a39.js similarity index 99% rename from assets/gbcompo21.html-dc2cba05.js rename to assets/gbcompo21.html-30e84a39.js index ebd9c49..c45f5d9 100644 --- a/assets/gbcompo21.html-dc2cba05.js +++ b/assets/gbcompo21.html-30e84a39.js @@ -1 +1 @@ -import{_ as a,r as n,o as i,c as s,a as t,b as e,d as o,e as d}from"./app-19015fbd.js";const l="/images/square.png",h="/images/incube8_logo_white_bg.png",c="/images/sponsor_greenboygames_50h.png",u="/images/sponsor_catskull_50h.png",p="/images/mega_cat_studios_hq.png",g="/images/bitmap_soft.png",m="/images/1stpress_2.png",b="/images/gbstudio_logo.png",f="/images/RBIconSmallSquare.jpg",_={},y=t("h1",{id:"game-boy-competition-2021",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#game-boy-competition-2021","aria-hidden":"true"},"#"),e(" Game Boy Competition 2021")],-1),w=t("p",{align:"center"},[t("img",{src:l,style:{width:"50%"}})],-1),k=t("em",null,"gbcompo21",-1),B={href:"https://itch.io/jam/gbcompo21",target:"_blank",rel:"noopener noreferrer"},G=t("p",null,[e("Create original games, demos, homebrews tools and music for the original Game Boy (Color) and compete for glory (and up to "),t("img",{src:"https://shields.io/endpoint?url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg%26cellRange%3DI11",alt:"$3000+"}),e(" in prizes)!")],-1),v=t("h2",{id:"results",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#results","aria-hidden":"true"},"#"),e(" Results")],-1),C=t("a",{href:"#full-results"},"here",-1),S={href:"https://hh.gbdev.io/games/gbcompo21",target:"_blank",rel:"noopener noreferrer"},M={href:"https://itch.io/jam/gbcompo21/entries",target:"_blank",rel:"noopener noreferrer"},R=d('

    Games:

    1. Unearthed
    2. Rhythm Land
    3. Shock Lobster
    4. Dango Dash
    5. Rebound
    6. Core Machina
    7. Sushi Nights
    8. MARLA and the Elemental Rings
    9. Porklike GB
    10. GB Corp
    11. Dawn Will Come
    12. <corrib75>
    13. El Dueloroso
    14. Glory Hunter
    15. Renegade rush
    16. Fix My Heart
    17. GBCspelunky

    Winning entry for the Music category: Zilogized

    Winning entry for the Tools category: Brainfox

    Entries

    ',5),x={href:"https://itch.io/jam/gbcompo21/entries",target:"_blank",rel:"noopener noreferrer"},D={href:"https://github.com/gbdev/gbcompo21/releases/tag/gbcompo21_entries",target:"_blank",rel:"noopener noreferrer"},T=t("h2",{id:"sponsors",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#sponsors","aria-hidden":"true"},"#"),e(" Sponsors")],-1),A=t("div",{class:"custom-container warning"},[t("p",{class:"custom-container-title"},"WARNING"),t("p",null,[e("Donations to the prize pool are now "),t("strong",null,"closed"),e(", no more are being accepted.")])],-1),O={href:"https://github.com/sponsors/avivace?editing=true&frequency=one-time",target:"_blank",rel:"noopener noreferrer"},L=d('

    Incube 8 Games

    Greenboy GamesCatskull electronicsMega Cat StudiosBitmap Soft1st Press Games

    Donations from Individuals

    ',3),H={href:"https://github.com/untoxa",target:"_blank",rel:"noopener noreferrer"},I={href:"https://github.com/Nicolastriplec",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/tbsp",target:"_blank",rel:"noopener noreferrer"},z={href:"https://github.com/chrismaltby",target:"_blank",rel:"noopener noreferrer"},F={href:"https://github.com/willbr",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/oshf",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/Sanqui",target:"_blank",rel:"noopener noreferrer"},q=d('

    Partners

    GB Studio CentralGB Studio RetroBreak


    Community

    Come join us on Discord or others for help getting started, and head over to gbdev.io for useful links & resources!

    We'd love to hear from participants, share your progress on Twitter using the #gbcompo hashtag and join the conversation the on Discord #compo-chat channel!

    Resources

    Here a curated list tools and documentaiton to get you started.

    ',8),P={href:"https://gbdev.io/pandocs",target:"_blank",rel:"noopener noreferrer"},W={href:"https://gbdev.io/list",target:"_blank",rel:"noopener noreferrer"},U={href:"https://gbdev.io/list.html#software-development",target:"_blank",rel:"noopener noreferrer"},J={href:"https://gbdev.io/guides/tools.html#languages",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},V={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},X={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},tt=t("li",null,[t("a",{href:""},"Dedicated Discord")],-1),et={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},rt={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},dt=t("h2",{id:"prize-pool",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prize-pool","aria-hidden":"true"},"#"),e(" Prize pool")],-1),at=t("img",{src:"https://shields.io/endpoint?url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg%26cellRange%3DI11",alt:"$3000+"},null,-1),nt={href:"https://docs.google.com/spreadsheets/d/196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg",target:"_blank",rel:"noopener noreferrer"},it=d('

    Entries will compete in 4 separate categories and 4 rankings will be drawn up. Based on these leaderboards, the top entries will be awarded as follows:

    • Best games (80% of the prize pool)
      • The best 5 games will get a prize.
      • The best 3 OSS games will get an additional prize (can overlap)
    • Best homebrew/tool (1) (running on a GB/GBC)
    • Best music cartridge (1)
    • Best demo (1) (demoscene style demos)

    The rankings are decided according to the JUDGING criteria.

    Open Source Bonus

    ',4),st={href:"https://choosealicense.com/",target:"_blank",rel:"noopener noreferrer"},lt=t("strong",null,"20%",-1),ht=t("p",null,[t("em",null,"Prize tiers are still work in progress, expect changes. Money prizes are subject to fees and conversions. They may be delivered as gift cards of your choice.")],-1),ct=t("h2",{id:"rules",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#rules","aria-hidden":"true"},"#"),e(" Rules")],-1),ut=d("
  • Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown or HTML file format (e.g. game manual).

  • The ROM file will be tested on real hardware (usually a DMG or a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.

  • GBC features are allowed.

  • SGB features are allowed. The entries will be evaluated mainly on Game Boy (Color). You can use SGB features, but don't rely on them as main features for your entry.

  • Teams are allowed (award will be split).

  • The competition is focused on games, but you are allowed to submit homebrew tools, demoscene style demos and music cartridges. There may be special category prizes for those. There are no preferred themes.

  • ROM Hacks are not allowed.

  • NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.

  • You can submit more than one entry. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).

  • Judges can submit entries, but they are not eligible for prizes.

  • Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:

    1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
    2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
    3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
    4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
  • Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.

  • As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

  • ",13),pt=t("strong",null,"additional",-1),gt={href:"https://github.com/gbdev/gbcompo21/issues/3",target:"_blank",rel:"noopener noreferrer"},mt={href:"https://www.gnu.org/licenses/license-list.en.html",target:"_blank",rel:"noopener noreferrer"},bt=t("li",null,[t("p",null,"The entry must be submitted on the itch.io jam page.")],-1),ft=t("p",null,[e("Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding."),t("br"),e(" Examples of things that are "),t("strong",null,"allowed:")],-1),_t=t("li",null,"A brand new game using your own (or any) existing game engine.",-1),yt=t("li",null,"A remake of your (or someone else's) game for a different platform, but with new code and assets.",-1),wt=t("li",null,"A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).",-1),kt={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Bt=t("li",null,"Asset packs for art and music are ok if the licensing permits. Be sure to make note of what is being reused and under what terms. Use of pre-made assets (vs original ones) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).",-1),Gt=t("p",null,[e("Examples of things that are "),t("strong",null,"not allowed:")],-1),vt=t("ul",null,[t("li",null,"A project you've been working on for months."),t("li",null,"An update/patch for a game you already released publicly.")],-1),Ct=t("li",null,[t("p",null,"The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).")],-1),St=t("li",null,[t("p",null,"Multiple submissions are allowed.")],-1),Mt=t("li",null,[t("p",null,"If your submission contains text that isn't available in English, some judges might not be able to read that text, and they will judge accordingly.")],-1),Rt=d('

    Judging

    Judges will evaluate submissions using the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?

    Criteria applicability:

    • Games are ranked according to all the listed criteria
    • demos on 2,3,4,5
    • Music entries on 5
    • Homebrew/tools entries on 2 and 1 (with gameplay being UX)

    The leaderboards are computed by averaging the "Overall" score.

    FAQ

    Something not clear? Open an issue or join the discussion on Discord.

    Credits

    Special thanks to:

    ',10),xt={href:"https://github.com/avivace",target:"_blank",rel:"noopener noreferrer"},Dt={href:"https://proximitysound.com",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://github.com/untoxa",target:"_blank",rel:"noopener noreferrer"},At={href:"https://github.com/bbbbbr",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/Sanqui",target:"_blank",rel:"noopener noreferrer"},Lt={href:"https://github.com/aaaaaa123456789",target:"_blank",rel:"noopener noreferrer"},Ht={href:"https://github.com/ISSOtm",target:"_blank",rel:"noopener noreferrer"},It={href:"https://github.com/Hacktix",target:"_blank",rel:"noopener noreferrer"},Et=t("li",null,"Judges: ISSOtm, avivace, Sanqui, Asobi.tech, untoxa, Veund, duodreamer",-1),zt=d('

    Full results

    Music

    Winner: Zilogized by Kabcorp

    Tools

    Winner: BrainFox by Yprit

    Overall

    Sorted by "Overall" score, only the shortlisted entries were ranked by judges.

    NameGameplayTechnicalOriginalityGraphicsAudioOverall
    Unearthed4.293.864.864.433.294.15
    Rhythm Land3.713.714.143.864.574.0
    Shock Lobster4.04.294.713.713.143.97
    Dango Dash3.863.293.864.04.573.92
    Rebound4.03.863.573.714.293.89
    Core Machina3.143.434.04.574.143.86
    Sushi Nights3.863.864.03.713.713.83
    MARLA and the Elemental Rings3.293.863.434.03.863.69
    Porklike GB4.04.03.143.573.713.68
    GB Corp.3.143.864.573.143.293.6
    Dawn Will Come2.713.144.294.293.433.57
    <corrib75>3.713.863.143.713.293.54
    El Dueloroso3.293.573.863.03.293.4
    Glory Hunters3.433.143.433.573.433.4
    Renegade rush3.573.573.293.03.293.34
    Fix My Heart3.712.863.572.712.713.11
    GBCspelunky3.03.712.433.712.573.08

    Gameplay

    NameGameplay
    Unearthed4.29
    Rebound4.0
    Porklike GB4.0
    Shock Lobster4.0
    Dango Dash3.86
    Sushi Nights3.86
    Rhythm Land3.71
    <corrib75>3.71
    Fix My Heart3.71
    Renegade rush3.57
    Glory Hunters3.43
    MARLA and the Elemental Rings3.29
    El Dueloroso3.29
    Core Machina3.14
    GB Corp.3.14
    GBCspelunky3.0
    Dawn Will Come2.71

    Technical

    NameTechnical
    Shock Lobster4.29
    Porklike GB4.0
    Sushi Nights3.86
    <corrib75>3.86
    GB Corp.3.86
    MARLA and the Elemental Rings3.86
    Unearthed3.86
    Rebound3.86
    Rhythm Land3.71
    GBCspelunky3.71
    El Dueloroso3.57
    Renegade rush3.57
    Core Machina3.43
    Dango Dash3.29
    Dawn Will Come3.14
    Glory Hunters3.14
    Fix My Heart2.86

    Originality

    NameOriginality
    Unearthed4.86
    Shock Lobster4.71
    GB Corp.4.57
    Dawn Will Come4.29
    Rhythm Land4.14
    Core Machina4.0
    Sushi Nights4.0
    Dango Dash3.86
    El Dueloroso3.86
    Rebound3.57
    Fix My Heart3.57
    MARLA and the Elemental Rings3.43
    Glory Hunters3.43
    Renegade rush3.29
    Porklike GB3.14
    <corrib75>3.14
    GBCspelunky2.43

    Graphics

    NameGraphics
    Core Machina4.57
    Unearthed4.43
    Dawn Will Come4.29
    Dango Dash4.0
    MARLA and the Elemental Rings4.0
    Rhythm Land3.86
    <corrib75>3.71
    GBCspelunky3.71
    Rebound3.71
    Shock Lobster3.71
    Sushi Nights3.71
    Glory Hunters3.57
    Porklike GB3.57
    GB Corp.3.14
    El Dueloroso3.0
    Renegade rush3.0
    Fix My Heart2.71

    Audio

    NameAudio
    Dango Dash4.57
    Rhythm Land4.57
    Rebound4.29
    Core Machina4.14
    MARLA and the Elemental Rings3.86
    Porklike GB3.71
    Sushi Nights3.71
    Glory Hunters3.43
    Dawn Will Come3.43
    El Dueloroso3.29
    Renegade rush3.29
    Unearthed3.29
    <corrib75>3.29
    GB Corp.3.29
    Shock Lobster3.14
    Fix My Heart2.71
    GBCspelunky2.57
    ',18);function Ft(Nt,jt){const r=n("ExternalLinkIcon");return i(),s("div",null,[y,w,t("blockquote",null,[t("p",null,[k,e(" was a game jam run from July 1 to October 1 2021 and it was hosted on "),t("a",B,[e("itch.io/jam/gbcompo21"),o(r)]),e(".")])]),G,v,t("p",null,[e("Full leaderboards are available "),C,e(". Top rated entries are playable "),t("a",S,[e("here"),o(r)]),e(" while the complete list can be found on "),t("a",M,[e("Itch.io"),o(r)]),e(".")]),R,t("p",null,[e("The complete set of entries is available to browse on "),t("a",x,[e("Itch.io"),o(r)]),e(" or can be downloaded as a zip file from "),t("a",D,[e("GitHub"),o(r)]),e(".")]),T,A,t("p",null,[e("The entire prize pool is community funded. Donate or sponsor the competition through "),t("a",O,[e("GitHub sponsors"),o(r)]),e(".")]),L,t("p",null,[t("a",H,[e("Toxa"),o(r)]),e(", "),t("a",I,[e("Carles Castillo"),o(r)]),e(", "),t("a",E,[e("Dave VanEe"),o(r)]),e(", "),t("a",z,[e("Chris Maltby"),o(r)]),e(", "),t("a",F,[e("William Bettridge-Radford"),o(r)]),e(", "),t("a",N,[e("Josh Frisby"),o(r)]),e(", "),t("a",j,[e("Sanqui"),o(r)])]),q,t("ul",null,[t("li",null,[e("General links "),t("ul",null,[t("li",null,[t("a",P,[e("Pan Docs"),o(r)]),e(", Game Boy technical documentation")]),t("li",null,[t("a",W,[e("Awesome Game Boy Development list of resources"),o(r)]),t("ul",null,[t("li",null,[e("Especially relevant is the "),t("a",U,[e('"Software Development"'),o(r)]),e(" paragraph")])])]),t("li",null,[t("a",J,[e("How to choose between C and ASM for GB?"),o(r)])])])]),t("li",null,[t("a",Z,[e("RGBDS"),o(r)]),e(" (ASM language) "),t("ul",null,[t("li",null,[t("a",V,[e("GB ASM Tutorial"),o(r)])])])]),t("li",null,[t("a",K,[e("GBDK"),o(r)]),e(" (C language) "),t("ul",null,[t("li",null,[t("a",Y,[e("API docs: Getting Started"),o(r)])]),t("li",null,[t("a",Q,[e("Examples"),o(r)])]),t("li",null,[t("a",X,[e("Docs, links and tools"),o(r)])]),t("li",null,[t("a",$,[e("ZGB: a game engine using GBDK"),o(r)])]),tt])]),t("li",null,[t("a",et,[e("GBStudio"),o(r)]),e(" (no coding required) "),t("ul",null,[t("li",null,[t("a",rt,[e("Resources to get started"),o(r)])]),t("li",null,[t("a",ot,[e("Dedicated Discord"),o(r)])])])])]),dt,t("p",null,[e("The current prize pool is "),at,e(" and will be split according to "),t("a",nt,[e("this document"),o(r)]),e(".")]),it,t("p",null,[e("If you publish your game source code and assets on a public repository (e.g. GitHub) under "),t("a",st,[e("an open source license"),o(r)]),e(" (GPL, MIT, Apache, CC0...) you get "),lt,e(" more of the prize as a bonus!")]),ht,ct,t("ol",null,[ut,t("li",null,[t("p",null,[e("Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 15) are eligible for "),pt,e(' prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. See '),t("a",gt,[e("this issue"),o(r)]),e(" for further details.")])]),t("li",null,[t("p",null,[e('To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed '),t("a",mt,[e("here"),o(r)]),e(" is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following istructions.")])]),bt,t("li",null,[ft,t("ul",null,[_t,yt,wt,t("li",null,[e("Using templates, tutorial code as starting point (when they're license allow to do so, e.g. "),t("a",kt,[e("gb-boilerplate"),o(r)]),e(")")]),Bt]),Gt,vt]),Ct,St,Mt]),Rt,t("ul",null,[t("li",null,[e("The organizers, from all over the gbdev community: "),t("a",xt,[e("avivace"),o(r)]),e(", "),t("a",Dt,[e("Proximity Sound"),o(r)]),e(", "),t("a",Tt,[e("untoxa"),o(r)]),e(", "),t("a",At,[e("bbbbbr"),o(r)]),e(", "),t("a",Ot,[e("Sanqui"),o(r)]),e(", "),t("a",Lt,[e("aaaaaa123456789"),o(r)]),e(", "),t("a",Ht,[e("ISSOtm"),o(r)])]),t("li",null,[t("a",It,[e("Optix"),o(r)]),e(", for the awesome logo and the other graphical assets")]),Et]),zt])}const Pt=a(_,[["render",Ft],["__file","gbcompo21.html.vue"]]);export{Pt as default}; +import{_ as a,r as n,o as i,c as s,a as t,b as e,d as o,e as d}from"./app-821120ad.js";const l="/images/square.png",h="/images/incube8_logo_white_bg.png",c="/images/sponsor_greenboygames_50h.png",u="/images/sponsor_catskull_50h.png",p="/images/mega_cat_studios_hq.png",g="/images/bitmap_soft.png",m="/images/1stpress_2.png",b="/images/gbstudio_logo.png",f="/images/RBIconSmallSquare.jpg",_={},y=t("h1",{id:"game-boy-competition-2021",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#game-boy-competition-2021","aria-hidden":"true"},"#"),e(" Game Boy Competition 2021")],-1),w=t("p",{align:"center"},[t("img",{src:l,style:{width:"50%"}})],-1),k=t("em",null,"gbcompo21",-1),B={href:"https://itch.io/jam/gbcompo21",target:"_blank",rel:"noopener noreferrer"},G=t("p",null,[e("Create original games, demos, homebrews tools and music for the original Game Boy (Color) and compete for glory (and up to "),t("img",{src:"https://shields.io/endpoint?url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg%26cellRange%3DI11",alt:"$3000+"}),e(" in prizes)!")],-1),v=t("h2",{id:"results",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#results","aria-hidden":"true"},"#"),e(" Results")],-1),C=t("a",{href:"#full-results"},"here",-1),S={href:"https://hh.gbdev.io/games/gbcompo21",target:"_blank",rel:"noopener noreferrer"},M={href:"https://itch.io/jam/gbcompo21/entries",target:"_blank",rel:"noopener noreferrer"},R=d('

    Games:

    1. Unearthed
    2. Rhythm Land
    3. Shock Lobster
    4. Dango Dash
    5. Rebound
    6. Core Machina
    7. Sushi Nights
    8. MARLA and the Elemental Rings
    9. Porklike GB
    10. GB Corp
    11. Dawn Will Come
    12. <corrib75>
    13. El Dueloroso
    14. Glory Hunter
    15. Renegade rush
    16. Fix My Heart
    17. GBCspelunky

    Winning entry for the Music category: Zilogized

    Winning entry for the Tools category: Brainfox

    Entries

    ',5),x={href:"https://itch.io/jam/gbcompo21/entries",target:"_blank",rel:"noopener noreferrer"},D={href:"https://github.com/gbdev/gbcompo21/releases/tag/gbcompo21_entries",target:"_blank",rel:"noopener noreferrer"},T=t("h2",{id:"sponsors",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#sponsors","aria-hidden":"true"},"#"),e(" Sponsors")],-1),A=t("div",{class:"custom-container warning"},[t("p",{class:"custom-container-title"},"WARNING"),t("p",null,[e("Donations to the prize pool are now "),t("strong",null,"closed"),e(", no more are being accepted.")])],-1),O={href:"https://github.com/sponsors/avivace?editing=true&frequency=one-time",target:"_blank",rel:"noopener noreferrer"},L=d('

    Incube 8 Games

    Greenboy GamesCatskull electronicsMega Cat StudiosBitmap Soft1st Press Games

    Donations from Individuals

    ',3),H={href:"https://github.com/untoxa",target:"_blank",rel:"noopener noreferrer"},I={href:"https://github.com/Nicolastriplec",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/tbsp",target:"_blank",rel:"noopener noreferrer"},z={href:"https://github.com/chrismaltby",target:"_blank",rel:"noopener noreferrer"},F={href:"https://github.com/willbr",target:"_blank",rel:"noopener noreferrer"},N={href:"https://github.com/oshf",target:"_blank",rel:"noopener noreferrer"},j={href:"https://github.com/Sanqui",target:"_blank",rel:"noopener noreferrer"},q=d('

    Partners

    GB Studio CentralGB Studio RetroBreak


    Community

    Come join us on Discord or others for help getting started, and head over to gbdev.io for useful links & resources!

    We'd love to hear from participants, share your progress on Twitter using the #gbcompo hashtag and join the conversation the on Discord #compo-chat channel!

    Resources

    Here a curated list tools and documentaiton to get you started.

    ',8),P={href:"https://gbdev.io/pandocs",target:"_blank",rel:"noopener noreferrer"},W={href:"https://gbdev.io/list",target:"_blank",rel:"noopener noreferrer"},U={href:"https://gbdev.io/list.html#software-development",target:"_blank",rel:"noopener noreferrer"},J={href:"https://gbdev.io/guides/tools.html#languages",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},V={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},K={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},X={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},$={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},tt=t("li",null,[t("a",{href:""},"Dedicated Discord")],-1),et={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},rt={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},dt=t("h2",{id:"prize-pool",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prize-pool","aria-hidden":"true"},"#"),e(" Prize pool")],-1),at=t("img",{src:"https://shields.io/endpoint?url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg%26cellRange%3DI11",alt:"$3000+"},null,-1),nt={href:"https://docs.google.com/spreadsheets/d/196vIZGLbSk1ewzRnZc7Dy_LJdPQpfJUg-udT4iyBVOg",target:"_blank",rel:"noopener noreferrer"},it=d('

    Entries will compete in 4 separate categories and 4 rankings will be drawn up. Based on these leaderboards, the top entries will be awarded as follows:

    • Best games (80% of the prize pool)
      • The best 5 games will get a prize.
      • The best 3 OSS games will get an additional prize (can overlap)
    • Best homebrew/tool (1) (running on a GB/GBC)
    • Best music cartridge (1)
    • Best demo (1) (demoscene style demos)

    The rankings are decided according to the JUDGING criteria.

    Open Source Bonus

    ',4),st={href:"https://choosealicense.com/",target:"_blank",rel:"noopener noreferrer"},lt=t("strong",null,"20%",-1),ht=t("p",null,[t("em",null,"Prize tiers are still work in progress, expect changes. Money prizes are subject to fees and conversions. They may be delivered as gift cards of your choice.")],-1),ct=t("h2",{id:"rules",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#rules","aria-hidden":"true"},"#"),e(" Rules")],-1),ut=d("
  • Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown or HTML file format (e.g. game manual).

  • The ROM file will be tested on real hardware (usually a DMG or a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.

  • GBC features are allowed.

  • SGB features are allowed. The entries will be evaluated mainly on Game Boy (Color). You can use SGB features, but don't rely on them as main features for your entry.

  • Teams are allowed (award will be split).

  • The competition is focused on games, but you are allowed to submit homebrew tools, demoscene style demos and music cartridges. There may be special category prizes for those. There are no preferred themes.

  • ROM Hacks are not allowed.

  • NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.

  • You can submit more than one entry. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).

  • Judges can submit entries, but they are not eligible for prizes.

  • Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:

    1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
    2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
    3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
    4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
  • Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.

  • As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

  • ",13),pt=t("strong",null,"additional",-1),gt={href:"https://github.com/gbdev/gbcompo21/issues/3",target:"_blank",rel:"noopener noreferrer"},mt={href:"https://www.gnu.org/licenses/license-list.en.html",target:"_blank",rel:"noopener noreferrer"},bt=t("li",null,[t("p",null,"The entry must be submitted on the itch.io jam page.")],-1),ft=t("p",null,[e("Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding."),t("br"),e(" Examples of things that are "),t("strong",null,"allowed:")],-1),_t=t("li",null,"A brand new game using your own (or any) existing game engine.",-1),yt=t("li",null,"A remake of your (or someone else's) game for a different platform, but with new code and assets.",-1),wt=t("li",null,"A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).",-1),kt={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Bt=t("li",null,"Asset packs for art and music are ok if the licensing permits. Be sure to make note of what is being reused and under what terms. Use of pre-made assets (vs original ones) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).",-1),Gt=t("p",null,[e("Examples of things that are "),t("strong",null,"not allowed:")],-1),vt=t("ul",null,[t("li",null,"A project you've been working on for months."),t("li",null,"An update/patch for a game you already released publicly.")],-1),Ct=t("li",null,[t("p",null,"The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).")],-1),St=t("li",null,[t("p",null,"Multiple submissions are allowed.")],-1),Mt=t("li",null,[t("p",null,"If your submission contains text that isn't available in English, some judges might not be able to read that text, and they will judge accordingly.")],-1),Rt=d('

    Judging

    Judges will evaluate submissions using the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?

    Criteria applicability:

    • Games are ranked according to all the listed criteria
    • demos on 2,3,4,5
    • Music entries on 5
    • Homebrew/tools entries on 2 and 1 (with gameplay being UX)

    The leaderboards are computed by averaging the "Overall" score.

    FAQ

    Something not clear? Open an issue or join the discussion on Discord.

    Credits

    Special thanks to:

    ',10),xt={href:"https://github.com/avivace",target:"_blank",rel:"noopener noreferrer"},Dt={href:"https://proximitysound.com",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://github.com/untoxa",target:"_blank",rel:"noopener noreferrer"},At={href:"https://github.com/bbbbbr",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/Sanqui",target:"_blank",rel:"noopener noreferrer"},Lt={href:"https://github.com/aaaaaa123456789",target:"_blank",rel:"noopener noreferrer"},Ht={href:"https://github.com/ISSOtm",target:"_blank",rel:"noopener noreferrer"},It={href:"https://github.com/Hacktix",target:"_blank",rel:"noopener noreferrer"},Et=t("li",null,"Judges: ISSOtm, avivace, Sanqui, Asobi.tech, untoxa, Veund, duodreamer",-1),zt=d('

    Full results

    Music

    Winner: Zilogized by Kabcorp

    Tools

    Winner: BrainFox by Yprit

    Overall

    Sorted by "Overall" score, only the shortlisted entries were ranked by judges.

    NameGameplayTechnicalOriginalityGraphicsAudioOverall
    Unearthed4.293.864.864.433.294.15
    Rhythm Land3.713.714.143.864.574.0
    Shock Lobster4.04.294.713.713.143.97
    Dango Dash3.863.293.864.04.573.92
    Rebound4.03.863.573.714.293.89
    Core Machina3.143.434.04.574.143.86
    Sushi Nights3.863.864.03.713.713.83
    MARLA and the Elemental Rings3.293.863.434.03.863.69
    Porklike GB4.04.03.143.573.713.68
    GB Corp.3.143.864.573.143.293.6
    Dawn Will Come2.713.144.294.293.433.57
    <corrib75>3.713.863.143.713.293.54
    El Dueloroso3.293.573.863.03.293.4
    Glory Hunters3.433.143.433.573.433.4
    Renegade rush3.573.573.293.03.293.34
    Fix My Heart3.712.863.572.712.713.11
    GBCspelunky3.03.712.433.712.573.08

    Gameplay

    NameGameplay
    Unearthed4.29
    Rebound4.0
    Porklike GB4.0
    Shock Lobster4.0
    Dango Dash3.86
    Sushi Nights3.86
    Rhythm Land3.71
    <corrib75>3.71
    Fix My Heart3.71
    Renegade rush3.57
    Glory Hunters3.43
    MARLA and the Elemental Rings3.29
    El Dueloroso3.29
    Core Machina3.14
    GB Corp.3.14
    GBCspelunky3.0
    Dawn Will Come2.71

    Technical

    NameTechnical
    Shock Lobster4.29
    Porklike GB4.0
    Sushi Nights3.86
    <corrib75>3.86
    GB Corp.3.86
    MARLA and the Elemental Rings3.86
    Unearthed3.86
    Rebound3.86
    Rhythm Land3.71
    GBCspelunky3.71
    El Dueloroso3.57
    Renegade rush3.57
    Core Machina3.43
    Dango Dash3.29
    Dawn Will Come3.14
    Glory Hunters3.14
    Fix My Heart2.86

    Originality

    NameOriginality
    Unearthed4.86
    Shock Lobster4.71
    GB Corp.4.57
    Dawn Will Come4.29
    Rhythm Land4.14
    Core Machina4.0
    Sushi Nights4.0
    Dango Dash3.86
    El Dueloroso3.86
    Rebound3.57
    Fix My Heart3.57
    MARLA and the Elemental Rings3.43
    Glory Hunters3.43
    Renegade rush3.29
    Porklike GB3.14
    <corrib75>3.14
    GBCspelunky2.43

    Graphics

    NameGraphics
    Core Machina4.57
    Unearthed4.43
    Dawn Will Come4.29
    Dango Dash4.0
    MARLA and the Elemental Rings4.0
    Rhythm Land3.86
    <corrib75>3.71
    GBCspelunky3.71
    Rebound3.71
    Shock Lobster3.71
    Sushi Nights3.71
    Glory Hunters3.57
    Porklike GB3.57
    GB Corp.3.14
    El Dueloroso3.0
    Renegade rush3.0
    Fix My Heart2.71

    Audio

    NameAudio
    Dango Dash4.57
    Rhythm Land4.57
    Rebound4.29
    Core Machina4.14
    MARLA and the Elemental Rings3.86
    Porklike GB3.71
    Sushi Nights3.71
    Glory Hunters3.43
    Dawn Will Come3.43
    El Dueloroso3.29
    Renegade rush3.29
    Unearthed3.29
    <corrib75>3.29
    GB Corp.3.29
    Shock Lobster3.14
    Fix My Heart2.71
    GBCspelunky2.57
    ',18);function Ft(Nt,jt){const r=n("ExternalLinkIcon");return i(),s("div",null,[y,w,t("blockquote",null,[t("p",null,[k,e(" was a game jam run from July 1 to October 1 2021 and it was hosted on "),t("a",B,[e("itch.io/jam/gbcompo21"),o(r)]),e(".")])]),G,v,t("p",null,[e("Full leaderboards are available "),C,e(". Top rated entries are playable "),t("a",S,[e("here"),o(r)]),e(" while the complete list can be found on "),t("a",M,[e("Itch.io"),o(r)]),e(".")]),R,t("p",null,[e("The complete set of entries is available to browse on "),t("a",x,[e("Itch.io"),o(r)]),e(" or can be downloaded as a zip file from "),t("a",D,[e("GitHub"),o(r)]),e(".")]),T,A,t("p",null,[e("The entire prize pool is community funded. Donate or sponsor the competition through "),t("a",O,[e("GitHub sponsors"),o(r)]),e(".")]),L,t("p",null,[t("a",H,[e("Toxa"),o(r)]),e(", "),t("a",I,[e("Carles Castillo"),o(r)]),e(", "),t("a",E,[e("Dave VanEe"),o(r)]),e(", "),t("a",z,[e("Chris Maltby"),o(r)]),e(", "),t("a",F,[e("William Bettridge-Radford"),o(r)]),e(", "),t("a",N,[e("Josh Frisby"),o(r)]),e(", "),t("a",j,[e("Sanqui"),o(r)])]),q,t("ul",null,[t("li",null,[e("General links "),t("ul",null,[t("li",null,[t("a",P,[e("Pan Docs"),o(r)]),e(", Game Boy technical documentation")]),t("li",null,[t("a",W,[e("Awesome Game Boy Development list of resources"),o(r)]),t("ul",null,[t("li",null,[e("Especially relevant is the "),t("a",U,[e('"Software Development"'),o(r)]),e(" paragraph")])])]),t("li",null,[t("a",J,[e("How to choose between C and ASM for GB?"),o(r)])])])]),t("li",null,[t("a",Z,[e("RGBDS"),o(r)]),e(" (ASM language) "),t("ul",null,[t("li",null,[t("a",V,[e("GB ASM Tutorial"),o(r)])])])]),t("li",null,[t("a",K,[e("GBDK"),o(r)]),e(" (C language) "),t("ul",null,[t("li",null,[t("a",Y,[e("API docs: Getting Started"),o(r)])]),t("li",null,[t("a",Q,[e("Examples"),o(r)])]),t("li",null,[t("a",X,[e("Docs, links and tools"),o(r)])]),t("li",null,[t("a",$,[e("ZGB: a game engine using GBDK"),o(r)])]),tt])]),t("li",null,[t("a",et,[e("GBStudio"),o(r)]),e(" (no coding required) "),t("ul",null,[t("li",null,[t("a",rt,[e("Resources to get started"),o(r)])]),t("li",null,[t("a",ot,[e("Dedicated Discord"),o(r)])])])])]),dt,t("p",null,[e("The current prize pool is "),at,e(" and will be split according to "),t("a",nt,[e("this document"),o(r)]),e(".")]),it,t("p",null,[e("If you publish your game source code and assets on a public repository (e.g. GitHub) under "),t("a",st,[e("an open source license"),o(r)]),e(" (GPL, MIT, Apache, CC0...) you get "),lt,e(" more of the prize as a bonus!")]),ht,ct,t("ol",null,[ut,t("li",null,[t("p",null,[e("Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 15) are eligible for "),pt,e(' prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. See '),t("a",gt,[e("this issue"),o(r)]),e(" for further details.")])]),t("li",null,[t("p",null,[e('To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed '),t("a",mt,[e("here"),o(r)]),e(" is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following istructions.")])]),bt,t("li",null,[ft,t("ul",null,[_t,yt,wt,t("li",null,[e("Using templates, tutorial code as starting point (when they're license allow to do so, e.g. "),t("a",kt,[e("gb-boilerplate"),o(r)]),e(")")]),Bt]),Gt,vt]),Ct,St,Mt]),Rt,t("ul",null,[t("li",null,[e("The organizers, from all over the gbdev community: "),t("a",xt,[e("avivace"),o(r)]),e(", "),t("a",Dt,[e("Proximity Sound"),o(r)]),e(", "),t("a",Tt,[e("untoxa"),o(r)]),e(", "),t("a",At,[e("bbbbbr"),o(r)]),e(", "),t("a",Ot,[e("Sanqui"),o(r)]),e(", "),t("a",Lt,[e("aaaaaa123456789"),o(r)]),e(", "),t("a",Ht,[e("ISSOtm"),o(r)])]),t("li",null,[t("a",It,[e("Optix"),o(r)]),e(", for the awesome logo and the other graphical assets")]),Et]),zt])}const Pt=a(_,[["render",Ft],["__file","gbcompo21.html.vue"]]);export{Pt as default}; diff --git a/assets/gbcompo23.html-b56bd135.js b/assets/gbcompo23.html-0396efa9.js similarity index 99% rename from assets/gbcompo23.html-b56bd135.js rename to assets/gbcompo23.html-0396efa9.js index 2e2096e..3866ac9 100644 --- a/assets/gbcompo23.html-b56bd135.js +++ b/assets/gbcompo23.html-0396efa9.js @@ -1 +1 @@ -import{_ as a,r as n,o as i,c as s,a as t,b as e,d as r,e as o}from"./app-19015fbd.js";const l="/images/kSruwo_alt.png",h={},c=o('

    Game Boy Competition 2023

    Game Boy Competition 2023

    Join us for an epic game development event celebrating the classics! Show off your creativity and skills by crafting original games, demos, homebrew tools or music specifically designed for the legendary Game Boy. Get ready to battle it out for fame, honor, and an incredible array of prizes that await the best entries.

    ',3),u={href:"https://itch.io/jam/gbcompo23",target:"_blank",rel:"noopener noreferrer"},p=t("strong",null,"June 15th",-1),g=t("strong",null,"September 15",-1),m=t("p",null,[e("Theme: "),t("em",null,"You are the monster"),e(".")],-1),b=t("h2",{id:"prizes-and-categories",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prizes-and-categories","aria-hidden":"true"},"#"),e(" Prizes and Categories")],-1),f=t("img",{src:"https://img.shields.io/endpoint?style=flat-square&color=red&url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D13LfVFg9UPjfUd65egc3WEmCNOHsPHNap3vAA-eLnpiQ%26cellRange%3DQuotas!F8"},null,-1),_={href:"https://docs.google.com/spreadsheets/d/e/2PACX-1vRTOM0XElTJJGF97GyxzL393SBuPAjW3woxYZo5Fs_X_tC8Yxq_hojVNw74XGeOFYHu0_5bwS3NyQLZ/pubhtml",target:"_blank",rel:"noopener noreferrer"},y={href:"https://opencollective.com/gbdev/projects/gbcompo23",target:"_blank",rel:"noopener noreferrer"},w=t("p",null,"An entry can compete in one and only one of the following leaderboards:",-1),k=t("li",null,[e("The best "),t("strong",null,"5"),e(" games will get a prize.")],-1),v=t("li",null,[e("The best "),t("strong",null,"3"),e(" OSS games will get an "),t("strong",null,"additional"),e(" prize (can overlap)")],-1),S={href:"https://hh.gbdev.io/game/dango-dash",target:"_blank",rel:"noopener noreferrer"},T={href:"https://hh.gbdev.io/game/core-machina",target:"_blank",rel:"noopener noreferrer"},G={href:"https://hh.gbdev.io/game/unearthed",target:"_blank",rel:"noopener noreferrer"},B=t("strong",null,"1 prize",-1),C={href:"https://hh.gbdev.io/game/zilogized",target:"_blank",rel:"noopener noreferrer"},M={href:"https://hh.gbdev.io/game/freebie-gbs-2018",target:"_blank",rel:"noopener noreferrer"},A=t("strong",null,"1 prize",-1),x={href:"https://en.wikipedia.org/wiki/Demoscene",target:"_blank",rel:"noopener noreferrer"},R={href:"https://hh.gbdev.io/game/back-to-color",target:"_blank",rel:"noopener noreferrer"},O={href:"https://hh.gbdev.io/game/is-that-a-demo-in-your-pocket",target:"_blank",rel:"noopener noreferrer"},j={href:"https://hh.gbdev.io/game/cute-demo-cgb",target:"_blank",rel:"noopener noreferrer"},N=t("strong",null,"1 prize",-1),H={href:"https://hh.gbdev.io/game/bannerprinter",target:"_blank",rel:"noopener noreferrer"},D={href:"https://hh.gbdev.io/game/obgbtc",target:"_blank",rel:"noopener noreferrer"},E={href:"https://hh.gbdev.io/game/stopwatch-version-1",target:"_blank",rel:"noopener noreferrer"},I=o('

    The rankings are decided according to the judging criteria.

    Community

    Come join us on Discord for help getting started (or find a team), and head over to gbdev.io for a curated list of links and development resources!

    We'd love to hear from participants, share your progress using the #gbcompo23 hashtag and join the conversation on the Discord #gbcompo23 channel!

    ',4),z={href:"https://mastodon.social/@gbdev",target:"_blank",rel:"noopener noreferrer"},F=t("h2",{id:"resources",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#resources","aria-hidden":"true"},"#"),e(" Resources")],-1),K=t("p",null,"Here is a curated list tools and documentation to get you started.",-1),P={href:"https://www.youtube.com/playlist?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",target:"_blank",rel:"noopener noreferrer"},L={href:"https://media.ccc.de/v/33c3-8029-the_ultimate_game_boy_talk",target:"_blank",rel:"noopener noreferrer"},U={href:"https://gbdev.io/pandocs",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbdev.io/resources.html",target:"_blank",rel:"noopener noreferrer"},q={href:"https://gbdev.io/resources.html#software-development",target:"_blank",rel:"noopener noreferrer"},J={href:"https://gbdev.io/guides/tools.html#languages",target:"_blank",rel:"noopener noreferrer"},W={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},X={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},V={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},$={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},tt={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},et={href:"https://discord.gg/XCbjCvqnUY",target:"_blank",rel:"noopener noreferrer"},dt={href:"https://laroldsjubilantjunkyard.com/tutorials/how-to-make-a-gameboy-game/",target:"_blank",rel:"noopener noreferrer"},rt={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},at={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},nt={href:"https://github.com/daid/gbsdk",target:"_blank",rel:"noopener noreferrer"},it={href:"https://daid.github.io/gbsdk/",target:"_blank",rel:"noopener noreferrer"},st={href:"https://github.com/QuinnPainter/CrossConnect",target:"_blank",rel:"noopener noreferrer"},lt={href:"https://github.com/QuinnPainter/Wyrmhole",target:"_blank",rel:"noopener noreferrer"},ht=t("h2",{id:"sponsors",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#sponsors","aria-hidden":"true"},"#"),e(" Sponsors")],-1),ct={href:"https://incube8games.com/",target:"_blank",rel:"noopener noreferrer"},ut={href:"https://ferrantecrafts.com/",target:"_blank",rel:"noopener noreferrer"},pt={href:"https://macho-nacho.com/",target:"_blank",rel:"noopener noreferrer"},gt={href:"https://www.bitmapsoft.co.uk/",target:"_blank",rel:"noopener noreferrer"},mt={href:"https://www.brokestudio.fr/",target:"_blank",rel:"noopener noreferrer"},bt={href:"https://yastuna-games.com/en/",target:"_blank",rel:"noopener noreferrer"},ft={href:"https://shop.insidegadgets.com/",target:"_blank",rel:"noopener noreferrer"},_t={href:"https://twitter.com/gbdev0",target:"_blank",rel:"noopener noreferrer"},yt=t("h2",{id:"rules",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#rules","aria-hidden":"true"},"#"),e(" Rules")],-1),wt=t("h3",{id:"prizes-and-judging",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prizes-and-judging","aria-hidden":"true"},"#"),e(" Prizes and Judging")],-1),kt=t("li",null,"The submitted entry must implement / interpret the jam theme (applies to Game category only).",-1),vt=t("li",null,"Multiple submissions are allowed from the same person or team. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).",-1),St=t("li",null,"Judges can submit entries, but the entries won't be eligible for prizes. Judges won't score the entries they submitted.",-1),Tt=t("strong",null,"additional",-1),Gt=t("em",null,"during",-1),Bt={href:"https://github.com/gbdev/gbcompo21/issues/3",target:"_blank",rel:"noopener noreferrer"},Ct={href:"https://www.gnu.org/licenses/license-list.en.html",target:"_blank",rel:"noopener noreferrer"},Mt=t("li",null,"If your submission contains text that isn't available in English, some judges might not be able to read that, and they will judge accordingly.",-1),At=t("li",null,"Shipment of physical prizes may not be available to all countries, they are subject to shipping ability of the prize donors.",-1),xt=o('

    Hardware Criteria

    1. Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown, PDF or HTML file format (e.g. game manual).
    2. The ROM file will be tested on real hardware (primarily a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.
    3. GBC features are allowed, and entries may be GBC only (GBC only should be indicated in game for non-GBC hardware or on the entry's page).
    4. SGB features are allowed. The entries will be evaluated mainly on Game Boy Color. You can use SGB features, but don't rely on them as main features for your entry.
    5. Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:
      1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
      2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
      3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
      4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
    6. Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.
    7. As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

    General Criteria

    ',3),Rt={start:"15"},Ot=t("li",null,[t("p",null,"Teams are allowed (award will be split).")],-1),jt=t("li",null,[t("p",null,"ROM Hacks are not allowed.")],-1),Nt=t("li",null,[t("p",null,"NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.")],-1),Ht=t("li",null,[t("p",null,"The entry must be submitted on the itch.io jam page.")],-1),Dt=t("p",null,"Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding.",-1),Et=t("p",null,[e("Examples of things that are "),t("strong",null,"allowed:")],-1),It=t("li",null,"A brand new game using your own (or any) existing game engine.",-1),zt=t("li",null,"A remake of your (or someone else's) game for a different platform, but with new code and assets.",-1),Ft=t("li",null,"A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).",-1),Kt={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Pt=t("li",null,"Asset packs for art and music and covers of other music are allowed if the licensing permits. Be sure to make note of what is being reused or re-interpreted and under what terms. Use of pre-made assets and content (vs wholly original) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).",-1),Lt=t("p",null,[e("Examples of things that are "),t("strong",null,"not allowed:")],-1),Ut=t("ul",null,[t("li",null,"A project you've been working on for months."),t("li",null,"An update/patch for a game you already released publicly.")],-1),Yt=t("li",null,[t("p",null,"The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).")],-1),qt=t("li",null,[t("p",null,"It is allowed to submit an entry to multiple events.")],-1),Jt=o('

    Judging

    A team of (~10) judges has been selected before the start of the competition.

    Every judge will be asked to compile an unranked shortlist of their favourite entries. Once the shortlists are ready from all the judges, the top 15 most selected entries will be evaluated by the judges on the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?
    6. Theme - How was the theme implemented in the gameplay, the mechanics and/or the story?

    Applicability may vary depending on the category of the entry (e.g. a "Music" ROM may be evaluated only on 5)-

    The final leaderboard is computed by averaging the "Overall" score.

    WARNING

    Judges are volunteers. Those details can change without prior notice, as the judging process is long and involves hundreds of entries. Detailed criteria leaderboards will be provided only for entries in the final shortlist.

    Acknowledgements

    Special thanks to everyone who helped organising and running this event:

    Donators: Anonymous Donator

    Partners: gbdev.io, LaroldsJubilantJunkyard, RetroBreak, GB Studio Central

    Organisers: avivace, Tronimal, duodreamer, bbbbbr, ISSOtm, RetroBreak, LaroldsJubilantJunkyard, ProximitySound, Hacktix

    Judges: avivace, ISSOtm, Duo, Tronimal, Ferrante Crafts, NickWestwood, Veund, Toxa

    Past editions

    ',14),Wt={href:"https://itch.io/jam/gbcompo21",target:"_blank",rel:"noopener noreferrer"},Xt=o('

    Results

    Music

    1. 8bit Sunset (GameBoy Music) -Kabcorp
    2. Gb Compo 23 - Music Cart - Tune In!- beatscribe
    3. Monkeys on Mars - Chavez.funktion
    4. The Infernodome - Original GB SongROM! - EmperorJub , No time for art sorry (Music Cart) -incognitio, Re: Cycle - sloopygoop

    Demoscene

    1. Did Somebody Say Demo? - VL2MSTUDIO
    2. DDDDDEEMO(N) - Lillie_chippie

    Tools

    1. Monster Orc-arina - Pearacidic
    2. Dungeon Master - joaobapt
    3. WeekPlanner- CreativaGS
    4. Iron Cor - Stainless - Elvies, Nyan note - Arky750, witch sound tracker - Arky750, SGB SOU_TRN demo -cloudscomputing

    Games

    Overall

    #NameOverallGameplayTechnicalOriginalityGraphicsAudioTheme
    1Hermano † §4.04.174.03.54.333.834.17
    2Feed IT Souls †3.924.173.53.833.833.674.5
    3Enceladus †3.753.53.03.833.673.674.83
    4The Host †3.583.333.03.333.174.04.67
    5NUNYA †3.583.333.03.174.333.674.0
    6Ghost of the Arcade3.423.333.53.333.673.333.33
    7Kaiju Kai Kai3.333.02.673.53.52.834.5
    8Chantey (Prologue)3.252.833.03.673.834.51.67
    9Slime Trials §3.063.833.173.672.332.832.5
    10Hidden Gems3.064.03.04.52.673.01.17
    11Abducted §2.942.833.173.833.831.172.83
    12Slayer the Hawk2.862.673.54.172.671.52.67
    13EXTERMINATOR2.832.672.673.173.02.832.67
    14Imperium Strike Force2.693.172.832.333.172.672.0
    15Lightseeker2.672.172.173.04.03.171.5

    Tiebreaks (4-5, 9-10) were explicitly resolved by judges for this leaderboard.

    Entries marked with † are awarded the "Best Games" prizes and ones with § get the "Best Open Source Games".

    Gameplay

    #NameScore
    1Feed IT Souls4.17
    2Hermano4.17
    3Hidden Gems4.0
    4Slime Trials3.83
    5Enceladus3.5
    6Ghost of the Arcade3.33
    7NUNYA3.33
    8The Host3.33
    9Imperium Strike Force3.17
    10Kaiju Kai Kai3.0
    11Abducted2.83
    12Chantey (Prologue)2.83
    13EXTERMINATOR2.67
    14Slayer the Hawk2.67
    15Lightseeker2.17

    Technical

    #NameScore
    1Hermano4.0
    2Feed IT Souls3.5
    3Ghost of the Arcade3.5
    4Slayer the Hawk3.5
    5Slime Trials3.17
    6Abducted3.17
    7Enceladus3.0
    8NUNYA3.0
    9The Host3.0
    10Hidden Gems3.0
    11Chantey (Prologue)3.0
    12Imperium Strike Force2.83
    13Kaiju Kai Kai2.67
    14EXTERMINATOR2.67
    15Lightseeker2.17

    Originality

    #NameScore
    1Hidden Gems4.5
    2Slayer the Hawk4.17
    3Enceladus3.83
    4Feed IT Souls3.83
    5Abducted3.83
    6Slime Trials3.67
    7Chantey (Prologue)3.67
    8Hermano3.5
    9Kaiju Kai Kai3.5
    10Ghost of the Arcade3.33
    11The Host3.33
    12NUNYA3.17
    13EXTERMINATOR3.17
    14Lightseeker3.0
    15Imperium Strike Force2.33

    Graphics

    #NameScore
    1Hermano4.33
    2NUNYA4.33
    3Lightseeker4.0
    4Feed IT Souls3.83
    5Abducted3.83
    6Chantey (Prologue)3.83
    7Enceladus3.67
    8Ghost of the Arcade3.67
    9Kaiju Kai Kai3.5
    10The Host3.17
    11Imperium Strike Force3.17
    12EXTERMINATOR3.0
    13Hidden Gems2.67
    14Slayer the Hawk2.67
    15Slime Trials2.33

    Audio Ranking

    #NameScore
    1Chantey (Prologue)4.5
    2The Host4.0
    3Hermano3.83
    4Enceladus3.67
    5Feed IT Souls3.67
    6NUNYA3.67
    7Ghost of the Arcade3.33
    8Lightseeker3.17
    9Hidden Gems3.0
    10Slime Trials2.83
    11Kaiju Kai Kai2.83
    12EXTERMINATOR2.83
    13Imperium Strike Force2.67
    14Slayer the Hawk1.5
    15Abducted1.17

    Theme

    #NameScore
    1Enceladus4.83
    2The Host4.67
    3Feed IT Souls4.5
    4Kaiju Kai Kai4.5
    5Hermano4.17
    6NUNYA4.0
    7Ghost of the Arcade3.33
    8Abducted2.83
    9EXTERMINATOR2.67
    10Slayer the Hawk2.67
    11Slime Trials2.5
    12Imperium Strike Force2.0
    13Chantey (Prologue)1.67
    14Lightseeker1.5
    15Hidden Gems1.17
    ',24);function Vt(Zt,Qt){const d=n("ExternalLinkIcon");return i(),s("div",null,[c,t("p",null,[e("The jam is hosted on "),t("a",u,[e("Itch.io"),r(d)]),e(". It will run from "),p,e(" to "),g,e(", 2023.")]),m,b,t("p",null,[e("The total prize pool of "),f,e(" will be split according to "),t("a",_,[e("this document"),r(d)]),e(". Anybody can contribute by "),t("a",y,[e("donating"),r(d)]),e(".")]),w,t("ul",null,[t("li",null,[e("Games (80% of the prize pool) "),t("ul",null,[k,v,t("li",null,[e("Examples: "),t("a",S,[e("Dango Dash"),r(d)]),e(", "),t("a",T,[e("Core Machina"),r(d)]),e(", "),t("a",G,[e("Unearthed"),r(d)])])])]),t("li",null,[e("Music cartridges ("),B,e(") "),t("ul",null,[t("li",null,[e("Examples: "),t("a",C,[e("Zilogized"),r(d)]),e(", "),t("a",M,[e("Freebie-gbs-2018"),r(d)])])])]),t("li",null,[e("Demoscene style ("),A,e(") "),t("ul",null,[t("li",null,[e("This category is for audio-visual demonstrations that run without viewer interaction, in such a way as to demonstrate skill in manipulation of the Game Boy hardware through code, special effects, art, music, and direction. More on "),t("a",x,[e("Wikipedia"),r(d)]),e(".")]),t("li",null,[e("Examples: "),t("a",R,[e("Back to Color"),r(d)]),e(", "),t("a",O,[e("Is that a demo in your pocket?"),r(d)]),e(", "),t("a",j,[e("Cute Demo CGB"),r(d)]),e(".")])])]),t("li",null,[e("Tool ("),N,e(") "),t("ul",null,[t("li",null,[e("Examples: "),t("a",H,[e("Bannerprinter"),r(d)]),e(", "),t("a",D,[e("On-Board GB Tile Creator"),r(d)]),e(", "),t("a",E,[e("StopWatch"),r(d)]),e(".")])])])]),I,t("p",null,[e("We're also on "),t("a",z,[e("Mastodon"),r(d)]),e(".")]),F,K,t("ul",null,[t("li",null,[e("General links "),t("ul",null,[t("li",null,[t("a",P,[e("The Game Boy, a hardware autopsy"),r(d)]),e(" (Video)")]),t("li",null,[t("a",L,[e("The Ultimate Game Boy Talk"),r(d)]),e(" (Video)")]),t("li",null,[t("a",U,[e("Pan Docs"),r(d)]),e(", Game Boy technical documentation")]),t("li",null,[t("a",Y,[e("Awesome Game Boy Development list of resources"),r(d)]),t("ul",null,[t("li",null,[e("Especially relevant is the "),t("a",q,[e('"Software Development"'),r(d)]),e(" section")])])]),t("li",null,[t("a",J,[e("How to choose between C and ASM for GB?"),r(d)])])])]),t("li",null,[t("a",W,[e("RGBDS"),r(d)]),e(" (ASM language) "),t("ul",null,[t("li",null,[t("a",X,[e("GB ASM Tutorial"),r(d)])])])]),t("li",null,[t("a",V,[e("GBDK"),r(d)]),e(" (C language) "),t("ul",null,[t("li",null,[t("a",Z,[e("API docs: Getting Started"),r(d)])]),t("li",null,[t("a",Q,[e("Examples"),r(d)])]),t("li",null,[t("a",$,[e("Docs, links and tools"),r(d)])]),t("li",null,[t("a",tt,[e("ZGB: a game engine using GBDK"),r(d)])]),t("li",null,[t("a",et,[e("Dedicated Discord"),r(d)])]),t("li",null,[t("a",dt,[e('"How-to make a Gameboy Game"'),r(d)]),e(" tutorial series")])])]),t("li",null,[t("a",rt,[e("GBStudio"),r(d)]),e(" (no coding required) "),t("ul",null,[t("li",null,[t("a",ot,[e("Resources to get started"),r(d)])]),t("li",null,[t("a",at,[e("Dedicated Discord"),r(d)])])])]),t("li",null,[t("a",nt,[e("GBSDK"),r(d)]),e(" (C + RGBDS ASM, without a standard library) "),t("ul",null,[t("li",null,[t("a",it,[e("Documentation"),r(d)])]),t("li",null,[t("a",st,[e("Source for a game"),r(d)]),e(" and "),t("a",lt,[e("another game"),r(d)]),e(" built with GBSDK")])])])]),ht,t("ul",null,[t("li",null,[e("Main sponsor: "),t("a",ct,[e("Incube8Games"),r(d)])]),t("li",null,[e("Gold sponsors: "),t("a",ut,[e("FerranteCrafts"),r(d)]),e(", "),t("a",pt,[e("Macho Nacho"),r(d)])]),t("li",null,[e("Silver sponsors: "),t("a",gt,[e("Bitmap Soft"),r(d)]),e(", "),t("a",mt,[e("Broke Studio"),r(d)]),e(", "),t("a",bt,[e("Yastuna Games"),r(d)])]),t("li",null,[e("Bronze sponsors: "),t("a",ft,[e("insideGadgets"),r(d)])])]),t("p",null,[e("Interested in sponsoring? Shoot us a "),t("a",_t,[e("DM"),r(d)]),e(".")]),yt,wt,t("ol",null,[kt,vt,St,t("li",null,[e("Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 5) are eligible for "),Tt,e(' prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. It is NOT necessary for the source to be available '),Gt,e(" the competition period. Repositories/sources just need to be public from the time the event ends. See "),t("a",Bt,[e("this issue"),r(d)]),e(" for further details.")]),t("li",null,[e('To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed '),t("a",Ct,[e("here"),r(d)]),e(" is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following instructions.")]),Mt,At]),xt,t("ol",Rt,[Ot,jt,Nt,Ht,t("li",null,[Dt,Et,t("ul",null,[It,zt,Ft,t("li",null,[e("Using templates, tutorial code as starting point (when they're license allow to do so, e.g. "),t("a",Kt,[e("gb-boilerplate"),r(d)]),e(")")]),Pt]),Lt,Ut]),Yt,qt]),Jt,t("ul",null,[t("li",null,[t("a",Wt,[e("GB Competition 2021"),r(d)])])]),Xt])}const te=a(h,[["render",Vt],["__file","gbcompo23.html.vue"]]);export{te as default}; +import{_ as a,r as n,o as i,c as s,a as t,b as e,d as r,e as o}from"./app-821120ad.js";const l="/images/kSruwo_alt.png",h={},c=o('

    Game Boy Competition 2023

    Game Boy Competition 2023

    Join us for an epic game development event celebrating the classics! Show off your creativity and skills by crafting original games, demos, homebrew tools or music specifically designed for the legendary Game Boy. Get ready to battle it out for fame, honor, and an incredible array of prizes that await the best entries.

    ',3),u={href:"https://itch.io/jam/gbcompo23",target:"_blank",rel:"noopener noreferrer"},p=t("strong",null,"June 15th",-1),g=t("strong",null,"September 15",-1),m=t("p",null,[e("Theme: "),t("em",null,"You are the monster"),e(".")],-1),b=t("h2",{id:"prizes-and-categories",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prizes-and-categories","aria-hidden":"true"},"#"),e(" Prizes and Categories")],-1),f=t("img",{src:"https://img.shields.io/endpoint?style=flat-square&color=red&url=https%3A%2F%2Fcellshield.info%2Fgs%3FspreadSheetId%3D13LfVFg9UPjfUd65egc3WEmCNOHsPHNap3vAA-eLnpiQ%26cellRange%3DQuotas!F8"},null,-1),_={href:"https://docs.google.com/spreadsheets/d/e/2PACX-1vRTOM0XElTJJGF97GyxzL393SBuPAjW3woxYZo5Fs_X_tC8Yxq_hojVNw74XGeOFYHu0_5bwS3NyQLZ/pubhtml",target:"_blank",rel:"noopener noreferrer"},y={href:"https://opencollective.com/gbdev/projects/gbcompo23",target:"_blank",rel:"noopener noreferrer"},w=t("p",null,"An entry can compete in one and only one of the following leaderboards:",-1),k=t("li",null,[e("The best "),t("strong",null,"5"),e(" games will get a prize.")],-1),v=t("li",null,[e("The best "),t("strong",null,"3"),e(" OSS games will get an "),t("strong",null,"additional"),e(" prize (can overlap)")],-1),S={href:"https://hh.gbdev.io/game/dango-dash",target:"_blank",rel:"noopener noreferrer"},T={href:"https://hh.gbdev.io/game/core-machina",target:"_blank",rel:"noopener noreferrer"},G={href:"https://hh.gbdev.io/game/unearthed",target:"_blank",rel:"noopener noreferrer"},B=t("strong",null,"1 prize",-1),C={href:"https://hh.gbdev.io/game/zilogized",target:"_blank",rel:"noopener noreferrer"},M={href:"https://hh.gbdev.io/game/freebie-gbs-2018",target:"_blank",rel:"noopener noreferrer"},A=t("strong",null,"1 prize",-1),x={href:"https://en.wikipedia.org/wiki/Demoscene",target:"_blank",rel:"noopener noreferrer"},R={href:"https://hh.gbdev.io/game/back-to-color",target:"_blank",rel:"noopener noreferrer"},O={href:"https://hh.gbdev.io/game/is-that-a-demo-in-your-pocket",target:"_blank",rel:"noopener noreferrer"},j={href:"https://hh.gbdev.io/game/cute-demo-cgb",target:"_blank",rel:"noopener noreferrer"},N=t("strong",null,"1 prize",-1),H={href:"https://hh.gbdev.io/game/bannerprinter",target:"_blank",rel:"noopener noreferrer"},D={href:"https://hh.gbdev.io/game/obgbtc",target:"_blank",rel:"noopener noreferrer"},E={href:"https://hh.gbdev.io/game/stopwatch-version-1",target:"_blank",rel:"noopener noreferrer"},I=o('

    The rankings are decided according to the judging criteria.

    Community

    Come join us on Discord for help getting started (or find a team), and head over to gbdev.io for a curated list of links and development resources!

    We'd love to hear from participants, share your progress using the #gbcompo23 hashtag and join the conversation on the Discord #gbcompo23 channel!

    ',4),z={href:"https://mastodon.social/@gbdev",target:"_blank",rel:"noopener noreferrer"},F=t("h2",{id:"resources",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#resources","aria-hidden":"true"},"#"),e(" Resources")],-1),K=t("p",null,"Here is a curated list tools and documentation to get you started.",-1),P={href:"https://www.youtube.com/playlist?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",target:"_blank",rel:"noopener noreferrer"},L={href:"https://media.ccc.de/v/33c3-8029-the_ultimate_game_boy_talk",target:"_blank",rel:"noopener noreferrer"},U={href:"https://gbdev.io/pandocs",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbdev.io/resources.html",target:"_blank",rel:"noopener noreferrer"},q={href:"https://gbdev.io/resources.html#software-development",target:"_blank",rel:"noopener noreferrer"},J={href:"https://gbdev.io/guides/tools.html#languages",target:"_blank",rel:"noopener noreferrer"},W={href:"https://rgbds.gbdev.io/",target:"_blank",rel:"noopener noreferrer"},X={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},V={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},$={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},tt={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},et={href:"https://discord.gg/XCbjCvqnUY",target:"_blank",rel:"noopener noreferrer"},dt={href:"https://laroldsjubilantjunkyard.com/tutorials/how-to-make-a-gameboy-game/",target:"_blank",rel:"noopener noreferrer"},rt={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},at={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},nt={href:"https://github.com/daid/gbsdk",target:"_blank",rel:"noopener noreferrer"},it={href:"https://daid.github.io/gbsdk/",target:"_blank",rel:"noopener noreferrer"},st={href:"https://github.com/QuinnPainter/CrossConnect",target:"_blank",rel:"noopener noreferrer"},lt={href:"https://github.com/QuinnPainter/Wyrmhole",target:"_blank",rel:"noopener noreferrer"},ht=t("h2",{id:"sponsors",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#sponsors","aria-hidden":"true"},"#"),e(" Sponsors")],-1),ct={href:"https://incube8games.com/",target:"_blank",rel:"noopener noreferrer"},ut={href:"https://ferrantecrafts.com/",target:"_blank",rel:"noopener noreferrer"},pt={href:"https://macho-nacho.com/",target:"_blank",rel:"noopener noreferrer"},gt={href:"https://www.bitmapsoft.co.uk/",target:"_blank",rel:"noopener noreferrer"},mt={href:"https://www.brokestudio.fr/",target:"_blank",rel:"noopener noreferrer"},bt={href:"https://yastuna-games.com/en/",target:"_blank",rel:"noopener noreferrer"},ft={href:"https://shop.insidegadgets.com/",target:"_blank",rel:"noopener noreferrer"},_t={href:"https://twitter.com/gbdev0",target:"_blank",rel:"noopener noreferrer"},yt=t("h2",{id:"rules",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#rules","aria-hidden":"true"},"#"),e(" Rules")],-1),wt=t("h3",{id:"prizes-and-judging",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#prizes-and-judging","aria-hidden":"true"},"#"),e(" Prizes and Judging")],-1),kt=t("li",null,"The submitted entry must implement / interpret the jam theme (applies to Game category only).",-1),vt=t("li",null,"Multiple submissions are allowed from the same person or team. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).",-1),St=t("li",null,"Judges can submit entries, but the entries won't be eligible for prizes. Judges won't score the entries they submitted.",-1),Tt=t("strong",null,"additional",-1),Gt=t("em",null,"during",-1),Bt={href:"https://github.com/gbdev/gbcompo21/issues/3",target:"_blank",rel:"noopener noreferrer"},Ct={href:"https://www.gnu.org/licenses/license-list.en.html",target:"_blank",rel:"noopener noreferrer"},Mt=t("li",null,"If your submission contains text that isn't available in English, some judges might not be able to read that, and they will judge accordingly.",-1),At=t("li",null,"Shipment of physical prizes may not be available to all countries, they are subject to shipping ability of the prize donors.",-1),xt=o('

    Hardware Criteria

    1. Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown, PDF or HTML file format (e.g. game manual).
    2. The ROM file will be tested on real hardware (primarily a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.
    3. GBC features are allowed, and entries may be GBC only (GBC only should be indicated in game for non-GBC hardware or on the entry's page).
    4. SGB features are allowed. The entries will be evaluated mainly on Game Boy Color. You can use SGB features, but don't rely on them as main features for your entry.
    5. Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:
      1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
      2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
      3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
      4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
    6. Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.
    7. As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

    General Criteria

    ',3),Rt={start:"15"},Ot=t("li",null,[t("p",null,"Teams are allowed (award will be split).")],-1),jt=t("li",null,[t("p",null,"ROM Hacks are not allowed.")],-1),Nt=t("li",null,[t("p",null,"NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.")],-1),Ht=t("li",null,[t("p",null,"The entry must be submitted on the itch.io jam page.")],-1),Dt=t("p",null,"Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding.",-1),Et=t("p",null,[e("Examples of things that are "),t("strong",null,"allowed:")],-1),It=t("li",null,"A brand new game using your own (or any) existing game engine.",-1),zt=t("li",null,"A remake of your (or someone else's) game for a different platform, but with new code and assets.",-1),Ft=t("li",null,"A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).",-1),Kt={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Pt=t("li",null,"Asset packs for art and music and covers of other music are allowed if the licensing permits. Be sure to make note of what is being reused or re-interpreted and under what terms. Use of pre-made assets and content (vs wholly original) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).",-1),Lt=t("p",null,[e("Examples of things that are "),t("strong",null,"not allowed:")],-1),Ut=t("ul",null,[t("li",null,"A project you've been working on for months."),t("li",null,"An update/patch for a game you already released publicly.")],-1),Yt=t("li",null,[t("p",null,"The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).")],-1),qt=t("li",null,[t("p",null,"It is allowed to submit an entry to multiple events.")],-1),Jt=o('

    Judging

    A team of (~10) judges has been selected before the start of the competition.

    Every judge will be asked to compile an unranked shortlist of their favourite entries. Once the shortlists are ready from all the judges, the top 15 most selected entries will be evaluated by the judges on the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?
    6. Theme - How was the theme implemented in the gameplay, the mechanics and/or the story?

    Applicability may vary depending on the category of the entry (e.g. a "Music" ROM may be evaluated only on 5)-

    The final leaderboard is computed by averaging the "Overall" score.

    WARNING

    Judges are volunteers. Those details can change without prior notice, as the judging process is long and involves hundreds of entries. Detailed criteria leaderboards will be provided only for entries in the final shortlist.

    Acknowledgements

    Special thanks to everyone who helped organising and running this event:

    Donators: Anonymous Donator

    Partners: gbdev.io, LaroldsJubilantJunkyard, RetroBreak, GB Studio Central

    Organisers: avivace, Tronimal, duodreamer, bbbbbr, ISSOtm, RetroBreak, LaroldsJubilantJunkyard, ProximitySound, Hacktix

    Judges: avivace, ISSOtm, Duo, Tronimal, Ferrante Crafts, NickWestwood, Veund, Toxa

    Past editions

    ',14),Wt={href:"https://itch.io/jam/gbcompo21",target:"_blank",rel:"noopener noreferrer"},Xt=o('

    Results

    Music

    1. 8bit Sunset (GameBoy Music) -Kabcorp
    2. Gb Compo 23 - Music Cart - Tune In!- beatscribe
    3. Monkeys on Mars - Chavez.funktion
    4. The Infernodome - Original GB SongROM! - EmperorJub , No time for art sorry (Music Cart) -incognitio, Re: Cycle - sloopygoop

    Demoscene

    1. Did Somebody Say Demo? - VL2MSTUDIO
    2. DDDDDEEMO(N) - Lillie_chippie

    Tools

    1. Monster Orc-arina - Pearacidic
    2. Dungeon Master - joaobapt
    3. WeekPlanner- CreativaGS
    4. Iron Cor - Stainless - Elvies, Nyan note - Arky750, witch sound tracker - Arky750, SGB SOU_TRN demo -cloudscomputing

    Games

    Overall

    #NameOverallGameplayTechnicalOriginalityGraphicsAudioTheme
    1Hermano † §4.04.174.03.54.333.834.17
    2Feed IT Souls †3.924.173.53.833.833.674.5
    3Enceladus †3.753.53.03.833.673.674.83
    4The Host †3.583.333.03.333.174.04.67
    5NUNYA †3.583.333.03.174.333.674.0
    6Ghost of the Arcade3.423.333.53.333.673.333.33
    7Kaiju Kai Kai3.333.02.673.53.52.834.5
    8Chantey (Prologue)3.252.833.03.673.834.51.67
    9Slime Trials §3.063.833.173.672.332.832.5
    10Hidden Gems3.064.03.04.52.673.01.17
    11Abducted §2.942.833.173.833.831.172.83
    12Slayer the Hawk2.862.673.54.172.671.52.67
    13EXTERMINATOR2.832.672.673.173.02.832.67
    14Imperium Strike Force2.693.172.832.333.172.672.0
    15Lightseeker2.672.172.173.04.03.171.5

    Tiebreaks (4-5, 9-10) were explicitly resolved by judges for this leaderboard.

    Entries marked with † are awarded the "Best Games" prizes and ones with § get the "Best Open Source Games".

    Gameplay

    #NameScore
    1Feed IT Souls4.17
    2Hermano4.17
    3Hidden Gems4.0
    4Slime Trials3.83
    5Enceladus3.5
    6Ghost of the Arcade3.33
    7NUNYA3.33
    8The Host3.33
    9Imperium Strike Force3.17
    10Kaiju Kai Kai3.0
    11Abducted2.83
    12Chantey (Prologue)2.83
    13EXTERMINATOR2.67
    14Slayer the Hawk2.67
    15Lightseeker2.17

    Technical

    #NameScore
    1Hermano4.0
    2Feed IT Souls3.5
    3Ghost of the Arcade3.5
    4Slayer the Hawk3.5
    5Slime Trials3.17
    6Abducted3.17
    7Enceladus3.0
    8NUNYA3.0
    9The Host3.0
    10Hidden Gems3.0
    11Chantey (Prologue)3.0
    12Imperium Strike Force2.83
    13Kaiju Kai Kai2.67
    14EXTERMINATOR2.67
    15Lightseeker2.17

    Originality

    #NameScore
    1Hidden Gems4.5
    2Slayer the Hawk4.17
    3Enceladus3.83
    4Feed IT Souls3.83
    5Abducted3.83
    6Slime Trials3.67
    7Chantey (Prologue)3.67
    8Hermano3.5
    9Kaiju Kai Kai3.5
    10Ghost of the Arcade3.33
    11The Host3.33
    12NUNYA3.17
    13EXTERMINATOR3.17
    14Lightseeker3.0
    15Imperium Strike Force2.33

    Graphics

    #NameScore
    1Hermano4.33
    2NUNYA4.33
    3Lightseeker4.0
    4Feed IT Souls3.83
    5Abducted3.83
    6Chantey (Prologue)3.83
    7Enceladus3.67
    8Ghost of the Arcade3.67
    9Kaiju Kai Kai3.5
    10The Host3.17
    11Imperium Strike Force3.17
    12EXTERMINATOR3.0
    13Hidden Gems2.67
    14Slayer the Hawk2.67
    15Slime Trials2.33

    Audio Ranking

    #NameScore
    1Chantey (Prologue)4.5
    2The Host4.0
    3Hermano3.83
    4Enceladus3.67
    5Feed IT Souls3.67
    6NUNYA3.67
    7Ghost of the Arcade3.33
    8Lightseeker3.17
    9Hidden Gems3.0
    10Slime Trials2.83
    11Kaiju Kai Kai2.83
    12EXTERMINATOR2.83
    13Imperium Strike Force2.67
    14Slayer the Hawk1.5
    15Abducted1.17

    Theme

    #NameScore
    1Enceladus4.83
    2The Host4.67
    3Feed IT Souls4.5
    4Kaiju Kai Kai4.5
    5Hermano4.17
    6NUNYA4.0
    7Ghost of the Arcade3.33
    8Abducted2.83
    9EXTERMINATOR2.67
    10Slayer the Hawk2.67
    11Slime Trials2.5
    12Imperium Strike Force2.0
    13Chantey (Prologue)1.67
    14Lightseeker1.5
    15Hidden Gems1.17
    ',24);function Vt(Zt,Qt){const d=n("ExternalLinkIcon");return i(),s("div",null,[c,t("p",null,[e("The jam is hosted on "),t("a",u,[e("Itch.io"),r(d)]),e(". It will run from "),p,e(" to "),g,e(", 2023.")]),m,b,t("p",null,[e("The total prize pool of "),f,e(" will be split according to "),t("a",_,[e("this document"),r(d)]),e(". Anybody can contribute by "),t("a",y,[e("donating"),r(d)]),e(".")]),w,t("ul",null,[t("li",null,[e("Games (80% of the prize pool) "),t("ul",null,[k,v,t("li",null,[e("Examples: "),t("a",S,[e("Dango Dash"),r(d)]),e(", "),t("a",T,[e("Core Machina"),r(d)]),e(", "),t("a",G,[e("Unearthed"),r(d)])])])]),t("li",null,[e("Music cartridges ("),B,e(") "),t("ul",null,[t("li",null,[e("Examples: "),t("a",C,[e("Zilogized"),r(d)]),e(", "),t("a",M,[e("Freebie-gbs-2018"),r(d)])])])]),t("li",null,[e("Demoscene style ("),A,e(") "),t("ul",null,[t("li",null,[e("This category is for audio-visual demonstrations that run without viewer interaction, in such a way as to demonstrate skill in manipulation of the Game Boy hardware through code, special effects, art, music, and direction. More on "),t("a",x,[e("Wikipedia"),r(d)]),e(".")]),t("li",null,[e("Examples: "),t("a",R,[e("Back to Color"),r(d)]),e(", "),t("a",O,[e("Is that a demo in your pocket?"),r(d)]),e(", "),t("a",j,[e("Cute Demo CGB"),r(d)]),e(".")])])]),t("li",null,[e("Tool ("),N,e(") "),t("ul",null,[t("li",null,[e("Examples: "),t("a",H,[e("Bannerprinter"),r(d)]),e(", "),t("a",D,[e("On-Board GB Tile Creator"),r(d)]),e(", "),t("a",E,[e("StopWatch"),r(d)]),e(".")])])])]),I,t("p",null,[e("We're also on "),t("a",z,[e("Mastodon"),r(d)]),e(".")]),F,K,t("ul",null,[t("li",null,[e("General links "),t("ul",null,[t("li",null,[t("a",P,[e("The Game Boy, a hardware autopsy"),r(d)]),e(" (Video)")]),t("li",null,[t("a",L,[e("The Ultimate Game Boy Talk"),r(d)]),e(" (Video)")]),t("li",null,[t("a",U,[e("Pan Docs"),r(d)]),e(", Game Boy technical documentation")]),t("li",null,[t("a",Y,[e("Awesome Game Boy Development list of resources"),r(d)]),t("ul",null,[t("li",null,[e("Especially relevant is the "),t("a",q,[e('"Software Development"'),r(d)]),e(" section")])])]),t("li",null,[t("a",J,[e("How to choose between C and ASM for GB?"),r(d)])])])]),t("li",null,[t("a",W,[e("RGBDS"),r(d)]),e(" (ASM language) "),t("ul",null,[t("li",null,[t("a",X,[e("GB ASM Tutorial"),r(d)])])])]),t("li",null,[t("a",V,[e("GBDK"),r(d)]),e(" (C language) "),t("ul",null,[t("li",null,[t("a",Z,[e("API docs: Getting Started"),r(d)])]),t("li",null,[t("a",Q,[e("Examples"),r(d)])]),t("li",null,[t("a",$,[e("Docs, links and tools"),r(d)])]),t("li",null,[t("a",tt,[e("ZGB: a game engine using GBDK"),r(d)])]),t("li",null,[t("a",et,[e("Dedicated Discord"),r(d)])]),t("li",null,[t("a",dt,[e('"How-to make a Gameboy Game"'),r(d)]),e(" tutorial series")])])]),t("li",null,[t("a",rt,[e("GBStudio"),r(d)]),e(" (no coding required) "),t("ul",null,[t("li",null,[t("a",ot,[e("Resources to get started"),r(d)])]),t("li",null,[t("a",at,[e("Dedicated Discord"),r(d)])])])]),t("li",null,[t("a",nt,[e("GBSDK"),r(d)]),e(" (C + RGBDS ASM, without a standard library) "),t("ul",null,[t("li",null,[t("a",it,[e("Documentation"),r(d)])]),t("li",null,[t("a",st,[e("Source for a game"),r(d)]),e(" and "),t("a",lt,[e("another game"),r(d)]),e(" built with GBSDK")])])])]),ht,t("ul",null,[t("li",null,[e("Main sponsor: "),t("a",ct,[e("Incube8Games"),r(d)])]),t("li",null,[e("Gold sponsors: "),t("a",ut,[e("FerranteCrafts"),r(d)]),e(", "),t("a",pt,[e("Macho Nacho"),r(d)])]),t("li",null,[e("Silver sponsors: "),t("a",gt,[e("Bitmap Soft"),r(d)]),e(", "),t("a",mt,[e("Broke Studio"),r(d)]),e(", "),t("a",bt,[e("Yastuna Games"),r(d)])]),t("li",null,[e("Bronze sponsors: "),t("a",ft,[e("insideGadgets"),r(d)])])]),t("p",null,[e("Interested in sponsoring? Shoot us a "),t("a",_t,[e("DM"),r(d)]),e(".")]),yt,wt,t("ol",null,[kt,vt,St,t("li",null,[e("Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 5) are eligible for "),Tt,e(' prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. It is NOT necessary for the source to be available '),Gt,e(" the competition period. Repositories/sources just need to be public from the time the event ends. See "),t("a",Bt,[e("this issue"),r(d)]),e(" for further details.")]),t("li",null,[e('To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed '),t("a",Ct,[e("here"),r(d)]),e(" is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following instructions.")]),Mt,At]),xt,t("ol",Rt,[Ot,jt,Nt,Ht,t("li",null,[Dt,Et,t("ul",null,[It,zt,Ft,t("li",null,[e("Using templates, tutorial code as starting point (when they're license allow to do so, e.g. "),t("a",Kt,[e("gb-boilerplate"),r(d)]),e(")")]),Pt]),Lt,Ut]),Yt,qt]),Jt,t("ul",null,[t("li",null,[t("a",Wt,[e("GB Competition 2021"),r(d)])])]),Xt])}const te=a(h,[["render",Vt],["__file","gbcompo23.html.vue"]]);export{te as default}; diff --git a/assets/index.html-3102c219.js b/assets/index.html-e90463f4.js similarity index 99% rename from assets/index.html-3102c219.js rename to assets/index.html-e90463f4.js index 76d589d..5f07f39 100644 --- a/assets/index.html-3102c219.js +++ b/assets/index.html-e90463f4.js @@ -1 +1 @@ -import{_ as u,r as s,o as b,c as p,a as e,b as t,d as o,w as d,e as g}from"./app-19015fbd.js";const m={mounted(){let i=document.createElement("script");i.setAttribute("src","https://buttons.github.io/buttons.js"),document.head.appendChild(i);let n=["#5f98c6","#FCCF37","#EB1667","#A8F602","rgba(255, 255, 255, 0.5)","rgba(91, 48, 153, 0.5)"],r=n[Math.floor(Math.random()*n.length)];var l=document.querySelector("#box");l.style.setProperty("background-color",r),console.log(r)}},v=g('


    Game Boy Development community

    We are a non for profit collective of passionate developers and hackers working on development tools, homebrew games, emulators, preservation and documentation for the Nintendo Game Boy handheld console, the original gray brick from 1989.

    Join us on GitHub, Mastodon, Twitter and Discord.
    ',5),_=e("br",null,null,-1),f=e("h1",{id:"projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#projects","aria-hidden":"true"},"#"),t(" Projects")],-1),y=e("p",null,[t("Here's what we are up to:"),e("br")],-1),k=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://gbdev.io/pandocs/"},"Pan Docs "),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/pandocs","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/awesome-gbdev on GitHub"},"Star"),e("span")],-1),w=e("br",null,null,-1),B={id:"game-boy-cpu-opcode-tables",tabindex:"-1"},G=e("a",{class:"header-anchor",href:"#game-boy-cpu-opcode-tables","aria-hidden":"true"},"#",-1),S={href:"https://gbdev.io/gb-opcodes/optables",target:"_blank",rel:"noopener noreferrer"},j=e("br",null,null,-1),x=e("p",null,[e("a",{class:"projectTitle",href:"resources.html"},"awesome-gbdev "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/awesome-gbdev","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/awesome-gbdev on GitHub"},"Star"),e("span")],-1),C=e("br",null,null,-1),T=e("br",null,null,-1),A=e("br",null,null,-1),D=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://rgbds.gbdev.io/"},"RGBDS "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/rgbds","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/rgbds on GitHub"},"Star"),e("span")],-1),F=e("br",null,null,-1),H={href:"https://github.com/gbdev/hardware.inc",target:"_blank",rel:"noopener noreferrer"},R={href:"https://gbdev.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},q=e("br",null,null,-1),E=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://gbdev.io/gb-asm-tutorial/"},"GB ASM Tutorial "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/gb-asm-tutorial","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/gb-asm-tutorial on GitHub"},"Star"),e("span")],-1),L=e("br",null,null,-1),M=e("br",null,null,-1),P=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://github.com/gbdk-2020/gbdk-2020"},"GBDK 2020 "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdk-2020/gbdk-2020","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/rgbds on GitHub"},"Star"),e("span")],-1),N=e("br",null,null,-1),W=e("br",null,null,-1),z=e("p",{class:"projectTitle"},[e("a",{href:"https://gbdev.io/chat"},"Chat Channels"),t(" "),e("img",{height:"22",src:"https://img.shields.io/badge/dynamic/json.svg?label=chat&colorB=green&suffix= online&query=presence_count&uri=https://discordapp.com/api/guilds/303217943234215948/widget.json&style=flat-square"})],-1),I=e("b",null,"chat",-1),V=e("br",null,null,-1),$=e("br",null,null,-1),K=e("p",{class:"projectTitle"},[e("a",{target:"_blank",href:"https://hh.gbdev.io"},"Homebrew Hub"),t(" "),e("img",{height:"22",src:"https://img.shields.io/badge/dynamic/json?label=games&query=results&url=https%3A%2F%2Fhh3.gbdev.io%2Fapi%2Fall&style=flat-square"})],-1),O=e("br",null,null,-1),U=e("br",null,null,-1),J=e("br",null,null,-1),Q=e("p",{class:"projectTitle"},[e("a",{target:"_blank",href:"https://github.com/gb-archive"},"The Game Boy Archive"),t(" "),e("img",{style:{"font-family":"Monospace"},height:"22",src:"https://img.shields.io/badge/dynamic/json.svg?label=mirrored projects&url=https%3A%2F%2Fapi.github.com%2Forgs%2Fgb-archive&query=public_repos&style=flat-square"})],-1),X=e("br",null,null,-1),Y=e("br",null,null,-1),Z=e("p",{class:"projectTitle",style:{"font-weight":"500"}},"Events",-1),ee=e("br",null,null,-1),te=e("em",null,"Advance",-1),oe={href:"https://gbadev.net",target:"_blank",rel:"noopener noreferrer"};function ae(i,n,r,l,ie,ne){const a=s("ExternalLinkIcon"),c=s("RouterLink"),h=s("smalL");return b(),p("div",null,[v,e("div",null,[_,f,y,k,t(" The single, most comprehensive technical reference to Game Boy available to the public. "),w,e("h4",B,[G,t(),e("a",S,[t("Game Boy CPU Opcode tables"),o(a)])]),j,x,t(" Curated list of Game Boy development resources such as tools, guides, technical documentation, tutorials, emulators, related projects and open-source ROMs. Everything you'll ever need to know and see about this console is here. "),C,t("If you want to code an emulator, create your own game or simply dive into the software and hardware architecture of the Game Boy, this is the place! "),T,A,D,t(" Rednex Game Boy Development System: the de-facto ASM development toolkit for the Game Boy and Game Boy Color. "),F,e("p",null,[e("a",H,[t("hardware.inc"),o(a)]),t(" - Standard include file containing Game Boy hardware definitions for use in RGBDS projects.")]),e("p",null,[e("a",R,[t("rgbds-live"),o(a)]),t(" - A live Game Boy programming environment in the browser, allowing for realtime assembly programming with RGBDS.")]),q,E,t(" A (work in progress) tutorial on how to program for the Game Boy in assembly, touching on every aspect required to make Game Boy games, via a Hello World, constructing an Arkanoid clone, and capping off by making a playable Shoot-'Em-Up."),L,M,P,t(" Maintained and modernized GBDK, the Game Boy Development Kit. Now powered by an updated version of the SDCC toolchain, provides a C compiler, assembler, linker and a set of libraries. "),N,W,z,t(" The places where our community thrives. Here we "),I,t(", discuss, help each other and show what we are working on. We have a Discord server, an IRC channel, and more. "),V,$,K,t(" Play Game Boy games online from an archive of hundreds of entries! "),O,t(" A community-led attempt to collect, archive and save every unofficial game, homebrew, demo, patch, hackrom for Game Boy produced by the community through the last 3 decades of passionate work. "),U,J,Q,t(" Digital library of Game Boy related software, hardware and literature. Aimed to mirror and preserve old and fragmented contributions in the scene from the last three decades. "),X,Y,Z,t(" We host coding competitions in which anyone can partecipate by creating original games, demos, homebrews tools and music for the Game Boy and compete for glory and prizes. "),e("p",null,[o(c,{to:"/gbcompo21.html"},{default:d(()=>[t("GB Competition '21")]),_:1}),t(" - "),o(c,{to:"/gbcompo23.html"},{default:d(()=>[t("GB Competition '23")]),_:1})])]),ee,o(h,null,{default:d(()=>[e("p",null,[t("For Game Boy "),te,t(" development, check "),e("a",oe,[t("gbadev.net"),o(a)]),t(".")])]),_:1})])}const se=u(m,[["render",ae],["__file","index.html.vue"]]);export{se as default}; +import{_ as u,r as s,o as b,c as p,a as e,b as t,d as o,w as d,e as g}from"./app-821120ad.js";const m={mounted(){let i=document.createElement("script");i.setAttribute("src","https://buttons.github.io/buttons.js"),document.head.appendChild(i);let n=["#5f98c6","#FCCF37","#EB1667","#A8F602","rgba(255, 255, 255, 0.5)","rgba(91, 48, 153, 0.5)"],r=n[Math.floor(Math.random()*n.length)];var l=document.querySelector("#box");l.style.setProperty("background-color",r),console.log(r)}},v=g('


    Game Boy Development community

    We are a non for profit collective of passionate developers and hackers working on development tools, homebrew games, emulators, preservation and documentation for the Nintendo Game Boy handheld console, the original gray brick from 1989.

    Join us on GitHub, Mastodon, Twitter and Discord.
    ',5),_=e("br",null,null,-1),f=e("h1",{id:"projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#projects","aria-hidden":"true"},"#"),t(" Projects")],-1),y=e("p",null,[t("Here's what we are up to:"),e("br")],-1),k=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://gbdev.io/pandocs/"},"Pan Docs "),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/pandocs","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/awesome-gbdev on GitHub"},"Star"),e("span")],-1),w=e("br",null,null,-1),B={id:"game-boy-cpu-opcode-tables",tabindex:"-1"},G=e("a",{class:"header-anchor",href:"#game-boy-cpu-opcode-tables","aria-hidden":"true"},"#",-1),S={href:"https://gbdev.io/gb-opcodes/optables",target:"_blank",rel:"noopener noreferrer"},j=e("br",null,null,-1),x=e("p",null,[e("a",{class:"projectTitle",href:"resources.html"},"awesome-gbdev "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/awesome-gbdev","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/awesome-gbdev on GitHub"},"Star"),e("span")],-1),C=e("br",null,null,-1),T=e("br",null,null,-1),A=e("br",null,null,-1),D=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://rgbds.gbdev.io/"},"RGBDS "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/rgbds","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/rgbds on GitHub"},"Star"),e("span")],-1),F=e("br",null,null,-1),H={href:"https://github.com/gbdev/hardware.inc",target:"_blank",rel:"noopener noreferrer"},R={href:"https://gbdev.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},q=e("br",null,null,-1),E=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://gbdev.io/gb-asm-tutorial/"},"GB ASM Tutorial "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdev/gb-asm-tutorial","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/gb-asm-tutorial on GitHub"},"Star"),e("span")],-1),L=e("br",null,null,-1),M=e("br",null,null,-1),P=e("p",null,[e("a",{class:"projectTitle",target:"_blank",href:"https://github.com/gbdk-2020/gbdk-2020"},"GBDK 2020 "),t(),e("a",{class:"github-button",target:"_blank",href:"https://github.com/gbdk-2020/gbdk-2020","data-icon":"octicon-star","data-show-count":"true","aria-label":"Star gbdev/rgbds on GitHub"},"Star"),e("span")],-1),N=e("br",null,null,-1),W=e("br",null,null,-1),z=e("p",{class:"projectTitle"},[e("a",{href:"https://gbdev.io/chat"},"Chat Channels"),t(" "),e("img",{height:"22",src:"https://img.shields.io/badge/dynamic/json.svg?label=chat&colorB=green&suffix= online&query=presence_count&uri=https://discordapp.com/api/guilds/303217943234215948/widget.json&style=flat-square"})],-1),I=e("b",null,"chat",-1),V=e("br",null,null,-1),$=e("br",null,null,-1),K=e("p",{class:"projectTitle"},[e("a",{target:"_blank",href:"https://hh.gbdev.io"},"Homebrew Hub"),t(" "),e("img",{height:"22",src:"https://img.shields.io/badge/dynamic/json?label=games&query=results&url=https%3A%2F%2Fhh3.gbdev.io%2Fapi%2Fall&style=flat-square"})],-1),O=e("br",null,null,-1),U=e("br",null,null,-1),J=e("br",null,null,-1),Q=e("p",{class:"projectTitle"},[e("a",{target:"_blank",href:"https://github.com/gb-archive"},"The Game Boy Archive"),t(" "),e("img",{style:{"font-family":"Monospace"},height:"22",src:"https://img.shields.io/badge/dynamic/json.svg?label=mirrored projects&url=https%3A%2F%2Fapi.github.com%2Forgs%2Fgb-archive&query=public_repos&style=flat-square"})],-1),X=e("br",null,null,-1),Y=e("br",null,null,-1),Z=e("p",{class:"projectTitle",style:{"font-weight":"500"}},"Events",-1),ee=e("br",null,null,-1),te=e("em",null,"Advance",-1),oe={href:"https://gbadev.net",target:"_blank",rel:"noopener noreferrer"};function ae(i,n,r,l,ie,ne){const a=s("ExternalLinkIcon"),c=s("RouterLink"),h=s("smalL");return b(),p("div",null,[v,e("div",null,[_,f,y,k,t(" The single, most comprehensive technical reference to Game Boy available to the public. "),w,e("h4",B,[G,t(),e("a",S,[t("Game Boy CPU Opcode tables"),o(a)])]),j,x,t(" Curated list of Game Boy development resources such as tools, guides, technical documentation, tutorials, emulators, related projects and open-source ROMs. Everything you'll ever need to know and see about this console is here. "),C,t("If you want to code an emulator, create your own game or simply dive into the software and hardware architecture of the Game Boy, this is the place! "),T,A,D,t(" Rednex Game Boy Development System: the de-facto ASM development toolkit for the Game Boy and Game Boy Color. "),F,e("p",null,[e("a",H,[t("hardware.inc"),o(a)]),t(" - Standard include file containing Game Boy hardware definitions for use in RGBDS projects.")]),e("p",null,[e("a",R,[t("rgbds-live"),o(a)]),t(" - A live Game Boy programming environment in the browser, allowing for realtime assembly programming with RGBDS.")]),q,E,t(" A (work in progress) tutorial on how to program for the Game Boy in assembly, touching on every aspect required to make Game Boy games, via a Hello World, constructing an Arkanoid clone, and capping off by making a playable Shoot-'Em-Up."),L,M,P,t(" Maintained and modernized GBDK, the Game Boy Development Kit. Now powered by an updated version of the SDCC toolchain, provides a C compiler, assembler, linker and a set of libraries. "),N,W,z,t(" The places where our community thrives. Here we "),I,t(", discuss, help each other and show what we are working on. We have a Discord server, an IRC channel, and more. "),V,$,K,t(" Play Game Boy games online from an archive of hundreds of entries! "),O,t(" A community-led attempt to collect, archive and save every unofficial game, homebrew, demo, patch, hackrom for Game Boy produced by the community through the last 3 decades of passionate work. "),U,J,Q,t(" Digital library of Game Boy related software, hardware and literature. Aimed to mirror and preserve old and fragmented contributions in the scene from the last three decades. "),X,Y,Z,t(" We host coding competitions in which anyone can partecipate by creating original games, demos, homebrews tools and music for the Game Boy and compete for glory and prizes. "),e("p",null,[o(c,{to:"/gbcompo21.html"},{default:d(()=>[t("GB Competition '21")]),_:1}),t(" - "),o(c,{to:"/gbcompo23.html"},{default:d(()=>[t("GB Competition '23")]),_:1})])]),ee,o(h,null,{default:d(()=>[e("p",null,[t("For Game Boy "),te,t(" development, check "),e("a",oe,[t("gbadev.net"),o(a)]),t(".")])]),_:1})])}const se=u(m,[["render",ae],["__file","index.html.vue"]]);export{se as default}; diff --git a/assets/lyc_timing.html-8835a7cd.js b/assets/lyc_timing.html-da2e2b9d.js similarity index 99% rename from assets/lyc_timing.html-8835a7cd.js rename to assets/lyc_timing.html-da2e2b9d.js index 272c607..c60982c 100644 --- a/assets/lyc_timing.html-8835a7cd.js +++ b/assets/lyc_timing.html-da2e2b9d.js @@ -1,4 +1,4 @@ -import{_ as H,r as A,o as q,c as I,a as n,b as s,d as e,w as h,h as l,e as v}from"./app-19015fbd.js";const E=`.waitVRAM +import{_ as H,r as A,o as q,c as I,a as n,b as s,d as e,w as h,h as l,e as v}from"./app-821120ad.js";const E=`.waitVRAM ldh a, [rSTAT] and STATF_BUSY ; 2 jr nz, .waitVRAM diff --git a/assets/meetings.html-ac085808.js b/assets/meetings.html-1272f640.js similarity index 89% rename from assets/meetings.html-ac085808.js rename to assets/meetings.html-1272f640.js index 2ca3a45..85fe163 100644 --- a/assets/meetings.html-ac085808.js +++ b/assets/meetings.html-1272f640.js @@ -1 +1 @@ -import{_ as o,r as i,o as r,c,a as e,d as s,w as a,b as t}from"./app-19015fbd.js";const l={},m=e("h1",{id:"meetings-minutes",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#meetings-minutes","aria-hidden":"true"},"#"),t(" Meetings minutes")],-1);function _(u,d){const n=i("RouterLink");return r(),c("div",null,[m,e("ul",null,[e("li",null,[s(n,{to:"/meetings/2024-03-10-sc2.html"},{default:a(()=>[t("March 10, 2024")]),_:1})]),e("li",null,[s(n,{to:"/meetings/2023-11-04-sc.html"},{default:a(()=>[t("November 4th, 2023")]),_:1})])])])}const f=o(l,[["render",_],["__file","meetings.html.vue"]]);export{f as default}; +import{_ as o,r as i,o as r,c,a as e,d as s,w as a,b as t}from"./app-821120ad.js";const l={},m=e("h1",{id:"meetings-minutes",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#meetings-minutes","aria-hidden":"true"},"#"),t(" Meetings minutes")],-1);function _(u,d){const n=i("RouterLink");return r(),c("div",null,[m,e("ul",null,[e("li",null,[s(n,{to:"/meetings/2024-03-10-sc2.html"},{default:a(()=>[t("March 10, 2024")]),_:1})]),e("li",null,[s(n,{to:"/meetings/2023-11-04-sc.html"},{default:a(()=>[t("November 4th, 2023")]),_:1})])])])}const f=o(l,[["render",_],["__file","meetings.html.vue"]]);export{f as default}; diff --git a/assets/newsletter.html-9902ee4e.js b/assets/newsletter.html-579cb2e7.js similarity index 92% rename from assets/newsletter.html-9902ee4e.js rename to assets/newsletter.html-579cb2e7.js index d847a56..f329b55 100644 --- a/assets/newsletter.html-9902ee4e.js +++ b/assets/newsletter.html-579cb2e7.js @@ -1 +1 @@ -import{_ as o,r as s,o as a,c as l,a as e,b as t,d as n}from"./app-19015fbd.js";const c={},d=e("h1",{id:"newsletter",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#newsletter","aria-hidden":"true"},"#"),t(" Newsletter")],-1),_=e("li",null,[e("a",{href:"/newsletter/1"},"gbdev newsletter Issue #1 - 2021")],-1),h={href:"https://eldred.fr/blog/gbdev-status",target:"_blank",rel:"noopener noreferrer"},i={href:"https://avivace.com/blog/gbdev-updates-nov20.html",target:"_blank",rel:"noopener noreferrer"};function f(u,p){const r=s("ExternalLinkIcon");return a(),l("div",null,[d,e("ul",null,[_,e("li",null,[e("a",h,[t("State of GBDev - March 2021"),n(r)])]),e("li",null,[e("a",i,[t("gbdev updates - November 2020"),n(r)])])])])}const b=o(c,[["render",f],["__file","newsletter.html.vue"]]);export{b as default}; +import{_ as o,r as s,o as a,c as l,a as e,b as t,d as n}from"./app-821120ad.js";const c={},d=e("h1",{id:"newsletter",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#newsletter","aria-hidden":"true"},"#"),t(" Newsletter")],-1),_=e("li",null,[e("a",{href:"/newsletter/1"},"gbdev newsletter Issue #1 - 2021")],-1),h={href:"https://eldred.fr/blog/gbdev-status",target:"_blank",rel:"noopener noreferrer"},i={href:"https://avivace.com/blog/gbdev-updates-nov20.html",target:"_blank",rel:"noopener noreferrer"};function f(u,p){const r=s("ExternalLinkIcon");return a(),l("div",null,[d,e("ul",null,[_,e("li",null,[e("a",h,[t("State of GBDev - March 2021"),n(r)])]),e("li",null,[e("a",i,[t("gbdev updates - November 2020"),n(r)])])])])}const b=o(c,[["render",f],["__file","newsletter.html.vue"]]);export{b as default}; diff --git a/assets/privacypolicy.html-0bfa63bd.js b/assets/privacypolicy.html-b74fe81b.js similarity index 93% rename from assets/privacypolicy.html-0bfa63bd.js rename to assets/privacypolicy.html-b74fe81b.js index 17efaa7..6c47ed7 100644 --- a/assets/privacypolicy.html-0bfa63bd.js +++ b/assets/privacypolicy.html-b74fe81b.js @@ -1 +1 @@ -import{_ as a,r,o as s,c as i,a as e,b as o,d as t}from"./app-19015fbd.js";const l={},c=e("h1",{id:"privacy-policy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#privacy-policy","aria-hidden":"true"},"#"),o(" Privacy Policy")],-1),d={href:"https://en.wikipedia.org/wiki/Matomo_(software)",target:"_blank",rel:"noopener noreferrer"},h=e("code",null,"*.gbdev.io",-1),u=e("code",null,"*.gbadev.net",-1),_=e("h3",{id:"how",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#how","aria-hidden":"true"},"#"),o(" How")],-1),p=e("li",null,[o("Visitors' IP addresses are "),e("strong",null,"anonymized"),o(". The last byte is masked and fully qualified addressess "),e("strong",null,"never"),o(" reach our analytics software.")],-1),y=e("li",null,[o("User IDs are replaced by "),e("strong",null,"pseudonyms"),o(" to avoid directly storing and displaying personally identifiable information.")],-1),f=e("strong",null,"DOES NOT use any cookie",-1),g={href:"https://www.cookiesandyou.com/",target:"_blank",rel:"noopener noreferrer"},k=e("li",null,'We honor your browser "I do not want to be tracked" preference.',-1),m=e("li",null,"Data is aggregated and reports are compiled. Raw logs are regularly cleaned up.",-1),b={href:"https://stats.gbdev.io/index.php?module=CoreAdminHome&action=optOut&language=en",target:"_blank",rel:"noopener noreferrer"};function w(v,x){const n=r("ExternalLinkIcon");return s(),i("div",null,[c,e("p",null,[o("We use a self hosted instance of "),e("a",d,[o("Matomo"),t(n)]),o(", a free and open source web analytics application to track online visits to our websites ("),h,o(", "),u,o("), in order to better understand which audience we serve and what content is consulted.")]),_,e("ul",null,[p,y,e("li",null,[o("We ignore any existing tracking cookie and our tracking "),f,o(". (See also: "),e("a",g,[o("What are cookies?"),t(n)]),o(")")]),k,m]),e("p",null,[o("You can opt out by clicking "),e("a",b,[o("here"),t(n)]),o(".")])])}const E=a(l,[["render",w],["__file","privacypolicy.html.vue"]]);export{E as default}; +import{_ as a,r,o as s,c as i,a as e,b as o,d as t}from"./app-821120ad.js";const l={},c=e("h1",{id:"privacy-policy",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#privacy-policy","aria-hidden":"true"},"#"),o(" Privacy Policy")],-1),d={href:"https://en.wikipedia.org/wiki/Matomo_(software)",target:"_blank",rel:"noopener noreferrer"},h=e("code",null,"*.gbdev.io",-1),u=e("code",null,"*.gbadev.net",-1),_=e("h3",{id:"how",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#how","aria-hidden":"true"},"#"),o(" How")],-1),p=e("li",null,[o("Visitors' IP addresses are "),e("strong",null,"anonymized"),o(". The last byte is masked and fully qualified addressess "),e("strong",null,"never"),o(" reach our analytics software.")],-1),y=e("li",null,[o("User IDs are replaced by "),e("strong",null,"pseudonyms"),o(" to avoid directly storing and displaying personally identifiable information.")],-1),f=e("strong",null,"DOES NOT use any cookie",-1),g={href:"https://www.cookiesandyou.com/",target:"_blank",rel:"noopener noreferrer"},k=e("li",null,'We honor your browser "I do not want to be tracked" preference.',-1),m=e("li",null,"Data is aggregated and reports are compiled. Raw logs are regularly cleaned up.",-1),b={href:"https://stats.gbdev.io/index.php?module=CoreAdminHome&action=optOut&language=en",target:"_blank",rel:"noopener noreferrer"};function w(v,x){const n=r("ExternalLinkIcon");return s(),i("div",null,[c,e("p",null,[o("We use a self hosted instance of "),e("a",d,[o("Matomo"),t(n)]),o(", a free and open source web analytics application to track online visits to our websites ("),h,o(", "),u,o("), in order to better understand which audience we serve and what content is consulted.")]),_,e("ul",null,[p,y,e("li",null,[o("We ignore any existing tracking cookie and our tracking "),f,o(". (See also: "),e("a",g,[o("What are cookies?"),t(n)]),o(")")]),k,m]),e("p",null,[o("You can opt out by clicking "),e("a",b,[o("here"),t(n)]),o(".")])])}const E=a(l,[["render",w],["__file","privacypolicy.html.vue"]]);export{E as default}; diff --git a/assets/resources.html-5ebeee12.js b/assets/resources.html-7fa92572.js similarity index 99% rename from assets/resources.html-5ebeee12.js rename to assets/resources.html-7fa92572.js index 2ce5385..baab12a 100644 --- a/assets/resources.html-5ebeee12.js +++ b/assets/resources.html-7fa92572.js @@ -1 +1 @@ -import{_ as s,r as l,o as h,c as d,a as e,b as r,d as t,w as i,e as n}from"./app-19015fbd.js";const c={},g=n('
    Awesome Game Boy Development

    A curated list of awesome Game Boy (Color) Development resources, tools, docs, related projects and homebrews. Inspired by the awesome list thing.

    This project is open source and community-lead. Come contribute!


    Introduction

    ',8),m={id:"the-game-boy-a-hardware-autopsy",tabindex:"-1"},p=e("a",{class:"header-anchor",href:"#the-game-boy-a-hardware-autopsy","aria-hidden":"true"},"#",-1),u={href:"https://www.youtube.com/playlist?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",target:"_blank",rel:"noopener noreferrer"},b=e("br",null,null,-1),_=e("div",{class:"videoWrapper"},[e("iframe",{id:"ytplayer",type:"text/html",src:"https://www.youtube.com/embed/videoseries?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",frameborder:"0",allowfullscreen:""}),e("br")],-1),f={id:"the-ultimate-game-boy-talk",tabindex:"-1"},k=e("a",{class:"header-anchor",href:"#the-ultimate-game-boy-talk","aria-hidden":"true"},"#",-1),y={href:"https://media.ccc.de/v/33c3-8029-the_ultimate_game_boy_talk",target:"_blank",rel:"noopener noreferrer"},B=e("br",null,null,-1),G=e("div",{class:"videoWrapper"},[e("iframe",{id:"ytplayer",type:"text/html",src:"https://www.youtube.com/embed/HyzD8pNlpwI",frameborder:"0",allowfullscreen:""}),e("br")],-1),w=e("h3",{id:"disambiguation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#disambiguation","aria-hidden":"true"},"#"),r(" Disambiguation")],-1),v=e("h4",{id:"game-boy-advance",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-advance","aria-hidden":"true"},"#"),r(" Game Boy Advance")],-1),C={href:"https://github.com/gbdev/awesome-gbadev",target:"_blank",rel:"noopener noreferrer"},A=n('

    Game Boy Color and Super Game Boy

    This list is focused on the original (1989) Game Boy (DMG), the Game Boy Color (GBC) and Super Game Boy (SGB) are very similar systems, with a few important distinctions, such as:

    • Different hardware specifications
    • Specific hardware and software features
    • Specific registers
    • Specific bugs, quirks and exploitable behaviours

    If you aim to develop your software for SGB or GBC, or you want to know how it runs on the other systems, you may want to take advantage and adapt to these differences, check the Game Boy Color category and look for specific references to GBC/CGB and SGB.

    ',4),D=e("h2",{id:"documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#documentation","aria-hidden":"true"},"#"),r(" Documentation")],-1),S={href:"https://gbdev.github.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"Pan Docs",-1),x={href:"https://github.com/AntonioND/giibiiadvance/blob/master/docs/TCAGBD.pdf",target:"_blank",rel:"noopener noreferrer"},P={href:"https://gekkio.fi/files/gb-docs/gbctr.pdf",target:"_blank",rel:"noopener noreferrer"},R={href:"https://www.copetti.org/writings/consoles/game-boy/",target:"_blank",rel:"noopener noreferrer"},T={href:"http://www.cs.columbia.edu/~sedwards/classes/2019/4840-spring/reports/GameBoy.pdf",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/kitsuneh/SVGameBoy",target:"_blank",rel:"noopener noreferrer"},j=e("h4",{id:"opcodes",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#opcodes","aria-hidden":"true"},"#"),r(" Opcodes")],-1),L={href:"https://gbdev.github.io/gb-opcodes/optables/",target:"_blank",rel:"noopener noreferrer"},F={href:"https://rgbds.gbdev.io/docs/gbz80.7",target:"_blank",rel:"noopener noreferrer"},z=e("h3",{id:"game-boy-color",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-color","aria-hidden":"true"},"#"),r(" Game Boy Color")],-1),I={href:"https://tcrf.net/Game_Boy_Color_Bootstrap_ROM",target:"_blank",rel:"noopener noreferrer"},O={href:"https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM",target:"_blank",rel:"noopener noreferrer"},H={href:"https://forums.nesdev.com/viewtopic.php?p=114388&sid=c3d4ce08cfd9d9c834958d4f148750c3#p114388",target:"_blank",rel:"noopener noreferrer"},N={href:"https://gist.github.com/drhelius/6063265",target:"_blank",rel:"noopener noreferrer"},K={href:"https://romhack.github.io/doc/gbcHiColour/",target:"_blank",rel:"noopener noreferrer"},U=e("h3",{id:"hardware",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hardware","aria-hidden":"true"},"#"),r(" Hardware")],-1),V={href:"http://gbdev.gg8.se/wiki/articles/DMG_Schematics",target:"_blank",rel:"noopener noreferrer"},W={href:"http://marc.rawer.de/Gameboy/Docs/GBProject.pdf",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/Gekkio/gb-hardware",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/applefreak/esp8266-gameboy-dev-board",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/applefreak/esp8266-gameboy-printer",target:"_blank",rel:"noopener noreferrer"},X={href:"http://verhoeven272.nl/fruttenboel/Gameboy/index.html",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbhwdb.gekkio.fi/",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/msinger/dmg-schematics",target:"_blank",rel:"noopener noreferrer"},$=e("h3",{id:"peripherals",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#peripherals","aria-hidden":"true"},"#"),r(" Peripherals")],-1),ee={href:"https://shonumi.github.io/dandocs.html",target:"_blank",rel:"noopener noreferrer"},re={href:"https://shonumi.github.io/articles.html",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/shonumi/gbe-plus/tree/master/src/docs/technical",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://shonumi.github.io/articles/art14.html",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://shonumi.github.io/articles/art2.html",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://shonumi.github.io/articles/art13.html",target:"_blank",rel:"noopener noreferrer"},le={href:"https://shonumi.github.io/articles/art8.html",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://shonumi.github.io/articles/art11.html",target:"_blank",rel:"noopener noreferrer"},se={href:"https://shonumi.github.io/articles/art9.html",target:"_blank",rel:"noopener noreferrer"},he={href:"https://shonumi.github.io/articles/art7.html",target:"_blank",rel:"noopener noreferrer"},de={href:"https://shonumi.github.io/articles/art6.html",target:"_blank",rel:"noopener noreferrer"},ce={href:"https://raw.githubusercontent.com/shonumi/gbe-plus/master/src/docs/technical/DMG_07.txt",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://github.com/AntonioND/gbcam-rev-engineer",target:"_blank",rel:"noopener noreferrer"},me={href:"http://www.pinchofintelligence.com/photorealistic-neural-network-gameboy/",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://shonumi.github.io/articles/art2.html",target:"_blank",rel:"noopener noreferrer"},ue={href:"https://www.youtube.com/watch?v=43FfJvd-YP4",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/mofosyne/arduino-gameboy-printer-emulator",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://bulbapedia.bulbagarden.net/wiki/Mobile_Game_Boy_Adapter",target:"_blank",rel:"noopener noreferrer"},fe={href:"http://nectaris.tg-16.com/GB-KISS-LINK-FAQ-hudson-gameboy-nectaris.html",target:"_blank",rel:"noopener noreferrer"},ke=e("h3",{id:"cartridges",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#cartridges","aria-hidden":"true"},"#"),r(" Cartridges")],-1),ye={href:"https://bbbbbr.github.io/GameBoy-Flash-Carts/",target:"_blank",rel:"noopener noreferrer"},Be={href:"https://github.com/AntonioND/giibiiadvance/tree/master/docs",target:"_blank",rel:"noopener noreferrer"},Ge={href:"http://gekkio.fi/blog/2015-02-14-mooneye-gb-gameboy-cartridge-types.html",target:"_blank",rel:"noopener noreferrer"},we={href:"http://gekkio.fi/blog/2015-05-18-mooneye-gb-cartridge-analysis-dmg-bean-02.html",target:"_blank",rel:"noopener noreferrer"},ve={href:"http://gekkio.fi/blog/2015-05-17-mooneye-gb-cartridge-analysis-fortress-of-fear.html",target:"_blank",rel:"noopener noreferrer"},Ce={href:"http://gekkio.fi/blog/2015-02-28-mooneye-gb-cartridge-analysis-tetris.html",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://wiki.tauwasser.eu/view/MBC1",target:"_blank",rel:"noopener noreferrer"},De={href:"https://wiki.tauwasser.eu/view/MBC2",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://wiki.tauwasser.eu/view/MMM01",target:"_blank",rel:"noopener noreferrer"},Me={href:"http://www.devrs.com/gb/files/gb.html",target:"_blank",rel:"noopener noreferrer"},xe={href:"https://imgur.com/a/D5bpC",target:"_blank",rel:"noopener noreferrer"},Pe={href:"http://www.devrs.com/gb/files/mbc1.gif",target:"_blank",rel:"noopener noreferrer"},Re={href:"http://fms.komkon.org/GameBoy/Tech/Carts.html",target:"_blank",rel:"noopener noreferrer"},Te=e("li",null,[e("a",{href:"CartridgeList.csv"},"GB Rom List"),r(" - Navigable table of every game released with details on their cartridges.")],-1),Ee={href:"http://gekkio.fi/blog/2016-03-19-game-boy-cartridge-pcb-photos.html",target:"_blank",rel:"noopener noreferrer"},je=e("h4",{id:"custom-cartridges",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#custom-cartridges","aria-hidden":"true"},"#"),r(" Custom cartridges")],-1),Le={href:"https://dhole.github.io/post/gameboy_cartridge_emu_1/",target:"_blank",rel:"noopener noreferrer"},Fe={href:"http://www.happydaze.se/wolf/",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/dwaq/Homebrew-Gameboy-Cartridge",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/Xyl2k/Gameboy-Color-Cartridge",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://github.com/zephray/NekoCart-GB",target:"_blank",rel:"noopener noreferrer"},He={href:"https://hackaday.io/project/41160-nekocart-cpld-gameboy-cartridge",target:"_blank",rel:"noopener noreferrer"},Ne={href:"http://reinerziegler.de.mirrors.gg8.se/",target:"_blank",rel:"noopener noreferrer"},Ke={href:"https://github.com/insidegadgets/Gameboy-MBC5-MBC1-Hybrid",target:"_blank",rel:"noopener noreferrer"},Ue=e("h4",{id:"misc",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#misc","aria-hidden":"true"},"#"),r(" Misc")],-1),Ve={href:"http://pepijndevos.nl/sha2017/workshop.pdf",target:"_blank",rel:"noopener noreferrer"},We={href:"https://github.com/bwhitman/pushpin/blob/master/src/gbsound.txt",target:"_blank",rel:"noopener noreferrer"},Ze={href:"http://www.devrs.com/gb/files/faqs.html",target:"_blank",rel:"noopener noreferrer"},Je={href:"http://www.neviksti.com/DMG/DMG_ROM.asm",target:"_blank",rel:"noopener noreferrer"},qe={href:"http://www.z80.info/z80gboy.txt",target:"_blank",rel:"noopener noreferrer"},Xe={href:"http://www.huderlem.com/demos/gameboy2bpp.html",target:"_blank",rel:"noopener noreferrer"},Ye=e("h2",{id:"emulator-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#emulator-development","aria-hidden":"true"},"#"),r(" Emulator Development")],-1),Qe={href:"https://www.youtube.com/watch?v=GBYwjch6oEE",target:"_blank",rel:"noopener noreferrer"},$e={href:"https://gekkio.fi/blog/2018-02-05-errata-for-reverse-engineering-fine-details-of-game-boy-hardware.html",target:"_blank",rel:"noopener noreferrer"},er={href:"https://github.com/Baekalfen/PyBoy/blob/master/extras/PyBoy.pdf",target:"_blank",rel:"noopener noreferrer"},rr={href:"https://rylev.github.io/DMG-01/public/book/",target:"_blank",rel:"noopener noreferrer"},tr={href:"https://media.ccc.de/v/rustfest-rome-3-gameboy-emulator",target:"_blank",rel:"noopener noreferrer"},or={href:"http://imrannazar.com/gameboy-Emulation-in-JavaScript",target:"_blank",rel:"noopener noreferrer"},nr={href:"https://cturt.github.io/cinoop.html",target:"_blank",rel:"noopener noreferrer"},ar={href:"https://jeremybanks.github.io/0dmg/2018/05/23/getting-started.html",target:"_blank",rel:"noopener noreferrer"},lr={href:"https://realboyemulator.wordpress.com/posts/",target:"_blank",rel:"noopener noreferrer"},ir={href:"http://www.codeslinger.co.uk/pages/projects/gameboy.html",target:"_blank",rel:"noopener noreferrer"},sr={href:"http://blog.rekawek.eu/2017/02/09/coffee-gb/",target:"_blank",rel:"noopener noreferrer"},hr={href:"https://binji.github.io/2017/12/31/binjgb-rewind.html",target:"_blank",rel:"noopener noreferrer"},dr={href:"https://binji.github.io/2017/02/26/binjgb-on-the-web-part-1.html",target:"_blank",rel:"noopener noreferrer"},cr={href:"https://binji.github.io/2017/02/27/binjgb-on-the-web-part-2.html",target:"_blank",rel:"noopener noreferrer"},gr={href:"https://binji.github.io/2017/05/03/debugging-hangs.html",target:"_blank",rel:"noopener noreferrer"},mr={href:"https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html",target:"_blank",rel:"noopener noreferrer"},pr={href:"https://djhworld.github.io/post/2018/09/21/i-ported-my-gameboy-color-emulator-to-webassembly/",target:"_blank",rel:"noopener noreferrer"},ur={href:"https://mitxela.com/projects/swotgb/about",target:"_blank",rel:"noopener noreferrer"},br={href:"https://github.com/robert/gameboy-doctor",target:"_blank",rel:"noopener noreferrer"},_r=e("h3",{id:"testing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#testing","aria-hidden":"true"},"#"),r(" Testing")],-1),fr={href:"http://gbdev.gg8.se/files/roms/blargg-gb-tests/",target:"_blank",rel:"noopener noreferrer"},kr={href:"https://gekkio.fi/files/mooneye-gb/latest/",target:"_blank",rel:"noopener noreferrer"},yr={href:"https://github.com/LIJI32/SameSuite",target:"_blank",rel:"noopener noreferrer"},Br={href:"https://github.com/mattcurrie/mealybug-tearoom-tests",target:"_blank",rel:"noopener noreferrer"},Gr={href:"http://tasvideos.org/EmulatorResources/GBAccuracyTests.html",target:"_blank",rel:"noopener noreferrer"},wr={href:"https://github.com/pinobatch/240p-test-mini/tree/master/gameboy",target:"_blank",rel:"noopener noreferrer"},vr={href:"https://github.com/aaaaaa123456789/rtc3test",target:"_blank",rel:"noopener noreferrer"},Cr={href:"https://github.com/mattcurrie/dmg-acid2",target:"_blank",rel:"noopener noreferrer"},Ar={href:"https://github.com/mattcurrie/cgb-acid2",target:"_blank",rel:"noopener noreferrer"},Dr=e("h2",{id:"software-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#software-development","aria-hidden":"true"},"#"),r(" Software Development")],-1),Sr={href:"https://gbdev.io/guides/tools.html",target:"_blank",rel:"noopener noreferrer"},Mr=e("h3",{id:"assemblers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#assemblers","aria-hidden":"true"},"#"),r(" Assemblers")],-1),xr={href:"https://github.com/gbdev/rgbds",target:"_blank",rel:"noopener noreferrer"},Pr={href:"https://rgbds.gbdev.io/docs/",target:"_blank",rel:"noopener noreferrer"},Rr={href:"https://github.com/csoren/asmotor",target:"_blank",rel:"noopener noreferrer"},Tr={href:"https://github.com/asmotor/asmotor/tree/develop#further-reading",target:"_blank",rel:"noopener noreferrer"},Er={href:"https://github.com/vhelin/wla-dx",target:"_blank",rel:"noopener noreferrer"},jr={href:"http://www.villehelin.com/wla.txt",target:"_blank",rel:"noopener noreferrer"},Lr=e("h3",{id:"compilers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compilers","aria-hidden":"true"},"#"),r(" Compilers")],-1),Fr={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},zr={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Ir={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},Or={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},Hr={href:"https://lemonspawn.com/turbo-rascal-syntax-error-expected-but-begin/",target:"_blank",rel:"noopener noreferrer"},Nr=e("h4",{id:"experimental-proof-of-concepts",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#experimental-proof-of-concepts","aria-hidden":"true"},"#"),r(" Experimental/Proof of Concepts")],-1),Kr={href:"https://daid.github.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},Ur={href:"https://github.com/wiz-lang/wiz",target:"_blank",rel:"noopener noreferrer"},Vr={href:"https://github.com/ams-hackers/gbforth",target:"_blank",rel:"noopener noreferrer"},Wr={href:"https://gitlab.com/BonsaiDen/gbasm-rs",target:"_blank",rel:"noopener noreferrer"},Zr={href:"https://github.com/BonsaiDen/gbasm",target:"_blank",rel:"noopener noreferrer"},Jr={href:"http://www.tni.nl/products/tniasm.html",target:"_blank",rel:"noopener noreferrer"},qr={href:"https://github.com/ulrikdamm/Assembler",target:"_blank",rel:"noopener noreferrer"},Xr={href:"https://github.com/Bevinsky/llvm-gbz80",target:"_blank",rel:"noopener noreferrer"},Yr={href:"https://github.com/Bevinsky/clang-gbz80",target:"_blank",rel:"noopener noreferrer"},Qr={href:"https://github.com/euclio/llvm-gbz80",target:"_blank",rel:"noopener noreferrer"},$r={href:"https://github.com/pokemium/gbdk-go",target:"_blank",rel:"noopener noreferrer"},et=e("h3",{id:"emulators",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#emulators","aria-hidden":"true"},"#"),r(" Emulators")],-1),rt={href:"https://bgb.bircd.org/",target:"_blank",rel:"noopener noreferrer"},tt={href:"https://github.com/LIJI32/SameBoy",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://github.com/Gekkio/mooneye-gb",target:"_blank",rel:"noopener noreferrer"},nt={href:"https://github.com/mgba-emu/mgba",target:"_blank",rel:"noopener noreferrer"},at={href:"https://github.com/binji/binjgb",target:"_blank",rel:"noopener noreferrer"},lt={href:"https://github.com/gb-archive/gambatte",target:"_blank",rel:"noopener noreferrer"},it={href:"https://github.com/aappleby/MetroBoy",target:"_blank",rel:"noopener noreferrer"},st={href:"https://github.com/shonumi/gbe-plus",target:"_blank",rel:"noopener noreferrer"},ht={href:"https://emulicious.net/",target:"_blank",rel:"noopener noreferrer"},dt={href:"https://marketplace.visualstudio.com/items?itemName=emulicious.emulicious-debugger",target:"_blank",rel:"noopener noreferrer"},ct=e("h3",{id:"tools",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tools","aria-hidden":"true"},"#"),r(" Tools")],-1),gt=e("h4",{id:"engines",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#engines","aria-hidden":"true"},"#"),r(" Engines")],-1),mt={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},pt={href:"http://zalods.blogspot.com/2017/01/zgb-little-engine-for-game-boy.html",target:"_blank",rel:"noopener noreferrer"},ut={href:"https://bitbucket.org/HellSuffering/retr0-gb/",target:"_blank",rel:"noopener noreferrer"},bt=e("h4",{id:"development-tools",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-tools","aria-hidden":"true"},"#"),r(" Development tools")],-1),_t={href:"http://www.tensi.eu/thomas/programming/gameboy/gbextended.html",target:"_blank",rel:"noopener noreferrer"},ft={href:"https://github.com/ProGM/gbdk-lib-extension",target:"_blank",rel:"noopener noreferrer"},kt={href:"http://www.dotmatrixgame.com/",target:"_blank",rel:"noopener noreferrer"},yt={href:"https://github.com/mattcurrie/mgbdis",target:"_blank",rel:"noopener noreferrer"},Bt={href:"http://catskull.net/GB-Logo-Generator/",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/bbbbbr/romusage",target:"_blank",rel:"noopener noreferrer"},wt={href:"https://github.com/devdri/awake",target:"_blank",rel:"noopener noreferrer"},vt={href:"https://github.com/raphaklaus/gameboy-text-tools",target:"_blank",rel:"noopener noreferrer"},Ct={href:"https://github.com/eievui5/evscript",target:"_blank",rel:"noopener noreferrer"},At={href:"https://github.com/eievui5/evunit",target:"_blank",rel:"noopener noreferrer"},Dt=e("h4",{id:"graphics-utilities",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#graphics-utilities","aria-hidden":"true"},"#"),r(" Graphics utilities")],-1),St={href:"https://github.com/chrisantonellis/gbtdg",target:"_blank",rel:"noopener noreferrer"},Mt={href:"http://www.devrs.com/gb/hmgd/intro.html",target:"_blank",rel:"noopener noreferrer"},xt={href:"https://github.com/bashaus/gbtiles",target:"_blank",rel:"noopener noreferrer"},Pt={href:"https://github.com/gitendo/bmp2cgb",target:"_blank",rel:"noopener noreferrer"},Rt={href:"https://github.com/LuckyLights/png2gb",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://github.com/exezin/gb-convert",target:"_blank",rel:"noopener noreferrer"},Et={href:"http://make.vg/brewtool/",target:"_blank",rel:"noopener noreferrer"},jt={href:"https://github.com/paul-arutyunov/vtGBte",target:"_blank",rel:"noopener noreferrer"},Lt={href:"https://github.com/TwitchPlaysPokemon/tpp1",target:"_blank",rel:"noopener noreferrer"},Ft={href:"https://github.com/delwink/libstdgb",target:"_blank",rel:"noopener noreferrer"},zt={href:"https://github.com/bbbbbr/gimp-tilemap-gb",target:"_blank",rel:"noopener noreferrer"},It={href:"https://github.com/bbbbbr/gimp-tilemap-helper",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/Rangi42/tilemap-studio",target:"_blank",rel:"noopener noreferrer"},Ht={href:"https://github.com/Optiroc/SuperFamiconv",target:"_blank",rel:"noopener noreferrer"},Nt=e("h4",{id:"hardware-and-rom-utilities",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hardware-and-rom-utilities","aria-hidden":"true"},"#"),r(" Hardware and ROM utilities")],-1),Kt={href:"https://github.com/Palmr/cart-dumper",target:"_blank",rel:"noopener noreferrer"},Ut={href:"https://github.com/jkbenaim/gbcamextract",target:"_blank",rel:"noopener noreferrer"},Vt={href:"https://github.com/svendahlstrand/game-boy-lcd-sniffing",target:"_blank",rel:"noopener noreferrer"},Wt={href:"https://github.com/sanqui/swapdump",target:"_blank",rel:"noopener noreferrer"},Zt={href:"https://github.com/JustinLloyd/Gameboy-LinkUp",target:"_blank",rel:"noopener noreferrer"},Jt=e("h4",{id:"music-drivers-and-trackers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#music-drivers-and-trackers","aria-hidden":"true"},"#"),r(" Music drivers and trackers")],-1),qt={href:"https://github.com/DevEd2/DevSound",target:"_blank",rel:"noopener noreferrer"},Xt={href:"http://gbdev.gg8.se/files/musictools/Aleksi%20Eeben/Carillon%20Editor.zip",target:"_blank",rel:"noopener noreferrer"},Yt={href:"https://github.com/AntonioND/gbt-player",target:"_blank",rel:"noopener noreferrer"},Qt={href:"https://github.com/SimonLarsen/mmlgb",target:"_blank",rel:"noopener noreferrer"},$t={href:"https://github.com/bazzinotti/XPMCK",target:"_blank",rel:"noopener noreferrer"},eo={href:"https://github.com/gbdev/GBSoundSystem",target:"_blank",rel:"noopener noreferrer"},ro={href:"https://github.com/SuperDisk/hUGETracker",target:"_blank",rel:"noopener noreferrer"},to={href:"https://github.com/datguywitha3ds/CBT-FX",target:"_blank",rel:"noopener noreferrer"},oo=n('

    Programming

    Guides, tutorials and tools to develop software for Game Boy using the development toolchains described in the Software Development chapter.

    ASM

    ',3),no={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},ao={href:"http://gameboy.mongenel.com/asmschool.html",target:"_blank",rel:"noopener noreferrer"},lo={href:"https://github.com/tobiasvl/hardware.inc",target:"_blank",rel:"noopener noreferrer"},io={href:"https://gb-archive.github.io/salvage/tutorial_de_ensamblador/tutorial_de_ensamblador_la_decadence.html",target:"_blank",rel:"noopener noreferrer"},so={href:"https://github.com/assemblydigest/gameboy",target:"_blank",rel:"noopener noreferrer"},ho={href:"http://assemblydigest.tumblr.com/post/77203696711/tutorial-making-an-empty-game-boy-rom-in-wiz",target:"_blank",rel:"noopener noreferrer"},co={href:"http://assemblydigest.tumblr.com/post/77404621743/tutorial-making-art-for-the-game-boy",target:"_blank",rel:"noopener noreferrer"},go={href:"http://web.archive.org/web/20150511145100/http://www.bennvenn.com/Beginners_Guide_To_Reverse_Engineering.htm",target:"_blank",rel:"noopener noreferrer"},mo={href:"http://voidptr.io/blog/2017/01/21/GameBoy.html",target:"_blank",rel:"noopener noreferrer"},po={href:"https://imanoleasgames.blogspot.no/2016/12/games-aside-1-super-game-boy.html",target:"_blank",rel:"noopener noreferrer"},uo={href:"https://peterwynroberts.wordpress.com/2014/05/11/gameboy-programming-tutorial-hello-world/",target:"_blank",rel:"noopener noreferrer"},bo={href:"https://github.com/lancekindle/DMGreport",target:"_blank",rel:"noopener noreferrer"},_o={href:"https://gbdev.gg8.se/wiki/articles/OAM_DMA_tutorial",target:"_blank",rel:"noopener noreferrer"},fo={href:"https://github.com/ahrnbom/gbapfomgd",target:"_blank",rel:"noopener noreferrer"},ko=e("h4",{id:"sources",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sources","aria-hidden":"true"},"#"),r(" Sources")],-1),yo=e("p",null,"Fragments of code, effects, proof of concepts and generally non complete games.",-1),Bo={href:"http://www.devrs.com/gb/asmcode.php",target:"_blank",rel:"noopener noreferrer"},Go={href:"https://github.com/EmmaEwert/gameboy",target:"_blank",rel:"noopener noreferrer"},wo={href:"https://github.com/gb-archive/DeadCScroll",target:"_blank",rel:"noopener noreferrer"},vo=e("h4",{id:"timings",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#timings","aria-hidden":"true"},"#"),r(" Timings")],-1),Co={href:"http://blog.kevtris.org/blogfiles/Nitty%20Gritty%20Gameboy%20VRAM%20Timing.txt",target:"_blank",rel:"noopener noreferrer"},Ao={href:"https://www.reddit.com/r/EmuDev/comments/59pawp/gb_mode3_sprite_timing/",target:"_blank",rel:"noopener noreferrer"},Do={href:"http://gameboy.mongenel.com/dmg/gbc_dma_transfers.txt",target:"_blank",rel:"noopener noreferrer"},So={href:"http://gameboy.mongenel.com/dmg/istat98.txt",target:"_blank",rel:"noopener noreferrer"},Mo={href:"https://github.com/jdeblese/gbcpu/wiki/Video-Timing",target:"_blank",rel:"noopener noreferrer"},xo=e("h4",{id:"boilerplates-and-libraries",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#boilerplates-and-libraries","aria-hidden":"true"},"#"),r(" Boilerplates and libraries")],-1),Po={href:"https://github.com/nezticle/rgbds-template",target:"_blank",rel:"noopener noreferrer"},Ro={href:"http://www.devrs.com/gb/files/galp.zip",target:"_blank",rel:"noopener noreferrer"},To={href:"https://github.com/yenatch/bootstrap.gb",target:"_blank",rel:"noopener noreferrer"},Eo={href:"https://github.com/junebug12851/GameboyBoilerplateProj",target:"_blank",rel:"noopener noreferrer"},jo={href:"https://github.com/ahrnbom/gingerbread",target:"_blank",rel:"noopener noreferrer"},Lo={href:"https://github.com/ahrnbom/gbapfomgd",target:"_blank",rel:"noopener noreferrer"},Fo={href:"https://github.com/ISSOtm/gb-vwf",target:"_blank",rel:"noopener noreferrer"},zo={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Io={href:"https://github.com/ISSOtm/gb-starter-kit",target:"_blank",rel:"noopener noreferrer"},Oo={href:"https://github.com/gb-archive/gb-template",target:"_blank",rel:"noopener noreferrer"},Ho=e("h4",{id:"syntax-highlighting-packages",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#syntax-highlighting-packages","aria-hidden":"true"},"#"),r(" Syntax highlighting packages")],-1),No={href:"https://github.com/ISSOtm/gbz80-highlight",target:"_blank",rel:"noopener noreferrer"},Ko={href:"http://www.vim.org/scripts/script.php?script_id=819",target:"_blank",rel:"noopener noreferrer"},Uo={href:"https://github.com/Leandros/dotfiles/blob/master/.vim/syntax/rgbds.vim",target:"_blank",rel:"noopener noreferrer"},Vo={href:"https://packagecontrol.io/packages/RGBDS",target:"_blank",rel:"noopener noreferrer"},Wo={href:"https://github.com/Imanolea/z80asm-vscode",target:"_blank",rel:"noopener noreferrer"},Zo={href:"https://github.com/DonaldHays/rgbds-vscode",target:"_blank",rel:"noopener noreferrer"},Jo={href:"https://github.com/japanoise/rgbds-mode",target:"_blank",rel:"noopener noreferrer"},qo=e("h3",{id:"c",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#c","aria-hidden":"true"},"#"),r(" C")],-1),Xo={href:"https://github.com/gb-archive/salvage/blob/master/misc/8bit_wonderland.pdf",target:"_blank",rel:"noopener noreferrer"},Yo={href:"https://github.com/gbdk-salvage/grooves-game-boy-programming",target:"_blank",rel:"noopener noreferrer"},Qo={href:"http://pastebin.com/F3tHLj68",target:"_blank",rel:"noopener noreferrer"},$o={href:"http://pastebin.com/gzT47MPJ",target:"_blank",rel:"noopener noreferrer"},en={href:"https://refreshgames.co.uk/2016/04/18/gameboy-tutorial-rom/",target:"_blank",rel:"noopener noreferrer"},rn={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Sprite_Tutorial",target:"_blank",rel:"noopener noreferrer"},tn={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Color_Tutorial",target:"_blank",rel:"noopener noreferrer"},on={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Joypad_Tutorial",target:"_blank",rel:"noopener noreferrer"},nn={href:"https://web.archive.org/web/20210427064949/www.personal.triticom.com/~erm/GameBoy/",target:"_blank",rel:"noopener noreferrer"},an={href:"https://videlais.com/2016/07/03/programming-game-boy-games-using-gbdk-part-1-configuring-programming-and-compiling/",target:"_blank",rel:"noopener noreferrer"},ln={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},sn={href:"https://www.youtube.com/playlist?list=PLeEj4c2zF7PaFv5MPYhNAkBGrkx4iPGJo",target:"_blank",rel:"noopener noreferrer"},hn={href:"https://laroldsjubilantjunkyard.com/tutorials/",target:"_blank",rel:"noopener noreferrer"},dn=e("h2",{id:"homebrews",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrews","aria-hidden":"true"},"#"),r(" Homebrews")],-1),cn=e("p",null,"Complete and open source games.",-1),gn={href:"https://hh.gbdev.io",target:"_blank",rel:"noopener noreferrer"},mn=e("h3",{id:"asm-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#asm-1","aria-hidden":"true"},"#"),r(" ASM")],-1),pn={href:"https://github.com/BonsaiDen/Tuff.gb",target:"_blank",rel:"noopener noreferrer"},un={href:"https://github.com/Sanqui/2048-gb",target:"_blank",rel:"noopener noreferrer"},bn={href:"https://bitbucket.org/Sanqui/snake/src/?at=master",target:"_blank",rel:"noopener noreferrer"},_n={href:"https://github.com/huderlem/lazerpong",target:"_blank",rel:"noopener noreferrer"},fn={href:"https://github.com/AntonioND/geometrix",target:"_blank",rel:"noopener noreferrer"},kn={href:"https://github.com/AntonioND/ucity",target:"_blank",rel:"noopener noreferrer"},yn={href:"https://github.com/mholtkamp/carazu",target:"_blank",rel:"noopener noreferrer"},Bn={href:"https://github.com/DonaldHays/snake-gb",target:"_blank",rel:"noopener noreferrer"},Gn={href:"https://github.com/furrtek/GB303",target:"_blank",rel:"noopener noreferrer"},wn={href:"https://github.com/JustSid/Sushi",target:"_blank",rel:"noopener noreferrer"},vn={href:"https://github.com/bitnenfer/flappy-boy-asm",target:"_blank",rel:"noopener noreferrer"},Cn={href:"https://github.com/dubvulture/gbdev",target:"_blank",rel:"noopener noreferrer"},An={href:"https://github.com/tbsp/Adjustris",target:"_blank",rel:"noopener noreferrer"},Dn={href:"https://github.com/exezin/exeman/",target:"_blank",rel:"noopener noreferrer"},Sn={href:"https://github.com/ISSOtm/Aevilia-GB",target:"_blank",rel:"noopener noreferrer"},Mn={href:"https://github.com/Kartones/gameboy",target:"_blank",rel:"noopener noreferrer"},xn={href:"https://github.com/dannye/pokered-gbc",target:"_blank",rel:"noopener noreferrer"},Pn={href:"https://github.com/tslanina/Retro-GameBoyColor-ToyToy",target:"_blank",rel:"noopener noreferrer"},Rn={href:"https://github.com/tslanina/Retro-GameBoyColor-StefaN",target:"_blank",rel:"noopener noreferrer"},Tn={href:"https://github.com/tslanina/Retro-GameBoyColor-Galaxia",target:"_blank",rel:"noopener noreferrer"},En={href:"https://github.com/sanqui/desgb",target:"_blank",rel:"noopener noreferrer"},jn={href:"https://github.com/l0k1/superhappyfunbubbletime",target:"_blank",rel:"noopener noreferrer"},Ln={href:"https://github.com/lancekindle/minesweepGB",target:"_blank",rel:"noopener noreferrer"},Fn={href:"https://github.com/pinobatch/libbet",target:"_blank",rel:"noopener noreferrer"},zn={href:"https://github.com/dannye/waveform-gb",target:"_blank",rel:"noopener noreferrer"},In={href:"https://gitlab.com/BonsaiDen/vectroid.gb",target:"_blank",rel:"noopener noreferrer"},On={href:"https://github.com/gb-archive/plantboy",target:"_blank",rel:"noopener noreferrer"},Hn={href:"https://makrill.itch.io/death-planet",target:"_blank",rel:"noopener noreferrer"},Nn={href:"https://makrill.itch.io/quartet",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://snorpung.itch.io/dangan-gb",target:"_blank",rel:"noopener noreferrer"},Un=e("h3",{id:"c-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#c-1","aria-hidden":"true"},"#"),r(" C")],-1),Vn={href:"https://github.com/bitnenfer/FlappyBoy",target:"_blank",rel:"noopener noreferrer"},Wn={href:"https://github.com/pashutk/flappybird-gameboy",target:"_blank",rel:"noopener noreferrer"},Zn={href:"https://github.com/gb-archive/fbgb",target:"_blank",rel:"noopener noreferrer"},Jn={href:"https://web.archive.org/web/20171002042716/http://ludumdare.com/compo/ludum-dare-34/?action=preview&uid=6823",target:"_blank",rel:"noopener noreferrer"},qn={href:"https://github.com/cppchriscpp/SquishyTheTurtle",target:"_blank",rel:"noopener noreferrer"},Xn={href:"https://github.com/avivace/quadratino",target:"_blank",rel:"noopener noreferrer"},Yn={href:"https://github.com/elfgames/doctorhow",target:"_blank",rel:"noopener noreferrer"},Qn={href:"https://github.com/Zal0/gbjam2016",target:"_blank",rel:"noopener noreferrer"},$n={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},ea={href:"https://github.com/brovador/GBsnake",target:"_blank",rel:"noopener noreferrer"},ra={href:"https://github.com/andreasjhkarlsson/gb-mines",target:"_blank",rel:"noopener noreferrer"},ta={href:"http://www.atari2600land.com/gameboy/oranges.html",target:"_blank",rel:"noopener noreferrer"},oa={href:"https://github.com/Imanolea/bitbitjam3_red_hot_princess_carnage",target:"_blank",rel:"noopener noreferrer"},na={href:"http://www.tensi.eu/thomas/programming/gameboy/loderunner.html",target:"_blank",rel:"noopener noreferrer"},aa={href:"https://refreshgames.co.uk/2017/04/24/ludum-dare-38-entry-hives/",target:"_blank",rel:"noopener noreferrer"},la={href:"https://github.com/DonaldHays/bubblefactory",target:"_blank",rel:"noopener noreferrer"},ia={href:"https://github.com/rubfi/gbc-atari-boxing",target:"_blank",rel:"noopener noreferrer"},sa={href:"https://github.com/haroldo-ok/really-old-stuff/tree/master/gameboy",target:"_blank",rel:"noopener noreferrer"},ha={href:"https://github.com/SimonLarsen/tobutobugirl-dx",target:"_blank",rel:"noopener noreferrer"},da={href:"http://sebastianmihai.com/gameboy-burly-bear.html",target:"_blank",rel:"noopener noreferrer"},ca={href:"http://sebastianmihai.com/gameboy-color-burly-bear.html",target:"_blank",rel:"noopener noreferrer"},ga={href:"https://github.com/MasterIV/PostBot",target:"_blank",rel:"noopener noreferrer"},ma={href:"https://github.com/kanfor/gunsridersgameboy",target:"_blank",rel:"noopener noreferrer"},pa={href:"https://github.com/gingemonster/DinosOfflineAdventure",target:"_blank",rel:"noopener noreferrer"},ua={href:"https://github.com/rnegron/dino-gb",target:"_blank",rel:"noopener noreferrer"},ba={href:"https://github.com/flozz/evoland.gb",target:"_blank",rel:"noopener noreferrer"},_a={href:"https://github.com/bbbbbr/Petris",target:"_blank",rel:"noopener noreferrer"},fa={href:"https://bbbbbr.itch.io/petris",target:"_blank",rel:"noopener noreferrer"},ka={href:"https://github.com/gb-archive/infinity-gbc",target:"_blank",rel:"noopener noreferrer"},ya={href:"https://gbdev.gg8.se/forums/viewtopic.php?id=743",target:"_blank",rel:"noopener noreferrer"},Ba={href:"https://user0x7f.itch.io/black-castle",target:"_blank",rel:"noopener noreferrer"},Ga={href:"https://gbdev.gg8.se/forums/viewtopic.php?id=674",target:"_blank",rel:"noopener noreferrer"},wa={href:"https://user0x7f.itch.io/genesis",target:"_blank",rel:"noopener noreferrer"},va={href:"https://antonylavelle.itch.io/indestructotank-gb",target:"_blank",rel:"noopener noreferrer"},Ca={href:"https://pocketpixel.design/super-jetpak-dx-game-boy-rom.html",target:"_blank",rel:"noopener noreferrer"},Aa={href:"https://aiguanachein.itch.io/powa",target:"_blank",rel:"noopener noreferrer"},Da={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},Sa={href:"https://thegreatgallus.itch.io/cavern-mvm-9",target:"_blank",rel:"noopener noreferrer"},Ma={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},xa={href:"https://ctneptune.itch.io/mona-and-the-witchs-hat-dx",target:"_blank",rel:"noopener noreferrer"},Pa={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},Ra={href:"https://gamejolt.com/games/the-bouncing-ball-gb/86699",target:"_blank",rel:"noopener noreferrer"},Ta={href:"https://drludos.itch.io/dmg-deals-damage",target:"_blank",rel:"noopener noreferrer"},Ea=e("h3",{id:"gb-studio",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gb-studio","aria-hidden":"true"},"#"),r(" GB Studio")],-1),ja={href:"https://kadabura.itch.io/soul-void",target:"_blank",rel:"noopener noreferrer"},La={href:"https://izma.itch.io/deadeus",target:"_blank",rel:"noopener noreferrer"},Fa={href:"https://lumpytouch.itch.io/super-impostor-bros",target:"_blank",rel:"noopener noreferrer"},za=e("h3",{id:"demos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#demos","aria-hidden":"true"},"#"),r(" Demos")],-1),Ia={href:"https://github.com/AntonioND/back-to-color",target:"_blank",rel:"noopener noreferrer"},Oa={href:"https://github.com/vegard/beach-gbc",target:"_blank",rel:"noopener noreferrer"},Ha={href:"https://github.com/mills32/CUTE_DEMO",target:"_blank",rel:"noopener noreferrer"},Na={href:"https://github.com/svendahlstrand/10-print-game-boy",target:"_blank",rel:"noopener noreferrer"},Ka=e("code",null,"10 PRINT",-1),Ua={href:"https://github.com/naavis/roboto-demo",target:"_blank",rel:"noopener noreferrer"},Va={href:"https://github.com/wtjones/matrix-rain-gb",target:"_blank",rel:"noopener noreferrer"},Wa={href:"https://github.com/LIJI32/GBVideoPlayer",target:"_blank",rel:"noopener noreferrer"},Za={href:"https://github.com/LIJI32/GBVideoPlayer2",target:"_blank",rel:"noopener noreferrer"},Ja=e("em",null,"stereo- PCM audio, and introduces video compression",-1),qa=e("h2",{id:"reverse-engineering",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#reverse-engineering","aria-hidden":"true"},"#"),r(" Reverse Engineering")],-1),Xa={href:"http://ecc-comp.blogspot.it/2016/03/reverse-engineering-kirbys-dreamland-2.html",target:"_blank",rel:"noopener noreferrer"},Ya={href:"https://github.com/pret/pokemon-reverse-engineering-tools",target:"_blank",rel:"noopener noreferrer"},Qa={href:"https://www.megabeets.net/reverse-engineering-a-gameboy-rom-with-radare2",target:"_blank",rel:"noopener noreferrer"},$a={href:"http://kemenaran.winosx.com/posts/category-disassembling-links-awakening/",target:"_blank",rel:"noopener noreferrer"},el={href:"https://github.com/h3nnn4n/Reverse-Engineering-the-GameBoy-Tetris",target:"_blank",rel:"noopener noreferrer"},rl={href:"https://gbdev.io/guides/dma_hijacking",target:"_blank",rel:"noopener noreferrer"},tl=e("h3",{id:"game-disassemblies",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-disassemblies","aria-hidden":"true"},"#"),r(" Game Disassemblies")],-1),ol={href:"https://github.com/pret/pokered",target:"_blank",rel:"noopener noreferrer"},nl={href:"https://github.com/pret/pokecrystal",target:"_blank",rel:"noopener noreferrer"},al={href:"https://github.com/pret/pokeyellow",target:"_blank",rel:"noopener noreferrer"},ll={href:"https://github.com/pret/pokegold",target:"_blank",rel:"noopener noreferrer"},il={href:"https://github.com/pret/pokepinball",target:"_blank",rel:"noopener noreferrer"},sl={href:"https://github.com/pret/poketcg",target:"_blank",rel:"noopener noreferrer"},hl={href:"https://github.com/pret/pokegold-spaceworld",target:"_blank",rel:"noopener noreferrer"},dl={href:"https://github.com/mojobojo/LADX-Disassembly",target:"_blank",rel:"noopener noreferrer"},cl={href:"https://github.com/drenn1/ages-disasm",target:"_blank",rel:"noopener noreferrer"},gl={href:"https://github.com/vinheim3/tetris-gb-disasm",target:"_blank",rel:"noopener noreferrer"},ml={href:"https://github.com/DevEd2/FXHammer-Disasm",target:"_blank",rel:"noopener noreferrer"},pl={href:"https://github.com/sanqui/hm3",target:"_blank",rel:"noopener noreferrer"},ul={href:"https://github.com/daid/FFA-disassembly",target:"_blank",rel:"noopener noreferrer"},bl=e("h2",{id:"game-boy-camera",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-camera","aria-hidden":"true"},"#"),r(" Game Boy Camera")],-1),_l=e("h3",{id:"retrieving-images",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#retrieving-images","aria-hidden":"true"},"#"),r(" Retrieving images")],-1),fl=e("p",null,"Game Boy Printer emulation (e.g. to retrieve images from the camera):",-1),kl={href:"https://github.com/mofosyne/arduino-gameboy-printer-emulator",target:"_blank",rel:"noopener noreferrer"},yl={href:"https://github.com/applefreak/esp8266-gameboy-printer",target:"_blank",rel:"noopener noreferrer"},Bl={href:"https://github.com/HerrZatacke/wifi-gbp-emulator",target:"_blank",rel:"noopener noreferrer"},Gl={href:"https://github.com/cristofercruz/gbp-esp-shield-pcb",target:"_blank",rel:"noopener noreferrer"},wl={href:"https://github.com/mofosyne/GameboyPrinterSniffer",target:"_blank",rel:"noopener noreferrer"},vl=e("h3",{id:"changing-the-camera-s-behavior",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#changing-the-camera-s-behavior","aria-hidden":"true"},"#"),r(" Changing the camera's behavior")],-1),Cl=e("p",null,"Methods to improve and/or manipulate the camera's quality and behavior:",-1),Al={href:"http://ekeler.com/game-boy-camera-canon-ef-mount",target:"_blank",rel:"noopener noreferrer"},Dl={href:"https://www.thingiverse.com/thing:4337362",target:"_blank",rel:"noopener noreferrer"},Sl={href:"https://github.com/cristofercruz/game-boy-camera-frame-replacer",target:"_blank",rel:"noopener noreferrer"},Ml=e("h3",{id:"post-processing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#post-processing","aria-hidden":"true"},"#"),r(" Post processing")],-1),xl={href:"https://github.com/mofosyne/GameboyPrinterPaperSimulation",target:"_blank",rel:"noopener noreferrer"},Pl={href:"https://github.com/HerrZatacke/gb-printer-web",target:"_blank",rel:"noopener noreferrer"},Rl=e("h2",{id:"related-projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#related-projects","aria-hidden":"true"},"#"),r(" Related projects")],-1),Tl={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},El={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},jl={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},Ll={href:"https://github.com/trash80/Arduinoboy",target:"_blank",rel:"noopener noreferrer"},Fl={href:"https://github.com/diegovalverde/papiGB",target:"_blank",rel:"noopener noreferrer"},zl={href:"https://github.com/trun/fpgaboy",target:"_blank",rel:"noopener noreferrer"},Il={href:"https://github.com/danShumway/Piglet",target:"_blank",rel:"noopener noreferrer"},Ol={href:"https://github.com/PumpMagic/ostrich",target:"_blank",rel:"noopener noreferrer"},Hl={href:"https://github.com/trash80/mGB",target:"_blank",rel:"noopener noreferrer"},Nl={href:"https://github.com/LIJI32/GBVisualizer",target:"_blank",rel:"noopener noreferrer"},Kl={href:"https://github.com/drhelius/arduinogameboy",target:"_blank",rel:"noopener noreferrer"},Ul={href:"https://github.com/bitnenfer/gameboy-brainfuck",target:"_blank",rel:"noopener noreferrer"},Vl={href:"https://github.com/elseyf/gbfk",target:"_blank",rel:"noopener noreferrer"},Wl={href:"https://github.com/mattcurrie/gb-save-states",target:"_blank",rel:"noopener noreferrer"},Zl={href:"https://github.com/jdeblese/gbcpu",target:"_blank",rel:"noopener noreferrer"},Jl={href:"https://youtube.com/watch?v=1lzHfLYzyRM",target:"_blank",rel:"noopener noreferrer"},ql={href:"https://dhole.github.io/post/gameboy_serial_1/",target:"_blank",rel:"noopener noreferrer"},Xl={href:"https://dhole.github.io/post/gameboy_serial_2/",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://dhole.github.io/post/gameboy_serial_3/",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://dhole.github.io/post/gameboy_cartridge_rw_1/",target:"_blank",rel:"noopener noreferrer"},$l={href:"https://tilde.town/~minerobber/techwriteups/pokemonpc.html",target:"_blank",rel:"noopener noreferrer"},ei={href:"https://dhole.github.io/post/gameboy_custom_logo/",target:"_blank",rel:"noopener noreferrer"},ri={href:"https://www.gamasutra.com/blogs/DoctorLudos/20171207/311143/",target:"_blank",rel:"noopener noreferrer"},ti={href:"https://www.gamasutra.com/blogs/DoctorLudos/20180213/314554/",target:"_blank",rel:"noopener noreferrer"},oi={href:"http://fuji.drillspirits.net/?post=87",target:"_blank",rel:"noopener noreferrer"},ni={href:"https://github.com/stijnfrishert/liblsdj",target:"_blank",rel:"noopener noreferrer"},ai={href:"https://github.com/jkotlinski/lsdpatch",target:"_blank",rel:"noopener noreferrer"},li={href:"https://github.com/ChaosCabbage/crazy-gameboy-video-experiments",target:"_blank",rel:"noopener noreferrer"},ii={href:"https://github.com/ekimekim/gbos",target:"_blank",rel:"noopener noreferrer"},si={href:"https://translate.google.com/translate?hl=&sl=ru&tl=en&u=https%3A%2F%2Fweb.archive.org%2Fweb%2F20081226145726%2Fhttp%3A%2F%2Fworkmaster.ru%2Findex.php%3Fp%3D8&sandbox=1",target:"_blank",rel:"noopener noreferrer"},hi={href:"https://github.com/Palmr/gb-link-cable",target:"_blank",rel:"noopener noreferrer"},di={href:"https://github.com/Tauwasser/GBCartFlasher",target:"_blank",rel:"noopener noreferrer"},ci={href:"https://github.com/zephray/VerilogBoy/",target:"_blank",rel:"noopener noreferrer"},gi={href:"https://github.com/furrtek/GBCamcorder",target:"_blank",rel:"noopener noreferrer"},mi={href:"https://github.com/insidegadgets/GBCartRead",target:"_blank",rel:"noopener noreferrer"},pi={href:"https://github.com/insidegadgets/GBxCart-RW",target:"_blank",rel:"noopener noreferrer"},ui={href:"http://www.its.caltech.edu/~costis/sgb_hack/",target:"_blank",rel:"noopener noreferrer"},bi=e("h3",{id:"directories",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#directories","aria-hidden":"true"},"#"),r(" Directories")],-1),_i={href:"http://gbdev.gg8.se/files/",target:"_blank",rel:"noopener noreferrer"},fi={href:"https://github.com/gb-archive",target:"_blank",rel:"noopener noreferrer"},ki={href:"https://github.com/gb-archive/salvage",target:"_blank",rel:"noopener noreferrer"},yi=e("h3",{id:"websites",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#websites","aria-hidden":"true"},"#"),r(" Websites")],-1),Bi={href:"http://devrs.com/gb",target:"_blank",rel:"noopener noreferrer"},Gi={href:"http://pdroms.de/news/gameboy/",target:"_blank",rel:"noopener noreferrer"},wi={href:"http://hhug.me",target:"_blank",rel:"noopener noreferrer"};function vi(Ci,Ai){const o=l("ExternalLinkIcon"),a=l("RouterLink");return h(),d("div",null,[g,e("h3",m,[p,r(),e("a",u,[r("The Game Boy, a hardware autopsy"),t(o)])]),b,_,e("h3",f,[k,r(),e("a",y,[r("The Ultimate Game Boy Talk"),t(o)])]),B,G,e("blockquote",null,[w,v,e("p",null,[r("Game Boy Advance development is covered by another project, the "),e("a",C,[r("awesome-GBAdev"),t(o)]),r(" list. GBA, however, can run GB/GBC games. It does so in a slightly different way compared to native hardware. This is covered in the Emulator Development section of this list.")]),A]),D,e("ul",null,[e("li",null,[e("a",S,[M,t(o)]),r(" - The single, most comprehensive technical reference to Game Boy available to the public. Corrected, updated and maintained by the community.")]),e("li",null,[e("a",x,[r("The Cycle-Accurate Game Boy Docs"),t(o)]),r(" - A precise documentation by AntonioND to make a cycle-accurate Game Boy emulator.")]),e("li",null,[e("a",P,[r("Complete Technical Reference"),t(o)]),r(" - by Gekkio.")]),e("li",null,[e("a",R,[r("Game Boy Architecture: A Practical Analysis"),t(o)]),r(" - by Rodrigo Copetti.")]),e("li",null,[e("a",T,[r("Game Boy Project Report"),t(o)]),r(" - Report of an hardware "),e("a",E,[r("emulator"),t(o)]),r(" (on a Terasic DE1-SoC Board) developed as final project for the CSEE4840 Embedded Systems Design course at Columbia University.")])]),j,e("ul",null,[e("li",null,[e("a",L,[r("gb-opcodes"),t(o)]),r(" - Opcodes table")]),e("li",null,[e("a",F,[r("RGBDS opcodes reference"),t(o)]),r(" - A reference of all instructions, including short descriptions, cycle and byte counts, and explanations of flag modifications.")])]),z,e("ul",null,[e("li",null,[e("a",I,[r("Bootstrap ROM"),t(o)])]),e("li",null,[e("a",O,[r("Unused Palettes"),t(o)])]),e("li",null,[e("a",H,[r("Colorization palettes in the BIOS"),t(o)])]),e("li",null,[e("a",N,[r("Boot ROM Disassembly"),t(o)])]),e("li",null,[e("a",K,[r("GBC Hicolour notes"),t(o)]),r(" - A technical note regarding Hicolour mode trick for Game Boy Color and its realization in the GBC game “Crystalis”.")])]),U,e("ul",null,[e("li",null,[e("a",V,[r("DMG Schematics"),t(o)]),r(" - Hardware schematics.")]),e("li",null,[e("a",W,[r("The Game Boy Project"),t(o)]),r(" - Provides a study on the hardware and detailed constructional information for the implementation of three 8-bit bidirectional parallel ports.")]),e("li",null,[e("a",Z,[r("Related custom hardware"),t(o)]),r(" - by Gekkio.")]),e("li",null,[e("a",J,[r("ESP8266 GB Dev Board"),t(o)]),r(" - Dev board for Game Boy accessories development, powered by ESP8266.")]),e("li",null,[e("a",q,[r("ESP8266 GB Printer"),t(o)]),r(" - A device that emulates the GB Printer and lets you retrieve images using WiFi.")]),e("li",null,[e("a",X,[r("fruttenboel"),t(o)]),r(" - Page with loads of information on the hardware, custom boards to interface with the console and other related projects.")]),e("li",null,[e("a",Y,[r("Game Boy hardware database"),t(o)]),r(" - Data and photos of various types of Game Boy consoles.")]),e("li",null,[e("a",Q,[r("dmg-schematics"),t(o)]),r(" - Schematics and annotated overlay for the DMG-CPU B chip, extracted from die photos, made with KiCad. Also contains Electric VLSI library with layouts for some of the cells and memories.")])]),$,e("ul",null,[e("li",null,[e("a",ee,[r("Dan Docs"),t(o)]),r(" - Obscure Game Boy hardware documentation.")]),e("li",null,[e("a",re,[r("Edge of Emulation"),t(o)]),r(", a series of articles about emulating and investigating Game Boy accessories. Also available as "),e("a",te,[r("technical documents"),t(o)]),r(" in the GBE- emulator documentation. "),e("ul",null,[e("li",null,[e("a",oe,[r("Mobile Adapter GB"),t(o)]),r(" - Internet connectivity and DLC on the Game Boy Color.")]),e("li",null,[e("a",ne,[r("The Game Boy Printer"),t(o)])]),e("li",null,[e("a",ae,[r("Pocket Sonar"),t(o)]),r(" - A blue cart with built-in sonar hardware.")]),e("li",null,[e("a",le,[r("Zok Zok Heroes"),t(o)]),r(" - Zok Zok Heroes' Full Changer, a motion-activated accessory.")]),e("li",null,[e("a",ie,[r("Infrared Madness"),t(o)]),r(" - Infrared communication on the Game Boy Color.")]),e("li",null,[e("a",se,[r("Game Boy 4-Player Adapter"),t(o)]),r(" - DMG-07.")]),e("li",null,[e("a",he,[r("Barcode Boy"),t(o)]),r(" - The first Game Boy card-scanner.")]),e("li",null,[e("a",de,[r("Barcode Taisen Bardigun"),t(o)]),r(" - A late 90s DMG-GBC barcode reader.")])])]),e("li",null,[e("a",ce,[r("DMG-07 Technical Documentation"),t(o)])]),e("li",null,[e("a",ge,[r("Game Boy Camera RE"),t(o)]),r(" - Documentation about GB Camera and tools used to reverse engineer it by using Arduino.")]),e("li",null,[e("a",me,[r("Creating photo realistic images with neural networks and a Gameboy Camera"),t(o)])]),e("li",null,[e("a",pe,[r("The Game Boy Printer"),t(o)]),r(" - An in-depth technical document about the printer hardware, the communication protocol and the usual routine that games used for implementing the print feature.")]),e("li",null,[e("a",ue,[r("Ben Heck Reverse Engineers Game Boy Printer"),t(o)]),r(" (Errata: the used thermal paper is expired, 4 colors are actually printable).")]),e("li",null,[e("a",be,[r("Arduino Game Boy Printer Emulator"),t(o)]),r(" - Emulating a Game Boy Printer via the Game Boy Link cable with an Arduino.")]),e("li",null,[e("a",_e,[r("Mobile Game Boy Adapter"),t(o)])]),e("li",null,[e("a",fe,[r("GB KISS LINK MODEM"),t(o)])])]),ke,e("ul",null,[e("li",null,[e("a",ye,[r("GB Flash Cartridges for Sale"),t(o)]),r(" - A List of available, ready-made Game Boy Flash Cartridges.")]),e("li",null,[e("a",Be,[r("AntonioND's docs"),t(o)]),r(" - Corrected schematics and infos on cartridge header data.")]),e("li",null,[e("a",Ge,[r("Gekkio's Game Boy cartridge types"),t(o)]),r(" - An overview on existing cartridge types.")]),e("li",null,[r("Gekkio's cartridge analysis: "),e("ul",null,[e("li",null,[e("a",we,[r("DMG-BEAN-02"),t(o)]),r(";")]),e("li",null,[e("a",ve,[r("MBC1"),t(o)]),r(";")]),e("li",null,[e("a",Ce,[r("no MBC"),t(o)]),r(".")])])]),e("li",null,[r("Pinout, registers descriptions and VHDL code of some cartridge types on Tauwasser's wiki: "),e("ul",null,[e("li",null,[e("a",Ae,[r("MBC1"),t(o)])]),e("li",null,[e("a",De,[r("MBC2"),t(o)])]),e("li",null,[e("a",Se,[r("MMM01"),t(o)])])])]),e("li",null,[e("a",Me,[r("Game Boy Cartridges Schematics"),t(o)]),r(" - Schematics for MBC2 and MBC3 types.")]),e("li",null,[e("a",xe,[r("Cartridges PCB photos"),t(o)])]),e("li",null,[e("a",Pe,[r("MBC1+RAM+Battery cartridge Schematic"),t(o)]),r(" - First schematics by Jeff Frohwein.")]),e("li",null,[e("a",Re,[r("MBC1 and MBC2 cartridges circuits"),t(o)]),r(" - and explanation on how these MBC bank switch and control RAM.")]),Te,e("li",null,[e("a",Ee,[r("Game Boy cartridge PCB photos"),t(o)])])]),je,e("ul",null,[e("li",null,[e("a",Le,[r("Emulating a GameBoy Cartridge"),t(o)]),r(" - Emulating the functionality of a Game Boy cartridge with the development board STM32F4.")]),e("li",null,[e("a",Fe,[r("Wolf"),t(o)]),r(" - Game Boy cartridge with co-processor.")]),e("li",null,[e("a",ze,[r("Homebrew-Gameboy-Cartridge"),t(o)]),r(" - Eagle library, schematic, and board files for a cartridge PCB using an Atmel AT49F040 as ROM.")]),e("li",null,[e("a",Ie,[r("Homebrew Gameboy Color Cartridge"),t(o)]),r(" - Board layout for an EEPROM powered cartridge.")]),e("li",null,[e("a",Oe,[r("Nekocart"),t(o)]),r(" - Open-source flash cartridge using an Xilinx CPLD as MBC5 ("),e("a",He,[r("Post"),t(o)]),r(").")]),e("li",null,[e("a",Ne,[r("Reiner Ziegler's Game Boy page"),t(o)]),r(" - Commercial and homemade programmable cartridges and programming systems. Tutorials, wiring and schematics provided.")]),e("li",null,[e("a",Ke,[r("Gameboy-MBC5-MBC1-Hybrid"),t(o)]),r(" - CPLD implementation of a MBC5/MBC1 Hybrid cartridge.")])]),Ue,e("ul",null,[e("li",null,[e("a",Ve,[r("Introduction to Game Boy Hacking"),t(o)]),r(" - Workshop introducing basic assembly, debugging and reverse engineering.")]),e("li",null,[e("a",We,[r("GBSOUND.txt"),t(o)]),r(" - A document detailing the Game Boy sound engine.")]),e("li",null,[e("a",Ze,[r("gbdev FAQs"),t(o)]),r(" - Must read by Jeff Frohwein.")]),e("li",null,[e("a",Je,[r("Game Boy Bootrom"),t(o)]),r(" - Commented dump of the DMG bootrom.")]),e("li",null,[e("a",qe,[r("Differences between the Z80 and the gameboy's processor"),t(o)])]),e("li",null,[e("a",Xe,[r("Gameboy 2BPP Graphics Format"),t(o)]),r(" - Information on how the Game Boy interprets VRAM tile data to color pixels.")])]),Ye,e("ul",null,[e("li",null,[e("a",Qe,[r("Reverse Engineering fine details of Game Boy hardware"),t(o)]),r(" - 43 minutes talk by Gekkio given at Disobey 2018 ("),e("a",$e,[r("errata"),t(o)]),r(").")]),e("li",null,[e("a",er,[r("Emulation of Nintendo Game Boy"),t(o)]),r(" - Overview of the Game Boy hardware with the perspective of building an emulator.")]),e("li",null,[e("a",rr,[r("DMG-01"),t(o)]),r(" - An educational Gameboy Emulator in Rust and a companion book explaining its development. *"),e("a",tr,[r("Oh Boy! Creating a Game Boy Emulator in Rust"),t(o)]),r("- is a talk given at Rust Fest 18 about this.")]),e("li",null,[e("a",or,[r("Building a Game Boy emulator in JavaScript"),t(o)]),r(" - Step by step tutorial.")]),e("li",null,[e("a",nr,[r("Writing a Game Boy emulator, Cinoop"),t(o)])]),e("li",null,[e("a",ar,[r("0dmg"),t(o)]),r(" - Learning Rust by building a partial Game Boy emulator.")]),e("li",null,[e("a",lr,[r("RealBoy Emulator"),t(o)]),r(" - A series of posts about the design and implementation of the RealBoy Emulator.")]),e("li",null,[e("a",ir,[r("Codeslinger"),t(o)]),r(" - Another series of posts documenting the building of an emulator.")]),e("li",null,[e("a",sr,[r("Why did I spend 1.5 months creating a Gameboy emulator?"),t(o)]),r(" - Blog post.")]),e("li",null,[e("a",hr,[r("binjgb rewind"),t(o)]),r(" - Implementing a *rewind- feature.")]),e("li",null,[e("a",dr,[r("binjgb on the web"),t(o)]),r(" - Porting of the binjgb emulator to Web Assembly. "),e("a",cr,[r("(Part 2)"),t(o)])]),e("li",null,[e("a",gr,[r("binjgb debugging hangs"),t(o)]),r(" - Investigations on emulations quirks.")]),e("li",null,[e("a",mr,[r("Decoding Gameboy Z80 opcodes"),t(o)]),r(" - How to algorithmically decode Game Boy instructions (as opposed to writing one huge switch-case statement).")]),e("li",null,[e("a",pr,[r("Porting a GO Game Boy emulator to WebAssembly"),t(o)])]),e("li",null,[e("a",ur,[r("About swotGB"),t(o)]),r(" - Notes about the development of a Game Boy emulator in JavaScript.")]),e("li",null,[t(a,{to:"/EMULATORS.html"},{default:i(()=>[r("List of open source emulators")]),_:1})]),e("li",null,[e("a",br,[r("Game Boy Doctor"),t(o)]),r(" - A command line tool for comparing logs from your emulator to those from a known-correct one. Useful for line-by-line debugging of Blargg's test ROMs.")])]),_r,e("ul",null,[e("li",null,[e("a",fr,[r("Blargg's test roms"),t(o)])]),e("li",null,[e("a",kr,[r("Gekkio's test roms"),t(o)])]),e("li",null,[e("a",yr,[r("SameSuite"),t(o)])]),e("li",null,[e("a",Br,[r("Mealybug Tearoom Tests"),t(o)])]),e("li",null,[e("a",Gr,[r("GB Accuracy Tests"),t(o)])]),e("li",null,[e("a",wr,[r("144p Test Suite"),t(o)]),r(" - Port of Artemio Urbina's 240p Test Suite to the Game Boy.")]),e("li",null,[e("a",vr,[r("MBC3 RTC test ROM"),t(o)])]),e("li",null,[e("a",Cr,[r("dmg-acid2"),t(o)]),r(" and "),e("a",Ar,[r("cgb-acid2"),t(o)]),r(" - Basic PPU rendering tests.")])]),Dr,e("p",null,[r("The "),e("a",Sr,[r("Choosing tools for Game Boy development"),t(o)]),r(" essay provides an overview of the available development tools for Game Boy.")]),Mr,e("ul",null,[e("li",null,[e("a",xr,[r("RGBDS"),t(o)]),r(" - Assembler and linker package. "),e("a",Pr,[r("Documentation"),t(o)]),r(".")]),e("li",null,[e("a",Rr,[r("ASMotor"),t(o)]),r(" - Assembler engine and development system targeting Game Boy, among other CPUs. Written by the original RGBDS author. "),e("a",Tr,[r("Documentation"),t(o)]),r(".")]),e("li",null,[e("a",Er,[r("wla-dx"),t(o)]),r(" - Yet Another GB-Z80/Z80/... Multi Platform Cross Assembler Package. "),e("a",jr,[r("Documentation"),t(o)]),r(".")])]),Lr,e("ul",null,[e("li",null,[e("a",Fr,[r("GBDK"),t(o)]),r(" - Maintained and modernized GBDK (Game Boy Development Kit) powered by an updated version of the SDCC toolchain. Provides a C compiler, assembler, linker and a set of libraries. "),e("ul",null,[e("li",null,[e("a",zr,[r("API docs: Getting Started"),t(o)])]),e("li",null,[e("a",Ir,[r("Examples"),t(o)])]),e("li",null,[e("a",Or,[r("Documentation, links and tools"),t(o)])])])]),e("li",null,[e("a",Hr,[r("Turbo Rascal Syntax Error"),t(o)]),r(" - Complete suite (IDE, compiler, programming language, resource editor) intended for developing games/demos for 8 / 16-bit line of computers, including the Game Boy and Game Boy Color.")])]),Nr,e("ul",null,[e("li",null,[e("a",Kr,[r("RGBDS-Live"),t(o)]),r(" - In-browser coding environment to try out RGBDS.")]),e("li",null,[e("a",Ur,[r("Wiz"),t(o)]),r(" - A high-level assembly language for writing homebrew on retro console platforms (Game Boy, NES, Atari 2600, and more).")]),e("li",null,[e("a",Vr,[r("gbforth"),t(o)]),r(" - A Forth-based Game Boy development kit.")]),e("li",null,[e("a",Wr,[r("gbasm-rs"),t(o)]),r(" - An opinionated Rust based compiler for Game Boy z80 assembly code.")]),e("li",null,[e("a",Zr,[r("gbasm"),t(o)]),r(" - A JavaScript based compiler for Game Boy z80 assembly code.")]),e("li",null,[e("a",Jr,[r("tniASM"),t(o)]),r(" - Macro Assembler.")]),e("li",null,[e("a",qr,[r("Assembler"),t(o)]),r(" - Assembler written in Swift.")]),e("li",null,[e("a",Xr,[r("llvm-gbz80"),t(o)]),r(" / "),e("a",Yr,[r("clang-gbz80"),t(o)]),r(" - Clang/LLVM port to the GBZ80 CPU (similar to the deprecated "),e("a",Qr,[r("euclio/llvm-gbz80"),t(o)]),r(").")]),e("li",null,[e("a",$r,[r("gbdk-go"),t(o)]),r(" - A compiler translates Go programs to C code. The output C code is built into GB ROM by GBDK.")])]),et,e("ul",null,[e("li",null,[e("p",null,[e("a",rt,[r("BGB"),t(o)]),r(" - Powerful emulator and debugger. Provides an accurate hardware emulation.")])]),e("li",null,[e("p",null,[e("a",tt,[r("SameBoy"),t(o)]),r(" - Accurate emulator with a wide range of powerful debugging features.")])]),e("li",null,[e("p",null,[e("a",ot,[r("Mooneye GB"),t(o)]),r(" - Research project and emulator in Rust.")])]),e("li",null,[e("p",null,[e("a",nt,[r("mGBA"),t(o)]),r(" - Modern cross platform GBA emulator which also runs GB/GBC games.")])]),e("li",null,[e("p",null,[e("a",at,[r("Binjgb"),t(o)]),r(" - 5Kloc emulator that passes most of the tests. *Rewind- feature. Runs in the browser using WebAssembly.")])]),e("li",null,[e("p",null,[e("a",lt,[r("Gambatte"),t(o)]),r(" - Cross-platform and accurate emulator.")])]),e("li",null,[e("p",null,[e("a",it,[r("MetroBoy"),t(o)]),r(" - A playable, circuit-level simulation of an entire Game Boy.")])]),e("li",null,[e("p",null,[e("a",st,[r("gbe-plus"),t(o)]),r(" - A recently rewritten emulator that has a large effort in preserving the functions of obscure accessories (such as IR link, Mobile Network GB, Barcode Boy, GB Printer, local and online GB Serial Link Cable, ... )")])]),e("li",null,[e("p",null,[e("a",ht,[r("Emulicious"),t(o)]),r(" - Provides accurate emulation and includes powerful tools such as a profiler and source-level debugging for ASM and C via a "),e("a",dt,[r("VS Code debug adapter"),t(o)]),r(".")])])]),e("p",null,[t(a,{to:"/EMULATORS.html"},{default:i(()=>[r("Complete list of open source emulators")]),_:1})]),ct,gt,e("ul",null,[e("li",null,[e("a",mt,[r("ZGB"),t(o)]),r(" - A little engine for creating games for the original Game Boy (expands gbdk, more info "),e("a",pt,[r("here"),t(o)]),r(").")]),e("li",null,[e("a",ut,[r("Retr0 GB"),t(o)]),r(" - An engine for creating games (expands GBDK).")])]),bt,e("ul",null,[e("li",null,[e("a",_t,[r("GBExtended"),t(o)]),r(" - C library extending gbdk.")]),e("li",null,[e("a",ft,[r("gbdk-lib-extension"),t(o)]),r(" - A small set of sources and tools for the Game Boy Development Kit by Michael Hope.")]),e("li",null,[e("a",kt,[r("Dot Matrix Game Editor"),t(o)]),r(" - An IDE for Game Boy programming in a C-like language called GBL, with many other features like tile and map extraction, WLA-DX assembly, and more.")]),e("li",null,[e("a",yt,[r("mgbdis"),t(o)]),r(" - Game Boy ROM disassembler with RGBDS compatible output.")]),e("li",null,[e("a",Bt,[r("ROM Header Utility"),t(o)]),r(" - An online tool to inspect and modify a ROM's header data, including the logo.")]),e("li",null,[e("a",Gt,[r("romusage"),t(o)]),r(" - Command line tool for estimating usage (free space) of Game Boy ROMs from a .map, .noi or ihx file. Works with GBDK-2020 and RGBDS.")]),e("li",null,[e("a",wt,[r("awake"),t(o)]),r(" - Game Boy decompiler.")]),e("li",null,[e("a",vt,[r("Game Boy Text Tools"),t(o)]),r(" - Set of tools for text manipulation and translation of Game Boy ROMs written in Node.js.")]),e("li",null,[e("a",Ct,[r("evscript"),t(o)]),r(" - A scripting language for the Game Boy, useful for enemy AI, dialogue, animations, and coroutines.")]),e("li",null,[e("a",At,[r("evunit"),t(o)]),r(" - A unit testing program for assembly code.")])]),Dt,e("ul",null,[e("li",null,[e("a",St,[r("Game Boy Tile Data Generator"),t(o)]),r(" - HTML5 / JS web application that will convert bitmap images to hexadecimal data appropriate for use in tile based graphical applications, specifically GB.")]),e("li",null,[e("a",Mt,[r("Harry Mulder's GB Development"),t(o)]),r(" - Some sources and home of Game Boy Tile Designer (GBTD) and Game Boy Map Builder (GBMB) tools.")]),e("li",null,[e("a",xt,[r("GBTiles"),t(o)]),r(" - Converts .GBR files created with Harry Mulder's Tile Designer (GBTD) and .GBM files created with Harry Mulder's Map Builder (GBMB) to different formats for use with the Game Boy and GBDK.")]),e("li",null,[e("a",Pt,[r("bmp2cgb"),t(o)]),r(" - Graphics converter for Game Boy Color development providing real time palette adjustments.")]),e("li",null,[e("a",Rt,[r("png2gb"),t(o)]),r(" - CLI tool to convert image file to game boy .c array.")]),e("li",null,[e("a",Tt,[r("GB-convert"),t(o)]),r(" - Game Boy tile conversion and map editor tool (converts to assembly).")]),e("li",null,[e("a",Et,[r("brewtool"),t(o)]),r(" - A collection of primitive editor/converter tools for making assets used with homebrew ROM development.")]),e("li",null,[e("a",jt,[r("vtGBte"),t(o)]),r(" - A minimalistic ncurses tile editor.")]),e("li",null,[e("a",Lt,[r("tpp1"),t(o)]),r(" - Definition and specification of a custom GB/GBC memory/hardware mapper, as a functional superset of MBC.")]),e("li",null,[e("a",Ft,[r("libstdgb"),t(o)]),r(" - A C library of useful Game Boy operations (SDCC).")]),e("li",null,[e("a",zt,[r("Tilemap GB"),t(o)]),r(" - GIMP image editor plug-in for importing & exporting GBMB and GBTD tilemaps and tilesets (as bitmap images or .GBM/.GBR files).")]),e("li",null,[e("a",It,[r("Tilemap Helper"),t(o)]),r(" - GIMP image editor plug-in for optimizing tile maps and tile sets.")]),e("li",null,[e("a",Ot,[r("Tilemap Studio"),t(o)]),r(" - A tilemap editor for Game Boy, Color, Advance, and SNES projects. Written in C++ with FLTK.")]),e("li",null,[e("a",Ht,[r("Superfamiconv"),t(o)]),r(" - Flexible and composable tile graphics converter supporting Super Nintendo, Game Boy, Game Boy Color, Game Boy Advance, Mega Drive and PC Engine formats.")])]),Nt,e("ul",null,[e("li",null,[e("a",Kt,[r("cart-dumper"),t(o)]),r(" - Game Boy Cartridge Dumper ROM.")]),e("li",null,[e("a",Ut,[r("gbcamextract"),t(o)]),r(" - Extracts photos from Game Boy Camera saves.")]),e("li",null,[e("a",Vt,[r("Game Boy LCD sniffing"),t(o)]),r(" - Sniff your Game Boy's LCD using a logic analyzer.")]),e("li",null,[e("a",Wt,[r("swapdump"),t(o)]),r(" - Diagnostic utility for Game Boy flashcarts.")]),e("li",null,[e("a",Zt,[r("Gameboy-LinkUp"),t(o)]),r(" - Game Boy LinkUp serial cable networking project.")])]),Jt,e("ul",null,[e("li",null,[e("a",qt,[r("DevSound"),t(o)]),r(" - Sound driver embeddable in homebrews which supports pulse width manipulation, arpeggios, and multiple waveforms.")]),e("li",null,[e("a",Xt,[r("Carillon Player"),t(o)]),r(" - Music Engine.")]),e("li",null,[e("a",Yt,[r("GBT PLAYER"),t(o)]),r(" - A music player library and converter kit.")]),e("li",null,[e("a",Qt,[r("mmlgb"),t(o)]),r(" - A MML parser and GBDK sound driver for the Nintendo Game Boy.")]),e("li",null,[e("a",$t,[r("XPMCK"),t(o)]),r(" - An MML based music compiler with support for Game Boy & Game Boy Color.")]),e("li",null,[e("a",eo,[r("GBSoundSystem"),t(o)]),r(" - A modernized audio driver for GameBoy Tracker (aka the Paragon 5 music player).")]),e("li",null,[e("a",ro,[r("hUGETracker"),t(o)]),r(" - A music tracker based on OpenMPT, focused on ease of use, compact output, and embeddability in homebrew games.")]),e("li",null,[e("a",to,[r("CBT-FX"),t(o)]),r(" - A GBDK-2020 sound effect driver compatible with FX-Hammer sound effects.")])]),oo,e("ul",null,[e("li",null,[e("strong",null,[e("a",no,[r("gb asm tutorial"),t(o)])]),r(" - Step by step tutorial, building several ROMs to accompany its explanations.")]),e("li",null,[e("a",ao,[r("ASMSchool"),t(o)]),r(" - A set of lessons by Duo about coding in Assembly for GB/GBC and disassembling.")]),e("li",null,[e("a",lo,[r("hardware.inc"),t(o)]),r(" - Standard include file containing Game Boy hardware definitions for use in RGBDS projects.")]),e("li",null,[e("a",io,[r("Assembly tutorial by David Pello"),t(o)]),r(" - Good document to learn to produce working asm code for gb. Brief explanations of many important topics. Many examples with commented source code.")]),e("li",null,[e("a",so,[r("assemblydigest"),t(o)]),r(" - Exploring Game Boy programming techniques: "),e("ul",null,[e("li",null,[e("a",ho,[r("Making an Empty Game Boy ROM (in Wiz)"),t(o)])]),e("li",null,[e("a",co,[r("Making Art for the Game Boy"),t(o)])])])]),e("li",null,[e("a",go,[r("Beginner's Guide to Reverse Engineering GB"),t(o)]),r(" - Some starting tips on disassembling and reverse engineering.")]),e("li",null,[e("a",mo,[r("FlappyBoy: Making a simple Game Boy Game"),t(o)])]),e("li",null,[e("a",po,[r("Super Game Boy development"),t(o)]),r(" - Step by step tutorial to implement Super Game Boy features (frame and palettes).")]),e("li",null,[e("a",uo,[r("GameBoy programming tutorial: Hello World!"),t(o)]),r(" - Step by step tutorial.")]),e("li",null,[e("a",bo,[r("DMGreport"),t(o)]),r(" - Game programming tutorials in assembly.")]),e("li",null,[e("a",_o,[r("OAM DMA tutorial"),t(o)]),r(" - Example of how to use OAM DMA in assembly.")]),e("li",null,[e("a",fo,[r("Game Boy Assembly Programming for the Modern Game Developer"),t(o)]),r(" - An e-book about making Game Boy games in Assembly.")])]),ko,yo,e("ul",null,[e("li",null,[e("a",Bo,[r("dev'rs ASM section"),t(o)]),r(" - A lot of working demos and sources.")]),e("li",null,[e("a",Go,[r("EmmaEwert's experiments"),t(o)]),r(" - A collection of prototype programs, mostly just toying around. Among others, a daylight effect, transparency and a weather effect.")]),e("li",null,[e("a",wo,[r("DeadCScroll"),t(o)]),r(' - A detailed tutorial on how to make the screen wobble, among other "raster effects"')])]),vo,e("ul",null,[e("li",null,[e("a",Co,[r("Nitty Gritty Gameboy Cycle Timing"),t(o)])]),e("li",null,[e("a",Ao,[r("Mode3 Sprite Timing"),t(o)])]),e("li",null,[e("a",Do,[r("GameBoy Color DMA-Transfers v0.0.1"),t(o)])]),e("li",null,[e("a",So,[r("STAT interrupt timings"),t(o)])]),e("li",null,[e("a",Mo,[r("Video Timing"),t(o)])])]),xo,e("ul",null,[e("li",null,[e("a",Po,[r("rgbds-template"),t(o)]),r(" - Basic hello-world example for Game Boy using RGBDS.")]),e("li",null,[e("a",Ro,[r("Game Boy Assembly Language Primer"),t(o)]),r(" - Simple template code with memory defines, copy routines and IBM font tilemap.")]),e("li",null,[e("a",To,[r("bootstrap.gb"),t(o)]),r(" - An example Game Boy project.")]),e("li",null,[e("a",Eo,[r("Gameboy Boilerplate"),t(o)]),r(" - Boilerplate project to move quicker into the actual assembly code for your game.")]),e("li",null,[e("a",jo,[r("GingerBread"),t(o)]),r(" - A software library for making your own Game Boy games. It is made to be used alongside the book "),e("a",Lo,[r("Game Boy Assembly Programming for the Modern Game Developer"),t(o)]),r(" which also doubles as documentation.")]),e("li",null,[e("a",Fo,[r("gb-vwf"),t(o)]),r(" - Library to print variable-width text, comes with a demo.")]),e("li",null,[e("a",zo,[r("gb-boilerplate"),t(o)]),r(" - A template for starting Game Boy projects, providing a Makefile for infrastructure.")]),e("li",null,[e("a",Io,[r("gb-starter-kit"),t(o)]),r(" - An expansion on the above, including base library code as well to get started faster.")]),e("li",null,[e("a",Oo,[r("gb-template"),t(o)]),r(" - A template with basic functions such as joypad input, DMA transfers, and map/tile data loading.")])]),Ho,e("ul",null,[e("li",null,[e("a",No,[r("gbz80-highlight"),t(o)]),r(" - Notepad+- and gedit syntax highlighting files for RGBDS assembly.")]),e("li",null,[e("a",Ko,[r("Vim syntax file for the Game Boy assembler RGBASM"),t(o)]),r(" - Vim syntax highlighting for RGBDS assembly.")]),e("li",null,[e("a",Uo,[r("Vim syntax file for RGBDS"),t(o)]),r(" - Another Vim syntax highlighting file for RGBDS assembly.")]),e("li",null,[e("a",Vo,[r("sublime-rgbds"),t(o)]),r(" - A Sublime Text 3 package for RGBDS, including syntax highlighting and some completion snippets.")]),e("li",null,[e("a",Wo,[r("Z80 Assembly support for Visual Studio Code"),t(o)])]),e("li",null,[e("a",Zo,[r("rgbds-vscode"),t(o)]),r(" - Visual Studio Code language extension for RGBDS GBZ80 Assembly.")]),e("li",null,[e("a",Jo,[r("rgbds-mode"),t(o)]),r(" - Emacs major mode for RGBDS assembly.")])]),qo,e("ul",null,[e("li",null,[e("a",Xo,[r("8-Bit Wonderland"),t(o)]),r(" - Well-written introductory document about how the Game Boy works and how to start developing working code for it.")]),e("li",null,[e("a",Yo,[r("Grooves Game Boy Programming"),t(o)]),r(" - A complete set of lessons about implementing various game mechanics in a Game Boy game.")]),e("li",null,[e("a",Qo,[r("How to Write a Simple Side Scrolling Game"),t(o)]),r(" - Old (but still relevant) tutorial.")]),e("li",null,[e("a",$o,[r("Just another simple tutorial"),t(o)])]),e("li",null,[e("a",en,[r("GBDK Tutorial"),t(o)]),r(" - Fairly minimal game demo for getting started with GBDK.")]),e("li",null,[e("a",rn,[r("GBDK Sprite"),t(o)]),r(" - Presents a workflow for getting multiple sprites to display and animate.")]),e("li",null,[e("a",tn,[r("GBDK Color"),t(o)]),r(" - Extends your knowledge of basic spriting on the Game Boy by adding colors to sprites, backgrounds and the window layer.")]),e("li",null,[e("a",on,[r("GBDK Joypad"),t(o)]),r(" - Details the use of the joypad with GBDK.")]),e("li",null,[e("a",nn,[r("Game Boy home of Flavor"),t(o)]),r(" - Some full games and sources.")]),e("li",null,[e("a",an,[r("GBDK Configuring and Programming Tutorial"),t(o)]),r(" - Configuring GBDK, Using Tiles, Colliding Sprites, GBTD, GBMB, Memory Management and ROM Banking.")]),e("li",null,[e("a",ln,[r("Simplified GBDK examples"),t(o)])]),e("li",null,[e("a",sn,[r("GBDK Programming Video Tutorials"),t(o)]),r(" - A series of video tutorials introducing beginners to programming with GBDK.")]),e("li",null,[e("a",hn,[r("Larold's Jubilant Junkyard"),t(o)]),r(" - A collection of detailed GBDK-2020 based tutorials.")])]),dn,cn,e("ul",null,[e("li",null,[e("a",gn,[r("Homebrew Hub"),t(o)]),r(" - A community-led attempt to collect, archive and preserve every unlicensed and homebrew game released for Game Boy. Entries are playable online.")])]),mn,e("ul",null,[e("li",null,[e("a",pn,[r("Tuff"),t(o)])]),e("li",null,[e("a",un,[r("2048-gb"),t(o)])]),e("li",null,[e("a",bn,[r("Snake"),t(o)])]),e("li",null,[e("a",_n,[r("Lazerpong"),t(o)])]),e("li",null,[e("a",fn,[r("Geometrix"),t(o)])]),e("li",null,[e("a",kn,[r("µCity"),t(o)])]),e("li",null,[e("a",yn,[r("Carazu"),t(o)])]),e("li",null,[e("a",Bn,[r("Snake-gb"),t(o)])]),e("li",null,[e("a",Gn,[r("GB303"),t(o)]),r(" - GB303 wavetable-based TB-303 style synthesizer for the Nintendo Game Boy.")]),e("li",null,[e("a",wn,[r("Sushi"),t(o)])]),e("li",null,[e("a",vn,[r("Flappy-boy-asm"),t(o)])]),e("li",null,[e("a",Cn,[r("kupman"),t(o)]),r(" and some other projects.")]),e("li",null,[e("a",An,[r("Adjustris"),t(o)])]),e("li",null,[e("a",Dn,[r("exeman"),t(o)])]),e("li",null,[e("a",Sn,[r("Aevilia"),t(o)])]),e("li",null,[e("a",Mn,[r("GBSlides"),t(o)]),r(" - A simple Game Boy Powerpoint-like slides viewer.")]),e("li",null,[e("a",xn,[r("Pokered-gbc"),t(o)]),r(" - Pokémon Red remade with full GBC support.")]),e("li",null,[e("a",Pn,[r("ToyToy"),t(o)])]),e("li",null,[e("a",Rn,[r("StefaN"),t(o)]),r(" - Fourway Breakout clone.")]),e("li",null,[e("a",Tn,[r("Galaxia"),t(o)])]),e("li",null,[e("a",En,[r("desgb"),t(o)]),r(" - DES encryption.")]),e("li",null,[e("a",jn,[r("superhappyfunbubbletime"),t(o)])]),e("li",null,[e("a",Ln,[r("minesweepGB"),t(o)])]),e("li",null,[e("a",Fn,[r("Libbet and the Magic Floor"),t(o)])]),e("li",null,[e("a",zn,[r("waveform-gb"),t(o)]),r(" - Program visualizing the wave form used by the wave channel. The wave form can be edited freely and playback of the wave is updated immediately.")]),e("li",null,[e("a",In,[r("vectroid.gb"),t(o)]),r(" - Developed with gbasm.")]),e("li",null,[e("a",On,[r("PlantBoy"),t(o)])]),e("li",null,[e("a",Hn,[r("Death Planet"),t(o)])]),e("li",null,[e("a",Nn,[r("Quartet"),t(o)]),r(" - Puzzle game for the Game Boy (Color) and Super Game Boy.")]),e("li",null,[e("a",Kn,[r("Dangan"),t(o)])])]),Un,e("ul",null,[e("li",null,[e("a",Vn,[r("FlappyBoy"),t(o)])]),e("li",null,[e("a",Wn,[r("flappybird-gameboy"),t(o)])]),e("li",null,[e("a",Zn,[r("fbgb"),t(o)])]),e("li",null,[e("a",Jn,[r("Novascape"),t(o)])]),e("li",null,[e("a",qn,[r("Squishy the Turtle"),t(o)])]),e("li",null,[e("a",Xn,[r("Quadratino"),t(o)])]),e("li",null,[e("a",Yn,[r("Doctor How"),t(o)])]),e("li",null,[e("a",Qn,[r("Super Princess' 2092 Exodus"),t(o)]),r(" - ("),e("a",$n,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",ea,[r("GBsnake"),t(o)])]),e("li",null,[e("a",ra,[r("gb-mines"),t(o)])]),e("li",null,[e("a",ta,[r("oranges"),t(o)])]),e("li",null,[e("a",oa,[r("red hot princess carnage"),t(o)])]),e("li",null,[e("a",na,[r("loderunner"),t(o)])]),e("li",null,[e("a",aa,[r("Hives"),t(o)])]),e("li",null,[e("a",la,[r("Bubble Factory"),t(o)]),r(" - *Vanilla- SDCC (no gbdk).")]),e("li",null,[e("a",ia,[r("GBC Atari Boxing"),t(o)]),r(" - Atari 2600 Boxing clone for the Game Boy (Color).")]),e("li",null,[e("a",sa,[r("GB raycaster, Vision-8"),t(o)]),r(" - and some other projects.")]),e("li",null,[e("a",ha,[r("Tobu Tobu Girl Deluxe"),t(o)]),r(" - An arcade platformer for the Game Boy (Color).")]),e("li",null,[e("a",da,[r("Burly Bear vs. The Mean Foxes"),t(o)]),r(" ("),e("a",ca,[r("GBC"),t(o)]),r(" port)")]),e("li",null,[e("a",ga,[r("PostBot"),t(o)])]),e("li",null,[e("a",ma,[r("Guns & Riders"),t(o)])]),e("li",null,[e("a",pa,[r("Dino's Offline Adventure"),t(o)]),r(" - A clone of the Google Chrome offline game.")]),e("li",null,[e("a",ua,[r("dino-gb"),t(o)]),r(" - Another clone of the Chrome game.")]),e("li",null,[e("a",ba,[r("Evoland.gb"),t(o)]),r(" - A port of the first level of Evoland.")]),e("li",null,[e("a",_a,[r("Petris"),t(o)]),r(" - A puzzle game of shapely pets for the Game Boy Color ("),e("a",fa,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",ka,[r("Infinity"),t(o)]),r(" - RPG developed by Affinix Software primarily between the years 1999 and 2001. The game never found a publisher and was eventually canceled. Got recently released with the full source, development tools and workflows.")]),e("li",null,[e("a",ya,[r("Black Castle"),t(o)]),r(" - Side scrolling platformer for the Game Boy ("),e("a",Ba,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",Ga,[r("Genesis"),t(o)]),r(" - Shmup for the Game Boy ("),e("a",wa,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",va,[r("Indestructo Tank!"),t(o)])]),e("li",null,[e("a",Ca,[r("Super JetPak DX"),t(o)])]),e("li",null,[e("a",Aa,[r("Powa!"),t(o)]),r(" - Side scrolling platformer for the Game Boy (Color) ("),e("a",Da,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",Sa,[r("Cavern"),t(o)]),r(" - ("),e("a",Ma,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",xa,[r("Mona and the Witch's Hat Deluxe"),t(o)]),r(" - ("),e("a",Pa,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",Ra,[r("The Bouncing Ball"),t(o)])]),e("li",null,[e("a",Ta,[r("DMG Deals Damage"),t(o)])])]),Ea,e("ul",null,[e("li",null,[e("a",ja,[r("Soul Void"),t(o)]),r(" - Interactive horror fiction.")]),e("li",null,[e("a",La,[r("Deadeus"),t(o)])]),e("li",null,[e("a",Fa,[r("SUPER IMPOSTOR BROS."),t(o)])])]),za,e("ul",null,[e("li",null,[e("a",Ia,[r("Back to Color"),t(o)])]),e("li",null,[e("a",Oa,[r("beach-gbc"),t(o)])]),e("li",null,[e("a",Ha,[r("CUTE DEMO"),t(o)])]),e("li",null,[e("a",Na,[Ka,r(" Game Boy"),t(o)])]),e("li",null,[e("a",Ua,[r("Roboto Demo"),t(o)])]),e("li",null,[e("a",Va,[r("matrix-rain-gb"),t(o)]),r(" - A Matrix digital rain effect in assembler.")]),e("li",null,[e("a",Wa,[r("GBVideoPlayer"),t(o)]),r(" - A technical demo demonstrating how the Game Boy LCD controller can be hacked to make a Game Boy Color play a full motion video in color, together with music.")]),e("li",null,[e("a",Za,[r("GBVideoPlayer2"),t(o)]),r(" - The second iteration of the above demo, which increases the resolution, adds "),Ja,r(".")])]),qa,e("ul",null,[e("li",null,[e("a",Xa,[r("Reverse engineering Kirby's Dreamland 2"),t(o)])]),e("li",null,[e("a",Ya,[r("pokemontools"),t(o)]),r(" - a python module that provides various reverse engineering components for various Pokémon games.")]),e("li",null,[e("a",Qa,[r("Reverse Engineering a Gameboy ROM with radare2"),t(o)]),r(" - A walkthrough to reverse engineer a Game Boy ROM challenge using radare2.")]),e("li",null,[e("a",$a,[r("Disassembling Link's Awakening"),t(o)]),r(" - A series of blog posts about disassembling Link's Awakening DX.")]),e("li",null,[e("a",el,[r("Reverse Engineering the GameBoy Tetris"),t(o)])]),e("li",null,[e("a",rl,[r("DMA hijacking"),t(o)]),r(" - A simple technique that allows you to run custom code in most GB/SGB/CGB games, provided you have an ACE exploit.")])]),tl,e("ul",null,[e("li",null,[e("a",ol,[r("Pokémon Red/Blue"),t(o)])]),e("li",null,[e("a",nl,[r("Pokémon Crystal"),t(o)])]),e("li",null,[e("a",al,[r("Pokémon Yellow"),t(o)])]),e("li",null,[e("a",ll,[r("Pokémon Gold and Silver"),t(o)])]),e("li",null,[e("a",il,[r("Pokémon Pinball"),t(o)])]),e("li",null,[e("a",sl,[r("Pokémon TCG"),t(o)])]),e("li",null,[e("a",hl,[r("pokegold-spaceworld"),t(o)]),r(" - Pokémon Gold and Silver 1997 Space World demo.")]),e("li",null,[e("a",dl,[r("Link's Awakening DX"),t(o)])]),e("li",null,[e("a",cl,[r("Oracle of Ages"),t(o)])]),e("li",null,[e("a",gl,[r("Tetris"),t(o)]),r(" - Complete Tetris disassembly.")]),e("li",null,[e("a",ml,[r("FX Hammer"),t(o)])]),e("li",null,[e("a",pl,[r("Harvest Moon 3"),t(o)])]),e("li",null,[e("a",ul,[r("Final Fantasy Adventure"),t(o)])])]),bl,_l,fl,e("ul",null,[e("li",null,[e("a",kl,[r("Arduino Gameboy Printer Emulator"),t(o)]),r(" - Emulate a gameboy printer via the gameboy link cable.")]),e("li",null,[e("a",yl,[r("ESP8266 Game Boy Printer"),t(o)]),r(" - A device that emulates the Gameboy Printer and lets you retrieve images using WiFi powered by an ESP8266.")]),e("li",null,[e("a",Bl,[r("WiFi GBP Emulator"),t(o)]),r(" - A GameBoy printer emulator which provides the received data over a WiFi connection.")]),e("li",null,[e("a",Gl,[r("Game Boy WiFi Printer - D1 Mini Shield"),t(o)]),r(" - Game Boy Printer interface shield for D1 mini/mini Pro ESP8266 boards.")]),e("li",null,[e("a",wl,[r("Game Boy Printer Sniffer"),t(o)]),r(" - Sniff packet communications between a Game Boy and the Printer.")])]),vl,Cl,e("ul",null,[e("li",null,[e("a",Al,[r("Game Boy Camera Canon EF Lens Mount"),t(o)])]),e("li",null,[e("a",Dl,[r("Game Boy Camera to Canon Lens mount"),t(o)]),r(" - based on the above.")]),e("li",null,[e("a",Sl,[r("game-boy-camera-frame-replacer"),t(o)]),r(" - Manipulate the ROM of a camera to include custom frames")])]),Ml,e("ul",null,[e("li",null,[e("a",xl,[r("Game Boy Printer Paper Simulation"),t(o)]),r(" - Generate as-if-printed images of digital printed images.")]),e("li",null,[e("a",Pl,[r("Game Boy Printer Web"),t(o)]),r(" - Gallery app for to the Game Boy camera: import pictures from exports or cartridge dumps and choose color palettes.")])]),Rl,e("ul",null,[e("li",null,[e("a",Tl,[r("GB Studio"),t(o)]),r(" - Drag and drop game creator with simple, no knowledge required, visual scripting. "),e("ul",null,[e("li",null,[e("a",El,[r("Resources to get started"),t(o)])]),e("li",null,[e("a",jl,[r("Dedicated Discord"),t(o)])])])]),e("li",null,[e("a",Ll,[r("ArduinoBoy"),t(o)]),r(" - Serial communication (MIDI) from an Arduino to the Game Boy for music applications such as LittleSoundDJ, Nanoloop, and mGB.")]),e("li",null,[e("a",Fl,[r("papiGB"),t(o)]),r(" - Game Boy Classic fully functional FPGA implementation from scratch.")]),e("li",null,[e("a",zl,[r("fpgaboy"),t(o)]),r(" - Implementation Nintendo's Game Boy console on an FPGA.")]),e("li",null,[e("a",Il,[r("Piglet"),t(o)]),r(" - A LUA-driven AI that plays classic Game Boy color games using experimentation. In active development.")]),e("li",null,[e("a",Ol,[r("Ostrich"),t(o)]),r(" - A Game Boy Sound System player written in Swift.")]),e("li",null,[e("a",Hl,[r("mGB"),t(o)]),r(" - A Game Boy cartridge program that enables the Game Boy to act as a full MIDI supported sound module.")]),e("li",null,[e("a",Nl,[r("GBVisualizer"),t(o)]),r(" - Demonstrating the use of two undocumented Game Boy Color registers, nicknamed PCM12 (FF76) and PCM34 (FF77), which can be used to read the current PCM amplitude of the 4 APU channels.")]),e("li",null,[e("a",Kl,[r("ArduinoGameBoy"),t(o)]),r(" - Arduino based Game Boy cartridge reader and writer.")]),e("li",null,[e("a",Ul,[r("gameboy-brainfuck"),t(o)]),r(" - Brainf*ck interpreter.")]),e("li",null,[e("a",Vl,[r("gbfk"),t(o)]),r(" - Brainf*ck interpreter, with input.")]),e("li",null,[e("a",Wl,[r("gb-save-states"),t(o)]),r(" - Patches to add save state support to Game Boy games when playing on the original hardware.")]),e("li",null,[e("a",Zl,[r("gbcpu"),t(o)]),r(" - A CPU and peripherals implementing the Game Boy instruction set and functionality.")]),e("li",null,[e("a",Jl,[r("Digitized Speech in Game Boy Games"),t(o)])]),e("li",null,[e("a",ql,[r("Sniffing Game Boy serial traffic with an STM32F4"),t(o)])]),e("li",null,[e("a",Xl,[r("Virtual Game Boy Printer with an STM32F4"),t(o)])]),e("li",null,[e("a",Yl,[r("Printing on the Game Boy Printer using an STM32F4"),t(o)])]),e("li",null,[e("a",Ql,[r("Programming Game Boy Chinese cartridges with an STM32F4"),t(o)])]),e("li",null,[e("a",$l,[r("Pokemon Pocket Computer:"),t(o)]),r(" - What is it and how to use it to make cheat codes.")]),e("li",null,[e("a",ei,[r("Booting the Game Boy with a custom logo"),t(o)]),r(" - Bypassing the Nintendo logo check.")]),e("li",null,[r('Making a Game Boy game in 2017: A "Sheep It Up!" Post-Mortem ('),e("a",ri,[r("part 1"),t(o)]),r(", "),e("a",ti,[r("part 2"),t(o)]),r(")")]),e("li",null,[e("a",oi,[r("Nintendo's fake logos"),t(o)]),r(" - Every cartridge has to show the authentic logo to be considered valid and be run, but obviously some companies managed to exploit the check system.")]),e("li",null,[e("a",ni,[r("liblsdj"),t(o)]),r(" - Utility library for interacting with the LSDj save format (.sav), song files (.lsdsng) and more.")]),e("li",null,[e("a",ai,[r("lsdpatch"),t(o)]),r(" - Tool for modifying samples, fonts and palettes on LSDj ROM images.")]),e("li",null,[e("a",li,[r("Game Boy video effects"),t(o)]),r(" - Some little experiments using the STAT interrupt to do funny video manipulations.")]),e("li",null,[e("a",ii,[r("gbos"),t(o)]),r(" - A basic operating system for the Game Boy.")]),e("li",null,[e("a",si,[r("Work Master OS"),t(o)]),r(" - Russian multi tasking operating system.")]),e("li",null,[e("a",hi,[r("Game Boy Link Cable Breakout Board"),t(o)])]),e("li",null,[e("a",di,[r("GBCartFlasher firmware"),t(o)])]),e("li",null,[e("a",ci,[r("VerilogBoy"),t(o)]),r(" - Game Boy compatible console Verilog RTL implementation.")]),e("li",null,[e("a",gi,[r("GBCamcorder"),t(o)]),r(" - Lo-Fi portable video recorder using a GameBoy Camera cartridge.")]),e("li",null,[e("a",mi,[r("GBCartRead"),t(o)]),r(" - Read ROM, Read RAM or Write RAM from/to a GameBoy Cartridge.")]),e("li",null,[e("a",pi,[r("GBxCart-RW"),t(o)]),r(" - A device for reading game ROMs, save games and restoring saves for GB, GBC and GBA carts from your PC via USB.")]),e("li",null,[e("a",ui,[r("Dumping the Super Game Boy Boot ROM"),t(o)])])]),bi,e("ul",null,[e("li",null,[e("a",_i,[r("Archive of related files"),t(o)])]),e("li",null,[e("a",fi,[r("The Game Boy Archive"),t(o)]),r(" - A library of Game Boy related software, hardware and literature. Aimed to mirror and preserve old and fragmented contributions from the last three decades.")]),e("li",null,[e("a",ki,[r("The Game Boy Archive - Salvage"),t(o)]),r(" - Historical archive of software, old articles, FAQs and various documents.")])]),yi,e("ul",null,[e("li",null,[e("a",Bi,[r("devrs.com/gb"),t(o)]),r(" - Old home of the scene: examples, sources, complete documentation, guides, tutorials and various tools.")]),e("li",null,[e("a",Gi,[r("pdroms.de"),t(o)]),r(" - Game Boy releases.")]),e("li",null,[e("a",wi,[r("Handheld Underground"),t(o)]),r(" - Unlicensed games, blog posts about Game Boy, home of the hhugboy emulator.")])])])}const Si=s(c,[["render",vi],["__file","resources.html.vue"]]);export{Si as default}; +import{_ as s,r as l,o as h,c as d,a as e,b as r,d as t,w as i,e as n}from"./app-821120ad.js";const c={},g=n('
    Awesome Game Boy Development

    A curated list of awesome Game Boy (Color) Development resources, tools, docs, related projects and homebrews. Inspired by the awesome list thing.

    This project is open source and community-lead. Come contribute!


    Introduction

    ',8),m={id:"the-game-boy-a-hardware-autopsy",tabindex:"-1"},p=e("a",{class:"header-anchor",href:"#the-game-boy-a-hardware-autopsy","aria-hidden":"true"},"#",-1),u={href:"https://www.youtube.com/playlist?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",target:"_blank",rel:"noopener noreferrer"},b=e("br",null,null,-1),_=e("div",{class:"videoWrapper"},[e("iframe",{id:"ytplayer",type:"text/html",src:"https://www.youtube.com/embed/videoseries?list=PLu3xpmdUP-GRDp8tknpXC_Y4RUQtMMqEu",frameborder:"0",allowfullscreen:""}),e("br")],-1),f={id:"the-ultimate-game-boy-talk",tabindex:"-1"},k=e("a",{class:"header-anchor",href:"#the-ultimate-game-boy-talk","aria-hidden":"true"},"#",-1),y={href:"https://media.ccc.de/v/33c3-8029-the_ultimate_game_boy_talk",target:"_blank",rel:"noopener noreferrer"},B=e("br",null,null,-1),G=e("div",{class:"videoWrapper"},[e("iframe",{id:"ytplayer",type:"text/html",src:"https://www.youtube.com/embed/HyzD8pNlpwI",frameborder:"0",allowfullscreen:""}),e("br")],-1),w=e("h3",{id:"disambiguation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#disambiguation","aria-hidden":"true"},"#"),r(" Disambiguation")],-1),v=e("h4",{id:"game-boy-advance",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-advance","aria-hidden":"true"},"#"),r(" Game Boy Advance")],-1),C={href:"https://github.com/gbdev/awesome-gbadev",target:"_blank",rel:"noopener noreferrer"},A=n('

    Game Boy Color and Super Game Boy

    This list is focused on the original (1989) Game Boy (DMG), the Game Boy Color (GBC) and Super Game Boy (SGB) are very similar systems, with a few important distinctions, such as:

    • Different hardware specifications
    • Specific hardware and software features
    • Specific registers
    • Specific bugs, quirks and exploitable behaviours

    If you aim to develop your software for SGB or GBC, or you want to know how it runs on the other systems, you may want to take advantage and adapt to these differences, check the Game Boy Color category and look for specific references to GBC/CGB and SGB.

    ',4),D=e("h2",{id:"documentation",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#documentation","aria-hidden":"true"},"#"),r(" Documentation")],-1),S={href:"https://gbdev.github.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},M=e("strong",null,"Pan Docs",-1),x={href:"https://github.com/AntonioND/giibiiadvance/blob/master/docs/TCAGBD.pdf",target:"_blank",rel:"noopener noreferrer"},P={href:"https://gekkio.fi/files/gb-docs/gbctr.pdf",target:"_blank",rel:"noopener noreferrer"},R={href:"https://www.copetti.org/writings/consoles/game-boy/",target:"_blank",rel:"noopener noreferrer"},T={href:"http://www.cs.columbia.edu/~sedwards/classes/2019/4840-spring/reports/GameBoy.pdf",target:"_blank",rel:"noopener noreferrer"},E={href:"https://github.com/kitsuneh/SVGameBoy",target:"_blank",rel:"noopener noreferrer"},j=e("h4",{id:"opcodes",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#opcodes","aria-hidden":"true"},"#"),r(" Opcodes")],-1),L={href:"https://gbdev.github.io/gb-opcodes/optables/",target:"_blank",rel:"noopener noreferrer"},F={href:"https://rgbds.gbdev.io/docs/gbz80.7",target:"_blank",rel:"noopener noreferrer"},z=e("h3",{id:"game-boy-color",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-color","aria-hidden":"true"},"#"),r(" Game Boy Color")],-1),I={href:"https://tcrf.net/Game_Boy_Color_Bootstrap_ROM",target:"_blank",rel:"noopener noreferrer"},O={href:"https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM",target:"_blank",rel:"noopener noreferrer"},H={href:"https://forums.nesdev.com/viewtopic.php?p=114388&sid=c3d4ce08cfd9d9c834958d4f148750c3#p114388",target:"_blank",rel:"noopener noreferrer"},N={href:"https://gist.github.com/drhelius/6063265",target:"_blank",rel:"noopener noreferrer"},K={href:"https://romhack.github.io/doc/gbcHiColour/",target:"_blank",rel:"noopener noreferrer"},U=e("h3",{id:"hardware",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hardware","aria-hidden":"true"},"#"),r(" Hardware")],-1),V={href:"http://gbdev.gg8.se/wiki/articles/DMG_Schematics",target:"_blank",rel:"noopener noreferrer"},W={href:"http://marc.rawer.de/Gameboy/Docs/GBProject.pdf",target:"_blank",rel:"noopener noreferrer"},Z={href:"https://github.com/Gekkio/gb-hardware",target:"_blank",rel:"noopener noreferrer"},J={href:"https://github.com/applefreak/esp8266-gameboy-dev-board",target:"_blank",rel:"noopener noreferrer"},q={href:"https://github.com/applefreak/esp8266-gameboy-printer",target:"_blank",rel:"noopener noreferrer"},X={href:"http://verhoeven272.nl/fruttenboel/Gameboy/index.html",target:"_blank",rel:"noopener noreferrer"},Y={href:"https://gbhwdb.gekkio.fi/",target:"_blank",rel:"noopener noreferrer"},Q={href:"https://github.com/msinger/dmg-schematics",target:"_blank",rel:"noopener noreferrer"},$=e("h3",{id:"peripherals",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#peripherals","aria-hidden":"true"},"#"),r(" Peripherals")],-1),ee={href:"https://shonumi.github.io/dandocs.html",target:"_blank",rel:"noopener noreferrer"},re={href:"https://shonumi.github.io/articles.html",target:"_blank",rel:"noopener noreferrer"},te={href:"https://github.com/shonumi/gbe-plus/tree/master/src/docs/technical",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://shonumi.github.io/articles/art14.html",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://shonumi.github.io/articles/art2.html",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://shonumi.github.io/articles/art13.html",target:"_blank",rel:"noopener noreferrer"},le={href:"https://shonumi.github.io/articles/art8.html",target:"_blank",rel:"noopener noreferrer"},ie={href:"https://shonumi.github.io/articles/art11.html",target:"_blank",rel:"noopener noreferrer"},se={href:"https://shonumi.github.io/articles/art9.html",target:"_blank",rel:"noopener noreferrer"},he={href:"https://shonumi.github.io/articles/art7.html",target:"_blank",rel:"noopener noreferrer"},de={href:"https://shonumi.github.io/articles/art6.html",target:"_blank",rel:"noopener noreferrer"},ce={href:"https://raw.githubusercontent.com/shonumi/gbe-plus/master/src/docs/technical/DMG_07.txt",target:"_blank",rel:"noopener noreferrer"},ge={href:"https://github.com/AntonioND/gbcam-rev-engineer",target:"_blank",rel:"noopener noreferrer"},me={href:"http://www.pinchofintelligence.com/photorealistic-neural-network-gameboy/",target:"_blank",rel:"noopener noreferrer"},pe={href:"https://shonumi.github.io/articles/art2.html",target:"_blank",rel:"noopener noreferrer"},ue={href:"https://www.youtube.com/watch?v=43FfJvd-YP4",target:"_blank",rel:"noopener noreferrer"},be={href:"https://github.com/mofosyne/arduino-gameboy-printer-emulator",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://bulbapedia.bulbagarden.net/wiki/Mobile_Game_Boy_Adapter",target:"_blank",rel:"noopener noreferrer"},fe={href:"http://nectaris.tg-16.com/GB-KISS-LINK-FAQ-hudson-gameboy-nectaris.html",target:"_blank",rel:"noopener noreferrer"},ke=e("h3",{id:"cartridges",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#cartridges","aria-hidden":"true"},"#"),r(" Cartridges")],-1),ye={href:"https://bbbbbr.github.io/GameBoy-Flash-Carts/",target:"_blank",rel:"noopener noreferrer"},Be={href:"https://github.com/AntonioND/giibiiadvance/tree/master/docs",target:"_blank",rel:"noopener noreferrer"},Ge={href:"http://gekkio.fi/blog/2015-02-14-mooneye-gb-gameboy-cartridge-types.html",target:"_blank",rel:"noopener noreferrer"},we={href:"http://gekkio.fi/blog/2015-05-18-mooneye-gb-cartridge-analysis-dmg-bean-02.html",target:"_blank",rel:"noopener noreferrer"},ve={href:"http://gekkio.fi/blog/2015-05-17-mooneye-gb-cartridge-analysis-fortress-of-fear.html",target:"_blank",rel:"noopener noreferrer"},Ce={href:"http://gekkio.fi/blog/2015-02-28-mooneye-gb-cartridge-analysis-tetris.html",target:"_blank",rel:"noopener noreferrer"},Ae={href:"https://wiki.tauwasser.eu/view/MBC1",target:"_blank",rel:"noopener noreferrer"},De={href:"https://wiki.tauwasser.eu/view/MBC2",target:"_blank",rel:"noopener noreferrer"},Se={href:"https://wiki.tauwasser.eu/view/MMM01",target:"_blank",rel:"noopener noreferrer"},Me={href:"http://www.devrs.com/gb/files/gb.html",target:"_blank",rel:"noopener noreferrer"},xe={href:"https://imgur.com/a/D5bpC",target:"_blank",rel:"noopener noreferrer"},Pe={href:"http://www.devrs.com/gb/files/mbc1.gif",target:"_blank",rel:"noopener noreferrer"},Re={href:"http://fms.komkon.org/GameBoy/Tech/Carts.html",target:"_blank",rel:"noopener noreferrer"},Te=e("li",null,[e("a",{href:"CartridgeList.csv"},"GB Rom List"),r(" - Navigable table of every game released with details on their cartridges.")],-1),Ee={href:"http://gekkio.fi/blog/2016-03-19-game-boy-cartridge-pcb-photos.html",target:"_blank",rel:"noopener noreferrer"},je=e("h4",{id:"custom-cartridges",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#custom-cartridges","aria-hidden":"true"},"#"),r(" Custom cartridges")],-1),Le={href:"https://dhole.github.io/post/gameboy_cartridge_emu_1/",target:"_blank",rel:"noopener noreferrer"},Fe={href:"http://www.happydaze.se/wolf/",target:"_blank",rel:"noopener noreferrer"},ze={href:"https://github.com/dwaq/Homebrew-Gameboy-Cartridge",target:"_blank",rel:"noopener noreferrer"},Ie={href:"https://github.com/Xyl2k/Gameboy-Color-Cartridge",target:"_blank",rel:"noopener noreferrer"},Oe={href:"https://github.com/zephray/NekoCart-GB",target:"_blank",rel:"noopener noreferrer"},He={href:"https://hackaday.io/project/41160-nekocart-cpld-gameboy-cartridge",target:"_blank",rel:"noopener noreferrer"},Ne={href:"http://reinerziegler.de.mirrors.gg8.se/",target:"_blank",rel:"noopener noreferrer"},Ke={href:"https://github.com/insidegadgets/Gameboy-MBC5-MBC1-Hybrid",target:"_blank",rel:"noopener noreferrer"},Ue=e("h4",{id:"misc",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#misc","aria-hidden":"true"},"#"),r(" Misc")],-1),Ve={href:"http://pepijndevos.nl/sha2017/workshop.pdf",target:"_blank",rel:"noopener noreferrer"},We={href:"https://github.com/bwhitman/pushpin/blob/master/src/gbsound.txt",target:"_blank",rel:"noopener noreferrer"},Ze={href:"http://www.devrs.com/gb/files/faqs.html",target:"_blank",rel:"noopener noreferrer"},Je={href:"http://www.neviksti.com/DMG/DMG_ROM.asm",target:"_blank",rel:"noopener noreferrer"},qe={href:"http://www.z80.info/z80gboy.txt",target:"_blank",rel:"noopener noreferrer"},Xe={href:"http://www.huderlem.com/demos/gameboy2bpp.html",target:"_blank",rel:"noopener noreferrer"},Ye=e("h2",{id:"emulator-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#emulator-development","aria-hidden":"true"},"#"),r(" Emulator Development")],-1),Qe={href:"https://www.youtube.com/watch?v=GBYwjch6oEE",target:"_blank",rel:"noopener noreferrer"},$e={href:"https://gekkio.fi/blog/2018-02-05-errata-for-reverse-engineering-fine-details-of-game-boy-hardware.html",target:"_blank",rel:"noopener noreferrer"},er={href:"https://github.com/Baekalfen/PyBoy/blob/master/extras/PyBoy.pdf",target:"_blank",rel:"noopener noreferrer"},rr={href:"https://rylev.github.io/DMG-01/public/book/",target:"_blank",rel:"noopener noreferrer"},tr={href:"https://media.ccc.de/v/rustfest-rome-3-gameboy-emulator",target:"_blank",rel:"noopener noreferrer"},or={href:"http://imrannazar.com/gameboy-Emulation-in-JavaScript",target:"_blank",rel:"noopener noreferrer"},nr={href:"https://cturt.github.io/cinoop.html",target:"_blank",rel:"noopener noreferrer"},ar={href:"https://jeremybanks.github.io/0dmg/2018/05/23/getting-started.html",target:"_blank",rel:"noopener noreferrer"},lr={href:"https://realboyemulator.wordpress.com/posts/",target:"_blank",rel:"noopener noreferrer"},ir={href:"http://www.codeslinger.co.uk/pages/projects/gameboy.html",target:"_blank",rel:"noopener noreferrer"},sr={href:"http://blog.rekawek.eu/2017/02/09/coffee-gb/",target:"_blank",rel:"noopener noreferrer"},hr={href:"https://binji.github.io/2017/12/31/binjgb-rewind.html",target:"_blank",rel:"noopener noreferrer"},dr={href:"https://binji.github.io/2017/02/26/binjgb-on-the-web-part-1.html",target:"_blank",rel:"noopener noreferrer"},cr={href:"https://binji.github.io/2017/02/27/binjgb-on-the-web-part-2.html",target:"_blank",rel:"noopener noreferrer"},gr={href:"https://binji.github.io/2017/05/03/debugging-hangs.html",target:"_blank",rel:"noopener noreferrer"},mr={href:"https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html",target:"_blank",rel:"noopener noreferrer"},pr={href:"https://djhworld.github.io/post/2018/09/21/i-ported-my-gameboy-color-emulator-to-webassembly/",target:"_blank",rel:"noopener noreferrer"},ur={href:"https://mitxela.com/projects/swotgb/about",target:"_blank",rel:"noopener noreferrer"},br={href:"https://github.com/robert/gameboy-doctor",target:"_blank",rel:"noopener noreferrer"},_r=e("h3",{id:"testing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#testing","aria-hidden":"true"},"#"),r(" Testing")],-1),fr={href:"http://gbdev.gg8.se/files/roms/blargg-gb-tests/",target:"_blank",rel:"noopener noreferrer"},kr={href:"https://gekkio.fi/files/mooneye-gb/latest/",target:"_blank",rel:"noopener noreferrer"},yr={href:"https://github.com/LIJI32/SameSuite",target:"_blank",rel:"noopener noreferrer"},Br={href:"https://github.com/mattcurrie/mealybug-tearoom-tests",target:"_blank",rel:"noopener noreferrer"},Gr={href:"http://tasvideos.org/EmulatorResources/GBAccuracyTests.html",target:"_blank",rel:"noopener noreferrer"},wr={href:"https://github.com/pinobatch/240p-test-mini/tree/master/gameboy",target:"_blank",rel:"noopener noreferrer"},vr={href:"https://github.com/aaaaaa123456789/rtc3test",target:"_blank",rel:"noopener noreferrer"},Cr={href:"https://github.com/mattcurrie/dmg-acid2",target:"_blank",rel:"noopener noreferrer"},Ar={href:"https://github.com/mattcurrie/cgb-acid2",target:"_blank",rel:"noopener noreferrer"},Dr=e("h2",{id:"software-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#software-development","aria-hidden":"true"},"#"),r(" Software Development")],-1),Sr={href:"https://gbdev.io/guides/tools.html",target:"_blank",rel:"noopener noreferrer"},Mr=e("h3",{id:"assemblers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#assemblers","aria-hidden":"true"},"#"),r(" Assemblers")],-1),xr={href:"https://github.com/gbdev/rgbds",target:"_blank",rel:"noopener noreferrer"},Pr={href:"https://rgbds.gbdev.io/docs/",target:"_blank",rel:"noopener noreferrer"},Rr={href:"https://github.com/csoren/asmotor",target:"_blank",rel:"noopener noreferrer"},Tr={href:"https://github.com/asmotor/asmotor/tree/develop#further-reading",target:"_blank",rel:"noopener noreferrer"},Er={href:"https://github.com/vhelin/wla-dx",target:"_blank",rel:"noopener noreferrer"},jr={href:"http://www.villehelin.com/wla.txt",target:"_blank",rel:"noopener noreferrer"},Lr=e("h3",{id:"compilers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#compilers","aria-hidden":"true"},"#"),r(" Compilers")],-1),Fr={href:"https://github.com/gbdk-2020/gbdk-2020/",target:"_blank",rel:"noopener noreferrer"},zr={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_getting_started.html",target:"_blank",rel:"noopener noreferrer"},Ir={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},Or={href:"https://gbdk-2020.github.io/gbdk-2020/docs/api/docs_links_and_tools.html",target:"_blank",rel:"noopener noreferrer"},Hr={href:"https://lemonspawn.com/turbo-rascal-syntax-error-expected-but-begin/",target:"_blank",rel:"noopener noreferrer"},Nr=e("h4",{id:"experimental-proof-of-concepts",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#experimental-proof-of-concepts","aria-hidden":"true"},"#"),r(" Experimental/Proof of Concepts")],-1),Kr={href:"https://daid.github.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},Ur={href:"https://github.com/wiz-lang/wiz",target:"_blank",rel:"noopener noreferrer"},Vr={href:"https://github.com/ams-hackers/gbforth",target:"_blank",rel:"noopener noreferrer"},Wr={href:"https://gitlab.com/BonsaiDen/gbasm-rs",target:"_blank",rel:"noopener noreferrer"},Zr={href:"https://github.com/BonsaiDen/gbasm",target:"_blank",rel:"noopener noreferrer"},Jr={href:"http://www.tni.nl/products/tniasm.html",target:"_blank",rel:"noopener noreferrer"},qr={href:"https://github.com/ulrikdamm/Assembler",target:"_blank",rel:"noopener noreferrer"},Xr={href:"https://github.com/Bevinsky/llvm-gbz80",target:"_blank",rel:"noopener noreferrer"},Yr={href:"https://github.com/Bevinsky/clang-gbz80",target:"_blank",rel:"noopener noreferrer"},Qr={href:"https://github.com/euclio/llvm-gbz80",target:"_blank",rel:"noopener noreferrer"},$r={href:"https://github.com/pokemium/gbdk-go",target:"_blank",rel:"noopener noreferrer"},et=e("h3",{id:"emulators",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#emulators","aria-hidden":"true"},"#"),r(" Emulators")],-1),rt={href:"https://bgb.bircd.org/",target:"_blank",rel:"noopener noreferrer"},tt={href:"https://github.com/LIJI32/SameBoy",target:"_blank",rel:"noopener noreferrer"},ot={href:"https://github.com/Gekkio/mooneye-gb",target:"_blank",rel:"noopener noreferrer"},nt={href:"https://github.com/mgba-emu/mgba",target:"_blank",rel:"noopener noreferrer"},at={href:"https://github.com/binji/binjgb",target:"_blank",rel:"noopener noreferrer"},lt={href:"https://github.com/gb-archive/gambatte",target:"_blank",rel:"noopener noreferrer"},it={href:"https://github.com/aappleby/MetroBoy",target:"_blank",rel:"noopener noreferrer"},st={href:"https://github.com/shonumi/gbe-plus",target:"_blank",rel:"noopener noreferrer"},ht={href:"https://emulicious.net/",target:"_blank",rel:"noopener noreferrer"},dt={href:"https://marketplace.visualstudio.com/items?itemName=emulicious.emulicious-debugger",target:"_blank",rel:"noopener noreferrer"},ct=e("h3",{id:"tools",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#tools","aria-hidden":"true"},"#"),r(" Tools")],-1),gt=e("h4",{id:"engines",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#engines","aria-hidden":"true"},"#"),r(" Engines")],-1),mt={href:"https://github.com/Zal0/ZGB",target:"_blank",rel:"noopener noreferrer"},pt={href:"http://zalods.blogspot.com/2017/01/zgb-little-engine-for-game-boy.html",target:"_blank",rel:"noopener noreferrer"},ut={href:"https://bitbucket.org/HellSuffering/retr0-gb/",target:"_blank",rel:"noopener noreferrer"},bt=e("h4",{id:"development-tools",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#development-tools","aria-hidden":"true"},"#"),r(" Development tools")],-1),_t={href:"http://www.tensi.eu/thomas/programming/gameboy/gbextended.html",target:"_blank",rel:"noopener noreferrer"},ft={href:"https://github.com/ProGM/gbdk-lib-extension",target:"_blank",rel:"noopener noreferrer"},kt={href:"http://www.dotmatrixgame.com/",target:"_blank",rel:"noopener noreferrer"},yt={href:"https://github.com/mattcurrie/mgbdis",target:"_blank",rel:"noopener noreferrer"},Bt={href:"http://catskull.net/GB-Logo-Generator/",target:"_blank",rel:"noopener noreferrer"},Gt={href:"https://github.com/bbbbbr/romusage",target:"_blank",rel:"noopener noreferrer"},wt={href:"https://github.com/devdri/awake",target:"_blank",rel:"noopener noreferrer"},vt={href:"https://github.com/raphaklaus/gameboy-text-tools",target:"_blank",rel:"noopener noreferrer"},Ct={href:"https://github.com/eievui5/evscript",target:"_blank",rel:"noopener noreferrer"},At={href:"https://github.com/eievui5/evunit",target:"_blank",rel:"noopener noreferrer"},Dt=e("h4",{id:"graphics-utilities",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#graphics-utilities","aria-hidden":"true"},"#"),r(" Graphics utilities")],-1),St={href:"https://github.com/chrisantonellis/gbtdg",target:"_blank",rel:"noopener noreferrer"},Mt={href:"http://www.devrs.com/gb/hmgd/intro.html",target:"_blank",rel:"noopener noreferrer"},xt={href:"https://github.com/bashaus/gbtiles",target:"_blank",rel:"noopener noreferrer"},Pt={href:"https://github.com/gitendo/bmp2cgb",target:"_blank",rel:"noopener noreferrer"},Rt={href:"https://github.com/LuckyLights/png2gb",target:"_blank",rel:"noopener noreferrer"},Tt={href:"https://github.com/exezin/gb-convert",target:"_blank",rel:"noopener noreferrer"},Et={href:"http://make.vg/brewtool/",target:"_blank",rel:"noopener noreferrer"},jt={href:"https://github.com/paul-arutyunov/vtGBte",target:"_blank",rel:"noopener noreferrer"},Lt={href:"https://github.com/TwitchPlaysPokemon/tpp1",target:"_blank",rel:"noopener noreferrer"},Ft={href:"https://github.com/delwink/libstdgb",target:"_blank",rel:"noopener noreferrer"},zt={href:"https://github.com/bbbbbr/gimp-tilemap-gb",target:"_blank",rel:"noopener noreferrer"},It={href:"https://github.com/bbbbbr/gimp-tilemap-helper",target:"_blank",rel:"noopener noreferrer"},Ot={href:"https://github.com/Rangi42/tilemap-studio",target:"_blank",rel:"noopener noreferrer"},Ht={href:"https://github.com/Optiroc/SuperFamiconv",target:"_blank",rel:"noopener noreferrer"},Nt=e("h4",{id:"hardware-and-rom-utilities",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hardware-and-rom-utilities","aria-hidden":"true"},"#"),r(" Hardware and ROM utilities")],-1),Kt={href:"https://github.com/Palmr/cart-dumper",target:"_blank",rel:"noopener noreferrer"},Ut={href:"https://github.com/jkbenaim/gbcamextract",target:"_blank",rel:"noopener noreferrer"},Vt={href:"https://github.com/svendahlstrand/game-boy-lcd-sniffing",target:"_blank",rel:"noopener noreferrer"},Wt={href:"https://github.com/sanqui/swapdump",target:"_blank",rel:"noopener noreferrer"},Zt={href:"https://github.com/JustinLloyd/Gameboy-LinkUp",target:"_blank",rel:"noopener noreferrer"},Jt=e("h4",{id:"music-drivers-and-trackers",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#music-drivers-and-trackers","aria-hidden":"true"},"#"),r(" Music drivers and trackers")],-1),qt={href:"https://github.com/DevEd2/DevSound",target:"_blank",rel:"noopener noreferrer"},Xt={href:"http://gbdev.gg8.se/files/musictools/Aleksi%20Eeben/Carillon%20Editor.zip",target:"_blank",rel:"noopener noreferrer"},Yt={href:"https://github.com/AntonioND/gbt-player",target:"_blank",rel:"noopener noreferrer"},Qt={href:"https://github.com/SimonLarsen/mmlgb",target:"_blank",rel:"noopener noreferrer"},$t={href:"https://github.com/bazzinotti/XPMCK",target:"_blank",rel:"noopener noreferrer"},eo={href:"https://github.com/gbdev/GBSoundSystem",target:"_blank",rel:"noopener noreferrer"},ro={href:"https://github.com/SuperDisk/hUGETracker",target:"_blank",rel:"noopener noreferrer"},to={href:"https://github.com/datguywitha3ds/CBT-FX",target:"_blank",rel:"noopener noreferrer"},oo=n('

    Programming

    Guides, tutorials and tools to develop software for Game Boy using the development toolchains described in the Software Development chapter.

    ASM

    ',3),no={href:"https://eldred.fr/gb-asm-tutorial",target:"_blank",rel:"noopener noreferrer"},ao={href:"http://gameboy.mongenel.com/asmschool.html",target:"_blank",rel:"noopener noreferrer"},lo={href:"https://github.com/tobiasvl/hardware.inc",target:"_blank",rel:"noopener noreferrer"},io={href:"https://gb-archive.github.io/salvage/tutorial_de_ensamblador/tutorial_de_ensamblador_la_decadence.html",target:"_blank",rel:"noopener noreferrer"},so={href:"https://github.com/assemblydigest/gameboy",target:"_blank",rel:"noopener noreferrer"},ho={href:"http://assemblydigest.tumblr.com/post/77203696711/tutorial-making-an-empty-game-boy-rom-in-wiz",target:"_blank",rel:"noopener noreferrer"},co={href:"http://assemblydigest.tumblr.com/post/77404621743/tutorial-making-art-for-the-game-boy",target:"_blank",rel:"noopener noreferrer"},go={href:"http://web.archive.org/web/20150511145100/http://www.bennvenn.com/Beginners_Guide_To_Reverse_Engineering.htm",target:"_blank",rel:"noopener noreferrer"},mo={href:"http://voidptr.io/blog/2017/01/21/GameBoy.html",target:"_blank",rel:"noopener noreferrer"},po={href:"https://imanoleasgames.blogspot.no/2016/12/games-aside-1-super-game-boy.html",target:"_blank",rel:"noopener noreferrer"},uo={href:"https://peterwynroberts.wordpress.com/2014/05/11/gameboy-programming-tutorial-hello-world/",target:"_blank",rel:"noopener noreferrer"},bo={href:"https://github.com/lancekindle/DMGreport",target:"_blank",rel:"noopener noreferrer"},_o={href:"https://gbdev.gg8.se/wiki/articles/OAM_DMA_tutorial",target:"_blank",rel:"noopener noreferrer"},fo={href:"https://github.com/ahrnbom/gbapfomgd",target:"_blank",rel:"noopener noreferrer"},ko=e("h4",{id:"sources",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#sources","aria-hidden":"true"},"#"),r(" Sources")],-1),yo=e("p",null,"Fragments of code, effects, proof of concepts and generally non complete games.",-1),Bo={href:"http://www.devrs.com/gb/asmcode.php",target:"_blank",rel:"noopener noreferrer"},Go={href:"https://github.com/EmmaEwert/gameboy",target:"_blank",rel:"noopener noreferrer"},wo={href:"https://github.com/gb-archive/DeadCScroll",target:"_blank",rel:"noopener noreferrer"},vo=e("h4",{id:"timings",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#timings","aria-hidden":"true"},"#"),r(" Timings")],-1),Co={href:"http://blog.kevtris.org/blogfiles/Nitty%20Gritty%20Gameboy%20VRAM%20Timing.txt",target:"_blank",rel:"noopener noreferrer"},Ao={href:"https://www.reddit.com/r/EmuDev/comments/59pawp/gb_mode3_sprite_timing/",target:"_blank",rel:"noopener noreferrer"},Do={href:"http://gameboy.mongenel.com/dmg/gbc_dma_transfers.txt",target:"_blank",rel:"noopener noreferrer"},So={href:"http://gameboy.mongenel.com/dmg/istat98.txt",target:"_blank",rel:"noopener noreferrer"},Mo={href:"https://github.com/jdeblese/gbcpu/wiki/Video-Timing",target:"_blank",rel:"noopener noreferrer"},xo=e("h4",{id:"boilerplates-and-libraries",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#boilerplates-and-libraries","aria-hidden":"true"},"#"),r(" Boilerplates and libraries")],-1),Po={href:"https://github.com/nezticle/rgbds-template",target:"_blank",rel:"noopener noreferrer"},Ro={href:"http://www.devrs.com/gb/files/galp.zip",target:"_blank",rel:"noopener noreferrer"},To={href:"https://github.com/yenatch/bootstrap.gb",target:"_blank",rel:"noopener noreferrer"},Eo={href:"https://github.com/junebug12851/GameboyBoilerplateProj",target:"_blank",rel:"noopener noreferrer"},jo={href:"https://github.com/ahrnbom/gingerbread",target:"_blank",rel:"noopener noreferrer"},Lo={href:"https://github.com/ahrnbom/gbapfomgd",target:"_blank",rel:"noopener noreferrer"},Fo={href:"https://github.com/ISSOtm/gb-vwf",target:"_blank",rel:"noopener noreferrer"},zo={href:"https://github.com/ISSOtm/gb-boilerplate",target:"_blank",rel:"noopener noreferrer"},Io={href:"https://github.com/ISSOtm/gb-starter-kit",target:"_blank",rel:"noopener noreferrer"},Oo={href:"https://github.com/gb-archive/gb-template",target:"_blank",rel:"noopener noreferrer"},Ho=e("h4",{id:"syntax-highlighting-packages",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#syntax-highlighting-packages","aria-hidden":"true"},"#"),r(" Syntax highlighting packages")],-1),No={href:"https://github.com/ISSOtm/gbz80-highlight",target:"_blank",rel:"noopener noreferrer"},Ko={href:"http://www.vim.org/scripts/script.php?script_id=819",target:"_blank",rel:"noopener noreferrer"},Uo={href:"https://github.com/Leandros/dotfiles/blob/master/.vim/syntax/rgbds.vim",target:"_blank",rel:"noopener noreferrer"},Vo={href:"https://packagecontrol.io/packages/RGBDS",target:"_blank",rel:"noopener noreferrer"},Wo={href:"https://github.com/Imanolea/z80asm-vscode",target:"_blank",rel:"noopener noreferrer"},Zo={href:"https://github.com/DonaldHays/rgbds-vscode",target:"_blank",rel:"noopener noreferrer"},Jo={href:"https://github.com/japanoise/rgbds-mode",target:"_blank",rel:"noopener noreferrer"},qo=e("h3",{id:"c",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#c","aria-hidden":"true"},"#"),r(" C")],-1),Xo={href:"https://github.com/gb-archive/salvage/blob/master/misc/8bit_wonderland.pdf",target:"_blank",rel:"noopener noreferrer"},Yo={href:"https://github.com/gbdk-salvage/grooves-game-boy-programming",target:"_blank",rel:"noopener noreferrer"},Qo={href:"http://pastebin.com/F3tHLj68",target:"_blank",rel:"noopener noreferrer"},$o={href:"http://pastebin.com/gzT47MPJ",target:"_blank",rel:"noopener noreferrer"},en={href:"https://refreshgames.co.uk/2016/04/18/gameboy-tutorial-rom/",target:"_blank",rel:"noopener noreferrer"},rn={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Sprite_Tutorial",target:"_blank",rel:"noopener noreferrer"},tn={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Color_Tutorial",target:"_blank",rel:"noopener noreferrer"},on={href:"http://gbdev.gg8.se/wiki/articles/GBDK_Joypad_Tutorial",target:"_blank",rel:"noopener noreferrer"},nn={href:"https://web.archive.org/web/20210427064949/www.personal.triticom.com/~erm/GameBoy/",target:"_blank",rel:"noopener noreferrer"},an={href:"https://videlais.com/2016/07/03/programming-game-boy-games-using-gbdk-part-1-configuring-programming-and-compiling/",target:"_blank",rel:"noopener noreferrer"},ln={href:"https://github.com/mrombout/gbdk_playground",target:"_blank",rel:"noopener noreferrer"},sn={href:"https://www.youtube.com/playlist?list=PLeEj4c2zF7PaFv5MPYhNAkBGrkx4iPGJo",target:"_blank",rel:"noopener noreferrer"},hn={href:"https://laroldsjubilantjunkyard.com/tutorials/",target:"_blank",rel:"noopener noreferrer"},dn=e("h2",{id:"homebrews",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#homebrews","aria-hidden":"true"},"#"),r(" Homebrews")],-1),cn=e("p",null,"Complete and open source games.",-1),gn={href:"https://hh.gbdev.io",target:"_blank",rel:"noopener noreferrer"},mn=e("h3",{id:"asm-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#asm-1","aria-hidden":"true"},"#"),r(" ASM")],-1),pn={href:"https://github.com/BonsaiDen/Tuff.gb",target:"_blank",rel:"noopener noreferrer"},un={href:"https://github.com/Sanqui/2048-gb",target:"_blank",rel:"noopener noreferrer"},bn={href:"https://bitbucket.org/Sanqui/snake/src/?at=master",target:"_blank",rel:"noopener noreferrer"},_n={href:"https://github.com/huderlem/lazerpong",target:"_blank",rel:"noopener noreferrer"},fn={href:"https://github.com/AntonioND/geometrix",target:"_blank",rel:"noopener noreferrer"},kn={href:"https://github.com/AntonioND/ucity",target:"_blank",rel:"noopener noreferrer"},yn={href:"https://github.com/mholtkamp/carazu",target:"_blank",rel:"noopener noreferrer"},Bn={href:"https://github.com/DonaldHays/snake-gb",target:"_blank",rel:"noopener noreferrer"},Gn={href:"https://github.com/furrtek/GB303",target:"_blank",rel:"noopener noreferrer"},wn={href:"https://github.com/JustSid/Sushi",target:"_blank",rel:"noopener noreferrer"},vn={href:"https://github.com/bitnenfer/flappy-boy-asm",target:"_blank",rel:"noopener noreferrer"},Cn={href:"https://github.com/dubvulture/gbdev",target:"_blank",rel:"noopener noreferrer"},An={href:"https://github.com/tbsp/Adjustris",target:"_blank",rel:"noopener noreferrer"},Dn={href:"https://github.com/exezin/exeman/",target:"_blank",rel:"noopener noreferrer"},Sn={href:"https://github.com/ISSOtm/Aevilia-GB",target:"_blank",rel:"noopener noreferrer"},Mn={href:"https://github.com/Kartones/gameboy",target:"_blank",rel:"noopener noreferrer"},xn={href:"https://github.com/dannye/pokered-gbc",target:"_blank",rel:"noopener noreferrer"},Pn={href:"https://github.com/tslanina/Retro-GameBoyColor-ToyToy",target:"_blank",rel:"noopener noreferrer"},Rn={href:"https://github.com/tslanina/Retro-GameBoyColor-StefaN",target:"_blank",rel:"noopener noreferrer"},Tn={href:"https://github.com/tslanina/Retro-GameBoyColor-Galaxia",target:"_blank",rel:"noopener noreferrer"},En={href:"https://github.com/sanqui/desgb",target:"_blank",rel:"noopener noreferrer"},jn={href:"https://github.com/l0k1/superhappyfunbubbletime",target:"_blank",rel:"noopener noreferrer"},Ln={href:"https://github.com/lancekindle/minesweepGB",target:"_blank",rel:"noopener noreferrer"},Fn={href:"https://github.com/pinobatch/libbet",target:"_blank",rel:"noopener noreferrer"},zn={href:"https://github.com/dannye/waveform-gb",target:"_blank",rel:"noopener noreferrer"},In={href:"https://gitlab.com/BonsaiDen/vectroid.gb",target:"_blank",rel:"noopener noreferrer"},On={href:"https://github.com/gb-archive/plantboy",target:"_blank",rel:"noopener noreferrer"},Hn={href:"https://makrill.itch.io/death-planet",target:"_blank",rel:"noopener noreferrer"},Nn={href:"https://makrill.itch.io/quartet",target:"_blank",rel:"noopener noreferrer"},Kn={href:"https://snorpung.itch.io/dangan-gb",target:"_blank",rel:"noopener noreferrer"},Un=e("h3",{id:"c-1",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#c-1","aria-hidden":"true"},"#"),r(" C")],-1),Vn={href:"https://github.com/bitnenfer/FlappyBoy",target:"_blank",rel:"noopener noreferrer"},Wn={href:"https://github.com/pashutk/flappybird-gameboy",target:"_blank",rel:"noopener noreferrer"},Zn={href:"https://github.com/gb-archive/fbgb",target:"_blank",rel:"noopener noreferrer"},Jn={href:"https://web.archive.org/web/20171002042716/http://ludumdare.com/compo/ludum-dare-34/?action=preview&uid=6823",target:"_blank",rel:"noopener noreferrer"},qn={href:"https://github.com/cppchriscpp/SquishyTheTurtle",target:"_blank",rel:"noopener noreferrer"},Xn={href:"https://github.com/avivace/quadratino",target:"_blank",rel:"noopener noreferrer"},Yn={href:"https://github.com/elfgames/doctorhow",target:"_blank",rel:"noopener noreferrer"},Qn={href:"https://github.com/Zal0/gbjam2016",target:"_blank",rel:"noopener noreferrer"},$n={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},ea={href:"https://github.com/brovador/GBsnake",target:"_blank",rel:"noopener noreferrer"},ra={href:"https://github.com/andreasjhkarlsson/gb-mines",target:"_blank",rel:"noopener noreferrer"},ta={href:"http://www.atari2600land.com/gameboy/oranges.html",target:"_blank",rel:"noopener noreferrer"},oa={href:"https://github.com/Imanolea/bitbitjam3_red_hot_princess_carnage",target:"_blank",rel:"noopener noreferrer"},na={href:"http://www.tensi.eu/thomas/programming/gameboy/loderunner.html",target:"_blank",rel:"noopener noreferrer"},aa={href:"https://refreshgames.co.uk/2017/04/24/ludum-dare-38-entry-hives/",target:"_blank",rel:"noopener noreferrer"},la={href:"https://github.com/DonaldHays/bubblefactory",target:"_blank",rel:"noopener noreferrer"},ia={href:"https://github.com/rubfi/gbc-atari-boxing",target:"_blank",rel:"noopener noreferrer"},sa={href:"https://github.com/haroldo-ok/really-old-stuff/tree/master/gameboy",target:"_blank",rel:"noopener noreferrer"},ha={href:"https://github.com/SimonLarsen/tobutobugirl-dx",target:"_blank",rel:"noopener noreferrer"},da={href:"http://sebastianmihai.com/gameboy-burly-bear.html",target:"_blank",rel:"noopener noreferrer"},ca={href:"http://sebastianmihai.com/gameboy-color-burly-bear.html",target:"_blank",rel:"noopener noreferrer"},ga={href:"https://github.com/MasterIV/PostBot",target:"_blank",rel:"noopener noreferrer"},ma={href:"https://github.com/kanfor/gunsridersgameboy",target:"_blank",rel:"noopener noreferrer"},pa={href:"https://github.com/gingemonster/DinosOfflineAdventure",target:"_blank",rel:"noopener noreferrer"},ua={href:"https://github.com/rnegron/dino-gb",target:"_blank",rel:"noopener noreferrer"},ba={href:"https://github.com/flozz/evoland.gb",target:"_blank",rel:"noopener noreferrer"},_a={href:"https://github.com/bbbbbr/Petris",target:"_blank",rel:"noopener noreferrer"},fa={href:"https://bbbbbr.itch.io/petris",target:"_blank",rel:"noopener noreferrer"},ka={href:"https://github.com/gb-archive/infinity-gbc",target:"_blank",rel:"noopener noreferrer"},ya={href:"https://gbdev.gg8.se/forums/viewtopic.php?id=743",target:"_blank",rel:"noopener noreferrer"},Ba={href:"https://user0x7f.itch.io/black-castle",target:"_blank",rel:"noopener noreferrer"},Ga={href:"https://gbdev.gg8.se/forums/viewtopic.php?id=674",target:"_blank",rel:"noopener noreferrer"},wa={href:"https://user0x7f.itch.io/genesis",target:"_blank",rel:"noopener noreferrer"},va={href:"https://antonylavelle.itch.io/indestructotank-gb",target:"_blank",rel:"noopener noreferrer"},Ca={href:"https://pocketpixel.design/super-jetpak-dx-game-boy-rom.html",target:"_blank",rel:"noopener noreferrer"},Aa={href:"https://aiguanachein.itch.io/powa",target:"_blank",rel:"noopener noreferrer"},Da={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},Sa={href:"https://thegreatgallus.itch.io/cavern-mvm-9",target:"_blank",rel:"noopener noreferrer"},Ma={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},xa={href:"https://ctneptune.itch.io/mona-and-the-witchs-hat-dx",target:"_blank",rel:"noopener noreferrer"},Pa={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},Ra={href:"https://gamejolt.com/games/the-bouncing-ball-gb/86699",target:"_blank",rel:"noopener noreferrer"},Ta={href:"https://drludos.itch.io/dmg-deals-damage",target:"_blank",rel:"noopener noreferrer"},Ea=e("h3",{id:"gb-studio",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#gb-studio","aria-hidden":"true"},"#"),r(" GB Studio")],-1),ja={href:"https://kadabura.itch.io/soul-void",target:"_blank",rel:"noopener noreferrer"},La={href:"https://izma.itch.io/deadeus",target:"_blank",rel:"noopener noreferrer"},Fa={href:"https://lumpytouch.itch.io/super-impostor-bros",target:"_blank",rel:"noopener noreferrer"},za=e("h3",{id:"demos",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#demos","aria-hidden":"true"},"#"),r(" Demos")],-1),Ia={href:"https://github.com/AntonioND/back-to-color",target:"_blank",rel:"noopener noreferrer"},Oa={href:"https://github.com/vegard/beach-gbc",target:"_blank",rel:"noopener noreferrer"},Ha={href:"https://github.com/mills32/CUTE_DEMO",target:"_blank",rel:"noopener noreferrer"},Na={href:"https://github.com/svendahlstrand/10-print-game-boy",target:"_blank",rel:"noopener noreferrer"},Ka=e("code",null,"10 PRINT",-1),Ua={href:"https://github.com/naavis/roboto-demo",target:"_blank",rel:"noopener noreferrer"},Va={href:"https://github.com/wtjones/matrix-rain-gb",target:"_blank",rel:"noopener noreferrer"},Wa={href:"https://github.com/LIJI32/GBVideoPlayer",target:"_blank",rel:"noopener noreferrer"},Za={href:"https://github.com/LIJI32/GBVideoPlayer2",target:"_blank",rel:"noopener noreferrer"},Ja=e("em",null,"stereo- PCM audio, and introduces video compression",-1),qa=e("h2",{id:"reverse-engineering",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#reverse-engineering","aria-hidden":"true"},"#"),r(" Reverse Engineering")],-1),Xa={href:"http://ecc-comp.blogspot.it/2016/03/reverse-engineering-kirbys-dreamland-2.html",target:"_blank",rel:"noopener noreferrer"},Ya={href:"https://github.com/pret/pokemon-reverse-engineering-tools",target:"_blank",rel:"noopener noreferrer"},Qa={href:"https://www.megabeets.net/reverse-engineering-a-gameboy-rom-with-radare2",target:"_blank",rel:"noopener noreferrer"},$a={href:"http://kemenaran.winosx.com/posts/category-disassembling-links-awakening/",target:"_blank",rel:"noopener noreferrer"},el={href:"https://github.com/h3nnn4n/Reverse-Engineering-the-GameBoy-Tetris",target:"_blank",rel:"noopener noreferrer"},rl={href:"https://gbdev.io/guides/dma_hijacking",target:"_blank",rel:"noopener noreferrer"},tl=e("h3",{id:"game-disassemblies",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-disassemblies","aria-hidden":"true"},"#"),r(" Game Disassemblies")],-1),ol={href:"https://github.com/pret/pokered",target:"_blank",rel:"noopener noreferrer"},nl={href:"https://github.com/pret/pokecrystal",target:"_blank",rel:"noopener noreferrer"},al={href:"https://github.com/pret/pokeyellow",target:"_blank",rel:"noopener noreferrer"},ll={href:"https://github.com/pret/pokegold",target:"_blank",rel:"noopener noreferrer"},il={href:"https://github.com/pret/pokepinball",target:"_blank",rel:"noopener noreferrer"},sl={href:"https://github.com/pret/poketcg",target:"_blank",rel:"noopener noreferrer"},hl={href:"https://github.com/pret/pokegold-spaceworld",target:"_blank",rel:"noopener noreferrer"},dl={href:"https://github.com/mojobojo/LADX-Disassembly",target:"_blank",rel:"noopener noreferrer"},cl={href:"https://github.com/drenn1/ages-disasm",target:"_blank",rel:"noopener noreferrer"},gl={href:"https://github.com/vinheim3/tetris-gb-disasm",target:"_blank",rel:"noopener noreferrer"},ml={href:"https://github.com/DevEd2/FXHammer-Disasm",target:"_blank",rel:"noopener noreferrer"},pl={href:"https://github.com/sanqui/hm3",target:"_blank",rel:"noopener noreferrer"},ul={href:"https://github.com/daid/FFA-disassembly",target:"_blank",rel:"noopener noreferrer"},bl=e("h2",{id:"game-boy-camera",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#game-boy-camera","aria-hidden":"true"},"#"),r(" Game Boy Camera")],-1),_l=e("h3",{id:"retrieving-images",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#retrieving-images","aria-hidden":"true"},"#"),r(" Retrieving images")],-1),fl=e("p",null,"Game Boy Printer emulation (e.g. to retrieve images from the camera):",-1),kl={href:"https://github.com/mofosyne/arduino-gameboy-printer-emulator",target:"_blank",rel:"noopener noreferrer"},yl={href:"https://github.com/applefreak/esp8266-gameboy-printer",target:"_blank",rel:"noopener noreferrer"},Bl={href:"https://github.com/HerrZatacke/wifi-gbp-emulator",target:"_blank",rel:"noopener noreferrer"},Gl={href:"https://github.com/cristofercruz/gbp-esp-shield-pcb",target:"_blank",rel:"noopener noreferrer"},wl={href:"https://github.com/mofosyne/GameboyPrinterSniffer",target:"_blank",rel:"noopener noreferrer"},vl=e("h3",{id:"changing-the-camera-s-behavior",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#changing-the-camera-s-behavior","aria-hidden":"true"},"#"),r(" Changing the camera's behavior")],-1),Cl=e("p",null,"Methods to improve and/or manipulate the camera's quality and behavior:",-1),Al={href:"http://ekeler.com/game-boy-camera-canon-ef-mount",target:"_blank",rel:"noopener noreferrer"},Dl={href:"https://www.thingiverse.com/thing:4337362",target:"_blank",rel:"noopener noreferrer"},Sl={href:"https://github.com/cristofercruz/game-boy-camera-frame-replacer",target:"_blank",rel:"noopener noreferrer"},Ml=e("h3",{id:"post-processing",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#post-processing","aria-hidden":"true"},"#"),r(" Post processing")],-1),xl={href:"https://github.com/mofosyne/GameboyPrinterPaperSimulation",target:"_blank",rel:"noopener noreferrer"},Pl={href:"https://github.com/HerrZatacke/gb-printer-web",target:"_blank",rel:"noopener noreferrer"},Rl=e("h2",{id:"related-projects",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#related-projects","aria-hidden":"true"},"#"),r(" Related projects")],-1),Tl={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},El={href:"https://gbstudiocentral.com/resources/",target:"_blank",rel:"noopener noreferrer"},jl={href:"https://discord.gg/knRryZWGcm",target:"_blank",rel:"noopener noreferrer"},Ll={href:"https://github.com/trash80/Arduinoboy",target:"_blank",rel:"noopener noreferrer"},Fl={href:"https://github.com/diegovalverde/papiGB",target:"_blank",rel:"noopener noreferrer"},zl={href:"https://github.com/trun/fpgaboy",target:"_blank",rel:"noopener noreferrer"},Il={href:"https://github.com/danShumway/Piglet",target:"_blank",rel:"noopener noreferrer"},Ol={href:"https://github.com/PumpMagic/ostrich",target:"_blank",rel:"noopener noreferrer"},Hl={href:"https://github.com/trash80/mGB",target:"_blank",rel:"noopener noreferrer"},Nl={href:"https://github.com/LIJI32/GBVisualizer",target:"_blank",rel:"noopener noreferrer"},Kl={href:"https://github.com/drhelius/arduinogameboy",target:"_blank",rel:"noopener noreferrer"},Ul={href:"https://github.com/bitnenfer/gameboy-brainfuck",target:"_blank",rel:"noopener noreferrer"},Vl={href:"https://github.com/elseyf/gbfk",target:"_blank",rel:"noopener noreferrer"},Wl={href:"https://github.com/mattcurrie/gb-save-states",target:"_blank",rel:"noopener noreferrer"},Zl={href:"https://github.com/jdeblese/gbcpu",target:"_blank",rel:"noopener noreferrer"},Jl={href:"https://youtube.com/watch?v=1lzHfLYzyRM",target:"_blank",rel:"noopener noreferrer"},ql={href:"https://dhole.github.io/post/gameboy_serial_1/",target:"_blank",rel:"noopener noreferrer"},Xl={href:"https://dhole.github.io/post/gameboy_serial_2/",target:"_blank",rel:"noopener noreferrer"},Yl={href:"https://dhole.github.io/post/gameboy_serial_3/",target:"_blank",rel:"noopener noreferrer"},Ql={href:"https://dhole.github.io/post/gameboy_cartridge_rw_1/",target:"_blank",rel:"noopener noreferrer"},$l={href:"https://tilde.town/~minerobber/techwriteups/pokemonpc.html",target:"_blank",rel:"noopener noreferrer"},ei={href:"https://dhole.github.io/post/gameboy_custom_logo/",target:"_blank",rel:"noopener noreferrer"},ri={href:"https://www.gamasutra.com/blogs/DoctorLudos/20171207/311143/",target:"_blank",rel:"noopener noreferrer"},ti={href:"https://www.gamasutra.com/blogs/DoctorLudos/20180213/314554/",target:"_blank",rel:"noopener noreferrer"},oi={href:"http://fuji.drillspirits.net/?post=87",target:"_blank",rel:"noopener noreferrer"},ni={href:"https://github.com/stijnfrishert/liblsdj",target:"_blank",rel:"noopener noreferrer"},ai={href:"https://github.com/jkotlinski/lsdpatch",target:"_blank",rel:"noopener noreferrer"},li={href:"https://github.com/ChaosCabbage/crazy-gameboy-video-experiments",target:"_blank",rel:"noopener noreferrer"},ii={href:"https://github.com/ekimekim/gbos",target:"_blank",rel:"noopener noreferrer"},si={href:"https://translate.google.com/translate?hl=&sl=ru&tl=en&u=https%3A%2F%2Fweb.archive.org%2Fweb%2F20081226145726%2Fhttp%3A%2F%2Fworkmaster.ru%2Findex.php%3Fp%3D8&sandbox=1",target:"_blank",rel:"noopener noreferrer"},hi={href:"https://github.com/Palmr/gb-link-cable",target:"_blank",rel:"noopener noreferrer"},di={href:"https://github.com/Tauwasser/GBCartFlasher",target:"_blank",rel:"noopener noreferrer"},ci={href:"https://github.com/zephray/VerilogBoy/",target:"_blank",rel:"noopener noreferrer"},gi={href:"https://github.com/furrtek/GBCamcorder",target:"_blank",rel:"noopener noreferrer"},mi={href:"https://github.com/insidegadgets/GBCartRead",target:"_blank",rel:"noopener noreferrer"},pi={href:"https://github.com/insidegadgets/GBxCart-RW",target:"_blank",rel:"noopener noreferrer"},ui={href:"http://www.its.caltech.edu/~costis/sgb_hack/",target:"_blank",rel:"noopener noreferrer"},bi=e("h3",{id:"directories",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#directories","aria-hidden":"true"},"#"),r(" Directories")],-1),_i={href:"http://gbdev.gg8.se/files/",target:"_blank",rel:"noopener noreferrer"},fi={href:"https://github.com/gb-archive",target:"_blank",rel:"noopener noreferrer"},ki={href:"https://github.com/gb-archive/salvage",target:"_blank",rel:"noopener noreferrer"},yi=e("h3",{id:"websites",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#websites","aria-hidden":"true"},"#"),r(" Websites")],-1),Bi={href:"http://devrs.com/gb",target:"_blank",rel:"noopener noreferrer"},Gi={href:"http://pdroms.de/news/gameboy/",target:"_blank",rel:"noopener noreferrer"},wi={href:"http://hhug.me",target:"_blank",rel:"noopener noreferrer"};function vi(Ci,Ai){const o=l("ExternalLinkIcon"),a=l("RouterLink");return h(),d("div",null,[g,e("h3",m,[p,r(),e("a",u,[r("The Game Boy, a hardware autopsy"),t(o)])]),b,_,e("h3",f,[k,r(),e("a",y,[r("The Ultimate Game Boy Talk"),t(o)])]),B,G,e("blockquote",null,[w,v,e("p",null,[r("Game Boy Advance development is covered by another project, the "),e("a",C,[r("awesome-GBAdev"),t(o)]),r(" list. GBA, however, can run GB/GBC games. It does so in a slightly different way compared to native hardware. This is covered in the Emulator Development section of this list.")]),A]),D,e("ul",null,[e("li",null,[e("a",S,[M,t(o)]),r(" - The single, most comprehensive technical reference to Game Boy available to the public. Corrected, updated and maintained by the community.")]),e("li",null,[e("a",x,[r("The Cycle-Accurate Game Boy Docs"),t(o)]),r(" - A precise documentation by AntonioND to make a cycle-accurate Game Boy emulator.")]),e("li",null,[e("a",P,[r("Complete Technical Reference"),t(o)]),r(" - by Gekkio.")]),e("li",null,[e("a",R,[r("Game Boy Architecture: A Practical Analysis"),t(o)]),r(" - by Rodrigo Copetti.")]),e("li",null,[e("a",T,[r("Game Boy Project Report"),t(o)]),r(" - Report of an hardware "),e("a",E,[r("emulator"),t(o)]),r(" (on a Terasic DE1-SoC Board) developed as final project for the CSEE4840 Embedded Systems Design course at Columbia University.")])]),j,e("ul",null,[e("li",null,[e("a",L,[r("gb-opcodes"),t(o)]),r(" - Opcodes table")]),e("li",null,[e("a",F,[r("RGBDS opcodes reference"),t(o)]),r(" - A reference of all instructions, including short descriptions, cycle and byte counts, and explanations of flag modifications.")])]),z,e("ul",null,[e("li",null,[e("a",I,[r("Bootstrap ROM"),t(o)])]),e("li",null,[e("a",O,[r("Unused Palettes"),t(o)])]),e("li",null,[e("a",H,[r("Colorization palettes in the BIOS"),t(o)])]),e("li",null,[e("a",N,[r("Boot ROM Disassembly"),t(o)])]),e("li",null,[e("a",K,[r("GBC Hicolour notes"),t(o)]),r(" - A technical note regarding Hicolour mode trick for Game Boy Color and its realization in the GBC game “Crystalis”.")])]),U,e("ul",null,[e("li",null,[e("a",V,[r("DMG Schematics"),t(o)]),r(" - Hardware schematics.")]),e("li",null,[e("a",W,[r("The Game Boy Project"),t(o)]),r(" - Provides a study on the hardware and detailed constructional information for the implementation of three 8-bit bidirectional parallel ports.")]),e("li",null,[e("a",Z,[r("Related custom hardware"),t(o)]),r(" - by Gekkio.")]),e("li",null,[e("a",J,[r("ESP8266 GB Dev Board"),t(o)]),r(" - Dev board for Game Boy accessories development, powered by ESP8266.")]),e("li",null,[e("a",q,[r("ESP8266 GB Printer"),t(o)]),r(" - A device that emulates the GB Printer and lets you retrieve images using WiFi.")]),e("li",null,[e("a",X,[r("fruttenboel"),t(o)]),r(" - Page with loads of information on the hardware, custom boards to interface with the console and other related projects.")]),e("li",null,[e("a",Y,[r("Game Boy hardware database"),t(o)]),r(" - Data and photos of various types of Game Boy consoles.")]),e("li",null,[e("a",Q,[r("dmg-schematics"),t(o)]),r(" - Schematics and annotated overlay for the DMG-CPU B chip, extracted from die photos, made with KiCad. Also contains Electric VLSI library with layouts for some of the cells and memories.")])]),$,e("ul",null,[e("li",null,[e("a",ee,[r("Dan Docs"),t(o)]),r(" - Obscure Game Boy hardware documentation.")]),e("li",null,[e("a",re,[r("Edge of Emulation"),t(o)]),r(", a series of articles about emulating and investigating Game Boy accessories. Also available as "),e("a",te,[r("technical documents"),t(o)]),r(" in the GBE- emulator documentation. "),e("ul",null,[e("li",null,[e("a",oe,[r("Mobile Adapter GB"),t(o)]),r(" - Internet connectivity and DLC on the Game Boy Color.")]),e("li",null,[e("a",ne,[r("The Game Boy Printer"),t(o)])]),e("li",null,[e("a",ae,[r("Pocket Sonar"),t(o)]),r(" - A blue cart with built-in sonar hardware.")]),e("li",null,[e("a",le,[r("Zok Zok Heroes"),t(o)]),r(" - Zok Zok Heroes' Full Changer, a motion-activated accessory.")]),e("li",null,[e("a",ie,[r("Infrared Madness"),t(o)]),r(" - Infrared communication on the Game Boy Color.")]),e("li",null,[e("a",se,[r("Game Boy 4-Player Adapter"),t(o)]),r(" - DMG-07.")]),e("li",null,[e("a",he,[r("Barcode Boy"),t(o)]),r(" - The first Game Boy card-scanner.")]),e("li",null,[e("a",de,[r("Barcode Taisen Bardigun"),t(o)]),r(" - A late 90s DMG-GBC barcode reader.")])])]),e("li",null,[e("a",ce,[r("DMG-07 Technical Documentation"),t(o)])]),e("li",null,[e("a",ge,[r("Game Boy Camera RE"),t(o)]),r(" - Documentation about GB Camera and tools used to reverse engineer it by using Arduino.")]),e("li",null,[e("a",me,[r("Creating photo realistic images with neural networks and a Gameboy Camera"),t(o)])]),e("li",null,[e("a",pe,[r("The Game Boy Printer"),t(o)]),r(" - An in-depth technical document about the printer hardware, the communication protocol and the usual routine that games used for implementing the print feature.")]),e("li",null,[e("a",ue,[r("Ben Heck Reverse Engineers Game Boy Printer"),t(o)]),r(" (Errata: the used thermal paper is expired, 4 colors are actually printable).")]),e("li",null,[e("a",be,[r("Arduino Game Boy Printer Emulator"),t(o)]),r(" - Emulating a Game Boy Printer via the Game Boy Link cable with an Arduino.")]),e("li",null,[e("a",_e,[r("Mobile Game Boy Adapter"),t(o)])]),e("li",null,[e("a",fe,[r("GB KISS LINK MODEM"),t(o)])])]),ke,e("ul",null,[e("li",null,[e("a",ye,[r("GB Flash Cartridges for Sale"),t(o)]),r(" - A List of available, ready-made Game Boy Flash Cartridges.")]),e("li",null,[e("a",Be,[r("AntonioND's docs"),t(o)]),r(" - Corrected schematics and infos on cartridge header data.")]),e("li",null,[e("a",Ge,[r("Gekkio's Game Boy cartridge types"),t(o)]),r(" - An overview on existing cartridge types.")]),e("li",null,[r("Gekkio's cartridge analysis: "),e("ul",null,[e("li",null,[e("a",we,[r("DMG-BEAN-02"),t(o)]),r(";")]),e("li",null,[e("a",ve,[r("MBC1"),t(o)]),r(";")]),e("li",null,[e("a",Ce,[r("no MBC"),t(o)]),r(".")])])]),e("li",null,[r("Pinout, registers descriptions and VHDL code of some cartridge types on Tauwasser's wiki: "),e("ul",null,[e("li",null,[e("a",Ae,[r("MBC1"),t(o)])]),e("li",null,[e("a",De,[r("MBC2"),t(o)])]),e("li",null,[e("a",Se,[r("MMM01"),t(o)])])])]),e("li",null,[e("a",Me,[r("Game Boy Cartridges Schematics"),t(o)]),r(" - Schematics for MBC2 and MBC3 types.")]),e("li",null,[e("a",xe,[r("Cartridges PCB photos"),t(o)])]),e("li",null,[e("a",Pe,[r("MBC1+RAM+Battery cartridge Schematic"),t(o)]),r(" - First schematics by Jeff Frohwein.")]),e("li",null,[e("a",Re,[r("MBC1 and MBC2 cartridges circuits"),t(o)]),r(" - and explanation on how these MBC bank switch and control RAM.")]),Te,e("li",null,[e("a",Ee,[r("Game Boy cartridge PCB photos"),t(o)])])]),je,e("ul",null,[e("li",null,[e("a",Le,[r("Emulating a GameBoy Cartridge"),t(o)]),r(" - Emulating the functionality of a Game Boy cartridge with the development board STM32F4.")]),e("li",null,[e("a",Fe,[r("Wolf"),t(o)]),r(" - Game Boy cartridge with co-processor.")]),e("li",null,[e("a",ze,[r("Homebrew-Gameboy-Cartridge"),t(o)]),r(" - Eagle library, schematic, and board files for a cartridge PCB using an Atmel AT49F040 as ROM.")]),e("li",null,[e("a",Ie,[r("Homebrew Gameboy Color Cartridge"),t(o)]),r(" - Board layout for an EEPROM powered cartridge.")]),e("li",null,[e("a",Oe,[r("Nekocart"),t(o)]),r(" - Open-source flash cartridge using an Xilinx CPLD as MBC5 ("),e("a",He,[r("Post"),t(o)]),r(").")]),e("li",null,[e("a",Ne,[r("Reiner Ziegler's Game Boy page"),t(o)]),r(" - Commercial and homemade programmable cartridges and programming systems. Tutorials, wiring and schematics provided.")]),e("li",null,[e("a",Ke,[r("Gameboy-MBC5-MBC1-Hybrid"),t(o)]),r(" - CPLD implementation of a MBC5/MBC1 Hybrid cartridge.")])]),Ue,e("ul",null,[e("li",null,[e("a",Ve,[r("Introduction to Game Boy Hacking"),t(o)]),r(" - Workshop introducing basic assembly, debugging and reverse engineering.")]),e("li",null,[e("a",We,[r("GBSOUND.txt"),t(o)]),r(" - A document detailing the Game Boy sound engine.")]),e("li",null,[e("a",Ze,[r("gbdev FAQs"),t(o)]),r(" - Must read by Jeff Frohwein.")]),e("li",null,[e("a",Je,[r("Game Boy Bootrom"),t(o)]),r(" - Commented dump of the DMG bootrom.")]),e("li",null,[e("a",qe,[r("Differences between the Z80 and the gameboy's processor"),t(o)])]),e("li",null,[e("a",Xe,[r("Gameboy 2BPP Graphics Format"),t(o)]),r(" - Information on how the Game Boy interprets VRAM tile data to color pixels.")])]),Ye,e("ul",null,[e("li",null,[e("a",Qe,[r("Reverse Engineering fine details of Game Boy hardware"),t(o)]),r(" - 43 minutes talk by Gekkio given at Disobey 2018 ("),e("a",$e,[r("errata"),t(o)]),r(").")]),e("li",null,[e("a",er,[r("Emulation of Nintendo Game Boy"),t(o)]),r(" - Overview of the Game Boy hardware with the perspective of building an emulator.")]),e("li",null,[e("a",rr,[r("DMG-01"),t(o)]),r(" - An educational Gameboy Emulator in Rust and a companion book explaining its development. *"),e("a",tr,[r("Oh Boy! Creating a Game Boy Emulator in Rust"),t(o)]),r("- is a talk given at Rust Fest 18 about this.")]),e("li",null,[e("a",or,[r("Building a Game Boy emulator in JavaScript"),t(o)]),r(" - Step by step tutorial.")]),e("li",null,[e("a",nr,[r("Writing a Game Boy emulator, Cinoop"),t(o)])]),e("li",null,[e("a",ar,[r("0dmg"),t(o)]),r(" - Learning Rust by building a partial Game Boy emulator.")]),e("li",null,[e("a",lr,[r("RealBoy Emulator"),t(o)]),r(" - A series of posts about the design and implementation of the RealBoy Emulator.")]),e("li",null,[e("a",ir,[r("Codeslinger"),t(o)]),r(" - Another series of posts documenting the building of an emulator.")]),e("li",null,[e("a",sr,[r("Why did I spend 1.5 months creating a Gameboy emulator?"),t(o)]),r(" - Blog post.")]),e("li",null,[e("a",hr,[r("binjgb rewind"),t(o)]),r(" - Implementing a *rewind- feature.")]),e("li",null,[e("a",dr,[r("binjgb on the web"),t(o)]),r(" - Porting of the binjgb emulator to Web Assembly. "),e("a",cr,[r("(Part 2)"),t(o)])]),e("li",null,[e("a",gr,[r("binjgb debugging hangs"),t(o)]),r(" - Investigations on emulations quirks.")]),e("li",null,[e("a",mr,[r("Decoding Gameboy Z80 opcodes"),t(o)]),r(" - How to algorithmically decode Game Boy instructions (as opposed to writing one huge switch-case statement).")]),e("li",null,[e("a",pr,[r("Porting a GO Game Boy emulator to WebAssembly"),t(o)])]),e("li",null,[e("a",ur,[r("About swotGB"),t(o)]),r(" - Notes about the development of a Game Boy emulator in JavaScript.")]),e("li",null,[t(a,{to:"/EMULATORS.html"},{default:i(()=>[r("List of open source emulators")]),_:1})]),e("li",null,[e("a",br,[r("Game Boy Doctor"),t(o)]),r(" - A command line tool for comparing logs from your emulator to those from a known-correct one. Useful for line-by-line debugging of Blargg's test ROMs.")])]),_r,e("ul",null,[e("li",null,[e("a",fr,[r("Blargg's test roms"),t(o)])]),e("li",null,[e("a",kr,[r("Gekkio's test roms"),t(o)])]),e("li",null,[e("a",yr,[r("SameSuite"),t(o)])]),e("li",null,[e("a",Br,[r("Mealybug Tearoom Tests"),t(o)])]),e("li",null,[e("a",Gr,[r("GB Accuracy Tests"),t(o)])]),e("li",null,[e("a",wr,[r("144p Test Suite"),t(o)]),r(" - Port of Artemio Urbina's 240p Test Suite to the Game Boy.")]),e("li",null,[e("a",vr,[r("MBC3 RTC test ROM"),t(o)])]),e("li",null,[e("a",Cr,[r("dmg-acid2"),t(o)]),r(" and "),e("a",Ar,[r("cgb-acid2"),t(o)]),r(" - Basic PPU rendering tests.")])]),Dr,e("p",null,[r("The "),e("a",Sr,[r("Choosing tools for Game Boy development"),t(o)]),r(" essay provides an overview of the available development tools for Game Boy.")]),Mr,e("ul",null,[e("li",null,[e("a",xr,[r("RGBDS"),t(o)]),r(" - Assembler and linker package. "),e("a",Pr,[r("Documentation"),t(o)]),r(".")]),e("li",null,[e("a",Rr,[r("ASMotor"),t(o)]),r(" - Assembler engine and development system targeting Game Boy, among other CPUs. Written by the original RGBDS author. "),e("a",Tr,[r("Documentation"),t(o)]),r(".")]),e("li",null,[e("a",Er,[r("wla-dx"),t(o)]),r(" - Yet Another GB-Z80/Z80/... Multi Platform Cross Assembler Package. "),e("a",jr,[r("Documentation"),t(o)]),r(".")])]),Lr,e("ul",null,[e("li",null,[e("a",Fr,[r("GBDK"),t(o)]),r(" - Maintained and modernized GBDK (Game Boy Development Kit) powered by an updated version of the SDCC toolchain. Provides a C compiler, assembler, linker and a set of libraries. "),e("ul",null,[e("li",null,[e("a",zr,[r("API docs: Getting Started"),t(o)])]),e("li",null,[e("a",Ir,[r("Examples"),t(o)])]),e("li",null,[e("a",Or,[r("Documentation, links and tools"),t(o)])])])]),e("li",null,[e("a",Hr,[r("Turbo Rascal Syntax Error"),t(o)]),r(" - Complete suite (IDE, compiler, programming language, resource editor) intended for developing games/demos for 8 / 16-bit line of computers, including the Game Boy and Game Boy Color.")])]),Nr,e("ul",null,[e("li",null,[e("a",Kr,[r("RGBDS-Live"),t(o)]),r(" - In-browser coding environment to try out RGBDS.")]),e("li",null,[e("a",Ur,[r("Wiz"),t(o)]),r(" - A high-level assembly language for writing homebrew on retro console platforms (Game Boy, NES, Atari 2600, and more).")]),e("li",null,[e("a",Vr,[r("gbforth"),t(o)]),r(" - A Forth-based Game Boy development kit.")]),e("li",null,[e("a",Wr,[r("gbasm-rs"),t(o)]),r(" - An opinionated Rust based compiler for Game Boy z80 assembly code.")]),e("li",null,[e("a",Zr,[r("gbasm"),t(o)]),r(" - A JavaScript based compiler for Game Boy z80 assembly code.")]),e("li",null,[e("a",Jr,[r("tniASM"),t(o)]),r(" - Macro Assembler.")]),e("li",null,[e("a",qr,[r("Assembler"),t(o)]),r(" - Assembler written in Swift.")]),e("li",null,[e("a",Xr,[r("llvm-gbz80"),t(o)]),r(" / "),e("a",Yr,[r("clang-gbz80"),t(o)]),r(" - Clang/LLVM port to the GBZ80 CPU (similar to the deprecated "),e("a",Qr,[r("euclio/llvm-gbz80"),t(o)]),r(").")]),e("li",null,[e("a",$r,[r("gbdk-go"),t(o)]),r(" - A compiler translates Go programs to C code. The output C code is built into GB ROM by GBDK.")])]),et,e("ul",null,[e("li",null,[e("p",null,[e("a",rt,[r("BGB"),t(o)]),r(" - Powerful emulator and debugger. Provides an accurate hardware emulation.")])]),e("li",null,[e("p",null,[e("a",tt,[r("SameBoy"),t(o)]),r(" - Accurate emulator with a wide range of powerful debugging features.")])]),e("li",null,[e("p",null,[e("a",ot,[r("Mooneye GB"),t(o)]),r(" - Research project and emulator in Rust.")])]),e("li",null,[e("p",null,[e("a",nt,[r("mGBA"),t(o)]),r(" - Modern cross platform GBA emulator which also runs GB/GBC games.")])]),e("li",null,[e("p",null,[e("a",at,[r("Binjgb"),t(o)]),r(" - 5Kloc emulator that passes most of the tests. *Rewind- feature. Runs in the browser using WebAssembly.")])]),e("li",null,[e("p",null,[e("a",lt,[r("Gambatte"),t(o)]),r(" - Cross-platform and accurate emulator.")])]),e("li",null,[e("p",null,[e("a",it,[r("MetroBoy"),t(o)]),r(" - A playable, circuit-level simulation of an entire Game Boy.")])]),e("li",null,[e("p",null,[e("a",st,[r("gbe-plus"),t(o)]),r(" - A recently rewritten emulator that has a large effort in preserving the functions of obscure accessories (such as IR link, Mobile Network GB, Barcode Boy, GB Printer, local and online GB Serial Link Cable, ... )")])]),e("li",null,[e("p",null,[e("a",ht,[r("Emulicious"),t(o)]),r(" - Provides accurate emulation and includes powerful tools such as a profiler and source-level debugging for ASM and C via a "),e("a",dt,[r("VS Code debug adapter"),t(o)]),r(".")])])]),e("p",null,[t(a,{to:"/EMULATORS.html"},{default:i(()=>[r("Complete list of open source emulators")]),_:1})]),ct,gt,e("ul",null,[e("li",null,[e("a",mt,[r("ZGB"),t(o)]),r(" - A little engine for creating games for the original Game Boy (expands gbdk, more info "),e("a",pt,[r("here"),t(o)]),r(").")]),e("li",null,[e("a",ut,[r("Retr0 GB"),t(o)]),r(" - An engine for creating games (expands GBDK).")])]),bt,e("ul",null,[e("li",null,[e("a",_t,[r("GBExtended"),t(o)]),r(" - C library extending gbdk.")]),e("li",null,[e("a",ft,[r("gbdk-lib-extension"),t(o)]),r(" - A small set of sources and tools for the Game Boy Development Kit by Michael Hope.")]),e("li",null,[e("a",kt,[r("Dot Matrix Game Editor"),t(o)]),r(" - An IDE for Game Boy programming in a C-like language called GBL, with many other features like tile and map extraction, WLA-DX assembly, and more.")]),e("li",null,[e("a",yt,[r("mgbdis"),t(o)]),r(" - Game Boy ROM disassembler with RGBDS compatible output.")]),e("li",null,[e("a",Bt,[r("ROM Header Utility"),t(o)]),r(" - An online tool to inspect and modify a ROM's header data, including the logo.")]),e("li",null,[e("a",Gt,[r("romusage"),t(o)]),r(" - Command line tool for estimating usage (free space) of Game Boy ROMs from a .map, .noi or ihx file. Works with GBDK-2020 and RGBDS.")]),e("li",null,[e("a",wt,[r("awake"),t(o)]),r(" - Game Boy decompiler.")]),e("li",null,[e("a",vt,[r("Game Boy Text Tools"),t(o)]),r(" - Set of tools for text manipulation and translation of Game Boy ROMs written in Node.js.")]),e("li",null,[e("a",Ct,[r("evscript"),t(o)]),r(" - A scripting language for the Game Boy, useful for enemy AI, dialogue, animations, and coroutines.")]),e("li",null,[e("a",At,[r("evunit"),t(o)]),r(" - A unit testing program for assembly code.")])]),Dt,e("ul",null,[e("li",null,[e("a",St,[r("Game Boy Tile Data Generator"),t(o)]),r(" - HTML5 / JS web application that will convert bitmap images to hexadecimal data appropriate for use in tile based graphical applications, specifically GB.")]),e("li",null,[e("a",Mt,[r("Harry Mulder's GB Development"),t(o)]),r(" - Some sources and home of Game Boy Tile Designer (GBTD) and Game Boy Map Builder (GBMB) tools.")]),e("li",null,[e("a",xt,[r("GBTiles"),t(o)]),r(" - Converts .GBR files created with Harry Mulder's Tile Designer (GBTD) and .GBM files created with Harry Mulder's Map Builder (GBMB) to different formats for use with the Game Boy and GBDK.")]),e("li",null,[e("a",Pt,[r("bmp2cgb"),t(o)]),r(" - Graphics converter for Game Boy Color development providing real time palette adjustments.")]),e("li",null,[e("a",Rt,[r("png2gb"),t(o)]),r(" - CLI tool to convert image file to game boy .c array.")]),e("li",null,[e("a",Tt,[r("GB-convert"),t(o)]),r(" - Game Boy tile conversion and map editor tool (converts to assembly).")]),e("li",null,[e("a",Et,[r("brewtool"),t(o)]),r(" - A collection of primitive editor/converter tools for making assets used with homebrew ROM development.")]),e("li",null,[e("a",jt,[r("vtGBte"),t(o)]),r(" - A minimalistic ncurses tile editor.")]),e("li",null,[e("a",Lt,[r("tpp1"),t(o)]),r(" - Definition and specification of a custom GB/GBC memory/hardware mapper, as a functional superset of MBC.")]),e("li",null,[e("a",Ft,[r("libstdgb"),t(o)]),r(" - A C library of useful Game Boy operations (SDCC).")]),e("li",null,[e("a",zt,[r("Tilemap GB"),t(o)]),r(" - GIMP image editor plug-in for importing & exporting GBMB and GBTD tilemaps and tilesets (as bitmap images or .GBM/.GBR files).")]),e("li",null,[e("a",It,[r("Tilemap Helper"),t(o)]),r(" - GIMP image editor plug-in for optimizing tile maps and tile sets.")]),e("li",null,[e("a",Ot,[r("Tilemap Studio"),t(o)]),r(" - A tilemap editor for Game Boy, Color, Advance, and SNES projects. Written in C++ with FLTK.")]),e("li",null,[e("a",Ht,[r("Superfamiconv"),t(o)]),r(" - Flexible and composable tile graphics converter supporting Super Nintendo, Game Boy, Game Boy Color, Game Boy Advance, Mega Drive and PC Engine formats.")])]),Nt,e("ul",null,[e("li",null,[e("a",Kt,[r("cart-dumper"),t(o)]),r(" - Game Boy Cartridge Dumper ROM.")]),e("li",null,[e("a",Ut,[r("gbcamextract"),t(o)]),r(" - Extracts photos from Game Boy Camera saves.")]),e("li",null,[e("a",Vt,[r("Game Boy LCD sniffing"),t(o)]),r(" - Sniff your Game Boy's LCD using a logic analyzer.")]),e("li",null,[e("a",Wt,[r("swapdump"),t(o)]),r(" - Diagnostic utility for Game Boy flashcarts.")]),e("li",null,[e("a",Zt,[r("Gameboy-LinkUp"),t(o)]),r(" - Game Boy LinkUp serial cable networking project.")])]),Jt,e("ul",null,[e("li",null,[e("a",qt,[r("DevSound"),t(o)]),r(" - Sound driver embeddable in homebrews which supports pulse width manipulation, arpeggios, and multiple waveforms.")]),e("li",null,[e("a",Xt,[r("Carillon Player"),t(o)]),r(" - Music Engine.")]),e("li",null,[e("a",Yt,[r("GBT PLAYER"),t(o)]),r(" - A music player library and converter kit.")]),e("li",null,[e("a",Qt,[r("mmlgb"),t(o)]),r(" - A MML parser and GBDK sound driver for the Nintendo Game Boy.")]),e("li",null,[e("a",$t,[r("XPMCK"),t(o)]),r(" - An MML based music compiler with support for Game Boy & Game Boy Color.")]),e("li",null,[e("a",eo,[r("GBSoundSystem"),t(o)]),r(" - A modernized audio driver for GameBoy Tracker (aka the Paragon 5 music player).")]),e("li",null,[e("a",ro,[r("hUGETracker"),t(o)]),r(" - A music tracker based on OpenMPT, focused on ease of use, compact output, and embeddability in homebrew games.")]),e("li",null,[e("a",to,[r("CBT-FX"),t(o)]),r(" - A GBDK-2020 sound effect driver compatible with FX-Hammer sound effects.")])]),oo,e("ul",null,[e("li",null,[e("strong",null,[e("a",no,[r("gb asm tutorial"),t(o)])]),r(" - Step by step tutorial, building several ROMs to accompany its explanations.")]),e("li",null,[e("a",ao,[r("ASMSchool"),t(o)]),r(" - A set of lessons by Duo about coding in Assembly for GB/GBC and disassembling.")]),e("li",null,[e("a",lo,[r("hardware.inc"),t(o)]),r(" - Standard include file containing Game Boy hardware definitions for use in RGBDS projects.")]),e("li",null,[e("a",io,[r("Assembly tutorial by David Pello"),t(o)]),r(" - Good document to learn to produce working asm code for gb. Brief explanations of many important topics. Many examples with commented source code.")]),e("li",null,[e("a",so,[r("assemblydigest"),t(o)]),r(" - Exploring Game Boy programming techniques: "),e("ul",null,[e("li",null,[e("a",ho,[r("Making an Empty Game Boy ROM (in Wiz)"),t(o)])]),e("li",null,[e("a",co,[r("Making Art for the Game Boy"),t(o)])])])]),e("li",null,[e("a",go,[r("Beginner's Guide to Reverse Engineering GB"),t(o)]),r(" - Some starting tips on disassembling and reverse engineering.")]),e("li",null,[e("a",mo,[r("FlappyBoy: Making a simple Game Boy Game"),t(o)])]),e("li",null,[e("a",po,[r("Super Game Boy development"),t(o)]),r(" - Step by step tutorial to implement Super Game Boy features (frame and palettes).")]),e("li",null,[e("a",uo,[r("GameBoy programming tutorial: Hello World!"),t(o)]),r(" - Step by step tutorial.")]),e("li",null,[e("a",bo,[r("DMGreport"),t(o)]),r(" - Game programming tutorials in assembly.")]),e("li",null,[e("a",_o,[r("OAM DMA tutorial"),t(o)]),r(" - Example of how to use OAM DMA in assembly.")]),e("li",null,[e("a",fo,[r("Game Boy Assembly Programming for the Modern Game Developer"),t(o)]),r(" - An e-book about making Game Boy games in Assembly.")])]),ko,yo,e("ul",null,[e("li",null,[e("a",Bo,[r("dev'rs ASM section"),t(o)]),r(" - A lot of working demos and sources.")]),e("li",null,[e("a",Go,[r("EmmaEwert's experiments"),t(o)]),r(" - A collection of prototype programs, mostly just toying around. Among others, a daylight effect, transparency and a weather effect.")]),e("li",null,[e("a",wo,[r("DeadCScroll"),t(o)]),r(' - A detailed tutorial on how to make the screen wobble, among other "raster effects"')])]),vo,e("ul",null,[e("li",null,[e("a",Co,[r("Nitty Gritty Gameboy Cycle Timing"),t(o)])]),e("li",null,[e("a",Ao,[r("Mode3 Sprite Timing"),t(o)])]),e("li",null,[e("a",Do,[r("GameBoy Color DMA-Transfers v0.0.1"),t(o)])]),e("li",null,[e("a",So,[r("STAT interrupt timings"),t(o)])]),e("li",null,[e("a",Mo,[r("Video Timing"),t(o)])])]),xo,e("ul",null,[e("li",null,[e("a",Po,[r("rgbds-template"),t(o)]),r(" - Basic hello-world example for Game Boy using RGBDS.")]),e("li",null,[e("a",Ro,[r("Game Boy Assembly Language Primer"),t(o)]),r(" - Simple template code with memory defines, copy routines and IBM font tilemap.")]),e("li",null,[e("a",To,[r("bootstrap.gb"),t(o)]),r(" - An example Game Boy project.")]),e("li",null,[e("a",Eo,[r("Gameboy Boilerplate"),t(o)]),r(" - Boilerplate project to move quicker into the actual assembly code for your game.")]),e("li",null,[e("a",jo,[r("GingerBread"),t(o)]),r(" - A software library for making your own Game Boy games. It is made to be used alongside the book "),e("a",Lo,[r("Game Boy Assembly Programming for the Modern Game Developer"),t(o)]),r(" which also doubles as documentation.")]),e("li",null,[e("a",Fo,[r("gb-vwf"),t(o)]),r(" - Library to print variable-width text, comes with a demo.")]),e("li",null,[e("a",zo,[r("gb-boilerplate"),t(o)]),r(" - A template for starting Game Boy projects, providing a Makefile for infrastructure.")]),e("li",null,[e("a",Io,[r("gb-starter-kit"),t(o)]),r(" - An expansion on the above, including base library code as well to get started faster.")]),e("li",null,[e("a",Oo,[r("gb-template"),t(o)]),r(" - A template with basic functions such as joypad input, DMA transfers, and map/tile data loading.")])]),Ho,e("ul",null,[e("li",null,[e("a",No,[r("gbz80-highlight"),t(o)]),r(" - Notepad+- and gedit syntax highlighting files for RGBDS assembly.")]),e("li",null,[e("a",Ko,[r("Vim syntax file for the Game Boy assembler RGBASM"),t(o)]),r(" - Vim syntax highlighting for RGBDS assembly.")]),e("li",null,[e("a",Uo,[r("Vim syntax file for RGBDS"),t(o)]),r(" - Another Vim syntax highlighting file for RGBDS assembly.")]),e("li",null,[e("a",Vo,[r("sublime-rgbds"),t(o)]),r(" - A Sublime Text 3 package for RGBDS, including syntax highlighting and some completion snippets.")]),e("li",null,[e("a",Wo,[r("Z80 Assembly support for Visual Studio Code"),t(o)])]),e("li",null,[e("a",Zo,[r("rgbds-vscode"),t(o)]),r(" - Visual Studio Code language extension for RGBDS GBZ80 Assembly.")]),e("li",null,[e("a",Jo,[r("rgbds-mode"),t(o)]),r(" - Emacs major mode for RGBDS assembly.")])]),qo,e("ul",null,[e("li",null,[e("a",Xo,[r("8-Bit Wonderland"),t(o)]),r(" - Well-written introductory document about how the Game Boy works and how to start developing working code for it.")]),e("li",null,[e("a",Yo,[r("Grooves Game Boy Programming"),t(o)]),r(" - A complete set of lessons about implementing various game mechanics in a Game Boy game.")]),e("li",null,[e("a",Qo,[r("How to Write a Simple Side Scrolling Game"),t(o)]),r(" - Old (but still relevant) tutorial.")]),e("li",null,[e("a",$o,[r("Just another simple tutorial"),t(o)])]),e("li",null,[e("a",en,[r("GBDK Tutorial"),t(o)]),r(" - Fairly minimal game demo for getting started with GBDK.")]),e("li",null,[e("a",rn,[r("GBDK Sprite"),t(o)]),r(" - Presents a workflow for getting multiple sprites to display and animate.")]),e("li",null,[e("a",tn,[r("GBDK Color"),t(o)]),r(" - Extends your knowledge of basic spriting on the Game Boy by adding colors to sprites, backgrounds and the window layer.")]),e("li",null,[e("a",on,[r("GBDK Joypad"),t(o)]),r(" - Details the use of the joypad with GBDK.")]),e("li",null,[e("a",nn,[r("Game Boy home of Flavor"),t(o)]),r(" - Some full games and sources.")]),e("li",null,[e("a",an,[r("GBDK Configuring and Programming Tutorial"),t(o)]),r(" - Configuring GBDK, Using Tiles, Colliding Sprites, GBTD, GBMB, Memory Management and ROM Banking.")]),e("li",null,[e("a",ln,[r("Simplified GBDK examples"),t(o)])]),e("li",null,[e("a",sn,[r("GBDK Programming Video Tutorials"),t(o)]),r(" - A series of video tutorials introducing beginners to programming with GBDK.")]),e("li",null,[e("a",hn,[r("Larold's Jubilant Junkyard"),t(o)]),r(" - A collection of detailed GBDK-2020 based tutorials.")])]),dn,cn,e("ul",null,[e("li",null,[e("a",gn,[r("Homebrew Hub"),t(o)]),r(" - A community-led attempt to collect, archive and preserve every unlicensed and homebrew game released for Game Boy. Entries are playable online.")])]),mn,e("ul",null,[e("li",null,[e("a",pn,[r("Tuff"),t(o)])]),e("li",null,[e("a",un,[r("2048-gb"),t(o)])]),e("li",null,[e("a",bn,[r("Snake"),t(o)])]),e("li",null,[e("a",_n,[r("Lazerpong"),t(o)])]),e("li",null,[e("a",fn,[r("Geometrix"),t(o)])]),e("li",null,[e("a",kn,[r("µCity"),t(o)])]),e("li",null,[e("a",yn,[r("Carazu"),t(o)])]),e("li",null,[e("a",Bn,[r("Snake-gb"),t(o)])]),e("li",null,[e("a",Gn,[r("GB303"),t(o)]),r(" - GB303 wavetable-based TB-303 style synthesizer for the Nintendo Game Boy.")]),e("li",null,[e("a",wn,[r("Sushi"),t(o)])]),e("li",null,[e("a",vn,[r("Flappy-boy-asm"),t(o)])]),e("li",null,[e("a",Cn,[r("kupman"),t(o)]),r(" and some other projects.")]),e("li",null,[e("a",An,[r("Adjustris"),t(o)])]),e("li",null,[e("a",Dn,[r("exeman"),t(o)])]),e("li",null,[e("a",Sn,[r("Aevilia"),t(o)])]),e("li",null,[e("a",Mn,[r("GBSlides"),t(o)]),r(" - A simple Game Boy Powerpoint-like slides viewer.")]),e("li",null,[e("a",xn,[r("Pokered-gbc"),t(o)]),r(" - Pokémon Red remade with full GBC support.")]),e("li",null,[e("a",Pn,[r("ToyToy"),t(o)])]),e("li",null,[e("a",Rn,[r("StefaN"),t(o)]),r(" - Fourway Breakout clone.")]),e("li",null,[e("a",Tn,[r("Galaxia"),t(o)])]),e("li",null,[e("a",En,[r("desgb"),t(o)]),r(" - DES encryption.")]),e("li",null,[e("a",jn,[r("superhappyfunbubbletime"),t(o)])]),e("li",null,[e("a",Ln,[r("minesweepGB"),t(o)])]),e("li",null,[e("a",Fn,[r("Libbet and the Magic Floor"),t(o)])]),e("li",null,[e("a",zn,[r("waveform-gb"),t(o)]),r(" - Program visualizing the wave form used by the wave channel. The wave form can be edited freely and playback of the wave is updated immediately.")]),e("li",null,[e("a",In,[r("vectroid.gb"),t(o)]),r(" - Developed with gbasm.")]),e("li",null,[e("a",On,[r("PlantBoy"),t(o)])]),e("li",null,[e("a",Hn,[r("Death Planet"),t(o)])]),e("li",null,[e("a",Nn,[r("Quartet"),t(o)]),r(" - Puzzle game for the Game Boy (Color) and Super Game Boy.")]),e("li",null,[e("a",Kn,[r("Dangan"),t(o)])])]),Un,e("ul",null,[e("li",null,[e("a",Vn,[r("FlappyBoy"),t(o)])]),e("li",null,[e("a",Wn,[r("flappybird-gameboy"),t(o)])]),e("li",null,[e("a",Zn,[r("fbgb"),t(o)])]),e("li",null,[e("a",Jn,[r("Novascape"),t(o)])]),e("li",null,[e("a",qn,[r("Squishy the Turtle"),t(o)])]),e("li",null,[e("a",Xn,[r("Quadratino"),t(o)])]),e("li",null,[e("a",Yn,[r("Doctor How"),t(o)])]),e("li",null,[e("a",Qn,[r("Super Princess' 2092 Exodus"),t(o)]),r(" - ("),e("a",$n,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",ea,[r("GBsnake"),t(o)])]),e("li",null,[e("a",ra,[r("gb-mines"),t(o)])]),e("li",null,[e("a",ta,[r("oranges"),t(o)])]),e("li",null,[e("a",oa,[r("red hot princess carnage"),t(o)])]),e("li",null,[e("a",na,[r("loderunner"),t(o)])]),e("li",null,[e("a",aa,[r("Hives"),t(o)])]),e("li",null,[e("a",la,[r("Bubble Factory"),t(o)]),r(" - *Vanilla- SDCC (no gbdk).")]),e("li",null,[e("a",ia,[r("GBC Atari Boxing"),t(o)]),r(" - Atari 2600 Boxing clone for the Game Boy (Color).")]),e("li",null,[e("a",sa,[r("GB raycaster, Vision-8"),t(o)]),r(" - and some other projects.")]),e("li",null,[e("a",ha,[r("Tobu Tobu Girl Deluxe"),t(o)]),r(" - An arcade platformer for the Game Boy (Color).")]),e("li",null,[e("a",da,[r("Burly Bear vs. The Mean Foxes"),t(o)]),r(" ("),e("a",ca,[r("GBC"),t(o)]),r(" port)")]),e("li",null,[e("a",ga,[r("PostBot"),t(o)])]),e("li",null,[e("a",ma,[r("Guns & Riders"),t(o)])]),e("li",null,[e("a",pa,[r("Dino's Offline Adventure"),t(o)]),r(" - A clone of the Google Chrome offline game.")]),e("li",null,[e("a",ua,[r("dino-gb"),t(o)]),r(" - Another clone of the Chrome game.")]),e("li",null,[e("a",ba,[r("Evoland.gb"),t(o)]),r(" - A port of the first level of Evoland.")]),e("li",null,[e("a",_a,[r("Petris"),t(o)]),r(" - A puzzle game of shapely pets for the Game Boy Color ("),e("a",fa,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",ka,[r("Infinity"),t(o)]),r(" - RPG developed by Affinix Software primarily between the years 1999 and 2001. The game never found a publisher and was eventually canceled. Got recently released with the full source, development tools and workflows.")]),e("li",null,[e("a",ya,[r("Black Castle"),t(o)]),r(" - Side scrolling platformer for the Game Boy ("),e("a",Ba,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",Ga,[r("Genesis"),t(o)]),r(" - Shmup for the Game Boy ("),e("a",wa,[r("itch.io"),t(o)]),r(").")]),e("li",null,[e("a",va,[r("Indestructo Tank!"),t(o)])]),e("li",null,[e("a",Ca,[r("Super JetPak DX"),t(o)])]),e("li",null,[e("a",Aa,[r("Powa!"),t(o)]),r(" - Side scrolling platformer for the Game Boy (Color) ("),e("a",Da,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",Sa,[r("Cavern"),t(o)]),r(" - ("),e("a",Ma,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",xa,[r("Mona and the Witch's Hat Deluxe"),t(o)]),r(" - ("),e("a",Pa,[r("ZGB engine"),t(o)]),r(").")]),e("li",null,[e("a",Ra,[r("The Bouncing Ball"),t(o)])]),e("li",null,[e("a",Ta,[r("DMG Deals Damage"),t(o)])])]),Ea,e("ul",null,[e("li",null,[e("a",ja,[r("Soul Void"),t(o)]),r(" - Interactive horror fiction.")]),e("li",null,[e("a",La,[r("Deadeus"),t(o)])]),e("li",null,[e("a",Fa,[r("SUPER IMPOSTOR BROS."),t(o)])])]),za,e("ul",null,[e("li",null,[e("a",Ia,[r("Back to Color"),t(o)])]),e("li",null,[e("a",Oa,[r("beach-gbc"),t(o)])]),e("li",null,[e("a",Ha,[r("CUTE DEMO"),t(o)])]),e("li",null,[e("a",Na,[Ka,r(" Game Boy"),t(o)])]),e("li",null,[e("a",Ua,[r("Roboto Demo"),t(o)])]),e("li",null,[e("a",Va,[r("matrix-rain-gb"),t(o)]),r(" - A Matrix digital rain effect in assembler.")]),e("li",null,[e("a",Wa,[r("GBVideoPlayer"),t(o)]),r(" - A technical demo demonstrating how the Game Boy LCD controller can be hacked to make a Game Boy Color play a full motion video in color, together with music.")]),e("li",null,[e("a",Za,[r("GBVideoPlayer2"),t(o)]),r(" - The second iteration of the above demo, which increases the resolution, adds "),Ja,r(".")])]),qa,e("ul",null,[e("li",null,[e("a",Xa,[r("Reverse engineering Kirby's Dreamland 2"),t(o)])]),e("li",null,[e("a",Ya,[r("pokemontools"),t(o)]),r(" - a python module that provides various reverse engineering components for various Pokémon games.")]),e("li",null,[e("a",Qa,[r("Reverse Engineering a Gameboy ROM with radare2"),t(o)]),r(" - A walkthrough to reverse engineer a Game Boy ROM challenge using radare2.")]),e("li",null,[e("a",$a,[r("Disassembling Link's Awakening"),t(o)]),r(" - A series of blog posts about disassembling Link's Awakening DX.")]),e("li",null,[e("a",el,[r("Reverse Engineering the GameBoy Tetris"),t(o)])]),e("li",null,[e("a",rl,[r("DMA hijacking"),t(o)]),r(" - A simple technique that allows you to run custom code in most GB/SGB/CGB games, provided you have an ACE exploit.")])]),tl,e("ul",null,[e("li",null,[e("a",ol,[r("Pokémon Red/Blue"),t(o)])]),e("li",null,[e("a",nl,[r("Pokémon Crystal"),t(o)])]),e("li",null,[e("a",al,[r("Pokémon Yellow"),t(o)])]),e("li",null,[e("a",ll,[r("Pokémon Gold and Silver"),t(o)])]),e("li",null,[e("a",il,[r("Pokémon Pinball"),t(o)])]),e("li",null,[e("a",sl,[r("Pokémon TCG"),t(o)])]),e("li",null,[e("a",hl,[r("pokegold-spaceworld"),t(o)]),r(" - Pokémon Gold and Silver 1997 Space World demo.")]),e("li",null,[e("a",dl,[r("Link's Awakening DX"),t(o)])]),e("li",null,[e("a",cl,[r("Oracle of Ages"),t(o)])]),e("li",null,[e("a",gl,[r("Tetris"),t(o)]),r(" - Complete Tetris disassembly.")]),e("li",null,[e("a",ml,[r("FX Hammer"),t(o)])]),e("li",null,[e("a",pl,[r("Harvest Moon 3"),t(o)])]),e("li",null,[e("a",ul,[r("Final Fantasy Adventure"),t(o)])])]),bl,_l,fl,e("ul",null,[e("li",null,[e("a",kl,[r("Arduino Gameboy Printer Emulator"),t(o)]),r(" - Emulate a gameboy printer via the gameboy link cable.")]),e("li",null,[e("a",yl,[r("ESP8266 Game Boy Printer"),t(o)]),r(" - A device that emulates the Gameboy Printer and lets you retrieve images using WiFi powered by an ESP8266.")]),e("li",null,[e("a",Bl,[r("WiFi GBP Emulator"),t(o)]),r(" - A GameBoy printer emulator which provides the received data over a WiFi connection.")]),e("li",null,[e("a",Gl,[r("Game Boy WiFi Printer - D1 Mini Shield"),t(o)]),r(" - Game Boy Printer interface shield for D1 mini/mini Pro ESP8266 boards.")]),e("li",null,[e("a",wl,[r("Game Boy Printer Sniffer"),t(o)]),r(" - Sniff packet communications between a Game Boy and the Printer.")])]),vl,Cl,e("ul",null,[e("li",null,[e("a",Al,[r("Game Boy Camera Canon EF Lens Mount"),t(o)])]),e("li",null,[e("a",Dl,[r("Game Boy Camera to Canon Lens mount"),t(o)]),r(" - based on the above.")]),e("li",null,[e("a",Sl,[r("game-boy-camera-frame-replacer"),t(o)]),r(" - Manipulate the ROM of a camera to include custom frames")])]),Ml,e("ul",null,[e("li",null,[e("a",xl,[r("Game Boy Printer Paper Simulation"),t(o)]),r(" - Generate as-if-printed images of digital printed images.")]),e("li",null,[e("a",Pl,[r("Game Boy Printer Web"),t(o)]),r(" - Gallery app for to the Game Boy camera: import pictures from exports or cartridge dumps and choose color palettes.")])]),Rl,e("ul",null,[e("li",null,[e("a",Tl,[r("GB Studio"),t(o)]),r(" - Drag and drop game creator with simple, no knowledge required, visual scripting. "),e("ul",null,[e("li",null,[e("a",El,[r("Resources to get started"),t(o)])]),e("li",null,[e("a",jl,[r("Dedicated Discord"),t(o)])])])]),e("li",null,[e("a",Ll,[r("ArduinoBoy"),t(o)]),r(" - Serial communication (MIDI) from an Arduino to the Game Boy for music applications such as LittleSoundDJ, Nanoloop, and mGB.")]),e("li",null,[e("a",Fl,[r("papiGB"),t(o)]),r(" - Game Boy Classic fully functional FPGA implementation from scratch.")]),e("li",null,[e("a",zl,[r("fpgaboy"),t(o)]),r(" - Implementation Nintendo's Game Boy console on an FPGA.")]),e("li",null,[e("a",Il,[r("Piglet"),t(o)]),r(" - A LUA-driven AI that plays classic Game Boy color games using experimentation. In active development.")]),e("li",null,[e("a",Ol,[r("Ostrich"),t(o)]),r(" - A Game Boy Sound System player written in Swift.")]),e("li",null,[e("a",Hl,[r("mGB"),t(o)]),r(" - A Game Boy cartridge program that enables the Game Boy to act as a full MIDI supported sound module.")]),e("li",null,[e("a",Nl,[r("GBVisualizer"),t(o)]),r(" - Demonstrating the use of two undocumented Game Boy Color registers, nicknamed PCM12 (FF76) and PCM34 (FF77), which can be used to read the current PCM amplitude of the 4 APU channels.")]),e("li",null,[e("a",Kl,[r("ArduinoGameBoy"),t(o)]),r(" - Arduino based Game Boy cartridge reader and writer.")]),e("li",null,[e("a",Ul,[r("gameboy-brainfuck"),t(o)]),r(" - Brainf*ck interpreter.")]),e("li",null,[e("a",Vl,[r("gbfk"),t(o)]),r(" - Brainf*ck interpreter, with input.")]),e("li",null,[e("a",Wl,[r("gb-save-states"),t(o)]),r(" - Patches to add save state support to Game Boy games when playing on the original hardware.")]),e("li",null,[e("a",Zl,[r("gbcpu"),t(o)]),r(" - A CPU and peripherals implementing the Game Boy instruction set and functionality.")]),e("li",null,[e("a",Jl,[r("Digitized Speech in Game Boy Games"),t(o)])]),e("li",null,[e("a",ql,[r("Sniffing Game Boy serial traffic with an STM32F4"),t(o)])]),e("li",null,[e("a",Xl,[r("Virtual Game Boy Printer with an STM32F4"),t(o)])]),e("li",null,[e("a",Yl,[r("Printing on the Game Boy Printer using an STM32F4"),t(o)])]),e("li",null,[e("a",Ql,[r("Programming Game Boy Chinese cartridges with an STM32F4"),t(o)])]),e("li",null,[e("a",$l,[r("Pokemon Pocket Computer:"),t(o)]),r(" - What is it and how to use it to make cheat codes.")]),e("li",null,[e("a",ei,[r("Booting the Game Boy with a custom logo"),t(o)]),r(" - Bypassing the Nintendo logo check.")]),e("li",null,[r('Making a Game Boy game in 2017: A "Sheep It Up!" Post-Mortem ('),e("a",ri,[r("part 1"),t(o)]),r(", "),e("a",ti,[r("part 2"),t(o)]),r(")")]),e("li",null,[e("a",oi,[r("Nintendo's fake logos"),t(o)]),r(" - Every cartridge has to show the authentic logo to be considered valid and be run, but obviously some companies managed to exploit the check system.")]),e("li",null,[e("a",ni,[r("liblsdj"),t(o)]),r(" - Utility library for interacting with the LSDj save format (.sav), song files (.lsdsng) and more.")]),e("li",null,[e("a",ai,[r("lsdpatch"),t(o)]),r(" - Tool for modifying samples, fonts and palettes on LSDj ROM images.")]),e("li",null,[e("a",li,[r("Game Boy video effects"),t(o)]),r(" - Some little experiments using the STAT interrupt to do funny video manipulations.")]),e("li",null,[e("a",ii,[r("gbos"),t(o)]),r(" - A basic operating system for the Game Boy.")]),e("li",null,[e("a",si,[r("Work Master OS"),t(o)]),r(" - Russian multi tasking operating system.")]),e("li",null,[e("a",hi,[r("Game Boy Link Cable Breakout Board"),t(o)])]),e("li",null,[e("a",di,[r("GBCartFlasher firmware"),t(o)])]),e("li",null,[e("a",ci,[r("VerilogBoy"),t(o)]),r(" - Game Boy compatible console Verilog RTL implementation.")]),e("li",null,[e("a",gi,[r("GBCamcorder"),t(o)]),r(" - Lo-Fi portable video recorder using a GameBoy Camera cartridge.")]),e("li",null,[e("a",mi,[r("GBCartRead"),t(o)]),r(" - Read ROM, Read RAM or Write RAM from/to a GameBoy Cartridge.")]),e("li",null,[e("a",pi,[r("GBxCart-RW"),t(o)]),r(" - A device for reading game ROMs, save games and restoring saves for GB, GBC and GBA carts from your PC via USB.")]),e("li",null,[e("a",ui,[r("Dumping the Super Game Boy Boot ROM"),t(o)])])]),bi,e("ul",null,[e("li",null,[e("a",_i,[r("Archive of related files"),t(o)])]),e("li",null,[e("a",fi,[r("The Game Boy Archive"),t(o)]),r(" - A library of Game Boy related software, hardware and literature. Aimed to mirror and preserve old and fragmented contributions from the last three decades.")]),e("li",null,[e("a",ki,[r("The Game Boy Archive - Salvage"),t(o)]),r(" - Historical archive of software, old articles, FAQs and various documents.")])]),yi,e("ul",null,[e("li",null,[e("a",Bi,[r("devrs.com/gb"),t(o)]),r(" - Old home of the scene: examples, sources, complete documentation, guides, tutorials and various tools.")]),e("li",null,[e("a",Gi,[r("pdroms.de"),t(o)]),r(" - Game Boy releases.")]),e("li",null,[e("a",wi,[r("Handheld Underground"),t(o)]),r(" - Unlicensed games, blog posts about Game Boy, home of the hhugboy emulator.")])])])}const Si=s(c,[["render",vi],["__file","resources.html.vue"]]);export{Si as default}; diff --git a/assets/sgb_border.html-29f3ff42.js b/assets/sgb_border.html-41de5f86.js similarity index 99% rename from assets/sgb_border.html-29f3ff42.js rename to assets/sgb_border.html-41de5f86.js index 6272b4e..113a8a8 100644 --- a/assets/sgb_border.html-29f3ff42.js +++ b/assets/sgb_border.html-41de5f86.js @@ -1,4 +1,4 @@ -import{_ as s,r as i,o as r,c as l,a as e,b as t,d as n,e as a}from"./app-19015fbd.js";const d={},c=e("h1",{id:"adding-a-custom-sgb-border",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#adding-a-custom-sgb-border","aria-hidden":"true"},"#"),t(" Adding a custom SGB border")],-1),h=e("p",null,"This document aims to help developers of DMG-compatible homebrew with adding Super Game Boy borders.",-1),u=e("p",null,"We will see how to:",-1),p=e("ul",null,[e("li",null,"Detect whether the program is running on a SGB"),e("li",null,"Transfer the border's tiles"),e("li",null,"Transfer and display the border's tilemap and palettes")],-1),b={href:"https://zlago.github.io/me/",target:"_blank",rel:"noopener noreferrer"},f={href:"https://coffeebat.neocities.org/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://eldred.fr",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/avivace",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/pinobatch",target:"_blank",rel:"noopener noreferrer"},_=e("h2",{id:"enabling-sgb-features",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#enabling-sgb-features","aria-hidden":"true"},"#"),t(" Enabling SGB features")],-1),y=e("p",null,"Before we can do anything else, we must first specify in the header that this game is aware of SGB features. Otherwise, the SGB BIOS will ignore any packets we send, and we won't even be able to detect when the program is running on SGB.",-1),S=e("p",null,"To enable SGB features:",-1),k={href:"https://gbdev.io/pandocs/The_Cartridge_Header#0146--sgb-flag",target:"_blank",rel:"noopener noreferrer"},B=e("code",null,"$03",-1),w={href:"https://gbdev.io/pandocs/The_Cartridge_Header#014b--old-licensee-code",target:"_blank",rel:"noopener noreferrer"},x=e("code",null,"$33",-1),G=e("code",null,"--sgb-compatible",-1),T=e("code",null,"--old-licensee 0x33",-1),P={href:"https://rgbds.gbdev.io/docs/rgbfix.1",target:"_blank",rel:"noopener noreferrer"},$=e("code",null,"rgbfix",-1),R=a('

    Packets

    The SGB BIOS can be "talked to" via command packets, sent bit by bit via the P1/JOYP register.

    An SGB packet consists of:

    • a "start" pulse (P1=%xx00xxxx)
    • 128 data pulses (P1=%xx01xxxx for "1", P1=%xx10xxxx for "0")
    • a "0" pulse (P1=%xx10xxxx)

    You must set P1 to %xx11xxxx between each pulse.

    This adds up to 16 bytes of data (LSB first). If a packet doesn't read all 16 bytes, the unused bytes are ignored.

    You should wait 4 frames between each packet and the next. This gives the SGB BIOS a chance to receive a packet even if it is doing something else time-consuming.

    ',7),I={href:"https://github.com/zlago/violence-gbc/blob/11cfdb6ee8a35e042fa9712484d814e0961cea7c/src/sub.sm83#L413-L463",target:"_blank",rel:"noopener noreferrer"},C={href:"https://gbdev.io/pandocs/SGB_Command_Packet.html",target:"_blank",rel:"noopener noreferrer"},N=a('

    This guide glosses over a minor detail, as certain packets can be (albeit unccomon) more than 16 bytes.

    TRN

    Bulk transfer (TRN) packets tell the SGB to copy the contents of the screen to buffers in Super NES work RAM. The CHR_TRN and PCT_TRN packets are used to send data for SGB borders.

    For a transfer to function properly, you must prepare VRAM and the LCD registers:

    1. set BGP to $e4 and LCDC to $91 (screen enabled, BG uses tiles $8000-$8fff and tilemap $9800, WIN and OBJ disabled, BG enabled)
    2. set SCX and SCY to $00
    3. the tilemap consists of $00, $01..$13, 12 bytes padding (offscreen), $14..$27, padding, repeat until $ff (inclusive)
    4. the data you want to send must be loaded at $8000-$8fff
    ',5),L={href:"https://github.com/zlago/snek-gbc/blob/baef0369f57d2b0d58316cb1c28c6cc22475a6c9/code/init.sm83#L208-L230",target:"_blank",rel:"noopener noreferrer"},O=a('
    • You must load the data into VRAM and enable the screen before sending the TRN packet. The SGB reads TRN payloads from the screen. If rendering is off, there is nothing on the screen to read.
    • You must wait ~8 frames after each TRN instead of just 4. The SGB BIOS has to finish what it's doing, receive the packet, and then read the screen.

    Detecting SGB

    Here's how a SGB detection routine should look like:

    1. Wait 12 or more frames for the SGB BIOS to start listening for packets.
    2. Send a MLT_REQ packet selecting 2 or 4 players ($89, $01 or $89, $03), and wait a couple frames for the SGB to receive the packet.
    3. Read the controller. Set P1 bit 5 to 0, then set P1 bits 5 and 4 to %11 (%xx11xxxx) to release the key matrix.
    4. Read the low nibble (bits 3-0) of P1, and look for a value other than %1111 (which indicates player 1).
    5. If player 1 was still found, repeat steps 3 and 4 once more, in case the next read indicates player 2.
    6. Optionally turn off multiplayer mode.

    If a non-%1111 value was found in step 4 either time, the program is running on SGB.

    ',5),A={href:"https://github.com/zlago/snek-gbc/blob/baef0369f57d2b0d58316cb1c28c6cc22475a6c9/code/init.sm83#L167-L196",target:"_blank",rel:"noopener noreferrer"},q=a(`
    SGB_Detect:
    +import{_ as s,r as i,o as r,c as l,a as e,b as t,d as n,e as a}from"./app-821120ad.js";const d={},c=e("h1",{id:"adding-a-custom-sgb-border",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#adding-a-custom-sgb-border","aria-hidden":"true"},"#"),t(" Adding a custom SGB border")],-1),h=e("p",null,"This document aims to help developers of DMG-compatible homebrew with adding Super Game Boy borders.",-1),u=e("p",null,"We will see how to:",-1),p=e("ul",null,[e("li",null,"Detect whether the program is running on a SGB"),e("li",null,"Transfer the border's tiles"),e("li",null,"Transfer and display the border's tilemap and palettes")],-1),b={href:"https://zlago.github.io/me/",target:"_blank",rel:"noopener noreferrer"},f={href:"https://coffeebat.neocities.org/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://eldred.fr",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/avivace",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/pinobatch",target:"_blank",rel:"noopener noreferrer"},_=e("h2",{id:"enabling-sgb-features",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#enabling-sgb-features","aria-hidden":"true"},"#"),t(" Enabling SGB features")],-1),y=e("p",null,"Before we can do anything else, we must first specify in the header that this game is aware of SGB features. Otherwise, the SGB BIOS will ignore any packets we send, and we won't even be able to detect when the program is running on SGB.",-1),S=e("p",null,"To enable SGB features:",-1),k={href:"https://gbdev.io/pandocs/The_Cartridge_Header#0146--sgb-flag",target:"_blank",rel:"noopener noreferrer"},B=e("code",null,"$03",-1),w={href:"https://gbdev.io/pandocs/The_Cartridge_Header#014b--old-licensee-code",target:"_blank",rel:"noopener noreferrer"},x=e("code",null,"$33",-1),G=e("code",null,"--sgb-compatible",-1),T=e("code",null,"--old-licensee 0x33",-1),P={href:"https://rgbds.gbdev.io/docs/rgbfix.1",target:"_blank",rel:"noopener noreferrer"},$=e("code",null,"rgbfix",-1),R=a('

    Packets

    The SGB BIOS can be "talked to" via command packets, sent bit by bit via the P1/JOYP register.

    An SGB packet consists of:

    • a "start" pulse (P1=%xx00xxxx)
    • 128 data pulses (P1=%xx01xxxx for "1", P1=%xx10xxxx for "0")
    • a "0" pulse (P1=%xx10xxxx)

    You must set P1 to %xx11xxxx between each pulse.

    This adds up to 16 bytes of data (LSB first). If a packet doesn't read all 16 bytes, the unused bytes are ignored.

    You should wait 4 frames between each packet and the next. This gives the SGB BIOS a chance to receive a packet even if it is doing something else time-consuming.

    ',7),I={href:"https://github.com/zlago/violence-gbc/blob/11cfdb6ee8a35e042fa9712484d814e0961cea7c/src/sub.sm83#L413-L463",target:"_blank",rel:"noopener noreferrer"},C={href:"https://gbdev.io/pandocs/SGB_Command_Packet.html",target:"_blank",rel:"noopener noreferrer"},N=a('

    This guide glosses over a minor detail, as certain packets can be (albeit unccomon) more than 16 bytes.

    TRN

    Bulk transfer (TRN) packets tell the SGB to copy the contents of the screen to buffers in Super NES work RAM. The CHR_TRN and PCT_TRN packets are used to send data for SGB borders.

    For a transfer to function properly, you must prepare VRAM and the LCD registers:

    1. set BGP to $e4 and LCDC to $91 (screen enabled, BG uses tiles $8000-$8fff and tilemap $9800, WIN and OBJ disabled, BG enabled)
    2. set SCX and SCY to $00
    3. the tilemap consists of $00, $01..$13, 12 bytes padding (offscreen), $14..$27, padding, repeat until $ff (inclusive)
    4. the data you want to send must be loaded at $8000-$8fff
    ',5),L={href:"https://github.com/zlago/snek-gbc/blob/baef0369f57d2b0d58316cb1c28c6cc22475a6c9/code/init.sm83#L208-L230",target:"_blank",rel:"noopener noreferrer"},O=a('
    • You must load the data into VRAM and enable the screen before sending the TRN packet. The SGB reads TRN payloads from the screen. If rendering is off, there is nothing on the screen to read.
    • You must wait ~8 frames after each TRN instead of just 4. The SGB BIOS has to finish what it's doing, receive the packet, and then read the screen.

    Detecting SGB

    Here's how a SGB detection routine should look like:

    1. Wait 12 or more frames for the SGB BIOS to start listening for packets.
    2. Send a MLT_REQ packet selecting 2 or 4 players ($89, $01 or $89, $03), and wait a couple frames for the SGB to receive the packet.
    3. Read the controller. Set P1 bit 5 to 0, then set P1 bits 5 and 4 to %11 (%xx11xxxx) to release the key matrix.
    4. Read the low nibble (bits 3-0) of P1, and look for a value other than %1111 (which indicates player 1).
    5. If player 1 was still found, repeat steps 3 and 4 once more, in case the next read indicates player 2.
    6. Optionally turn off multiplayer mode.

    If a non-%1111 value was found in step 4 either time, the program is running on SGB.

    ',5),A={href:"https://github.com/zlago/snek-gbc/blob/baef0369f57d2b0d58316cb1c28c6cc22475a6c9/code/init.sm83#L167-L196",target:"_blank",rel:"noopener noreferrer"},q=a(`
    SGB_Detect:
       ; test for SGB
       di
       call SGB_Wait4Frames
    diff --git a/assets/tools.html-c48ffccf.js b/assets/tools.html-c48ffccf.js
    new file mode 100644
    index 0000000..d35e854
    --- /dev/null
    +++ b/assets/tools.html-c48ffccf.js
    @@ -0,0 +1 @@
    +import{_ as i,r as s,o as r,c as l,a as e,b as t,d as a,e as n}from"./app-821120ad.js";const h={},d=e("h1",{id:"choosing-tools-for-game-boy-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#choosing-tools-for-game-boy-development","aria-hidden":"true"},"#"),t(" Choosing tools for Game Boy development")],-1),u=e("p",null,"This essay gives an overview of the Game Boy's capabilities, discussing the pros and cons of the available development tools, and providing a few tips to write more efficient code.",-1),c={href:"https://github.com/ISSOtm/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/tobiasvl",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/bbbbbr",target:"_blank",rel:"noopener noreferrer"},p=e("hr",null,null,-1),f=e("p",null,"In the past few years as retro gaming has grown in popularity, programming for older platforms has also gained traction. A popular platform is the Game Boy, both for its nostalgia and (relative) ease to program for.",-1),b={class:"custom-container warning"},y=e("p",{class:"custom-container-title"},"WARNING",-1),w=e("p",null,"This document only applies to the Game Boy and Game Boy Color. Game Boy Advance programming has little in common with Game Boy programming.",-1),_={href:"https://gbadev.net/tonc/",target:"_blank",rel:"noopener noreferrer"},v=n('

    When someone wants to make their own game, one of the first problems they will encounter is picking the tools they will use. There current main options are:

    • RGBDS (Rednex Game Boy Development System) and the Game Boy's Assembly language (ASM)
    • GBDK-2020 (Game Boy Development Kit) and the C language
    • ZGB (an engine built on GBDK-2020) and the C language
    • GB Studio (a drag-and-drop game creator with scripting)

    The purpose of this document is to provide some insights and help you make the better choice if you're starting a new project. I will also provide some "good practice" tips, both for C and ASM, if you have already made up your mind or are already using one of these.

    Overview

    The original Game Boy, codenamed the DMG, has a 1 MHz CPU [the CPU is actually clocked at 4 MHz, but every instruction takes up a multiple of 4 clocks, so it's often simplified to a 1 MHz CPU]. Given that an instruction takes approximately 2 to 3 cycles, this gives the CPU a capacity of 333,000~500,000 instructions per second. Its LCD boasts 60 fps [it's actually 59.73 fps], which rounds up to between 50,000 and 80,000 instructions per frame. Suddenly not so much, eh? It also has 8 kB of RAM, and 8 kB of video RAM ; a 160x144 px LCD (thus slightly wider than it's tall), 4 colors, and 4-channel audio.

    The Super Game Boy adds a few minor things, such as a customizable screen border, and some crude color. It's also slightly faster than the DMG.

    The Game Boy Color can [if you tell it to] unlock additional functionality, such as more fleshed-out color, a double-speed CPU, twice the video RAM and four times the RAM! (With caveats, obviously.)

    Languages

    The choice of programming language is important and can have a very large effect on a project. It determines how much work is involved, what will be possible, and how fast it will be able to run.

    Assembly (ASM)

    Most games and programs for the Game Boy written in ASM will use RGBDS or WLA-DX.

    Strengths:

    • Not too difficult to learn.
    • Extremely powerful and flexible.
    • When well written it allows for maximum speed and efficiency on the limited resources of the Game Boy hardware.

    Weaknesses:

    • It takes a special kind of work to write optimized ASM code.
    • It's quite verbose and sometimes tedious.
    • Will require more time and learning to get up and running when compared with C.
    • Code may not be easily shared with ports of a game on other platforms.

    C

    ',16),k={href:"https://github.com/z88dk/",target:"_blank",rel:"noopener noreferrer"},B=n('

    Strengths:

    • Allows for getting up and running faster than with ASM, especially when building on top of GBDK-2020 and ZGB.
    • The language abstractions make it relatively easy to implement ideas and algorithms.
    • C source debugging is available through Emulicious with the VSCode debug adapter, making it easier to understand problems if they arise.
    • ASM can be included in projects with C, either standalone or inline for speed critical features.

    Weaknesses:

    • The SDCC C compiler won't always generate code that runs as fast as skilled, hand-optimized assembly. It has matured a lot in the 20 years since the original GBDK, but bugs still turns up on occasion. On a platform with a slow CPU such as the Game Boy this can be a factor.
    • It’s easier to write inefficient code in C without realizing it. The Game Boy's CPU is only capable of performing 8-bit addition or subtraction, or 16-bit addition. Using INT32s is quite taxing on the CPU (it needs to do two consecutive 16-bit adds, and add the carry). See the tips below to avoid such blunders.
    • There is overhead due to C being a stack-oriented language, whereas the Game Boy's CPU is rather built for a register-oriented strategy. This most notably makes passing function arguments a lot slower, although SDCC has some optimizations for this.

    Non-Programming Language option

    Using a GUI instead- If you don’t want to learn a programming language in order to make Game Boy games, then GB Studio is an option. See the GB Studio section for more details.

    Development Platforms

    ',7),G={id:"rgbds-with-asm",tabindex:"-1"},S=e("a",{class:"header-anchor",href:"#rgbds-with-asm","aria-hidden":"true"},"#",-1),M={href:"http://github.com/rednex/rgbds",target:"_blank",rel:"noopener noreferrer"},C=e("p",null,"RGBDS is an actively maintained suite of programs that allow building a ROM using ASM (assembly). It contains three programs that perform different stages of the compilation, as well as a program that converts PNG images to the Game Boy's tile format. RGBDS is available for Linux, Windows and MacOS.",-1),A=e("p",null,"Strengths:",-1),x=e("ul",null,[e("li",null,"Very knowledgeable community with a lot of history."),e("li",null,"Built in support for ROM banking."),e("li",null,"Works quite well with BGB for debugging.")],-1),I=e("p",null,"Weaknesses:",-1),D=e("ul",null,[e("li",null,"Provides a limited amount of built-in code and functionality (does not include a large API like GBDK-2020 does).")],-1),R={id:"wla-dx-with-asm",tabindex:"-1"},T=e("a",{class:"header-anchor",href:"#wla-dx-with-asm","aria-hidden":"true"},"#",-1),z={href:"https://github.com/vhelin/wla-dx",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"WLA-DX is also sometimes used when writing in ASM, mostly due to its better struct support than RGBDS.",-1),O={id:"gbdk-2020-with-c",tabindex:"-1"},P=e("a",{class:"header-anchor",href:"#gbdk-2020-with-c","aria-hidden":"true"},"#",-1),K={href:"https://github.com/Zal0/gbdk-2020",target:"_blank",rel:"noopener noreferrer"},q={href:"http://gbdk.sourceforge.net",target:"_blank",rel:"noopener noreferrer"},E=e("p",null,"Strengths:",-1),L=e("ul",null,[e("li",null,"Flexible and extensible."),e("li",null,"Comprehensive API that covers most hardware features."),e("li",null,"Many sample projects and open source games are available that demonstrate how to use the API, hardware, and structure games."),e("li",null,"C source debugging is available with Emulicious.")],-1),N=e("p",null,"Weaknesses:",-1),U=e("ul",null,[e("li",null,"Takes care of some aspects of the hardware without requiring the developer to initiate them (such as OAM DMA during VBLANK), so it's not always obvious to beginners what the hardware is doing behind the scenes, or how to fix them when something goes wrong."),e("li",null,"ROM banking may require more management in code than RGBDS.")],-1),V={id:"zgb-with-c-gbdk-2020",tabindex:"-1"},j=e("a",{class:"header-anchor",href:"#zgb-with-c-gbdk-2020","aria-hidden":"true"},"#",-1),Z={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},H=e("p",null,"ZGB is a small engine for the Game Boy built on top of GBDK-2020 and written in C. Strengths:",-1),F=e("ul",null,[e("li",null,"The basic graphics, sound and event structure are all pre-written, so it’s faster and easier to start writing a game."),e("li",null,"Several open source games built with it are available as examples.")],-1),Y=e("p",null,"Weaknesses:",-1),X=e("ul",null,[e("li",null,"The engine just has the basics and custom code may need to be needed for common game features (such as moving platforms, etc.)."),e("li",null,"Even more of the hardware configuration and processing is taken care of behind the scenes than with GBDK, so less experienced users may have trouble when problems arise.")],-1),J={id:"gb-studio",tabindex:"-1"},Q=e("a",{class:"header-anchor",href:"#gb-studio","aria-hidden":"true"},"#",-1),$={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},ee=n('

    GB Studio is a drag-and-drop game creator for the Game Boy that does not require knowledge of programming languages. Games are built using a graphical interface to script graphics, sound and actions. It is available for Linux, Windows and MacOS.

    Strengths:

    • Very easy for beginners to start building games right away. Everything is built-in and requires minimal knowledge and understanding of the Game Boy hardware.
    • Has been used to create large and extensive projects.
    • Very active community for help and support.

    Weaknesses:

    • It’s games will tend to be slower than both ASM and C.
    • There is a limited set of commands to script with and some artificially smaller restrictions on palettes, sprites, background tiles and other hardware features (due to how GB Studio manages them).
    • Games may be more constrained or require workarounds to do things if they don’t easily fit within the available scripting, graphics and sound tools. (Though it is possible for advanced users to do a “engine eject” and add more functionality using C and ASM.)

    Emulators and debuging tools

    Accurate emulators and debugging tools are tremendously helpful for testing and tracking down problems. The following Game Boy emulators provide excellent accuracy and include a variety of different features.

    ',7),te={href:"http://bgb.bircd.org",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://emulicious.net/",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://marketplace.visualstudio.com/items?itemName=emulicious.emulicious-debugger",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://sameboy.github.io/features/",target:"_blank",rel:"noopener noreferrer"},ie={href:"http://github.com/sinamas/gambatte",target:"_blank",rel:"noopener noreferrer"},se={href:"http://retroarch.com",target:"_blank",rel:"noopener noreferrer"},re={href:"http://tasvideos.org/BizHawk.html",target:"_blank",rel:"noopener noreferrer"},le={href:"http://krikzz.com/store/",target:"_blank",rel:"noopener noreferrer"},he={href:"https://krikzz.com/store/home/47-everdrive-gb.html",target:"_blank",rel:"noopener noreferrer"},de=n('

    Side note : if you are using VBA or VBA-rr, stop using them right now. These emulators are extremely inaccurate, and also contain severe security flaws. I strongly urge you to ditch these emulators and spread the word.

    Summary

    If your question is "What should I use for my game project ?", then you're in the right section. The first question you should ask yourself is what languages you know.

    If you don't know ASM, C or C++

    Consider starting with C and GBDK. This will introduce you to working with the hardware and is an easier starting place.

    ',5),ue={href:"https://daid.github.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},ce=n('

    For C / GBDK users, knowing ASM will help you understand what its API (which is mostly written in ASM) is doing behind the scenes and will make using emulator debuggers easier to understand.

    If you don't wan't to learn a language at all, GB Studio is an alternative to C and ASM.

    If you know C but not ASM

    Consider the goals, scope and time frame of your project. If you'd like to start building right away then C and GBDK will make that easy. You'll also have growing exposure to ASM as time goes on due to working with the hardware and tracking down problems in the debugger.

    On the other hand, if you'd like to expand your programming skill set and have additional time, learning to use ASM and RGBDS will provide you with a lot of knowledge about the Game Boy hardware. Once you know ASM in addition to C, you'll have a lot of flexibility in what tools you use for projects.

    If you know ASM

    RGBDS with ASM is a solid option. You'll be able to get the best performance out of the hardware, and there is an experienced community available to help.

    Another option is to reach out to us, and discuss the matter.

    Tips For Better Code

    ',9),me=e("em",null,"very first thing",-1),ge=e("strong",null,"in all cases",-1),pe={href:"https://gbdev.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://gbdev.io/resources.html",target:"_blank",rel:"noopener noreferrer"},be=n('

    ASM Help

    • Modules
      Separate your game into several "entities" that interact together. Camera, Player, NPCs, Loading zones, etc. This simplifies coding, by allowing you to reason independently on smaller units. This facilitates development and reduces the amount of bugs.
    • Document your functions
      For each function, write a comment saying what it does, what memory it touches, and what registers it affects. This will avoid conflicts, and let you optimize your code by minimizing the amount of registers you save when calling a function.
    • Plan before writing
      You should plan what register is going to be used for what within your functions before starting to write them. Your goal is to minimize the amount of register swapping. There's no general rule, so feel free to drop by and ask us, if you're in doubt.
    • RGBASM -E and RGBLINK -n <symfile>
      When you load ROM.gb or ROM.gbc in BGB, it automatically loads (if it exists) the file ROM.sym in the same folder as the ROM. This adds symbols to the debugger, which - believe me - helps a ton.

    Optimizing For GBDK

    • Global variables
      Use as many global variables as you can; the Game Boy has a lot of RAM compared to other platforms such as the NES, but is slow at using the stack. Thus, minimizing the number of local variables, especially in heavily-called functions, will reduce the time spent manipulating the stack.
    • Optimized code
      Write code as efficient as possible. Sometimes there is a readability tradeoff, so I recommend you get the comment machine gun out and put some everywhere.
    • By default GBDK-2020 (after v4.0.1) will use the SDCC flag --max-allocs-per-node 50000 for an increased optimization pass. You may also choose to use --opt-code-speed (optimize code generation towards fast code, possibly at the expense of codesize) or --opt-code-size (optimize code generation towards compact code, possibly at the expense of codespeed).
    • Inlining
      When performance is important avoid using functions if you can inline them, which skips passing all arguments to the stack, mostly. Macros will be your friends there. If needed you can also use inline ASM.
    • NEVER use recursive functions
    • AVOID printf
      printf clobbers a sizeable chunk of VRAM with unnecessary text tiles. Instead, you should sprintf to a buffer in WRAM, then put that on the screen using a custom font.
    • Geometry funcs
      Avoid the functions that draw geometry on-screen (lines, rectangles, etc.). The Game Boy isn't designed for this kind of drawing method, and you will have a hard time mixing this with, say, background art. Plus, the functions are super slow.
    • const (very important!)
      Declaring a variable that doesn't change as const greatly reduces the amount of ROM, RAM, and CPU used.
      The technical reason behind that is that non-const values, especially arrays, are loaded to RAM from ROM in an extremely inefficient way. This takes up a LOT more ROM, and copies the value(s) to RAM when it's unneeded. (And the GB does not have enough RAM for that to be viable.)
    • Don't use MBC1
      MBC1 is often assumed to be the simplest of all MBCs... but it has a quirk that adds some overhead every time ROM or SRAM bank switches are performed. MBC3 and MBC5 don't have this quirk, and don't add any complexity. Using MBC1 has no real use. (Let's not talk about MBC2, either.)

    Community And Help

    If you want to get help from the community, go:

    ',6),ye={href:"http://efnet.net",target:"_blank",rel:"noopener noreferrer"},we={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://github.com/Zal0/gbdk-2020#discord-servers",target:"_blank",rel:"noopener noreferrer"},ve={href:"http://gbdev.gg8.se/forums",target:"_blank",rel:"noopener noreferrer"};function ke(Be,Ge){const o=s("ExternalLinkIcon");return r(),l("div",null,[d,u,e("p",null,[t("Written by "),e("a",c,[t("ISSOtm"),a(o)]),t(" with help from "),e("a",m,[t("tobiasvl"),a(o)]),t(", some updates by "),e("a",g,[t("bbbbbr"),a(o)]),t(".")]),p,f,e("div",b,[y,w,e("p",null,[t("If you want to program for the GBA, which is much more C-friendly (and C++ and Rust, for that matter) than the GB and GBC, then I advise you to download devkitARM and follow the "),e("a",_,[t("Tonc"),a(o)]),t(" tutorial. Please note that the Game Boy Advance also functions as a Game Boy Color, so if you only have a GBA, you can use it for both GB and GBC development.")])]),v,e("p",null,[t("C will typically be used with the SDCC compiler and GBDK-2020 or ZGB, though it can also be used on its own without a framework or with a different compiler/dev kit (such as "),e("a",k,[t("z88dk"),a(o)]),t(").")]),B,e("h3",G,[S,t(),e("a",M,[t("RGBDS"),a(o)]),t(" with ASM")]),C,A,x,I,D,e("h3",R,[T,t(),e("a",z,[t("WLA-DX"),a(o)]),t(" with ASM")]),W,e("h3",O,[P,t(),e("a",K,[t("GBDK-2020"),a(o)]),t(" with C")]),e("p",null,[t("GBDK-2020 is a development kit and toolchain built around the SDCC C compiler which allows you to write programs in C and build ROMs. It includes an API for interfacing with the Game Boy. GBDK-2020 is a modernized version of the original "),e("a",q,[t("GBDK"),a(o)]),t(". It's available for Linux, Windows and MacOS.")]),E,L,N,U,e("h3",V,[j,t(),e("a",Z,[t("ZGB"),a(o)]),t(" with C & GBDK-2020")]),H,F,Y,X,e("h3",J,[Q,t(),e("a",$,[t("GB Studio"),a(o)])]),ee,e("ul",null,[e("li",null,[e("p",null,[e("a",te,[t("BGB"),a(o)]),t(" has a convenient (ASM) debugger, though its minimal interface can be confusing at first. It is available for Windows only, but runs almost flawlessly with Wine.")])]),e("li",null,[e("p",null,[e("a",oe,[t("Emulicious"),a(o)]),t(" includes powerful tools such as a profiler and source-level debugging for ASM and C via a "),e("a",ae,[t("VS Code debug adapter"),a(o)]),t(". It runs on Linux, Windows, MacOS and any other operating systems that supports Java SE.")])]),e("li",null,[e("p",null,[e("a",ne,[t("Same Boy"),a(o)]),t(" is user friendly and has a wide range of powerful (ASM) debugging features. It runs on Windows and MacOS.")])]),e("li",null,[e("p",null,[e("a",ie,[t("Gambatte"),a(o)]),t(" lacks a debugger and must be compiled from source, but is packaged both in "),e("a",se,[t("RetroArch"),a(o)]),t(" (Linux, Windows and Mac) and "),e("a",re,[t("BizHawk"),a(o)]),t(" (Windows-only).")])]),e("li",null,[e("p",null,[t("Purists prefer to also run their games on hardware, which is possible thanks to flashcarts. My personal recommendation is "),e("a",le,[t("krikzz's carts"),a(o)]),t(", particularly the "),e("a",he,[t("Everdrive GB X5"),a(o)]),t(".")])])]),de,e("p",null,[t(`Once you've grasped C's concepts (most importantly pointers), give ASM a go. The language is simpler than it looks. Even if you don't manage to get working ASM code, it actually helps a lot (especially on such a constrained system) to know what's "under the hood". There is even an `),e("a",ue,[t("online IDE"),a(o)]),t(" to experiment with.")]),ce,e("p",null,[t("The "),me,t(" to do "),ge,t(" is to "),e("a",pe,[t("read the docs"),a(o)]),t(", to grasp how the Game Boy works. In ASM, this is essential; in C, this will let you understand what a given library function does. It will also let you understand what is possible on the Game Boy, and what isn't. (You can always ask, if you have doubts.)")]),e("p",null,[t("I also recommend looking up "),e("a",fe,[t("awesome-gbdev"),a(o)]),t(" for resources and tutorials. There are a lot of helpful articles there, as well as helper tools.")]),be,e("ul",null,[e("li",null,[t("To the historical IRC channel, #gbdev on "),e("a",ye,[t("EFNet"),a(o)]),t(` [if you don't have an IRC client, you can use the "Webchat login" box, just enter a username].`)]),e("li",null,[t("To the more recent "),e("a",we,[t("gbdev Discord server"),a(o)]),t(" or "),e("a",_e,[t("GBDK/ZGB"),a(o)]),t(" specific server.")]),e("li",null,[t("And to the "),e("a",ve,[t("GBDev forums"),a(o)]),t("!")])])])}const Me=i(h,[["render",ke],["__file","tools.html.vue"]]);export{Me as default}; diff --git a/assets/tools.html-e2d74e0f.js b/assets/tools.html-e2d74e0f.js deleted file mode 100644 index 131b764..0000000 --- a/assets/tools.html-e2d74e0f.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as i,r,o as s,c as l,a as e,b as t,d as a,e as n}from"./app-19015fbd.js";const h={},d=e("h1",{id:"choosing-tools-for-game-boy-development",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#choosing-tools-for-game-boy-development","aria-hidden":"true"},"#"),t(" Choosing tools for Game Boy development")],-1),u=e("p",null,"This essay gives an overview of the Game Boy's capabilities, discussing the pros and cons of the available development tools, and providing a few tips to write more efficient code.",-1),c={href:"https://github.com/ISSOtm/",target:"_blank",rel:"noopener noreferrer"},m={href:"https://github.com/tobiasvl",target:"_blank",rel:"noopener noreferrer"},g={href:"https://github.com/bbbbbr",target:"_blank",rel:"noopener noreferrer"},p=e("hr",null,null,-1),f=e("p",null,"In the past few years as retro gaming has grown in popularity, programming for older platforms has also gained traction. A popular platform is the Game Boy, both for its nostalgia and (relative) ease to program for.",-1),b={class:"custom-container warning"},w=e("p",{class:"custom-container-title"},"WARNING",-1),y=e("p",null,"This document only applies to the Game Boy and Game Boy Color. Game Boy Advance programming has little in common with Game Boy programming.",-1),_={href:"https://www.coranac.com/tonc/text/",target:"_blank",rel:"noopener noreferrer"},v=n('

    When someone wants to make their own game, one of the first problems they will encounter is picking the tools they will use. There current main options are:

    • RGBDS (Rednex Game Boy Development System) and the Game Boy's Assembly language (ASM)
    • GBDK-2020 (Game Boy Development Kit) and the C language
    • ZGB (an engine built on GBDK-2020) and the C language
    • GB Studio (a drag-and-drop game creator with scripting)

    The purpose of this document is to provide some insights and help you make the better choice if you're starting a new project. I will also provide some "good practice" tips, both for C and ASM, if you have already made up your mind or are already using one of these.

    Overview

    The original Game Boy, codenamed the DMG, has a 1 MHz CPU [the CPU is actually clocked at 4 MHz, but every instruction takes up a multiple of 4 clocks, so it's often simplified to a 1 MHz CPU]. Given that an instruction takes approximately 2 to 3 cycles, this gives the CPU a capacity of 333,000~500,000 instructions per second. Its LCD boasts 60 fps [it's actually 59.73 fps], which rounds up to between 50,000 and 80,000 instructions per frame. Suddenly not so much, eh? It also has 8 kB of RAM, and 8 kB of video RAM ; a 160x144 px LCD (thus slightly wider than it's tall), 4 colors, and 4-channel audio.

    The Super Game Boy adds a few minor things, such as a customizable screen border, and some crude color. It's also slightly faster than the DMG.

    The Game Boy Color can [if you tell it to] unlock additional functionality, such as more fleshed-out color, a double-speed CPU, twice the video RAM and four times the RAM! (With caveats, obviously.)

    Languages

    The choice of programming language is important and can have a very large effect on a project. It determines how much work is involved, what will be possible, and how fast it will be able to run.

    Assembly (ASM)

    Most games and programs for the Game Boy written in ASM will use RGBDS or WLA-DX.

    Strengths:

    • Not too difficult to learn.
    • Extremely powerful and flexible.
    • When well written it allows for maximum speed and efficiency on the limited resources of the Game Boy hardware.

    Weaknesses:

    • It takes a special kind of work to write optimized ASM code.
    • It's quite verbose and sometimes tedious.
    • Will require more time and learning to get up and running when compared with C.
    • Code may not be easily shared with ports of a game on other platforms.

    C

    ',16),k={href:"https://github.com/z88dk/",target:"_blank",rel:"noopener noreferrer"},B=n('

    Strengths:

    • Allows for getting up and running faster than with ASM, especially when building on top of GBDK-2020 and ZGB.
    • The language abstractions make it relatively easy to implement ideas and algorithms.
    • C source debugging is available through Emulicious with the VSCode debug adapter, making it easier to understand problems if they arise.
    • ASM can be included in projects with C, either standalone or inline for speed critical features.

    Weaknesses:

    • The SDCC C compiler won't always generate code that runs as fast as skilled, hand-optimized assembly. It has matured a lot in the 20 years since the original GBDK, but bugs still turns up on occasion. On a platform with a slow CPU such as the Game Boy this can be a factor.
    • It’s easier to write inefficient code in C without realizing it. The Game Boy's CPU is only capable of performing 8-bit addition or subtraction, or 16-bit addition. Using INT32s is quite taxing on the CPU (it needs to do two consecutive 16-bit adds, and add the carry). See the tips below to avoid such blunders.
    • There is overhead due to C being a stack-oriented language, whereas the Game Boy's CPU is rather built for a register-oriented strategy. This most notably makes passing function arguments a lot slower, although SDCC has some optimizations for this.

    Non-Programming Language option

    Using a GUI instead- If you don’t want to learn a programming language in order to make Game Boy games, then GB Studio is an option. See the GB Studio section for more details.

    Development Platforms

    ',7),G={id:"rgbds-with-asm",tabindex:"-1"},S=e("a",{class:"header-anchor",href:"#rgbds-with-asm","aria-hidden":"true"},"#",-1),M={href:"http://github.com/rednex/rgbds",target:"_blank",rel:"noopener noreferrer"},C=e("p",null,"RGBDS is an actively maintained suite of programs that allow building a ROM using ASM (assembly). It contains three programs that perform different stages of the compilation, as well as a program that converts PNG images to the Game Boy's tile format. RGBDS is available for Linux, Windows and MacOS.",-1),A=e("p",null,"Strengths:",-1),x=e("ul",null,[e("li",null,"Very knowledgeable community with a lot of history."),e("li",null,"Built in support for ROM banking."),e("li",null,"Works quite well with BGB for debugging.")],-1),I=e("p",null,"Weaknesses:",-1),D=e("ul",null,[e("li",null,"Provides a limited amount of built-in code and functionality (does not include a large API like GBDK-2020 does).")],-1),R={id:"wla-dx-with-asm",tabindex:"-1"},T=e("a",{class:"header-anchor",href:"#wla-dx-with-asm","aria-hidden":"true"},"#",-1),z={href:"https://github.com/vhelin/wla-dx",target:"_blank",rel:"noopener noreferrer"},W=e("p",null,"WLA-DX is also sometimes used when writing in ASM, mostly due to its better struct support than RGBDS.",-1),O={id:"gbdk-2020-with-c",tabindex:"-1"},P=e("a",{class:"header-anchor",href:"#gbdk-2020-with-c","aria-hidden":"true"},"#",-1),K={href:"https://github.com/Zal0/gbdk-2020",target:"_blank",rel:"noopener noreferrer"},q={href:"http://gbdk.sourceforge.net",target:"_blank",rel:"noopener noreferrer"},E=e("p",null,"Strengths:",-1),L=e("ul",null,[e("li",null,"Flexible and extensible."),e("li",null,"Comprehensive API that covers most hardware features."),e("li",null,"Many sample projects and open source games are available that demonstrate how to use the API, hardware, and structure games."),e("li",null,"C source debugging is available with Emulicious.")],-1),N=e("p",null,"Weaknesses:",-1),U=e("ul",null,[e("li",null,"Takes care of some aspects of the hardware without requiring the developer to initiate them (such as OAM DMA during VBLANK), so it's not always obvious to beginners what the hardware is doing behind the scenes, or how to fix them when something goes wrong."),e("li",null,"ROM banking may require more management in code than RGBDS.")],-1),V={id:"zgb-with-c-gbdk-2020",tabindex:"-1"},j=e("a",{class:"header-anchor",href:"#zgb-with-c-gbdk-2020","aria-hidden":"true"},"#",-1),Z={href:"https://github.com/Zal0/ZGB/",target:"_blank",rel:"noopener noreferrer"},H=e("p",null,"ZGB is a small engine for the Game Boy built on top of GBDK-2020 and written in C. Strengths:",-1),F=e("ul",null,[e("li",null,"The basic graphics, sound and event structure are all pre-written, so it’s faster and easier to start writing a game."),e("li",null,"Several open source games built with it are available as examples.")],-1),Y=e("p",null,"Weaknesses:",-1),X=e("ul",null,[e("li",null,"The engine just has the basics and custom code may need to be needed for common game features (such as moving platforms, etc.)."),e("li",null,"Even more of the hardware configuration and processing is taken care of behind the scenes than with GBDK, so less experienced users may have trouble when problems arise.")],-1),J={id:"gb-studio",tabindex:"-1"},Q=e("a",{class:"header-anchor",href:"#gb-studio","aria-hidden":"true"},"#",-1),$={href:"https://www.gbstudio.dev/",target:"_blank",rel:"noopener noreferrer"},ee=n('

    GB Studio is a drag-and-drop game creator for the Game Boy that does not require knowledge of programming languages. Games are built using a graphical interface to script graphics, sound and actions. It is available for Linux, Windows and MacOS.

    Strengths:

    • Very easy for beginners to start building games right away. Everything is built-in and requires minimal knowledge and understanding of the Game Boy hardware.
    • Has been used to create large and extensive projects.
    • Very active community for help and support.

    Weaknesses:

    • It’s games will tend to be slower than both ASM and C.
    • There is a limited set of commands to script with and some artificially smaller restrictions on palettes, sprites, background tiles and other hardware features (due to how GB Studio manages them).
    • Games may be more constrained or require workarounds to do things if they don’t easily fit within the available scripting, graphics and sound tools. (Though it is possible for advanced users to do a “engine eject” and add more functionality using C and ASM.)

    Emulators and debuging tools

    Accurate emulators and debugging tools are tremendously helpful for testing and tracking down problems. The following Game Boy emulators provide excellent accuracy and include a variety of different features.

    ',7),te={href:"http://bgb.bircd.org",target:"_blank",rel:"noopener noreferrer"},oe={href:"https://emulicious.net/",target:"_blank",rel:"noopener noreferrer"},ae={href:"https://marketplace.visualstudio.com/items?itemName=emulicious.emulicious-debugger",target:"_blank",rel:"noopener noreferrer"},ne={href:"https://sameboy.github.io/features/",target:"_blank",rel:"noopener noreferrer"},ie={href:"http://github.com/sinamas/gambatte",target:"_blank",rel:"noopener noreferrer"},re={href:"http://retroarch.com",target:"_blank",rel:"noopener noreferrer"},se={href:"http://tasvideos.org/BizHawk.html",target:"_blank",rel:"noopener noreferrer"},le={href:"http://krikzz.com/store/",target:"_blank",rel:"noopener noreferrer"},he={href:"https://krikzz.com/store/home/47-everdrive-gb.html",target:"_blank",rel:"noopener noreferrer"},de=n('

    Side note : if you are using VBA or VBA-rr, stop using them right now. These emulators are extremely inaccurate, and also contain severe security flaws. I strongly urge you to ditch these emulators and spread the word.

    Summary

    If your question is "What should I use for my game project ?", then you're in the right section. The first question you should ask yourself is what languages you know.

    If you don't know ASM, C or C++

    Consider starting with C and GBDK. This will introduce you to working with the hardware and is an easier starting place.

    ',5),ue={href:"https://daid.github.io/rgbds-live/",target:"_blank",rel:"noopener noreferrer"},ce=n('

    For C / GBDK users, knowing ASM will help you understand what its API (which is mostly written in ASM) is doing behind the scenes and will make using emulator debuggers easier to understand.

    If you don't wan't to learn a language at all, GB Studio is an alternative to C and ASM.

    If you know C but not ASM

    Consider the goals, scope and time frame of your project. If you'd like to start building right away then C and GBDK will make that easy. You'll also have growing exposure to ASM as time goes on due to working with the hardware and tracking down problems in the debugger.

    On the other hand, if you'd like to expand your programming skill set and have additional time, learning to use ASM and RGBDS will provide you with a lot of knowledge about the Game Boy hardware. Once you know ASM in addition to C, you'll have a lot of flexibility in what tools you use for projects.

    If you know ASM

    RGBDS with ASM is a solid option. You'll be able to get the best performance out of the hardware, and there is an experienced community available to help.

    Another option is to reach out to us, and discuss the matter.

    Tips For Better Code

    ',9),me=e("em",null,"very first thing",-1),ge=e("strong",null,"in all cases",-1),pe={href:"https://gbdev.io/pandocs/",target:"_blank",rel:"noopener noreferrer"},fe={href:"https://gbdev.io/resources.html",target:"_blank",rel:"noopener noreferrer"},be=n('

    ASM Help

    • Modules
      Separate your game into several "entities" that interact together. Camera, Player, NPCs, Loading zones, etc. This simplifies coding, by allowing you to reason independently on smaller units. This facilitates development and reduces the amount of bugs.
    • Document your functions
      For each function, write a comment saying what it does, what memory it touches, and what registers it affects. This will avoid conflicts, and let you optimize your code by minimizing the amount of registers you save when calling a function.
    • Plan before writing
      You should plan what register is going to be used for what within your functions before starting to write them. Your goal is to minimize the amount of register swapping. There's no general rule, so feel free to drop by and ask us, if you're in doubt.
    • RGBASM -E and RGBLINK -n <symfile>
      When you load ROM.gb or ROM.gbc in BGB, it automatically loads (if it exists) the file ROM.sym in the same folder as the ROM. This adds symbols to the debugger, which - believe me - helps a ton.

    Optimizing For GBDK

    • Global variables
      Use as many global variables as you can; the Game Boy has a lot of RAM compared to other platforms such as the NES, but is slow at using the stack. Thus, minimizing the number of local variables, especially in heavily-called functions, will reduce the time spent manipulating the stack.
    • Optimized code
      Write code as efficient as possible. Sometimes there is a readability tradeoff, so I recommend you get the comment machine gun out and put some everywhere.
    • By default GBDK-2020 (after v4.0.1) will use the SDCC flag --max-allocs-per-node 50000 for an increased optimization pass. You may also choose to use --opt-code-speed (optimize code generation towards fast code, possibly at the expense of codesize) or --opt-code-size (optimize code generation towards compact code, possibly at the expense of codespeed).
    • Inlining
      When performance is important avoid using functions if you can inline them, which skips passing all arguments to the stack, mostly. Macros will be your friends there. If needed you can also use inline ASM.
    • NEVER use recursive functions
    • AVOID printf
      printf clobbers a sizeable chunk of VRAM with unnecessary text tiles. Instead, you should sprintf to a buffer in WRAM, then put that on the screen using a custom font.
    • Geometry funcs
      Avoid the functions that draw geometry on-screen (lines, rectangles, etc.). The Game Boy isn't designed for this kind of drawing method, and you will have a hard time mixing this with, say, background art. Plus, the functions are super slow.
    • const (very important!)
      Declaring a variable that doesn't change as const greatly reduces the amount of ROM, RAM, and CPU used.
      The technical reason behind that is that non-const values, especially arrays, are loaded to RAM from ROM in an extremely inefficient way. This takes up a LOT more ROM, and copies the value(s) to RAM when it's unneeded. (And the GB does not have enough RAM for that to be viable.)
    • Don't use MBC1
      MBC1 is often assumed to be the simplest of all MBCs... but it has a quirk that adds some overhead every time ROM or SRAM bank switches are performed. MBC3 and MBC5 don't have this quirk, and don't add any complexity. Using MBC1 has no real use. (Let's not talk about MBC2, either.)

    Community And Help

    If you want to get help from the community, go:

    ',6),we={href:"http://efnet.net",target:"_blank",rel:"noopener noreferrer"},ye={href:"https://gbdev.io/chat.html",target:"_blank",rel:"noopener noreferrer"},_e={href:"https://github.com/Zal0/gbdk-2020#discord-servers",target:"_blank",rel:"noopener noreferrer"},ve={href:"http://gbdev.gg8.se/forums",target:"_blank",rel:"noopener noreferrer"};function ke(Be,Ge){const o=r("ExternalLinkIcon");return s(),l("div",null,[d,u,e("p",null,[t("Written by "),e("a",c,[t("ISSOtm"),a(o)]),t(" with help from "),e("a",m,[t("tobiasvl"),a(o)]),t(", some updates by "),e("a",g,[t("bbbbbr"),a(o)]),t(".")]),p,f,e("div",b,[w,y,e("p",null,[t("If you want to program for the GBA, which is much more C-friendly (and C++ and Rust, for that matter) than the GB and GBC, then I advise you to download devkitARM and follow the "),e("a",_,[t("Tonc"),a(o)]),t(" tutorial. Please note that the Game Boy Advance also functions as a Game Boy Color, so if you only have a GBA, you can use it for both GB and GBC development.")])]),v,e("p",null,[t("C will typically be used with the SDCC compiler and GBDK-2020 or ZGB, though it can also be used on its own without a framework or with a different compiler/dev kit (such as "),e("a",k,[t("z88dk"),a(o)]),t(").")]),B,e("h3",G,[S,t(),e("a",M,[t("RGBDS"),a(o)]),t(" with ASM")]),C,A,x,I,D,e("h3",R,[T,t(),e("a",z,[t("WLA-DX"),a(o)]),t(" with ASM")]),W,e("h3",O,[P,t(),e("a",K,[t("GBDK-2020"),a(o)]),t(" with C")]),e("p",null,[t("GBDK-2020 is a development kit and toolchain built around the SDCC C compiler which allows you to write programs in C and build ROMs. It includes an API for interfacing with the Game Boy. GBDK-2020 is a modernized version of the original "),e("a",q,[t("GBDK"),a(o)]),t(". It's available for Linux, Windows and MacOS.")]),E,L,N,U,e("h3",V,[j,t(),e("a",Z,[t("ZGB"),a(o)]),t(" with C & GBDK-2020")]),H,F,Y,X,e("h3",J,[Q,t(),e("a",$,[t("GB Studio"),a(o)])]),ee,e("ul",null,[e("li",null,[e("p",null,[e("a",te,[t("BGB"),a(o)]),t(" has a convenient (ASM) debugger, though its minimal interface can be confusing at first. It is available for Windows only, but runs almost flawlessly with Wine.")])]),e("li",null,[e("p",null,[e("a",oe,[t("Emulicious"),a(o)]),t(" includes powerful tools such as a profiler and source-level debugging for ASM and C via a "),e("a",ae,[t("VS Code debug adapter"),a(o)]),t(". It runs on Linux, Windows, MacOS and any other operating systems that supports Java SE.")])]),e("li",null,[e("p",null,[e("a",ne,[t("Same Boy"),a(o)]),t(" is user friendly and has a wide range of powerful (ASM) debugging features. It runs on Windows and MacOS.")])]),e("li",null,[e("p",null,[e("a",ie,[t("Gambatte"),a(o)]),t(" lacks a debugger and must be compiled from source, but is packaged both in "),e("a",re,[t("RetroArch"),a(o)]),t(" (Linux, Windows and Mac) and "),e("a",se,[t("BizHawk"),a(o)]),t(" (Windows-only).")])]),e("li",null,[e("p",null,[t("Purists prefer to also run their games on hardware, which is possible thanks to flashcarts. My personal recommendation is "),e("a",le,[t("krikzz's carts"),a(o)]),t(", particularly the "),e("a",he,[t("Everdrive GB X5"),a(o)]),t(".")])])]),de,e("p",null,[t(`Once you've grasped C's concepts (most importantly pointers), give ASM a go. The language is simpler than it looks. Even if you don't manage to get working ASM code, it actually helps a lot (especially on such a constrained system) to know what's "under the hood". There is even an `),e("a",ue,[t("online IDE"),a(o)]),t(" to experiment with.")]),ce,e("p",null,[t("The "),me,t(" to do "),ge,t(" is to "),e("a",pe,[t("read the docs"),a(o)]),t(", to grasp how the Game Boy works. In ASM, this is essential; in C, this will let you understand what a given library function does. It will also let you understand what is possible on the Game Boy, and what isn't. (You can always ask, if you have doubts.)")]),e("p",null,[t("I also recommend looking up "),e("a",fe,[t("awesome-gbdev"),a(o)]),t(" for resources and tutorials. There are a lot of helpful articles there, as well as helper tools.")]),be,e("ul",null,[e("li",null,[t("To the historical IRC channel, #gbdev on "),e("a",we,[t("EFNet"),a(o)]),t(` [if you don't have an IRC client, you can use the "Webchat login" box, just enter a username].`)]),e("li",null,[t("To the more recent "),e("a",ye,[t("gbdev Discord server"),a(o)]),t(" or "),e("a",_e,[t("GBDK/ZGB"),a(o)]),t(" specific server.")]),e("li",null,[t("And to the "),e("a",ve,[t("GBDev forums"),a(o)]),t("!")])])])}const Me=i(h,[["render",ke],["__file","tools.html.vue"]]);export{Me as default}; diff --git a/chat.html b/chat.html index b3ed495..48a7a63 100644 --- a/chat.html +++ b/chat.html @@ -36,10 +36,10 @@ })(); Community channels | gbdev.io - +

    Community channels

    Join our community on the following channels. Before posting, read the rules and the FAQ (usually in the welcome threads or in the signup).

    - + diff --git a/contributing.html b/contributing.html index 58d552b..a133300 100644 --- a/contributing.html +++ b/contributing.html @@ -36,10 +36,10 @@ })(); Contribution guidelines | gbdev.io - +

    Contribution guidelines

    These base guidelines (if not specified otherwise) apply to every repository under the gbdevopen in new window github organisation. The specific CONTRIBUTING rules of the repository in object also apply. In case of conflicts, those last ones have the priority.

    General

    Issues

    • Provide an example to reproduce the problem in isolation. This should include no private code. The example should be self-runnable. If a snippet is too small, create a repository.
    • Unless the problem is visual, do not include screenshots. They are not helpful.
    • Please be patient. You are probably frustrated by your problem - the maintainers are likely not aware of your workflow.
    • Be grateful for any help you are getting and follow through. The maintainers are likely giving you support for free.
    • Informal conversations are great (e.g. on Discord), but once a problem, feature request etc is outlined, opening an issue formalizing it is the most important thing you can do to help this information flow.
      • Open an issue in the related repository. If you don't know where it's better suited, ask for helpopen in new window.
      • Include context and any information useful to understand the situation. Don't be scared about doing something wrong or not good enough, maintainers will follow up if needed.

    Pull Requests

    • Keep titles and commit messages brief and concise.
    • If the PR is not self-explanatory, add brief description of what has been done and implementation choices (if any).
    • Keep the work in the branch focused and directed at accomplishing only what you are describing in the PR. Ideally a PR should address a single issue (or a set of assimilable ones).
    • PRs require commitment and they are an investment by the (volunteer) maintainers. If you don't have time or abandon the PR after reviews have been left and additional changes are needed, other maintainers may take over to make sure the PR can move forward and the work is not lost.
    • Maintainers may chime in and commit to your feature branch on minor fixes (or suggestions agreed upon).
    • Don't be scared of opening more PRs for the same task, if they can be logically divided. The smaller the changes, the faster they can get reviewed and eventually merged.
    • When adding new features, think about tests and possibly updating documentation. Think about other parts of the project which may be affected by the change.
    • Document trade-offs, risks, implementation and design choices, if any.

    Maintainers workflow

    • Tests and pipelines must pass. If they failed because of something unrelated to the PR (e.g. a link died in the meantime), mention it in the PR thread.
    • If the solution is "sub-optimal" (but still better than the actual implementation) and there are clear possible improvements, mention them and try to collaborate with the contributor, but ultimately prefer merging something sub-optimal than keeping the content stale/inactive. An issue can be opened (or kept opened) to report this situation.

    For disruptive PRs:

    • Wait for 2* maintainers approval
    • Every week of inactivity/staleness, ping maintainers
    • After 5 weeks from last activity, PR is merge-able with only 1 maintainer approval

    For non-disruptive PRs:

    • Wait for 1 maintainer approval and merge it after 5 days
    • If a maintainer wants to put a veto and to make the PR wait for his/her input after the mentioned period, the "veto" label can be used

    *if there are at least 2 active maintainers, otherwise 1.

    References

    1open in new window

    Where can I help?

    Here's a list of the project in most need of help:

    GB ASM Tutorial

    If you're confident in writing assembly, we need contributors in helping us write, proofread and suggest improvements for new lessons in the tutorial.

    Technologies and tools: Assembly, RGBDS, Rust, mdBook.

    Homepageopen in new window - Repositoryopen in new window

    Pan Docs

    The single, most comprehensive technical reference to Game Boy available to the public. Here, you can help adding new content, proof reading, fixing typos, preparing updated versions of figures or port new content from old resources.

    Technologies and tools: Markdown, Rust, Python, mdBook.

    Homepageopen in new window - Repositoryopen in new window - Beginner issuesopen in new window

    RGBDS

    The de-facto standard assembly toolchain for the Nintendo Game Boy & Game Boy Color.

    Technologies and tools: C, C++, Assembly, Rust

    Homepageopen in new window - Repositoryopen in new window - Beginner issuesopen in new window

    Homebrew Hub

    A community-led attempt to collect, archive and save every unofficial game, homebrew, patch, hackrom for Game Boy produced by the community through decades of passionate work.

    Technologies and tools:

    • Frontend: Vue JS 3, Nuxt 3
    • Backend: Django REST

    Homepageopen in new window - Repository (backend)open in new window - Repository (frontend)open in new window

    Homebrew Hub Database

    This is the database of games powering the main Homebrew Hub project. Find a game (we have a lot to add!) and add it with a Pull Request. Or - even better - write scrapers to dump entire sources and add them to our repository!

    Technologies and tools: JSON Schema, Python, Javascript, BeautifulSoup

    Homepageopen in new window - Repositoryopen in new window - Beginner issuesopen in new window

    - + diff --git a/donate.html b/donate.html index 648b1fd..2cb0989 100644 --- a/donate.html +++ b/donate.html @@ -36,10 +36,10 @@ })(); Donations and bounties | gbdev.io - +

    Donations and bounties

    You can donate on our Open Collectiveopen in new window or on GitHub sponsorsopen in new window. You can send a one-time donation of any amount or join the collective as backer, donating monthly.

    WHY OPENCOLLECTIVE

    The gbdevopen in new window organisation is an informal collective of individuals. As such, we are not able to hold any fund in our accounts. Instead, the US based non-profit Open Source Collectiveopen in new window is our fiscal hostopen in new window, providing us the financial and legal infrastructure to receive donations and spend money.

    It's also possible to donate specifically towards a projectopen in new window under our umbrella. We'll do our best to honour this preference.

    Donations are subject to a 10% fee from our Open Collective host (Open Source Collective) plus a variable fee from the payment processor (Wise).

    Money collected on GitHub sponsors are paid out by GitHub to our Open Collective at the end of each month.

    What do we spend the money on?

    We mostly use the money to:

    • Organize events (such as the gbcompo21) and give prizes,
    • Fund maintainers and contributors to our repositories,
    • Put bounties on issues on our repositories,
    • Donate back to some of the packages we use,
    • Pay servers and domains.

    Expenses are tracked hereopen in new window.

    Sponsoring

    If you have a company and you are interested in being highlighted on some of our webpages and channels, we have sponsorship tiers starting at 50$/month. Get in touch at sponsors@gbdev.io to understand if this could be for you. We are interested in hearing how our software is helping your business etc.

    Sponsorships are evaluated on a case-to-case basis and only be accepted if we feel like our core values are compatible and the relationship can last in the long term with beneficial effect for both parties.

    Bounties

    Sometimes, we may assign a bounty to an Issue. Labels such as bounty-25$, bounty-50$, bounty-100$ are used to specify the amount. If you wish to work on a issue with a bounty attached, it's a good measure to comment on the issue asking for it to be assigned to you*.

    If you send a Pull Request fixing that issue and this work gets merged, you will be able to claim this issue.

    Bounties are paid from our OpenCollective: submit an expense mentioning the Issue you worked on and make sure to use your GitHub email (or the one you authored the git commit with) when creating an account on OpenCollective. Wire transfers and PayPal are supported**.

    Details are generally verified in 24-48 hours. Payments are then processed by our Open Collective host a couple of times per week.

    TAX CONSIDERATIONS

    Make sure to check the tax regulations of your country and properly declare the bounties received. We're not tax consultants and we cannot help with that.

    * In case of inactivity we may remove the assignment to you or let someone else who submitted a PR claim the bounty.

    ** Our Open Collective host uses Wise as the payment processor so the countries supported for the bank transfers depends on them.

    - + diff --git a/gbcompo21.html b/gbcompo21.html index 986df32..a5b9d11 100644 --- a/gbcompo21.html +++ b/gbcompo21.html @@ -37,10 +37,10 @@ })(); Game Boy Competition 2021 | gbdev.io - +

    Game Boy Competition 2021

    gbcompo21 was a game jam run from July 1 to October 1 2021 and it was hosted on itch.io/jam/gbcompo21open in new window.

    Create original games, demos, homebrews tools and music for the original Game Boy (Color) and compete for glory (and up to $3000+ in prizes)!

    Results

    Full leaderboards are available here. Top rated entries are playable hereopen in new window while the complete list can be found on Itch.ioopen in new window.

    Games:

    1. Unearthed
    2. Rhythm Land
    3. Shock Lobster
    4. Dango Dash
    5. Rebound
    6. Core Machina
    7. Sushi Nights
    8. MARLA and the Elemental Rings
    9. Porklike GB
    10. GB Corp
    11. Dawn Will Come
    12. <corrib75>
    13. El Dueloroso
    14. Glory Hunter
    15. Renegade rush
    16. Fix My Heart
    17. GBCspelunky

    Winning entry for the Music category: Zilogized

    Winning entry for the Tools category: Brainfox

    Entries

    The complete set of entries is available to browse on Itch.ioopen in new window or can be downloaded as a zip file from GitHubopen in new window.

    Sponsors

    WARNING

    Donations to the prize pool are now closed, no more are being accepted.

    The entire prize pool is community funded. Donate or sponsor the competition through GitHub sponsorsopen in new window.

    Incube 8 Games

    Greenboy GamesCatskull electronicsMega Cat StudiosBitmap Soft1st Press Games

    Donations from Individuals

    Toxaopen in new window, Carles Castilloopen in new window, Dave VanEeopen in new window, Chris Maltbyopen in new window, William Bettridge-Radfordopen in new window, Josh Frisbyopen in new window, Sanquiopen in new window

    Partners

    GB Studio CentralGB Studio RetroBreak


    Community

    Come join us on Discord or others for help getting started, and head over to gbdev.io for useful links & resources!

    We'd love to hear from participants, share your progress on Twitter using the #gbcompo hashtag and join the conversation the on Discord #compo-chat channel!

    Resources

    Here a curated list tools and documentaiton to get you started.

    Prize pool

    The current prize pool is $3000+ and will be split according to this documentopen in new window.

    Entries will compete in 4 separate categories and 4 rankings will be drawn up. Based on these leaderboards, the top entries will be awarded as follows:

    • Best games (80% of the prize pool)
      • The best 5 games will get a prize.
      • The best 3 OSS games will get an additional prize (can overlap)
    • Best homebrew/tool (1) (running on a GB/GBC)
    • Best music cartridge (1)
    • Best demo (1) (demoscene style demos)

    The rankings are decided according to the JUDGING criteria.

    Open Source Bonus

    If you publish your game source code and assets on a public repository (e.g. GitHub) under an open source licenseopen in new window (GPL, MIT, Apache, CC0...) you get 20% more of the prize as a bonus!

    Prize tiers are still work in progress, expect changes. Money prizes are subject to fees and conversions. They may be delivered as gift cards of your choice.

    Rules

    1. Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown or HTML file format (e.g. game manual).

    2. The ROM file will be tested on real hardware (usually a DMG or a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.

    3. GBC features are allowed.

    4. SGB features are allowed. The entries will be evaluated mainly on Game Boy (Color). You can use SGB features, but don't rely on them as main features for your entry.

    5. Teams are allowed (award will be split).

    6. The competition is focused on games, but you are allowed to submit homebrew tools, demoscene style demos and music cartridges. There may be special category prizes for those. There are no preferred themes.

    7. ROM Hacks are not allowed.

    8. NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.

    9. You can submit more than one entry. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).

    10. Judges can submit entries, but they are not eligible for prizes.

    11. Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:

      1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
      2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
      3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
      4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
    12. Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.

    13. As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

    14. Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 15) are eligible for additional prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. See this issueopen in new window for further details.

    15. To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed hereopen in new window is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following istructions.

    16. The entry must be submitted on the itch.io jam page.

    17. Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding.
      Examples of things that are allowed:

      • A brand new game using your own (or any) existing game engine.
      • A remake of your (or someone else's) game for a different platform, but with new code and assets.
      • A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).
      • Using templates, tutorial code as starting point (when they're license allow to do so, e.g. gb-boilerplateopen in new window)
      • Asset packs for art and music are ok if the licensing permits. Be sure to make note of what is being reused and under what terms. Use of pre-made assets (vs original ones) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).

      Examples of things that are not allowed:

      • A project you've been working on for months.
      • An update/patch for a game you already released publicly.
    18. The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).

    19. Multiple submissions are allowed.

    20. If your submission contains text that isn't available in English, some judges might not be able to read that text, and they will judge accordingly.

    Judging

    Judges will evaluate submissions using the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?

    Criteria applicability:

    • Games are ranked according to all the listed criteria
    • demos on 2,3,4,5
    • Music entries on 5
    • Homebrew/tools entries on 2 and 1 (with gameplay being UX)

    The leaderboards are computed by averaging the "Overall" score.

    FAQ

    Something not clear? Open an issue or join the discussion on Discord.

    Credits

    Special thanks to:

    Full results

    Music

    Winner: Zilogized by Kabcorp

    Tools

    Winner: BrainFox by Yprit

    Overall

    Sorted by "Overall" score, only the shortlisted entries were ranked by judges.

    NameGameplayTechnicalOriginalityGraphicsAudioOverall
    Unearthed4.293.864.864.433.294.15
    Rhythm Land3.713.714.143.864.574.0
    Shock Lobster4.04.294.713.713.143.97
    Dango Dash3.863.293.864.04.573.92
    Rebound4.03.863.573.714.293.89
    Core Machina3.143.434.04.574.143.86
    Sushi Nights3.863.864.03.713.713.83
    MARLA and the Elemental Rings3.293.863.434.03.863.69
    Porklike GB4.04.03.143.573.713.68
    GB Corp.3.143.864.573.143.293.6
    Dawn Will Come2.713.144.294.293.433.57
    <corrib75>3.713.863.143.713.293.54
    El Dueloroso3.293.573.863.03.293.4
    Glory Hunters3.433.143.433.573.433.4
    Renegade rush3.573.573.293.03.293.34
    Fix My Heart3.712.863.572.712.713.11
    GBCspelunky3.03.712.433.712.573.08

    Gameplay

    NameGameplay
    Unearthed4.29
    Rebound4.0
    Porklike GB4.0
    Shock Lobster4.0
    Dango Dash3.86
    Sushi Nights3.86
    Rhythm Land3.71
    <corrib75>3.71
    Fix My Heart3.71
    Renegade rush3.57
    Glory Hunters3.43
    MARLA and the Elemental Rings3.29
    El Dueloroso3.29
    Core Machina3.14
    GB Corp.3.14
    GBCspelunky3.0
    Dawn Will Come2.71

    Technical

    NameTechnical
    Shock Lobster4.29
    Porklike GB4.0
    Sushi Nights3.86
    <corrib75>3.86
    GB Corp.3.86
    MARLA and the Elemental Rings3.86
    Unearthed3.86
    Rebound3.86
    Rhythm Land3.71
    GBCspelunky3.71
    El Dueloroso3.57
    Renegade rush3.57
    Core Machina3.43
    Dango Dash3.29
    Dawn Will Come3.14
    Glory Hunters3.14
    Fix My Heart2.86

    Originality

    NameOriginality
    Unearthed4.86
    Shock Lobster4.71
    GB Corp.4.57
    Dawn Will Come4.29
    Rhythm Land4.14
    Core Machina4.0
    Sushi Nights4.0
    Dango Dash3.86
    El Dueloroso3.86
    Rebound3.57
    Fix My Heart3.57
    MARLA and the Elemental Rings3.43
    Glory Hunters3.43
    Renegade rush3.29
    Porklike GB3.14
    <corrib75>3.14
    GBCspelunky2.43

    Graphics

    NameGraphics
    Core Machina4.57
    Unearthed4.43
    Dawn Will Come4.29
    Dango Dash4.0
    MARLA and the Elemental Rings4.0
    Rhythm Land3.86
    <corrib75>3.71
    GBCspelunky3.71
    Rebound3.71
    Shock Lobster3.71
    Sushi Nights3.71
    Glory Hunters3.57
    Porklike GB3.57
    GB Corp.3.14
    El Dueloroso3.0
    Renegade rush3.0
    Fix My Heart2.71

    Audio

    NameAudio
    Dango Dash4.57
    Rhythm Land4.57
    Rebound4.29
    Core Machina4.14
    MARLA and the Elemental Rings3.86
    Porklike GB3.71
    Sushi Nights3.71
    Glory Hunters3.43
    Dawn Will Come3.43
    El Dueloroso3.29
    Renegade rush3.29
    Unearthed3.29
    <corrib75>3.29
    GB Corp.3.29
    Shock Lobster3.14
    Fix My Heart2.71
    GBCspelunky2.57
    - + diff --git a/gbcompo23.html b/gbcompo23.html index 399375a..41bb7a9 100644 --- a/gbcompo23.html +++ b/gbcompo23.html @@ -37,10 +37,10 @@ })(); Game Boy Competition 2023 | gbdev.io - +

    Game Boy Competition 2023

    Game Boy Competition 2023

    Join us for an epic game development event celebrating the classics! Show off your creativity and skills by crafting original games, demos, homebrew tools or music specifically designed for the legendary Game Boy. Get ready to battle it out for fame, honor, and an incredible array of prizes that await the best entries.

    The jam is hosted on Itch.ioopen in new window. It will run from June 15th to September 15, 2023.

    Theme: You are the monster.

    Prizes and Categories

    The total prize pool of will be split according to this documentopen in new window. Anybody can contribute by donatingopen in new window.

    An entry can compete in one and only one of the following leaderboards:

    The rankings are decided according to the judging criteria.

    Community

    Come join us on Discord for help getting started (or find a team), and head over to gbdev.io for a curated list of links and development resources!

    We'd love to hear from participants, share your progress using the #gbcompo23 hashtag and join the conversation on the Discord #gbcompo23 channel!

    We're also on Mastodonopen in new window.

    Resources

    Here is a curated list tools and documentation to get you started.

    Sponsors

    Interested in sponsoring? Shoot us a DMopen in new window.

    Rules

    Prizes and Judging

    1. The submitted entry must implement / interpret the jam theme (applies to Game category only).
    2. Multiple submissions are allowed from the same person or team. They will be rated separately, but each person or team may only accept prizes on behalf of a single entry (e.g., you can't win both the 1st and 2nd place prize).
    3. Judges can submit entries, but the entries won't be eligible for prizes. Judges won't score the entries they submitted.
    4. Source code is optional, but very much appreciated. Entries submitted with source code (public repositories on GitHub/GitLab/... are accepted) and with an open source license (See rule 5) are eligible for additional prizes. Make sure to fill the "Open Source repository" field with a valid and public repository when submitting on itch.io. It is NOT necessary for the source to be available during the competition period. Repositories/sources just need to be public from the time the event ends. See this issueopen in new window for further details.
    5. To be eligible for the OSS bonus, the code must be licensed under an "Open Source" license (any of the "Free" license listed hereopen in new window is accepted). Assets can be licensed under any of the CC licenses. Obfuscated code, non-reproducible builds, intentionally making the source code hard to read/re-use will exclude the entry form the OSS leaderboards. This is at discretion of the hosts and judges. We must be able to read the code and compile it into a working ROM, running a script or following instructions.
    6. If your submission contains text that isn't available in English, some judges might not be able to read that, and they will judge accordingly.
    7. Shipment of physical prizes may not be available to all countries, they are subject to shipping ability of the prize donors.

    Hardware Criteria

    1. Final entry "deliverable" must consist of a GB or GBC ROM file. You can also attach descriptive documents in TXT, Markdown, PDF or HTML file format (e.g. game manual).
    2. The ROM file will be tested on real hardware (primarily a GBC) and on the BGB emulator. In case of different results, the hardware test will be the trusted one.
    3. GBC features are allowed, and entries may be GBC only (GBC only should be indicated in game for non-GBC hardware or on the entry's page).
    4. SGB features are allowed. The entries will be evaluated mainly on Game Boy Color. You can use SGB features, but don't rely on them as main features for your entry.
    5. Only some official MBC chips (MBC1, MBC2, MBC3 and MBC5, as well as no MBC at all) are allowed. The only exceptions are:
      1. While Nintendo only manufactured very specific MBC+ROM combinations, we will allow any power-of-two ROM size between 32 KiB and the maximum for the chosen chip. (This is simply a convenience feature, as any ROM image can be extended to fit a larger ROM chip by appending copies of itself.)
      2. The ROM+RAM combination (i.e., without an MBC, up to 32 KiB ROM and 8 KiB SRAM), with or without battery, will be accepted for compatibility, as many people have simple flash carts that do have SRAM but don't have an MBC. (This can be trivially emulated by any MBC1, MBC3 or MBC5 configuration.)
      3. The variants MBC30 and MBC1M are accepted, as they have been used in licensed games.
      4. Some official MBCs added extra components to the cart: MBC3/MBC30 carts could have an RTC, and MBC5 carts could have rumble. These combinations, and only these combinations, will be accepted. In particular, this means it's impossible to have RTC and rumble in the same cart.
    6. Entries cannot rely on extra hardware or add-on devices, they must be playable without a specific setup.
    7. As long as you produce a GB or GBC ROM file that runs on GB/GBC, any tool to develop the entry is allowed. This includes RGBDS (ASM), GBDK (C), ZGB (C), GB Studio, ...

    General Criteria

    1. Teams are allowed (award will be split).

    2. ROM Hacks are not allowed.

    3. NSFW content is not allowed. Please keep it safe for work and avoid anything overly edgy or distasteful.

    4. The entry must be submitted on the itch.io jam page.

    5. Your work must be new and original. You cannot enter with something you were already working on before the start of the jam. The majority of work should be done during the jam. If in doubt, please ask us before proceeding.

      Examples of things that are allowed:

      • A brand new game using your own (or any) existing game engine.
      • A remake of your (or someone else's) game for a different platform, but with new code and assets.
      • A brand new game you barely started (e.g. you only made a title screen or a mockup of the gameplay).
      • Using templates, tutorial code as starting point (when they're license allow to do so, e.g. gb-boilerplateopen in new window)
      • Asset packs for art and music and covers of other music are allowed if the licensing permits. Be sure to make note of what is being reused or re-interpreted and under what terms. Use of pre-made assets and content (vs wholly original) may be factored in when judges assess points for relevant criteria (e.g. graphics, audio).

      Examples of things that are not allowed:

      • A project you've been working on for months.
      • An update/patch for a game you already released publicly.
    6. The submission must be available for free for the public (and not only the judges). Submission will be published and kept online for free on the competition website, while you are free to keep working on it (and eventually charge for it/make commercial usage).

    7. It is allowed to submit an entry to multiple events.

    Judging

    A team of (~10) judges has been selected before the start of the competition.

    Every judge will be asked to compile an unranked shortlist of their favourite entries. Once the shortlists are ready from all the judges, the top 15 most selected entries will be evaluated by the judges on the following criteria:

    1. Gameplay - How entertaining are the gameplay mechanics? How fun is the game?
    2. Technical - How innovative is it from a technical perspective? Does it push the hardware to the limit?
    3. Originality - How refreshing is it from a non-technical perspective? Does it have a unique design / mechanics?
    4. Graphics - How impressive are the art, animation and visual effects?
    5. Audio - How good are the music and sound effects?
    6. Theme - How was the theme implemented in the gameplay, the mechanics and/or the story?

    Applicability may vary depending on the category of the entry (e.g. a "Music" ROM may be evaluated only on 5)-

    The final leaderboard is computed by averaging the "Overall" score.

    WARNING

    Judges are volunteers. Those details can change without prior notice, as the judging process is long and involves hundreds of entries. Detailed criteria leaderboards will be provided only for entries in the final shortlist.

    Acknowledgements

    Special thanks to everyone who helped organising and running this event:

    Donators: Anonymous Donator

    Partners: gbdev.io, LaroldsJubilantJunkyard, RetroBreak, GB Studio Central

    Organisers: avivace, Tronimal, duodreamer, bbbbbr, ISSOtm, RetroBreak, LaroldsJubilantJunkyard, ProximitySound, Hacktix

    Judges: avivace, ISSOtm, Duo, Tronimal, Ferrante Crafts, NickWestwood, Veund, Toxa

    Past editions

    Results

    Music

    1. 8bit Sunset (GameBoy Music) -Kabcorp
    2. Gb Compo 23 - Music Cart - Tune In!- beatscribe
    3. Monkeys on Mars - Chavez.funktion
    4. The Infernodome - Original GB SongROM! - EmperorJub , No time for art sorry (Music Cart) -incognitio, Re: Cycle - sloopygoop

    Demoscene

    1. Did Somebody Say Demo? - VL2MSTUDIO
    2. DDDDDEEMO(N) - Lillie_chippie

    Tools

    1. Monster Orc-arina - Pearacidic
    2. Dungeon Master - joaobapt
    3. WeekPlanner- CreativaGS
    4. Iron Cor - Stainless - Elvies, Nyan note - Arky750, witch sound tracker - Arky750, SGB SOU_TRN demo -cloudscomputing

    Games

    Overall

    #NameOverallGameplayTechnicalOriginalityGraphicsAudioTheme
    1Hermano † §4.04.174.03.54.333.834.17
    2Feed IT Souls †3.924.173.53.833.833.674.5
    3Enceladus †3.753.53.03.833.673.674.83
    4The Host †3.583.333.03.333.174.04.67
    5NUNYA †3.583.333.03.174.333.674.0
    6Ghost of the Arcade3.423.333.53.333.673.333.33
    7Kaiju Kai Kai3.333.02.673.53.52.834.5
    8Chantey (Prologue)3.252.833.03.673.834.51.67
    9Slime Trials §3.063.833.173.672.332.832.5
    10Hidden Gems3.064.03.04.52.673.01.17
    11Abducted §2.942.833.173.833.831.172.83
    12Slayer the Hawk2.862.673.54.172.671.52.67
    13EXTERMINATOR2.832.672.673.173.02.832.67
    14Imperium Strike Force2.693.172.832.333.172.672.0
    15Lightseeker2.672.172.173.04.03.171.5

    Tiebreaks (4-5, 9-10) were explicitly resolved by judges for this leaderboard.

    Entries marked with † are awarded the "Best Games" prizes and ones with § get the "Best Open Source Games".

    Gameplay

    #NameScore
    1Feed IT Souls4.17
    2Hermano4.17
    3Hidden Gems4.0
    4Slime Trials3.83
    5Enceladus3.5
    6Ghost of the Arcade3.33
    7NUNYA3.33
    8The Host3.33
    9Imperium Strike Force3.17
    10Kaiju Kai Kai3.0
    11Abducted2.83
    12Chantey (Prologue)2.83
    13EXTERMINATOR2.67
    14Slayer the Hawk2.67
    15Lightseeker2.17

    Technical

    #NameScore
    1Hermano4.0
    2Feed IT Souls3.5
    3Ghost of the Arcade3.5
    4Slayer the Hawk3.5
    5Slime Trials3.17
    6Abducted3.17
    7Enceladus3.0
    8NUNYA3.0
    9The Host3.0
    10Hidden Gems3.0
    11Chantey (Prologue)3.0
    12Imperium Strike Force2.83
    13Kaiju Kai Kai2.67
    14EXTERMINATOR2.67
    15Lightseeker2.17

    Originality

    #NameScore
    1Hidden Gems4.5
    2Slayer the Hawk4.17
    3Enceladus3.83
    4Feed IT Souls3.83
    5Abducted3.83
    6Slime Trials3.67
    7Chantey (Prologue)3.67
    8Hermano3.5
    9Kaiju Kai Kai3.5
    10Ghost of the Arcade3.33
    11The Host3.33
    12NUNYA3.17
    13EXTERMINATOR3.17
    14Lightseeker3.0
    15Imperium Strike Force2.33

    Graphics

    #NameScore
    1Hermano4.33
    2NUNYA4.33
    3Lightseeker4.0
    4Feed IT Souls3.83
    5Abducted3.83
    6Chantey (Prologue)3.83
    7Enceladus3.67
    8Ghost of the Arcade3.67
    9Kaiju Kai Kai3.5
    10The Host3.17
    11Imperium Strike Force3.17
    12EXTERMINATOR3.0
    13Hidden Gems2.67
    14Slayer the Hawk2.67
    15Slime Trials2.33

    Audio Ranking

    #NameScore
    1Chantey (Prologue)4.5
    2The Host4.0
    3Hermano3.83
    4Enceladus3.67
    5Feed IT Souls3.67
    6NUNYA3.67
    7Ghost of the Arcade3.33
    8Lightseeker3.17
    9Hidden Gems3.0
    10Slime Trials2.83
    11Kaiju Kai Kai2.83
    12EXTERMINATOR2.83
    13Imperium Strike Force2.67
    14Slayer the Hawk1.5
    15Abducted1.17

    Theme

    #NameScore
    1Enceladus4.83
    2The Host4.67
    3Feed IT Souls4.5
    4Kaiju Kai Kai4.5
    5Hermano4.17
    6NUNYA4.0
    7Ghost of the Arcade3.33
    8Abducted2.83
    9EXTERMINATOR2.67
    10Slayer the Hawk2.67
    11Slime Trials2.5
    12Imperium Strike Force2.0
    13Chantey (Prologue)1.67
    14Lightseeker1.5
    15Hidden Gems1.17
    - + diff --git a/guides/asmstyle.html b/guides/asmstyle.html index c954da0..6a0a416 100644 --- a/guides/asmstyle.html +++ b/guides/asmstyle.html @@ -36,10 +36,10 @@ })(); Game Boy ASM style guide | gbdev.io - +

    Game Boy ASM style guide

    Written by ISSOtmopen in new window


    This style guide aims to formalize a style that most Game Boy ASM programmers agree on, and provide a good baseline for new programmers just starting in this field. (If that's you, welcome! 😄)

    To quote the Linux kernel style guideopen in new window:

    Coding style is very personal, and I won't force my views on anybody, but this is what goes for anything that I have to be able to maintain, and I'd prefer it for most other things too. Please at least consider the points made here.

    Many people follow alternate style guides, and that's fine; but if you're starting to code in ASM, a clean style goes a long way to keep your code organized. Again: you don't have to do everything listed here, but please at least consider the reasons behind each bullet point.

    Oh, by the way, you're free to contribute to this documentopen in new window and/or chat with us about itopen in new window!

    Naming

    RGBASM accepts a lot of symbol namesopen in new window:

    Symbol names can contain letters, numbers, underscores ‘_’, hashes ‘#’ and at signs ‘@’. However, they must begin with either a letter, or an underscore.

    However, naming conventions make code easier to read, since they help convey the different semantics between each symbol's name.

    • Labels use PascalCase: DrawNPCs, GetOffsetFromCamera.

    • Labels in RAM (VRAM, SRAM, WRAM, HRAM; you shouldn't be using Echo RAM or OAM) use the same convention but are prefixed with the initial of the RAM they're in, in lowercase: wCameraOffsetBuffer, hVBlankFlag, vTilesetTiles, sSaveFileChecksum. Rationale: to know in which memory type the label is; this is important because VRAM and SRAM have special access precautions and HRAM can (should (must)) be accessed using the ldh instruction.

    • Local labels use camelCase, regardless of memory type: .waitVRAM, wPlayer.xCoord.

    • Macro names use snake_case: wait_vram, end_struct.

    • Constants use CAPS_SNAKE: NB_NPCS, OVERWORLD_STATE_LOAD_MAP.

      Exception: constants that are used like labels should follow the label naming conventions. For example, see hardware.incopen in new window's rXXX constants.

    Best practices

    • Avoid hardcoding things. This means:

    • Allocate space for your variables using labelsopen in new window + ds & coopen in new window instead of equopen in new window. This has several benefits:

      • Removing, adding, or changing the size of a variable that isn't the last one doesn't require updating every variable after it.
      • The size of each variable is obvious (ds 4) instead of having to be calculated from the addresses.
      • equ allocation is equivalent to hardcoding section addresses (see above), whereas labels are placed automatically by RGBLINK.
      • Labels support BANK()open in new window and many cool other features!
      • Labels are output in map and symopen in new window files.
    • If a file gets too big, you should split it. Files too large are harder to read and navigate. However, the splitting should stay coherent and consistent; having to jump around files constantly is equally as hard to read and navigate.

    • Unless you're making a 32k ROMopen in new window, put things in ROMXopen in new window by default. ROM0 space is precious, and can deplete quickly; and when you run out, it's difficult to move things to ROMX.

      However, if you have code in ROM bank A refer to code or data in ROM bank B, then either should probably be moved to ROM0, or both be placed in the same bank (options for that are mentioned further above). farcallopen in new window is a good way to make your code really spaghettiopen in new window.

    • Don't clear RAM at init! Good debugging emulators will warn you when you're reading uninitialized RAM (BGBopen in new window has one in the option's Exceptions tab, for example), which will let you know that you forgot to initialize a variable. Clearing RAM does not fix most of these bugs, but silences the helpful warnings.

      Also, a lot of the time, variables need to get initialized to values other than 0, so clearing RAM is actually counter-productive in these cases.

    Recommendations

    The difference between these and the "best practices" above is that these are more subjective, but they're still worth talking about here.

    • Historically, RGBDS has required label definitions to begin at "column 1" (i.e. no whitespace before them on their line). However, later versions (with full support added in 0.5.0) allow indenting labelsopen in new window, for example to make loops stand out like in higher-level languages. However, a lot of people don't do thisopen in new window, so it's up to you.

    • Please use the .asm (or .s) file extensions, not .z80. The GB CPU isn't a Z80, so syntax highlighters get it mostly right, but not quite. And it helps spreading the false idea that the GB CPU is a Z80. 😢

    • Compressing data is useful for several reasons; however, it's not necessary in a lot of cases nowadays, so you may want to only look at it after more high-priority aspects.

    • Avoid abusing macros. Macros tend to make code opaque and hard to read for people trying to help you, in addition to having side effects and sometimes leading to very inefficient code.

    • Never let the hardware draw a corrupted frame even if it's just one frame. If it's noticeable by squinting a bit, it must go.

    • Makefiles are baeopen in new window; they speed up build time by not re-processing what hasn't changed, and they can automate a lot of tedium. Writing a good Makefile can be quite daunting, but gb-boilerplateopen in new window and gb-starter-kitopen in new window can help you get started faster.

    - + diff --git a/guides/deadcscroll.html b/guides/deadcscroll.html index ed90606..b847c70 100644 --- a/guides/deadcscroll.html +++ b/guides/deadcscroll.html @@ -36,7 +36,7 @@ })(); Dead C Scroll | gbdev.io - +

    Dead C Scroll

    Written by Bob.


    An assembly tutorial for Game Boy showing how the scroll registers can be exploited to create some nice and interesting effects.

    Files related to this tutorial can be found hereopen in new window.

    Introducing the registers

    SCY ($FF42)/SCX ($FF43)

    The SCY/SCX registers have a simple purpose: specify the coordinate of the screen's top-left pixel (or view, if you prefer) somewhere on the 256x256 pixel background map. This is really handy for certain kinds of games like platformers or top-down racing games (though there are LOTS of other kinds of games that benefit from this) where the view is the 'camera' and its position is set once per frame.

    When you don't require scrolling, and when your cart boots, SCY/SCX is typically set to 0,0. When a screen is displayed, it appears normally even though you only set the values once. This is because as the screen draws, the PPU automatically adds the value in LY ($FF44) to the value in SCY in order to know what row of pixels to draw.

    SCY value (set once)
    @@ -176,6 +176,6 @@
       pop af
       reti
     

    Notice that we can take advantage of the fact that there is only 2 bytes per line. We can use LY directly and quickly turn it into pointer. (Thanks to rondnelson99 for pointing this out!)

    Use the fill buffer

    And there you have it. An automatic and stable way to take advantage of the HBlank to do whatever your imagination wants to do!

    All you need to do is set the fill buffer while the draw buffer is being displayed (you have an entire frame's worth of time to do this) and the system does the rest!

    Effects

    X (Horizontal) Sine

    This effect uses a sine table to shift each line in a pleasant way. There are 3 states to this effect:

    • The image is stable and a progression line moves up the screen starting each line on its way
    • The table cycles a few times
    • The image stability is restored with the progression line moving up the screen

    The values in the table can dramatically change the effect. For example, if the sine cycle was short enough, you could simulate a smoke effect (for example). Try it out!

    Also, you could create a 'glitch' effect during a cut-scene, perhaps in a sci-fi game to simulate a slightly dirty transmission.

    X Sine

    Y (Vertical) Sine

    This effect is structured very similar to X Sine, in that there is a table of sine values driven by 3 states. The only difference is that SCY is changed instead of SCX.

    This is a really good way to simulate water reflections.

    Y Sine

    X and Y Sine

    This is simply a combination of the X Sine and Y Sine effects so you can see how different it looks compared to just the X or Y changing.

    Instead of a full-screen image like this tutorial uses, imagine if you had a repeating image in VRAM (bigger than the screen) that looked like water ripples. This would move just like water!

    XY Sine

    Smear On

    This is like a flood fill effect used as an appearance transition. It's quite simple in that it repeats the lines to achieve the 'smear' effect and is perhaps more interesting than a fade in.

    The specific image used in the tutorial is light along the bottom so it looks better if the screen was already light before the effect starts. You would change this to suit your image.

    Smear On

    Smear Off

    This is a disappearance transition and the reverse of Smear On. Due to the specific image that was used (i.e. it is light along the bottom), it looks better in this tutorial to have the effect reveal a light screen instead of dark. Again, you would change this to suit your image.

    Smear Off

    Roll On

    This effect simulates an image unrolling onto the screen. This might be useful for fantasy RPGs to transition to a map screen or perhaps a message written on a scroll. The image unrolls over a dark screen because the top of the image is mostly dark so it looks better to keep it dark than the contrast of using a light screen.

    Roll On

    Roll Off

    This effect simulates an image rolling off screen. This might be useful for fantasy RPGs to transition away from a map or scroll screen. This reveals a dark screen because the first thing you see in the roll is dark (because that's what's in VRAM below the screen). Keeping it dark made the transition more seamless.

    Roll Off

    The roll effects look complicated but the implementation is probably one of the simpler ones. The key to make this look good is the values in the table. The roll size is 32 pixels, but you can change this to whatever size you want, provided the table values support it. This SpecBas demoopen in new window was used as a reference to obtain those values.

    How to build

    A GNU makefile is included. You will have to tailor it for your development environment but it builds cleanly with RGBDSopen in new window 0.4.2. The only dependency is hardware.incopen in new window. All of the effects are shown hereopen in new window so you don't have to build first to see them.

    Notes about the code

    To reduce dependencies, everything is in one .asm file. It's structured in a logical way and there are comments where applicable.

    The effects are called "parts" by the code and each part has an Init and Process routine. The sequence is controlled by a table of Init pointers and driven by the ProcessPartTransition routine. Each Init is responsible for setting up the data for the effect (part) and to set the Process function pointer via the SetProcessFunc macro. When the effect is done, the Process routine calls the SetChangePartFlag to tell the tutorial driver to move to the next part.

    There are non-effect parts present to get the effect sequence looking good when the parts are played one after the other. These are "delay" parts of various flavors:

    • ShowDelay: this shows the screen normally for a few seconds
    • LightDelay: this shows a light-colored blank screen for a few seconds
    • DarkDelay: this shows a dark-colored blank screen for a few seconds

    The Delay parts share code because they're only present to make the ROM look nice, but the effects parts were developed in a way to be isolated from one another. This was done to make extraction easier. Because of this, you will see similar code present across several parts, for example, the various Sine effects.

    One quirk you might notice when looking at VRAM is that the tile map is placed at 0,4 instead of 0,0. This was done to get the roll/unroll to handle the top of the screen correctly. The effects look best when they smoothly (dis)appear off-screen and if the image was placed at 0,0, the code to handle that would be distracting to how to implement the core of the effect.

    Another topic worth mentioning is the row of light tiles that are under the image in VRAM. This was necessary to allow LightDelay to exist. Those light tiles don't have to be right under the image, that's just where it was placed for this tutorial. It could be moved well out of the way so it doesn't affect the effects that show that part of VRAM (Y Sine, Roll On, Roll Off).

    If you run the ROM in BGBopen in new window and have the Debug Messages window open, you will see the various parts announce themselves when they are initialized.

    Exercises for the reader

    You can do more things than just change the scroll registers. For example, you can change the palette. Can you do this to make the roll/unroll effect look better? Here's an example of scroll register and palette changesopen in new window.

    This appearance effectopen in new window from Sword of Sodan (Amiga) is really cool! (And you might recognize one of the opening effects if you scrub to the beginning.)

    Another raster effect you could do is a 'twist' like the one in the Wired demoopen in new window.

    You can use this system to make a racing game similar to F-1 World Grand Prix IIopen in new window or Wacky Racesopen in new window. How might you achieve this?

    PRs are welcome!

    Other effects can be done, such as flipping the entire image about the X axis to look like its tumbling. What other effects can you create?

    Acknowledgements

    Thanks go to Baŝto for use of the Dead Boyopen in new window image and ISSOtmopen in new window for peer review!

    License

    This was released for educational purposes and so is placed in the Public Domain. See LICENSEopen in new window for more details.

    - + diff --git a/guides/dma_hijacking.html b/guides/dma_hijacking.html index 6e2438a..6454fd1 100644 --- a/guides/dma_hijacking.html +++ b/guides/dma_hijacking.html @@ -36,7 +36,7 @@ })(); DMA Hijacking | gbdev.io - +

    DMA Hijacking

    Written by ISSOtmopen in new window.

    TARGET AUDIENCE

    Unlike most resources here, this guide is not very useful to developers or even ROM hackers, but rather to glitch-hunters and exploit developers.


    What is it?

    OAM DMA hijacking is a simple technique that allows you to run custom code in most GB/SGB/CGB games, provided you have an ACE exploit.

    One would be quick to point out that if you have an ACE exploit, you can already execute custom code. So then, what is the point? It's that code ran through DMA Hijacking will be run on every game frame (for most games, at least).

    How is it done?

    If you are familiar enough with OAMopen in new window, you may know about a feature called OAM DMA.

    OAM DMAopen in new window is a convenient feature that allows quickly updating the on-screen "objects"open in new window (often known as "sprites") quickly—which is especially useful since it typically needs to occur on every frame. However, using OAM DMA requires a small routine to be copied to HRAM and then run from there.

    Interestingly, most games only copy the routine when starting up, and then execute it on every subsequent frame. But, if we modified that routine while the game is running, then the game will happily run the customized routine!

    Patching the code

    Here is the standard routine, given by Nintendo in the GB programming manual (using RGBASM syntaxopen in new window and a symbol from hardware.incopen in new window):

        ld a, HIGH(OAMBuffer)
    @@ -99,6 +99,6 @@
         ld a, HIGH(OAMBuffer)
         ret
     



     
     

    However, if the OAM buffer address passed to the function (in a) is not static, push af and pop af will have to be used instead of ld a, HIGH(OAMBuffer).

    - + diff --git a/guides/lyc_timing.html b/guides/lyc_timing.html index c3afaba..e7f79e8 100644 --- a/guides/lyc_timing.html +++ b/guides/lyc_timing.html @@ -36,7 +36,7 @@ })(); The Timing of LYC STAT Handlers | gbdev.io - +

    The Timing of LYC STAT Handlers

    Written by Ron Nelsonopen in new window and ISSOtmopen in new window


    Raster effects are probably the greatest assets that retro game consoles have. The fact that the PPU generates the image right as it is displayed allows many special effects to be created by modifying the rendering parameters while the image is being drawn. Here is an example:

    Example of raster effect

    However, unlike some consoles like the SNES, the Game Boy contains no hardware dedicated to raster effects, so the task falls squarely on the CPU. This causes raster FX code to interact with the rest of the program in complex ways, particularly when it comes to accessing VRAMopen in new window.

    In this article, we will explore different techniques for handling raster effects, and discuss their pros and cons with the help of some diagrams.

    PRIOR KNOWLEDGE ASSUMED

    This article is not a friendly introduction to programming raster effects, and assumes you are already comfortable with Game Boy programming. To learn more about how to achieve neat raster effects like the above, check out DeadCScroll first, which the above GIF is actually from!

    Additionally, since the operations discussed here are extremely timing-sensitive, discussions will revolve around assembly instructions. You can learn how to program for the Game Boy in assembly in GB ASM Tutorialopen in new window.

    TERMINOLOGY

    We'll reference a few terms throughout this tutorial; here are brief explanations of them:

    • SoC: System-on-a-Chipopen in new window, a single chip that includes most (or all!) components of a system. The Game Boy's functionality is almost entirely contained within a single chip, confusingly labelled "DMG-CPU" or similar. (Contrast this with, for example, the SNES, where there is one chip for the CPU, two for the PPU, and many more.)
    • CPU: Central Processing Unit, the part of the SoC that executes code and configures everything else.
    • PPU: Pixel Processing Unit, the part of the SoC that is responsible for sending pixels to the LCD and generating them.
    • Rasterization: the process of turning... something (for example, a collection of textured polygons; or, on the GB, tiles and tilemaps) into an array of pixels. "Raster" is sort of a contraction of that term.
    • Scanline: a row of pixels; it's called a "scan"-line because the lines get drawn one by one, pixel by pixel, as if the PPU was "scanning" along the screen.
    • Register: in general, a small piece of memory, usually linked to some hardware component.
    • PPU mode: The PPU can be in one of four modes at a given time, depending on what it's doing. Please refer to Pan Docsopen in new window to learn what each mode corresponds to and how they are scheduled—they interact very tightly with raster effects.
    • Interrupt: an event that gets generated. Typically, this causes a "handler" to be called, which is a special routine dedicated to reacting to a given interrupt.
    • "Main thread": any code that is executed outside of interrupt handlers.

    Introduction

    The easiest way to implement raster effects is to use the LYC register with the STAT interrupt.

    Here is what the Pan Docs have to say about this register's simple function:

    FF45 - LYC (LY Compare) (R/W)open in new window

    The Game Boy permanently compares the value of the LYC and LY registers. When both values are identical, the “LYC=LY” flag in the STAT register is set, and (if enabled) a STAT interrupt is requested.

    So then, the outline for setting up a raster effect is as follows:

    1. Register an interrupt by setting LYC to the desired scanline
    2. When that scanline begins, the STAT interrupt handler will automatically be called
    3. Perform your chosen effect by modifying PPU registers
    4. Exit the handler with reti

    ALTERNATIVES

    There are other ways to perform raster FX, such as busy-waiting in the "main thread", but as this article's title suggests, we won't discuss them here.

    A major pro of LYC-interrupt-based raster effects is that they can be made self-contained, and thus largely independent of whatever the "main thread" is doing. This, in turn, simplifies the mental complexity of the code (decoupling), copes better with lag frames, and more.

    Many of the points brought forth later, particularly regarding cycle counting, are still relevant with these alternatives, so this is still worth reading!

    These four steps sound simple enough on their own, but there are numerous caveats we will discuss. Strap in!

    • Most raster effects are implemented by modifying registers between scanlines. Thus, you will want to write the register either during Mode 2 (of the same scanline), or Mode 0 (of the previous one)—anything but Mode 3, really.
      Unfortunately, LY=LYC interrupts are requested at the beginning of a scanline, so during the very short Mode 2, leaving too little time to perform but the most basic of effects.
    • Writing to the register during HBlank instead implies triggering the interrupt on the scanline above the effect, as well as idling for most of the scanline. So, if I wanted to enable sprites on scanline 16, I'd write 15 to LYC.
    • Mode 3's length is variable, so syncing to HBlank is difficult and time-consuming.
    • The interrupt handler's execution may be delayed by a few cycles, which makes it difficult to reliably sync to the PPU.
    • If the "main thread" is itself trying to sync with the PPU (typically by polling STAT in a loop), our interrupt may throw off its timing.

    Sounds good? Then let's get started!

    Timing

    First, let's look at the timing of the rendering itself, courtesy of the Pan Docsopen in new window:

    Here are some key points:

    • A "dot" is one period of the PPU's 4 MiHz clock, i.e. 0.25 µs.
    • A "cycle" is the main unit of time in the CPU, which is equal to 1 µs, or 4 dots. (The Game Boy Color CPU can enter a "double-speed" mode which halves the length of cycles, but not of dots. For the sake of simplicity, we won't consider the differences it involves here.)
    • Each scanline takes exactly 456 dots, or 114 cycles.
    • Mode 2 also takes a constant amount of time (20 cycles)
    • HBlank's length varies wildly, and will often be nearly as long as or longer than the drawing phase.
    • HBlank and OAM scan are mostly interchangeable, and long as you're not writing to OAM.
    • The worst-case HBlank's length is not a multiple of 4 dots, so we will round down to 21 cycles.

    Let's consider a simple STAT handler, which disables OBJs if called at line 128, and enables them otherwise:

    LYC::
    @@ -150,6 +150,6 @@
         pop af ; 100
         reti ; 104
     

    Once the handler finishes its logic, the handler delays cycles until it reaches the window then HBlank might start. With a 5-cycle offset due to a call, and the longest possible HBlank, the earliest HBlank might start is cycle 54, so that's the first attempt to read STAT. It keeps checking STAT until even in the worst-case scenario, it knows that HBlank will start. Then, it uses that time to write the scroll registers and exit. This way, it can still exit early, as long as the HBlank length permits. This routine takes 104 cycles in the worst-case scenario, but may take as few as 79 if HBlank comes sooner.

    The reason that the double-busy-loop method requires checking for Mode 3 but this method does not is that the double-busy-loop method is not cycle-counted, so you might be at the very end of HBlank which is problematic. Since this method is cycle-counted, you know that if HBlank has begun, you are at or near the start of it.

    If we make a similar list of pros and cons for this method, this is what it might look like:

    Hybrid cycle-counting

    Pros

    • may exit very early if HBlank is longer
    • allows enough time during blanking to write to up to three registers
    • never takes longer than one scanline

    Cons

    • requires all code to be constant-time
    • requires tedious cycle-counting

    This method can work well in many circumstances, and is especially suited to frequent effects that modify multiple registers and need to exit quickly to avoid taking too much CPU time. This method can even work reasonably well when used on every scanline through the Mode 2 interrupt.

    All three of these methods can generate great-looking effects, but I think the third one is an especially attractive option.

    Congrats! You made it to the end of the tutorial! I bet you're tired of reading it, and I'm tired of writing it too. So thanks for reading, see you next time!

    - + diff --git a/guides/sgb_border.html b/guides/sgb_border.html index daab26b..8cc2a66 100644 --- a/guides/sgb_border.html +++ b/guides/sgb_border.html @@ -36,7 +36,7 @@ })(); Adding a custom SGB border | gbdev.io - +

    Adding a custom SGB border

    This document aims to help developers of DMG-compatible homebrew with adding Super Game Boy borders.

    We will see how to:

    • Detect whether the program is running on a SGB
    • Transfer the border's tiles
    • Transfer and display the border's tilemap and palettes

    Written by sylvie (zlago)open in new window, idea (and minor help) by valentina (coffee bat)open in new window, reviews and improvements by ISSOtmopen in new window, avivaceopen in new window, and PinoBatchopen in new window.

    Enabling SGB features

    Before we can do anything else, we must first specify in the header that this game is aware of SGB features. Otherwise, the SGB BIOS will ignore any packets we send, and we won't even be able to detect when the program is running on SGB.

    To enable SGB features:

    This can be achieved by passing the --sgb-compatible and --old-licensee 0x33 flags to rgbfixopen in new window.

    Packets

    The SGB BIOS can be "talked to" via command packets, sent bit by bit via the P1/JOYP register.

    An SGB packet consists of:

    • a "start" pulse (P1=%xx00xxxx)
    • 128 data pulses (P1=%xx01xxxx for "1", P1=%xx10xxxx for "0")
    • a "0" pulse (P1=%xx10xxxx)

    You must set P1 to %xx11xxxx between each pulse.

    This adds up to 16 bytes of data (LSB first). If a packet doesn't read all 16 bytes, the unused bytes are ignored.

    You should wait 4 frames between each packet and the next. This gives the SGB BIOS a chance to receive a packet even if it is doing something else time-consuming.

    For an example of such routine, see this codeopen in new window and the related Pan Docs entry: SGB Command Packet on Pandocsopen in new window.

    This guide glosses over a minor detail, as certain packets can be (albeit unccomon) more than 16 bytes.

    TRN

    Bulk transfer (TRN) packets tell the SGB to copy the contents of the screen to buffers in Super NES work RAM. The CHR_TRN and PCT_TRN packets are used to send data for SGB borders.

    For a transfer to function properly, you must prepare VRAM and the LCD registers:

    1. set BGP to $e4 and LCDC to $91 (screen enabled, BG uses tiles $8000-$8fff and tilemap $9800, WIN and OBJ disabled, BG enabled)
    2. set SCX and SCY to $00
    3. the tilemap consists of $00, $01..$13, 12 bytes padding (offscreen), $14..$27, padding, repeat until $ff (inclusive)
    4. the data you want to send must be loaded at $8000-$8fff

    You can do 1, 2 and 3 via this snippetopen in new window

    • You must load the data into VRAM and enable the screen before sending the TRN packet. The SGB reads TRN payloads from the screen. If rendering is off, there is nothing on the screen to read.
    • You must wait ~8 frames after each TRN instead of just 4. The SGB BIOS has to finish what it's doing, receive the packet, and then read the screen.

    Detecting SGB

    Here's how a SGB detection routine should look like:

    1. Wait 12 or more frames for the SGB BIOS to start listening for packets.
    2. Send a MLT_REQ packet selecting 2 or 4 players ($89, $01 or $89, $03), and wait a couple frames for the SGB to receive the packet.
    3. Read the controller. Set P1 bit 5 to 0, then set P1 bits 5 and 4 to %11 (%xx11xxxx) to release the key matrix.
    4. Read the low nibble (bits 3-0) of P1, and look for a value other than %1111 (which indicates player 1).
    5. If player 1 was still found, repeat steps 3 and 4 once more, in case the next read indicates player 2.
    6. Optionally turn off multiplayer mode.

    If a non-%1111 value was found in step 4 either time, the program is running on SGB.

    A routine like this may be used to detect SGB (modified from sourceopen in new window):

    SGB_Detect:
    @@ -92,6 +92,6 @@
       ret
     

    SGB detection notes

    • It would be a good idea to save somewhere in RAM whether the game is running on an SGB capable device or not, such that if you wish to change the border mid-gameplay, you won't have to perform SGB detection again. The sample code stores it in wIsSGB.
    • If you wish to only use 1 controller for the game, you will have to send another MLT_REQ to disable multiplayer ($89, $00)
    • SGB_Wait4Frames above uses busy waiting. Depending on the structure of your initialization code, you can change it to use vblank interrupts or di+halt instead.

    Border limitations

    An SGB border has:

    • 255 tiles + 1 transparent tile (preferably tile #0)
    • 3 palettes of 15 (+ 1 transparent) colors, (up to 45 solid colors total)
    • a 256×224-pixel tilemap (there's a bit more to this, see notes)

    Converting borders

    With a recent version of superfamiconvopen in new window:

    superfamiconv -v -i input.png -p output.pal -t output.4bpp -P 4 -m output.pct -M snes --color-zero 0000ff -B 4
     
    • --color-zero should be the color that your image for transparency, in my case it was blue.
      • If your image has an alpha channel, it can be set can also be set to 00000000 to use the actual transparent color; however, this may cause some issues.
    • -v is optional, for showing details of the conversion process
    • You can add a row of the transparent color at the top of the image to force superfamiconv to make it tile #0, then incbin "output.pct", 64 to leave out that row.
    • -P 4 sets the base palette to the 4th one, and SGB borders use SNES palettes 4, 5, and 6. as of writing this, this option only works if you built superfamiconv from source.

    Uploading borders

    As stated before, the SGB border consists of tile data, picture data, and palette data. These are split across 2-3 packets:

    • CHR_TRN ($99) is used to send 4KiB of tile data.

      • since the border can use up to 8KiB of tiles, bit 0 of the second byte specifies which "half" you're sending
        • $99, $00 if the screen is loaded with the first 4KiB of tile data
        • $99, $01 if the screen is loaded with the second 4KiB of tile data
    • PCT_TRN ($a1) is used to send the picture and palette data. it also swaps the border, generally a good idea to send it after the tile data[^1]

      • assuming tiles 0-255 use VRAM from $8000 to $8fff:
        • the picture data must be at $8000-$873f (last 64 bytes are usually offscreen, see notes)
        • palette data must be at $8800-$885f
        • everything else is ignored
          • how you skip putting data at $8740-$87ff is up to you, I prefer doing separate copies, others prefer copying tilemap and palette data in one go, with the area between them padded.

    See also the related Pan Docs entry: SGB Command Borderopen in new window.

    [^1]: You can send a CHR_TRN up to ~60 framesopen in new window after the PCT_TRN for it to apply to the current border, but not all emulators will emulate this. It's fine to just pretend CHR_TRNs must go before PCT_TRN.

    Notes

    1. You can set the first row of tiles to your transparent color to force superfamiconv to put the transparent tile as the 1st tile, however you must then exclude 64 bytes of the tilemap (incbin "border.pct" -> incbin "border.pct", 64)

    2. SGB BIOS reserves palettes 4 through 6 for borders. If you really know what you're doing, you may be able to use palette 0 (the gameplay palette) for animated borders. You will probably have to edit the border in a tile editor such as YY-CHR, as there aren't yet any other tools for that.

    3. When the SNES lags, scanline 225 of the SGB border will be visible! You can set the topmost row of the 29th row of tiles to black to hide this.

    4. If this doesn't work for you, you can ask for help on the gbdevopen in new window channels.

    - + diff --git a/guides/tools.html b/guides/tools.html index 6644029..4bf5966 100644 --- a/guides/tools.html +++ b/guides/tools.html @@ -36,10 +36,10 @@ })(); Choosing tools for Game Boy development | gbdev.io - + -

    Choosing tools for Game Boy development

    This essay gives an overview of the Game Boy's capabilities, discussing the pros and cons of the available development tools, and providing a few tips to write more efficient code.

    Written by ISSOtmopen in new window with help from tobiasvlopen in new window, some updates by bbbbbropen in new window.


    In the past few years as retro gaming has grown in popularity, programming for older platforms has also gained traction. A popular platform is the Game Boy, both for its nostalgia and (relative) ease to program for.

    WARNING

    This document only applies to the Game Boy and Game Boy Color. Game Boy Advance programming has little in common with Game Boy programming.

    If you want to program for the GBA, which is much more C-friendly (and C++ and Rust, for that matter) than the GB and GBC, then I advise you to download devkitARM and follow the Toncopen in new window tutorial. Please note that the Game Boy Advance also functions as a Game Boy Color, so if you only have a GBA, you can use it for both GB and GBC development.

    When someone wants to make their own game, one of the first problems they will encounter is picking the tools they will use. There current main options are:

    • RGBDS (Rednex Game Boy Development System) and the Game Boy's Assembly language (ASM)
    • GBDK-2020 (Game Boy Development Kit) and the C language
    • ZGB (an engine built on GBDK-2020) and the C language
    • GB Studio (a drag-and-drop game creator with scripting)

    The purpose of this document is to provide some insights and help you make the better choice if you're starting a new project. I will also provide some "good practice" tips, both for C and ASM, if you have already made up your mind or are already using one of these.

    Overview

    The original Game Boy, codenamed the DMG, has a 1 MHz CPU [the CPU is actually clocked at 4 MHz, but every instruction takes up a multiple of 4 clocks, so it's often simplified to a 1 MHz CPU]. Given that an instruction takes approximately 2 to 3 cycles, this gives the CPU a capacity of 333,000~500,000 instructions per second. Its LCD boasts 60 fps [it's actually 59.73 fps], which rounds up to between 50,000 and 80,000 instructions per frame. Suddenly not so much, eh? It also has 8 kB of RAM, and 8 kB of video RAM ; a 160x144 px LCD (thus slightly wider than it's tall), 4 colors, and 4-channel audio.

    The Super Game Boy adds a few minor things, such as a customizable screen border, and some crude color. It's also slightly faster than the DMG.

    The Game Boy Color can [if you tell it to] unlock additional functionality, such as more fleshed-out color, a double-speed CPU, twice the video RAM and four times the RAM! (With caveats, obviously.)

    Languages

    The choice of programming language is important and can have a very large effect on a project. It determines how much work is involved, what will be possible, and how fast it will be able to run.

    Assembly (ASM)

    Most games and programs for the Game Boy written in ASM will use RGBDS or WLA-DX.

    Strengths:

    • Not too difficult to learn.
    • Extremely powerful and flexible.
    • When well written it allows for maximum speed and efficiency on the limited resources of the Game Boy hardware.

    Weaknesses:

    • It takes a special kind of work to write optimized ASM code.
    • It's quite verbose and sometimes tedious.
    • Will require more time and learning to get up and running when compared with C.
    • Code may not be easily shared with ports of a game on other platforms.

    C

    C will typically be used with the SDCC compiler and GBDK-2020 or ZGB, though it can also be used on its own without a framework or with a different compiler/dev kit (such as z88dkopen in new window).

    Strengths:

    • Allows for getting up and running faster than with ASM, especially when building on top of GBDK-2020 and ZGB.
    • The language abstractions make it relatively easy to implement ideas and algorithms.
    • C source debugging is available through Emulicious with the VSCode debug adapter, making it easier to understand problems if they arise.
    • ASM can be included in projects with C, either standalone or inline for speed critical features.

    Weaknesses:

    • The SDCC C compiler won't always generate code that runs as fast as skilled, hand-optimized assembly. It has matured a lot in the 20 years since the original GBDK, but bugs still turns up on occasion. On a platform with a slow CPU such as the Game Boy this can be a factor.
    • It’s easier to write inefficient code in C without realizing it. The Game Boy's CPU is only capable of performing 8-bit addition or subtraction, or 16-bit addition. Using INT32s is quite taxing on the CPU (it needs to do two consecutive 16-bit adds, and add the carry). See the tips below to avoid such blunders.
    • There is overhead due to C being a stack-oriented language, whereas the Game Boy's CPU is rather built for a register-oriented strategy. This most notably makes passing function arguments a lot slower, although SDCC has some optimizations for this.

    Non-Programming Language option

    Using a GUI instead- If you don’t want to learn a programming language in order to make Game Boy games, then GB Studio is an option. See the GB Studio section for more details.

    Development Platforms

    RGBDSopen in new window with ASM

    RGBDS is an actively maintained suite of programs that allow building a ROM using ASM (assembly). It contains three programs that perform different stages of the compilation, as well as a program that converts PNG images to the Game Boy's tile format. RGBDS is available for Linux, Windows and MacOS.

    Strengths:

    • Very knowledgeable community with a lot of history.
    • Built in support for ROM banking.
    • Works quite well with BGB for debugging.

    Weaknesses:

    • Provides a limited amount of built-in code and functionality (does not include a large API like GBDK-2020 does).

    WLA-DXopen in new window with ASM

    WLA-DX is also sometimes used when writing in ASM, mostly due to its better struct support than RGBDS.

    GBDK-2020open in new window with C

    GBDK-2020 is a development kit and toolchain built around the SDCC C compiler which allows you to write programs in C and build ROMs. It includes an API for interfacing with the Game Boy. GBDK-2020 is a modernized version of the original GBDKopen in new window. It's available for Linux, Windows and MacOS.

    Strengths:

    • Flexible and extensible.
    • Comprehensive API that covers most hardware features.
    • Many sample projects and open source games are available that demonstrate how to use the API, hardware, and structure games.
    • C source debugging is available with Emulicious.

    Weaknesses:

    • Takes care of some aspects of the hardware without requiring the developer to initiate them (such as OAM DMA during VBLANK), so it's not always obvious to beginners what the hardware is doing behind the scenes, or how to fix them when something goes wrong.
    • ROM banking may require more management in code than RGBDS.

    ZGBopen in new window with C & GBDK-2020

    ZGB is a small engine for the Game Boy built on top of GBDK-2020 and written in C. Strengths:

    • The basic graphics, sound and event structure are all pre-written, so it’s faster and easier to start writing a game.
    • Several open source games built with it are available as examples.

    Weaknesses:

    • The engine just has the basics and custom code may need to be needed for common game features (such as moving platforms, etc.).
    • Even more of the hardware configuration and processing is taken care of behind the scenes than with GBDK, so less experienced users may have trouble when problems arise.

    GB Studioopen in new window

    GB Studio is a drag-and-drop game creator for the Game Boy that does not require knowledge of programming languages. Games are built using a graphical interface to script graphics, sound and actions. It is available for Linux, Windows and MacOS.

    Strengths:

    • Very easy for beginners to start building games right away. Everything is built-in and requires minimal knowledge and understanding of the Game Boy hardware.
    • Has been used to create large and extensive projects.
    • Very active community for help and support.

    Weaknesses:

    • It’s games will tend to be slower than both ASM and C.
    • There is a limited set of commands to script with and some artificially smaller restrictions on palettes, sprites, background tiles and other hardware features (due to how GB Studio manages them).
    • Games may be more constrained or require workarounds to do things if they don’t easily fit within the available scripting, graphics and sound tools. (Though it is possible for advanced users to do a “engine eject” and add more functionality using C and ASM.)

    Emulators and debuging tools

    Accurate emulators and debugging tools are tremendously helpful for testing and tracking down problems. The following Game Boy emulators provide excellent accuracy and include a variety of different features.

    Side note : if you are using VBA or VBA-rr, stop using them right now. These emulators are extremely inaccurate, and also contain severe security flaws. I strongly urge you to ditch these emulators and spread the word.

    Summary

    If your question is "What should I use for my game project ?", then you're in the right section. The first question you should ask yourself is what languages you know.

    If you don't know ASM, C or C++

    Consider starting with C and GBDK. This will introduce you to working with the hardware and is an easier starting place.

    Once you've grasped C's concepts (most importantly pointers), give ASM a go. The language is simpler than it looks. Even if you don't manage to get working ASM code, it actually helps a lot (especially on such a constrained system) to know what's "under the hood". There is even an online IDEopen in new window to experiment with.

    For C / GBDK users, knowing ASM will help you understand what its API (which is mostly written in ASM) is doing behind the scenes and will make using emulator debuggers easier to understand.

    If you don't wan't to learn a language at all, GB Studio is an alternative to C and ASM.

    If you know C but not ASM

    Consider the goals, scope and time frame of your project. If you'd like to start building right away then C and GBDK will make that easy. You'll also have growing exposure to ASM as time goes on due to working with the hardware and tracking down problems in the debugger.

    On the other hand, if you'd like to expand your programming skill set and have additional time, learning to use ASM and RGBDS will provide you with a lot of knowledge about the Game Boy hardware. Once you know ASM in addition to C, you'll have a lot of flexibility in what tools you use for projects.

    If you know ASM

    RGBDS with ASM is a solid option. You'll be able to get the best performance out of the hardware, and there is an experienced community available to help.

    Another option is to reach out to us, and discuss the matter.

    Tips For Better Code

    The very first thing to do in all cases is to read the docsopen in new window, to grasp how the Game Boy works. In ASM, this is essential; in C, this will let you understand what a given library function does. It will also let you understand what is possible on the Game Boy, and what isn't. (You can always ask, if you have doubts.)

    I also recommend looking up awesome-gbdevopen in new window for resources and tutorials. There are a lot of helpful articles there, as well as helper tools.

    ASM Help

    • Modules
      Separate your game into several "entities" that interact together. Camera, Player, NPCs, Loading zones, etc. This simplifies coding, by allowing you to reason independently on smaller units. This facilitates development and reduces the amount of bugs.
    • Document your functions
      For each function, write a comment saying what it does, what memory it touches, and what registers it affects. This will avoid conflicts, and let you optimize your code by minimizing the amount of registers you save when calling a function.
    • Plan before writing
      You should plan what register is going to be used for what within your functions before starting to write them. Your goal is to minimize the amount of register swapping. There's no general rule, so feel free to drop by and ask us, if you're in doubt.
    • RGBASM -E and RGBLINK -n <symfile>
      When you load ROM.gb or ROM.gbc in BGB, it automatically loads (if it exists) the file ROM.sym in the same folder as the ROM. This adds symbols to the debugger, which - believe me - helps a ton.

    Optimizing For GBDK

    • Global variables
      Use as many global variables as you can; the Game Boy has a lot of RAM compared to other platforms such as the NES, but is slow at using the stack. Thus, minimizing the number of local variables, especially in heavily-called functions, will reduce the time spent manipulating the stack.
    • Optimized code
      Write code as efficient as possible. Sometimes there is a readability tradeoff, so I recommend you get the comment machine gun out and put some everywhere.
    • By default GBDK-2020 (after v4.0.1) will use the SDCC flag --max-allocs-per-node 50000 for an increased optimization pass. You may also choose to use --opt-code-speed (optimize code generation towards fast code, possibly at the expense of codesize) or --opt-code-size (optimize code generation towards compact code, possibly at the expense of codespeed).
    • Inlining
      When performance is important avoid using functions if you can inline them, which skips passing all arguments to the stack, mostly. Macros will be your friends there. If needed you can also use inline ASM.
    • NEVER use recursive functions
    • AVOID printf
      printf clobbers a sizeable chunk of VRAM with unnecessary text tiles. Instead, you should sprintf to a buffer in WRAM, then put that on the screen using a custom font.
    • Geometry funcs
      Avoid the functions that draw geometry on-screen (lines, rectangles, etc.). The Game Boy isn't designed for this kind of drawing method, and you will have a hard time mixing this with, say, background art. Plus, the functions are super slow.
    • const (very important!)
      Declaring a variable that doesn't change as const greatly reduces the amount of ROM, RAM, and CPU used.
      The technical reason behind that is that non-const values, especially arrays, are loaded to RAM from ROM in an extremely inefficient way. This takes up a LOT more ROM, and copies the value(s) to RAM when it's unneeded. (And the GB does not have enough RAM for that to be viable.)
    • Don't use MBC1
      MBC1 is often assumed to be the simplest of all MBCs... but it has a quirk that adds some overhead every time ROM or SRAM bank switches are performed. MBC3 and MBC5 don't have this quirk, and don't add any complexity. Using MBC1 has no real use. (Let's not talk about MBC2, either.)

    Community And Help

    If you want to get help from the community, go:

    - +

    Choosing tools for Game Boy development

    This essay gives an overview of the Game Boy's capabilities, discussing the pros and cons of the available development tools, and providing a few tips to write more efficient code.

    Written by ISSOtmopen in new window with help from tobiasvlopen in new window, some updates by bbbbbropen in new window.


    In the past few years as retro gaming has grown in popularity, programming for older platforms has also gained traction. A popular platform is the Game Boy, both for its nostalgia and (relative) ease to program for.

    WARNING

    This document only applies to the Game Boy and Game Boy Color. Game Boy Advance programming has little in common with Game Boy programming.

    If you want to program for the GBA, which is much more C-friendly (and C++ and Rust, for that matter) than the GB and GBC, then I advise you to download devkitARM and follow the Toncopen in new window tutorial. Please note that the Game Boy Advance also functions as a Game Boy Color, so if you only have a GBA, you can use it for both GB and GBC development.

    When someone wants to make their own game, one of the first problems they will encounter is picking the tools they will use. There current main options are:

    • RGBDS (Rednex Game Boy Development System) and the Game Boy's Assembly language (ASM)
    • GBDK-2020 (Game Boy Development Kit) and the C language
    • ZGB (an engine built on GBDK-2020) and the C language
    • GB Studio (a drag-and-drop game creator with scripting)

    The purpose of this document is to provide some insights and help you make the better choice if you're starting a new project. I will also provide some "good practice" tips, both for C and ASM, if you have already made up your mind or are already using one of these.

    Overview

    The original Game Boy, codenamed the DMG, has a 1 MHz CPU [the CPU is actually clocked at 4 MHz, but every instruction takes up a multiple of 4 clocks, so it's often simplified to a 1 MHz CPU]. Given that an instruction takes approximately 2 to 3 cycles, this gives the CPU a capacity of 333,000~500,000 instructions per second. Its LCD boasts 60 fps [it's actually 59.73 fps], which rounds up to between 50,000 and 80,000 instructions per frame. Suddenly not so much, eh? It also has 8 kB of RAM, and 8 kB of video RAM ; a 160x144 px LCD (thus slightly wider than it's tall), 4 colors, and 4-channel audio.

    The Super Game Boy adds a few minor things, such as a customizable screen border, and some crude color. It's also slightly faster than the DMG.

    The Game Boy Color can [if you tell it to] unlock additional functionality, such as more fleshed-out color, a double-speed CPU, twice the video RAM and four times the RAM! (With caveats, obviously.)

    Languages

    The choice of programming language is important and can have a very large effect on a project. It determines how much work is involved, what will be possible, and how fast it will be able to run.

    Assembly (ASM)

    Most games and programs for the Game Boy written in ASM will use RGBDS or WLA-DX.

    Strengths:

    • Not too difficult to learn.
    • Extremely powerful and flexible.
    • When well written it allows for maximum speed and efficiency on the limited resources of the Game Boy hardware.

    Weaknesses:

    • It takes a special kind of work to write optimized ASM code.
    • It's quite verbose and sometimes tedious.
    • Will require more time and learning to get up and running when compared with C.
    • Code may not be easily shared with ports of a game on other platforms.

    C

    C will typically be used with the SDCC compiler and GBDK-2020 or ZGB, though it can also be used on its own without a framework or with a different compiler/dev kit (such as z88dkopen in new window).

    Strengths:

    • Allows for getting up and running faster than with ASM, especially when building on top of GBDK-2020 and ZGB.
    • The language abstractions make it relatively easy to implement ideas and algorithms.
    • C source debugging is available through Emulicious with the VSCode debug adapter, making it easier to understand problems if they arise.
    • ASM can be included in projects with C, either standalone or inline for speed critical features.

    Weaknesses:

    • The SDCC C compiler won't always generate code that runs as fast as skilled, hand-optimized assembly. It has matured a lot in the 20 years since the original GBDK, but bugs still turns up on occasion. On a platform with a slow CPU such as the Game Boy this can be a factor.
    • It’s easier to write inefficient code in C without realizing it. The Game Boy's CPU is only capable of performing 8-bit addition or subtraction, or 16-bit addition. Using INT32s is quite taxing on the CPU (it needs to do two consecutive 16-bit adds, and add the carry). See the tips below to avoid such blunders.
    • There is overhead due to C being a stack-oriented language, whereas the Game Boy's CPU is rather built for a register-oriented strategy. This most notably makes passing function arguments a lot slower, although SDCC has some optimizations for this.

    Non-Programming Language option

    Using a GUI instead- If you don’t want to learn a programming language in order to make Game Boy games, then GB Studio is an option. See the GB Studio section for more details.

    Development Platforms

    RGBDSopen in new window with ASM

    RGBDS is an actively maintained suite of programs that allow building a ROM using ASM (assembly). It contains three programs that perform different stages of the compilation, as well as a program that converts PNG images to the Game Boy's tile format. RGBDS is available for Linux, Windows and MacOS.

    Strengths:

    • Very knowledgeable community with a lot of history.
    • Built in support for ROM banking.
    • Works quite well with BGB for debugging.

    Weaknesses:

    • Provides a limited amount of built-in code and functionality (does not include a large API like GBDK-2020 does).

    WLA-DXopen in new window with ASM

    WLA-DX is also sometimes used when writing in ASM, mostly due to its better struct support than RGBDS.

    GBDK-2020open in new window with C

    GBDK-2020 is a development kit and toolchain built around the SDCC C compiler which allows you to write programs in C and build ROMs. It includes an API for interfacing with the Game Boy. GBDK-2020 is a modernized version of the original GBDKopen in new window. It's available for Linux, Windows and MacOS.

    Strengths:

    • Flexible and extensible.
    • Comprehensive API that covers most hardware features.
    • Many sample projects and open source games are available that demonstrate how to use the API, hardware, and structure games.
    • C source debugging is available with Emulicious.

    Weaknesses:

    • Takes care of some aspects of the hardware without requiring the developer to initiate them (such as OAM DMA during VBLANK), so it's not always obvious to beginners what the hardware is doing behind the scenes, or how to fix them when something goes wrong.
    • ROM banking may require more management in code than RGBDS.

    ZGBopen in new window with C & GBDK-2020

    ZGB is a small engine for the Game Boy built on top of GBDK-2020 and written in C. Strengths:

    • The basic graphics, sound and event structure are all pre-written, so it’s faster and easier to start writing a game.
    • Several open source games built with it are available as examples.

    Weaknesses:

    • The engine just has the basics and custom code may need to be needed for common game features (such as moving platforms, etc.).
    • Even more of the hardware configuration and processing is taken care of behind the scenes than with GBDK, so less experienced users may have trouble when problems arise.

    GB Studioopen in new window

    GB Studio is a drag-and-drop game creator for the Game Boy that does not require knowledge of programming languages. Games are built using a graphical interface to script graphics, sound and actions. It is available for Linux, Windows and MacOS.

    Strengths:

    • Very easy for beginners to start building games right away. Everything is built-in and requires minimal knowledge and understanding of the Game Boy hardware.
    • Has been used to create large and extensive projects.
    • Very active community for help and support.

    Weaknesses:

    • It’s games will tend to be slower than both ASM and C.
    • There is a limited set of commands to script with and some artificially smaller restrictions on palettes, sprites, background tiles and other hardware features (due to how GB Studio manages them).
    • Games may be more constrained or require workarounds to do things if they don’t easily fit within the available scripting, graphics and sound tools. (Though it is possible for advanced users to do a “engine eject” and add more functionality using C and ASM.)

    Emulators and debuging tools

    Accurate emulators and debugging tools are tremendously helpful for testing and tracking down problems. The following Game Boy emulators provide excellent accuracy and include a variety of different features.

    Side note : if you are using VBA or VBA-rr, stop using them right now. These emulators are extremely inaccurate, and also contain severe security flaws. I strongly urge you to ditch these emulators and spread the word.

    Summary

    If your question is "What should I use for my game project ?", then you're in the right section. The first question you should ask yourself is what languages you know.

    If you don't know ASM, C or C++

    Consider starting with C and GBDK. This will introduce you to working with the hardware and is an easier starting place.

    Once you've grasped C's concepts (most importantly pointers), give ASM a go. The language is simpler than it looks. Even if you don't manage to get working ASM code, it actually helps a lot (especially on such a constrained system) to know what's "under the hood". There is even an online IDEopen in new window to experiment with.

    For C / GBDK users, knowing ASM will help you understand what its API (which is mostly written in ASM) is doing behind the scenes and will make using emulator debuggers easier to understand.

    If you don't wan't to learn a language at all, GB Studio is an alternative to C and ASM.

    If you know C but not ASM

    Consider the goals, scope and time frame of your project. If you'd like to start building right away then C and GBDK will make that easy. You'll also have growing exposure to ASM as time goes on due to working with the hardware and tracking down problems in the debugger.

    On the other hand, if you'd like to expand your programming skill set and have additional time, learning to use ASM and RGBDS will provide you with a lot of knowledge about the Game Boy hardware. Once you know ASM in addition to C, you'll have a lot of flexibility in what tools you use for projects.

    If you know ASM

    RGBDS with ASM is a solid option. You'll be able to get the best performance out of the hardware, and there is an experienced community available to help.

    Another option is to reach out to us, and discuss the matter.

    Tips For Better Code

    The very first thing to do in all cases is to read the docsopen in new window, to grasp how the Game Boy works. In ASM, this is essential; in C, this will let you understand what a given library function does. It will also let you understand what is possible on the Game Boy, and what isn't. (You can always ask, if you have doubts.)

    I also recommend looking up awesome-gbdevopen in new window for resources and tutorials. There are a lot of helpful articles there, as well as helper tools.

    ASM Help

    • Modules
      Separate your game into several "entities" that interact together. Camera, Player, NPCs, Loading zones, etc. This simplifies coding, by allowing you to reason independently on smaller units. This facilitates development and reduces the amount of bugs.
    • Document your functions
      For each function, write a comment saying what it does, what memory it touches, and what registers it affects. This will avoid conflicts, and let you optimize your code by minimizing the amount of registers you save when calling a function.
    • Plan before writing
      You should plan what register is going to be used for what within your functions before starting to write them. Your goal is to minimize the amount of register swapping. There's no general rule, so feel free to drop by and ask us, if you're in doubt.
    • RGBASM -E and RGBLINK -n <symfile>
      When you load ROM.gb or ROM.gbc in BGB, it automatically loads (if it exists) the file ROM.sym in the same folder as the ROM. This adds symbols to the debugger, which - believe me - helps a ton.

    Optimizing For GBDK

    • Global variables
      Use as many global variables as you can; the Game Boy has a lot of RAM compared to other platforms such as the NES, but is slow at using the stack. Thus, minimizing the number of local variables, especially in heavily-called functions, will reduce the time spent manipulating the stack.
    • Optimized code
      Write code as efficient as possible. Sometimes there is a readability tradeoff, so I recommend you get the comment machine gun out and put some everywhere.
    • By default GBDK-2020 (after v4.0.1) will use the SDCC flag --max-allocs-per-node 50000 for an increased optimization pass. You may also choose to use --opt-code-speed (optimize code generation towards fast code, possibly at the expense of codesize) or --opt-code-size (optimize code generation towards compact code, possibly at the expense of codespeed).
    • Inlining
      When performance is important avoid using functions if you can inline them, which skips passing all arguments to the stack, mostly. Macros will be your friends there. If needed you can also use inline ASM.
    • NEVER use recursive functions
    • AVOID printf
      printf clobbers a sizeable chunk of VRAM with unnecessary text tiles. Instead, you should sprintf to a buffer in WRAM, then put that on the screen using a custom font.
    • Geometry funcs
      Avoid the functions that draw geometry on-screen (lines, rectangles, etc.). The Game Boy isn't designed for this kind of drawing method, and you will have a hard time mixing this with, say, background art. Plus, the functions are super slow.
    • const (very important!)
      Declaring a variable that doesn't change as const greatly reduces the amount of ROM, RAM, and CPU used.
      The technical reason behind that is that non-const values, especially arrays, are loaded to RAM from ROM in an extremely inefficient way. This takes up a LOT more ROM, and copies the value(s) to RAM when it's unneeded. (And the GB does not have enough RAM for that to be viable.)
    • Don't use MBC1
      MBC1 is often assumed to be the simplest of all MBCs... but it has a quirk that adds some overhead every time ROM or SRAM bank switches are performed. MBC3 and MBC5 don't have this quirk, and don't add any complexity. Using MBC1 has no real use. (Let's not talk about MBC2, either.)

    Community And Help

    If you want to get help from the community, go:

    + diff --git a/index.html b/index.html index 350635f..e70802f 100644 --- a/index.html +++ b/index.html @@ -37,10 +37,10 @@ })(); Projects | gbdev.io - +


    Game Boy Development community

    We are a non for profit collective of passionate developers and hackers working on development tools, homebrew games, emulators, preservation and documentation for the Nintendo Game Boy handheld console, the original gray brick from 1989.

    Join us on GitHub, Mastodon, Twitter and Discord.

    Projects

    Here's what we are up to:

    Pan Docs Star

    The single, most comprehensive technical reference to Game Boy available to the public.

    Game Boy CPU Opcode tablesopen in new window


    awesome-gbdev  Star

    Curated list of Game Boy development resources such as tools, guides, technical documentation, tutorials, emulators, related projects and open-source ROMs. Everything you'll ever need to know and see about this console is here.
    If you want to code an emulator, create your own game or simply dive into the software and hardware architecture of the Game Boy, this is the place!

    RGBDS  Star

    Rednex Game Boy Development System: the de-facto ASM development toolkit for the Game Boy and Game Boy Color.

    hardware.incopen in new window - Standard include file containing Game Boy hardware definitions for use in RGBDS projects.

    rgbds-liveopen in new window - A live Game Boy programming environment in the browser, allowing for realtime assembly programming with RGBDS.


    GB ASM Tutorial  Star

    A (work in progress) tutorial on how to program for the Game Boy in assembly, touching on every aspect required to make Game Boy games, via a Hello World, constructing an Arkanoid clone, and capping off by making a playable Shoot-'Em-Up.

    GBDK 2020  Star

    Maintained and modernized GBDK, the Game Boy Development Kit. Now powered by an updated version of the SDCC toolchain, provides a C compiler, assembler, linker and a set of libraries.

    Chat Channels 

    The places where our community thrives. Here we chat, discuss, help each other and show what we are working on. We have a Discord server, an IRC channel, and more.

    Homebrew Hub 

    Play Game Boy games online from an archive of hundreds of entries!
    A community-led attempt to collect, archive and save every unofficial game, homebrew, demo, patch, hackrom for Game Boy produced by the community through the last 3 decades of passionate work.

    The Game Boy Archive 

    Digital library of Game Boy related software, hardware and literature. Aimed to mirror and preserve old and fragmented contributions in the scene from the last three decades.

    Events

    We host coding competitions in which anyone can partecipate by creating original games, demos, homebrews tools and music for the Game Boy and compete for glory and prizes.

    GB Competition '21 - GB Competition '23


    - + diff --git a/meetings.html b/meetings.html index dc5fed2..01a85a8 100644 --- a/meetings.html +++ b/meetings.html @@ -36,10 +36,10 @@ })(); Meetings minutes | gbdev.io - + - + diff --git a/meetings/2023-11-04-sc.html b/meetings/2023-11-04-sc.html index 68469a0..ebcdfbc 100644 --- a/meetings/2023-11-04-sc.html +++ b/meetings/2023-11-04-sc.html @@ -36,10 +36,10 @@ })(); Steering Committee - November 2023 | gbdev.io - +

    Steering Committee - November 2023

    Written by avivace.

    November 4th, 2023. 15:00 — 17:30 UTC. Discord VC.

    Invited

    Moderators, Staff, Experts, Outreach, RGBDS maintainers.

    Partecipants

    PinoBatch, avivace, ISSO, Calindro, Duo, nitro2k01, QuangDX, superdisk, kva64, Sylvie, Sanqui

    About those meetings

    Participants were asked to fill in discussion points beforehand. The results of these discussions (decisions, suggestions, comments, etc.) are reported as subitems.

    Discussion points marked * were not brought up due to lack of time.

    Anyone can reach out in #meta on the Discord server to comment/discuss on any of the points reported here.

    Minutes
    • avivace:

      • Q to ISSO: RGBDS Rust port plans?
        • Scope: Full port from the old codebase, can’t be 1-to-1
        • Architecture design in progress
        • Motivation: C not attractive anymore for potential contributors. Showing its age. Technicalities (std::vector). Rust is fancier, more active community.
        • (Personal) De-risking/Viability study
        • Question from Pino: will this affect availability of binaries?
      • Homebrew Hub: developments and expanding to NES *
      • Gbcompo23: [...] *
      • Funding: how to? *
      • Creating the steering committee: Roles? *
      • Q to Sanqui: how to run these meetings? Minutes *
    • ISSOtm:

      • Difficulties finding contributors
        • Pan Docs, RGBDS, ASM Tutorial are lacking
        • AV: Homebrew Hub is OK
        • Quality barrier too high? Is our PR review process too much?
          • Possible (partial) solution = avoid nitpicking
          • Interesting actionable by DUO: give reviews in “steps”, avoid attacking a PR with everything all at once.
          • If making follow-up changes separately, be upfront about that in the initial PR to avoid the contributor feeling “the rug pulled under their feet”
          • Put a hard cap on the PR’s “TTL” before being merged (e.g. 3 weeks), and avoid minor changes as the deadline looms closer
        • How to handle contributors going silent?
        • “Better merge something incomplete to beg correction work, rather than drop everything done thus far”
        • Promoting a “Bug Day”?
      • Moving projects to SourceHut? *
    • Sanqui:

      • Overview of Wikidata and the possibility of contributing Homebrew Hub information to Wikidata
        • Add Ext ID in the game metadata schema and point it to Wikidata entry. Possibly populate others.
        • HHub - cartridges/published games/publishers
    • DUO:

      • Remarks and compliments on the great state of gbdev.
      • Promote PRs that need to be worked on, but also promote work that has been done “for cred” - Start using #feedback again.
    • nitro2k01:

      • Potentially add a long-term solution for the IRC bridge as a point/responsibility.
        • Someone other than @avivace needs to volunteer (=> @nitro2k01) and get SSH access and/or a webhook token to delegate the responsibility of handling the bridge
      • Future of the forums *
    • Kva64:

      • Social media handling — general outline and feedback request
        • Not only game releases/showcase content can be shared, but projects themselves may have cool milestones to share
        • Allow developers, maintainers, etc. to raise up things that can be promoted, so people helping with social media don’t have to “chase” those. Should those go in #showcase? Should #showcase be split?
        • Encourage (PSA?) developers to post in #showcase Move all showcase channels to a separate category, and rename “showcase” to “wip-showcase”? Split #releases into e.g. #releases-games and #releases-tooling
        • To discuss in #meta: opt-in/opt-out status of showcase channels. A suggestion: make sharing opt-out in #releases-*, and opt-in in #wip-showcase
      • Policy on sharing and promoting commercial projects?
        • DUO: do not shy away from promoting them because it’s a motivation to some; however, restrictions should be put to avoid being taken advantage of
        • Should the cooldown (if any) apply per project, per user...?
      • Need for using any newly-emerging social media platforms (e.g. Threads and Bluesky)?
        • Threads and Bluesky currently have very little reach, so maybe not
        • Other platforms (e.g. Instagram): maybe, but this may require more people to handle them
        • Creating a channel to coordinate them
    • Sylvie:

      • Q to ISSO: Continue improving existing C++ while Rust progresses?
        • C to C++ in parallel
        • Talk separately (and later) about whether we want to upstream the port, and if yes, the roadmap (responsibility & task distribution, etc.)
    - + diff --git a/meetings/2024-03-10-sc2.html b/meetings/2024-03-10-sc2.html index f9c0d98..abbe635 100644 --- a/meetings/2024-03-10-sc2.html +++ b/meetings/2024-03-10-sc2.html @@ -36,10 +36,10 @@ })(); Steering Committee - March 2024 | gbdev.io - +

    Steering Committee - March 2024

    Minutes curated by Sanqui and avivace


    Participants: avivace, Sanqui, Calindro, superdisk, ISSOtm, nitro, Pino, asie, tobias, DUO, Sylvie, kva

    Where: Discord gbdev, #sc-meeting voice channel

    When: March 10th 2024, 6:30 PM - 8:00 PM CET (UTC +1)

    Last meeting minutesopen in new window

    Discussion points are ordered by priority.


    Updates

    avivace:

    • Creation of a new Outreach issue tracker / board to coordinate social media posting etc.
    • Asking for help (and funding) gb-asm-tutorial
    • matomo statistics shows growing interest in gb-asm-tutorial
    • Unblocking gb-asm-tutorial

    Discussion

    nitro2k01

    • Future of the forums
      • Problems
        • Not mobile friendly
        • People don’t want to make another account -> offer login using Discord or GitHub
      • When/if migrating to a new system, what do with old posts?
        • Migrate to new? (lose URLs)
        • Set old in read-only
      • Threads on Discord <-> Forum ?
      • Options
        • Leave it the way it is
        • Could switch forum systems
        • Discourse is very popular, but JS heavy
        • Migrate to nesdev as they would be willing to help
        • Migrate to https://forum.gbadev.net/open in new window, which uses Flaskbb
          • Recycling logins may make the forum more attractive (e.g. nesdev or gbadev may have users overlap)

    ISSOtm:

    • RGBDS (and other projects?): onboarding friction (https://matklad.github.io/2021/02/06/ARCHITECTURE.md.htmlopen in new window for inspiration)
      • Projects are complex and “unapproachable”
      • Adding examples to CONTRIBUTING.md?
      • Which projects don’t have CONTRIBUTING.md?
      • Write down what is expected of a maintainer!
      • Finding some time to write down the “vision” Isso has for the Rust port (what needs to be done, how, etc.)
    • Prioritization, among and within…
      • gb-asm-tutorial (1)
      • Pan Docs (2)
      • rsgbds (RGBDS on “life support” with Sylvie maintaining) (last)
    • Next meeting:
      • Moving projects to SourceHut?

    avivace

    • FOSDEM feedback
      • Fosdem25. Who wants to join and come in the “gbdev” delegation?
      • Isso wants to give a talk
        • RGBDS
          • “Breaking changes and how to live with them”
          • Working from a codebase from the 90’s
        • Tutorial?

    kva64

    • Promoting usage of public domain/creative commons/”use as long as you give credit” assets among community members (open related issue on github)
    • How do deal with “drama” against users/companies/etc we want to shout out: consult with outreach team + use best judgment
    - + diff --git a/newsletter.html b/newsletter.html index 0544529..2015624 100644 --- a/newsletter.html +++ b/newsletter.html @@ -36,10 +36,10 @@ })(); Newsletter | gbdev.io - + - + diff --git a/newsletter/1.html b/newsletter/1.html index 99372ef..d13dc9e 100644 --- a/newsletter/1.html +++ b/newsletter/1.html @@ -36,10 +36,10 @@ })(); The Gbdev Digest #1 - 2021 Recap | gbdev.io - +

    The Gbdev Digest #1 - 2021 Recap

    Written by avivace, on behalf of the gbdev org. Originally published on "getrevue" on the 21st of February, 2022.

    Hey all and welcome to the first Issue of the new gbdev curated digest! Our idea is to prepare a collection of curated news about what is happening in our community, with a particular focus on our Open Source projects. Whatever you are interested in what’s happening the gbdev scene, new homebrew, tools, and documentation releases, find stuff where you can contribute with code or provide feedback, this newsletter is for you!

    About us and our commitment to OSS

    The following is a quick clarification since this is the first issue of the Gbdev Digest. Feel free to shamelessly skip it.

    This newsletter is curated by the team behind the gbdev.io community, with a lot of help from members of other smaller communities and groups. We are directly involved with the development and maintaining of a lot of projects (e.g. Pan Docs, RGBDS, and Homebrew Hub), but of course not with everything that will be mentioned in this newsletter.

    The gbdev initiative promotes the development of tools, documentation and homebrew games. We also push research and emulation efforts while trying to keep everything as accessible as possible to everyone, no matter the technical background. Another big commitment is the archiving one: we are working on salvaging old and unavailable content, creating a digital memory of a scene that is now three decades old.

    Since our inception in 2015, open source and free software values are at the core of our commitment. We release everything we work on under OSS licenses (or in the Public Domain), maintaining a strong non-profit approach. Even if we reshare and give exposure to commercial products related to gbdev, we don’t get any cash from any of the involved companies and we don’t sponsor or endorse any particular release or publisher. No referral links are ever shared through our channels.

    Our expenses are entirely sustained by voluntary contributions (for which donators don’t get any benefit) and sponsorships (such as the DigitalOcean one). Everything is tracked trasparently on our OpenCollective.

    While a core team of maintainers is behind every project, we welcome any type of contribution, from feedback to participation in Request For Comments threads. Check the bottom of this page to learn how to join our community.

    Best year yet, for the 4th year in a row

    2021 was a huge success for gbdev. The Game Boy scene was never this alive and flourishing, with an unprecedented number of releases. From the incredible gbcompo21 (for which we are preparing a dedicated issue of this newsletter) to the number of new releases of our projects, we enjoyed the most traffic we ever saw, for the fourth year in a row.

    New guide on choosing development tools

    We finished revamping a quite comprehensive guide on how to choose tools for Game Boy, giving an overview on the different available approaches to developing homebrews for the grey brick.

    https://gbdev.io/guides/tools.html

    Homebrew Hub 2.0

    Homebrew Hub is a community-led attempt to collect, archive and preserve every unofficial game and homebrew released for Game Boy produced through decades of passionate work. Every entry , with its metadata and related assets is exposed through an API available to everyone.

    We started a complete rewrite of the backend and the frontend software behind Homebrew Hub. Originally built with Express in 2016 the codebase started to show its age… The new backend, powered by Django, will offer a full Restful API to access all the games, assets, metadata and ROMs we have in the JSON database. The new frontend is powered by the binjgb emulator, running in the browser via WebAssembly. This will bring better emulation accuracy and more features!

    New games on the Homebrew Hub database

    The Homebrew Hub database is community maintained. Everyone can contribute adding a game or writing a scraper to mass-import games on the website.

    In parallel to the rewrite, a lot of stuff is happening on the database, too:

    New CI scripts are now in place to detect potentially duplicated entries, calculating checksums of assets. The pipeline will now run on Pull Requests and also validate the submitted metadata and the referenced files, to aid contributors.

    The following new entries have been added: Crystal Lake, Grub Glide, Labirinth, Bannerprint and Europa Rescue (thanks to N•I•L, v666, reini1305, Exetric and godai78).

    All the 20 shortlisted entries from the GB Competition 2021 were also added and are ready to play.

    dag7dev worked on new scrapers, cleaned up a bunch of entries metadata and merged some duplicates. Hundreds of new homebrews are now available thanks to his work!

    A new game metadata schema is in preparation, enabling game translations and specific tags for hardware support (e.g. gb-printer, gb-camera, ..).

    The total number of games is now 748! Go play with them!

    New RGBDS website and documentation

    RGBDS is the standard toolchain for developing homebrew Game Boy programs in Assembly. First released in 1997, it’s now enjoying renewed community attention.

    A new version of the RGBDS website, providing downloads, build instructions and full documentation is now work in progress.

    From a statically built HTML version we are migrating to a solution based on Docusaurus, a documentation framework powered by React.

    RGBGFX rewrite incoming

    The rgbgfx program, part of the RGBDS suite, converts PNG images into the Nintendo Game Boy’s planar tile format.

    A new version is being rewritten in modern C++17, enabling a series of improvements such as better error messages (more explicit), proper transparency support, explicit palette specification and proper 8×16 support.

    GBDK 4.0.5 and 4.0.6

    GBDK is a C compiler, assembler, linker and set of libraries for the Z80 like Nintendo Gameboy.

    Our friends over at the GBDK team worked on a big release, the first adding more targets to the toolchain: GBDK can now compile to Sega Master System/Sega Game Gear and the Analogue Pocket.

    4.0.6 shipped support for the Mega Duck, too!

    Other notable features added in 2021 were:

    • Metasprite API and conversion tool
    • Auto ROM bank assignment and packing
    • Compression API and console tool

    More information can be found in the release notes.

    GBDK Tutorials

    For a long time now the main GBDK tutorials online have been mostly outdated and based on the 20 year old version GBDK but this is now changing: Larold is working on a series of tutorials where they break down the Game Boy game creation process into multiple high-level steps.

    https://laroldsjubilantjunkyard.com/tutorials/

    GB Studio 3 is out

    GB Studio is a quick and easy to use drag and drop retro game creator for the Game Boy. No programming required. Here are some of the highlights from the new release:

    • Improved UI for adding Events
    • Math Expressions
    • Large Sprites
    • Sprite Editor
    • Animation States
    • New Music Engine (hUGETracker)
    • Music Editor
    • Multiple Save Slots
    • Parallax Scrolling
    • Super Game Boy Borders
    • Multiple Fonts

    You can learn more from the dedicated articleopen in new window on GB Studio Central.

    Contributions to other (non-gbdev) projects

    mdbook is the wonderful Rust tool we use to render Pan Docs. Apart from overloading it with custom features, we also contribute upstream.

    ISSOtm recently prepared a PR to add a feature for generating sitemaps, which we hope will get some attention from the upstream maintainers soon.

    https://github.com/rust-lang/mdBook/pull/1618

    Wrapping up and feedback

    Thanks for reading! That’s all for this issue. We hope you’re having fun developing or playing games for Game Boy. As always, your contributions to our initiatives are appreciated. You’re welcome to browse around our GitHub organisation or join our Discord server to see what everyone is working on.

    If you still want more gbdev, our Twitter feed provides a curated (and frequent) collection of new releases, WIP content and news about our projects.

    If you have any feedback, want to send us some gbdev links or comment on any of the topics brought up in this issue (or on the newsletter itself) feel free to reach us.

    Next Issue

    This digest won’t try to respect an actual schedule but will rather go online when enough quality content is ready. On the next issue, we will continue to shed some light on the incredible accomplishments we made in 2021, such as the GB Competition 2021, showing you how some games enjoyed continued support and physical releases. We will also tell you how we managed to make Pan Docs this good and what’s new in the latest RGBDS releases.

    If you’d like to send us some gbdev content you found interesting and you think would fit this newsletter, feel free to reach out.

    Special thanks to bbbbbr, ISSOtm, toxa and Emi Paternostro.

    - + diff --git a/privacypolicy.html b/privacypolicy.html index 3757a24..c3a2ff7 100644 --- a/privacypolicy.html +++ b/privacypolicy.html @@ -36,10 +36,10 @@ })(); Privacy Policy | gbdev.io - +

    Privacy Policy

    We use a self hosted instance of Matomoopen in new window, a free and open source web analytics application to track online visits to our websites (*.gbdev.io, *.gbadev.net), in order to better understand which audience we serve and what content is consulted.

    How

    • Visitors' IP addresses are anonymized. The last byte is masked and fully qualified addressess never reach our analytics software.
    • User IDs are replaced by pseudonyms to avoid directly storing and displaying personally identifiable information.
    • We ignore any existing tracking cookie and our tracking DOES NOT use any cookie. (See also: What are cookies?open in new window)
    • We honor your browser "I do not want to be tracked" preference.
    • Data is aggregated and reports are compiled. Raw logs are regularly cleaned up.

    You can opt out by clicking hereopen in new window.

    - + diff --git a/resources.html b/resources.html index 1f6b5ba..ee67048 100644 --- a/resources.html +++ b/resources.html @@ -36,10 +36,10 @@ })(); Resources | gbdev.io - +

    Awesome Game Boy Development

    A curated list of awesome Game Boy (Color) Development resources, tools, docs, related projects and homebrews. Inspired by the awesome list thing.

    This project is open source and community-lead. Come contribute!


    Introduction

    The Game Boy, a hardware autopsyopen in new window



    The Ultimate Game Boy Talkopen in new window



    Disambiguation

    Game Boy Advance

    Game Boy Advance development is covered by another project, the awesome-GBAdevopen in new window list. GBA, however, can run GB/GBC games. It does so in a slightly different way compared to native hardware. This is covered in the Emulator Development section of this list.

    Game Boy Color and Super Game Boy

    This list is focused on the original (1989) Game Boy (DMG), the Game Boy Color (GBC) and Super Game Boy (SGB) are very similar systems, with a few important distinctions, such as:

    • Different hardware specifications
    • Specific hardware and software features
    • Specific registers
    • Specific bugs, quirks and exploitable behaviours

    If you aim to develop your software for SGB or GBC, or you want to know how it runs on the other systems, you may want to take advantage and adapt to these differences, check the Game Boy Color category and look for specific references to GBC/CGB and SGB.

    Documentation

    Opcodes

    Game Boy Color

    Hardware

    Peripherals

    Cartridges

    Custom cartridges

    Misc

    Emulator Development

    Testing

    Software Development

    The Choosing tools for Game Boy developmentopen in new window essay provides an overview of the available development tools for Game Boy.

    Assemblers

    Compilers

    Experimental/Proof of Concepts

    Emulators

    Complete list of open source emulators

    Tools

    Engines

    Development tools

    Graphics utilities

    Hardware and ROM utilities

    Music drivers and trackers

    Programming

    Guides, tutorials and tools to develop software for Game Boy using the development toolchains described in the Software Development chapter.

    ASM

    Sources

    Fragments of code, effects, proof of concepts and generally non complete games.

    Timings

    Boilerplates and libraries

    Syntax highlighting packages

    C

    Homebrews

    Complete and open source games.

    • Homebrew Hubopen in new window - A community-led attempt to collect, archive and preserve every unlicensed and homebrew game released for Game Boy. Entries are playable online.

    ASM

    C

    GB Studio

    Demos

    Reverse Engineering

    Game Disassemblies

    Game Boy Camera

    Retrieving images

    Game Boy Printer emulation (e.g. to retrieve images from the camera):

    Changing the camera's behavior

    Methods to improve and/or manipulate the camera's quality and behavior:

    Post processing

    Directories

    Websites

    - +