mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-09-29 15:15:08 -04:00
2 lines
48 KiB
HTML
2 lines
48 KiB
HTML
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <link rel="stylesheet" href="/Meshtastic-Android/main/assets/css/just-the-docs-default.css"> <link rel="stylesheet" href="/Meshtastic-Android/main/assets/css/just-the-docs-head-nav.css" id="jtd-head-nav-stylesheet"> <style id="jtd-nav-activation"> .site-nav > ul.nav-list:first-child > li > a, .site-nav > ul.nav-list:first-child > li > ul > li:not(:nth-child(11)) > a, .site-nav > ul.nav-list:first-child > li > ul > li > ul > li a { background-image: none; } .site-nav > ul.nav-list:not(:first-child) a, .site-nav li.external a { background-image: none; } .site-nav > ul.nav-list:first-child > li:nth-child(4) > ul > li:nth-child(11) > a { font-weight: 600; text-decoration: none; }.site-nav > ul.nav-list:first-child > li:nth-child(4) > button svg, .site-nav > ul.nav-list:first-child > li:nth-child(4) > ul > li:nth-child(11) > button svg { transform: rotate(-90deg); }.site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(4) > ul.nav-list, .site-nav > ul.nav-list:first-child > li.nav-list-item:nth-child(4) > ul.nav-list > li.nav-list-item:nth-child(11) > ul.nav-list { display: block; } </style> <script src="/Meshtastic-Android/main/assets/js/vendor/lunr.min.js"></script> <script src="/Meshtastic-Android/main/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.9.0 --> <title>Documentation Style | Meshtastic Android</title> <meta name="generator" content="Jekyll v4.4.1" /> <meta property="og:title" content="Documentation Style" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="House style for the user and developer docs — voice, wording, formatting, page structure, and the decisions behind them." /> <meta name="twitter:description" property="og:description" content="House style for the user and developer docs — voice, wording, formatting, page structure, and the decisions behind them." /> <link rel="canonical" href="/Meshtastic-Android/main/en/developer/documentation-style.html" /> <meta property="og:url" content="/Meshtastic-Android/main/en/developer/documentation-style.html" /> <meta property="og:site_name" content="Meshtastic Android" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta name="twitter:title" content="Documentation Style" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","description":"House style for the user and developer docs — voice, wording, formatting, page structure, and the decisions behind them.","headline":"Documentation Style","url":"/Meshtastic-Android/main/en/developer/documentation-style.html"}</script> <!-- End Jekyll SEO tag --> <!-- Inter font from Google Fonts --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> <style> /* M3-inspired typography */ :root { --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', ui-monospace, monospace; } body, .site-title, .search-input { font-family: var(--font-sans) !important; } code, pre, .highlight { font-family: var(--font-mono) !important; font-size: 0.875em; } /* M3 surface elevation & rounding */ .main-content table { border-radius: 12px; overflow: hidden; } .main-content blockquote { border-radius: 12px; padding: 1rem 1.25rem; border-left-width: 4px; } .main-content pre { border-radius: 12px; } .main-content code { border-radius: 6px; padding: 0.15em 0.4em; } /* Smooth transitions for theme switching */ body, .side-bar, .main, .main-content, .site-header, .search-input, .search-results, a { transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; } /* Theme toggle button styling */ .theme-toggle { background: none; border: 1px solid var(--border-color, #D5D6E0); border-radius: 20px; padding: 6px 12px; cursor: pointer; font-family: var(--font-sans); font-size: 0.75rem; font-weight: 500; display: inline-flex; align-items: center; gap: 6px; color: inherit; margin: 0 auto; transition: background-color 0.2s ease, border-color 0.2s ease; } .theme-toggle:hover { background-color: rgba(128, 128, 128, 0.1); } .theme-toggle-wrap { text-align: center; padding: 12px 0 4px; } /* Heading weight refinement */ h1, h2, h3, h4, h5, h6 { font-weight: 600; letter-spacing: -0.01em; } h1 { font-weight: 700; letter-spacing: -0.02em; } /* Smooth anchor scroll */ html { scroll-behavior: smooth; } /* Language switcher */ .language-switcher { display: inline-block; position: relative; margin-left: 8px; } .language-switcher-btn { cursor: pointer; font-size: 0.8rem; font-weight: 500; font-family: var(--font-sans); list-style: none; padding: 4px 10px; border: 1px solid var(--border-color, #D5D6E0); border-radius: 16px; display: inline-flex; align-items: center; gap: 4px; transition: background-color 0.2s ease; } .language-switcher-btn:hover { background-color: rgba(128, 128, 128, 0.1); } .language-switcher[open] .language-switcher-list { display: block; } .language-switcher-list { position: absolute; top: 100%; right: 0; left: auto; z-index: 100; list-style: none; padding: 8px 0; margin: 4px 0 0; min-width: 140px; background: var(--body-background-color, #fff); border: 1px solid var(--border-color, #D5D6E0); border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); } .language-switcher-list li { padding: 0; } .language-switcher-list a { display: block; padding: 6px 16px; text-decoration: none; font-size: 0.85rem; color: inherit; } .language-switcher-list a:hover { background-color: rgba(103, 234, 148, 0.15); } /* Version switcher (shares the language-switcher dropdown styling) */ .version-switcher { margin-left: 8px; } .version-switcher[hidden] { display: none; } /* Link out to the upstream meshtastic.org docs */ .upstream-docs-link { display: inline-flex; align-items: center; margin-left: 8px; padding: 4px 10px; border: 1px solid var(--border-color, #D5D6E0); border-radius: 16px; font-size: 0.8rem; font-weight: 500; font-family: var(--font-sans); text-decoration: none; color: inherit; transition: background-color 0.2s ease; } .upstream-docs-link:hover { background-color: rgba(128, 128, 128, 0.1); } </style> <script> // Respect OS preference on first visit, then remember user choice (function() { var stored = localStorage.getItem('jtd-theme'); if (stored) return; // will be applied by jtd.setTheme below if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { localStorage.setItem('jtd-theme', 'meshtastic-dark'); } })(); </script> </head> <body> <a class="skip-to-main" href="#main-content">Skip to main content</a> <svg xmlns="http://www.w3.org/2000/svg" class="d-none"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE --> <symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"> <title id="svg-external-link-title">(external link)</title> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md --> <symbol id="svg-copy" viewBox="0 0 16 16"> <title>Copy</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16"> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/> <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/> </svg> </symbol> <symbol id="svg-copied" viewBox="0 0 16 16"> <title>Copied</title> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16"> <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/> <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/> </svg> </symbol> </svg> <header class="side-bar"> <div class="site-header"> <a href="/Meshtastic-Android/main/" class="site-title lh-tight"> Meshtastic Android </a> <button id="menu-button" class="site-button btn-reset" aria-label="Menu" aria-expanded="false"> <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg> </button> </div> <nav aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/" class="nav-list-link">Home</a></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="User Guide submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/Meshtastic-Android/main/en/user.html" class="nav-list-link">User Guide</a><ul class="nav-list"><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/onboarding.html" class="nav-list-link">Getting Started</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/onboarding.html" class="nav-list-link">Getting Started</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/connections.html" class="nav-list-link">Connexions</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/connections.html" class="nav-list-link">Connections</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/messages-and-channels.html" class="nav-list-link">Messages & Channels</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/messages-and-channels.html" class="nav-list-link">Messages & Channels</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/nodes.html" class="nav-list-link">Nœuds</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/nodes.html" class="nav-list-link">Nodes</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/node-metrics.html" class="nav-list-link">Node Metrics</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/node-metrics.html" class="nav-list-link">Node Metrics</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/map-and-waypoints.html" class="nav-list-link">Map & Waypoints</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/map-and-waypoints.html" class="nav-list-link">Map & Waypoints</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/settings-radio-user.html" class="nav-list-link">Settings — Radio & User</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/settings-radio-user.html" class="nav-list-link">Settings — Radio & User</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/settings-module-admin.html" class="nav-list-link">Settings — Modules & Admin</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/settings-module-admin.html" class="nav-list-link">Settings — Modules & Admin</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/telemetry-and-sensors.html" class="nav-list-link">Telemetry & Sensors</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/telemetry-and-sensors.html" class="nav-list-link">Telemetry & Sensors</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/tak.html" class="nav-list-link">TAK Integration</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/tak.html" class="nav-list-link">TAK Integration</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/mqtt.html" class="nav-list-link">MQTT</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/mqtt.html" class="nav-list-link">MQTT</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/discovery.html" class="nav-list-link">Découverte de maille locale</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/discovery.html" class="nav-list-link">Local Mesh Discovery</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/firmware.html" class="nav-list-link">Firmware Updates</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/firmware.html" class="nav-list-link">Firmware Updates</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/desktop.html" class="nav-list-link">Desktop App</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/desktop.html" class="nav-list-link">Desktop App</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/signal-meter.html" class="nav-list-link">How the Meshtastic Signal Meter Works</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/signal-meter.html" class="nav-list-link">How the Meshtastic Signal Meter Works</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/units-and-locale.html" class="nav-list-link">Units, Measurement & Locale</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/units-and-locale.html" class="nav-list-link">Units, Measurement & Locale</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/fr-rCA/user/translate.html" class="nav-list-link">Translate the App</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/translate.html" class="nav-list-link">Translate the App</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/app-functions.html" class="nav-list-link">App Functions</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/widget.html" class="nav-list-link">Home Screen Widget</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/help-and-docs.html" class="nav-list-link">Help & In-App Docs</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/user/debug-logs.html" class="nav-list-link">Debug Logs</a></li></ul></li><li class="nav-list-item"><button class="nav-list-expander btn-reset" aria-label="Developer Guide submenu" aria-expanded="false"> <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg> </button><a href="/Meshtastic-Android/main/en/developer.html" class="nav-list-link">Developer Guide</a><ul class="nav-list"><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/architecture.html" class="nav-list-link">Architecture</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/codebase.html" class="nav-list-link">Codebase</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/adding-a-feature-module.html" class="nav-list-link">Adding a Feature Module</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/navigation-and-deep-links.html" class="nav-list-link">Navigation & Deep Links</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/transport.html" class="nav-list-link">Transport</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/persistence.html" class="nav-list-link">Persistence</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/testing.html" class="nav-list-link">Testing</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/contributing.html" class="nav-list-link">Contributing</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/measurement.html" class="nav-list-link">Measurement & Formatting</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/test-builds.html" class="nav-list-link">Test Builds & Obtainium</a></li><li class="nav-list-item"><a href="/Meshtastic-Android/main/en/developer/documentation-style.html" class="nav-list-link">Documentation Style</a></li></ul></li></ul> </nav> <div class="d-md-block d-sm-none"> <div class="site-footer"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </div> </header> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search" role="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search Meshtastic Android" autocomplete="off"> <label for="search-input" class="search-label"> <span class="sr-only">Search Meshtastic Android</span> <svg viewBox="0 0 24 24" class="search-icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg> </label> </div> <div id="search-results" class="search-results"></div> </div> <div class="theme-toggle-wrap"> <button class="theme-toggle" id="theme-toggle" aria-label="Toggle dark mode" title="Toggle light/dark theme" onclick="toggleMeshtasticTheme()"> <span id="theme-icon">🌙</span> <span id="theme-label">Dark</span> </button> <details class="language-switcher version-switcher" id="version-switcher" aria-label="Documentation version" hidden> <summary class="language-switcher-btn" title="Switch documentation version"> 🏷️ <span id="version-current"></span> </summary> <ul class="language-switcher-list" id="version-switcher-list"></ul> </details> <script> (function() { var baseurl = '/Meshtastic-Android/main'; var root = baseurl; var channel = 'latest'; // /main/, /vX.Y.Z/ or a prerelease snapshot like /v2.8.0-open.1/. var match = baseurl.match(/^(.*)\/(main|v\d+\.\d+\.\d+(?:-(?:open|closed)\.\d+)?)$/); if (match) { root = match[1]; channel = match[2]; } fetch(root + '/versions.json') .then(function(res) { return res.ok ? res.json() : Promise.reject(); }) .then(function(data) { var switcher = document.getElementById('version-switcher'); var list = document.getElementById('version-switcher-list'); var current = document.getElementById('version-current'); if (!switcher || !list || !current) return; // Keep the reader on the same page when switching channels; a page // that doesn't exist in the target version lands on the 404 page. var relativePath = location.pathname.slice(baseurl.length) + location.hash; var entries = []; if (data.latest) { entries.push({ id: 'latest', label: 'latest (v' + data.latest + ')', base: root }); } // Prereleases are documented ahead of general availability, so the track // is always spelled out — a reader must not mistake a closed-testing // snapshot for a shipped release. (data.prereleases || []).forEach(function(p) { entries.push({ id: p.dir, label: p.dir.replace(/^v/, 'v') + ' — ' + p.track + ' testing', base: root + '/' + p.dir }); }); if (data.hasMain) { entries.push({ id: 'main', label: 'main (unreleased snapshot)', base: root + '/main' }); } (data.versions || []).forEach(function(v) { entries.push({ id: 'v' + v, label: 'v' + v, base: root + '/v' + v }); }); var currentEntry = entries.filter(function(e) { return e.id === channel; })[0]; current.textContent = currentEntry ? currentEntry.label : channel; var others = entries.filter(function(e) { return e.id !== channel; }); if (others.length === 0) return; others.forEach(function(e) { var li = document.createElement('li'); var a = document.createElement('a'); a.href = e.base + relativePath; a.textContent = e.label; li.appendChild(a); list.appendChild(li); }); switcher.hidden = false; }) .catch(function() { /* no manifest (local build) — leave switcher hidden */ }); })(); </script> <a class="upstream-docs-link" href="https://meshtastic.org/docs/" title="Official Meshtastic documentation (meshtastic.org)">Meshtastic Docs ↗</a> </div> <script> function toggleMeshtasticTheme() { var current = localStorage.getItem('jtd-theme') || 'meshtastic'; var next = (current === 'meshtastic-dark') ? 'meshtastic' : 'meshtastic-dark'; if (typeof jtd !== 'undefined' && typeof jtd.setTheme === 'function') { jtd.setTheme(next); } localStorage.setItem('jtd-theme', next); var icon = document.getElementById('theme-icon'); var label = document.getElementById('theme-label'); if (icon && label) { icon.textContent = (next === 'meshtastic-dark') ? '☀️' : '🌙'; label.textContent = (next === 'meshtastic-dark') ? 'Light' : 'Dark'; } } // Apply stored/OS theme on page load (function() { var theme = localStorage.getItem('jtd-theme') || 'meshtastic'; // Sync toggle label immediately var icon = document.getElementById('theme-icon'); var label = document.getElementById('theme-label'); if (icon && label) { icon.textContent = (theme === 'meshtastic-dark') ? '☀️' : '🌙'; label.textContent = (theme === 'meshtastic-dark') ? 'Light' : 'Dark'; } // Apply theme once jtd is ready function tryApply() { if (typeof jtd !== 'undefined' && typeof jtd.setTheme === 'function') { jtd.setTheme(theme); } else { setTimeout(tryApply, 50); } } tryApply(); })(); </script> </div> <div class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="/Meshtastic-Android/main/en/developer.html">Developer Guide</a></li> <li class="breadcrumb-nav-list-item"><span>Documentation Style</span></li> </ol> </nav> <div id="main-content" class="main-content"> <main> <h1 id="documentation-style"> <a href="#documentation-style" class="anchor-heading" aria-labelledby="documentation-style"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Documentation Style </h1> <p>House style for everything under <code class="language-plaintext highlighter-rouge">docs/en/</code>. These pages ship to three places — the in-app docs browser, the GitHub Pages site, and meshtastic.org — so one page has to read well in all of them, and its English source is the translation base for 40+ locales on Crowdin.</p> <p>This guide synthesizes the <a href="https://developers.google.com/style">Google developer documentation style guide</a>, the <a href="https://learn.microsoft.com/en-us/style-guide/welcome/">Microsoft Writing Style Guide</a>, the Apple Style Guide’s gesture vocabulary, the US <a href="https://www.plainlanguage.gov/guidelines/">plain language guidelines</a> and <a href="https://github.com/18F/content-guide">18F content guide</a>, and Red Hat’s admonition rules — adjudicated against this repo’s own established conventions. Where an entry here decides something, follow it; for anything not covered, follow Google’s guide.</p> <p>Every rule has an ID so review feedback and audit findings can cite it.</p> <h2 id="voice-and-tone"> <a href="#voice-and-tone" class="anchor-heading" aria-labelledby="voice-and-tone"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Voice and Tone </h2> <ul> <li><strong>VOICE-1</strong> — Address the reader as <em>you</em>. <em>We</em> means the Meshtastic project team, nothing else. Never <em>the user</em> for the reader.</li> <li><strong>VOICE-2</strong> — Warm, plain, and direct. Contractions are house voice (<em>you’ll</em>, <em>doesn’t</em>, <em>it’s</em>) — but in warnings, write <em>do not</em>: negative contractions are too easy to misread when the cost of misreading is data loss.</li> <li><strong>VOICE-3</strong> — No hype and no filler: no exclamation points, no <em>simply</em>, <em>just</em>, <em>easy</em>, <em>easily</em>, or <em>quickly</em> in instructions, no <em>please</em>, no scare quotes, no pop-culture jokes. If a task is genuinely hard, say what makes it hard instead of calling it easy.</li> <li><strong>VOICE-4</strong> — Voice stays constant; tone flexes with the reader’s situation. A troubleshooting section addresses someone who is stuck and possibly annoyed — that is the calmest, most concrete writing on the page. Clear beats entertaining, always.</li> <li><strong>VOICE-5</strong> — Active voice by default. Passive is fine when the actor is irrelevant (<em>the packet is re-encrypted</em>) or to avoid blaming the reader (<em>over 50 conflicts were found</em>).</li> <li><strong>VOICE-6</strong> — Timeless present tense. The app <em>sends</em>, not <em>will send</em>. Reserve <em>will</em> for events genuinely later than the sentence (<em>the file will be removed on the next sync</em>). Never <em>currently</em>, <em>now</em>, <em>soon</em>, <em>new</em>, or <em>as of this writing</em> — the page outlives all of them — and never pre-announce unreleased features.</li> </ul> <h2 id="language"> <a href="#language" class="anchor-heading" aria-labelledby="language"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Language </h2> <ul> <li><strong>LANG-1</strong> — American English spelling: <em>color</em>, <em>behavior</em>, <em>honors</em>, <em>gray</em>, <em>organize</em>.</li> <li><strong>LANG-2</strong> — Keep sentences to roughly 25 words and one idea; keep paragraphs to about five sentences and one topic. Front-load: main point first, exceptions after the rule. A one-sentence paragraph is fine.</li> <li><strong>LANG-3</strong> — Requirement words carry exact weight: <em>must</em> (obligation), <em>must not</em> (prohibition), <em>should</em> (recommendation), <em>can</em> (capability), <em>may</em> (permission). Never <em>shall</em>.</li> <li><strong>LANG-4</strong> — Prefer <em>for example</em> and <em>such as</em> over <em>e.g.</em>, and <em>that is</em> over <em>i.e.</em>, in running prose. Inside table cells and parentheses, <em>e.g.</em> is acceptable where space is tight.</li> <li><strong>LANG-5</strong> — One term per concept, everywhere. If the settings page calls it a <em>modem preset</em>, no page calls it a <em>radio profile</em>. Keep clarifying words that ease translation: <em>the</em>, <em>that</em>, <em>who</em> (<em>the radios <strong>that</strong> you have paired</em>, not <em>the radios you paired</em>).</li> <li><strong>LANG-6</strong> — Inclusive, literal language: <em>allowlist</em>/<em>blocklist</em>, singular <em>they</em>, no ableist idioms (<em>final check</em>, not <em>sanity check</em>), no violent metaphors (<em>the app stops responding</em>, not <em>hangs</em>), no culture-bound idioms that defeat translators.</li> <li><strong>LANG-7</strong> — Oxford comma (<em>Android, iOS, and Windows</em>). Em dashes are spaced — like this — matching the entire existing corpus.</li> <li><strong>LANG-8</strong> — Spell out zero through nine in prose; numerals for 10 and up, for all measurements and units (<em>3 dB</em>, <em>915 MHz</em>), for values the reader enters, and with <code class="language-plaintext highlighter-rouge">%</code>. Dates spell the month: <em>June 12, 2026</em>.</li> <li><strong>LANG-9</strong> — Don’t use <em>above</em> and <em>below</em> to point at other text — say <em>earlier</em>, <em>the following</em>, or link to the section. (Literal technical use is fine: <em>below the noise floor</em>.)</li> </ul> <h2 id="word-list"> <a href="#word-list" class="anchor-heading" aria-labelledby="word-list"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Word List </h2> <p>Project- and platform-specific decisions, alphabetical. Google’s word list covers the rest.</p> <div class="table-wrapper"><table> <thead> <tr> <th>Term</th> <th>Rule</th> </tr> </thead> <tbody> <tr> <td>app</td> <td>The Meshtastic client this repo builds. Not <em>application</em>.</td> </tr> <tr> <td>channel</td> <td>Lowercase in prose; bold only when naming a UI element.</td> </tr> <tr> <td>direct message</td> <td>Lowercase; <em>DM</em> is fine after the page has spelled it out once.</td> </tr> <tr> <td>email</td> <td>No hyphen.</td> </tr> <tr> <td>firmware</td> <td>Lowercase, even when referring to the Meshtastic firmware project.</td> </tr> <tr> <td>internet</td> <td>Lowercase.</td> </tr> <tr> <td>LoRa</td> <td>Exactly this casing, everywhere.</td> </tr> <tr> <td>mesh</td> <td>Lowercase: <em>your mesh</em>, <em>the mesh network</em>.</td> </tr> <tr> <td>node</td> <td>A participant in the mesh — yours or anyone’s — as it appears in the node list and on the map.</td> </tr> <tr> <td>phone</td> <td>The Android handset the app runs on. Use <em>phone</em> even when a tablet also works, unless the distinction matters.</td> </tr> <tr> <td>radio</td> <td>The Meshtastic hardware the app connects to. Prefer this over the ambiguous <em>device</em> — see the note after this table.</td> </tr> <tr> <td>set up / setup</td> <td>Verb two words, noun/adjective one word.</td> </tr> <tr> <td>sign in</td> <td>Verb; <em>sign-in</em> as adjective. Not <em>log in</em> or <em>login</em>.</td> </tr> <tr> <td>tap</td> <td>The interaction verb for the app’s touch UI. <em>Click</em> only in desktop-app or web contexts; never <em>tap on</em> or <em>click on</em>.</td> </tr> <tr> <td>touch & hold</td> <td>Exactly this form (Google’s Android convention). Not <em>long press</em>, not <em>tap and hold</em>.</td> </tr> <tr> <td>Wi-Fi</td> <td>Never <em>WiFi</em> or <em>wifi</em> — in docs and in the app’s own strings alike (this word outranks PROC-1’s match-the-UI rule if a stray label slips back in).</td> </tr> </tbody> </table></div> <p><strong>radio vs. phone vs. node vs. device:</strong> the corpus’s biggest ambiguity is <em>device</em>, which has meant both the radio and the phone. Use <em>radio</em> for the Meshtastic hardware, <em>phone</em> for the Android handset, and <em>node</em> for a mesh participant. Use <em>device</em> only when quoting Android’s own UI (the <strong>Nearby devices</strong> permission, <em>Devices</em> system pages) or in established compounds (<em>device metrics</em>, <em>device firmware</em> where the UI uses them).</p> <h2 id="headings"> <a href="#headings" class="anchor-heading" aria-labelledby="headings"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Headings </h2> <ul> <li><strong>HEAD-1</strong> — Title Case for page titles and all headings: <em>Where Signal Information Appears</em>, not <em>Where signal information appears</em>. This deliberately deviates from Google, Microsoft, and gov.uk (all sentence case) — the entire corpus is Title Case, and re-casing every heading would invalidate the translation memory for 40+ locales with zero reader benefit. See <a href="#decisions-and-why">Decisions</a>.</li> <li><strong>HEAD-2</strong> — One <code class="language-plaintext highlighter-rouge">#</code> H1 per page, and it matches the frontmatter <code class="language-plaintext highlighter-rouge">title</code> exactly.</li> <li><strong>HEAD-3</strong> — Never skip a level (H2 → H4). No links, no trailing punctuation, and no numbering in headings — the one exception is a genuine question heading in troubleshooting content (<em>Which Channels Can Obtainium Reach?</em>), which research says helps readers find answers.</li> <li><strong>HEAD-4</strong> — Headings are scannable noun or verb phrases, shorter than the text they cover. No bare code identifiers as an entire heading — add a noun.</li> </ul> <h2 id="page-structure"> <a href="#page-structure" class="anchor-heading" aria-labelledby="page-structure"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Page Structure </h2> <ul> <li><strong>STRUCT-1</strong> — Complete frontmatter on every page, user <em>and</em> developer: <code class="language-plaintext highlighter-rouge">title</code>, <code class="language-plaintext highlighter-rouge">parent</code>, <code class="language-plaintext highlighter-rouge">nav_order</code>, <code class="language-plaintext highlighter-rouge">last_updated</code> (bump it whenever content changes — CI checks freshness), <code class="language-plaintext highlighter-rouge">description</code> (one sentence, ~160 characters, used by search and link previews), and <code class="language-plaintext highlighter-rouge">aliases</code> (search terms the in-app browser resolves).</li> <li><strong>STRUCT-2</strong> — Open with a one-to-three-sentence lede that says what the page covers and who needs it. No <em>Welcome!</em> preamble.</li> <li><strong>STRUCT-3</strong> — User pages end with a <code class="language-plaintext highlighter-rouge">## Related Topics</code> section: bulleted links, each with an em-dash clause saying why you’d go there.</li> <li><strong>STRUCT-4</strong> — No horizontal rules (<code class="language-plaintext highlighter-rouge">---</code>) in page bodies, and especially not at the end of the file — the site layout adds its own footer rule, so a trailing <code class="language-plaintext highlighter-rouge">---</code> renders as a doubled line. Headings already separate sections.</li> <li><strong>STRUCT-5</strong> — New pages must be registered in <code class="language-plaintext highlighter-rouge">DocBundleLoader.kt</code> (the in-app index) — CI fails in both directions if the page and the index disagree. Screenshots go in <code class="language-plaintext highlighter-rouge">docs/assets/screenshots/</code>.</li> <li><strong>STRUCT-6</strong> — Notable page changes get a <em>What’s New</em> entry at the top of <code class="language-plaintext highlighter-rouge">user.md</code> or <code class="language-plaintext highlighter-rouge">developer.md</code>, in the format the HTML comment there specifies.</li> </ul> <h2 id="admonitions"> <a href="#admonitions" class="anchor-heading" aria-labelledby="admonitions"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Admonitions </h2> <ul> <li> <p><strong>ADMON-1</strong> — One form: a blockquote starting with an emoji and a bold label, from this closed set.</p> <div class="table-wrapper"><table> <thead> <tr> <th>Admonition</th> <th>Use for</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">> 💡 **Tip:**</code></td> <td>An optional shortcut or non-obvious alternative. The reader loses nothing by skipping it.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">> ℹ️ **Note:**</code></td> <td>Supplementary information worth knowing but not required for the task.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">> ⚠️ **Important:**</code></td> <td>Information essential to completing the task correctly, without danger of loss.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">> ⚠️ **Warning:**</code></td> <td>Risk of data loss, lockout, or hardware damage. Must come <em>before</em> the action it applies to.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">> 🔒 **Privacy:**</code></td> <td>What data leaves the phone, who on the mesh can see it, and how to limit it.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">> 🔒 **Security:**</code></td> <td>Cryptographic caveats — key handling, unencrypted channels, admin access.</td> </tr> </tbody> </table></div> <p>Privacy and Security are house-specific labels; they exist because the app’s constitution makes privacy a core principle, and they should not be flattened into Note.</p> </li> <li><strong>ADMON-2</strong> — Admonitions are for information only: never put a required step inside one — if the reader must act, it’s a numbered step; if inaction causes loss, it’s a Warning. Use them sparingly (rarely more than one per section, never adjacent), or they stop working.</li> <li><strong>ADMON-3</strong> — A Warning names the concrete consequence first, then how to avoid it: <em>Formatting a mounted filesystem destroys all data on it</em>, not <em>take care when formatting</em>.</li> </ul> <h2 id="procedures-and-ui"> <a href="#procedures-and-ui" class="anchor-heading" aria-labelledby="procedures-and-ui"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Procedures and UI </h2> <ul> <li><strong>PROC-1</strong> — Bold the exact UI label: tap <strong>Get started</strong>. No quotation marks, and no element type (<em>button</em>, <em>menu</em>) unless it disambiguates. Match the UI’s own capitalization exactly.</li> <li><strong>PROC-2</strong> — Menu paths use a spaced arrow between bold labels: <strong>Settings → Permissions</strong>. Never <code class="language-plaintext highlighter-rouge">></code> or <code class="language-plaintext highlighter-rouge">›</code>.</li> <li><strong>PROC-3</strong> — Steps are imperative, one action each, ordered goal → location → action: <em>To pair a second radio, on the Connections screen, tap <strong>Scan</strong>.</em> Number steps only when order matters; prefer seven or fewer; prefix genuinely optional steps with <em>Optional:</em>.</li> <li><strong>PROC-4</strong> — State the result of a step in the same paragraph as the action, not as its own step.</li> <li><strong>PROC-5</strong> — Describe the task, not the widget, when you can: <em>turn on the <strong>MQTT</strong> module</em>, not <em>tap the toggle switch next to MQTT</em>.</li> </ul> <h2 id="links"> <a href="#links" class="anchor-heading" aria-labelledby="links"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Links </h2> <ul> <li><strong>LINK-1</strong> — Link text describes the destination — the page title or a noun phrase. Never <em>click here</em>, <em>this page</em>, or a raw URL as text. The standing formula: <em>For more information, see <a href="connections">Connections</a>.</em></li> <li><strong>LINK-2</strong> — Sibling pages link by bare slug (<code class="language-plaintext highlighter-rouge">connections</code>), cross-section by relative path (<code class="language-plaintext highlighter-rouge">../developer/testing</code>). <code class="language-plaintext highlighter-rouge">scripts/validate-doc-links.js</code> enforces resolvability.</li> <li><strong>LINK-3</strong> — Radio-side concepts (LoRa presets, firmware regions, MQTT topics) link out to <a href="https://meshtastic.org/docs/">meshtastic.org docs</a> rather than re-explaining them here — one source drifts less than two.</li> </ul> <h2 id="images"> <a href="#images" class="anchor-heading" aria-labelledby="images"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Images </h2> <ul> <li><strong>IMG-1</strong> — Reference screenshots by relative path: <code class="language-plaintext highlighter-rouge">../../assets/screenshots/<page>_<subject>.png</code>. Both the Docusaurus sync and the in-app renderer anchor on the <code class="language-plaintext highlighter-rouge">assets/</code> segment, so this one form works in all three consumers.</li> <li><strong>IMG-2</strong> — Every image has alt text that names the screen and the state it shows: <em>Scanning for Bluetooth devices, with a discovered radio in the list</em>.</li> <li><strong>IMG-3</strong> — Screenshot only what words can’t carry — a complex screen the reader must orient in, not a confirmation dialog. Capture the state right before the action, crop to the relevant surface, and keep version numbers, dates, and real user data out of frame. Place the image directly after the sentence it illustrates.</li> <li><strong>IMG-4</strong> — Never post an image of text, code, or terminal output — use a code block.</li> </ul> <h2 id="code"> <a href="#code" class="anchor-heading" aria-labelledby="code"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Code </h2> <ul> <li><strong>CODE-1</strong> — Code font for file paths, Gradle tasks, module paths (<code class="language-plaintext highlighter-rouge">core:ble</code>), class and function names, setting keys, values the reader types, and protocol identifiers (<code class="language-plaintext highlighter-rouge">LongFast</code>, <code class="language-plaintext highlighter-rouge">!a1b2c3d4</code>).</li> <li><strong>CODE-2</strong> — Not code font: product names, and URLs the reader is meant to visit (link those instead).</li> <li><strong>CODE-3</strong> — Fenced blocks with a language tag; shell blocks show the bare command with no <code class="language-plaintext highlighter-rouge">$</code> prompt, so it copies cleanly.</li> <li><strong>CODE-4</strong> — Placeholders in angle brackets: <code class="language-plaintext highlighter-rouge">docs/<scope></code>, <code class="language-plaintext highlighter-rouge">--tests "<pattern>"</code>.</li> </ul> <h2 id="developer-pages"> <a href="#developer-pages" class="anchor-heading" aria-labelledby="developer-pages"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Developer Pages </h2> <ul> <li><strong>DEV-1</strong> — Same voice, different reader: assume Kotlin, Gradle, and Android fluency, and skip the reassurance — but the rules above still apply. Terse is good; cryptic is not.</li> <li><strong>DEV-2</strong> — All frontmatter rules apply, including <code class="language-plaintext highlighter-rouge">description</code> — developer pages are indexed by the same in-app search as user pages.</li> <li><strong>DEV-3</strong> — Structural or procedural changes get a <em>What’s New for Developers</em> entry in <code class="language-plaintext highlighter-rouge">developer.md</code>.</li> </ul> <h2 id="decisions-and-why"> <a href="#decisions-and-why" class="anchor-heading" aria-labelledby="decisions-and-why"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Decisions and Why </h2> <p>Where this guide deviates from the external guides it synthesizes, the deviation is deliberate:</p> <div class="table-wrapper"><table> <thead> <tr> <th>Decision</th> <th>External guides say</th> <th>Why we differ</th> </tr> </thead> <tbody> <tr> <td>Title Case headings (HEAD-1)</td> <td>Google, Microsoft, gov.uk: sentence case</td> <td>The whole corpus is Title Case; re-casing invalidates ~150 headings’ translations across 40+ locales for no reader benefit.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">→</code> in menu paths (PROC-2)</td> <td>Google, Microsoft: <code class="language-plaintext highlighter-rouge">></code></td> <td><code class="language-plaintext highlighter-rouge">→</code> is the entrenched house form (29:2 in the corpus), unambiguous in Markdown, and reads naturally in the in-app renderer.</td> </tr> <tr> <td>Emoji admonition labels (ADMON-1)</td> <td>Red Hat, SUSE: plain labeled blocks</td> <td>The in-app renderer has no admonition component; the emoji-plus-bold-blockquote form is the established house pattern and survives all three renderers.</td> </tr> <tr> <td>Privacy/Security labels (ADMON-1)</td> <td>Not in any external set</td> <td>They map directly to the constitution’s Privacy First principle and deserve more visual weight than Note.</td> </tr> <tr> <td>Relative image paths (IMG-1)</td> <td>(Repo history preferred root-relative)</td> <td>The in-app image transformer documents the relative form as canonical, the sync script rewrites either form, and every existing page already uses it.</td> </tr> <tr> <td>Spaced em dashes (LANG-7)</td> <td>Microsoft: unspaced</td> <td>477:0 in the corpus; also kinder to narrow in-app line widths.</td> </tr> <tr> <td>Contractions (VOICE-2)</td> <td>gov.uk warns on negative contractions</td> <td>We follow Microsoft/18F (contractions are the house voice) and adopt gov.uk’s caution only inside warnings.</td> </tr> </tbody> </table></div> <h2 id="new-page-checklist"> <a href="#new-page-checklist" class="anchor-heading" aria-labelledby="new-page-checklist"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> New Page Checklist </h2> <ol> <li>Create <code class="language-plaintext highlighter-rouge">docs/en/user/<slug>.md</code> or <code class="language-plaintext highlighter-rouge">docs/en/developer/<slug>.md</code> with complete frontmatter (STRUCT-1).</li> <li>Register the page in <code class="language-plaintext highlighter-rouge">feature/docs/.../data/DocBundleLoader.kt</code> with keywords and aliases.</li> <li>Put screenshots in <code class="language-plaintext highlighter-rouge">docs/assets/screenshots/</code>, referenced per IMG-1.</li> <li>Add a <em>What’s New</em> entry (STRUCT-6).</li> <li>Validate locally: <code class="language-plaintext highlighter-rouge">node scripts/validate-doc-links.js docs/en</code>, <code class="language-plaintext highlighter-rouge">node scripts/check-doc-coverage.js .</code>, <code class="language-plaintext highlighter-rouge">node scripts/check-doc-aliases.js .</code> (every alias in step 1’s frontmatter must also be in step 2’s loader entry — only the loader’s list reaches in-app search), and the docs bundle Gradle checks in <a href="contributing">Contributing</a>.</li> </ol> <h2 id="related-topics"> <a href="#related-topics" class="anchor-heading" aria-labelledby="related-topics"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Related Topics </h2> <ul> <li><a href="contributing">Contributing</a> — branch naming, PR workflow, and the verification gates docs changes run through</li> <li><a href="test-builds">Test Builds & Obtainium</a> — where prerelease docs snapshots are published</li> </ul> </main> <hr> <footer> <footer class="site-footer"> Copyright © 2026 Meshtastic LLC. Distributed under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPL v3 License.</a> </footer> <div class="d-sm-block d-md-none"> <div class="mt-4 fs-2"> This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </div> </div> </footer> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
|