@@ -8,7 +8,7 @@ import { generateHowToSchema, meshCoreSetupHowTo } from "@/lib/schemas/howto";
88export const metadata : Metadata = {
99 title : "Get Started with MeshCore" ,
1010 description : "Learn how to join the Denver mesh network. Hardware requirements, firmware setup guide, configuration instructions, and community resources." ,
11- keywords : [ "MeshCore" , "mesh network" , "getting started" , "Denver" , "LoRa" , "ESP32" , "firmware" , "setup guide" , "tutorial" ] ,
11+ keywords : [ "MeshCore" , "mesh network" , "getting started" , "Denver" , "LoRa" , "ESP32" , "firmware" , "setup guide" , "tutorial" , "naming standard" , "node naming" ] ,
1212 alternates : {
1313 canonical : '/start' ,
1414 } ,
@@ -277,6 +277,66 @@ const resources = [
277277 } ,
278278] ;
279279
280+ // Naming Standard v1.0 data
281+ const infraNodeTypes = [
282+ { code : "RC" , description : "Core Repeater — Backbone. Mountain/tower. Battery backup." } ,
283+ { code : "RD" , description : "Distribution Rpt — Bridges core to edge. Suburban elevated." } ,
284+ { code : "RE" , description : "Edge Repeater — Rooftop/residential. Mains power OK." } ,
285+ { code : "RM" , description : "Mobile Repeater — Vehicle or temporary." } ,
286+ { code : "T" , description : "Room Server — Fixed location." } ,
287+ { code : "TM" , description : "Mobile Room — Location changes." } ,
288+ { code : "TR" , description : "Room + Repeat — Room server w/ repeat on." } ,
289+ { code : "OB" , description : "Observer — Listen-only/monitoring." } ,
290+ ] ;
291+
292+ const infraExamples = [
293+ { name : "CO-DENVER-CHSPARK-RC01" , description : "Core rpt, Cheesman Park" } ,
294+ { name : "CO-DENVER-SLOAN-RE01" , description : "Edge rpt, Sloan\u2019s Lake" } ,
295+ { name : "CO-LKWD-GRENMTN-RD01" , description : "Dist rpt, Green Mtn" } ,
296+ { name : "CO-REDROCKS-RC01" , description : "Core rpt, Red Rocks (no city needed)" } ,
297+ { name : "CO-DENVER-RINO-T01" , description : "Room server, RiNo" } ,
298+ ] ;
299+
300+ const cityCodes = [
301+ "DENVER" , "AURORA" , "LKWD" , "ARVADA" , "WSTMNR" , "THRTON" , "CENTL" , "BROOM" ,
302+ "LTTN" , "ENGL" , "CMRCE" , "GLDN" , "BOULDR" , "PARKER" , "CSTLRK" , "HGHLND" ,
303+ "CSPRGS" , "LSVL" , "LFAYTE" ,
304+ ] ;
305+
306+ const landmarkExamples = [
307+ { code : "CHSPARK" , name : "Cheesman" } ,
308+ { code : "SLOAN" , name : "Sloan\u2019s" } ,
309+ { code : "WSHPARK" , name : "Wash Park" } ,
310+ { code : "RINO" , name : "RiNo" } ,
311+ { code : "LODO" , name : "LoDo" } ,
312+ { code : "CAPHILL" , name : "Cap Hill" } ,
313+ { code : "UNION" , name : "Union Station" } ,
314+ { code : "COLFAX" , name : "Colfax" } ,
315+ { code : "REDRKS" , name : "Red Rocks" } ,
316+ { code : "CONFLU" , name : "Confluence" } ,
317+ { code : "16THST" , name : "16th St" } ,
318+ { code : "STAPLE" , name : "Stapleton" } ,
319+ { code : "DIA" , name : "DIA" } ,
320+ { code : "SPR+I25" , name : "Speer & I-25" } ,
321+ ] ;
322+
323+ const companionExamples = [
324+ { name : "\u{1F47B} M3SHGH\u00D8ST 01" , description : "Primary carry node" } ,
325+ { name : "\u{1F47B} M3SHGH\u00D8ST 02" , description : "Home base node" } ,
326+ { name : "\u{1F47B} M3SHGH\u00D8ST 03" , description : "Vehicle node" } ,
327+ { name : "\u{1F43F}\uFE0F SQRLNUT 01" , description : "Primary companion" } ,
328+ { name : "\u{1F525} BURNR F4" , description : "Companion (key prefix suffix)" } ,
329+ { name : "\u{1F3D4}\uFE0F PKBAGGER 01" , description : "Primary companion" } ,
330+ ] ;
331+
332+ const companionDoNots = [
333+ "Use your real name" ,
334+ "Put hardware in the name" ,
335+ "Use different emojis per device \u2014 one emoji per person" ,
336+ "Take someone else\u2019s emoji" ,
337+ "Go over 23 characters" ,
338+ ] ;
339+
280340const breadcrumbData = generateBreadcrumbSchema ( [
281341 { name : 'Home' , url : 'https://denvermc.com' } ,
282342 { name : 'Get Started' , url : 'https://denvermc.com/start' } ,
@@ -318,6 +378,9 @@ export default function StartPage() {
318378 < a href = "#setup" className = "btn-outline" >
319379 Setup Guide
320380 </ a >
381+ < a href = "#naming" className = "btn-outline" >
382+ Naming Standard
383+ </ a >
321384 </ div >
322385 </ div >
323386 </ section >
@@ -587,8 +650,230 @@ export default function StartPage() {
587650 </ div >
588651 </ section >
589652
653+ { /* Naming Standard */ }
654+ < section id = "naming" className = "px-6 py-16 bg-background-secondary" >
655+ < div className = "max-w-4xl mx-auto" >
656+ < h2 className = "text-3xl md:text-4xl font-bold mb-4 text-foreground text-center" >
657+ Naming Standard
658+ </ h2 >
659+ < p className = "text-foreground-muted text-center mb-12 max-w-2xl mx-auto" >
660+ All MeshCore node names are limited to < span className = "text-mesh font-semibold" > 23 characters</ span > — this is a hard limit in the firmware. Follow the conventions below so the network stays organized and readable.
661+ </ p >
662+
663+ { /* Part 1: Infrastructure Nodes */ }
664+ < div className = "mb-16" >
665+ < h3 className = "text-2xl font-bold text-foreground mb-6 flex items-center gap-3" >
666+ < span className = "text-3xl" > 📡</ span >
667+ Part 1: Infrastructure Nodes
668+ </ h3 >
669+
670+ { /* Format Card */ }
671+ < div className = "card-mesh p-6 mb-8" >
672+ < p className = "font-mono text-lg text-mesh mb-4 text-center" >
673+ CO-[CITY]-[LANDMARK]-[TYPE][##]
674+ </ p >
675+ < div className = "grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm text-foreground-muted" >
676+ < div > < span className = "font-semibold text-foreground" > CO</ span > — State prefix (Colorado)</ div >
677+ < div > < span className = "font-semibold text-foreground" > CITY</ span > — City code from the list below</ div >
678+ < div > < span className = "font-semibold text-foreground" > LANDMARK</ span > — Recognizable location</ div >
679+ < div > < span className = "font-semibold text-foreground" > TYPE</ span > — Node type code</ div >
680+ < div > < span className = "font-semibold text-foreground" > ##</ span > — Two-digit sequence number</ div >
681+ </ div >
682+ < p className = "text-sm text-foreground-muted mt-4" >
683+ When the landmark is prominent enough on its own (e.g., Red Rocks), you can drop CITY — the landmark gets up to 14 characters.
684+ </ p >
685+ </ div >
686+
687+ { /* Infrastructure Examples Table */ }
688+ < div className = "card-mesh overflow-hidden mb-8" >
689+ < table className = "w-full" >
690+ < thead className = "bg-night-800/50" >
691+ < tr >
692+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Name</ th >
693+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Description</ th >
694+ </ tr >
695+ </ thead >
696+ < tbody className = "divide-y divide-card-border" >
697+ { infraExamples . map ( ( ex ) => (
698+ < tr key = { ex . name } className = "hover:bg-night-800/30 transition-colors" >
699+ < td className = "px-6 py-3 font-mono text-mesh text-sm" > { ex . name } </ td >
700+ < td className = "px-6 py-3 text-foreground-muted text-sm" > { ex . description } </ td >
701+ </ tr >
702+ ) ) }
703+ </ tbody >
704+ </ table >
705+ </ div >
706+
707+ { /* Node Type Codes Table */ }
708+ < h4 className = "text-lg font-semibold text-foreground mb-3" > Node Type Codes</ h4 >
709+ < div className = "card-mesh overflow-hidden mb-8" >
710+ < table className = "w-full" >
711+ < thead className = "bg-night-800/50" >
712+ < tr >
713+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Code</ th >
714+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Description</ th >
715+ </ tr >
716+ </ thead >
717+ < tbody className = "divide-y divide-card-border" >
718+ { infraNodeTypes . map ( ( type ) => (
719+ < tr key = { type . code } className = "hover:bg-night-800/30 transition-colors" >
720+ < td className = "px-6 py-3 font-mono font-semibold text-mountain-500" > { type . code } </ td >
721+ < td className = "px-6 py-3 text-foreground-muted text-sm" > { type . description } </ td >
722+ </ tr >
723+ ) ) }
724+ </ tbody >
725+ </ table >
726+ </ div >
727+
728+ { /* City Codes Grid */ }
729+ < h4 className = "text-lg font-semibold text-foreground mb-3" > City Codes</ h4 >
730+ < div className = "card-mesh p-6 mb-8" >
731+ < div className = "grid grid-cols-2 md:grid-cols-4 gap-2" >
732+ { cityCodes . map ( ( code ) => (
733+ < span key = { code } className = "font-mono text-sm text-mesh bg-night-800/30 px-3 py-1.5 rounded text-center" >
734+ { code }
735+ </ span >
736+ ) ) }
737+ </ div >
738+ < p className = "text-sm text-foreground-muted mt-4" >
739+ Don't see your city? Propose a code in{ " " }
740+ < a href = "https://discord.gg/QpaW8FTTCE" className = "text-mesh hover:text-mesh-light" >
741+ our Discord
742+ </ a > .
743+ </ p >
744+ </ div >
745+
746+ { /* Landmark Examples Grid */ }
747+ < h4 className = "text-lg font-semibold text-foreground mb-3" > Landmark Examples</ h4 >
748+ < div className = "card-mesh p-6 mb-8" >
749+ < div className = "grid grid-cols-2 md:grid-cols-4 gap-2" >
750+ { landmarkExamples . map ( ( lm ) => (
751+ < div key = { lm . code } className = "text-sm" >
752+ < span className = "font-mono text-mesh" > { lm . code } </ span >
753+ < span className = "text-foreground-muted" > { lm . name } </ span >
754+ </ div >
755+ ) ) }
756+ </ div >
757+ </ div >
758+
759+ { /* Public Key Prefixes Card */ }
760+ < div className = "card-mesh p-6" >
761+ < div className = "flex items-center gap-3 mb-3" >
762+ < span className = "text-3xl" > 🔑</ span >
763+ < h4 className = "text-lg font-semibold text-foreground" > Public Key Prefixes</ h4 >
764+ </ div >
765+ < p className = "text-foreground-muted text-sm mb-4" >
766+ Repeaters and room servers should use a unique public key prefix to avoid collisions. Check current prefix utilization and generate a key with a chosen prefix.
767+ </ p >
768+ < div className = "flex flex-wrap gap-3" >
769+ < a
770+ href = "https://analyzer.letsmesh.net/nodes/prefix-utilization"
771+ target = "_blank"
772+ rel = "noopener noreferrer"
773+ className = "text-mesh hover:text-mesh-light inline-flex items-center gap-1 text-sm"
774+ >
775+ Check Prefix Utilization
776+ < svg className = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
777+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
778+ </ svg >
779+ </ a >
780+ < a
781+ href = "https://gessaman.com/mc-keygen/"
782+ target = "_blank"
783+ rel = "noopener noreferrer"
784+ className = "text-mesh hover:text-mesh-light inline-flex items-center gap-1 text-sm"
785+ >
786+ Key Generator
787+ < svg className = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
788+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
789+ </ svg >
790+ </ a >
791+ </ div >
792+ </ div >
793+ </ div >
794+
795+ { /* Part 2: Companion Nodes */ }
796+ < div >
797+ < h3 className = "text-2xl font-bold text-foreground mb-6 flex items-center gap-3" >
798+ < span className = "text-3xl" > 📱</ span >
799+ Part 2: Companion Nodes
800+ </ h3 >
801+
802+ { /* Format Card */ }
803+ < div className = "card-mesh p-6 mb-8" >
804+ < p className = "font-mono text-lg text-mesh mb-4 text-center" >
805+ [EMOJI] [HANDLE] [##]
806+ </ p >
807+ < div className = "grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm text-foreground-muted" >
808+ < div > < span className = "font-semibold text-foreground" > EMOJI</ span > — Your personal emoji (one per person)</ div >
809+ < div > < span className = "font-semibold text-foreground" > HANDLE</ span > — Your unique handle/callsign</ div >
810+ < div > < span className = "font-semibold text-foreground" > ##</ span > — Number by purpose, not hardware</ div >
811+ </ div >
812+ < p className = "text-sm text-foreground-muted mt-4" >
813+ Number by purpose (01 = primary carry, 02 = home base, 03 = vehicle), not by hardware model. If you upgrade your radio, the name stays the same.
814+ </ p >
815+ </ div >
816+
817+ { /* Companion Examples Table */ }
818+ < div className = "card-mesh overflow-hidden mb-8" >
819+ < table className = "w-full" >
820+ < thead className = "bg-night-800/50" >
821+ < tr >
822+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Name</ th >
823+ < th className = "px-6 py-3 text-left text-sm font-semibold text-foreground" > Description</ th >
824+ </ tr >
825+ </ thead >
826+ < tbody className = "divide-y divide-card-border" >
827+ { companionExamples . map ( ( ex ) => (
828+ < tr key = { ex . name } className = "hover:bg-night-800/30 transition-colors" >
829+ < td className = "px-6 py-3 font-mono text-mesh text-sm" > { ex . name } </ td >
830+ < td className = "px-6 py-3 text-foreground-muted text-sm" > { ex . description } </ td >
831+ </ tr >
832+ ) ) }
833+ </ tbody >
834+ </ table >
835+ </ div >
836+
837+ { /* Do Not Rules */ }
838+ < div className = "card-mesh overflow-hidden mb-8" >
839+ < div className = "p-6 bg-sunset-500/10 border-b border-card-border" >
840+ < h4 className = "text-lg font-semibold text-sunset-700 flex items-center gap-3" >
841+ < span className = "text-xl" > ⚠️</ span >
842+ Do Not
843+ </ h4 >
844+ </ div >
845+ < div className = "p-6" >
846+ < ul className = "space-y-2" >
847+ { companionDoNots . map ( ( rule , index ) => (
848+ < li key = { index } className = "text-foreground-muted flex items-start gap-2" >
849+ < span className = "text-sunset-500 mt-1" > ✕</ span >
850+ < span > { rule } </ span >
851+ </ li >
852+ ) ) }
853+ </ ul >
854+ </ div >
855+ </ div >
856+
857+ { /* Community Tracking Card */ }
858+ < div className = "card-mesh p-6" >
859+ < div className = "flex items-center gap-3 mb-3" >
860+ < span className = "text-3xl" > 📋</ span >
861+ < h4 className = "text-lg font-semibold text-foreground" > Community Tracking</ h4 >
862+ </ div >
863+ < p className = "text-foreground-muted text-sm" >
864+ Before deploying a new node, check the shared community list to avoid duplicate names and emoji conflicts. Post your new node in{ " " }
865+ < a href = "https://discord.gg/QpaW8FTTCE" className = "text-mesh hover:text-mesh-light" >
866+ our Discord
867+ </ a > { " " }
868+ so others can update their records.
869+ </ p >
870+ </ div >
871+ </ div >
872+ </ div >
873+ </ section >
874+
590875 { /* Advanced Topics */ }
591- < section id = "advanced" className = "px-6 py-16 bg-background-secondary " >
876+ < section id = "advanced" className = "px-6 py-16" >
592877 < div className = "max-w-6xl mx-auto" >
593878 < h2 className = "text-3xl md:text-4xl font-bold mb-4 text-foreground text-center" >
594879 Advanced Topics
0 commit comments