Files
roro9stack/site/templates/index.html
T
twislaandClaude Sonnet 5.5 2f1befa7f5
Site / build (pull_request) Successful in 8s
Site: the user guide (phase 2): the basics, one page per App, Settings and Updates
Eleven pages under /guide/, written from the README, the milestone documents
and the Apps' own source: the keys, the Launcher, the Status Bar and the first
start; the LoRa Scanner, GNSS, Gemini, IRC, Wi-Fi tools, Notes, Storage and
System; Settings (with Wi-Fi) and Updates. Real screenshots where the site has
them, a Guide link in the navigation, and the home page points to it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
2026-10-06 20:38:40 +02:00

140 lines
7.2 KiB
HTML

{% extends "base.html" %}
{% block main %}
{% set latest = load_data(url=config.extra.api ~ "/releases/latest", format="json", required=false) %}
{% set apps = load_data(path="data/apps.toml", format="toml") %}
{% set screens = load_data(path="data/screens.toml", format="toml") %}
{% set px = [0,1,1,1,0, 1,0,0,0,1, 1,0,0,0,1, 0,1,1,1,1, 0,0,0,0,1, 0,0,0,0,1, 0,1,1,1,0] %}
<section class="wrap hero" aria-labelledby="hero-title">
<div class="hero-grid">
<div>
<div class="eyebrow-row"><span class="dot"></span><span class="eyebrow">Open firmware · GPL-3.0{% if latest %} · <span class="v">{{ latest.tag_name }}</span>{% endif %}</span></div>
<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>
<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>
</div>
<ul class="facts">
<li>GPL-3.0</li>
<li>Docker-only build</li>
<li>Signed updates</li>
</ul>
</div>
</div>
<div class="slab n-lg">
<div class="device">{% include "illustrations/sweep.html" %}</div>
<div class="device">{% include "illustrations/sky.html" %}</div>
</div>
<p class="caption">Drawings of the LoRa Scanner's Sweep view and the GNSS sky view, not screenshots: the real screens are further down.</p>
</section>
<section class="wrap" aria-labelledby="status-title">
<div class="status-box n-md">
<h2 id="status-title" class="eyebrow">Where it stands</h2>
<p>Early software{% if latest %}, {{ latest.tag_name }}{% endif %}. The radio listens; it doesn't transmit yet. Sending and reading mesh messages is planned and waits for a second node to test with. <a href="{{ config.extra.repo }}/milestones">The milestones</a> show what's done and what's next.</p>
</div>
</section>
<section class="wrap" id="need" aria-labelledby="need-title">
<div class="section-head">
<span class="eyebrow">Before you start</span>
<h2 id="need-title">What you need.</h2>
</div>
<ul class="need">
<li><strong>An M5Stack Cardputer ADV</strong><span>The handheld the firmware runs on.</span></li>
<li><strong>The Cap LoRa-1262</strong><span>The LoRa Scanner and GNSS need it. The other Apps don't use it.</span></li>
<li><strong>A microSD card</strong><span>For Notes, Storage, Logs, Captures and Tracks.</span></li>
<li><strong>Wi-Fi</strong><span>For IRC, Gemini and updates.</span></li>
<li><strong>A computer, for the first install</strong><span>Chrome or Edge, and a USB-C cable. After that the device updates itself.</span></li>
</ul>
</section>
<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>
</div>
<div class="cards">
{% for a in apps.app %}
<article class="card n-lg{% if a.planned %} planned{% endif %}">
<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>
<p>{{ a.text }}</p>
<span class="fact">{{ a.fact }}</span>
</article>
{% endfor %}
</div>
<p class="cards-note">Plus 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>
</section>
<section class="wrap" id="screens" aria-labelledby="screens-title">
<div class="section-head">
<span class="eyebrow">On the device</span>
<h2 id="screens-title">The real screens.</h2>
</div>
<div class="shots">
{% for s in screens.screen %}
<figure class="shot n-md">
<img src="/screens/{{ s.file }}" width="480" height="270" alt="{{ s.alt }}" loading="lazy">
<figcaption>{{ s.caption }}</figcaption>
</figure>
{% endfor %}
</div>
</section>
<section class="wrap" id="updates" aria-labelledby="updates-title">
<div class="updates n-lg split">
<div>
<span class="eyebrow">Updates</span>
<h2 id="updates-title">Update over Wi-Fi. It rolls back if it fails.</h2>
<p class="lead">Install a new release from the project's server in Settings, from the SD card, or push one from your computer. Every update is signed: the device checks the signature before it writes anything, restarts, and runs the new firmware on Probation. If it crashes, or can't reconnect Wi-Fi, it goes back to the previous firmware and says so.</p>
<div class="terminal n-md"><span class="p">$</span> scripts/flash.sh --ota 10.39.39.12</div>
</div>
<div class="aside">
<div class="num-row"><span class="big c1">60 s</span><p>The longest the device waits for you to stop typing before it restarts into an update.</p></div>
<div class="num-row"><span class="big c2">3 min</span><p>How long new firmware has to reconnect Wi-Fi on Probation before it rolls back.</p></div>
<div class="num-row"><span class="big c2">3</span><p>Crash restarts in a row, and it starts in Safe Mode: only Wi-Fi, updates and the Debug Console, so a fix can still be pushed.</p></div>
</div>
</div>
</section>
<section class="wrap split" id="build" aria-labelledby="build-title">
<div>
<span class="eyebrow">Build and flash</span>
<h2 id="build-title">Only Docker needed.</h2>
<p class="lead">PlatformIO and the ESP32 toolchain run in a container. The first build downloads about 1 GB; after that, builds take under a minute.</p>
<p class="muted">If the upload can't connect, hold G0, the button next to the screen, while plugging in USB, then retry.</p>
<p>Prefer a ready-made build? <a class="accent-link" href="/install/">Install it from your browser</a>, or take the factory image and the signed update file from <a class="accent-link" href="/downloads/">the downloads</a>.</p>
</div>
<div class="blocks n-lg">
<div class="c"># run the tests, then build</div>
<div><span class="p">$</span> scripts/ci.sh</div>
<div class="gap"></div>
<div class="c"># flash over USB-C</div>
<div><span class="p">$</span> scripts/flash.sh</div>
<div class="gap"></div>
<div class="c"># or update over Wi-Fi</div>
<div><span class="p">$</span> scripts/flash.sh --ota 10.39.39.12</div>
</div>
</section>
<section class="wrap" aria-labelledby="cta-title">
<div class="cta n-lg">
<div>
<h2 id="cta-title">Open source, GPL-3.0.</h2>
<p>Read the code, flash it, send a patch.</p>
<div class="actions">
<a class="btn n-md" href="{{ config.extra.repo }}">Source</a>
<a class="btn n-md" href="{{ config.extra.repo }}/releases">Releases</a>
<a class="btn n-md" href="{{ config.extra.repo }}/issues">Issues</a>
</div>
</div>
<div class="nine" aria-hidden="true">{% for v in px %}<i{% if v == 1 %} class="on"{% endif %}></i>{% endfor %}</div>
</div>
</section>
{% endblock main %}