Merge pull request 'Site: an Apps page, and a front page that points to it' (#105) from apps-page into main
Site / build (push) Successful in 14s
CI / build (push) Successful in 3m26s

This commit was merged in pull request #105.
This commit is contained in:
2026-10-15 10:38:05 +00:00
18 changed files with 172 additions and 51 deletions
+5
View File
@@ -0,0 +1,5 @@
+++
title = "The Apps"
description = "Everything on the device, an App at a time: what it does, a screen from the device itself, and where its guide is."
template = "apps.html"
+++
+99 -38
View File
@@ -1,72 +1,133 @@
# The App cards on the home page. Each says what the firmware does today (docs/milestones/W1.md, Q185):
# what isn't built is marked planned, with its milestone. `icon` is a cell of static/img/icons-*.svg.
# The Apps, in the Launcher's order: the Apps page shows them all, the home page those marked
# `featured`. Each says what the firmware does today (docs/milestones/W1.md, Q185); what isn't
# built is marked planned, with its milestone. `icon` is a cell of static/img/icons-*.svg (three
# across: 0 planned, 1 LoRa, 2 GNSS, 3 Wi-Fi, 4 Gemini, 5 IRC, 6 Notes, 7 System, 8 Storage,
# 9 Settings, 10 SSH, 11 Shell, 12 Games). `screen` is a file in static/screens/, a screenshot
# from the device at 2x; an App without one has none.
[[app]]
num = "01"
tag = "LoRa Scanner"
title = "See what is on the air"
text = "Lists every packet it hears with time, RSSI, SNR, sender and hops, reading the Meshtastic or MeshCore header. A Sweep shows signal strength from 863 to 870 MHz. Capture to a pcap for Wireshark."
fact = "Only listens, never transmits"
icon = 1
tag = "IRC"
title = "Chat from the keyboard"
text = "Join channels and type commands as you would anywhere, with a log a day written to the SD card. It stays connected when you leave the App, and the Launcher marks unread messages."
fact = "Logs to SD"
icon = 5
guide = "/guide/irc/"
[[app]]
tag = "Wi-Fi Tools"
title = "Scan the air for networks"
text = "The networks around you, sorted and filtered; how busy each channel is; a tracker that follows one network's signal as you walk. Scans log to a CSV file on the SD card."
fact = "Scans log to CSV"
icon = 3
guide = "/guide/wifi-tools/"
[[app]]
num = "02"
tag = "GNSS"
title = "Find your place in the sky"
text = "Position and Sky views show where you are and which satellites you can see. Tracks save to the SD card as GPX, and the clock follows the fix."
fact = "Sky view and GPX Tracks"
title = "Find your place, and your way"
text = "Position, a Sky view of every satellite, and a Compass that leads back to a place you marked. Tracks save to the SD card as GPX, and the clock follows the fix."
fact = "No magnetometer: north from walking, or the sun"
icon = 2
guide = "/guide/gnss/"
screen = "apps/gnss.png"
alt = "The GNSS App's sky view: a circle with the satellites of four constellations as coloured dots, filled when used, and a legend counting them: GPS 6 of 12, GLONASS 3 of 4, Galileo 2 of 2, BeiDou 3 of 3, 3D Fix"
featured = true
[[app]]
num = "03"
tag = "Gemini"
title = "Browse Geminispace"
text = "Follow links with Tab and Enter, go Back to where you were, bookmark pages and save them to the SD card to read offline."
fact = "Certificates trusted on first use"
icon = 4
guide = "/guide/gemini/"
screen = "apps/gemini.png"
alt = "The Gemini App's start page: Gemini, your bookmarks and Saved Pages, then a few places to start, and a saved page from bbs.geminispace.org"
featured = true
[[app]]
num = "04"
tag = "IRC"
title = "Chat from the keyboard"
text = "Join channels and type commands as you would anywhere, with daily logs written to the SD card."
fact = "Logs to SD"
icon = 5
tag = "LoRa Scanner"
title = "See what is on the air"
text = "Lists every packet it hears with its signal, and reads the Meshtastic and MeshCore headers, and MeshCore's public channel. A Sweep shows signal strength from 863 to 870 MHz. Capture to a pcap for Wireshark."
fact = "Only listens, never transmits"
icon = 1
guide = "/guide/lora-scanner/"
screen = "apps/lora.png"
alt = "The LoRa Scanner's Sweep: bars of signal strength from 863.0 to 870.0 MHz with peak marks, a waterfall under them, and a footer reading floor -100, 866.3 MHz at -88 dBm"
featured = true
[[app]]
num = "05"
tag = "Wi-Fi tools"
title = "Scan the air for networks"
text = "See the networks around you, sort and filter the list, and log scans to a CSV file on the SD card."
fact = "Scans log to CSV"
icon = 3
[[app]]
num = "06"
tag = "Notes"
title = "Write it down"
text = "Keep plain text notes on the SD card, of any size: a megabyte opens as fast as a line. There is no save key: the editor writes five seconds after you stop typing, so a power cut never costs the note."
fact = "Plain .txt files in /notes"
icon = 6
[[app]]
num = "07"
tag = "Storage"
title = "Manage the SD card"
text = "Browse, copy, cut, rename and delete with a clipboard. Opens text, pictures, hex, captures, tracks and update files. Press w and the card is a web page in your phone's browser: upload and download with nothing to install."
fact = "Checks every copy by size"
icon = 8
guide = "/guide/storage/"
screen = "apps/storage.png"
alt = "The Storage App at the top of the SD card: the folders captures, gemini, gnss, irc, notes, pictures, screenshots and system, with 15 GB free"
featured = true
[[app]]
tag = "Notes"
title = "Write it down"
text = "Keep plain text notes on the SD card, of any size: a megabyte opens as fast as a line. There is no save key: the editor writes five seconds after you stop typing, so a power cut never costs the note."
fact = "Plain .txt files in /notes"
icon = 6
guide = "/guide/notes/"
screen = "apps/notes.png"
alt = "The Notes App listing the notes in /notes, each under its first line, with its date"
[[app]]
tag = "SSH"
title = "A terminal on another machine"
text = "Log in to a server with a password or with the device's own key, and run a shell, vim or top on the Cardputer's screen, in sixteen colours. Files go with scp, from the Shell."
fact = "The session stays open when you leave"
icon = 10
guide = "/guide/ssh/"
screen = "apps/ssh.png"
alt = "The SSH App: a host connected to before, then New connection and This device's key"
featured = true
[[app]]
tag = "Shell"
title = "The console, on the device"
text = "Every command the firmware's console knows, typed on its own keyboard: the card's files, ping, nslookup, traceroute, a certificate check, the radio and the GNSS receiver. Tab completes."
fact = "The same commands as over USB"
icon = 11
guide = "/guide/shell/"
screen = "apps/shell.png"
alt = "The Shell after uname -a: roro9stack, its version, xtensa-lx7 esp32s3, and an empty line to type the next command"
[[app]]
tag = "Games"
title = "For when the radio is quiet"
text = "Pong, Snake and Tetris with its tune, Minesweeper, 2048, and Asteroids steered by leaning the device. Pong can be steered by tilting too."
fact = "The best of each is kept"
icon = 12
guide = "/guide/games/"
screen = "apps/games.png"
alt = "The Games App: six icons in a row, Pong chosen on a filled tile, and under them Pong and its longest rally"
featured = true
[[app]]
num = "08"
tag = "System"
title = "Watch it think"
text = "Per-core load, every task and its spare stack, free heap, network traffic, battery and chip temperature, live."
fact = "Live and read-only"
icon = 7
guide = "/guide/system/"
screen = "apps/system.png"
alt = "The System App's overview: the load of both cores, 84 KB of memory free, the network's traffic, the battery at 99 percent, uptime and temperature, and a graph"
[[app]]
tag = "Settings"
title = "Make it yours"
text = "The device's name and region, brightness and seven colour themes, GNSS and the radio, Wi-Fi networks and a WireGuard VPN, firmware updates and the Debug Console, in five groups."
fact = "Every theme dark and light"
icon = 9
guide = "/guide/settings/"
screen = "apps/settings.png"
alt = "Settings, in five groups: This device, Display, GNSS and radio, Network and System"
[[app]]
num = "09"
tag = "Planned"
title = "A mesh messenger"
text = "Sending and reading messages on a Meshtastic-compatible mesh. The radio listens today, in the LoRa Scanner; transmitting is the next step and waits for a second node to test with."
+24 -2
View File
@@ -142,11 +142,32 @@ section { padding-top: 64px; padding-bottom: 64px; }
.card .fact::before { content: ""; width: 8px; height: 8px; background: var(--cyan); flex: none; }
.card.planned .tag { color: var(--orangetext); }
.card.planned .fact::before { background: var(--orange); }
.ic { width: 48px; height: 48px; flex: none; background-image: var(--icons); background-repeat: no-repeat; background-size: 144px 192px; image-rendering: pixelated; }
.ic { width: 48px; height: 48px; flex: none; background-image: var(--icons); background-repeat: no-repeat; background-size: 144px 288px; image-rendering: pixelated; }
.i0 { background-position: 0 0; } .i1 { background-position: -48px 0; } .i2 { background-position: -96px 0; }
.i3 { background-position: 0 -48px; } .i4 { background-position: -48px -48px; } .i5 { background-position: -96px -48px; }
.i6 { background-position: 0 -96px; } .i7 { background-position: -48px -96px; } .i8 { background-position: -96px -96px; }
.i9 { background-position: 0 -144px; }
.i9 { background-position: 0 -144px; } .i10 { background-position: -48px -144px; } .i11 { background-position: -96px -144px; }
.i12 { background-position: 0 -192px; }
/* The Apps page: an App a row, its words beside a screen from the device. */
.apps { display: flex; flex-direction: column; gap: 24px; margin-top: 40px; }
.app { background: var(--s2); padding: 32px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 400px); gap: 32px; align-items: center; scroll-margin-top: 96px; }
.app-text { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.app .card-top { justify-content: flex-start; gap: 16px; }
.app .tag { font: 500 12px/16px var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--cyantext); }
.app h2 { font-size: 24px; line-height: 28px; }
.app h2 a { color: inherit; text-decoration: none; }
.app h2 a:hover, .app h2 a:focus-visible { text-decoration: underline; text-underline-offset: 4px; }
.app p { color: var(--muted); }
.app .fact { display: flex; align-items: center; gap: 8px; font: 500 12px/16px var(--mono); letter-spacing: .04em; }
.app .fact::before { content: ""; width: 8px; height: 8px; background: var(--cyan); flex: none; }
.app.planned .tag { color: var(--orangetext); }
.app.planned .fact::before { background: var(--orange); }
.app-guide { font-size: 14px; }
.app-shot { margin: 0; }
.app-shot img { display: block; width: 100%; height: auto; }
.cards-more { margin-top: 24px; }
.card h3 a { color: inherit; text-decoration: none; }
.card h3 a:hover, .card h3 a:focus-visible { text-decoration: underline; text-underline-offset: 4px; }
.cards-note { margin-top: 24px; font-size: 14px; line-height: 20px; color: var(--muted); }
/* Real screenshots */
@@ -225,6 +246,7 @@ footer small { display: block; max-width: 760px; }
section { padding-top: 48px; padding-bottom: 48px; }
.slab, .updates, .cta { padding: 24px; }
.panel, .card { padding: 24px; }
.app { grid-template-columns: minmax(0, 1fr); padding: 24px; gap: 24px; }
.hero .caption { margin-top: -24px; }
.num-row .big { font-size: 48px; line-height: 48px; min-width: 120px; }
}
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

+32
View File
@@ -0,0 +1,32 @@
{% extends "base.html" %}
{% block title %}The Apps: roro9stack{% endblock %}
{% block description %}{{ page.description }}{% endblock %}
{% block main %}
{% set apps = load_data(path="data/apps.toml", format="toml") %}
<div class="wrap page">
<header>
<span class="eyebrow">What's inside</span>
<h1>{{ page.title }}</h1>
<p class="lead">{{ page.description }} On the device, the Launcher shows them as a grid of icons; <kbd>Fn</kbd> + <kbd>h</kbd> lists the keys of any screen.</p>
</header>
<div class="apps">
{% for a in apps.app %}
<article class="app n-lg{% if a.planned %} planned{% endif %}" id="{{ a.tag | slugify }}">
<div class="app-text">
<div class="card-top"><div class="ic i{{ a.icon }}" aria-hidden="true"></div><span class="tag">{{ a.tag }}</span></div>
<h2>{% if a.guide %}<a href="{{ a.guide }}">{{ a.title }}</a>{% else %}{{ a.title }}{% endif %}</h2>
<p>{{ a.text }}</p>
<span class="fact">{{ a.fact }}</span>
{% if a.guide %}<a class="accent-link app-guide" href="{{ a.guide }}">Its page in the guide →</a>{% endif %}
</div>
{% if a.screen %}
<figure class="app-shot">
<img src="/screens/{{ a.screen | safe }}" width="480" height="270" alt="{{ a.alt }}" loading="lazy">
</figure>
{% endif %}
</article>
{% endfor %}
</div>
</div>
{% endblock main %}
+1 -1
View File
@@ -27,7 +27,7 @@
<img class="logo logo-light" src="/img/logo-light.svg" alt="" width="201" height="28">
</a>
<nav aria-label="Main">
<a href="/#apps">Apps</a>
<a href="/apps/">Apps</a>
<a href="/install/">Install</a>
<a href="/guide/">Guide</a>
<a href="/dev/">Developers</a>
+9 -8
View File
@@ -12,7 +12,7 @@
<h1 id="hero-title">Open firmware for a <span class="accent">pocket computer.</span></h1>
</div>
<div>
<p class="lead">roro9stack is firmware for the M5Stack Cardputer ADV with the Cap LoRa-1262: a LoRa scanner that reads Meshtastic traffic, GNSS, IRC, a Gemini browser, Wi-Fi tools, notes and more.</p>
<p class="lead">roro9stack is firmware for the M5Stack Cardputer ADV with the Cap LoRa-1262: a LoRa scanner that reads Meshtastic and MeshCore traffic, GNSS with a compass, an SSH client, a Gemini browser, IRC, Wi-Fi tools, notes, games and more.</p>
<div class="actions">
<a class="btn btn-primary n-md" href="/install/">Install{% if latest %} {{ latest.tag_name }}{% endif %}</a>
<a class="btn btn-secondary n-md" href="{{ config.extra.repo }}">Read the source</a>
@@ -55,20 +55,21 @@
<section class="wrap" id="apps" aria-labelledby="apps-title">
<div class="section-head">
<span class="eyebrow">What's inside</span>
<h2 id="apps-title">Apps for the radio, the web and the card.</h2>
<h2 id="apps-title">Apps for the radio, the network, the card and the evening.</h2>
</div>
<div class="cards">
{% for a in apps.app %}
<article class="card n-lg{% if a.planned %} planned{% endif %}">
{% for a in apps.app %}{% if a.featured %}
<article class="card n-lg">
<div class="ic i{{ a.icon }}" aria-hidden="true"></div>
<div class="card-top"><span class="tag">{{ a.tag }}</span><span class="num">{{ a.num }}</span></div>
<h3>{{ a.title }}</h3>
<div class="card-top"><span class="tag">{{ a.tag }}</span></div>
<h3><a class="card-link" href="/apps/#{{ a.tag | slugify }}">{{ a.title }}</a></h3>
<p>{{ a.text }}</p>
<span class="fact">{{ a.fact }}</span>
</article>
{% endfor %}
{% endif %}{% endfor %}
</div>
<p class="cards-note">Plus a <a class="accent-link" href="/guide/shell/">Shell</a> that runs the firmware's commands on the device, an <a class="accent-link" href="/guide/ssh/">SSH client</a> with a real terminal, a <a class="accent-link" href="/guide/vpn/">WireGuard VPN</a>, a screenshot key that works on every screen, and Settings, with its Wi-Fi and Firmware pages. Every App has a page in the <a class="accent-link" href="/guide/">user guide</a>.</p>
<p class="cards-more"><a class="btn btn-secondary n-md" href="/apps/">All {{ apps.app | length - 1 }} Apps, with their screens</a></p>
<p class="cards-note">Also on every screen: a key that lists the keys, and a key that takes a screenshot. Every App has a page in the <a class="accent-link" href="/guide/">user guide</a>.</p>
</section>
<section class="wrap" id="screens" aria-labelledby="screens-title">