@@ -40,7 +40,9 @@ const tokens = md.parse(readme, {});
4040const title = extractTitle ( tokens ) ?? "TPS Format Specification" ;
4141const summary = extractSummary ( tokens ) ?? "Markdown-based teleprompter scripts with timing, pacing, emotion, and styling metadata." ;
4242const sections = extractSections ( tokens ) ;
43- const articleHtml = md . render ( readme ) ;
43+ const stats = buildStats ( readme , sections ) ;
44+ const articleHtml = md . renderer . render ( trimTitle ( tokens ) , md . options , { } ) ;
45+ const heroTitle = buildHeroTitle ( title ) ;
4446const builtAt = new Intl . DateTimeFormat ( "en" , {
4547 dateStyle : "long" ,
4648 timeStyle : "short" ,
@@ -70,12 +72,23 @@ const page = `<!DOCTYPE html>
7072 <div class="page-shell">
7173 <header class="hero">
7274 <div class="hero-copy">
73- <span class="eyebrow">ManagedCode Format Spec</span>
74- <h1>${ escapeHtml ( title ) } </h1>
75+ <span class="eyebrow">Managed Code / Open Spec</span>
76+ <p class="hero-kicker">A markdown-first teleprompter format built for natural delivery.</p>
77+ ${ heroTitle }
7578 <p class="hero-summary">${ escapeHtml ( summary ) } </p>
79+ <ul class="hero-signals" aria-label="Format highlights">
80+ <li>Markdown-native authoring</li>
81+ <li>Actor and RSVP reading profiles</li>
82+ <li>Timing, pace, and emotion metadata</li>
83+ </ul>
7684 <div class="hero-actions">
77- <a class="button button-primary" href="https://github.com/managedcode/TPS">Open Repository</a>
78- <a class="button button-secondary" href="https://github.com/managedcode/TPS/blob/main/README.md">View Raw README</a>
85+ <a class="button button-primary" href="#specification">Read Specification</a>
86+ <a class="button button-secondary" href="https://github.com/managedcode/TPS">Open Repository</a>
87+ </div>
88+ <div class="hero-facts">
89+ <span><strong>${ stats . sectionCount } </strong> major sections</span>
90+ <span><strong>${ stats . subsectionCount } </strong> deep-dive subsections</span>
91+ <span><strong>${ stats . wordCount . toLocaleString ( "en-US" ) } </strong> words of spec detail</span>
7992 </div>
8093 </div>
8194 </header>
@@ -86,17 +99,19 @@ const page = `<!DOCTYPE html>
8699 <p class="panel-label">Contents</p>
87100 <a href="#top">Back to top</a>
88101 </div>
102+ <p class="toc-summary">Jump straight to the part of the format you need.</p>
89103 <nav aria-label="Table of contents">
90104 <ol class="toc-list">
91105 ${ renderSections ( sections ) }
92106 </ol>
93107 </nav>
94108 </aside>
95109
96- <article class="content-card">
110+ <article class="content-card" id="specification" >
97111 <div class="content-meta" id="top">
98- <span>Source of truth: <code>README.md</code></span>
99- <span>Last site build: ${ escapeHtml ( builtAt ) } UTC</span>
112+ <span class="meta-chip">Source of truth <code>README.md</code></span>
113+ <span class="meta-chip">${ stats . sectionCount } sections / ${ stats . subsectionCount } subsections</span>
114+ <span class="meta-chip">Built ${ escapeHtml ( builtAt ) } UTC</span>
100115 </div>
101116 <div class="markdown-body">
102117 ${ articleHtml }
@@ -179,6 +194,44 @@ function extractSections(tokenList) {
179194 return sectionList ;
180195}
181196
197+ function buildStats ( markdown , sectionList ) {
198+ return {
199+ sectionCount : sectionList . filter ( ( section ) => section . depth === 2 ) . length ,
200+ subsectionCount : sectionList . filter ( ( section ) => section . depth === 3 ) . length ,
201+ wordCount : markdown . match ( / \b [ \p{ L} \p{ N} ] [ \p{ L} \p{ N} ' - ] * \b / gu) ?. length ?? 0
202+ } ;
203+ }
204+
205+ function trimTitle ( tokenList ) {
206+ if (
207+ tokenList [ 0 ] ?. type === "heading_open" &&
208+ tokenList [ 0 ] ?. tag === "h1" &&
209+ tokenList [ 2 ] ?. type === "heading_close"
210+ ) {
211+ return tokenList . slice ( 3 ) ;
212+ }
213+
214+ return tokenList ;
215+ }
216+
217+ function buildHeroTitle ( value ) {
218+ const match = value . match ( / ^ ( .* ?) \s * \( ( .* ?) \) \s * $ / ) ;
219+ if ( ! match ) {
220+ return `<h1>${ escapeHtml ( value ) } </h1>` ;
221+ }
222+
223+ const baseTitle = match [ 1 ] . trim ( ) ;
224+ const subtitle = match [ 2 ] . trim ( ) ;
225+ const [ lead , ...rest ] = baseTitle . split ( / \s + / ) ;
226+ const titleTail = rest . join ( " " ) ;
227+
228+ if ( ! lead || ! titleTail ) {
229+ return `<h1>${ escapeHtml ( baseTitle ) } </h1><p class="hero-title-sub">${ escapeHtml ( subtitle ) } </p>` ;
230+ }
231+
232+ return `<h1><span class="hero-title-mark">${ escapeHtml ( lead ) } </span><span class="hero-title-main">${ escapeHtml ( titleTail ) } </span></h1><p class="hero-title-sub">${ escapeHtml ( subtitle ) } </p>` ;
233+ }
234+
182235function renderSections ( sectionList ) {
183236 return sectionList
184237 . map ( ( section ) => {
0 commit comments