From 36ac7b0cd6d71487a75b276a0a1a606bcda0514d Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 22 Oct 2026 13:13:52 +0200 Subject: [PATCH] feat: split the heavy site pages A manufacturer page over 500 KB of Markdown becomes a summary: its largest consoles move to pages of their own, cut into parts when one console is still too large, and every console keeps its heading there. MAME's 1,564 cards move to four pages, its page keeping a row per entry with the card's old anchor. RetroDECK's arcade list gets its own page. site.js follows a moved card by content or by its row. The largest page drops from 10.5 MB to 0.88 MB. Emulator groups of the navigation open by initial (65 KB to 41 KB before the content). File cards are level 3 under a level 2, and the hook keeps the table of contents of card pages to level 2: platform pages no longer list every system id. Key/value cards name their columns. The sweep runs before the decoration, which kept every page no generator wrote any more. --- docs_assets/site.js | 16 +- mkdocs.yml | 1188 +++++++++++++++++++------------------ scripts/generate_site.py | 627 +++++++++++++++----- scripts/mkdocs_hooks.py | 20 + scripts/siterender.py | 66 ++- tests/test_site_render.py | 4 +- tests/test_site_weight.py | 168 ++++++ wiki/testing-guide.md | 2 +- 8 files changed, 1362 insertions(+), 729 deletions(-) create mode 100644 tests/test_site_weight.py diff --git a/docs_assets/site.js b/docs_assets/site.js index aacaaa24..33548400 100644 --- a/docs_assets/site.js +++ b/docs_assets/site.js @@ -238,10 +238,20 @@ }; // A file card moved to another page keeps its address: an id of the form - // sha1-<12 hex> that this page does not hold is looked up by content. + // sha1-<12 hex> that this page does not hold is looked up by content, and + // an emulator card listed in the table of a split page opens its page. const followMovedCard = () => { - const match = /^#sha1-([0-9a-f]{12})$/.exec(window.location.hash); - if (!match || document.getElementById(`sha1-${match[1]}`)) return; + const id = decodeURIComponent(window.location.hash.slice(1)); + if (!id) return; + const target = document.getElementById(id); + const row = target?.closest(".rb-card-index tr"); + const link = row?.querySelector("a[href]"); + if (link) { + window.location.replace(link.href); + return; + } + const match = /^sha1-([0-9a-f]{12})$/.exec(id); + if (!match || target) return; window.location.replace(new URL(`files/?sha1=${match[1]}`, siteRoot())); }; diff --git a/mkdocs.yml b/mkdocs.yml index 2bbc5ee9..f38f336f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,19 +84,17 @@ markdown_extensions: - tables - toc: permalink: true - # File cards are level 4 headings: the search lands on them, and a - # page of a hundred cards keeps a readable table of contents. + # Level 3 is the wiki's subsections. On pages of file cards, also level + # 3, the hook keeps the table of contents to level 2. toc_depth: 3 - pymdownx.details - pymdownx.highlight: anchor_linenums: true - pymdownx.inlinehilite - pymdownx.keys -- pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format +# No mermaid fence: Material drew it in the browser with a script from a +# CDN. Diagrams are SVG files written by scripts/sitediagrams.py. +- pymdownx.superfences - pymdownx.tabbed: alternate_style: true plugins: @@ -245,587 +243,613 @@ nav: - 2600.emu: emulators/2600-emu.md - 3dSen: emulators/3dsen.md - A to C: - - a5200: emulators/a5200.md - - A7800: emulators/a7800.md - - Abuse: emulators/abuse.md - - ACE-DL: emulators/ace-dl.md - - advanced_drastic: emulators/advanced_drastic.md - - AdvanceMAME: emulators/advancemame.md - - AdvanceMAME 0.94: emulators/advmame-0.94.md - - AdvanceMAME 1.4: emulators/advmame-1.4.md - - Adventure Game Studio: emulators/ags.md - - AetherSX2: emulators/aethersx2.md - - Aleph One: emulators/alephone.md - - Altirra: emulators/altirra.md - - amiarcadia: emulators/amiarcadia.md - - Amiberry: emulators/amiberry.md - - AppleWin: emulators/applewin.md - - aPS3e: emulators/aps3e.md - - ArcadeDuck: emulators/arcadeduck.md - - ArcadeFlashWeb: emulators/arcadeflashweb.md - - Ardens: emulators/ardens.md - - Arduous: emulators/arduous.md - - ares: emulators/ares.md - - ARMSX1: emulators/armsx1.md - - ARMSX2: emulators/armsx2.md - - Atari800: emulators/atari800.md - - aX360e: emulators/ax360e.md - - Azahar: emulators/azahar.md - - AzaharPlus: emulators/azaharplus.md - - b2: emulators/b2.md - - Basilisk II: emulators/basiliskii.md - - BBKEmu: emulators/bbkemu.md - - beebem: emulators/beebem.md - - Beetle GBA (Mednafen): emulators/beetle_gba.md - - Beetle Lynx (Mednafen Lynx): emulators/beetle_lynx.md - - Beetle NGP (Mednafen Neo Geo Pocket): emulators/beetle_ngp.md - - Beetle PC-FX (Mednafen): emulators/beetle_pcfx.md - - Beetle PCE (Mednafen PCE): emulators/beetle_pce.md - - Beetle PSX (Mednafen PSX): emulators/beetle_psx.md - - Beetle VB (Mednafen Virtual Boy): emulators/beetle_vb.md - - Beetle WonderSwan (Mednafen WonderSwan): emulators/beetle_wswan.md - - beetle_saturn: emulators/beetle_saturn.md - - BennuGD: emulators/bennugd.md - - BennuGD monolithic (bgdi): emulators/bennugd-monolithic.md - - Bermuda Syndrome: emulators/bsyndrome.md - - Bermuda Syndrome (bs): emulators/bermuda.md - - BigPEmu: emulators/bigpemu.md - - BizHawk: emulators/bizhawk.md - - bk-emulator: emulators/bk.md - - BlastEm: emulators/blastem.md - - blueMSX: emulators/bluemsx.md - - bnes: emulators/bnes.md - - boom3: emulators/boom3.md - - Boytacean: emulators/boytacean.md - - bsnes: emulators/bsnes.md - - bsnes 2014: emulators/bsnes2014.md - - bsnes C++98: emulators/bsnes_cplusplus98.md - - bsnes-hd beta: emulators/bsnes_hd_beta.md - - bsnes-jg: emulators/bsnes-jg.md - - bsnes-mercury: emulators/bsnes_mercury.md - - BStone: emulators/bstone.md - - C-Dogs SDL: emulators/cdogs.md - - C64.emu: emulators/c64-emu.md - - Cannonball: emulators/cannonball.md - - CaPriCe Forever: emulators/capriceforever.md - - Caprice32: emulators/cap32.md - - CapriceRPI: emulators/capricerpi.md - - CatacombGL: emulators/catacombgl.md - - ccleste: emulators/ccleste.md - - CDi 2015: emulators/cdi2015.md - - Cemu: emulators/cemu.md - - Chihiro-DS: emulators/chihiro-ds.md - - ChimeraSNES: emulators/chimerasnes.md - - Chocolate Doom: emulators/chocolate-doom.md - - Citra: emulators/citra.md - - Citra 2018: emulators/citra2018.md - - Citra Canary: emulators/citra_canary.md - - Citra MMJ: emulators/citra-mmj.md - - Citron: emulators/citron.md - - Clock Signal (CLK): emulators/clk.md - - ClownMDEmu: emulators/clownmdemu.md - - ColEm: emulators/colem.md - - Commander Genius: emulators/cgenius.md - - CoolbarEmu: emulators/coolbaremu.md - - CoolCV: emulators/coolcv.md - - corsixth: emulators/corsixth.md - - CPCemu: emulators/cpcemu.md - - CrocoDS: emulators/crocods.md - - Cruzes: emulators/cruzes.md - - CSpect: emulators/cspect.md - - Cxbx-Reloaded: emulators/cxbx-reloaded.md - - Cxbx-Reloaded (31ff15b): emulators/cxbx-reloaded-2023.md + - A: + - a5200: emulators/a5200.md + - A7800: emulators/a7800.md + - Abuse: emulators/abuse.md + - ACE-DL: emulators/ace-dl.md + - advanced_drastic: emulators/advanced_drastic.md + - AdvanceMAME: emulators/advancemame.md + - AdvanceMAME 0.94: emulators/advmame-0.94.md + - AdvanceMAME 1.4: emulators/advmame-1.4.md + - Adventure Game Studio: emulators/ags.md + - AetherSX2: emulators/aethersx2.md + - Aleph One: emulators/alephone.md + - Altirra: emulators/altirra.md + - amiarcadia: emulators/amiarcadia.md + - Amiberry: emulators/amiberry.md + - AppleWin: emulators/applewin.md + - aPS3e: emulators/aps3e.md + - ArcadeDuck: emulators/arcadeduck.md + - ArcadeFlashWeb: emulators/arcadeflashweb.md + - Ardens: emulators/ardens.md + - Arduous: emulators/arduous.md + - ares: emulators/ares.md + - ARMSX1: emulators/armsx1.md + - ARMSX2: emulators/armsx2.md + - Atari800: emulators/atari800.md + - aX360e: emulators/ax360e.md + - Azahar: emulators/azahar.md + - AzaharPlus: emulators/azaharplus.md + - B: + - b2: emulators/b2.md + - Basilisk II: emulators/basiliskii.md + - BBKEmu: emulators/bbkemu.md + - beebem: emulators/beebem.md + - Beetle GBA (Mednafen): emulators/beetle_gba.md + - Beetle Lynx (Mednafen Lynx): emulators/beetle_lynx.md + - Beetle NGP (Mednafen Neo Geo Pocket): emulators/beetle_ngp.md + - Beetle PC-FX (Mednafen): emulators/beetle_pcfx.md + - Beetle PCE (Mednafen PCE): emulators/beetle_pce.md + - Beetle PSX (Mednafen PSX): emulators/beetle_psx.md + - Beetle VB (Mednafen Virtual Boy): emulators/beetle_vb.md + - Beetle WonderSwan (Mednafen WonderSwan): emulators/beetle_wswan.md + - beetle_saturn: emulators/beetle_saturn.md + - BennuGD: emulators/bennugd.md + - BennuGD monolithic (bgdi): emulators/bennugd-monolithic.md + - Bermuda Syndrome: emulators/bsyndrome.md + - Bermuda Syndrome (bs): emulators/bermuda.md + - BigPEmu: emulators/bigpemu.md + - BizHawk: emulators/bizhawk.md + - bk-emulator: emulators/bk.md + - BlastEm: emulators/blastem.md + - blueMSX: emulators/bluemsx.md + - bnes: emulators/bnes.md + - boom3: emulators/boom3.md + - Boytacean: emulators/boytacean.md + - bsnes: emulators/bsnes.md + - bsnes 2014: emulators/bsnes2014.md + - bsnes C++98: emulators/bsnes_cplusplus98.md + - bsnes-hd beta: emulators/bsnes_hd_beta.md + - bsnes-jg: emulators/bsnes-jg.md + - bsnes-mercury: emulators/bsnes_mercury.md + - BStone: emulators/bstone.md + - C: + - C-Dogs SDL: emulators/cdogs.md + - C64.emu: emulators/c64-emu.md + - Cannonball: emulators/cannonball.md + - CaPriCe Forever: emulators/capriceforever.md + - Caprice32: emulators/cap32.md + - CapriceRPI: emulators/capricerpi.md + - CatacombGL: emulators/catacombgl.md + - ccleste: emulators/ccleste.md + - CDi 2015: emulators/cdi2015.md + - Cemu: emulators/cemu.md + - Chihiro-DS: emulators/chihiro-ds.md + - ChimeraSNES: emulators/chimerasnes.md + - Chocolate Doom: emulators/chocolate-doom.md + - Citra: emulators/citra.md + - Citra 2018: emulators/citra2018.md + - Citra Canary: emulators/citra_canary.md + - Citra MMJ: emulators/citra-mmj.md + - Citron: emulators/citron.md + - Clock Signal (CLK): emulators/clk.md + - ClownMDEmu: emulators/clownmdemu.md + - ColEm: emulators/colem.md + - Commander Genius: emulators/cgenius.md + - CoolbarEmu: emulators/coolbaremu.md + - CoolCV: emulators/coolcv.md + - corsixth: emulators/corsixth.md + - CPCemu: emulators/cpcemu.md + - CrocoDS: emulators/crocods.md + - Cruzes: emulators/cruzes.md + - CSpect: emulators/cspect.md + - Cxbx-Reloaded: emulators/cxbx-reloaded.md + - Cxbx-Reloaded (31ff15b): emulators/cxbx-reloaded-2023.md - D to F: - - D.Smile: emulators/dsmile.md - - DaedalusX64: emulators/daedalusx64.md - - Daphne: emulators/daphne.md - - DarkPlaces: emulators/darkplaces.md - - Demul: emulators/demul.md - - DeSmuME: emulators/desmume.md - - DeSmuME 2015: emulators/desmume2015.md - - devilutionx: emulators/devilutionx.md - - DGen/SDL: emulators/dgen.md - - dhewm3: emulators/dhewm3.md - - DICE: emulators/dice.md - - DingooEmu: emulators/dingooemu.md - - Dinothawr: emulators/dinothawr.md - - DirectXBox: emulators/directxbox.md - - DirkSimple: emulators/dirksimple.md - - Dolphin: emulators/dolphin.md - - Dolphin Launcher: emulators/dolphin_launcher.md - - Dolphin MMJR: emulators/dolphin-mmjr.md - - Dolphin MMJR2: emulators/dolphin-mmjr2.md - - DOSBox: emulators/dosbox.md - - DOSBox (SDL2 fork): emulators/dosbox-sdl2.md - - DOSBox Pure: emulators/dosbox_pure.md - - DOSBox Pure Unleashed: emulators/dosbox-pure-unleashed.md - - DOSBox Staging: emulators/dosbox-staging.md - - DOSBox-core: emulators/dosbox_core.md - - DOSBox-SVN: emulators/dosbox_svn.md - - DOSBox-SVN CE: emulators/dosbox_svn_ce.md - - DOSBox-X: emulators/dosbox-x.md - - DoubleCherryGB: emulators/doublecherrygb.md - - doukutsu-rs: emulators/doukutsu_rs.md - - DraStic: emulators/drastic.md - - DREAMM: emulators/dreamm.md - - DroidArcadia: emulators/droidarcadia.md - - dsda-doom: emulators/dsda-doom.md - - DSperate: emulators/dsperate.md - - DuckStation: emulators/duckstation.md - - DuckStation (legacy): emulators/duckstation-legacy.md - - Dusklight: emulators/dusklight.md - - dxx-rebirth: emulators/dxx-rebirth.md - - EasyRPG Player: emulators/easyrpg.md - - ECWolf: emulators/ecwolf.md - - Eden: emulators/eden.md - - EDuke32: emulators/eduke32.md - - EightyOne: emulators/81.md - - EightyOne (Recalbox): emulators/eightyone.md - - eka2l1: emulators/eka2l1.md - - EmuCoreV: emulators/emucorev.md - - EmuCoreX: emulators/emucorex.md - - EmuCV: emulators/emucv.md - - EmuSCV: emulators/emuscv.md - - emux (CHIP-8): emulators/emux_chip8.md - - emux (Game Boy): emulators/emux_gb.md - - emux (NES): emulators/emux_nes.md - - emux (SMS): emulators/emux_sms.md - - ep128emu-core: emulators/ep128emu.md - - ep128emu_core: emulators/ep128emu_core.md - - ePSXe: emulators/epsxe.md - - ET Legacy: emulators/etlegacy.md - - Eternal Computer: emulators/eternal.md - - Exel-Hence: emulators/exel-hence.md - - FAKE-08: emulators/fake08.md - - fallout1-ce: emulators/fallout1-ce.md - - fallout2-ce: emulators/fallout2-ce.md - - FB Alpha 2012: emulators/fbalpha2012.md - - FB Alpha 2012 CPS-1: emulators/fbalpha2012_cps1.md - - FB Alpha 2012 CPS-2: emulators/fbalpha2012_cps2.md - - FB Alpha 2012 CPS-3: emulators/fbalpha2012_cps3.md - - FB Alpha 2012 Neo Geo: emulators/fbalpha2012_neogeo.md - - FB Alpha 2019: emulators/fbalpha2019.md - - FBZX: emulators/fbzx.md - - FCEUmm: emulators/fceumm.md - - FCEUmm Mod: emulators/fceumm_mod.md - - fheroes2: emulators/fheroes2.md - - FinalBurn Neo: emulators/fbneo.md - - FinalBurn Neo (CPS-1/CPS-2): emulators/fbneo_cps12.md - - FinalBurn Neo (Neo Geo): emulators/fbneo_neogeo.md - - fixGB: emulators/fixgb.md - - fixNES: emulators/fixnes.md - - Flycast: emulators/flycast.md - - Flycast 2021: emulators/flycast2021.md - - Flycast 2022 Low-End: emulators/flycast2021le.md - - Flycast Dojo: emulators/flycast-dojo.md - - fMSX: emulators/fmsx.md - - FPse: emulators/fpse.md - - FPseNG: emulators/fpse-ng.md - - FreeChaF: emulators/freechaf.md - - FreeIntv: emulators/freeintv.md - - FreeJ2ME: emulators/freej2me.md - - FreeJ2ME-Plus: emulators/freej2me_plus.md - - Frodo: emulators/frodo.md - - Frotz: emulators/frotz.md - - FS-UAE: emulators/fsuae.md - - FS-UAE 3.1: emulators/fs-uae.md - - Fuse: emulators/fuse.md - - future-pinball: emulators/future-pinball.md - - future-pinball-fploader: emulators/future-pinball-fploader.md + - D: + - D.Smile: emulators/dsmile.md + - DaedalusX64: emulators/daedalusx64.md + - Daphne: emulators/daphne.md + - DarkPlaces: emulators/darkplaces.md + - Demul: emulators/demul.md + - DeSmuME: emulators/desmume.md + - DeSmuME 2015: emulators/desmume2015.md + - devilutionx: emulators/devilutionx.md + - DGen/SDL: emulators/dgen.md + - dhewm3: emulators/dhewm3.md + - DICE: emulators/dice.md + - DingooEmu: emulators/dingooemu.md + - Dinothawr: emulators/dinothawr.md + - DirectXBox: emulators/directxbox.md + - DirkSimple: emulators/dirksimple.md + - Dolphin: emulators/dolphin.md + - Dolphin Launcher: emulators/dolphin_launcher.md + - Dolphin MMJR: emulators/dolphin-mmjr.md + - Dolphin MMJR2: emulators/dolphin-mmjr2.md + - DOSBox: emulators/dosbox.md + - DOSBox (SDL2 fork): emulators/dosbox-sdl2.md + - DOSBox Pure: emulators/dosbox_pure.md + - DOSBox Pure Unleashed: emulators/dosbox-pure-unleashed.md + - DOSBox Staging: emulators/dosbox-staging.md + - DOSBox-core: emulators/dosbox_core.md + - DOSBox-SVN: emulators/dosbox_svn.md + - DOSBox-SVN CE: emulators/dosbox_svn_ce.md + - DOSBox-X: emulators/dosbox-x.md + - DoubleCherryGB: emulators/doublecherrygb.md + - doukutsu-rs: emulators/doukutsu_rs.md + - DraStic: emulators/drastic.md + - DREAMM: emulators/dreamm.md + - DroidArcadia: emulators/droidarcadia.md + - dsda-doom: emulators/dsda-doom.md + - DSperate: emulators/dsperate.md + - DuckStation: emulators/duckstation.md + - DuckStation (legacy): emulators/duckstation-legacy.md + - Dusklight: emulators/dusklight.md + - dxx-rebirth: emulators/dxx-rebirth.md + - E: + - EasyRPG Player: emulators/easyrpg.md + - ECWolf: emulators/ecwolf.md + - Eden: emulators/eden.md + - EDuke32: emulators/eduke32.md + - EightyOne: emulators/81.md + - EightyOne (Recalbox): emulators/eightyone.md + - eka2l1: emulators/eka2l1.md + - EmuCoreV: emulators/emucorev.md + - EmuCoreX: emulators/emucorex.md + - EmuCV: emulators/emucv.md + - EmuSCV: emulators/emuscv.md + - emux (CHIP-8): emulators/emux_chip8.md + - emux (Game Boy): emulators/emux_gb.md + - emux (NES): emulators/emux_nes.md + - emux (SMS): emulators/emux_sms.md + - ep128emu-core: emulators/ep128emu.md + - ep128emu_core: emulators/ep128emu_core.md + - ePSXe: emulators/epsxe.md + - ET Legacy: emulators/etlegacy.md + - Eternal Computer: emulators/eternal.md + - Exel-Hence: emulators/exel-hence.md + - F: + - FAKE-08: emulators/fake08.md + - fallout1-ce: emulators/fallout1-ce.md + - fallout2-ce: emulators/fallout2-ce.md + - FB Alpha 2012: emulators/fbalpha2012.md + - FB Alpha 2012 CPS-1: emulators/fbalpha2012_cps1.md + - FB Alpha 2012 CPS-2: emulators/fbalpha2012_cps2.md + - FB Alpha 2012 CPS-3: emulators/fbalpha2012_cps3.md + - FB Alpha 2012 Neo Geo: emulators/fbalpha2012_neogeo.md + - FB Alpha 2019: emulators/fbalpha2019.md + - FBZX: emulators/fbzx.md + - FCEUmm: emulators/fceumm.md + - FCEUmm Mod: emulators/fceumm_mod.md + - fheroes2: emulators/fheroes2.md + - FinalBurn Neo: emulators/fbneo.md + - FinalBurn Neo (CPS-1/CPS-2): emulators/fbneo_cps12.md + - FinalBurn Neo (Neo Geo): emulators/fbneo_neogeo.md + - fixGB: emulators/fixgb.md + - fixNES: emulators/fixnes.md + - Flycast: emulators/flycast.md + - Flycast 2021: emulators/flycast2021.md + - Flycast 2022 Low-End: emulators/flycast2021le.md + - Flycast Dojo: emulators/flycast-dojo.md + - fMSX: emulators/fmsx.md + - FPse: emulators/fpse.md + - FPseNG: emulators/fpse-ng.md + - FreeChaF: emulators/freechaf.md + - FreeIntv: emulators/freeintv.md + - FreeJ2ME: emulators/freej2me.md + - FreeJ2ME-Plus: emulators/freej2me_plus.md + - Frodo: emulators/frodo.md + - Frotz: emulators/frotz.md + - FS-UAE: emulators/fsuae.md + - FS-UAE 3.1: emulators/fs-uae.md + - Fuse: emulators/fuse.md + - future-pinball: emulators/future-pinball.md + - future-pinball-fploader: emulators/future-pinball-fploader.md - G to L: - - galaksija: emulators/galaksija.md - - GAM4980: emulators/gam4980.md - - Gambatte: emulators/gambatte.md - - Game & Watch: emulators/gw.md - - GameTank: emulators/gametank.md - - Gargoyle: emulators/gargoyle.md - - GBA.emu: emulators/gba-emu.md - - GBC.emu: emulators/gbc-emu.md - - Gearboy: emulators/gearboy.md - - Gearcoleco: emulators/gearcoleco.md - - Geargrafx: emulators/geargrafx.md - - Gearlynx: emulators/gearlynx.md - - Gearsystem: emulators/gearsystem.md - - Geartowns: emulators/geartowns.md - - GemRB: emulators/gemrb.md - - Genesis Plus GX: emulators/genesis_plus_gx.md - - Genesis Plus GX Expanded: emulators/genesis_plus_gx_expanded.md - - Genesis Plus GX Wide: emulators/genesis_plus_gx_wide.md - - Geolith: emulators/geolith.md - - Ghostship: emulators/ghostship.md - - GnGeo-Pi: emulators/gngeopi.md - - Gopher2600: emulators/gopher2600.md - - gopher64: emulators/gopher64.md - - gpSP: emulators/gpsp.md - - GroovyMAME: emulators/groovymame.md - - GSplus: emulators/gsplus.md - - GSplus (legacy): emulators/gsplus-legacy.md - - GZDoom: emulators/gzdoom.md - - hakuX: emulators/hakux.md - - Handy: emulators/handy.md - - Hatari: emulators/hatari.md - - Hatari 2014: emulators/hatari2014.md - - hatariB: emulators/hatarib.md - - HBMAME (Homebrew MAME): emulators/hbmame.md - - higan (SFC Accuracy): emulators/higan_sfc.md - - hode: emulators/hode.md - - Holani: emulators/holani.md - - Hurrican: emulators/hurrican.md - - Hydra Castle Labyrinth: emulators/hcl.md - - Hypseus Singe: emulators/hypseus-singe.md - - idTech4A++: emulators/idtech4a++.md - - Ikemen GO: emulators/ikemen.md - - iNES: emulators/ines.md - - Infinity: emulators/infinity.md - - Ion Fury: emulators/fury.md - - ioquake3: emulators/ioquake3.md - - ioRTCW: emulators/iortcw.md - - IrataJaguar: emulators/iratajaguar.md - - IroGB: emulators/irogb.md - - Ishiiruka: emulators/ishiiruka.md - - izapple2: emulators/izapple2.md - - J2ME Loader: emulators/j2me-loader.md - - JAXE: emulators/jaxe.md - - Jazz² Resurrection: emulators/jazz2-native.md - - jgenesis: emulators/jgenesis.md - - JL-Mod: emulators/jl-mod.md - - JollyCV: emulators/jollycv.md - - Julius: emulators/julius.md - - Jynx: emulators/jynx.md - - jzIntv: emulators/jzintv.md - - Kega Fusion: emulators/kega-fusion.md - - KEGS: emulators/kegs.md - - KEmulator nnmod: emulators/kemulator.md - - Kenji-NX: emulators/kenji-nx.md - - Kronos: emulators/kronos.md - - Lexaloffle: emulators/lexaloffle.md - - lightspark: emulators/lightspark.md - - Lime3DS: emulators/lime3ds.md - - LinApple: emulators/linapple.md - - Lindbergh Loader: emulators/lindbergh-loader.md - - Linkboy: emulators/linkboy.md - - Linux Loader: emulators/linuxloader.md - - LowRes NX: emulators/lowresnx.md - - LRPS2: emulators/lrps2.md - - Lynx.emu: emulators/lynx-emu.md - - LZDoom: emulators/lzdoom.md + - G: + - galaksija: emulators/galaksija.md + - GAM4980: emulators/gam4980.md + - Gambatte: emulators/gambatte.md + - Game & Watch: emulators/gw.md + - GameTank: emulators/gametank.md + - Gargoyle: emulators/gargoyle.md + - GBA.emu: emulators/gba-emu.md + - GBC.emu: emulators/gbc-emu.md + - Gearboy: emulators/gearboy.md + - Gearcoleco: emulators/gearcoleco.md + - Geargrafx: emulators/geargrafx.md + - Gearlynx: emulators/gearlynx.md + - Gearsystem: emulators/gearsystem.md + - Geartowns: emulators/geartowns.md + - GemRB: emulators/gemrb.md + - Genesis Plus GX: emulators/genesis_plus_gx.md + - Genesis Plus GX Expanded: emulators/genesis_plus_gx_expanded.md + - Genesis Plus GX Wide: emulators/genesis_plus_gx_wide.md + - Geolith: emulators/geolith.md + - Ghostship: emulators/ghostship.md + - GnGeo-Pi: emulators/gngeopi.md + - Gopher2600: emulators/gopher2600.md + - gopher64: emulators/gopher64.md + - gpSP: emulators/gpsp.md + - GroovyMAME: emulators/groovymame.md + - GSplus: emulators/gsplus.md + - GSplus (legacy): emulators/gsplus-legacy.md + - GZDoom: emulators/gzdoom.md + - H: + - hakuX: emulators/hakux.md + - Handy: emulators/handy.md + - Hatari: emulators/hatari.md + - Hatari 2014: emulators/hatari2014.md + - hatariB: emulators/hatarib.md + - HBMAME (Homebrew MAME): emulators/hbmame.md + - higan (SFC Accuracy): emulators/higan_sfc.md + - hode: emulators/hode.md + - Holani: emulators/holani.md + - Hurrican: emulators/hurrican.md + - Hydra Castle Labyrinth: emulators/hcl.md + - Hypseus Singe: emulators/hypseus-singe.md + - I: + - idTech4A++: emulators/idtech4a++.md + - Ikemen GO: emulators/ikemen.md + - iNES: emulators/ines.md + - Infinity: emulators/infinity.md + - Ion Fury: emulators/fury.md + - ioquake3: emulators/ioquake3.md + - ioRTCW: emulators/iortcw.md + - IrataJaguar: emulators/iratajaguar.md + - IroGB: emulators/irogb.md + - Ishiiruka: emulators/ishiiruka.md + - izapple2: emulators/izapple2.md + - J: + - J2ME Loader: emulators/j2me-loader.md + - JAXE: emulators/jaxe.md + - Jazz² Resurrection: emulators/jazz2-native.md + - jgenesis: emulators/jgenesis.md + - JL-Mod: emulators/jl-mod.md + - JollyCV: emulators/jollycv.md + - Julius: emulators/julius.md + - Jynx: emulators/jynx.md + - jzIntv: emulators/jzintv.md + - K: + - Kega Fusion: emulators/kega-fusion.md + - KEGS: emulators/kegs.md + - KEmulator nnmod: emulators/kemulator.md + - Kenji-NX: emulators/kenji-nx.md + - Kronos: emulators/kronos.md + - L: + - Lexaloffle: emulators/lexaloffle.md + - lightspark: emulators/lightspark.md + - Lime3DS: emulators/lime3ds.md + - LinApple: emulators/linapple.md + - Lindbergh Loader: emulators/lindbergh-loader.md + - Linkboy: emulators/linkboy.md + - Linux Loader: emulators/linuxloader.md + - LowRes NX: emulators/lowresnx.md + - LRPS2: emulators/lrps2.md + - Lynx.emu: emulators/lynx-emu.md + - LZDoom: emulators/lzdoom.md - M to O: - - M2000: emulators/m2000.md - - M64Plus FZ: emulators/m64plus-fz.md - - MagicEngine: emulators/magicengine.md - - MAME: emulators/mame.md - - MAME 0.258: emulators/mame0258.md - - MAME 0.278: emulators/mame0278.md - - MAME 2000: emulators/mame2000.md - - MAME 2003: emulators/mame2003.md - - MAME 2003 Midway: emulators/mame2003_midway.md - - MAME 2003-Plus: emulators/mame2003_plus.md - - MAME 2009: emulators/mame2009.md - - MAME 2010: emulators/mame2010.md - - MAME 2014: emulators/mame2014.md - - MAME 2015: emulators/mame2015.md - - MAME 2016: emulators/mame2016.md - - MAME Arcade: emulators/mamearcade.md - - MAME MESS: emulators/mamemess.md - - MAME4ALL-Pi: emulators/mame4all.md - - MAME4droid (0.139u1): emulators/mame4droid.md - - MAME4droid 2024: emulators/mame4droid-2024.md - - Mandarine: emulators/mandarine.md - - Mariani: emulators/mariani.md - - MasterGear: emulators/mastergear.md - - MD.emu: emulators/md-emu.md - - Mednafen: emulators/mednafen.md - - Mednafen STV: emulators/mednafen_stv.md - - mednafen_gba: emulators/mednafen_gba.md - - mednafen_pce: emulators/mednafen_pce.md - - mednafen_pce_fast: emulators/mednafen_pce_fast.md - - mednafen_snes: emulators/mednafen_snes.md - - mednafen_supafaust: emulators/mednafen_supafaust.md - - mednafen_supergrafx: emulators/mednafen_supergrafx.md - - melonDS: emulators/melonds.md - - melonDS DS: emulators/melonds_ds.md - - melonDS Nightly: emulators/melonds-nightly.md - - Mesen: emulators/mesen.md - - mesen-s: emulators/mesen-s.md - - MesenCE: emulators/mesence.md - - MESS 2015: emulators/mess2015.md - - Meteor GBA: emulators/meteor.md - - MFME: emulators/mfme.md - - mGBA: emulators/mgba.md - - mGBA Splitscreen: emulators/mgba_splitscreen.md - - Mini vMac: emulators/minivmac.md - - Mini vMac 37: emulators/minivmac37.md - - mkxp-z: emulators/mkxp_z.md - - Model 2 Emulator: emulators/model2.md - - MojoZork: emulators/mojozork.md - - MSX.emu: emulators/msx-emu.md - - Mu: emulators/mu.md - - Mupen64Plus: emulators/mupen64plus.md - - Mupen64Plus (libretro, 2019): emulators/mupen64plus-libretro.md - - Mupen64Plus AE: emulators/mupen64plus-ae.md - - Mupen64Plus-Next: emulators/mupen64plus_next.md - - My Boy!: emulators/my-boy.md - - My OldBoy!: emulators/my-oldboy.md - - NanoBoyAdvance: emulators/nanoboyadvance.md - - Native32Emu: emulators/native32emu.md - - nekop2: emulators/nekop2.md - - NEO.emu: emulators/neo-emu.md - - NeoCD: emulators/neocd.md - - nes: emulators/nes.md - - NES.emu: emulators/nes-emu.md - - Nesoid: emulators/nesoid.md - - Nestopia UE: emulators/nestopia.md - - NetherSX2: emulators/nethersx2.md - - NetherSX2-Turnip: emulators/nethersx2-turnip.md - - NetherSX2-Turnip Classic: emulators/nethersx2-turnip-classic.md - - NGP.emu: emulators/ngp-emu.md - - NicaiEmu: emulators/nicaiemu.md - - no$gba: emulators/nosgba.md - - NooDS: emulators/noods.md - - NP2kai: emulators/np2kai.md - - np2pi: emulators/np2pi.md - - nSide (SFC Balanced): emulators/higan_sfc_balanced.md - - Nuance: emulators/nuance.md - - Numero: emulators/numero.md - - NXEngine: emulators/nxengine.md - - O2EM: emulators/o2em.md - - Oberon: emulators/oberon.md - - Omicron: emulators/omicron.md - - ONScripter: emulators/onscripter.md - - ONScripter Yuri: emulators/onsyuri.md - - openbor: emulators/openbor.md - - OpenGOAL: emulators/opengoal.md - - OpenJazz: emulators/openjazz.md - - openjk: emulators/openjk.md - - OpenJKDF2: emulators/openjkdf2.md - - OpenLara: emulators/openlara.md - - OpenMoHAA: emulators/openmohaa.md - - openMSX: emulators/openmsx.md - - OpenTTD: emulators/openttd.md - - OpenTyrian: emulators/opentyrian.md - - Opera (4DO): emulators/opera.md - - Oricutron: emulators/oricutron.md - - Osmose (RetroPie): emulators/osmose.md + - M: + - M2000: emulators/m2000.md + - M64Plus FZ: emulators/m64plus-fz.md + - MagicEngine: emulators/magicengine.md + - MAME: emulators/mame.md + - MAME 0.258: emulators/mame0258.md + - MAME 0.278: emulators/mame0278.md + - MAME 2000: emulators/mame2000.md + - MAME 2003: emulators/mame2003.md + - MAME 2003 Midway: emulators/mame2003_midway.md + - MAME 2003-Plus: emulators/mame2003_plus.md + - MAME 2009: emulators/mame2009.md + - MAME 2010: emulators/mame2010.md + - MAME 2014: emulators/mame2014.md + - MAME 2015: emulators/mame2015.md + - MAME 2016: emulators/mame2016.md + - MAME Arcade: emulators/mamearcade.md + - MAME MESS: emulators/mamemess.md + - MAME4ALL-Pi: emulators/mame4all.md + - MAME4droid (0.139u1): emulators/mame4droid.md + - MAME4droid 2024: emulators/mame4droid-2024.md + - Mandarine: emulators/mandarine.md + - Mariani: emulators/mariani.md + - MasterGear: emulators/mastergear.md + - MD.emu: emulators/md-emu.md + - Mednafen: emulators/mednafen.md + - Mednafen STV: emulators/mednafen_stv.md + - mednafen_gba: emulators/mednafen_gba.md + - mednafen_pce: emulators/mednafen_pce.md + - mednafen_pce_fast: emulators/mednafen_pce_fast.md + - mednafen_snes: emulators/mednafen_snes.md + - mednafen_supafaust: emulators/mednafen_supafaust.md + - mednafen_supergrafx: emulators/mednafen_supergrafx.md + - melonDS: emulators/melonds.md + - melonDS DS: emulators/melonds_ds.md + - melonDS Nightly: emulators/melonds-nightly.md + - Mesen: emulators/mesen.md + - mesen-s: emulators/mesen-s.md + - MesenCE: emulators/mesence.md + - MESS 2015: emulators/mess2015.md + - Meteor GBA: emulators/meteor.md + - MFME: emulators/mfme.md + - mGBA: emulators/mgba.md + - mGBA Splitscreen: emulators/mgba_splitscreen.md + - Mini vMac: emulators/minivmac.md + - Mini vMac 37: emulators/minivmac37.md + - mkxp-z: emulators/mkxp_z.md + - Model 2 Emulator: emulators/model2.md + - MojoZork: emulators/mojozork.md + - MSX.emu: emulators/msx-emu.md + - Mu: emulators/mu.md + - Mupen64Plus: emulators/mupen64plus.md + - Mupen64Plus (libretro, 2019): emulators/mupen64plus-libretro.md + - Mupen64Plus AE: emulators/mupen64plus-ae.md + - Mupen64Plus-Next: emulators/mupen64plus_next.md + - My Boy!: emulators/my-boy.md + - My OldBoy!: emulators/my-oldboy.md + - N: + - NanoBoyAdvance: emulators/nanoboyadvance.md + - Native32Emu: emulators/native32emu.md + - nekop2: emulators/nekop2.md + - NEO.emu: emulators/neo-emu.md + - NeoCD: emulators/neocd.md + - nes: emulators/nes.md + - NES.emu: emulators/nes-emu.md + - Nesoid: emulators/nesoid.md + - Nestopia UE: emulators/nestopia.md + - NetherSX2: emulators/nethersx2.md + - NetherSX2-Turnip: emulators/nethersx2-turnip.md + - NetherSX2-Turnip Classic: emulators/nethersx2-turnip-classic.md + - NGP.emu: emulators/ngp-emu.md + - NicaiEmu: emulators/nicaiemu.md + - no$gba: emulators/nosgba.md + - NooDS: emulators/noods.md + - NP2kai: emulators/np2kai.md + - np2pi: emulators/np2pi.md + - nSide (SFC Balanced): emulators/higan_sfc_balanced.md + - Nuance: emulators/nuance.md + - Numero: emulators/numero.md + - NXEngine: emulators/nxengine.md + - O: + - O2EM: emulators/o2em.md + - Oberon: emulators/oberon.md + - Omicron: emulators/omicron.md + - ONScripter: emulators/onscripter.md + - ONScripter Yuri: emulators/onsyuri.md + - openbor: emulators/openbor.md + - OpenGOAL: emulators/opengoal.md + - OpenJazz: emulators/openjazz.md + - openjk: emulators/openjk.md + - OpenJKDF2: emulators/openjkdf2.md + - OpenLara: emulators/openlara.md + - OpenMoHAA: emulators/openmohaa.md + - openMSX: emulators/openmsx.md + - OpenTTD: emulators/openttd.md + - OpenTyrian: emulators/opentyrian.md + - Opera (4DO): emulators/opera.md + - Oricutron: emulators/oricutron.md + - Osmose (RetroPie): emulators/osmose.md - P to R: - - P/EMU/SDL: emulators/piemu.md - - Panda3DS: emulators/panda3ds.md - - Parallel Launcher: emulators/parallel-launcher.md - - ParaLLEl N64: emulators/parallel_n64.md - - pce-emu: emulators/pce-emu.md - - PCEE2: emulators/pcee2.md - - PCem: emulators/pcem.md - - PCSX-ReARMed: emulators/pcsx_rearmed.md - - PCSX-ReARMed (standalone): emulators/pcsx_rearmed_standalone.md - - PCSX1: emulators/pcsx1.md - - PCSX2: emulators/pcsx2.md - - PCSX2 Legacy: emulators/pcsx2-legacy.md - - PCSX2x6: emulators/pcsx2x6.md - - PD777: emulators/pd777.md - - Perfect Dark (PC port): emulators/pdark.md - - Phoenix: emulators/phoenix.md - - Picocomputer 6502: emulators/rp6502.md - - PicoDrive: emulators/picodrive.md - - piece-emu: emulators/piece.md - - piFBA (fba2x): emulators/fba2x.md - - PiSNES: emulators/pisnes.md - - Pizza Boy GBA: emulators/pizza-boy-gba.md - - Pizza Boy GBC: emulators/pizza-boy-gbc.md - - Pizza Boy SC: emulators/pizza-boy-sc.md - - Plastic: emulators/plastic.md - - play: emulators/play.md - - PlaydiaEmu: emulators/playdiaemu.md - - PokeMini: emulators/pokemini.md - - pokketstation: emulators/pokketstation.md - - POM2: emulators/pom2.md - - Potator: emulators/potator.md - - PPSSPP: emulators/ppsspp.md - - PPSSPP 1.5.4: emulators/ppsspp-1.5.4.md - - PrBoom: emulators/prboom.md - - PrBoom+: emulators/prboom-plus.md - - PrimeHack: emulators/primehack.md - - project64: emulators/project64.md - - ProSystem: emulators/prosystem.md - - pSxMAME: emulators/psxmame.md - - PUAE (P-UAE): emulators/puae.md - - PUAE 2021: emulators/puae2021.md - - puNES: emulators/punes.md - - px68k: emulators/px68k.md - - px68k (SDL): emulators/px68k-sdl.md - - QEMU: emulators/qemu.md - - Quake 3 (Raspberry Pi): emulators/quake3.md - - QUASI88: emulators/quasi88.md - - QUASI88kai: emulators/quasi88kai.md - - QuickNES: emulators/quicknes.md - - RACE (Neo Geo Pocket): emulators/race.md - - radio: emulators/radio.md - - RAINE: emulators/raine.md - - Raze: emulators/raze.md - - RB5000: emulators/rb5000.md - - Real3DOPlayer: emulators/real3doplayer.md - - RealRTCW: emulators/realrtcw.md - - Redream: emulators/redream.md - - Reicast: emulators/reicast.md - - REminiscence: emulators/reminiscence.md - - Retro8: emulators/retro8.md - - RetroDream: emulators/retrodream.md - - RigelEngine: emulators/rigelengine.md - - Rosalie's Mupen GUI: emulators/rosalies-mupen-gui.md - - RPCS3: emulators/rpcs3.md - - rpix86: emulators/rpix86.md - - ruffle: emulators/ruffle.md - - Rust-DOS: emulators/rust_dos.md - - Rustation: emulators/rustation.md - - RustyNES: emulators/rustynes.md - - RVVM: emulators/rvvm.md - - Ryujinx: emulators/ryujinx.md + - P: + - P/EMU/SDL: emulators/piemu.md + - Panda3DS: emulators/panda3ds.md + - Parallel Launcher: emulators/parallel-launcher.md + - ParaLLEl N64: emulators/parallel_n64.md + - pce-emu: emulators/pce-emu.md + - PCEE2: emulators/pcee2.md + - PCem: emulators/pcem.md + - PCSX-ReARMed: emulators/pcsx_rearmed.md + - PCSX-ReARMed (standalone): emulators/pcsx_rearmed_standalone.md + - PCSX1: emulators/pcsx1.md + - PCSX2: emulators/pcsx2.md + - PCSX2 Legacy: emulators/pcsx2-legacy.md + - PCSX2x6: emulators/pcsx2x6.md + - PD777: emulators/pd777.md + - Perfect Dark (PC port): emulators/pdark.md + - Phoenix: emulators/phoenix.md + - Picocomputer 6502: emulators/rp6502.md + - PicoDrive: emulators/picodrive.md + - piece-emu: emulators/piece.md + - piFBA (fba2x): emulators/fba2x.md + - PiSNES: emulators/pisnes.md + - Pizza Boy GBA: emulators/pizza-boy-gba.md + - Pizza Boy GBC: emulators/pizza-boy-gbc.md + - Pizza Boy SC: emulators/pizza-boy-sc.md + - Plastic: emulators/plastic.md + - play: emulators/play.md + - PlaydiaEmu: emulators/playdiaemu.md + - PokeMini: emulators/pokemini.md + - pokketstation: emulators/pokketstation.md + - POM2: emulators/pom2.md + - Potator: emulators/potator.md + - PPSSPP: emulators/ppsspp.md + - PPSSPP 1.5.4: emulators/ppsspp-1.5.4.md + - PrBoom: emulators/prboom.md + - PrBoom+: emulators/prboom-plus.md + - PrimeHack: emulators/primehack.md + - project64: emulators/project64.md + - ProSystem: emulators/prosystem.md + - pSxMAME: emulators/psxmame.md + - PUAE (P-UAE): emulators/puae.md + - PUAE 2021: emulators/puae2021.md + - puNES: emulators/punes.md + - px68k: emulators/px68k.md + - px68k (SDL): emulators/px68k-sdl.md + - Q: + - QEMU: emulators/qemu.md + - Quake 3 (Raspberry Pi): emulators/quake3.md + - QUASI88: emulators/quasi88.md + - QUASI88kai: emulators/quasi88kai.md + - QuickNES: emulators/quicknes.md + - R: + - RACE (Neo Geo Pocket): emulators/race.md + - radio: emulators/radio.md + - RAINE: emulators/raine.md + - Raze: emulators/raze.md + - RB5000: emulators/rb5000.md + - Real3DOPlayer: emulators/real3doplayer.md + - RealRTCW: emulators/realrtcw.md + - Redream: emulators/redream.md + - Reicast: emulators/reicast.md + - REminiscence: emulators/reminiscence.md + - Retro8: emulators/retro8.md + - RetroDream: emulators/retrodream.md + - RigelEngine: emulators/rigelengine.md + - Rosalie's Mupen GUI: emulators/rosalies-mupen-gui.md + - RPCS3: emulators/rpcs3.md + - rpix86: emulators/rpix86.md + - ruffle: emulators/ruffle.md + - Rust-DOS: emulators/rust_dos.md + - Rustation: emulators/rustation.md + - RustyNES: emulators/rustynes.md + - RVVM: emulators/rvvm.md + - Ryujinx: emulators/ryujinx.md - S to U: - - SAME CDi: emulators/same_cdi.md - - SameBoy: emulators/sameboy.md - - sameduck: emulators/sameduck.md - - Saturn.emu: emulators/saturn-emu.md - - ScummVM: emulators/scummvm.md - - ScummVM (SDL1): emulators/scummvm-sdl1.md - - SDL2TRS: emulators/sdl2trs.md - - SDLPAL: emulators/sdlpal.md - - sdlpop: emulators/sdlpop.md - - shadps4: emulators/shadps4.md - - SheepShaver: emulators/sheepshaver.md - - Ship of Harkinian: emulators/soh.md - - SimCoupe: emulators/simcp.md - - SimCoupe (standalone): emulators/samcoupe.md - - simple64: emulators/simple64.md - - Singe 2: emulators/singe2.md - - sixtyforce: emulators/sixtyforce.md - - skyemu: emulators/skyemu.md - - Skyline: emulators/skyline.md - - SMS Plus GX: emulators/smsplus.md - - snes9x: emulators/snes9x.md - - Snes9x 2002: emulators/snes9x2002.md - - Snes9x 2005: emulators/snes9x2005.md - - Snes9x 2005 Plus: emulators/snes9x2005_plus.md - - Snes9x 2010: emulators/snes9x2010.md - - Snes9x EX+: emulators/snes9x-explus.md - - solarus: emulators/solarus.md - - Solarus 2.0.0: emulators/solarus-2.0.0.md - - Sonic 1 & 2 (2013) Decompilation: emulators/sonic2013.md - - Sonic 3 A.I.R.: emulators/sonic3-air.md - - Sonic CD Decompilation: emulators/soniccd.md - - Sonic Mania Decompilation: emulators/sonic-mania.md - - Sonic Robo Blast 2: emulators/srb2.md - - Speccy: emulators/speccy.md - - SplitWolf: emulators/splitwolf.md - - SPMP8000Emu: emulators/spmp8000emu.md - - SquirrelJME: emulators/squirreljme.md - - SSF: emulators/ssf.md - - Starboard: emulators/starboard.md - - Starship: emulators/starship.md - - Stella: emulators/stella.md - - Stella 2014: emulators/stella2014.md - - Stella 2023: emulators/stella2023.md - - Sudachi: emulators/sudachi.md - - Sugarbox2: emulators/sugarbox2.md - - Super Mario War: emulators/supermariowar.md - - SUPER ZSNES: emulators/superzsnes.md - - SUPER3: emulators/super3.md - - Supermodel: emulators/supermodel.md - - Supermodel (Sinden fork): emulators/supermodel3.md - - Supermodel Dojo: emulators/supermodel-dojo.md - - Supermodel Legacy: emulators/supermodel-legacy.md - - SuperSnes9x: emulators/supersnes9x.md - - SuperTux: emulators/supertux.md - - SuperTuxKart: emulators/supertuxkart.md - - Suyu: emulators/suyu.md - - Swan.emu: emulators/swan-emu.md - - swanstation: emulators/swanstation.md - - SWF Player: emulators/swf-player.md - - Syobon Action: emulators/syobonaction.md - - TamaLIBretro: emulators/tamalibretro.md - - Taradino: emulators/taradino.md - - TeknoParrot: emulators/teknoparrot.md - - TempGBA: emulators/tempgba.md - - TGB Dual: emulators/tgbdual.md - - The Force Engine: emulators/theforceengine.md - - Theodore: emulators/theodore.md - - TheXTech: emulators/thextech.md - - ti99sim: emulators/ti99sim.md - - ti99sim-sdl1: emulators/ti99sim-sdl1.md - - Tia: emulators/tia.md - - TIC-80: emulators/tic80.md - - touchHLE: emulators/touchhle.md - - TR1X: emulators/tr1x.md - - TR2X: emulators/tr2x.md - - trident: emulators/trident.md - - Triforce: emulators/triforce.md - - tsugaru: emulators/tsugaru.md - - TyrQuake: emulators/tyrquake.md - - UAE4ALL (libretro, Chips-fr): emulators/uae4all-rpi.md - - UAE4All2: emulators/uae4all.md - - uae4arm: emulators/uae4arm.md - - UME 2015: emulators/ume2015.md - - uqm: emulators/uqm.md - - UZDoom: emulators/uzdoom.md - - uzem: emulators/uzem.md + - S: + - SAME CDi: emulators/same_cdi.md + - SameBoy: emulators/sameboy.md + - sameduck: emulators/sameduck.md + - Saturn.emu: emulators/saturn-emu.md + - ScummVM: emulators/scummvm.md + - ScummVM (SDL1): emulators/scummvm-sdl1.md + - SDL2TRS: emulators/sdl2trs.md + - SDLPAL: emulators/sdlpal.md + - sdlpop: emulators/sdlpop.md + - shadps4: emulators/shadps4.md + - SheepShaver: emulators/sheepshaver.md + - Ship of Harkinian: emulators/soh.md + - SimCoupe: emulators/simcp.md + - SimCoupe (standalone): emulators/samcoupe.md + - simple64: emulators/simple64.md + - Singe 2: emulators/singe2.md + - sixtyforce: emulators/sixtyforce.md + - skyemu: emulators/skyemu.md + - Skyline: emulators/skyline.md + - SMS Plus GX: emulators/smsplus.md + - snes9x: emulators/snes9x.md + - Snes9x 2002: emulators/snes9x2002.md + - Snes9x 2005: emulators/snes9x2005.md + - Snes9x 2005 Plus: emulators/snes9x2005_plus.md + - Snes9x 2010: emulators/snes9x2010.md + - Snes9x EX+: emulators/snes9x-explus.md + - solarus: emulators/solarus.md + - Solarus 2.0.0: emulators/solarus-2.0.0.md + - Sonic 1 & 2 (2013) Decompilation: emulators/sonic2013.md + - Sonic 3 A.I.R.: emulators/sonic3-air.md + - Sonic CD Decompilation: emulators/soniccd.md + - Sonic Mania Decompilation: emulators/sonic-mania.md + - Sonic Robo Blast 2: emulators/srb2.md + - Speccy: emulators/speccy.md + - SplitWolf: emulators/splitwolf.md + - SPMP8000Emu: emulators/spmp8000emu.md + - SquirrelJME: emulators/squirreljme.md + - SSF: emulators/ssf.md + - Starboard: emulators/starboard.md + - Starship: emulators/starship.md + - Stella: emulators/stella.md + - Stella 2014: emulators/stella2014.md + - Stella 2023: emulators/stella2023.md + - Sudachi: emulators/sudachi.md + - Sugarbox2: emulators/sugarbox2.md + - Super Mario War: emulators/supermariowar.md + - SUPER ZSNES: emulators/superzsnes.md + - SUPER3: emulators/super3.md + - Supermodel: emulators/supermodel.md + - Supermodel (Sinden fork): emulators/supermodel3.md + - Supermodel Dojo: emulators/supermodel-dojo.md + - Supermodel Legacy: emulators/supermodel-legacy.md + - SuperSnes9x: emulators/supersnes9x.md + - SuperTux: emulators/supertux.md + - SuperTuxKart: emulators/supertuxkart.md + - Suyu: emulators/suyu.md + - Swan.emu: emulators/swan-emu.md + - swanstation: emulators/swanstation.md + - SWF Player: emulators/swf-player.md + - Syobon Action: emulators/syobonaction.md + - T: + - TamaLIBretro: emulators/tamalibretro.md + - Taradino: emulators/taradino.md + - TeknoParrot: emulators/teknoparrot.md + - TempGBA: emulators/tempgba.md + - TGB Dual: emulators/tgbdual.md + - The Force Engine: emulators/theforceengine.md + - Theodore: emulators/theodore.md + - TheXTech: emulators/thextech.md + - ti99sim: emulators/ti99sim.md + - ti99sim-sdl1: emulators/ti99sim-sdl1.md + - Tia: emulators/tia.md + - TIC-80: emulators/tic80.md + - touchHLE: emulators/touchhle.md + - TR1X: emulators/tr1x.md + - TR2X: emulators/tr2x.md + - trident: emulators/trident.md + - Triforce: emulators/triforce.md + - tsugaru: emulators/tsugaru.md + - TyrQuake: emulators/tyrquake.md + - U: + - UAE4ALL (libretro, Chips-fr): emulators/uae4all-rpi.md + - UAE4All2: emulators/uae4all.md + - uae4arm: emulators/uae4arm.md + - UME 2015: emulators/ume2015.md + - uqm: emulators/uqm.md + - UZDoom: emulators/uzdoom.md + - uzem: emulators/uzem.md - V to Z: - - VaporSpec: emulators/vaporspec.md - - VBA-M: emulators/vbam.md - - VBA-Next: emulators/vba_next.md - - vecx: emulators/vecx.md - - veesem: emulators/veesem.md - - VeMUlator: emulators/vemulator.md - - VICE: emulators/vice.md - - VICE x128: emulators/vice_x128.md - - VICE x64: emulators/vice_x64.md - - VICE x64dtv: emulators/vice_x64dtv.md - - VICE x64sc: emulators/vice_x64sc.md - - VICE xcbm2: emulators/vice_xcbm2.md - - VICE xcbm5x0: emulators/vice_xcbm5x0.md - - VICE xpet: emulators/vice_xpet.md - - VICE xplus4: emulators/vice_xplus4.md - - VICE xscpu64: emulators/vice_xscpu64.md - - VICE xvic: emulators/vice_xvic.md - - Vircon32: emulators/vircon32.md - - Virtual Jaguar: emulators/virtualjaguar.md - - Virtual Virtual Boy: emulators/virtual-virtual-boy.md - - VirtualXT: emulators/virtualxt.md - - visual-pinball: emulators/visual-pinball.md - - Vita3K: emulators/vita3k.md - - vitaQuakeII: emulators/vitaquake2.md - - vitaQuakeIII: emulators/vitaquake3.md - - vitavoyager: emulators/vitavoyager.md - - vkQuake: emulators/vkquake.md - - vkQuake2: emulators/vkquake2.md - - vkQuake3: emulators/vkquake3.md - - VVVVVV: emulators/vvvvvv.md - - WinUAE: emulators/winuae.md - - Wolf4SDL: emulators/wolf4sdl.md - - WQXEmu: emulators/wqxemu.md - - X Millennium: emulators/x1.md - - X1 BOX: emulators/x1-box.md - - x16emu: emulators/x16emu.md - - x64sdl: emulators/x64sdl.md - - Xash3D FWGS: emulators/xash3d_fwgs.md - - xemu: emulators/xemu.md - - xemu Chihiro: emulators/xemu-chihiro.md - - XenDroid: emulators/xendroid.md - - Xenia Canary: emulators/xenia.md - - Xenia Edge: emulators/xenia-edge.md - - XeniOS: emulators/xenios.md - - xm6pro68k: emulators/xm6pro68k.md - - xm6typeg: emulators/xm6typeg.md - - XM7: emulators/xm7.md - - XRick: emulators/xrick.md - - XRoar: emulators/xroar.md - - yabasanshiro: emulators/yabasanshiro.md - - yabause: emulators/yabause.md - - Yamagi Quake II: emulators/yquake2.md - - yaps2: emulators/yaps2.md - - ymir: emulators/ymir.md - - Yuzu: emulators/yuzu.md - - Zelda Classic 2.55 Prototype: emulators/zc255.md - - Zelda Classic v2.10: emulators/zc210.md - - ZEsarUX: emulators/zesarux.md - - ZiNc: emulators/zinc.md - - ZQuest Classic: emulators/zquestclassic.md + - V: + - VaporSpec: emulators/vaporspec.md + - VBA-M: emulators/vbam.md + - VBA-Next: emulators/vba_next.md + - vecx: emulators/vecx.md + - veesem: emulators/veesem.md + - VeMUlator: emulators/vemulator.md + - VICE: emulators/vice.md + - VICE x128: emulators/vice_x128.md + - VICE x64: emulators/vice_x64.md + - VICE x64dtv: emulators/vice_x64dtv.md + - VICE x64sc: emulators/vice_x64sc.md + - VICE xcbm2: emulators/vice_xcbm2.md + - VICE xcbm5x0: emulators/vice_xcbm5x0.md + - VICE xpet: emulators/vice_xpet.md + - VICE xplus4: emulators/vice_xplus4.md + - VICE xscpu64: emulators/vice_xscpu64.md + - VICE xvic: emulators/vice_xvic.md + - Vircon32: emulators/vircon32.md + - Virtual Jaguar: emulators/virtualjaguar.md + - Virtual Virtual Boy: emulators/virtual-virtual-boy.md + - VirtualXT: emulators/virtualxt.md + - visual-pinball: emulators/visual-pinball.md + - Vita3K: emulators/vita3k.md + - vitaQuakeII: emulators/vitaquake2.md + - vitaQuakeIII: emulators/vitaquake3.md + - vitavoyager: emulators/vitavoyager.md + - vkQuake: emulators/vkquake.md + - vkQuake2: emulators/vkquake2.md + - vkQuake3: emulators/vkquake3.md + - VVVVVV: emulators/vvvvvv.md + - W: + - WinUAE: emulators/winuae.md + - Wolf4SDL: emulators/wolf4sdl.md + - WQXEmu: emulators/wqxemu.md + - X: + - X Millennium: emulators/x1.md + - X1 BOX: emulators/x1-box.md + - x16emu: emulators/x16emu.md + - x64sdl: emulators/x64sdl.md + - Xash3D FWGS: emulators/xash3d_fwgs.md + - xemu: emulators/xemu.md + - xemu Chihiro: emulators/xemu-chihiro.md + - XenDroid: emulators/xendroid.md + - Xenia Canary: emulators/xenia.md + - Xenia Edge: emulators/xenia-edge.md + - XeniOS: emulators/xenios.md + - xm6pro68k: emulators/xm6pro68k.md + - xm6typeg: emulators/xm6typeg.md + - XM7: emulators/xm7.md + - XRick: emulators/xrick.md + - XRoar: emulators/xroar.md + - Y: + - yabasanshiro: emulators/yabasanshiro.md + - yabause: emulators/yabause.md + - Yamagi Quake II: emulators/yquake2.md + - yaps2: emulators/yaps2.md + - ymir: emulators/ymir.md + - Yuzu: emulators/yuzu.md + - Z: + - Zelda Classic 2.55 Prototype: emulators/zc255.md + - Zelda Classic v2.10: emulators/zc210.md + - ZEsarUX: emulators/zesarux.md + - ZiNc: emulators/zinc.md + - ZQuest Classic: emulators/zquestclassic.md - All installer options: wiki/installer.md - Reference: - wiki/index.md diff --git a/scripts/generate_site.py b/scripts/generate_site.py index b94d3779..d12f9e1d 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -1430,6 +1430,8 @@ def _browser_title(relative: Path, title: str) -> str: } if key in index_titles: return index_titles[key] + if key in PART_PAGES: + return title if key.startswith("emulators/"): return f"{title} emulator firmware" if key.startswith("systems/"): @@ -1474,6 +1476,9 @@ def _page_description(markdown: str, relative: Path, title: str) -> str: } if key in specific: return specific[key] + if key in PART_PAGES: + return (f"{title}: every file with its hashes, size, source references " + "and who reads it.") if key.startswith("platforms/") and relative.stem != "index": return (f"{title}: where the BIOS files go, the command that installs them, the pack, " "and every file by system with its hashes.") @@ -1510,9 +1515,13 @@ def _page_description(markdown: str, relative: Path, title: str) -> str: # Structured data a page generator knows beyond its text, by page path # relative to docs/: read by decorate_markdown_pages. PAGE_DATA: dict[str, dict] = {} +# Pages that hold part of a page too long for one (a console of a split +# manufacturer, a run of an emulator's cards), by path relative to docs/: +# their H1 already says what they are. +PART_PAGES: set[str] = set() -SYSTEM_PARTS_IN_FULL = 1000 +SYSTEM_PARTS_IN_FULL = 250 def collection_dat(db: dict, generated_at: str) -> str: @@ -1601,8 +1610,9 @@ def system_structured_data(slug: str, consoles: dict[str, list]) -> dict: part["citation"] = citations parts.append(part) if len(parts) > SYSTEM_PARTS_IN_FULL: - # game-engines would carry 2.6 MB of JSON-LD: past the cap a page - # lists its catalogue-verified files and points at the full table. + # A page of cards carried up to 2.6 MB of JSON-LD (game-engines), a + # quarter of its weight: past the cap a page lists its + # catalogue-verified files and points at the full table. return { "hasPart": [part for part in parts if part.get("citation")], "isBasedOn": urllib.parse.urljoin(SITE_URL, "downloads/files.csv"), @@ -1824,6 +1834,11 @@ def emulator_structured_data(profile: dict) -> dict: if members: part["hasPart"] = members parts.append(part) + if len(parts) > SYSTEM_PARTS_IN_FULL: + # MAME's 1,564 entries and their members were 614 KB of JSON-LD: past + # the cap the members are left to the profile's JSON. + for part in parts: + part.pop("hasPart", None) if parts: data["hasPart"] = parts return data @@ -2044,14 +2059,23 @@ def generate_platform_index(coverages: dict, registry: dict | None = None) -> st return "\n".join(lines) + "\n" +# A platform system whose file list passes this much Markdown gets a page +# of its own: RetroDECK's arcade list was 750 KB of a 1.1 MB page. +PLATFORM_SECTION_BUDGET = 200_000 + + def _render_platform_systems( - by_system: dict, config_files: dict, emulator_files: dict + by_system: dict, config_files: dict, emulator_files: dict, + platform: tuple[str, str] | None = None, moved: dict[str, str] | None = None, ) -> list[str]: """One collapsible block per system, listing every file it needs. Split out of generate_platform_page: the block is most of that function's branching, since each file renders a different set of hashes, sizes and provenance depending on what the platform declares. + With ``platform`` (its key and name) and ``moved``, a list longer than + PLATFORM_SECTION_BUDGET goes to a page of its own, written into + ``moved`` by stem, and the system's heading stays with a link to it. """ lines: list[str] = [] # Per-system detail sections (collapsible for large platforms) @@ -2154,6 +2178,26 @@ def _render_platform_systems( if f.get("category_evidence"): lines.append(f"{pad} {_category_evidence_md(f['category_evidence'])}") + block = lines[block_start:] + if moved is not None and platform and sum(len(line) + 1 for line in block) > PLATFORM_SECTION_BUDGET: + key, display = platform + stem = f"{key}-{anchor}" + body = block[2:] if use_collapsible else block + moved[stem] = "\n".join([ + f"# {display}: {sys_id}", "", + f"Part of the [{display} page]({key}.md#{anchor}), whose other systems " + f"are listed there. Each file below is as {display} declares it, with " + "its status in the pack.", + "", "## Files", "", + *search_excluded( + [line[len(pad):] if line.startswith(pad) else line for line in body]), + "", f"*Generated on {_timestamp()}*", + ]) + "\n" + lines[block_start:] = [ + f"{_count(total, 'file')}, {ok_count} verified: listed on " + f"[a page of their own]({stem}.md).", "", + ] + continue # The section's heading stays searchable, its file list with every # hash is the lookup's: retrodeck's arcade list was 495 KB of index. lines[block_start:] = search_excluded(lines[block_start:]) @@ -2386,9 +2430,13 @@ def generate_platform_page( cov: dict, registry: dict | None = None, emulator_files: dict | None = None, + moved: dict[str, str] | None = None, ) -> str: """A guide first (folder, command, pack, check), then every file the - platform's list and its emulators need, under a reference heading.""" + platform's list and its emulators need, under a reference heading. + + ``moved`` collects the pages of systems whose list is too long for it. + """ registry = registry or {} config = cov["config"] display = cov["platform"] @@ -2485,7 +2533,8 @@ def generate_platform_page( "", "", ] - lines.extend([*band, "| | |", "|---|---|"]) + lines.extend([*band, '
"]) if name not in GUIDES: detect = (registry.get(name, {}).get("install") or {}).get("detect") or [] on_card = any(rule.get("method") == "card_marker" for rule in detect) @@ -2576,7 +2626,8 @@ def generate_platform_page( lines.append("") lines.extend( - _render_platform_systems(by_system, config_files, emulator_files) + _render_platform_systems(by_system, config_files, emulator_files, + (name, display), moved) ) lines.append(f"*Generated on {_timestamp()}*") @@ -2701,8 +2752,8 @@ def file_location_items( parts = entry.get("path", "").split("/") if len(parts) < 3 or parts[0] != "bios": continue - slug = parts[1].lower().replace(" ", "-") - items.append({"sha1": sha1, "url": f"systems/{slug}/#sha1-{sha1[:12]}"}) + page = card_page(entry.get("path", ""), sha1) + items.append({"sha1": sha1, "url": f"systems/{page}/#sha1-{sha1[:12]}"}) # A data directory's files are listed on the page of an emulator reading # the tree: 2,534 hashes the packs ship were found nowhere on the site. owners = _data_member_owners(profiles or {}) @@ -2772,7 +2823,7 @@ def file_lookup_records( continue entries = profile.get("files") or [] for entry, anchor in zip(entries, emulator_file_anchors(entries)): - url = f"emulators/{key}/#{anchor}" + url = f"emulators/{emulator_card_page(key, anchor)}/#{anchor}" members = [(str(entry.get("name", "")), entry)] + [ (str(member["name"]), member) for member in entry.get("contents") or [] if isinstance(member, dict) and member.get("name") @@ -3207,8 +3258,9 @@ def _emulator_links(sha1: str, consumers: FileConsumers) -> list[str]: index = entries.get(emulator) anchor = (_emulator_card_anchor(emulator, files_of[emulator], index) if index is not None and emulator in files_of else "") + page = emulator_card_page(emulator, anchor) if anchor else emulator fragment = f"#{anchor}" if anchor else "" - links.append(f"[{emulator}](../emulators/{emulator}.md{fragment})") + links.append(f"[{emulator}](../emulators/{page}.md{fragment})") return links @@ -3379,14 +3431,16 @@ def _card_title(text: str, anchor: str, searchable: bool = True) -> str: """A file card's heading, so the site search lands on the card. The search splits a page at its headings: a card titled in bold sent a - pasted md5 to the top of a page of a hundred cards. Level 4 stays out - of the table of contents (toc_depth 3), and a card without an anchor - keeps the id the toc gives it. + pasted md5 to the top of a page of a hundred cards. Level 3, under + the console or the Files heading: a level 4 after a level 2 skipped + one for screen readers on 551 pages. The table of contents of a page + of cards stops above it (mkdocs_hooks.py), and a card without an + anchor keeps the id the toc gives it. """ attributes = f"#{anchor} .rb-file-title" if anchor else ".rb-file-title" if not searchable: attributes += " data-search-exclude" - return f"#### {text} {{ {attributes} }}" + return f"### {text} {{ {attributes} }}" def system_install_choices(coverages: dict) -> dict[str, dict[str, list[tuple[str, str]]]]: @@ -3418,6 +3472,197 @@ def system_install_choices(coverages: dict) -> dict[str, dict[str, list[tuple[st return choices +# A manufacturer page above this much Markdown becomes a summary with one +# page per console, and a console above it is cut into parts. 500 KB of +# Markdown renders to about 750 KB of HTML: game-engines was one 10.5 MB +# page that took 21 s of main-thread work on a phone. +SYSTEM_PAGE_BUDGET = 500_000 + +# A system card: whether it is a variant, its lines, its sha1. +Card = tuple[bool, list[str], str] + + +def _console_cards( + manufacturer: str, + files: list[dict], + consumers: FileConsumers, + anchored: set[str], +) -> list[Card]: + """Each card of one console, primaries by name then variants, with + whether it is a variant.""" + searchable = manufacturer not in GAME_DATA_TOPS + main_files = [f for f in files if "/.variants/" not in f["path"]] + variant_files = [f for f in files if "/.variants/" in f["path"]] + cards = [(False, _system_file_card(f, consumers, anchored, searchable), str(f.get("sha1", ""))) + for f in sorted(main_files, key=lambda x: x["name"])] + cards += [(True, _system_file_card(v, consumers, anchored, searchable), str(v.get("sha1", ""))) + for v in sorted(variant_files, key=lambda x: (x["name"], x["path"]))] + return cards + + +def _cards_markdown(cards: list[Card]) -> list[str]: + """Primaries, then the variants in a closed block.""" + lines = [line for variant, card, _sha1 in cards if not variant for line in card] + variants = [card for variant, card, _sha1 in cards if variant] + if variants: + # A variant gets the same card as a primary: the revision a + # platform pins is the one a reader comes to find, and showed as + # a name and a truncated MD5, nothing said who pins it. + lines.append(f'??? note "Variants ({len(variants)})"') + lines.append("") + for card in variants: + lines.extend(f" {line}" if line else "" for line in card) + lines.append("") + return lines + + +def _parts(cards: list[Card], budget: int) -> list[list[Card]]: + """Cards in runs of at most ``budget`` bytes of Markdown, in order.""" + parts: list[list[Card]] = [[]] + size = 0 + for card in cards: + weight = sum(len(line) + 1 for line in card[1]) + if parts[-1] and size + weight > budget: + parts.append([]) + size = 0 + parts[-1].append(card) + size += weight + return parts + + +_NEXT_FROM_SYSTEMS = [ + "[Get your files](../which-pack.md), for the setup you play on", + "[When a game does not start](../wiki/troubleshooting.md)", + "[Every emulator](../emulators/index.md), and the files each one reads", +] + + +def system_pages( + manufacturer: str, + consoles: dict[str, list], + consumers: FileConsumers, + installs: dict[str, list[tuple[str, str]]] | None = None, + budget: int = SYSTEM_PAGE_BUDGET, +) -> dict[str, tuple[str, dict[str, list]]]: + """A manufacturer's pages by stem under systems/: one page, or a summary + and a page per console when the whole would pass ``budget``. Each page + comes with the files whose cards it holds, by console. + + Every console keeps its heading on the summary, so a link to + systems/