diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml
index 183deaba..7a7a5de7 100644
--- a/.github/workflows/deploy-site.yml
+++ b/.github/workflows/deploy-site.yml
@@ -43,6 +43,7 @@ on:
- "scripts/restore_large_files.py"
- "scripts/safeparse.py"
- "scripts/sect233r1.py"
+ - "scripts/sitediagrams.py"
- "scripts/siteexports.py"
- "scripts/siterender.py"
- "scripts/sitesources.py"
diff --git a/docs_assets/extra.css b/docs_assets/extra.css
index dbc36106..a3d053d6 100644
--- a/docs_assets/extra.css
+++ b/docs_assets/extra.css
@@ -1,52 +1,230 @@
-/* RetroBIOS theme on top of mkdocs-material */
+/* RetroBIOS theme on top of mkdocs-material.
+
+ Classes the generator and the wiki pages can use:
+ .rb-lead first paragraph under a page title
+ .rb-level-* level label (start, setup, explore, reference, contribute)
+ .rb-page-header logo or image beside the title block of an entity page
+ .rb-cards, .rb-card card grid without Material's list markup
+ .grid.cards Material card grid, restyled here
+ .rb-card-logo 40 px logo tile inside a card
+ .rb-steps ordered list drawn as numbered steps
+ .rb-terminal wraps a code block that shows terminal output
+ .rb-cmd wraps a command that must wrap instead of scrolling
+ code.rb-path a folder path shown as a chip
+ .rb-figure a generated diagram (scripts/sitediagrams.py)
+ .rb-bar inline coverage bar, width from --v
+*/
:root {
- --rb-primary: #4a4e8a;
- --rb-primary-light: #6366a0;
- --rb-primary-dark: #363870;
+ --rb-primary: #3b3f7a;
+ --rb-primary-dark: #2b2e5c;
--rb-accent: #b42318;
--rb-link: #273c8f;
+ --rb-fg: rgba(0, 0, 0, 0.87);
--rb-surface: #f5f6fa;
--rb-border: #e0e3eb;
+ --rb-border-strong: #b8bdcc;
--rb-text-secondary: #546e7a;
+ --rb-ok-fg: #1b5e20;
+ --rb-ok-bg: #e8f5e9;
+ --rb-warn-fg: #a33f00;
+ --rb-warn-bg: #fff3e0;
+ --rb-err-fg: #b71c1c;
+ --rb-err-bg: #ffebee;
+ --rb-info-fg: #0d47a1;
+ --rb-info-bg: #e3f2fd;
+ --rb-muted-fg: #455a64;
+ --rb-muted-bg: #eceff1;
+ --rb-level-start: #1b5e20;
+ --rb-level-setup: #0d47a1;
+ --rb-level-explore: #6a1b9a;
+ --rb-level-reference: #455a64;
+ --rb-level-contribute: #a33f00;
+ --rb-terminal-bg: #1b1d2e;
+ --rb-terminal-fg: #e6e6f0;
+ --rb-terminal-label: #9aa0c3;
+ --rb-diagram-fill: #f5f6fa;
+ --rb-diagram-stroke: #8c92ac;
+ --rb-diagram-accent: #3b3f7a;
+ --md-code-font: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}
[data-md-color-scheme="slate"] {
- --rb-surface: #1e1e2e;
- --rb-border: #313244;
- --rb-text-secondary: #a6adc8;
--rb-accent: #ff9a8f;
--rb-link: #aebcff;
+ --rb-fg: #e3e4ee;
+ --rb-surface: #252838;
+ --rb-border: #3a3d52;
+ --rb-border-strong: #5a5e7a;
+ --rb-text-secondary: #a6adc8;
+ --rb-ok-fg: #a5d6a7;
+ --rb-ok-bg: #1b3a1f;
+ --rb-warn-fg: #ffcc80;
+ --rb-warn-bg: #7a2e00;
+ --rb-err-fg: #ef9a9a;
+ --rb-err-bg: #7f1414;
+ --rb-info-fg: #90caf9;
+ --rb-info-bg: #0d2a55;
+ --rb-muted-fg: #cfd8dc;
+ --rb-muted-bg: #37474f;
+ --rb-level-start: #a5d6a7;
+ --rb-level-setup: #90caf9;
+ --rb-level-explore: #ce93d8;
+ --rb-level-reference: #cfd8dc;
+ --rb-level-contribute: #ffcc80;
+ --rb-terminal-bg: #12131c;
+ --rb-diagram-fill: #252838;
+ --rb-diagram-stroke: #7c82a3;
+ --rb-diagram-accent: #aebcff;
}
+/* Colour roles. The header keeps the brand indigo in both schemes: the
+ lighter indigo it used in dark mode left the tab labels at 3.5:1. */
[data-md-color-scheme="default"] {
--md-primary-fg-color: var(--rb-primary);
- --md-primary-fg-color--light: var(--rb-primary-light);
+ --md-primary-fg-color--light: #4a4e8a;
--md-primary-fg-color--dark: var(--rb-primary-dark);
--md-accent-fg-color: var(--rb-accent);
+ --md-typeset-a-color: var(--rb-link);
+ /* Comments and punctuation sat at 4.47:1 on the code background. */
+ --md-code-hl-comment-color: #5c5c5c;
+ --md-code-hl-generic-color: #5c5c5c;
+ --md-code-hl-variable-color: #5c5c5c;
+ --md-code-hl-operator-color: #5c5c5c;
+ --md-code-hl-punctuation-color: #5c5c5c;
}
[data-md-color-scheme="slate"] {
- --md-primary-fg-color: var(--rb-primary-light);
+ --md-primary-fg-color: var(--rb-primary-dark);
+ --md-primary-fg-color--light: var(--rb-primary);
+ --md-primary-fg-color--dark: #1f2147;
--md-accent-fg-color: var(--rb-accent);
+ --md-accent-bg-color: #1e2129;
+ --md-typeset-a-color: var(--rb-link);
+ --md-code-hl-constant-color: #b39ddb;
+}
+
+/* Type scale: the page title is the strongest heading on the page. */
+.md-typeset h1 {
+ color: var(--md-default-fg-color);
+ font-size: 2em;
+ font-weight: 700;
+ letter-spacing: -0.01em;
+ line-height: 1.25;
+ margin: 0 0 0.9em;
+}
+
+.md-typeset h2 {
+ font-size: 1.45em;
+ font-weight: 600;
+ letter-spacing: -0.005em;
+ margin-top: 2em;
+}
+
+.md-typeset h3 {
+ font-size: 1.15em;
+ font-weight: 600;
+}
+
+.md-typeset h4 {
+ font-weight: 600;
+}
+
+.md-typeset .rb-lead {
+ font-size: 1.05em;
+ line-height: 1.55;
+ max-width: 44em;
+}
+
+/* Level label under a page title */
+.rb-level {
+ display: inline-block;
+ margin: 0 0 0.8rem;
+ padding: 0.05rem 0.45rem;
+ border: 1px solid currentColor;
+ border-radius: 2px;
+ font-size: 0.68rem;
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ line-height: 1.6;
+ color: var(--rb-level-reference);
+}
+
+.rb-level-start { color: var(--rb-level-start); }
+.rb-level-setup { color: var(--rb-level-setup); }
+.rb-level-explore { color: var(--rb-level-explore); }
+.rb-level-reference { color: var(--rb-level-reference); }
+.rb-level-contribute { color: var(--rb-level-contribute); }
+
+/* Header block of platform, system and emulator pages */
+.rb-page-header {
+ display: grid;
+ grid-template-columns: 56px 1fr;
+ gap: 0.4rem 1rem;
+ align-items: center;
+ margin: 0 0 1.2rem;
+}
+
+.rb-page-header > :first-child img,
+.rb-page-header > img {
+ width: 56px;
+ height: 56px;
+ object-fit: contain;
+}
+
+.md-typeset .rb-page-header h1 {
+ margin: 0;
+}
+
+.rb-page-header p {
+ margin: 0.2rem 0 0;
+}
+
+/* A page that names its logo next to the title floats it right; the logo
+ keeps its own box instead of shifting the counters below. */
+.md-typeset img[align="right"] {
+ width: 56px;
+ height: 56px;
+ object-fit: contain;
+ margin: 0 0 0.6rem 1rem;
+ padding: 4px;
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+ background: #fff;
+}
+
+/* Logos are drawn for a light background: they keep one in dark mode. */
+.md-typeset img[src*="assets/logos/"] {
+ padding: 2px;
+ border-radius: 2px;
+ background: #fff;
}
/* Headline figures, read as one line of numbers */
.rb-stats {
- display: flex;
- flex-wrap: wrap;
- gap: 0.4rem 2rem;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
+ gap: 0.6rem 1.5rem;
margin: 1rem 0 1.5rem;
+ padding: 0.8rem 1rem;
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+ background: var(--rb-surface);
+}
+
+.md-typeset .rb-stat p {
+ margin: 0;
}
.rb-stat .rb-stat-value {
font-size: 1.25rem;
font-weight: 700;
display: block;
+ font-variant-numeric: tabular-nums;
}
.rb-stat .rb-stat-label {
- font-size: 0.8rem;
+ font-size: 0.75rem;
color: var(--rb-text-secondary);
display: block;
}
@@ -61,22 +239,38 @@
white-space: nowrap;
}
-.rb-badge-success { background: #e8f5e9; color: #1b5e20; }
-.rb-badge-warning { background: #fff3e0; color: #a33f00; }
-.rb-badge-danger { background: #ffebee; color: #b71c1c; }
-.rb-badge-info { background: #e3f2fd; color: #0d47a1; }
-.rb-badge-muted { background: #eceff1; color: #455a64; }
+.rb-badge-success { background: var(--rb-ok-bg); color: var(--rb-ok-fg); }
+.rb-badge-warning { background: var(--rb-warn-bg); color: var(--rb-warn-fg); }
+.rb-badge-danger { background: var(--rb-err-bg); color: var(--rb-err-fg); }
+.rb-badge-info { background: var(--rb-info-bg); color: var(--rb-info-fg); }
+.rb-badge-muted { background: var(--rb-muted-bg); color: var(--rb-muted-fg); }
-[data-md-color-scheme="slate"] .rb-badge-success { background: #1b5e20; color: #a5d6a7; }
-[data-md-color-scheme="slate"] .rb-badge-warning { background: #e65100; color: #ffcc80; }
-[data-md-color-scheme="slate"] .rb-badge-danger { background: #b71c1c; color: #ef9a9a; }
-[data-md-color-scheme="slate"] .rb-badge-info { background: #0d47a1; color: #90caf9; }
-[data-md-color-scheme="slate"] .rb-badge-muted { background: #37474f; color: #b0bec5; }
+/* A link inside a badge keeps the badge's tested colour pair. */
+.md-typeset .rb-badge a:not(.md-button),
+.md-typeset a.rb-badge {
+ color: inherit;
+}
+
+/* Inline code inside a link reads as a link in both schemes. */
+.md-typeset a code {
+ color: var(--rb-link);
+}
+
+/* Tables */
+.md-typeset table:not([class]) {
+ font-variant-numeric: tabular-nums;
+}
.md-typeset table:not([class]) th {
position: sticky;
top: 0;
z-index: 1;
+ font-weight: 600;
+}
+
+.md-typeset table:not([class]) th,
+.md-typeset table:not([class]) td {
+ padding: 0.55em 0.9em;
}
.md-typeset__scrollwrap {
@@ -141,20 +335,27 @@
/* Hashes are printed whole so the search finds them, and wrap on phones */
.rb-hash {
- font-family: monospace;
+ font-family: var(--md-code-font);
font-size: 0.78rem;
color: var(--rb-text-secondary);
overflow-wrap: anywhere;
}
+/* Key and value cards: the header row is empty, so it is not drawn and
+ not announced. */
.rb-meta-card table {
margin: 1rem 0 !important;
}
-.rb-meta-card th {
+.rb-meta-card thead,
+.md-typeset table thead:not(:has(th:not(:empty))) {
display: none;
}
+.rb-meta-card td {
+ overflow-wrap: anywhere;
+}
+
.rb-meta-card td:first-child {
font-weight: 600;
color: var(--rb-text-secondary);
@@ -168,6 +369,24 @@
padding: 0.55em 0.8em;
}
+/* Buttons. The dark scheme draws them in the link colour: the header indigo
+ would sit at 3:1 on the page. */
+[data-md-color-scheme="slate"] .md-typeset .md-button {
+ color: var(--rb-link);
+ border-color: var(--rb-link);
+}
+
+[data-md-color-scheme="slate"] .md-typeset .md-button--primary {
+ background-color: var(--rb-link);
+ color: #1e2129;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .md-button:is(:hover, :focus) {
+ background-color: var(--rb-accent);
+ border-color: var(--rb-accent);
+ color: #1e2129;
+}
+
.md-typeset a:not(.md-button):not(.headerlink):not(.rb-badge) {
color: var(--rb-link);
text-decoration: underline;
@@ -179,7 +398,7 @@
text-decoration-thickness: 0.14em;
}
-:where(a, button, input, select, textarea, [tabindex]):focus-visible {
+:where(a, button, input, select, textarea, label, [tabindex]):focus-visible {
outline: 3px solid var(--rb-accent);
outline-offset: 3px;
}
@@ -240,6 +459,316 @@
outline-offset: 2px;
}
+/* Admonitions: one meaning per colour.
+ blue note, info, abstract, example, question, quote: background
+ teal tip: a shortcut
+ green success: what it looks like when it worked
+ orange warning: a risk of losing data or using the wrong file
+ red danger, failure, bug: something is broken or refused */
+.md-typeset :is(.admonition, details):is(.info, .abstract, .example, .question, .quote, .note) {
+ border-color: #448aff;
+}
+
+.md-typeset :is(.info, .abstract, .example, .question, .quote, .note) > :is(.admonition-title, summary) {
+ background-color: rgba(68, 138, 255, 0.1);
+}
+
+.md-typeset :is(.info, .abstract, .example, .question, .quote, .note) > :is(.admonition-title, summary)::before {
+ background-color: #448aff;
+ -webkit-mask-image: var(--md-admonition-icon--info);
+ mask-image: var(--md-admonition-icon--info);
+}
+
+.md-typeset :is(.admonition, details).tip {
+ border-color: #00897b;
+}
+
+.md-typeset .tip > :is(.admonition-title, summary) {
+ background-color: rgba(0, 137, 123, 0.1);
+}
+
+.md-typeset .tip > :is(.admonition-title, summary)::before {
+ background-color: #00897b;
+ -webkit-mask-image: var(--rb-icon-shortcut);
+ mask-image: var(--rb-icon-shortcut);
+}
+
+.md-typeset :is(.admonition, details):is(.danger, .failure, .bug, .error) {
+ border-color: #d32f2f;
+}
+
+.md-typeset :is(.danger, .failure, .bug, .error) > :is(.admonition-title, summary) {
+ background-color: rgba(211, 47, 47, 0.1);
+}
+
+.md-typeset :is(.danger, .failure, .bug, .error) > :is(.admonition-title, summary)::before {
+ background-color: #d32f2f;
+ -webkit-mask-image: var(--md-admonition-icon--danger);
+ mask-image: var(--md-admonition-icon--danger);
+}
+
+:root {
+ --rb-icon-shortcut: url('data:image/svg+xml;charset=utf-8,');
+}
+
+/* Code: shell commands wrap so the whole command shows on a phone, and the
+ copy button keeps its own column instead of covering the end. */
+.md-typeset :is(.language-sh, .language-bash, .language-shell, .language-console,
+ .language-powershell, .language-ps1, .language-pwsh, .language-cmd, .language-bat) pre > code,
+.md-typeset .rb-cmd pre > code {
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ padding-right: 2.6rem;
+}
+
+/* Terminal output: what the screen shows, not something to type */
+.md-typeset .rb-terminal pre,
+.md-typeset .rb-terminal pre > code {
+ background: var(--rb-terminal-bg);
+ color: var(--rb-terminal-fg);
+}
+
+.md-typeset .rb-terminal pre {
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+}
+
+.md-typeset .rb-terminal pre::before {
+ content: "Terminal output";
+ display: block;
+ padding: 0.5rem 1.2em 0;
+ font: 600 0.65rem var(--md-text-font-family);
+ color: var(--rb-terminal-label);
+}
+
+.md-typeset .rb-terminal .md-code__button {
+ color: var(--rb-terminal-label);
+}
+
+/* Numbered steps */
+.md-typeset ol.rb-steps,
+.md-typeset .rb-steps > ol {
+ counter-reset: rb-step;
+ list-style: none;
+ margin-left: 0;
+ padding-left: 0;
+}
+
+.md-typeset ol.rb-steps > li,
+.md-typeset .rb-steps > ol > li {
+ counter-increment: rb-step;
+ position: relative;
+ margin: 0 0 1.2rem;
+ padding-left: 2.6rem;
+ min-height: 1.8rem;
+}
+
+.md-typeset ol.rb-steps > li::before,
+.md-typeset .rb-steps > ol > li::before {
+ content: counter(rb-step);
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 1.8rem;
+ height: 1.8rem;
+ border-radius: 4px;
+ background: var(--md-primary-fg-color);
+ color: #fff;
+ font-weight: 700;
+ line-height: 1.8rem;
+ text-align: center;
+}
+
+[data-md-color-scheme="slate"] .md-typeset ol.rb-steps > li::before,
+[data-md-color-scheme="slate"] .md-typeset .rb-steps > ol > li::before {
+ background: var(--rb-link);
+ color: #1e2129;
+}
+
+/* Card grids. Material's grid cards keep their markup; the hover shadow
+ gives way to a stronger border. */
+.md-typeset .grid.cards {
+ --md-shadow-z2: 0 0 #0000;
+}
+
+.md-typeset .grid.cards > :is(ul, ol) > li,
+.md-typeset .grid > .card {
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+}
+
+.md-typeset .grid.cards > :is(ul, ol) > li:is(:hover, :focus-within),
+.md-typeset .grid > .card:is(:hover, :focus-within) {
+ border-color: var(--rb-border-strong);
+}
+
+.rb-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
+ gap: 0.8rem;
+ margin: 1rem 0 1.5rem;
+}
+
+.rb-card {
+ display: flex;
+ flex-direction: column;
+ gap: 0.35rem;
+ padding: 0.8rem;
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+ background: var(--md-default-bg-color);
+}
+
+.rb-card:is(:hover, :focus-within) {
+ border-color: var(--rb-border-strong);
+}
+
+.md-typeset .rb-card p {
+ margin: 0;
+}
+
+.md-typeset .rb-card .md-button {
+ margin-top: auto;
+ align-self: flex-start;
+}
+
+.md-typeset .rb-card-logo,
+.md-typeset .grid.cards img.rb-card-logo {
+ width: 40px;
+ height: 40px;
+ object-fit: contain;
+ padding: 4px;
+ border: 1px solid var(--rb-border);
+ border-radius: 4px;
+ background: #fff;
+ vertical-align: middle;
+}
+
+/* Path chip */
+.md-typeset code.rb-path {
+ padding: 0.15rem 0.45rem;
+ border: 1px solid var(--rb-border);
+ border-radius: 2px;
+ font-size: 0.8em;
+ overflow-wrap: anywhere;
+}
+
+/* Content tabs (operating systems): the selected tab reads clearly. */
+.md-typeset .tabbed-labels > label {
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: var(--rb-text-secondary);
+}
+
+.md-typeset .tabbed-set > input:checked + label,
+.md-typeset .tabbed-labels > label:hover {
+ color: var(--rb-link);
+}
+
+.md-typeset .tabbed-labels::before {
+ background: var(--rb-link);
+}
+
+/* Inline coverage bar beside a number */
+.rb-bar {
+ display: inline-block;
+ width: 5rem;
+ height: 0.4rem;
+ margin-right: 0.4rem;
+ border-radius: 2px;
+ background: var(--rb-border);
+ vertical-align: middle;
+}
+
+.rb-bar > span {
+ display: block;
+ width: var(--v, 0%);
+ height: 100%;
+ border-radius: 2px;
+ background: var(--rb-ok-fg);
+}
+
+/* Diagrams written by scripts/sitediagrams.py. Text takes the page font and
+ colour, boxes take the theme surface, so the drawing follows the palette
+ toggle. Each diagram carries a wide and a narrow layout. */
+.md-typeset .rb-figure {
+ margin: 1.2rem 0 1.6rem;
+}
+
+.md-typeset .rb-figure svg {
+ display: block;
+ width: 100%;
+ height: auto;
+ max-width: 52rem;
+ color: var(--md-default-fg-color);
+}
+
+.md-typeset .rb-figure figcaption {
+ max-width: 44em;
+ margin: 0.4rem 0 0;
+ font-size: 0.75rem;
+ font-style: normal;
+ color: var(--rb-text-secondary);
+ text-align: left;
+}
+
+.rb-diagram text {
+ font-family: var(--md-text-font-family);
+ fill: currentColor;
+}
+
+.rb-diagram .rb-d-box {
+ fill: var(--rb-diagram-fill);
+ stroke: var(--rb-diagram-stroke);
+}
+
+.rb-diagram .rb-d-accent {
+ stroke: var(--rb-diagram-accent);
+}
+
+.rb-diagram .rb-d-line {
+ stroke: var(--rb-diagram-stroke);
+}
+
+.rb-diagram .rb-d-head {
+ fill: var(--rb-diagram-stroke);
+}
+
+.rb-diagram .rb-d-num {
+ fill: var(--rb-diagram-accent);
+}
+
+.rb-diagram .rb-d-numtext {
+ fill: var(--md-default-bg-color);
+}
+
+.rb-diagram .rb-d-muted {
+ fill: var(--rb-text-secondary);
+}
+
+.rb-diagram-narrow {
+ display: none !important;
+}
+
+@media (max-width: 37.5em) {
+ .rb-diagram-wide {
+ display: none !important;
+ }
+
+ .rb-diagram-narrow {
+ display: block !important;
+ }
+}
+
+/* The sidebar title stays legible over the list scrolling under it. */
+@media (min-width: 76.25em) {
+ .md-nav--primary > .md-nav__title,
+ .md-nav--secondary > .md-nav__title {
+ background: var(--md-default-bg-color);
+ border-bottom: 1px solid var(--rb-border);
+ }
+}
+
/* Material's compact footer defaults sit just below WCAG AA on the dark bar. */
.md-footer-meta .md-copyright {
color: #b5b5b5;
@@ -249,6 +778,116 @@
color: #b8c6ff !important;
}
+/* 404 page */
+.rb-notfound-search {
+ display: inline-flex;
+ align-items: center;
+ min-height: 44px;
+ padding: 0.55em 1.2em;
+ border: 1px solid currentColor;
+ border-radius: 2px;
+ color: var(--rb-link);
+ font-weight: 700;
+ cursor: pointer;
+}
+
+@media (max-width: 44.984375em) {
+ /* Tables with an action column become one block per row, so the button
+ is never behind a horizontal scroll (site.js marks them). */
+ .md-typeset__table:has(table[data-rb-stack]) {
+ display: block;
+ }
+
+ .md-typeset table[data-rb-stack] {
+ display: block;
+ width: 100%;
+ }
+
+ .md-typeset table[data-rb-stack] thead {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ }
+
+ .md-typeset table[data-rb-stack] tbody,
+ .md-typeset table[data-rb-stack] tr {
+ display: block;
+ }
+
+ .md-typeset table[data-rb-stack] tr {
+ padding: 0.5rem 0;
+ border-top: 1px solid var(--rb-border);
+ }
+
+ .md-typeset table[data-rb-stack] td {
+ display: block;
+ position: relative;
+ min-height: 1.6rem;
+ padding: 0.25rem 0.6rem 0.25rem 8.4rem;
+ border: 0;
+ text-align: left !important;
+ overflow-wrap: anywhere;
+ }
+
+ .md-typeset table[data-rb-stack] td::before {
+ content: attr(data-label);
+ position: absolute;
+ top: 0.25rem;
+ left: 0.6rem;
+ width: 7.4rem;
+ font-weight: 600;
+ color: var(--rb-text-secondary);
+ }
+
+ .md-typeset table[data-rb-stack] td .md-button {
+ margin: 0 0.3rem 0.3rem 0;
+ }
+
+ .md-typeset table[data-rb-stack] td:empty {
+ display: none;
+ }
+
+ /* Other wide tables scroll with their first column held in place. */
+ .md-typeset table:not([class]):not([data-rb-stack]) :is(td, th):first-child {
+ position: sticky;
+ left: 0;
+ max-width: 40vw;
+ background: var(--md-default-bg-color);
+ overflow-wrap: anywhere;
+ }
+
+ .md-typeset table:not([class]):not([data-rb-stack]) th:first-child {
+ z-index: 2;
+ }
+
+ /* On a phone every command wraps: the end of a one-liner (the "| sh"
+ that makes it work) is never off-screen. Terminal output keeps its
+ columns and scrolls. */
+ .md-typeset pre > code {
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ padding-right: 2.6rem;
+ }
+
+ .md-typeset :is(.rb-terminal, .language-text) pre > code {
+ white-space: pre;
+ overflow-wrap: normal;
+ }
+
+ /* Text on reference pages stays at 12 px or more on a phone. */
+ .rb-file-entry ul,
+ .rb-sys-file ul,
+ .rb-hash {
+ font-size: 0.75rem;
+ }
+
+ .rb-page-header {
+ grid-template-columns: 1fr;
+ }
+}
+
@media (max-width: 600px) {
.rb-table-filter {
grid-template-columns: 1fr;
@@ -257,6 +896,14 @@
.rb-table-filter label {
grid-column: auto;
}
+
+ .rb-stats {
+ grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr));
+ }
+
+ .rb-stat .rb-stat-value {
+ font-size: 1.1rem;
+ }
}
@media (prefers-reduced-motion: reduce) {
diff --git a/docs_assets/images-needed.md b/docs_assets/images-needed.md
new file mode 100644
index 00000000..4bc29a92
--- /dev/null
+++ b/docs_assets/images-needed.md
@@ -0,0 +1,71 @@
+# Images that need a real device
+
+These pictures show a real screen, so they are captured on a real install and
+never drawn as a mock-up. Each entry says what the capture must show, where it
+goes, and the alt text it carries. Folder layouts that follow from data are
+drawn by `scripts/sitediagrams.py` instead (the MinUI card tree is
+``).
+
+Captures: PNG or WebP, 1200 px wide at most, cropped tight, under 150 KB,
+personal paths and user names removed. Menu labels are checked against the
+current release of the software before the capture is used. Put each file in
+`docs_assets/screens/` and note the software version in the commit message.
+
+## RetroArch System/BIOS directory
+
+Settings, Directory in RetroArch (Ozone menu), with the System/BIOS row
+highlighted and its path visible. For the RetroArch pages on Windows, macOS,
+Linux and Android.
+
+**Alt text**: RetroArch Settings, Directory screen, with the System/BIOS line highlighted showing the folder path.
+
+## RetroArch firmware check
+
+Main Menu, Information, Core Information after loading a PlayStation core, with
+the firmware lines reading Present. For RetroArch and Lakka pages, "Done when".
+
+**Alt text**: RetroArch Core Information for a PlayStation core, each firmware line marked Present.
+
+## Steam Deck Desktop Mode and Konsole
+
+Two panels: the Steam Deck power menu with Switch to Desktop selected, then the
+desktop with Konsole open and the install command pasted. For the EmuDeck and
+RetroDECK pages.
+
+**Alt text**: Steam Deck power menu with Switch to Desktop selected, then the Konsole terminal open with the install command pasted.
+
+## Installer run, annotated
+
+A real installer run in a terminal with three marks: the detected BIOS folder
+line, the confirmation prompt, and the Done line. For First install and every
+setup page.
+
+**Alt text**: Installer output in a terminal, with marks on the detected folder, the install choice and the Done line.
+
+## Batocera network share from Windows
+
+Windows File Explorer with `\\BATOCERA\share\bios` in the address bar and the
+BIOS files listed. For the Batocera and KNULLI pages.
+
+**Alt text**: Windows File Explorer showing the Batocera bios folder opened over the network.
+
+## Batocera missing BIOS screen
+
+Batocera's main menu path to the missing BIOS check, and the result screen with
+no missing file for the consoles in use. For the Batocera page, "Done when".
+
+**Alt text**: Batocera missing BIOS check listing no missing files.
+
+## Recalbox BIOS manager
+
+Recalbox's BIOS checking screen with green, yellow and red entries visible. For
+the Recalbox page.
+
+**Alt text**: Recalbox BIOS manager listing files marked present, present with another version, and missing.
+
+## A multi-part pack extracted
+
+A file manager showing two downloaded parts and the single folder both were
+extracted into. For Get your files.
+
+**Alt text**: Two downloaded pack parts and the one folder both were extracted into.
diff --git a/docs_assets/logos/amberelec.png b/docs_assets/logos/amberelec.png
new file mode 100644
index 00000000..ddc713f4
Binary files /dev/null and b/docs_assets/logos/amberelec.png differ
diff --git a/docs_assets/logos/batocera.svg b/docs_assets/logos/batocera.svg
new file mode 100644
index 00000000..de36c9b4
--- /dev/null
+++ b/docs_assets/logos/batocera.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs_assets/logos/bizhawk.png b/docs_assets/logos/bizhawk.png
new file mode 100644
index 00000000..511597b2
Binary files /dev/null and b/docs_assets/logos/bizhawk.png differ
diff --git a/docs_assets/logos/emudeck.png b/docs_assets/logos/emudeck.png
new file mode 100644
index 00000000..408a9415
Binary files /dev/null and b/docs_assets/logos/emudeck.png differ
diff --git a/docs_assets/logos/emuelec.png b/docs_assets/logos/emuelec.png
new file mode 100644
index 00000000..1c432fc5
Binary files /dev/null and b/docs_assets/logos/emuelec.png differ
diff --git a/docs_assets/logos/knulli.png b/docs_assets/logos/knulli.png
new file mode 100644
index 00000000..fc8885f1
Binary files /dev/null and b/docs_assets/logos/knulli.png differ
diff --git a/docs_assets/logos/lakka.svg b/docs_assets/logos/lakka.svg
new file mode 100644
index 00000000..fc89ee3c
--- /dev/null
+++ b/docs_assets/logos/lakka.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/docs_assets/logos/minui.png b/docs_assets/logos/minui.png
new file mode 100644
index 00000000..cc59063a
Binary files /dev/null and b/docs_assets/logos/minui.png differ
diff --git a/docs_assets/logos/misterfpga.png b/docs_assets/logos/misterfpga.png
new file mode 100644
index 00000000..35821644
Binary files /dev/null and b/docs_assets/logos/misterfpga.png differ
diff --git a/docs_assets/logos/nextui.png b/docs_assets/logos/nextui.png
new file mode 100644
index 00000000..dd758331
Binary files /dev/null and b/docs_assets/logos/nextui.png differ
diff --git a/docs_assets/logos/recalbox.svg b/docs_assets/logos/recalbox.svg
new file mode 100644
index 00000000..b96d2dd1
--- /dev/null
+++ b/docs_assets/logos/recalbox.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs_assets/logos/retroarch.svg b/docs_assets/logos/retroarch.svg
new file mode 100644
index 00000000..a35b434a
--- /dev/null
+++ b/docs_assets/logos/retroarch.svg
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/docs_assets/logos/retrobat.png b/docs_assets/logos/retrobat.png
new file mode 100644
index 00000000..2b4395ac
Binary files /dev/null and b/docs_assets/logos/retrobat.png differ
diff --git a/docs_assets/logos/retrodeck.svg b/docs_assets/logos/retrodeck.svg
new file mode 100644
index 00000000..185f9d63
--- /dev/null
+++ b/docs_assets/logos/retrodeck.svg
@@ -0,0 +1,53 @@
+
+
diff --git a/docs_assets/logos/retropie.png b/docs_assets/logos/retropie.png
new file mode 100644
index 00000000..e3885625
Binary files /dev/null and b/docs_assets/logos/retropie.png differ
diff --git a/docs_assets/logos/rocknix.png b/docs_assets/logos/rocknix.png
new file mode 100644
index 00000000..8158615d
Binary files /dev/null and b/docs_assets/logos/rocknix.png differ
diff --git a/docs_assets/logos/romm.png b/docs_assets/logos/romm.png
new file mode 100644
index 00000000..71d38413
Binary files /dev/null and b/docs_assets/logos/romm.png differ
diff --git a/docs_assets/logos/sources.json b/docs_assets/logos/sources.json
new file mode 100644
index 00000000..590c551d
--- /dev/null
+++ b/docs_assets/logos/sources.json
@@ -0,0 +1,124 @@
+{
+ "note": "Each platform's own logo, owned by its project and shown only to name that platform. Copied once by scripts/fetch_site_images.py.",
+ "images": [
+ {
+ "file": "amberelec.png",
+ "platform": "amberelec",
+ "source": "https://avatars.githubusercontent.com/u/102820909",
+ "owner": "AmberELEC",
+ "licence": "GitHub organisation avatar of AmberELEC"
+ },
+ {
+ "file": "batocera.svg",
+ "platform": "batocera",
+ "source": "https://raw.githubusercontent.com/batocera-linux/batocera-emulationstation/master/resources/splash_batocera.svg",
+ "owner": "Batocera",
+ "licence": "repository licence MIT"
+ },
+ {
+ "file": "bizhawk.png",
+ "platform": "bizhawk",
+ "source": "https://avatars.githubusercontent.com/u/11743303",
+ "owner": "TASVideos",
+ "licence": "GitHub organisation avatar of TASEmulators"
+ },
+ {
+ "file": "emudeck.png",
+ "platform": "emudeck",
+ "source": "https://raw.githubusercontent.com/dragoonDorise/EmuDeck/main/icons/EmuDeck.png",
+ "owner": "EmuDeck",
+ "licence": "repository licence GPL-3.0"
+ },
+ {
+ "file": "emuelec.png",
+ "platform": "emuelec",
+ "source": "https://avatars.githubusercontent.com/u/57574835",
+ "owner": "EmuELEC",
+ "licence": "GitHub organisation avatar of EmuELEC"
+ },
+ {
+ "file": "knulli.png",
+ "platform": "knulli",
+ "source": "https://avatars.githubusercontent.com/u/166268572",
+ "owner": "KNULLI",
+ "licence": "GitHub organisation avatar of knulli-cfw"
+ },
+ {
+ "file": "lakka.svg",
+ "platform": "lakka",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/src/xmb/flatui/lakka.svg",
+ "owner": "Lakka (libretro)",
+ "licence": "file from libretro/retroarch-assets, CC-BY-4.0"
+ },
+ {
+ "file": "minui.png",
+ "platform": "minui",
+ "source": "https://avatars.githubusercontent.com/u/225589",
+ "owner": "Shaun Inman",
+ "licence": "GitHub avatar of shauninman, the author of MinUI"
+ },
+ {
+ "file": "misterfpga.png",
+ "platform": "misterfpga",
+ "source": "https://avatars.githubusercontent.com/u/29345272",
+ "owner": "MiSTer FPGA",
+ "licence": "GitHub organisation avatar of MiSTer-devel"
+ },
+ {
+ "file": "nextui.png",
+ "platform": "nextui",
+ "source": "https://avatars.githubusercontent.com/u/202386615",
+ "owner": "LoveRetro",
+ "licence": "GitHub organisation avatar of LoveRetro"
+ },
+ {
+ "file": "recalbox.svg",
+ "platform": "recalbox",
+ "source": "https://raw.githubusercontent.com/homarr-labs/dashboard-icons/main/svg/recalbox.svg",
+ "owner": "Recalbox",
+ "licence": "file from homarr-labs/dashboard-icons, Apache-2.0"
+ },
+ {
+ "file": "retroarch.svg",
+ "platform": "retroarch",
+ "source": "https://raw.githubusercontent.com/libretro/RetroArch/master/media/retroarch-vector_invader-only.svg",
+ "owner": "libretro",
+ "licence": "repository licence GPL-3.0"
+ },
+ {
+ "file": "retrobat.png",
+ "platform": "retrobat",
+ "source": "https://raw.githubusercontent.com/RetroBat-Official/retrobat/main/system/resources/retrobat_logo_notext.png",
+ "owner": "RetroBat",
+ "licence": "repository states no licence"
+ },
+ {
+ "file": "retrodeck.svg",
+ "platform": "retrodeck",
+ "source": "https://raw.githubusercontent.com/RetroDECK/RetroDECK/main/res/icon.svg",
+ "owner": "RetroDECK",
+ "licence": "repository licence GPL-3.0"
+ },
+ {
+ "file": "retropie.png",
+ "platform": "retropie",
+ "source": "https://avatars.githubusercontent.com/u/11378204",
+ "owner": "RetroPie",
+ "licence": "GitHub organisation avatar of RetroPie"
+ },
+ {
+ "file": "rocknix.png",
+ "platform": "rocknix",
+ "source": "https://avatars.githubusercontent.com/u/163176886",
+ "owner": "ROCKNIX",
+ "licence": "GitHub organisation avatar of ROCKNIX"
+ },
+ {
+ "file": "romm.png",
+ "platform": "romm",
+ "source": "https://avatars.githubusercontent.com/u/164058018",
+ "owner": "RomM",
+ "licence": "GitHub organisation avatar of rommapp"
+ }
+ ]
+}
diff --git a/docs_assets/og/contribute.png b/docs_assets/og/contribute.png
new file mode 100644
index 00000000..88a40b47
Binary files /dev/null and b/docs_assets/og/contribute.png differ
diff --git a/docs_assets/og/explore.png b/docs_assets/og/explore.png
new file mode 100644
index 00000000..7e4c409d
Binary files /dev/null and b/docs_assets/og/explore.png differ
diff --git a/docs_assets/og/home.png b/docs_assets/og/home.png
new file mode 100644
index 00000000..3d2b7e17
Binary files /dev/null and b/docs_assets/og/home.png differ
diff --git a/docs_assets/og/reference.png b/docs_assets/og/reference.png
new file mode 100644
index 00000000..fc688a7a
Binary files /dev/null and b/docs_assets/og/reference.png differ
diff --git a/docs_assets/og/setup.png b/docs_assets/og/setup.png
new file mode 100644
index 00000000..84bd6f81
Binary files /dev/null and b/docs_assets/og/setup.png differ
diff --git a/docs_assets/og/start.png b/docs_assets/og/start.png
new file mode 100644
index 00000000..15245230
Binary files /dev/null and b/docs_assets/og/start.png differ
diff --git a/docs_assets/overrides/404.html b/docs_assets/overrides/404.html
new file mode 100644
index 00000000..59ad2c3d
--- /dev/null
+++ b/docs_assets/overrides/404.html
@@ -0,0 +1,37 @@
+{% extends "main.html" %}
+
+{#
+ The page a stale link lands on. Pages have moved before (file cards
+ refiled between manufacturers), so it offers the search, the two pages a
+ visitor most often wants, and the list a moved emulator, system or
+ platform page belongs to.
+#}
+{% block content %}
+
Page not found
+ This address has no page. It may have moved since the link was written.
+
+
+
+
+{% endblock %}
diff --git a/docs_assets/overrides/main.html b/docs_assets/overrides/main.html
index 4348d78c..893d3b1e 100644
--- a/docs_assets/overrides/main.html
+++ b/docs_assets/overrides/main.html
@@ -9,25 +9,43 @@
taking on two image dependencies. The links get shared on Discord, Reddit and
forums, where a bare URL with no preview is the difference between a card and
a grey rectangle.
+
+ One sharing card per section (docs_assets/og, made by
+ scripts/make_og_cards.py). The section is the page's level when the
+ generator gives one, otherwise it follows from the URL.
#}
{% block extrahead %}
{% set page_title = page.meta.title if page and page.meta and page.meta.title else (page.title if page and page.title else config.site_name) %}
{% set page_description = page.meta.description if page and page.meta and page.meta.description else config.site_description %}
{% set page_url = page.canonical_url if page and page.canonical_url else config.site_url %}
- {% set preview_image = config.site_url ~ 'assets/images/logo.png' if config.site_url else '' %}
+ {% set url = page.url if page and page.url else '' %}
+ {% set level = page.meta.level if page and page.meta and page.meta.level else '' %}
+ {% if not url %}{% set section = 'home' %}
+ {% elif level in ['start', 'setup', 'explore', 'reference', 'contribute'] %}{% set section = level %}
+ {% elif url.startswith('which-pack') or url.startswith('wiki/first-install') or url.startswith('wiki/faq') or url.startswith('wiki/getting-started') %}{% set section = 'start' %}
+ {% elif url.startswith('platforms') %}{% set section = 'setup' %}
+ {% elif url.startswith('systems') or url.startswith('emulators') or url.startswith('files') %}{% set section = 'explore' %}
+ {% elif url.startswith('contributing') or url.startswith('wiki/adding') or url.startswith('wiki/profiling') or url.startswith('wiki/testing') or url.startswith('wiki/release') %}{% set section = 'contribute' %}
+ {% else %}{% set section = 'reference' %}{% endif %}
+ {% set preview_image = config.site_url ~ 'assets/og/' ~ section ~ '.png' if config.site_url else '' %}
-
+
{% if page_url %}{% endif %}
- {% if preview_image %}{% endif %}
+ {% if preview_image %}
+
+
+
+
+ {% endif %}
{# The sitemap, named from every page: a project site under /retrobios/
cannot serve the host-root robots.txt that would announce it. #}
{% if config.site_url %}{% endif %}
-
+
{% if preview_image %}{% endif %}
diff --git a/docs_assets/site.js b/docs_assets/site.js
index 7dba3f05..db4d72e1 100644
--- a/docs_assets/site.js
+++ b/docs_assets/site.js
@@ -2,16 +2,65 @@
(() => {
"use strict";
+ // A heading's words without its permalink sign.
+ const headingText = (heading) => {
+ const copy = heading.cloneNode(true);
+ copy.querySelectorAll(".headerlink").forEach((link) => link.remove());
+ return copy.textContent.trim();
+ };
+
const textFromHeading = (element) => {
let cursor = element;
while (cursor) {
cursor = cursor.previousElementSibling;
if (!cursor) break;
if (/^H[1-6]$/.test(cursor.tagName)) {
- return cursor.textContent.trim();
+ return headingText(cursor);
}
}
- return document.querySelector("h1")?.textContent.trim() || "Data table";
+ const title = document.querySelector("h1");
+ return title ? headingText(title) : "Data table";
+ };
+
+ // A scroller is a stop in the tab order only while it overflows: a table
+ // in a closed block or a hidden tab gains its overflow later.
+ const markScrollable = (container, heading) => {
+ if (!container) return;
+ container.dataset.rbHeading = heading;
+ if (container.scrollWidth > container.clientWidth + 1) {
+ container.tabIndex = 0;
+ container.setAttribute("role", "region");
+ container.setAttribute("aria-label", `${heading}, scrollable table`);
+ } else if (container.getAttribute("role") === "region") {
+ container.removeAttribute("tabindex");
+ container.removeAttribute("role");
+ container.removeAttribute("aria-label");
+ }
+ };
+
+ const recheckScrollable = () => {
+ document.querySelectorAll(".md-typeset__scrollwrap[data-rb-heading]").forEach((container) => {
+ markScrollable(container, container.dataset.rbHeading);
+ });
+ };
+
+ // A table whose rows end in an action (a download button) is laid out one
+ // block per row on a phone, each cell under its column name, so the action
+ // never sits behind a horizontal scroll.
+ const stackActionTable = (table) => {
+ if (!table.querySelector("tbody .md-button")) return;
+ const labels = Array.from(table.querySelectorAll("thead th")).map((cell) =>
+ cell.textContent.trim()
+ );
+ if (!labels.length) return;
+ table.dataset.rbStack = "true";
+ table.querySelectorAll("tbody tr").forEach((row) => {
+ Array.from(row.children).forEach((cell, column) => {
+ if (labels[column] && !cell.hasAttribute("data-label")) {
+ cell.setAttribute("data-label", labels[column]);
+ }
+ });
+ });
};
const enhanceTables = () => {
@@ -27,7 +76,9 @@
if (first && !first.hasAttribute("scope")) first.setAttribute("scope", "row");
});
- const container = table.parentElement;
+ // The scrolling element is Material's scrollwrap, one level above
+ // the table's own wrapper.
+ const container = table.closest(".md-typeset__scrollwrap") || table.parentElement;
const heading = textFromHeading(container);
if (!table.querySelector("caption")) {
const caption = document.createElement("caption");
@@ -35,11 +86,8 @@
caption.textContent = heading;
table.prepend(caption);
}
- if (container && container.scrollWidth > container.clientWidth) {
- container.tabIndex = 0;
- container.setAttribute("role", "region");
- container.setAttribute("aria-label", `${heading}, scrollable table`);
- }
+ stackActionTable(table);
+ markScrollable(container, heading);
const rows = Array.from(table.querySelectorAll("tbody tr"));
if (rows.length < 20 || !container || container.dataset.rbFilter === "true") {
@@ -88,10 +136,15 @@
const heading = dialog.querySelector("h1, h2, h3");
dialog.setAttribute("aria-label", heading?.textContent.trim() || "Site search");
});
- document.querySelectorAll('[role="progressbar"]').forEach((progress) => {
- if (!progress.hasAttribute("aria-label") && !progress.hasAttribute("aria-labelledby")) {
- progress.setAttribute("aria-label", "Loading page");
- }
+ // The page-load bar is drawn for the eye only: the new page announces
+ // itself when it arrives.
+ document.querySelectorAll(".md-progress").forEach((progress) => {
+ progress.setAttribute("aria-hidden", "true");
+ });
+ // Material wraps each copy button in a nav element: one unnamed
+ // navigation landmark per code block. The button stays, the landmark goes.
+ document.querySelectorAll("nav.md-code__nav").forEach((nav) => {
+ nav.setAttribute("role", "none");
});
};
@@ -130,6 +183,16 @@
resolveFileAddress();
};
+ let resizeTimer = 0;
+ window.addEventListener("resize", () => {
+ window.clearTimeout(resizeTimer);
+ resizeTimer = window.setTimeout(recheckScrollable, 150);
+ });
+ document.addEventListener("toggle", recheckScrollable, true);
+ document.addEventListener("change", (event) => {
+ if (event.target.matches?.(".tabbed-set > input")) recheckScrollable();
+ });
+
if (window.document$?.subscribe) {
window.document$.subscribe(enhance);
} else if (document.readyState === "loading") {
diff --git a/docs_assets/system-icons/APF - Imagination Machine.png b/docs_assets/system-icons/APF - Imagination Machine.png
new file mode 100644
index 00000000..555187b6
Binary files /dev/null and b/docs_assets/system-icons/APF - Imagination Machine.png differ
diff --git a/docs_assets/system-icons/Acorn - Archimedes.png b/docs_assets/system-icons/Acorn - Archimedes.png
new file mode 100644
index 00000000..2095ae00
Binary files /dev/null and b/docs_assets/system-icons/Acorn - Archimedes.png differ
diff --git a/docs_assets/system-icons/Acorn - BBC Micro.png b/docs_assets/system-icons/Acorn - BBC Micro.png
new file mode 100644
index 00000000..884d75b4
Binary files /dev/null and b/docs_assets/system-icons/Acorn - BBC Micro.png differ
diff --git a/docs_assets/system-icons/Amstrad - CPC.png b/docs_assets/system-icons/Amstrad - CPC.png
new file mode 100644
index 00000000..7f662b08
Binary files /dev/null and b/docs_assets/system-icons/Amstrad - CPC.png differ
diff --git a/docs_assets/system-icons/Apple - Macintosh.png b/docs_assets/system-icons/Apple - Macintosh.png
new file mode 100644
index 00000000..5ebf86fd
Binary files /dev/null and b/docs_assets/system-icons/Apple - Macintosh.png differ
diff --git a/docs_assets/system-icons/Aquaplus - PIECE.png b/docs_assets/system-icons/Aquaplus - PIECE.png
new file mode 100644
index 00000000..8175bd5d
Binary files /dev/null and b/docs_assets/system-icons/Aquaplus - PIECE.png differ
diff --git a/docs_assets/system-icons/Atari - 2600.png b/docs_assets/system-icons/Atari - 2600.png
new file mode 100644
index 00000000..7371a2ad
Binary files /dev/null and b/docs_assets/system-icons/Atari - 2600.png differ
diff --git a/docs_assets/system-icons/Atari - 5200.png b/docs_assets/system-icons/Atari - 5200.png
new file mode 100644
index 00000000..ab577ecd
Binary files /dev/null and b/docs_assets/system-icons/Atari - 5200.png differ
diff --git a/docs_assets/system-icons/Atari - 7800.png b/docs_assets/system-icons/Atari - 7800.png
new file mode 100644
index 00000000..14e55633
Binary files /dev/null and b/docs_assets/system-icons/Atari - 7800.png differ
diff --git a/docs_assets/system-icons/Atari - Jaguar.png b/docs_assets/system-icons/Atari - Jaguar.png
new file mode 100644
index 00000000..a97bc861
Binary files /dev/null and b/docs_assets/system-icons/Atari - Jaguar.png differ
diff --git a/docs_assets/system-icons/Atari - Lynx.png b/docs_assets/system-icons/Atari - Lynx.png
new file mode 100644
index 00000000..e41d17a1
Binary files /dev/null and b/docs_assets/system-icons/Atari - Lynx.png differ
diff --git a/docs_assets/system-icons/Atari - ST.png b/docs_assets/system-icons/Atari - ST.png
new file mode 100644
index 00000000..c1fc39ef
Binary files /dev/null and b/docs_assets/system-icons/Atari - ST.png differ
diff --git a/docs_assets/system-icons/Atari - XEGS.png b/docs_assets/system-icons/Atari - XEGS.png
new file mode 100644
index 00000000..13142d95
Binary files /dev/null and b/docs_assets/system-icons/Atari - XEGS.png differ
diff --git a/docs_assets/system-icons/Bally - Astrocade.png b/docs_assets/system-icons/Bally - Astrocade.png
new file mode 100644
index 00000000..3cdfe989
Binary files /dev/null and b/docs_assets/system-icons/Bally - Astrocade.png differ
diff --git a/docs_assets/system-icons/Bandai - WonderSwan.png b/docs_assets/system-icons/Bandai - WonderSwan.png
new file mode 100644
index 00000000..1a6466c4
Binary files /dev/null and b/docs_assets/system-icons/Bandai - WonderSwan.png differ
diff --git a/docs_assets/system-icons/Bit Corporation - Gamate.png b/docs_assets/system-icons/Bit Corporation - Gamate.png
new file mode 100644
index 00000000..e2e8d9b8
Binary files /dev/null and b/docs_assets/system-icons/Bit Corporation - Gamate.png differ
diff --git a/docs_assets/system-icons/Casio - Loopy.png b/docs_assets/system-icons/Casio - Loopy.png
new file mode 100644
index 00000000..041e2dc6
Binary files /dev/null and b/docs_assets/system-icons/Casio - Loopy.png differ
diff --git a/docs_assets/system-icons/Casio - PV-2000.png b/docs_assets/system-icons/Casio - PV-2000.png
new file mode 100644
index 00000000..eb77b978
Binary files /dev/null and b/docs_assets/system-icons/Casio - PV-2000.png differ
diff --git a/docs_assets/system-icons/Coleco - ColecoVision.png b/docs_assets/system-icons/Coleco - ColecoVision.png
new file mode 100644
index 00000000..d09b36be
Binary files /dev/null and b/docs_assets/system-icons/Coleco - ColecoVision.png differ
diff --git a/docs_assets/system-icons/Commodore - Amiga.png b/docs_assets/system-icons/Commodore - Amiga.png
new file mode 100644
index 00000000..c437d3b5
Binary files /dev/null and b/docs_assets/system-icons/Commodore - Amiga.png differ
diff --git a/docs_assets/system-icons/Commodore - VIC-20.png b/docs_assets/system-icons/Commodore - VIC-20.png
new file mode 100644
index 00000000..21b31423
Binary files /dev/null and b/docs_assets/system-icons/Commodore - VIC-20.png differ
diff --git a/docs_assets/system-icons/Entex - Adventure Vision.png b/docs_assets/system-icons/Entex - Adventure Vision.png
new file mode 100644
index 00000000..667ef134
Binary files /dev/null and b/docs_assets/system-icons/Entex - Adventure Vision.png differ
diff --git a/docs_assets/system-icons/Epoch - Super Cassette Vision.png b/docs_assets/system-icons/Epoch - Super Cassette Vision.png
new file mode 100644
index 00000000..c1587518
Binary files /dev/null and b/docs_assets/system-icons/Epoch - Super Cassette Vision.png differ
diff --git a/docs_assets/system-icons/Fairchild - Channel F.png b/docs_assets/system-icons/Fairchild - Channel F.png
new file mode 100644
index 00000000..cba04c4d
Binary files /dev/null and b/docs_assets/system-icons/Fairchild - Channel F.png differ
diff --git a/docs_assets/system-icons/Fujitsu - FM Towns.png b/docs_assets/system-icons/Fujitsu - FM Towns.png
new file mode 100644
index 00000000..69ab318b
Binary files /dev/null and b/docs_assets/system-icons/Fujitsu - FM Towns.png differ
diff --git a/docs_assets/system-icons/Fujitsu - FM-7.png b/docs_assets/system-icons/Fujitsu - FM-7.png
new file mode 100644
index 00000000..455a850d
Binary files /dev/null and b/docs_assets/system-icons/Fujitsu - FM-7.png differ
diff --git a/docs_assets/system-icons/GCE - Vectrex.png b/docs_assets/system-icons/GCE - Vectrex.png
new file mode 100644
index 00000000..56b2b9da
Binary files /dev/null and b/docs_assets/system-icons/GCE - Vectrex.png differ
diff --git a/docs_assets/system-icons/GamePark - GP32.png b/docs_assets/system-icons/GamePark - GP32.png
new file mode 100644
index 00000000..218bf89c
Binary files /dev/null and b/docs_assets/system-icons/GamePark - GP32.png differ
diff --git a/docs_assets/system-icons/Hartung - Game Master.png b/docs_assets/system-icons/Hartung - Game Master.png
new file mode 100644
index 00000000..95546412
Binary files /dev/null and b/docs_assets/system-icons/Hartung - Game Master.png differ
diff --git a/docs_assets/system-icons/Infocom - Z-Machine.png b/docs_assets/system-icons/Infocom - Z-Machine.png
new file mode 100644
index 00000000..e3b45c71
Binary files /dev/null and b/docs_assets/system-icons/Infocom - Z-Machine.png differ
diff --git a/docs_assets/system-icons/Magnavox - Odyssey2.png b/docs_assets/system-icons/Magnavox - Odyssey2.png
new file mode 100644
index 00000000..550cb1cd
Binary files /dev/null and b/docs_assets/system-icons/Magnavox - Odyssey2.png differ
diff --git a/docs_assets/system-icons/Mattel - Intellivision.png b/docs_assets/system-icons/Mattel - Intellivision.png
new file mode 100644
index 00000000..8f0b3c11
Binary files /dev/null and b/docs_assets/system-icons/Mattel - Intellivision.png differ
diff --git a/docs_assets/system-icons/Microsoft - MSX.png b/docs_assets/system-icons/Microsoft - MSX.png
new file mode 100644
index 00000000..02767eb8
Binary files /dev/null and b/docs_assets/system-icons/Microsoft - MSX.png differ
diff --git a/docs_assets/system-icons/Microsoft - Xbox.png b/docs_assets/system-icons/Microsoft - Xbox.png
new file mode 100644
index 00000000..8a43ff96
Binary files /dev/null and b/docs_assets/system-icons/Microsoft - Xbox.png differ
diff --git a/docs_assets/system-icons/NEC - PC-88.png b/docs_assets/system-icons/NEC - PC-88.png
new file mode 100644
index 00000000..3d25da4d
Binary files /dev/null and b/docs_assets/system-icons/NEC - PC-88.png differ
diff --git a/docs_assets/system-icons/NEC - PC-98.png b/docs_assets/system-icons/NEC - PC-98.png
new file mode 100644
index 00000000..baf2062f
Binary files /dev/null and b/docs_assets/system-icons/NEC - PC-98.png differ
diff --git a/docs_assets/system-icons/NEC - PC-FX.png b/docs_assets/system-icons/NEC - PC-FX.png
new file mode 100644
index 00000000..2669847e
Binary files /dev/null and b/docs_assets/system-icons/NEC - PC-FX.png differ
diff --git a/docs_assets/system-icons/Nintendo - Game Boy Advance.png b/docs_assets/system-icons/Nintendo - Game Boy Advance.png
new file mode 100644
index 00000000..a475840c
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Game Boy Advance.png differ
diff --git a/docs_assets/system-icons/Nintendo - Game Boy Color.png b/docs_assets/system-icons/Nintendo - Game Boy Color.png
new file mode 100644
index 00000000..aa33b387
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Game Boy Color.png differ
diff --git a/docs_assets/system-icons/Nintendo - Game Boy.png b/docs_assets/system-icons/Nintendo - Game Boy.png
new file mode 100644
index 00000000..3a7277b8
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Game Boy.png differ
diff --git a/docs_assets/system-icons/Nintendo - GameCube.png b/docs_assets/system-icons/Nintendo - GameCube.png
new file mode 100644
index 00000000..0ff194ea
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - GameCube.png differ
diff --git a/docs_assets/system-icons/Nintendo - Nintendo 64.png b/docs_assets/system-icons/Nintendo - Nintendo 64.png
new file mode 100644
index 00000000..472e841d
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Nintendo 64.png differ
diff --git a/docs_assets/system-icons/Nintendo - Nintendo 64DD.png b/docs_assets/system-icons/Nintendo - Nintendo 64DD.png
new file mode 100644
index 00000000..15e472ce
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Nintendo 64DD.png differ
diff --git a/docs_assets/system-icons/Nintendo - Nintendo DS.png b/docs_assets/system-icons/Nintendo - Nintendo DS.png
new file mode 100644
index 00000000..e1a6c595
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Nintendo DS.png differ
diff --git a/docs_assets/system-icons/Nintendo - Pokemon Mini.png b/docs_assets/system-icons/Nintendo - Pokemon Mini.png
new file mode 100644
index 00000000..e3fc20ed
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Pokemon Mini.png differ
diff --git a/docs_assets/system-icons/Nintendo - Satellaview.png b/docs_assets/system-icons/Nintendo - Satellaview.png
new file mode 100644
index 00000000..372bda66
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Satellaview.png differ
diff --git a/docs_assets/system-icons/Nintendo - Switch.png b/docs_assets/system-icons/Nintendo - Switch.png
new file mode 100644
index 00000000..b893522d
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Switch.png differ
diff --git a/docs_assets/system-icons/Nintendo - Wii U.png b/docs_assets/system-icons/Nintendo - Wii U.png
new file mode 100644
index 00000000..c9edbf32
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Wii U.png differ
diff --git a/docs_assets/system-icons/Nintendo - Wii.png b/docs_assets/system-icons/Nintendo - Wii.png
new file mode 100644
index 00000000..672080d8
Binary files /dev/null and b/docs_assets/system-icons/Nintendo - Wii.png differ
diff --git a/docs_assets/system-icons/Nokia - N-Gage.png b/docs_assets/system-icons/Nokia - N-Gage.png
new file mode 100644
index 00000000..7786f38b
Binary files /dev/null and b/docs_assets/system-icons/Nokia - N-Gage.png differ
diff --git a/docs_assets/system-icons/Philips - CD-i.png b/docs_assets/system-icons/Philips - CD-i.png
new file mode 100644
index 00000000..bc0811ad
Binary files /dev/null and b/docs_assets/system-icons/Philips - CD-i.png differ
diff --git a/docs_assets/system-icons/Philips - Videopac+.png b/docs_assets/system-icons/Philips - Videopac+.png
new file mode 100644
index 00000000..38e03916
Binary files /dev/null and b/docs_assets/system-icons/Philips - Videopac+.png differ
diff --git a/docs_assets/system-icons/Pioneer - LaserActive.png b/docs_assets/system-icons/Pioneer - LaserActive.png
new file mode 100644
index 00000000..5bcb3345
Binary files /dev/null and b/docs_assets/system-icons/Pioneer - LaserActive.png differ
diff --git a/docs_assets/system-icons/RCA - Studio II.png b/docs_assets/system-icons/RCA - Studio II.png
new file mode 100644
index 00000000..47c0914a
Binary files /dev/null and b/docs_assets/system-icons/RCA - Studio II.png differ
diff --git a/docs_assets/system-icons/SNK - Neo Geo CD.png b/docs_assets/system-icons/SNK - Neo Geo CD.png
new file mode 100644
index 00000000..e575a324
Binary files /dev/null and b/docs_assets/system-icons/SNK - Neo Geo CD.png differ
diff --git a/docs_assets/system-icons/SNK - Neo Geo Pocket.png b/docs_assets/system-icons/SNK - Neo Geo Pocket.png
new file mode 100644
index 00000000..ffa25ff5
Binary files /dev/null and b/docs_assets/system-icons/SNK - Neo Geo Pocket.png differ
diff --git a/docs_assets/system-icons/SNK - Neo Geo.png b/docs_assets/system-icons/SNK - Neo Geo.png
new file mode 100644
index 00000000..f7e28b61
Binary files /dev/null and b/docs_assets/system-icons/SNK - Neo Geo.png differ
diff --git a/docs_assets/system-icons/Sega - 32X.png b/docs_assets/system-icons/Sega - 32X.png
new file mode 100644
index 00000000..292b22dd
Binary files /dev/null and b/docs_assets/system-icons/Sega - 32X.png differ
diff --git a/docs_assets/system-icons/Sega - Beena.png b/docs_assets/system-icons/Sega - Beena.png
new file mode 100644
index 00000000..3deee872
Binary files /dev/null and b/docs_assets/system-icons/Sega - Beena.png differ
diff --git a/docs_assets/system-icons/Sega - Chihiro.png b/docs_assets/system-icons/Sega - Chihiro.png
new file mode 100644
index 00000000..6eab6438
Binary files /dev/null and b/docs_assets/system-icons/Sega - Chihiro.png differ
diff --git a/docs_assets/system-icons/Sega - Dreamcast.png b/docs_assets/system-icons/Sega - Dreamcast.png
new file mode 100644
index 00000000..739918a1
Binary files /dev/null and b/docs_assets/system-icons/Sega - Dreamcast.png differ
diff --git a/docs_assets/system-icons/Sega - Game Gear.png b/docs_assets/system-icons/Sega - Game Gear.png
new file mode 100644
index 00000000..169bbaa1
Binary files /dev/null and b/docs_assets/system-icons/Sega - Game Gear.png differ
diff --git a/docs_assets/system-icons/Sega - Saturn.png b/docs_assets/system-icons/Sega - Saturn.png
new file mode 100644
index 00000000..3c3a03c9
Binary files /dev/null and b/docs_assets/system-icons/Sega - Saturn.png differ
diff --git a/docs_assets/system-icons/Sharp - X1.png b/docs_assets/system-icons/Sharp - X1.png
new file mode 100644
index 00000000..055c9b95
Binary files /dev/null and b/docs_assets/system-icons/Sharp - X1.png differ
diff --git a/docs_assets/system-icons/Sharp - X68000.png b/docs_assets/system-icons/Sharp - X68000.png
new file mode 100644
index 00000000..fdc8380c
Binary files /dev/null and b/docs_assets/system-icons/Sharp - X68000.png differ
diff --git a/docs_assets/system-icons/Sinclair - ZX 81.png b/docs_assets/system-icons/Sinclair - ZX 81.png
new file mode 100644
index 00000000..db75644c
Binary files /dev/null and b/docs_assets/system-icons/Sinclair - ZX 81.png differ
diff --git a/docs_assets/system-icons/Sinclair - ZX Spectrum.png b/docs_assets/system-icons/Sinclair - ZX Spectrum.png
new file mode 100644
index 00000000..465ba9d5
Binary files /dev/null and b/docs_assets/system-icons/Sinclair - ZX Spectrum.png differ
diff --git a/docs_assets/system-icons/Sony - PlayStation 2.png b/docs_assets/system-icons/Sony - PlayStation 2.png
new file mode 100644
index 00000000..f32ab5ea
Binary files /dev/null and b/docs_assets/system-icons/Sony - PlayStation 2.png differ
diff --git a/docs_assets/system-icons/Sony - PlayStation 4.png b/docs_assets/system-icons/Sony - PlayStation 4.png
new file mode 100644
index 00000000..ac2577ff
Binary files /dev/null and b/docs_assets/system-icons/Sony - PlayStation 4.png differ
diff --git a/docs_assets/system-icons/Sony - PlayStation Portable.png b/docs_assets/system-icons/Sony - PlayStation Portable.png
new file mode 100644
index 00000000..6516ef4b
Binary files /dev/null and b/docs_assets/system-icons/Sony - PlayStation Portable.png differ
diff --git a/docs_assets/system-icons/Sony - PlayStation Vita.png b/docs_assets/system-icons/Sony - PlayStation Vita.png
new file mode 100644
index 00000000..81c5710d
Binary files /dev/null and b/docs_assets/system-icons/Sony - PlayStation Vita.png differ
diff --git a/docs_assets/system-icons/Sony - PlayStation.png b/docs_assets/system-icons/Sony - PlayStation.png
new file mode 100644
index 00000000..cb5cbc3c
Binary files /dev/null and b/docs_assets/system-icons/Sony - PlayStation.png differ
diff --git a/docs_assets/system-icons/Texas Instruments - TI-83.png b/docs_assets/system-icons/Texas Instruments - TI-83.png
new file mode 100644
index 00000000..7419784f
Binary files /dev/null and b/docs_assets/system-icons/Texas Instruments - TI-83.png differ
diff --git a/docs_assets/system-icons/Tiger - Game.com.png b/docs_assets/system-icons/Tiger - Game.com.png
new file mode 100644
index 00000000..3accb44a
Binary files /dev/null and b/docs_assets/system-icons/Tiger - Game.com.png differ
diff --git a/docs_assets/system-icons/Tomy - Tutor.png b/docs_assets/system-icons/Tomy - Tutor.png
new file mode 100644
index 00000000..81677a2d
Binary files /dev/null and b/docs_assets/system-icons/Tomy - Tutor.png differ
diff --git a/docs_assets/system-icons/VTech - CreatiVision.png b/docs_assets/system-icons/VTech - CreatiVision.png
new file mode 100644
index 00000000..9635d68a
Binary files /dev/null and b/docs_assets/system-icons/VTech - CreatiVision.png differ
diff --git a/docs_assets/system-icons/VTech - Socrates.png b/docs_assets/system-icons/VTech - Socrates.png
new file mode 100644
index 00000000..eb6c98ad
Binary files /dev/null and b/docs_assets/system-icons/VTech - Socrates.png differ
diff --git a/docs_assets/system-icons/VTech - V.Smile.png b/docs_assets/system-icons/VTech - V.Smile.png
new file mode 100644
index 00000000..c89421e9
Binary files /dev/null and b/docs_assets/system-icons/VTech - V.Smile.png differ
diff --git a/docs_assets/system-icons/Videoton - TVC.png b/docs_assets/system-icons/Videoton - TVC.png
new file mode 100644
index 00000000..77be9b45
Binary files /dev/null and b/docs_assets/system-icons/Videoton - TVC.png differ
diff --git a/docs_assets/system-icons/sources.json b/docs_assets/system-icons/sources.json
new file mode 100644
index 00000000..9e65327f
--- /dev/null
+++ b/docs_assets/system-icons/sources.json
@@ -0,0 +1,321 @@
+{
+ "note": "System icons from libretro/retroarch-assets (xmb/systematic), licensed CC-BY-4.0 by the libretro team. Resized to 48 px.",
+ "images": [
+ {
+ "file": "APF - Imagination Machine.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/APF%20-%20Imagination%20Machine.png"
+ },
+ {
+ "file": "Acorn - Archimedes.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Acorn%20-%20Archimedes.png"
+ },
+ {
+ "file": "Acorn - BBC Micro.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Acorn%20-%20BBC%20Micro.png"
+ },
+ {
+ "file": "Amstrad - CPC.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Amstrad%20-%20CPC.png"
+ },
+ {
+ "file": "Apple - Macintosh.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Apple%20-%20Macintosh.png"
+ },
+ {
+ "file": "Aquaplus - PIECE.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Aquaplus%20-%20PIECE.png"
+ },
+ {
+ "file": "Atari - 2600.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%202600.png"
+ },
+ {
+ "file": "Atari - 5200.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%205200.png"
+ },
+ {
+ "file": "Atari - 7800.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%207800.png"
+ },
+ {
+ "file": "Atari - Jaguar.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%20Jaguar.png"
+ },
+ {
+ "file": "Atari - Lynx.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%20Lynx.png"
+ },
+ {
+ "file": "Atari - ST.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%20ST.png"
+ },
+ {
+ "file": "Atari - XEGS.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Atari%20-%20XEGS.png"
+ },
+ {
+ "file": "Bally - Astrocade.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Bally%20-%20Astrocade.png"
+ },
+ {
+ "file": "Bandai - WonderSwan.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Bandai%20-%20WonderSwan.png"
+ },
+ {
+ "file": "Bit Corporation - Gamate.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Bit%20Corporation%20-%20Gamate.png"
+ },
+ {
+ "file": "Casio - Loopy.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Casio%20-%20Loopy.png"
+ },
+ {
+ "file": "Casio - PV-2000.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Casio%20-%20PV-2000.png"
+ },
+ {
+ "file": "Coleco - ColecoVision.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Coleco%20-%20ColecoVision.png"
+ },
+ {
+ "file": "Commodore - Amiga.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Commodore%20-%20Amiga.png"
+ },
+ {
+ "file": "Commodore - VIC-20.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Commodore%20-%20VIC-20.png"
+ },
+ {
+ "file": "Entex - Adventure Vision.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Entex%20-%20Adventure%20Vision.png"
+ },
+ {
+ "file": "Epoch - Super Cassette Vision.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Epoch%20-%20Super%20Cassette%20Vision.png"
+ },
+ {
+ "file": "Fairchild - Channel F.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Fairchild%20-%20Channel%20F.png"
+ },
+ {
+ "file": "Fujitsu - FM Towns.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Fujitsu%20-%20FM%20Towns.png"
+ },
+ {
+ "file": "Fujitsu - FM-7.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Fujitsu%20-%20FM-7.png"
+ },
+ {
+ "file": "GCE - Vectrex.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/GCE%20-%20Vectrex.png"
+ },
+ {
+ "file": "GamePark - GP32.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/GamePark%20-%20GP32.png"
+ },
+ {
+ "file": "Hartung - Game Master.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Hartung%20-%20Game%20Master.png"
+ },
+ {
+ "file": "Infocom - Z-Machine.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Infocom%20-%20Z-Machine.png"
+ },
+ {
+ "file": "Magnavox - Odyssey2.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Magnavox%20-%20Odyssey2.png"
+ },
+ {
+ "file": "Mattel - Intellivision.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Mattel%20-%20Intellivision.png"
+ },
+ {
+ "file": "Microsoft - MSX.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Microsoft%20-%20MSX.png"
+ },
+ {
+ "file": "Microsoft - Xbox.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Microsoft%20-%20Xbox.png"
+ },
+ {
+ "file": "NEC - PC-88.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/NEC%20-%20PC-88.png"
+ },
+ {
+ "file": "NEC - PC-98.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/NEC%20-%20PC-98.png"
+ },
+ {
+ "file": "NEC - PC-FX.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/NEC%20-%20PC-FX.png"
+ },
+ {
+ "file": "Nintendo - Game Boy Advance.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Game%20Boy%20Advance.png"
+ },
+ {
+ "file": "Nintendo - Game Boy Color.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Game%20Boy%20Color.png"
+ },
+ {
+ "file": "Nintendo - Game Boy.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Game%20Boy.png"
+ },
+ {
+ "file": "Nintendo - GameCube.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20GameCube.png"
+ },
+ {
+ "file": "Nintendo - Nintendo 64.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Nintendo%2064.png"
+ },
+ {
+ "file": "Nintendo - Nintendo 64DD.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Nintendo%2064DD.png"
+ },
+ {
+ "file": "Nintendo - Nintendo DS.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Nintendo%20DS.png"
+ },
+ {
+ "file": "Nintendo - Pokemon Mini.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Pokemon%20Mini.png"
+ },
+ {
+ "file": "Nintendo - Satellaview.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Satellaview.png"
+ },
+ {
+ "file": "Nintendo - Switch.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Switch.png"
+ },
+ {
+ "file": "Nintendo - Wii U.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Wii%20U.png"
+ },
+ {
+ "file": "Nintendo - Wii.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nintendo%20-%20Wii.png"
+ },
+ {
+ "file": "Nokia - N-Gage.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Nokia%20-%20N-Gage.png"
+ },
+ {
+ "file": "Philips - CD-i.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Philips%20-%20CD-i.png"
+ },
+ {
+ "file": "Philips - Videopac+.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Philips%20-%20Videopac%2B.png"
+ },
+ {
+ "file": "Pioneer - LaserActive.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Pioneer%20-%20LaserActive.png"
+ },
+ {
+ "file": "RCA - Studio II.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/RCA%20-%20Studio%20II.png"
+ },
+ {
+ "file": "SNK - Neo Geo CD.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/SNK%20-%20Neo%20Geo%20CD.png"
+ },
+ {
+ "file": "SNK - Neo Geo Pocket.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/SNK%20-%20Neo%20Geo%20Pocket.png"
+ },
+ {
+ "file": "SNK - Neo Geo.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/SNK%20-%20Neo%20Geo.png"
+ },
+ {
+ "file": "Sega - 32X.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%2032X.png"
+ },
+ {
+ "file": "Sega - Beena.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%20Beena.png"
+ },
+ {
+ "file": "Sega - Chihiro.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%20Chihiro.png"
+ },
+ {
+ "file": "Sega - Dreamcast.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%20Dreamcast.png"
+ },
+ {
+ "file": "Sega - Game Gear.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%20Game%20Gear.png"
+ },
+ {
+ "file": "Sega - Saturn.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sega%20-%20Saturn.png"
+ },
+ {
+ "file": "Sharp - X1.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sharp%20-%20X1.png"
+ },
+ {
+ "file": "Sharp - X68000.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sharp%20-%20X68000.png"
+ },
+ {
+ "file": "Sinclair - ZX 81.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sinclair%20-%20ZX%2081.png"
+ },
+ {
+ "file": "Sinclair - ZX Spectrum.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sinclair%20-%20ZX%20Spectrum.png"
+ },
+ {
+ "file": "Sony - PlayStation 2.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sony%20-%20PlayStation%202.png"
+ },
+ {
+ "file": "Sony - PlayStation 4.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sony%20-%20PlayStation%204.png"
+ },
+ {
+ "file": "Sony - PlayStation Portable.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sony%20-%20PlayStation%20Portable.png"
+ },
+ {
+ "file": "Sony - PlayStation Vita.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sony%20-%20PlayStation%20Vita.png"
+ },
+ {
+ "file": "Sony - PlayStation.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Sony%20-%20PlayStation.png"
+ },
+ {
+ "file": "Texas Instruments - TI-83.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Texas%20Instruments%20-%20TI-83.png"
+ },
+ {
+ "file": "Tiger - Game.com.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Tiger%20-%20Game.com.png"
+ },
+ {
+ "file": "Tomy - Tutor.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Tomy%20-%20Tutor.png"
+ },
+ {
+ "file": "VTech - CreatiVision.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/VTech%20-%20CreatiVision.png"
+ },
+ {
+ "file": "VTech - Socrates.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/VTech%20-%20Socrates.png"
+ },
+ {
+ "file": "VTech - V.Smile.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/VTech%20-%20V.Smile.png"
+ },
+ {
+ "file": "Videoton - TVC.png",
+ "source": "https://raw.githubusercontent.com/libretro/retroarch-assets/master/xmb/systematic/png/Videoton%20-%20TVC.png"
+ }
+ ]
+}
diff --git a/platforms/_registry.yml b/platforms/_registry.yml
index 8156d33a..81e15bf5 100644
--- a/platforms/_registry.yml
+++ b/platforms/_registry.yml
@@ -673,7 +673,7 @@ platforms:
status: active
device_group: server
extract_to: library/bios/
- logo: https://avatars.githubusercontent.com/u/168586850
+ logo: https://avatars.githubusercontent.com/u/164058018
scraper: romm
source_url: https://raw.githubusercontent.com/rommapp/romm/master/backend/models/fixtures/known_bios_files.json
source_format: json
@@ -736,7 +736,7 @@ platforms:
status: active
device_group: handheld
extract_to: /storage/roms/bios/
- logo: https://avatars.githubusercontent.com/u/152618023
+ logo: https://avatars.githubusercontent.com/u/163176886
scraper: rocknix
schedule: weekly
target_scraper: rocknix_targets
@@ -912,7 +912,7 @@ platforms:
status: active
device_group: fpga
extract_to: /media/fat/games/
- logo: https://avatars.githubusercontent.com/u/47264183
+ logo: https://avatars.githubusercontent.com/u/29345272
scraper: misterfpga
source_url: https://raw.githubusercontent.com/ajgowans/BiosDB_MiSTer/db/bios_db.json.zip
source_format: mister_downloader_db
@@ -998,7 +998,6 @@ platforms:
# minarch hands each core SDCARD_PATH/Bios/
# (workspace/all/minarch/minarch.c:3532).
extract_to: /
- logo: https://avatars.githubusercontent.com/u/10894566
scraper: myminui
# minarch hands each core a folder and names no file (workspace/all/minarch/minarch.c:3532):
# there is no BIOS list of its own to export corrected.
diff --git a/scripts/fetch_site_images.py b/scripts/fetch_site_images.py
new file mode 100644
index 00000000..410b0214
--- /dev/null
+++ b/scripts/fetch_site_images.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+"""Download the platform logos and system icons the site shows, once.
+
+The site served these from other hosts: GitHub avatars and files on the
+``master`` branch of upstream repositories. A rename upstream broke an image
+in silence, and every page view hit third-party hosts. This tool copies them
+into ``docs_assets/logos/`` and ``docs_assets/system-icons/``, which are
+committed, and records where each came from in a ``sources.json`` beside
+them. The site build only reads those copies (``sitediagrams.localize_images``).
+
+Raster images are normalised to a square PNG (96 px for logos, 48 px for
+system icons) so every tile has the same weight; SVG is kept as published.
+Normalising needs Pillow. This is a maintenance tool run by hand when a
+logo changes, not a build step: the build stays on the standard library
+and PyYAML.
+
+ python scripts/fetch_site_images.py # logos and icons
+ python scripts/fetch_site_images.py --only logos
+"""
+
+from __future__ import annotations
+
+import argparse
+import io
+import json
+import sys
+import urllib.error
+import urllib.parse
+import urllib.request
+from pathlib import Path
+
+import yaml
+
+ROOT = Path(__file__).resolve().parent.parent
+sys.path.insert(0, str(ROOT / "scripts"))
+
+LOGO_DIR = ROOT / "docs_assets" / "logos"
+ICON_DIR = ROOT / "docs_assets" / "system-icons"
+LOGO_SIZE = 96
+ICON_SIZE = 48
+AVATAR_HOST = "avatars.githubusercontent.com"
+USER_AGENT = "retrobios-site-images"
+
+# Who owns each mark. Logos are shown to name the platform they belong to;
+# the note says so, and gives the licence of the repository the file was
+# taken from when that repository states one.
+OWNERS = {
+ "retroarch": ("libretro", "repository licence GPL-3.0"),
+ "lakka": ("Lakka (libretro)", "file from libretro/retroarch-assets, CC-BY-4.0"),
+ "batocera": ("Batocera", "repository licence MIT"),
+ "recalbox": ("Recalbox", "file from homarr-labs/dashboard-icons, Apache-2.0"),
+ "retrobat": ("RetroBat", "repository states no licence"),
+ "emudeck": ("EmuDeck", "repository licence GPL-3.0"),
+ "retrodeck": ("RetroDECK", "repository licence GPL-3.0"),
+ "romm": ("RomM", "GitHub organisation avatar of rommapp"),
+ "rocknix": ("ROCKNIX", "GitHub organisation avatar of ROCKNIX"),
+ "amberelec": ("AmberELEC", "GitHub organisation avatar of AmberELEC"),
+ "emuelec": ("EmuELEC", "GitHub organisation avatar of EmuELEC"),
+ "knulli": ("KNULLI", "GitHub organisation avatar of knulli-cfw"),
+ "retropie": ("RetroPie", "GitHub organisation avatar of RetroPie"),
+ "bizhawk": ("TASVideos", "GitHub organisation avatar of TASEmulators"),
+ "misterfpga": ("MiSTer FPGA", "GitHub organisation avatar of MiSTer-devel"),
+ "minui": ("Shaun Inman", "GitHub avatar of shauninman, the author of MinUI"),
+ "nextui": ("LoveRetro", "GitHub organisation avatar of LoveRetro"),
+}
+
+
+def fetch(url: str) -> bytes:
+ request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
+ with urllib.request.urlopen(request, timeout=60) as response:
+ return response.read()
+
+
+def square_png(data: bytes, size: int) -> bytes:
+ try:
+ from PIL import Image
+ except ImportError as exc:
+ raise SystemExit("Pillow is needed to normalise raster images: pip install Pillow") from exc
+ image = Image.open(io.BytesIO(data)).convert("RGBA")
+ image.thumbnail((size, size), Image.LANCZOS)
+ tile = Image.new("RGBA", (size, size), (0, 0, 0, 0))
+ tile.paste(image, ((size - image.width) // 2, (size - image.height) // 2), image)
+ out = io.BytesIO()
+ tile.save(out, "PNG", optimize=True)
+ return out.getvalue()
+
+
+def is_svg(data: bytes) -> bool:
+ head = data[:512].lstrip().lower()
+ return head.startswith(b" bytes:
+ lowered = data.lower()
+ for token in (b"