commit a22a9c98268c1f3ba912e3bccff65bf65a450adc Author: ssmithx Date: Tue Sep 1 11:32:58 2026 +0000 Initial scaffold: ArchyHCL, a community hardware compatibility list for Archipelago Modeled on three researched precedents (see README): OpenWrt's Table of Hardware for the browsable sortable/filterable table UX, postmarketOS's working/community/testing tiers for the status field (collapsed to working/partial/broken here), and RaspiBlitz's scattered GitHub-issues approach as a negative example to avoid — hence structured YAML report files validated against a JSON Schema instead of free-text issue threads. - data/reports/*.yml + data/schema.json: one file per report, schema requires `issues` whenever status is partial/broken - scripts/build.py: validates every report and builds site/data.json, fails loudly on bad data (same idea as archy's own validate-app-manifest.sh) - site/: plain HTML/CSS/JS, no framework or build step, fetches data.json client-side — search, filter by status/form-factor, sortable columns, click a row for issues/notes detail - .github/ISSUE_TEMPLATE/hardware-report.yml: structured submission path for contributors who don't want to touch git directly - .gitea/workflows/ci.yml: runs the build/validate step on push and PRs Not yet deployed anywhere — see README's Deployment section. Co-Authored-By: Claude Sonnet 5 diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..cf65c59 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,27 @@ +name: Build and validate + +on: + push: + branches: [main] + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies + run: pip install pyyaml jsonschema + + - name: Build and validate every report + run: python3 scripts/build.py diff --git a/.github/ISSUE_TEMPLATE/hardware-report.yml b/.github/ISSUE_TEMPLATE/hardware-report.yml new file mode 100644 index 0000000..8163f86 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/hardware-report.yml @@ -0,0 +1,116 @@ +name: Hardware report +description: Report a device you've installed Archipelago on, working or not. +title: "hw: " +labels: ["hardware-report"] +body: + - type: markdown + attributes: + value: | + Thanks for reporting! A maintainer turns this into a data file under + `data/reports/` and it shows up on the site. If you're comfortable + with git, opening a PR directly is faster — see CONTRIBUTING.md. + - type: input + id: device_model + attributes: + label: Device model + placeholder: "Lenovo ThinkPad T430" + validations: + required: true + - type: dropdown + id: form_factor + attributes: + label: Form factor + options: + - laptop + - desktop + - mini-pc + - sbc + - server + - other + validations: + required: true + - type: input + id: cpu + attributes: + label: CPU + placeholder: "Intel Core i5-3320M" + validations: + required: true + - type: input + id: ram_gb + attributes: + label: RAM (GB) + placeholder: "8" + validations: + required: true + - type: input + id: storage + attributes: + label: Storage (type and size) + placeholder: "256GB SSD" + validations: + required: true + - type: input + id: wifi_chip + attributes: + label: WiFi chip + description: Exact chipset if you know it. Put "none" if wired-only. + placeholder: "Intel Centrino Advanced-N 6205" + validations: + required: true + - type: input + id: ethernet + attributes: + label: Ethernet chip (optional) + placeholder: "Intel 82579LM" + - type: input + id: archy_version + attributes: + label: Archipelago version tested + placeholder: "1.8.4-alpha" + validations: + required: true + - type: dropdown + id: install_method + attributes: + label: Install method + options: + - usb-iso + - netboot + - existing-os-script + - other + validations: + required: true + - type: dropdown + id: status + attributes: + label: Status + description: "working = no known issues. partial = runs with specific known issues (describe below). broken = does not install or run." + options: + - working + - partial + - broken + validations: + required: true + - type: input + id: tested_date + attributes: + label: Date tested + placeholder: "2026-08-21" + validations: + required: true + - type: textarea + id: issues + attributes: + label: Issues (required if status is partial or broken) + description: What broke, and any workaround you found. + - type: textarea + id: notes + attributes: + label: Other notes + description: BIOS/UEFI settings needed, quirks, links to a fuller writeup. + - type: input + id: submitted_by + attributes: + label: Attribution (optional) + description: Your npub, Gitea username, or leave blank to stay anonymous. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b908d4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.pyc +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c4dffbf --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing to ArchyHCL + +Two ways to add a report, pick whichever's easier for you. + +## Option A — open an issue (no git needed) + +[Open a hardware report issue](https://source.archipelago-foundation.org/lfg2025/ArchyHCL/issues/new?template=hardware-report.yml) +and fill in the form. A maintainer will turn it into a data file and it'll +show up on the site. + +## Option B — open a PR directly + +1. Copy `data/reports/example-thinkpad-t430.yml` to a new file named + `-.yml` (e.g. `thinkpad-t430-a1b2.yml` — the + suffix just needs to make the filename unique if the same model's been + reported before). +2. Fill in your report. Every field is described in + [`data/schema.json`](data/schema.json); `issues` is required if your + `status` is `partial` or `broken`. +3. Validate locally before opening the PR: + ```bash + pip install pyyaml jsonschema # if you don't have them + python3 scripts/build.py + ``` + This fails loudly (and tells you exactly which field) if anything's + wrong — same idea as [archy](https://source.archipelago-foundation.org/lfg2025/archy)'s + own `scripts/validate-app-manifest.sh`. +4. Open the PR. Once merged, `scripts/build.py` regenerates `site/data.json` + and the site picks it up. + +## Updating an existing report + +Devices change over time (firmware updates fix WiFi issues, etc.) — if +you're re-testing a device that's already listed, open a PR editing the +existing file rather than adding a duplicate. Keep the old `tested_date` +context in mind: bump it to your test date so readers know how fresh the +report is. + +## What makes a good report + +- Be exact about the WiFi chip if you can (`iwconfig`/`lspci` on Linux, + Device Manager on Windows if you dual-booted to check). "Realtek" alone + isn't as useful as "Realtek RTL8821CE" — chip-specific driver issues are + the single most common thing this list exists to surface. +- If `status` is `partial` or `broken`, describe *what* broke and *how you + noticed* (crash on boot? WiFi drops under load? specific app won't + start?) — "doesn't work" isn't actionable for the next person. +- If you found a workaround, put it in `notes` even if the underlying issue + isn't fixed. A working-with-a-workaround report is more useful than no + report at all. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f919e8e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 the Archipelago Project contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ead0b5b --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# ArchyHCL + +A community hardware compatibility list for [Archipelago](https://source.archipelago-foundation.org/lfg2025/archy) — +what physical devices people have actually installed it on, what worked, +what didn't, and why. Model, CPU, RAM, storage, and WiFi chip for every +report, since WiFi chipsets are consistently the thing most likely to bite +someone doing an install on repurposed hardware. + +**[Browse the list →](https://hcl.archipelago-foundation.org)** (once deployed — +see [Deployment](#deployment) below) + +## Why this exists + +Archipelago runs on whatever hardware people have lying around — old +laptops, mini PCs, SBCs — and that's a much wider, messier compatibility +surface than a project that only targets its own reference hardware. Before +building this, I looked at how a few existing communities solve the same +problem: + +- **[OpenWrt's Table of Hardware](https://toh.openwrt.org/)** — a + searchable table of routers, generated nightly from structured wiki + pages into a `toh.json` file the site reads. Good model for the + browsing UX (sortable/filterable table of CPU/RAM/flash/WiFi chip), but + the underlying wiki pages are free-text and only loosely structured, + which the maintainers themselves have called out as a maintenance + problem over the years. +- **[postmarketOS's device list](https://wiki.postmarketos.org/wiki/Devices)** — + tiers devices into `main` / `community` / `testing` support levels, each + with a per-device page describing exactly what works and what doesn't. + Good model for the *status* field: a single working/broken flag loses + the "boots fine but WiFi is flaky" middle ground that's actually the + most common and most useful case to document. +- **[RaspiBlitz](https://github.com/raspiblitz/raspiblitz)** (closest + project to Archipelago in spirit — a Bitcoin/Lightning node OS for + repurposed hardware) — hardware feedback mostly lives scattered across + GitHub issues with no consistent fields, which makes it hard to search + or compare reports. Useful as a negative example: this is what we're + trying to avoid by using structured data files instead of free-form + issue threads. + +**The model this repo uses**: one small YAML file per report +(`data/reports/*.yml`), validated against a JSON Schema, built into a +single `data.json` a plain static site reads — OpenWrt's browsable-table UX, +postmarketOS's tiered status field, and RaspiBlitz's actual subject matter +(node-OS-on-repurposed-hardware), on top of git-native, PR-reviewable data +instead of a wiki or a scattered issue tracker. + +## Repo layout + +``` +data/ + schema.json — the report schema (source of truth for what fields exist) + reports/*.yml — one file per hardware report +scripts/ + build.py — validates every report and builds site/data.json +site/ + index.html/.css/.js — the static site (no framework, no build step — just fetches data.json) +.gitea/issue_template/hardware-report.yml — structured issue form for reporting without git +``` + +## Contributing a report + +See [CONTRIBUTING.md](CONTRIBUTING.md) — either open an issue with the +structured form, or add a YAML file directly and open a PR. + +## Building the site locally + +```bash +pip install pyyaml jsonschema +python3 scripts/build.py # writes site/data.json +python3 -m http.server 8000 --directory site +``` + +## Deployment + +Not yet deployed. This is a static site (`site/`) with no backend — any +static host works (the same nginx-in-front-of-a-container pattern archy's +other apps already use, GitHub/Gitea Pages, or a plain S3-style bucket). +`scripts/build.py` should run in CI on every push to `main` so `data.json` +never drifts from the source reports; wiring that up is the next step. + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/data/reports/example-raspberry-pi-5.yml b/data/reports/example-raspberry-pi-5.yml new file mode 100644 index 0000000..9a43325 --- /dev/null +++ b/data/reports/example-raspberry-pi-5.yml @@ -0,0 +1,22 @@ +device_model: "Raspberry Pi 5 (8GB)" +form_factor: sbc +cpu: "Broadcom BCM2712 (4x Cortex-A76)" +ram_gb: 8 +storage: + type: nvme + size_gb: 512 +wifi_chip: "Broadcom BCM43455 (onboard)" +ethernet: "Broadcom onboard Gigabit" +archy_version: "1.8.4-alpha" +install_method: netboot +status: partial +tested_date: "2026-08-10" +submitted_by: "example-contributor" +issues: | + Example report — replace with a real one. Onboard WiFi drops the + connection under sustained heavy P2P traffic (Bitcoin IBD); a workaround + is to run over Ethernet instead. Everything else (Lightning, apps, + dashboard) works fine. +notes: | + NVMe via the official PCIe HAT. Boots noticeably faster than SD-card + installs. diff --git a/data/reports/example-thinkpad-t430.yml b/data/reports/example-thinkpad-t430.yml new file mode 100644 index 0000000..4d011f8 --- /dev/null +++ b/data/reports/example-thinkpad-t430.yml @@ -0,0 +1,18 @@ +device_model: "Lenovo ThinkPad T430" +form_factor: laptop +cpu: "Intel Core i5-3320M" +ram_gb: 8 +storage: + type: ssd + size_gb: 256 +wifi_chip: "Intel Centrino Advanced-N 6205" +ethernet: "Intel 82579LM" +archy_version: "1.8.4-alpha" +install_method: usb-iso +status: working +tested_date: "2026-08-15" +submitted_by: "example-contributor" +notes: | + Example report — replace with a real one. Boots and installs cleanly from + a USB stick made with the standard ISO. No BIOS changes needed beyond + enabling AHCI mode (should already be default on most T430s). diff --git a/data/schema.json b/data/schema.json new file mode 100644 index 0000000..9b68b47 --- /dev/null +++ b/data/schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ArchyHCL hardware report", + "description": "One reported install of Archipelago on a physical device. One file per report under data/reports/.", + "type": "object", + "required": ["device_model", "form_factor", "cpu", "ram_gb", "storage", "wifi_chip", "archy_version", "install_method", "status", "tested_date"], + "additionalProperties": false, + "properties": { + "device_model": { + "type": "string", + "description": "Manufacturer + model, e.g. \"Lenovo ThinkPad T430\" or \"Raspberry Pi 5 8GB\"." + }, + "form_factor": { + "type": "string", + "enum": ["laptop", "desktop", "mini-pc", "sbc", "server", "other"] + }, + "cpu": { + "type": "string", + "description": "e.g. \"Intel Core i5-3320M\", \"Broadcom BCM2712\"." + }, + "ram_gb": { + "type": "number", + "exclusiveMinimum": 0 + }, + "storage": { + "type": "object", + "required": ["type", "size_gb"], + "additionalProperties": false, + "properties": { + "type": { "type": "string", "enum": ["hdd", "ssd", "nvme", "emmc", "sd"] }, + "size_gb": { "type": "number", "exclusiveMinimum": 0 } + } + }, + "wifi_chip": { + "type": "string", + "description": "Exact chipset if known, e.g. \"Intel Centrino Advanced-N 6205\". Use \"none\" for wired-only setups." + }, + "ethernet": { + "type": "string", + "description": "Optional — matters for a node OS more than most HCLs. e.g. \"Intel 82579LM\"." + }, + "archy_version": { + "type": "string", + "description": "Exact Archipelago version tested, e.g. \"1.8.4-alpha\"." + }, + "install_method": { + "type": "string", + "enum": ["usb-iso", "netboot", "existing-os-script", "other"] + }, + "status": { + "type": "string", + "enum": ["working", "partial", "broken"], + "description": "working = installs and runs with no known issues. partial = installs and runs but with specific known issues (detail in `issues`). broken = does not install or does not run at all." + }, + "tested_date": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "submitted_by": { + "type": "string", + "description": "Optional attribution — nostr npub, Gitea username, or leave unset for anonymous." + }, + "issues": { + "type": "string", + "description": "Required detail when status is partial or broken. Free text: what broke, workarounds found." + }, + "notes": { + "type": "string", + "description": "Anything else useful: BIOS/UEFI settings needed, quirks, links to a fuller writeup." + } + }, + "if": { + "properties": { "status": { "enum": ["partial", "broken"] } } + }, + "then": { + "required": ["issues"] + } +} diff --git a/scripts/build.py b/scripts/build.py new file mode 100755 index 0000000..a1e43db --- /dev/null +++ b/scripts/build.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""Build site/data.json from data/reports/*.yml. + +Every report is validated against data/schema.json before being included — +a malformed report fails the build loudly instead of shipping a broken row +to the site (same idea as archy's own scripts/validate-app-manifest.sh: +fail the build, don't ship the drift). +""" +import json +import sys +from pathlib import Path + +import yaml +from jsonschema import Draft7Validator + +ROOT = Path(__file__).resolve().parent.parent +REPORTS_DIR = ROOT / "data" / "reports" +SCHEMA_PATH = ROOT / "data" / "schema.json" +OUT_PATH = ROOT / "site" / "data.json" + + +def main() -> int: + schema = json.loads(SCHEMA_PATH.read_text()) + validator = Draft7Validator(schema) + + reports = [] + errors = [] + + for path in sorted(REPORTS_DIR.glob("*.yml")): + try: + data = yaml.safe_load(path.read_text()) + except yaml.YAMLError as e: + errors.append(f"{path.name}: invalid YAML — {e}") + continue + + report_errors = sorted(validator.iter_errors(data), key=lambda e: e.path) + if report_errors: + for err in report_errors: + loc = ".".join(str(p) for p in err.path) or "(root)" + errors.append(f"{path.name}: {loc}: {err.message}") + continue + + data["_source_file"] = path.name + reports.append(data) + + if errors: + print(f"Build failed — {len(errors)} error(s):", file=sys.stderr) + for e in errors: + print(f" {e}", file=sys.stderr) + return 1 + + reports.sort(key=lambda r: (r["device_model"], r["tested_date"])) + OUT_PATH.write_text(json.dumps(reports, indent=2) + "\n") + print(f"Wrote {len(reports)} report(s) to {OUT_PATH.relative_to(ROOT)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/site/app.js b/site/app.js new file mode 100644 index 0000000..ef415fe --- /dev/null +++ b/site/app.js @@ -0,0 +1,130 @@ +// No framework, no build step — this is a plain JSON file (site/data.json, +// generated by scripts/build.py) rendered client-side. Keeps the "add a +// device" contribution path as simple as adding one YAML file. + +let reports = []; +let sortKey = "device_model"; +let sortDir = 1; + +const rowsEl = document.getElementById("rows"); +const searchEl = document.getElementById("search"); +const statusEl = document.getElementById("status-filter"); +const formFactorEl = document.getElementById("form-factor-filter"); +const countEl = document.getElementById("count"); +const emptyEl = document.getElementById("empty"); + +function storageLabel(storage) { + return `${storage.size_gb}GB ${storage.type.toUpperCase()}`; +} + +function matchesFilters(r, query, status, formFactor) { + if (status && r.status !== status) return false; + if (formFactor && r.form_factor !== formFactor) return false; + if (!query) return true; + const haystack = [r.device_model, r.cpu, r.wifi_chip, r.ethernet] + .filter(Boolean) + .join(" ") + .toLowerCase(); + return haystack.includes(query); +} + +function sortValue(r, key) { + if (key === "storage") return r.storage.size_gb; + return r[key]; +} + +function render() { + const query = searchEl.value.trim().toLowerCase(); + const status = statusEl.value; + const formFactor = formFactorEl.value; + + const filtered = reports.filter((r) => matchesFilters(r, query, status, formFactor)); + + filtered.sort((a, b) => { + const av = sortValue(a, sortKey); + const bv = sortValue(b, sortKey); + if (av < bv) return -1 * sortDir; + if (av > bv) return 1 * sortDir; + return 0; + }); + + rowsEl.innerHTML = ""; + for (const r of filtered) { + const tr = document.createElement("tr"); + tr.className = "expandable"; + tr.innerHTML = ` + ${escapeHtml(r.device_model)} + ${escapeHtml(r.form_factor)} + ${escapeHtml(r.cpu)} + ${r.ram_gb}GB + ${storageLabel(r.storage)} + ${escapeHtml(r.wifi_chip)} + ${r.status} + ${escapeHtml(r.archy_version)} + ${escapeHtml(r.tested_date)} + `; + tr.addEventListener("click", () => toggleDetail(tr, r)); + rowsEl.appendChild(tr); + } + + countEl.textContent = `${filtered.length} of ${reports.length} report${reports.length === 1 ? "" : "s"}`; + emptyEl.hidden = filtered.length !== 0; +} + +function toggleDetail(tr, r) { + const next = tr.nextElementSibling; + if (next && next.classList.contains("detail-row")) { + next.remove(); + return; + } + document.querySelectorAll(".detail-row").forEach((el) => el.remove()); + + const detail = document.createElement("tr"); + detail.className = "detail-row"; + const parts = []; + if (r.ethernet) parts.push(`Ethernet: ${escapeHtml(r.ethernet)}`); + parts.push(`Install method: ${escapeHtml(r.install_method)}`); + if (r.submitted_by) parts.push(`Submitted by: ${escapeHtml(r.submitted_by)}`); + if (r.issues) parts.push(`Issues:\n${escapeHtml(r.issues.trim())}`); + if (r.notes) parts.push(`Notes:\n${escapeHtml(r.notes.trim())}`); + + const td = document.createElement("td"); + td.colSpan = 9; + td.innerHTML = parts.join("\n\n"); + detail.appendChild(td); + tr.after(detail); +} + +function escapeHtml(s) { + const div = document.createElement("div"); + div.textContent = s ?? ""; + return div.innerHTML; +} + +document.querySelectorAll("th[data-sort]").forEach((th) => { + th.addEventListener("click", () => { + const key = th.dataset.sort; + if (sortKey === key) { + sortDir *= -1; + } else { + sortKey = key; + sortDir = 1; + } + render(); + }); +}); + +searchEl.addEventListener("input", render); +statusEl.addEventListener("change", render); +formFactorEl.addEventListener("change", render); + +fetch("data.json") + .then((res) => res.json()) + .then((data) => { + reports = data; + render(); + }) + .catch((err) => { + emptyEl.hidden = false; + emptyEl.textContent = "Failed to load data.json — " + err; + }); diff --git a/site/data.json b/site/data.json new file mode 100644 index 0000000..9b43858 --- /dev/null +++ b/site/data.json @@ -0,0 +1,41 @@ +[ + { + "device_model": "Lenovo ThinkPad T430", + "form_factor": "laptop", + "cpu": "Intel Core i5-3320M", + "ram_gb": 8, + "storage": { + "type": "ssd", + "size_gb": 256 + }, + "wifi_chip": "Intel Centrino Advanced-N 6205", + "ethernet": "Intel 82579LM", + "archy_version": "1.8.4-alpha", + "install_method": "usb-iso", + "status": "working", + "tested_date": "2026-08-15", + "submitted_by": "example-contributor", + "notes": "Example report \u2014 replace with a real one. Boots and installs cleanly from\na USB stick made with the standard ISO. No BIOS changes needed beyond\nenabling AHCI mode (should already be default on most T430s).\n", + "_source_file": "example-thinkpad-t430.yml" + }, + { + "device_model": "Raspberry Pi 5 (8GB)", + "form_factor": "sbc", + "cpu": "Broadcom BCM2712 (4x Cortex-A76)", + "ram_gb": 8, + "storage": { + "type": "nvme", + "size_gb": 512 + }, + "wifi_chip": "Broadcom BCM43455 (onboard)", + "ethernet": "Broadcom onboard Gigabit", + "archy_version": "1.8.4-alpha", + "install_method": "netboot", + "status": "partial", + "tested_date": "2026-08-10", + "submitted_by": "example-contributor", + "issues": "Example report \u2014 replace with a real one. Onboard WiFi drops the\nconnection under sustained heavy P2P traffic (Bitcoin IBD); a workaround\nis to run over Ethernet instead. Everything else (Lightning, apps,\ndashboard) works fine.\n", + "notes": "NVMe via the official PCIe HAT. Boots noticeably faster than SD-card\ninstalls.\n", + "_source_file": "example-raspberry-pi-5.yml" + } +] diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..8350909 --- /dev/null +++ b/site/index.html @@ -0,0 +1,66 @@ + + + + + +ArchyHCL — Archipelago Hardware Compatibility List + + + +
+

ArchyHCL

+

Community-reported hardware compatibility for Archipelago. Every row here is a real install someone tested and reported — see it on GitHub/Gitea as a plain data file, no login required to browse.

+

+ Tested Archipelago on your own hardware? Report it — + takes two minutes and helps the next person know what to expect before they buy or repurpose a machine. +

+
+ +
+
+ + + + +
+ + + + + + + + + + + + + + + + +
DeviceTypeCPURAMStorageWiFi chipStatusArchy ver.Tested
+ + +
+ +
+

Data lives in data/reports/*.yml, one file per report — browse or fork the raw data here. See CONTRIBUTING.md for the two ways to add a report.

+
+ + + + diff --git a/site/style.css b/site/style.css new file mode 100644 index 0000000..2863999 --- /dev/null +++ b/site/style.css @@ -0,0 +1,140 @@ +:root { + --bg: #0a0e12; + --panel: #10161c; + --border: #223038; + --text: #d8e4e8; + --muted: #7f97a0; + --accent: #00fff2; + --accent-dim: #00b3a8; + --working: #33d17a; + --partial: #f5b23c; + --broken: #f0506e; +} + +* { box-sizing: border-box; } + +body { + margin: 0; + background: var(--bg); + color: var(--text); + font-family: ui-monospace, "SF Mono", Consolas, monospace; + line-height: 1.5; +} + +header, main, footer { + max-width: 1100px; + margin: 0 auto; + padding: 1.5rem; +} + +h1 { + color: var(--accent); + letter-spacing: 0.08em; + margin-bottom: 0.25rem; +} + +a { color: var(--accent-dim); } +a:hover { color: var(--accent); } + +header p { color: var(--muted); max-width: 70ch; } +header .cta { color: var(--text); } + +.controls { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + align-items: center; + margin-bottom: 1rem; +} + +#search { + flex: 1 1 260px; + min-width: 200px; +} + +input, select { + background: var(--panel); + border: 1px solid var(--border); + color: var(--text); + padding: 0.5rem 0.7rem; + border-radius: 4px; + font-family: inherit; + font-size: 0.9rem; +} + +input:focus, select:focus { + outline: none; + border-color: var(--accent-dim); +} + +.count { color: var(--muted); font-size: 0.85rem; margin-left: auto; } + +table { + width: 100%; + border-collapse: collapse; + font-size: 0.85rem; +} + +thead th { + text-align: left; + padding: 0.6rem 0.7rem; + border-bottom: 2px solid var(--border); + color: var(--muted); + cursor: pointer; + user-select: none; + white-space: nowrap; +} + +thead th:hover { color: var(--accent); } + +tbody tr { + border-bottom: 1px solid var(--border); +} + +tbody tr:hover { background: var(--panel); } + +tbody tr.expandable { cursor: pointer; } + +td { + padding: 0.6rem 0.7rem; + vertical-align: top; +} + +.badge { + display: inline-block; + padding: 0.15rem 0.5rem; + border-radius: 3px; + font-size: 0.75rem; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +.badge.working { background: rgba(51, 209, 122, 0.15); color: var(--working); } +.badge.partial { background: rgba(245, 178, 60, 0.15); color: var(--partial); } +.badge.broken { background: rgba(240, 80, 110, 0.15); color: var(--broken); } + +.detail-row td { + background: var(--panel); + color: var(--muted); + white-space: pre-wrap; + font-size: 0.82rem; + padding: 0.8rem 1.2rem; +} + +.detail-row strong { color: var(--text); } + +.empty { color: var(--muted); text-align: center; padding: 2rem; } + +footer { + color: var(--muted); + font-size: 0.8rem; + border-top: 1px solid var(--border); + margin-top: 2rem; +} + +footer code { + background: var(--panel); + padding: 0.1rem 0.35rem; + border-radius: 3px; +}