serve-my-md 1.1.8 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -393,7 +393,7 @@ import { cp, readdir as readdir2, rm, writeFile } from "fs/promises";
393
393
  import path4, { resolve } from "path";
394
394
  import { fileURLToPath } from "url";
395
395
  import { build as viteBuild } from "vite";
396
- import { mkdirSync } from "fs";
396
+ import { mkdirSync, existsSync } from "fs";
397
397
  var DIST_DIRNAME = finalConfig.outDir || "dist";
398
398
  var WEB_DIRNAME = "web";
399
399
  var PUBLIC_DIRNAME = "public";
@@ -458,12 +458,16 @@ async function build(options2) {
458
458
  await writeFile(path4.join(webDir, "index.html"), await generateHtml());
459
459
  Logger.log("Generated HTML from template");
460
460
  if (!skipBuild) {
461
- const entries = await readdir2(path4.join(webDir, PUBLIC_DIRNAME));
462
- for (const entry of entries) {
463
- await rm(path4.join(webDir, PUBLIC_DIRNAME, entry), {
464
- recursive: true,
465
- force: true
466
- });
461
+ if (existsSync(path4.join(webDir, PUBLIC_DIRNAME))) {
462
+ const entries = await readdir2(path4.join(webDir, PUBLIC_DIRNAME));
463
+ for (const entry of entries) {
464
+ await rm(path4.join(webDir, PUBLIC_DIRNAME, entry), {
465
+ recursive: true,
466
+ force: true
467
+ });
468
+ }
469
+ } else {
470
+ mkdirSync(path4.join(webDir, PUBLIC_DIRNAME));
467
471
  }
468
472
  if (finalConfig.publicPath) {
469
473
  if (await FileOrDirectoryExists(
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "serve-my-md",
3
- "version": "1.1.8",
3
+ "version": "1.1.10",
4
4
  "type": "module",
5
5
  "description": "Generate beautiful SEO-friendly static websites from Markdown files.",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/AshishAntil07/serve-my-md.git"
9
9
  },
10
- "homepage": "https://ashishantil.dev/serve-my-md",
10
+ "homepage": "https://serve-my-md.ashishantil.dev",
11
11
  "author": "AshishAntil07 <ashishantil.antil07@gmail.com>",
12
12
  "license": "MIT",
13
13
  "keywords": [
package/web/index.html CHANGED
@@ -7,14 +7,14 @@
7
7
  <meta name="theme-color" content="#000000" />
8
8
  <meta
9
9
  name="description"
10
- content="Docs for serve-my-md."
10
+ content="Documentation for the FollowPath library — animate HTML elements along SVG paths."
11
11
  />
12
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Exo:ital,wght@0,100..900;1,100..900&display=swap" /><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Commissioner:wght@100..900&display=swap" /><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap" />
13
- <meta property="og:title" content="Serve My MD Docs">
14
- <meta property="og:description" content="Documentation for serve-my-md, a CLI tool to generate static docs sites from markdown.">
12
+
13
+ <meta property="og:title" content="FollowPath Docs">
14
+ <meta property="og:description" content="Documentation for the FollowPath library animate HTML elements along SVG paths.">
15
15
  <meta property="og:type" content="website">
16
- <meta property="og:site_name" content="Serve My MD Docs">
17
- <title>Serve My MD Docs</title>
16
+ <meta property="og:site_name" content="FollowPath Docs">
17
+ <title>FollowPath Docs</title>
18
18
 
19
19
 
20
20
  <style>
@@ -0,0 +1,117 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+
5
+ <head>
6
+ <meta charset="utf-8">
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
+ <title></title>
9
+ <meta name="description" content="">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1">
11
+ <script src='./demo/index.js' type='module'></script>
12
+ <style>
13
+ * {
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ .element {
19
+ width: 50px;
20
+ height: 50px;
21
+ background-color: red;
22
+ display: flex;
23
+ justify-content: center;
24
+ align-items: center;
25
+ font-size: 25px;
26
+ position: absolute;
27
+ top: -25px;
28
+ left: -25px;
29
+ }
30
+
31
+ .logs {
32
+ position: absolute;
33
+ top: 0;
34
+ left: 0;
35
+ height: 100vh;
36
+ width: 100vw;
37
+ opacity: 50%;
38
+ color: black;
39
+ }
40
+ </style>
41
+ </head>
42
+
43
+ <body>
44
+ <svg xmlns='http://www.w3.org/2000/svg' height='700' width='1000'>
45
+ <polyline style="
46
+ fill: transparent;
47
+ stroke-linejoin: round;
48
+ stroke-linecap: round;
49
+ stroke: rgb(0, 0, 0);
50
+ stroke-width: 1px;
51
+ " points="198,264 199,262 200,259 201,257 202,256 202,255 202,253 202,252 203,250 204,249 204,247 205,247 205,245 206,244 207,242 208,240 209,237 210,236 210,235 211,234 212,232 213,232 214,230 214,229 216,227 217,225 219,223 220,221 221,220 222,219 223,217 224,216 225,215 226,214 229,211 231,210 233,208 236,207 238,206 240,204 242,203 247,200 249,199 254,196 257,194 260,192 262,191 264,190 266,189 268,188 270,187 274,186 280,185 287,183 294,182 298,182 300,182 302,182 305,182 308,184 312,185 316,187 319,189 322,190 324,192 327,195 328,196 330,198 332,201 332,204 334,207 335,210 336,213 336,216 336,218 337,221 337,224 337,225 338,228 339,232 339,235 339,238 339,242 339,245 338,249 337,252 337,255 334,260 332,264 332,268 332,272 332,278 332,282 332,286 333,289 334,293 334,298 332,305 332,313 333,315 335,318 338,321 340,323 343,325 345,325 347,325 348,325 350,325 352,325 354,325 358,323 364,320 366,320 371,317 373,315 375,313 377,311 377,309 379,307 381,304 383,302 384,300 386,299 387,299 388,299 389,299 391,299 394,299 397,300 399,302 402,303 404,305 406,307 408,310 410,314 413,319 414,322 415,325 415,329 415,331 415,335 415,338 415,341 413,343 413,345 412,347 412,349 411,352 411,354 408,359 406,362 404,364 402,366 401,368 399,369 395,371 388,373 378,375 369,378 365,380 362,380 357,381 354,381 352,381 349,381 347,381 344,381 342,381 338,381 332,381 329,381 326,380 323,378 321,376 318,374 315,372 313,370 311,368 309,367 307,365 305,363 303,361 299,356 297,352 295,350 294,348 293,346 292,344 291,342 290,341 289,339 288,338 287,337 286,336 285,334 284,332 283,331 282,328 281,324 279,320 279,316 279,312 279,309 280,303 281,299 283,294 285,290 288,286 291,282 298,276 299,275 304,271 308,268 310,266 310,265 311,263 312,261 312,260 312,258 312,257 312,256 312,254 310,253 308,251 305,248 303,247 300,246 298,246 297,246 295,246 292,246 289,247 283,250 281,251 277,253 272,256 269,257 267,259 264,263 262,266 260,270 258,273 256,276 256,278 255,283 254,286 253,290 253,294 253,297 253,302 254,314 254,316 255,322 258,328 259,333 261,340 263,347 264,353 266,360 269,369 271,374 273,378 275,382 278,389 283,394 286,398 288,404 292,409 298,411 304,413 310,415 323,416 333,418 344,418 356,419 366,419 377,419 390,417 398,414 401,412 412,403 420,398 422,396 432,385 438,377 444,368 446,364 451,355 453,348 455,342 456,333 456,328 456,324 456,320 456,314 454,310 452,306 450,301 447,297 444,293 441,288 438,281 437,279 435,274 431,267 430,263 429,259 429,252 431,244 433,236 440,225 453,205 468,190 484,175 493,166 518,145 533,132 548,120 564,112 573,107 584,105 591,102 597,102 607,104 611,107 620,113 636,128 652,137 668,147 686,153 705,157 725,158 747,157 780,148 796,141 804,137 818,129 835,116 849,106 860,102 871,98 880,97 885,97 889,98 895,102 903,110 913,124 928,145 944,176 967,221 976,243 983,263 991,282 996,302 1001,327 1005,352 1005,381 994,426 934,493 879,521 829,539 809,543 796,538 784,528 772,502 754,467 739,444 729,427 718,417 712,410 708,406 706,401 700,393 686,385 676,379 664,373 651,372 638,376 627,381 617,391 600,410 597,417 593,438 593,448 593,462 594,477 594,488 592,495 587,502 581,505 575,505 561,499 549,489 544,483 532,457 528,432 528,406 530,396 546,349 555,339 559,335 568,327 589,311 598,306 620,294 644,287 674,280 687,278 694,281 697,283 702,287 706,293 714,300 723,309 735,317 748,323 768,326 783,324 796,320 804,312 810,302 812,296 815,289 815,278 815,270 815,262 813,256 811,252 810,251 810,249 811,248 815,246 821,245 831,245 845,245 860,247 881,250 893,250 ">
52
+ </polyline>
53
+ </svg>
54
+ <div class='element'>&rarr;</div>
55
+ <div class="logs"></div>
56
+
57
+ <script>
58
+
59
+ document.addEventListener('DOMContentLoaded', () => {
60
+ const logsElem = document.querySelector(".logs");
61
+ function log(str) {
62
+ logsElem.innerHTML += str;
63
+ logsElem.appendChild(document.createElement("br"));
64
+ }
65
+
66
+ const fp = new FollowPath({ // creates an instance.
67
+ element: document.querySelector('.element'), // element to animate.
68
+ duration: 9000, // duration per iteration (in ms).
69
+ path: document.querySelector('polyline'), // path to follow (can be a polyline or path element).
70
+ iterations: 2.5, // number of times the element will animate over the path.
71
+ rotate: true, // whether to rotate the element along the path. (optional, false by default)
72
+
73
+ easing(t) { // easing function to control animation pacing. (optional)
74
+ // easeInOutCubic example
75
+ return t < 0.5
76
+ ? 4 * t * t * t
77
+ : 1 - Math.pow(-2 * t + 2, 3) / 2;
78
+ },
79
+
80
+ callback() { // callback function, called after all iterations are completed. (optional)
81
+ console.log('done');
82
+ },
83
+
84
+ timeline: { // timeline callback object. (optional)
85
+ '0%'() { console.log('started') },
86
+ '25%'() { console.log('25% completed') },
87
+ '50%'() { console.log('half completed') },
88
+ '75%'() { console.log('75% completed') },
89
+ } // timeline keys must be in percentages!
90
+ });
91
+
92
+ log("started animation");
93
+ fp.animate(); // starts the animation
94
+
95
+ setTimeout(() => {
96
+ fp.pause(); // pauses the animation after 1s
97
+ log("paused for 1 second");
98
+ setTimeout(() => {
99
+ fp.play();
100
+ log("resumed");
101
+ }, 1000); // resumes animation after another second
102
+ }, 1000);
103
+
104
+ setTimeout(() => {
105
+ console.log(`fps: ${fp.fps}\niterations: ${fp.iterations}`);
106
+ fp.stop(); // stops the animation after 6 seconds.
107
+ log("stopping the animation after 8.5 second by force.");
108
+ log("logged fps and completed iterations at the instant in the console.");
109
+ // Note: Stopping the animation by interruption doesn't call the callback.
110
+ }, 8500);
111
+
112
+ })
113
+
114
+ </script>
115
+ </body>
116
+
117
+ </html>
@@ -0,0 +1,3 @@
1
+ class FollowPath{#t;#e;#i;#s;#a;#n;#r;#o={clamp:t=>1,loop:t=>t>1?t%1:1-t%1,pingpong:t=>t>1?1-t%1:-t%1};#h;#l;path;iterations;callback;delay;easing;scale;fps;constructor(t){if(!this.#p(t))throw Error("Invalid Config.");const{element:e,duration:i,path:s,iterations:a,callback:n,rotate:r,timeline:o,toScale:h,delay:l,mode:p,easing:u}=t,c=s.getBBox(),d=s.getBoundingClientRect();this.#t=e,this.#e=i/a,this.#i=i,this.path=s,this.#n=a,this.iterations=a,this.callback=n,this.delay=l,this.easing=u||(t=>t),this.#r="function"==typeof p?p:p&&Object.keys(this.#o).includes(p)?this.#o[p]:this.#o.clamp,this.scale=h?{x:d.width/c.width,y:d.height/c.height}:{x:1,y:1},this.#a=r||!1,this.#h=o,this.#l=o?Object.keys(o).map((t=>Number(t.slice(0,t.length-1)))).sort(((t,e)=>e-t)):null,this.#s=!1}animate(t){let e,i;if(t&&(e=t.iterNumber,i=t.singleFrame),!this.path||!this.#t||!this.#e)throw Error(`Runtime Error (FollowPath): ${this.path?this.#t?this.#e?"":"Duration":"Element":"Path"} not specified.`);e||(e=0),this.fps=void 0;let s=null;const a=this.path.getTotalLength();if((this.#n<=0||e>this.#n)&&this.callback)return this.fps=void 0,void this.callback();const n=t=>{const e=a*this.easing(t/a);return e>a||e<0?this.#r(e):e},r=e-Math.floor(e);let o=a/this.#e*(1/(this.fps||60)),h=a*r;this.iterations=e;const l=()=>{if(e=this.iterations,this.#s||e>=this.#n)return this.fps=void 0,void(!this.#s&&this.callback&&this.callback());if(h>=a)return void(e<=this.#n&&(this.delay?setTimeout((()=>requestAnimationFrame((()=>this.animate({iterNumber:e})))),this.delay):requestAnimationFrame((()=>this.animate({iterNumber:e})))));if(s){const t=Date.now()-s;this.fps=1e3/t,o=a/this.#e*t}if(this.#h&&this.#l)for(;e/this.#n*100>=this.#l[this.#l.length-1];){const t=this.#l.pop();t&&this.#h[`${t}%`]()}let t=this.path.getPointAtLength(n(h)),i=this.path.getPointAtLength(n(h+1)),r=0;if(i.x!==this.path.getPointAtLength(a).x||i.y!==this.path.getPointAtLength(a).y)r=180*Math.atan2(i.y-t.y,i.x-t.x)/Math.PI;else{let e=this.path.getPointAtLength(h-1);r=180*Math.atan2(t.y-e.y,t.x-e.x)/Math.PI}this.#t.style.transform=`translate(${t.x*this.scale.x}px, ${t.y*this.scale.y}px)${this.#a?` rotate(${r}deg)`:""}`,h+=o,e+=o/a,this.iterations=e,s=Date.now(),requestAnimationFrame(l)};s=Date.now(),requestAnimationFrame(l)}renderFrame(t){this.animate({singleFrame:!0,iterNumber:t?t/(this.#i/50*3):this.iterations})}play(){this.#s=!1,this.animate({iterNumber:this.iterations})}pause(){this.#s=!0}stop(){this.#s=!0,this.iterations=0}getProgress(){return this.iterations/this.#n*100}setProgress(t){this.iterations=t*this.#n/100}getCurrentIterationProgress(){return 100*(this.#n-Math.floor(this.#n))}setCurrentIterationProgress(t){this.iterations=Math.floor(this.iterations)+t/100}#p(t){if(!t||"object"!=typeof t||Array.isArray(t))return!1;const{duration:e,path:i,element:s,iterations:a,easing:n,mode:r,delay:o,toScale:h,rotate:l,callback:p,timeline:u}=t;if("number"!=typeof e||Number.isNaN(e)||!i||!s||"number"!=typeof a||Number.isNaN(a)||"function"!=typeof n||r&&"function"!=typeof r&&!Object.keys(this.#o).includes(r))return!1;if(void 0!==o&&("number"!=typeof o||Number.isNaN(o)))return!1;if(void 0!==h&&"boolean"!=typeof h)return!1;if(void 0!==l&&"boolean"!=typeof l)return!1;if(void 0!==p&&"function"!=typeof p)return!1;if(void 0!==u){if("object"!=typeof u||Array.isArray(u))return!1;for(const t in u){if(!/^(\d{1,3})%$/.test(t))return!1;if("function"!=typeof u[t])return!1}}return!0}}
2
+ window.FollowPath = FollowPath;
3
+ export default FollowPath;
@@ -1 +1 @@
1
- {"rootTitle":"Serve My MD Docs","description":"Docs for serve-my-md.","baseRoute":"/","defaultTheme":"dark","name":"Serve My MD","showNameWithLogo":true,"routes":[{"path":"/","content":"<h1>serve-my-md Docs</h1>\n<p>Welcome to the docs for <code>serve-my-md</code>.</p>\n<p>A tiny CLI to generate a static docs website from markdown files.</p>\n<ul>\n<li><a href=\"/why-serve-my-md\">Why serve-my-md?</a></li>\n<li><a href=\"/getting-started\">Getting Started</a></li>\n<li><a href=\"/cli-reference\">CLI Reference</a></li>\n<li><a href=\"/key-behaviors\">Key Behaviors</a></li>\n</ul>\n<h3>Guide</h3>\n<ul>\n<li><a href=\"/routing-and-sidebar-patterns\">Routing and Sidebar Patterns</a></li>\n<li><a href=\"/markdown-and-rendering\">Markdown and Rendering</a></li>\n<li><a href=\"/build-output-and-assets\">Build Output and Assets</a></li>\n</ul>\n<h3>Configuration</h3>\n<ul>\n<li><a href=\"/smm-config\">SMM Config</a></li>\n<li><a href=\"/smm-ignore\">SMM Ignore</a></li>\n</ul>\n<h3>Examples</h3>\n<ul>\n<li><a href=\"/structure-examples\">Structure Examples</a></li>\n<li><a href=\"/config-examples\">Config Examples</a></li>\n</ul>\n<h2>Future goals</h2>\n<ul>\n<li><strong>Search Indexing</strong> — structured search index for smarter results</li>\n<li><strong>Config validation</strong> — Zod-based schema validation of <code>smm.config.json</code> with JSON Schema export</li>\n<li><strong>Sitemap</strong> — automatic <code>sitemap.xml</code> generation</li>\n<li><strong>Per-page Open Graph</strong> — page-level og tags from frontmatter</li>\n<li><strong>Doctor command</strong> — health checks: config validation, route discovery, broken link detection, and more</li>\n<li><strong>Link validation</strong> — flag invalid internal links at build-time</li>\n<li><strong>Optional RSS</strong> — config-enableable RSS feed for blog/changelog content</li>\n<li><strong>SchemaStore upload</strong> — publish JSON Schema to SchemaStore once stable</li>\n</ul>\n"},{"path":"/getting-started","content":"<h1>Getting Started</h1>\n<h2>Install</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> i <span class=\"token parameter variable\">-g</span> serve-my-md\n</code></pre>\n<h2>Run</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\">serve-my-md <span class=\"token parameter variable\">--directory</span> <span class=\"token builtin class-name\">.</span>\n</code></pre>\n<p>The CLI scans markdown files in the target directory and generates a static website there. Every page is a standalone HTML file (SSG) — deploy to any static host or CDN.</p>\n<h2>What gets read automatically</h2>\n<ul>\n<li><code>smm.config.json</code> at docs root (if present)</li>\n<li><code>.smmignore</code> at docs root (if present)</li>\n<li>fallback to built-in defaults when these files are missing</li>\n</ul>\n<h2>Important <code>index.md</code> behavior</h2>\n<ul>\n<li><code>index.md</code> is the landing page for its directory.</li>\n<li><code>index</code> is never included in the pathname.</li>\n<li>Internally, an <code>index.md</code> entry is treated as <code>&quot;&quot;</code> (empty string) in route tree naming.</li>\n</ul>\n<p>Example:</p>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n index.md\n guides/\n index.md\n install.md\n</code></pre>\n<p>Routes:</p>\n<ul>\n<li><code>/</code></li>\n<li><code>/guides</code></li>\n<li><code>/guides/install</code></li>\n</ul>\n<h2>Future goals</h2>\n<ul>\n<li><strong>Search Indexing</strong> — structured search index for smarter results</li>\n<li><strong>Config validation</strong> — Zod-based schema validation of <code>smm.config.json</code> with JSON Schema export</li>\n<li><strong>Sitemap</strong> — automatic <code>sitemap.xml</code> generation</li>\n<li><strong>Per-page Open Graph</strong> — page-level og tags from frontmatter</li>\n<li><strong>Doctor command</strong> — health checks: config validation, route discovery, broken link detection, and more</li>\n<li><strong>Link validation</strong> — flag invalid internal links at build-time</li>\n<li><strong>Optional RSS</strong> — config-enableable RSS feed for blog/changelog content</li>\n<li><strong>SchemaStore upload</strong> — publish JSON Schema to SchemaStore once stable</li>\n</ul>\n"},{"path":"/cli-reference","content":"<h1>CLI Reference</h1>\n<h2>Main command</h2>\n<ul>\n<li><code>serve-my-md</code>: build a static docs website from markdown files.</li>\n</ul>\n<h2>Options</h2>\n<ul>\n<li><code>-d, --directory &lt;path&gt;</code>: docs root path (default <code>.</code>).</li>\n<li><code>-i, --interactive</code>: prompt for docs root.</li>\n</ul>\n<h2>Build output (SSG)</h2>\n<p>The CLI generates a fully static site:</p>\n<ul>\n<li>Each route gets its own <code>.html</code> file with pre-rendered markdown content in the HTML</li>\n<li>Assets (CSS, JS) are built via Vite and placed under <code>dist/assets/</code></li>\n<li>The final <code>dist/</code> directory is copied to your docs root — ready to deploy</li>\n</ul>\n<h2>Config and ignore loading</h2>\n<ul>\n<li>Loads config from <code>./smm.config.json</code> relative to target directory.</li>\n<li>Loads ignore rules from <code>./.smmignore</code> relative to target directory.</li>\n<li>If <code>publicPath</code> is set in config, copies that directory into app public assets before build.</li>\n</ul>\n<h2>Markdown pipeline</h2>\n<ul>\n<li>Uses markdown-it with task lists and footnotes plugins enabled.</li>\n<li>Prism.js syntax highlighting with auto-loading for unknown languages.</li>\n<li>Generates OG/meta/font tags in HTML from config values.</li>\n</ul>\n<h2>Runtime/navigation behaviors</h2>\n<ul>\n<li>Markdown links with non-HTTP hrefs are intercepted and navigated client-side.</li>\n<li>Intent-based link preloading for faster navigation.</li>\n<li>Keyboard shortcuts:\n<ul>\n<li>Search: <code>Ctrl+Shift+F</code></li>\n<li>Next page: <code>Alt+Enter</code></li>\n<li>Previous page: <code>Alt+Shift+Enter</code></li>\n</ul>\n</li>\n<li>Search returns matches in current page and across other pages.</li>\n</ul>\n<h2>Test-only option</h2>\n<ul>\n<li><code>--skip-build</code> exists only in vitest mode, not in normal CLI usage.</li>\n</ul>\n<h2>Future goals</h2>\n<ul>\n<li><strong>Search Indexing</strong> — structured search index for smarter results</li>\n<li><strong>Config validation</strong> — Zod-based schema validation of <code>smm.config.json</code> with JSON Schema export</li>\n<li><strong>Sitemap</strong> — automatic <code>sitemap.xml</code> generation</li>\n<li><strong>Per-page Open Graph</strong> — page-level og tags from frontmatter</li>\n<li><strong>Doctor command</strong> — health checks: config validation, route discovery, broken link detection, and more</li>\n<li><strong>Link validation</strong> — flag invalid internal links at build-time</li>\n<li><strong>Optional RSS</strong> — config-enableable RSS feed for blog/changelog content</li>\n<li><strong>SchemaStore upload</strong> — publish JSON Schema to SchemaStore once stable</li>\n</ul>\n"},{"path":"/key-behaviors","content":"<h1>Key Behaviors</h1>\n<h2>Internal links auto-prepend <code>baseRoute</code></h2>\n<p>When you set a <code>baseRoute</code> in <code>smm.config.json</code> (e.g. <code>/docs</code>), any internal markdown link (<code>[text](/some-page)</code>) automatically has that base prepended during navigation. You never need to manually prefix links with the base route — change it in one place and all links adapt.</p>\n<h2>Sorting and indexing</h2>\n<p>Pages, directories, and groupers are sorted automatically when <code>sortRoutes: true</code>:</p>\n<ol>\n<li><code>index.md</code> always comes first.</li>\n<li>Regular files and directories come next, sorted lexicographically.</li>\n<li>Groupers <code>(Name)</code> come last, after all regular items.</li>\n</ol>\n<p>Numeric prefixes on filenames (<code>1. intro.md</code>, <code>2. setup.md</code>) control ordering within each tier. The prefix is stripped from the emitted URL when <code>trimIndexFromPath: true</code>.</p>\n<p>Grouper indexes only affect order among other groupers — they never collide with file/directory indexes since groupers always sort after regular items.</p>\n<h2>SSG pre-rendering</h2>\n<p>Every page is a standalone <code>.html</code> file with pre-rendered markdown content baked into the DOM. Search engines see the full content immediately. After the page loads, the React SPA hydrates and takes over for seamless client-side navigation.</p>\n<h2>Groupers</h2>\n<p>Directories named <code>(Name)</code> act as groupers:</p>\n<ul>\n<li>Rendered as a labeled section in the sidebar (not collapsible).</li>\n<li>Skipped from URL pathnames — files inside sit at the grouper's parent URL level.</li>\n<li>Cannot contain <code>index.md</code>.</li>\n<li>Can be ordered with numeric prefixes: <code>(1. Guide)</code>, <code>(2. Reference)</code>.</li>\n</ul>\n<h2>Client-side link interception</h2>\n<p>Internal markdown links (<code>[text](/path)</code>) are intercepted by the SPA router — navigating them does not cause a full page reload. External links (<code>https://...</code>) open normally.</p>\n<h2>Intent-based preloading</h2>\n<p>When you hover over or touch a link, its content is preloaded in the background. Navigation feels instant because the data is ready before you click.</p>\n<h2>Auto-slug generation</h2>\n<p>Route path segments are automatically normalized:</p>\n<ul>\n<li>Lowercased</li>\n<li>Spaces and underscores become <code>-</code></li>\n<li>Punctuation (<code>.,;&quot;'\\\\:&lt;&gt;</code>?!`) is removed</li>\n<li>Grouper directory names like <code>(Group)</code> are excluded entirely</li>\n</ul>\n<p>No need to manually craft URL-safe filenames.</p>\n<h2><code>index.md</code> as landing page</h2>\n<ul>\n<li><code>index.md</code> represents the landing page for its directory.</li>\n<li>It is never included in the URL pathname — internally maps to <code>&quot;&quot;</code>.</li>\n<li>If a directory contains only <code>index.md</code> and no other files, it collapses to a leaf node (no collapsible).</li>\n</ul>\n<h2><code>publicPath</code> auto-copy and auto-exclude</h2>\n<p>If <code>publicPath</code> is set in config, that directory is:</p>\n<ul>\n<li>Copied into the web app's public assets before the Vite build.</li>\n<li>Automatically excluded from markdown scanning — no need to also add it to <code>.smmignore</code>.</li>\n</ul>\n<h2>Config merge with sensible defaults</h2>\n<p><code>smm.config.json</code> is merged over built-in defaults. You only need to specify what you want to override. Missing options fall back to the CLI's internal defaults — the config file is entirely optional.</p>\n<h2><code>.smmignore</code> glob patterns</h2>\n<p>Create <code>.smmignore</code> at your docs root to exclude paths during markdown traversal:</p>\n<ul>\n<li>Lines starting with <code>#</code> are comments.</li>\n<li>Empty lines are ignored.</li>\n<li>Prefix with <code>!</code> to un-ignore.</li>\n<li>Patterns are evaluated top-to-bottom, last match wins.</li>\n</ul>\n"},{"path":"/why-serve-my-md","content":"<h1>Why serve-my-md?</h1>\n<h2>Zero-friction static site</h2>\n<p>serve-my-md generates a <strong>completely static site</strong> — every page is a standalone HTML file with pre-rendered content. No server, no database, no build-time backend. Deploy anywhere: CDN, GitHub Pages, Netlify, Vercel, S3, or a simple static file server.</p>\n<h2>Blazing fast</h2>\n<p>Static HTML means instant first paint. After load, the React SPA takes over for seamless client-side navigation with intent-based preloading.</p>\n<h2>Rich markdown support</h2>\n<ul>\n<li>Full markdown-it pipeline with footnotes, task lists, and configurable options</li>\n<li>Prism.js syntax highlighting for dozens of languages</li>\n<li>Configurable markdown-it options via <code>smm.config.json</code></li>\n</ul>\n<h2>Custom ordering</h2>\n<p>Control your page order with numeric filename prefixes:</p>\n<pre class=\"language-text\"><code class=\"language-text\">1. intro.md\n2. setup.md\n3. advanced.md\n</code></pre>\n<p>Set <code>trimIndexFromPath: true</code> in config and the prefixes are stripped from URLs while ordering is preserved.</p>\n<h2>Minimal yet powerful config</h2>\n<p>A single <code>smm.config.json</code> at your docs root is all you need. Override titles, theme, fonts, Open Graph tags, and more — or use the sensible defaults and get going immediately.</p>\n<h2>SEO built-in</h2>\n<p>Every page is a full HTML document with:</p>\n<ul>\n<li>Unique <code>&lt;title&gt;</code> and <code>&lt;meta description&gt;</code></li>\n<li>Open Graph tags for social previews</li>\n<li>Pre-rendered content in the HTML — search engines see everything</li>\n<li>Semantic HTML structure</li>\n</ul>\n<h2>Great user experience</h2>\n<ul>\n<li><strong>Site-wide search</strong> — instant full-text search with keyboard shortcut (Ctrl+Shift+F)</li>\n<li><strong>Accessibility</strong> — keyboard navigation, ARIA labels, semantic landmarks</li>\n<li><strong>Light/dark themes</strong> — automatic or user-toggleable</li>\n<li><strong>Responsive</strong> — works on desktop and mobile</li>\n<li><strong>Breadcrumbs</strong> — clear navigation context</li>\n<li><strong>Keyboard shortcuts</strong> — quick navigation between pages</li>\n</ul>\n"},{"path":"/routing-and-sidebar-patterns","content":"<h1>Routing and Sidebar Patterns</h1>\n<h2><code>index.md</code> is landing page</h2>\n<ul>\n<li><code>index.md</code> represents the landing page for its directory.</li>\n<li><code>index</code> is not part of URL pathnames.</li>\n<li>In nested name handling, <code>index.md</code> maps to <code>&quot;&quot;</code> (empty string).</li>\n<li>If a directory contains only an <code>index.md</code> and no other files, the directory collapses to a leaf node (no collapsible in sidebar).</li>\n</ul>\n<h2>Grouping directories with parentheses (groupers)</h2>\n<p>Directory names wrapped in <code>()</code> act as <strong>groupers</strong>:</p>\n<ul>\n<li>shown as a labeled section in the sidebar (not collapsible)</li>\n<li>skipped from route pathname segments</li>\n<li>should not contain <code>index.md</code></li>\n<li>can be ordered with numeric prefixes: <code>(2. Category)</code></li>\n</ul>\n<p>Groupers are useful for visually grouping related pages without adding extra URL segments.</p>\n<p>Example:</p>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n (Guides)/\n setup.md\n usage.md\n</code></pre>\n<p>Routes:</p>\n<ul>\n<li><code>/setup</code></li>\n<li><code>/usage</code></li>\n</ul>\n<p>Sidebar:</p>\n<pre class=\"language-text\"><code class=\"language-text\">Guides ← grouper label (not a link)\n Setup\n Usage\n</code></pre>\n<h2>Grouper ordering and index collision rules</h2>\n<p>Numeric prefixes on groupers only control ordering among other groupers — they never collide with indexes on regular files or directories. This is because the sort algorithm always places groupers after every regular file and directory at the same level, regardless of what prefix you give them.</p>\n<p>Similarly, numeric prefixes on regular files and directories only control ordering among their own kind.</p>\n<p>In short:</p>\n<ul>\n<li><code>index.md</code> is always sorted first.</li>\n<li>Regular files and directories are sorted next (by label).</li>\n<li>Groupers are sorted last (by label), after all regular files and directories.</li>\n<li>Within each group (regulars and groupers), ordering is controlled by numeric prefixes and <code>localeCompare</code>.</li>\n</ul>\n<p>Example:</p>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n index.md\n 1. Getting Started.md\n 2. CLI Reference.md\n (1. Guide)/\n routing.md\n (2. Configuration)/\n smm-config.md\n (3. Examples)/\n structure.md\n</code></pre>\n<p>Sidebar order:</p>\n<pre class=\"language-text\"><code class=\"language-text\">Home ← index.md first\nGetting Started\nCLI Reference\nGuide ← grouper label (after all regular files)\n Routing\nConfiguration ← next grouper\n SMM Config\nExamples ← last grouper\n Structure\n</code></pre>\n<h2>Regular directories (without parentheses)</h2>\n<ul>\n<li>appear as collapsible sidebar containers</li>\n<li>can have <code>index.md</code> and be clickable landing pages</li>\n<li>are included in pathname segments of child files</li>\n</ul>\n<p>Example:</p>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n guides/\n index.md\n setup.md\n</code></pre>\n<p>Routes:</p>\n<ul>\n<li><code>/guides</code></li>\n<li><code>/guides/setup</code></li>\n</ul>\n<h2>Ordered filenames with index prefixes</h2>\n<p>If you use names like:</p>\n<ul>\n<li><code>1. blahblah.md</code></li>\n<li><code>2. blhalbhablah.md</code></li>\n</ul>\n<p>and set <code>trimIndexFromPath: true</code> in config, names can be ordered while emitted as clean paths.</p>\n<p>The index prefix in filenames does not conflict with grouper indexes — they operate in separate sort tiers.</p>\n<h2>Directories vs groupers summary</h2>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>Sidebar rendering</th>\n<th>In URL path</th>\n<th>Can have <code>index.md</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Regular directory</td>\n<td>Collapsible</td>\n<td>Yes</td>\n<td>Yes</td>\n</tr>\n<tr>\n<td>Grouper <code>(Name)</code></td>\n<td>Labeled section</td>\n<td>No</td>\n<td>No</td>\n</tr>\n</tbody>\n</table>\n<h2>Slug generation rules</h2>\n<p>Route path segments are normalized by the CLI:</p>\n<ul>\n<li>converted to lowercase</li>\n<li>spaces/underscores become <code>-</code></li>\n<li>punctuation like <code>.,;&quot;'\\\\:&lt;&gt;</code>?!` is removed</li>\n<li>grouper directory names like <code>(Group)</code> are excluded from final pathname</li>\n</ul>\n"},{"path":"/markdown-and-rendering","content":"<h1>Markdown and Rendering</h1>\n<p>The CLI uses <code>markdown-it</code> and includes:</p>\n<ul>\n<li>footnotes support</li>\n<li>task lists support</li>\n</ul>\n<p>Code highlighting is enabled through Prism with language classes like <code>language-js</code>.</p>\n<p>Useful notes:</p>\n<ul>\n<li><code>linkify</code> is enabled by default in config options.</li>\n<li><code>fuzzyEmail</code> linkification is disabled.</li>\n<li>You can override markdown-it behavior via <code>markdownItOptions</code> in <code>smm.config.json</code>.</li>\n</ul>\n<p>Additional rendering behavior from the web app:</p>\n<ul>\n<li>Heading elements are assigned generated ids for anchor navigation.</li>\n<li>Other extracted elements can receive internal labels for in-page search scroll targets.</li>\n</ul>\n"},{"path":"/build-output-and-assets","content":"<h1>Build Output and Assets</h1>\n<h2>Static site generation (SSG)</h2>\n<p>The CLI generates a fully static site. Every route gets its own <code>.html</code> file with pre-rendered markdown content baked into the DOM. The site works without JavaScript — search engines see all content, and the page is immediately readable.</p>\n<p>Once the JS bundle loads, the React SPA hydrates and takes over navigation for seamless client-side transitions.</p>\n<h2>Build flow</h2>\n<ol>\n<li>Markdown files are scanned and parsed into route/content JSON.</li>\n<li>Generated route data is written under <code>web/src/.generated/</code>.</li>\n<li>Vite builds the web app (CSS + JS bundles).</li>\n<li>Static HTML pages are generated for each route via <code>buildDistRoutesFromRouteTree</code>.</li>\n<li>The built <code>dist/</code> directory is copied to the target docs directory.</li>\n</ol>\n<h2>Generated files</h2>\n<table>\n<thead>\n<tr>\n<th>File</th>\n<th>Purpose</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>.generated/output.json</code></td>\n<td>Route metadata and parsed markdown content for all pages</td>\n</tr>\n<tr>\n<td><code>.generated/paths.json</code></td>\n<td>Nested route tree used to render sidebar groups and collapsibles</td>\n</tr>\n</tbody>\n</table>\n<h2>Public assets</h2>\n<p>If <code>publicPath</code> is configured in <code>smm.config.json</code> and the directory exists, its contents are copied into the web app's <code>public/</code> directory before the Vite build. This is useful for images, fonts, or other static files.</p>\n<h2>Output structure</h2>\n<pre class=\"language-text\"><code class=\"language-text\">dist/\n index.html ← home page (pre-rendered)\n getting-started.html ← each route gets its own .html\n cli-reference.html\n smm-config/\n index.html\n defaults-and-options.html\n trim-and-ordering.html\n assets/\n index-abc123.css ← Vite-built CSS\n index-abc123.js ← Vite-built JS (hydration)\n</code></pre>\n<h2>Defaults</h2>\n<p>If no <code>smm.config.json</code> or <code>.smmignore</code> exists, built-in defaults are used automatically.</p>\n"},{"path":"/smm-config","content":"<h1>smm.config.json</h1>\n<p>Place <code>smm.config.json</code> at docs root.</p>\n<p>Defaults are merged with your overrides.</p>\n<p>Default values come from the CLI's built-in config at <code>cli/src/smm.config.json</code>.</p>\n<p>This is the complete schema:</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">SmmConfig</span> <span class=\"token punctuation\">{</span>\n rootTitle<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n description<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n markdownItOptions<span class=\"token operator\">?</span><span class=\"token operator\">:</span> Record<span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">any</span><span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n baseRoute<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n outDir<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n publicPath<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n defaultTheme<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n favicon<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n logo<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n name<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n showNameWithLogo<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span>\n og<span class=\"token operator\">?</span><span class=\"token operator\">:</span> OpenGraph<span class=\"token punctuation\">;</span>\n sortRoutes<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span>\n trimIndexFromPath<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span><span class=\"token punctuation\">;</span>\n version<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n fonts<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n title<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n url<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n body<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n url<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n mono<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n name<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n url<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>Read next:</p>\n<ul>\n<li><a href=\"/smm-config/defaults-and-options\">Defaults and Options</a></li>\n<li><a href=\"/smm-config/trim-and-ordering\">Trim and Ordering</a></li>\n<li><a href=\"/smm-config/opengraph\">OpenGraph</a></li>\n</ul>\n"},{"path":"/smm-config/defaults-and-options","content":"<h1>Defaults and Options</h1>\n<p><code>smm.config.json</code> supports these useful options:</p>\n<ul>\n<li><code>rootTitle</code>: document title.</li>\n<li><code>description</code>: default description.</li>\n<li><code>markdownItOptions</code>: markdown-it constructor options.</li>\n<li><code>baseRoute</code>: route base prefix.</li>\n<li><code>outDir</code>: output directory name for built artefacts (default <code>&quot;dist&quot;</code>).</li>\n<li><code>publicPath</code>: directory to copy as public assets.</li>\n<li><code>defaultTheme</code>: initial theme.</li>\n<li><code>favicon</code>: favicon URL/path.</li>\n<li><code>logo</code>: logo URL/path.</li>\n<li><code>name</code>: brand/app name.</li>\n<li><code>showNameWithLogo</code>: show name near logo.</li>\n<li><code>og</code>: Open Graph tags object.</li>\n<li><code>sortRoutes</code>: sort routes tree.</li>\n<li><code>trimIndexFromPath</code>: trims filename numeric prefixes from route names.</li>\n<li><code>version</code>: docs/site version string.</li>\n<li><code>fonts</code>: title/body/mono font names and optional stylesheet URLs.</li>\n</ul>\n<h2>Default values used when user config is missing</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"rootTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Serve My MD\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"A simple markdown to static site builder.\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"baseRoute\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"defaultTheme\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"dark\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"markdownItOptions\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"html\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"xhtmlOut\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"breaks\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"langPrefix\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"language-\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"linkify\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"typographer\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"outDir\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"dist\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"favicon\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"logo\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Serve My MD\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"showNameWithLogo\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"sortRoutes\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"trimIndexFromPath\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>Example:</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"rootTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"My Docs\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Team documentation\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"baseRoute\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"defaultTheme\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"dark\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"sortRoutes\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"trimIndexFromPath\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"publicPath\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"public\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"outDir\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-site\"</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"},{"path":"/smm-config/trim-and-ordering","content":"<h1>Trim and Ordering</h1>\n<p>Use numbered file names to force custom ordering:</p>\n<ul>\n<li><code>1. intro.md</code></li>\n<li><code>2. install.md</code></li>\n</ul>\n<p>When <code>trimIndexFromPath</code> is <code>true</code>, the numeric prefixes are removed from emitted route names while order stays controlled by your naming.</p>\n<p>Input files:</p>\n<pre class=\"language-text\"><code class=\"language-text\">1. blahblah.md\n2. blhalbhablah.md\n</code></pre>\n<p>Emitted routes:</p>\n<ul>\n<li><code>/blahblah</code></li>\n<li><code>/blhalbhablah</code></li>\n</ul>\n<p>If <code>trimIndexFromPath</code> is <code>false</code>, or not present, then the emitted routes would be:</p>\n<ul>\n<li><code>/1-blahblah</code></li>\n<li><code>/2-blhalbhablah</code></li>\n</ul>\n<p>If route sorting is enabled, routes are sorted lexicographically, with grouped <code>(Name)</code> directories ordered after regular names at the same level. Indexing can also be used for Grouper directories(directories whose names are enclosed within parenthesis) to determine their order.</p>\n"},{"path":"/smm-config/opengraph","content":"<h1>OpenGraph</h1>\n<p>The <code>og</code> field in <code>smm.config.json</code> controls Open Graph meta tags in the generated HTML. These tags control how your site appears when shared on social platforms (Twitter, Discord, Telegram, etc.) and in search results.</p>\n<h2>Schema</h2>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">interface</span> <span class=\"token class-name\">OpenGraph</span> <span class=\"token punctuation\">{</span>\n title<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n type<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n url<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n description<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n site_name<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n determiner<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token string\">\"a\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"an\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"the\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"auto\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">;</span>\n locale<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"locale:alternate\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n\n images<span class=\"token operator\">?</span><span class=\"token operator\">:</span> OpenGraphImage<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n videos<span class=\"token operator\">?</span><span class=\"token operator\">:</span> OpenGraphVideo<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n audios<span class=\"token operator\">?</span><span class=\"token operator\">:</span> OpenGraphAudio<span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">OpenGraphImage</span> <span class=\"token punctuation\">{</span>\n image<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"image:secure_url\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"image:type\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"image:width\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"image:height\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"image:alt\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">OpenGraphVideo</span> <span class=\"token punctuation\">{</span>\n video<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"video:secure_url\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"video:type\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"video:width\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"video:height\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">OpenGraphAudio</span> <span class=\"token punctuation\">{</span>\n audio<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"audio:secure_url\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n <span class=\"token string\">\"audio:type\"</span><span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>Basic usage</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"og\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"My Docs\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Documentation for my project.\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"website\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"site_name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"My Docs\"</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>This generates:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">property</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>og:title<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>My Docs<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">property</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>og:description<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Documentation for my project.<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">property</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>og:type<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>website<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>meta</span> <span class=\"token attr-name\">property</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>og:site_name<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">content</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>My Docs<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n</code></pre>\n<h2>With images</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"og\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"My Docs\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Documentation for my project.\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"images\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"image\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://example.com/og-image.png\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"image:width\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1200</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"image:height\"</span><span class=\"token operator\">:</span> <span class=\"token number\">630</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"image:alt\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"My Docs preview\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>With videos and audio</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"og\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Video Docs\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"videos\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"video\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://example.com/trailer.mp4\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"video:type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"video/mp4\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"audios\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"audio\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://example.com/song.mp3\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"audio:type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"audio/mpeg\"</span>\n <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>Locale</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"og\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"locale\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"en_US\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"locale:alternate\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"fr_FR\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"es_ES\"</span><span class=\"token punctuation\">]</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>How it works</h2>\n<p>The CLI reads the <code>og</code> field from <code>smm.config.json</code> and renders each entry as <code>&lt;meta property=&quot;og:key&quot; content=&quot;value&quot;&gt;</code> tags in the HTML <code>&lt;head&gt;</code>. Arrays (like <code>locale:alternate</code>) produce one meta tag per value. Image, video, and audio objects render their properties as flat <code>og:*</code> meta tags.</p>\n"},{"path":"/smm-ignore","content":"<h1>.smmignore</h1>\n<p>Create <code>.smmignore</code> at docs root to skip paths during markdown traversal.</p>\n<p>Rules are glob-like, processed top-to-bottom.</p>\n<ul>\n<li>Lines starting with <code>#</code> are comments.</li>\n<li>Empty lines are ignored.</li>\n<li>Prefix with <code>!</code> to un-ignore.</li>\n</ul>\n<p>Example:</p>\n<pre class=\"language-text\"><code class=\"language-text\">drafts/**\nprivate/**\n!private/keep.md\n</code></pre>\n<p>Paths are evaluated against traversal targets in the docs tree; ignored paths are skipped during route/content generation.</p>\n"},{"path":"/structure-examples","content":"<h1>Structure Examples</h1>\n<h2>Group directory (not in pathname)</h2>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n (Category)/\n tos.md\n</code></pre>\n<p>Route: <code>/tos</code></p>\n<h2>Normal directory with landing page</h2>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n features/\n index.md\n tea.md\n</code></pre>\n<p>Routes:</p>\n<ul>\n<li><code>/features</code></li>\n<li><code>/features/tea</code></li>\n</ul>\n<h2>Root landing page</h2>\n<pre class=\"language-text\"><code class=\"language-text\">docs/\n index.md\n about.md\n</code></pre>\n<p>Routes:</p>\n<ul>\n<li><code>/</code></li>\n<li><code>/about</code></li>\n</ul>\n"},{"path":"/config-examples","content":"<h1>Config Examples</h1>\n<h2>Basic customization</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"rootTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Company Docs\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Internal knowledge base\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"defaultTheme\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"dark\"</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"sortRoutes\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>Ordered file naming + trimmed paths</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"sortRoutes\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token property\">\"trimIndexFromPath\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h2>Public assets</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n <span class=\"token property\">\"publicPath\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"public\"</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<p>This copies <code>public</code> from docs root into build public assets, also ignores it for routes building.</p>\n"}],"outDir":"docs","fonts":{"title":"Exo","body":"Commissioner","mono":"Fira Code"}}
1
+ {"rootTitle":"FollowPath Docs","description":"Documentation for the FollowPath library — animate HTML elements along SVG paths.","baseRoute":"/","defaultTheme":"dark","name":"Serve My MD","showNameWithLogo":true,"routes":[{"path":"/","content":"<h1>FollowPath</h1>\n<p>A <strong>VanillaJS</strong> library to animate HTML elements along an SVG path with custom durations, iterations, easing, and lifecycle callbacks.</p>\n<h2>Features</h2>\n<ul>\n<li>Animate elements along any SVG <code>&lt;path&gt;</code> or <code>&lt;polyline&gt;</code></li>\n<li>Custom duration and rational iteration count (including <code>Infinity</code>)</li>\n<li>Configurable delay between iterations</li>\n<li>Path scale compensation (<code>toScale</code>)</li>\n<li>Rotation along the path tangent (<code>rotate</code>)</li>\n<li>Easing functions for custom pacing</li>\n<li>Timeline callbacks at arbitrary percentage points</li>\n<li>Animation modes: <code>clamp</code>, <code>loop</code>, <code>pingpong</code>, or custom</li>\n<li>Play / Pause / Stop controls</li>\n<li>Real-time FPS and iteration tracking</li>\n<li>Frame-accurate rendering with <code>renderFrame</code></li>\n<li>Progress getters and setters</li>\n</ul>\n<p>Check out the <a href=\"/demo\">live demo</a>.</p>\n<h2>Installation</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> i follow-path\n</code></pre>\n<p>Or clone from <a href=\"https://github.com/AshishAntil07/FollowPath.git\">GitHub</a>.</p>\n<hr />\n<ul>\n<li><a href=\"/getting-started\">Getting Started</a></li>\n<li><a href=\"/usage\">Usage</a></li>\n<li><a href=\"/constructor-config\">Constructor Config</a></li>\n<li><a href=\"/methods\">Methods</a></li>\n<li><a href=\"/properties\">Properties</a></li>\n<li><a href=\"/modes\">Modes</a></li>\n<li><a href=\"/basic-animation\">Basic Animation</a></li>\n<li><a href=\"/timeline-and-easing\">Timeline and Easing</a></li>\n</ul>\n"},{"path":"/getting-started","content":"<h1>Getting Started</h1>\n<h2>Install</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> i follow-path\n</code></pre>\n<h2>Import</h2>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> FollowPath <span class=\"token keyword\">from</span> <span class=\"token string\">'follow-path'</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<p>Or include the built file directly:</p>\n<pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>node_modules/follow-path/dist/index.js<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span>\n</code></pre>\n<h2>Minimal setup</h2>\n<pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>svg</span> <span class=\"token attr-name\">height</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>700<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">width</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>1000<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>polyline</span> <span class=\"token attr-name\">points</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>0,350 200,100 400,400 600,50 1000,350<span class=\"token punctuation\">\"</span></span>\n <span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>fill:transparent;stroke:black;stroke-width:5px<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>svg</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>element<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n</code></pre>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token literal-property property\">element</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.element'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">duration</span><span class=\"token operator\">:</span> <span class=\"token number\">3000</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'polyline'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">iterations</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"path":"/usage","content":"<h1>Usage</h1>\n<p>Create a <code>FollowPath</code> instance with your element, path, and timing options, then call <code>.animate()</code>.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token literal-property property\">element</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.element'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">duration</span><span class=\"token operator\">:</span> <span class=\"token number\">3000</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'polyline'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">iterations</span><span class=\"token operator\">:</span> <span class=\"token number\">2.5</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">rotate</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">delay</span><span class=\"token operator\">:</span> <span class=\"token number\">500</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token function\">easing</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">t</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">return</span> t <span class=\"token operator\">&lt;</span> <span class=\"token number\">0.5</span>\n <span class=\"token operator\">?</span> <span class=\"token number\">4</span> <span class=\"token operator\">*</span> t <span class=\"token operator\">*</span> t <span class=\"token operator\">*</span> t\n <span class=\"token operator\">:</span> <span class=\"token number\">1</span> <span class=\"token operator\">-</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span><span class=\"token number\">2</span> <span class=\"token operator\">*</span> t <span class=\"token operator\">+</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'done'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token literal-property property\">timeline</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token string\">'0%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'started'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'25%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'25%'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'50%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'halfway'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'75%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'75%'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<h2>Controls</h2>\n<pre class=\"language-js\"><code class=\"language-js\">fp<span class=\"token punctuation\">.</span><span class=\"token function\">pause</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// pause mid-animation</span>\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">play</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// resume</span>\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">stop</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// stop and reset progress</span>\n</code></pre>\n<h2>Progress tracking</h2>\n<pre class=\"language-js\"><code class=\"language-js\">console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fps: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fp<span class=\"token punctuation\">.</span>fps<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">progress: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fp<span class=\"token punctuation\">.</span><span class=\"token function\">getProgress</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">%</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"path":"/constructor-config","content":"<h1>Constructor Config</h1>\n<p>The <code>FollowPath</code> constructor accepts a single configuration object with the following properties:</p>\n<h2>Required</h2>\n<h3><code>element</code></h3>\n<p>Type: <code>HTMLElement</code></p>\n<p>The DOM element to animate along the path.</p>\n<h3><code>duration</code></h3>\n<p>Type: <code>number</code> (ms)</p>\n<p>Total duration of the animation across all iterations.</p>\n<h3><code>path</code></h3>\n<p>Type: <code>SVGPathElement | SVGPolylineElement</code></p>\n<p>The SVG path or polyline element defining the trajectory.</p>\n<h3><code>iterations</code></h3>\n<p>Type: <code>number</code></p>\n<p>Number of times the element traverses the path. Can be a floating point for partial traversal, or <code>Infinity</code> for infinite looping (callback will never fire).</p>\n<h2>Optional</h2>\n<h3><code>delay</code></h3>\n<p>Type: <code>number</code> (ms)</p>\n<p>Delay between each iteration before the next one starts.</p>\n<h3><code>toScale</code></h3>\n<p>Type: <code>boolean</code></p>\n<p>When <code>true</code>, compensates for differences between the SVG's internal coordinate system and the rendered bounding box, keeping the animation aligned with the visual path.</p>\n<h3><code>rotate</code></h3>\n<p>Type: <code>boolean</code></p>\n<p>When <code>true</code>, the element is automatically rotated to follow the path's tangent direction.</p>\n<h3><code>callback</code></h3>\n<p>Type: <code>() =&gt; void</code></p>\n<p>Function called once after all iterations complete. Not called if animation is stopped via <code>.stop()</code> or interrupted.</p>\n<h3><code>easing</code></h3>\n<p>Type: <code>(t: number) =&gt; number</code></p>\n<p>A function that maps progress <code>t</code> (0 to 1) to a eased value. Defaults to linear <code>(t) =&gt; t</code>.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">easing</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">t</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">return</span> t <span class=\"token operator\">*</span> t<span class=\"token punctuation\">;</span> <span class=\"token comment\">// ease-in</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n<h3><code>timeline</code></h3>\n<p>Type: <code>{ [key: </code>${number}%<code>]: () =&gt; void }</code></p>\n<p>An object whose keys are percentage strings (e.g. <code>'50%'</code>) and values are callbacks fired when the animation reaches that point.</p>\n<h3><code>mode</code></h3>\n<p>Type: <code>'pingpong' | 'loop' | 'clamp' | ((t: number) =&gt; number)</code></p>\n<p>Defines behavior when the animation exceeds the path length:</p>\n<ul>\n<li><code>'clamp'</code> — holds at the end position (default)</li>\n<li><code>'loop'</code> — wraps around to the start</li>\n<li><code>'pingpong'</code> — reverses direction each iteration</li>\n<li>Custom function — maps exceeded progress values manually</li>\n</ul>\n"},{"path":"/methods","content":"<h1>Methods</h1>\n<h2><code>animate(options?)</code></h2>\n<p>Starts the animation. Can be called with optional parameters:</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">animate</span><span class=\"token punctuation\">(</span>options<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> iterNumber<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span> singleFrame<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">boolean</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n</code></pre>\n<ul>\n<li><code>iterNumber</code> — start from a specific iteration (float for partial position, default <code>0</code>)</li>\n<li><code>singleFrame</code> — render only one frame instead of the full animation</li>\n</ul>\n<h2><code>play()</code></h2>\n<p>Resumes a paused animation from its current position.</p>\n<h2><code>pause()</code></h2>\n<p>Pauses the animation at the current frame. Call <code>.play()</code> to resume.</p>\n<h2><code>stop()</code></h2>\n<p>Stops the animation and resets progress to <code>0</code>. The <code>callback</code> is <strong>not</strong> called when stopped via interruption.</p>\n<h2><code>renderFrame(frameNumber?)</code></h2>\n<p>Renders a specific frame. If no argument is given, renders the next frame based on current progress.</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">renderFrame</span><span class=\"token punctuation\">(</span>frameNumber<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span>\n</code></pre>\n<h2><code>getProgress()</code></h2>\n<p>Returns the total progress as a percentage of all iterations.</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">getProgress</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span>\n</code></pre>\n<h2><code>setProgress(percentage)</code></h2>\n<p>Sets the total progress to a specific percentage.</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">setProgress</span><span class=\"token punctuation\">(</span>percentage<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span>\n</code></pre>\n<h2><code>getCurrentIterationProgress()</code></h2>\n<p>Returns the progress of the current iteration only (a whole iteration = 100%).</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">getCurrentIterationProgress</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">number</span>\n</code></pre>\n<h2><code>setCurrentIterationProgress(percentage)</code></h2>\n<p>Sets the progress of the current iteration without affecting the iteration count.</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">setCurrentIterationProgress</span><span class=\"token punctuation\">(</span>percentage<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token keyword\">void</span>\n</code></pre>\n"},{"path":"/properties","content":"<h1>Properties</h1>\n<h2>Public properties</h2>\n<table>\n<thead>\n<tr>\n<th>Property</th>\n<th>Type</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>path</code></td>\n<td><code>SVGPathElement | SVGPolylineElement</code></td>\n<td>The SVG path being animated</td>\n</tr>\n<tr>\n<td><code>iterations</code></td>\n<td><code>number</code></td>\n<td>Current iteration count (readable / writable)</td>\n</tr>\n<tr>\n<td><code>callback</code></td>\n<td><code>(() =&gt; void) | undefined</code></td>\n<td>Completion callback</td>\n</tr>\n<tr>\n<td><code>delay</code></td>\n<td><code>number | undefined</code></td>\n<td>Delay between iterations (ms)</td>\n</tr>\n<tr>\n<td><code>easing</code></td>\n<td><code>(t: number) =&gt; number</code></td>\n<td>Current easing function</td>\n</tr>\n<tr>\n<td><code>scale</code></td>\n<td><code>{ x: number; y: number }</code></td>\n<td>Active scale compensation factors</td>\n</tr>\n<tr>\n<td><code>fps</code></td>\n<td><code>number | undefined</code></td>\n<td>Measured frames per second (updates each frame)</td>\n</tr>\n</tbody>\n</table>\n"},{"path":"/modes","content":"<h1>Modes</h1>\n<p>The <code>mode</code> option controls what happens when the animation reaches or exceeds the end of the path.</p>\n<h2><code>'clamp'</code> (default)</h2>\n<p>Stops at the end of the path and holds the final position.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ...</span>\n <span class=\"token literal-property property\">mode</span><span class=\"token operator\">:</span> <span class=\"token string\">'clamp'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<h2><code>'loop'</code></h2>\n<p>Wraps around to the start each time the end is reached, creating a seamless repeat.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ...</span>\n <span class=\"token literal-property property\">mode</span><span class=\"token operator\">:</span> <span class=\"token string\">'loop'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<h2><code>'pingpong'</code></h2>\n<p>Reverses direction on each iteration, creating a back-and-forth effect.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ...</span>\n <span class=\"token literal-property property\">mode</span><span class=\"token operator\">:</span> <span class=\"token string\">'pingpong'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n<h2>Custom function</h2>\n<p>Provide your own function to handle exceeded progress values manually. Receives the raw exceeded value and must return a clamped/remapped value.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// ...</span>\n <span class=\"token function\">mode</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">t</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token keyword\">return</span> t <span class=\"token operator\">></span> <span class=\"token number\">1</span> <span class=\"token operator\">?</span> <span class=\"token number\">1</span> <span class=\"token operator\">-</span> <span class=\"token punctuation\">(</span>t <span class=\"token operator\">%</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> t<span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"path":"/basic-animation","content":"<h1>Basic Animation</h1>\n<p>Animate a <code>&lt;div&gt;</code> along an SVG <code>&lt;polyline&gt;</code> with rotation and play/pause/stop controls.</p>\n<pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>svg</span> <span class=\"token attr-name\">xmlns</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>http://www.w3.org/2000/svg<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">height</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>700<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">width</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>1000<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>polyline</span>\n <span class=\"token attr-name\">points</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>198,264 200,259 202,256 300,200 500,300 700,150 893,250<span class=\"token punctuation\">\"</span></span>\n <span class=\"token attr-name\">style</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>fill: transparent; stroke: black; stroke-width: 5px;<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>svg</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>div</span> <span class=\"token attr-name\">class</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>element<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>div</span><span class=\"token punctuation\">></span></span>\n</code></pre>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token literal-property property\">element</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.element'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">duration</span><span class=\"token operator\">:</span> <span class=\"token number\">3000</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'polyline'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">iterations</span><span class=\"token operator\">:</span> <span class=\"token number\">2.5</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">rotate</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'done'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Pause after 1 second</span>\n<span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> fp<span class=\"token punctuation\">.</span><span class=\"token function\">pause</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Resume after another second</span>\n<span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> fp<span class=\"token punctuation\">.</span><span class=\"token function\">play</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Stop after 6 seconds</span>\n<span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">fps: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fp<span class=\"token punctuation\">.</span>fps<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">, iterations: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>fp<span class=\"token punctuation\">.</span>iterations<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n fp<span class=\"token punctuation\">.</span><span class=\"token function\">stop</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">6000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"path":"/timeline-and-easing","content":"<h1>Timeline and Easing</h1>\n<p>Use timeline callbacks to trigger actions at specific percentages, and a custom easing function to control animation pacing.</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> fp <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">FollowPath</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n <span class=\"token literal-property property\">element</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.element'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">duration</span><span class=\"token operator\">:</span> <span class=\"token number\">4000</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">querySelector</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">iterations</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">rotate</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n <span class=\"token literal-property property\">delay</span><span class=\"token operator\">:</span> <span class=\"token number\">300</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token function\">easing</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">t</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n <span class=\"token comment\">// easeOutElastic</span>\n <span class=\"token keyword\">const</span> c4 <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token number\">2</span> <span class=\"token operator\">*</span> Math<span class=\"token punctuation\">.</span><span class=\"token constant\">PI</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span>\n <span class=\"token keyword\">return</span> t <span class=\"token operator\">===</span> <span class=\"token number\">0</span>\n <span class=\"token operator\">?</span> <span class=\"token number\">0</span>\n <span class=\"token operator\">:</span> t <span class=\"token operator\">===</span> <span class=\"token number\">1</span>\n <span class=\"token operator\">?</span> <span class=\"token number\">1</span>\n <span class=\"token operator\">:</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">-</span><span class=\"token number\">10</span> <span class=\"token operator\">*</span> t<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">sin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>t <span class=\"token operator\">*</span> <span class=\"token number\">10</span> <span class=\"token operator\">-</span> <span class=\"token number\">0.75</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> c4<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token literal-property property\">timeline</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n <span class=\"token string\">'0%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'animation started'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'33%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'first third done'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'66%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'two thirds done'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n <span class=\"token string\">'100%'</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'iteration complete'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'all iterations finished'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nfp<span class=\"token punctuation\">.</span><span class=\"token function\">animate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}],"outDir":"docs","fonts":{"title":"serif","body":"sans-serif","mono":"monospace"}}
@@ -1 +1 @@
1
- [{"label":"","children":null,"pathSegment":""},{"label":"Getting Started","children":null,"pathSegment":"getting-started"},{"label":"CLI Reference","children":null,"pathSegment":"cli-reference"},{"label":"Key Behaviors","children":null,"pathSegment":"key-behaviors"},{"label":"Why serve-my-md","children":null,"pathSegment":"why-serve-my-md"},{"label":"Guide","children":[{"label":"Routing and Sidebar Patterns","children":null,"pathSegment":"routing-and-sidebar-patterns"},{"label":"Markdown and Rendering","children":null,"pathSegment":"markdown-and-rendering"},{"label":"Build Output and Assets","children":null,"pathSegment":"build-output-and-assets"}],"pathSegment":"","isGrouper":true},{"label":"Configuration","children":[{"label":"SMM Config","children":[{"label":"","children":null,"pathSegment":""},{"label":"Defaults and Options","children":null,"pathSegment":"defaults-and-options"},{"label":"Trim and Ordering","children":null,"pathSegment":"trim-and-ordering"},{"label":"OpenGraph","children":null,"pathSegment":"opengraph"}],"pathSegment":"smm-config","isGrouper":false},{"label":"SMM Ignore","children":null,"pathSegment":"smm-ignore","isGrouper":false}],"pathSegment":"","isGrouper":true},{"label":"Examples","children":[{"label":"Structure Examples","children":null,"pathSegment":"structure-examples"},{"label":"Config Examples","children":null,"pathSegment":"config-examples"}],"pathSegment":"","isGrouper":true}]
1
+ [{"label":"","children":null,"pathSegment":""},{"label":"public","children":[{"label":"demo","children":[],"pathSegment":"demo","isGrouper":false}],"pathSegment":"public","isGrouper":false},{"label":"Guide","children":[{"label":"Getting Started","children":null,"pathSegment":"getting-started"},{"label":"Usage","children":null,"pathSegment":"usage"}],"pathSegment":"","isGrouper":true},{"label":"API Reference","children":[{"label":"Constructor Config","children":null,"pathSegment":"constructor-config"},{"label":"Methods","children":null,"pathSegment":"methods"},{"label":"Properties","children":null,"pathSegment":"properties"},{"label":"Modes","children":null,"pathSegment":"modes"}],"pathSegment":"","isGrouper":true},{"label":"Examples","children":[{"label":"Basic Animation","children":null,"pathSegment":"basic-animation"},{"label":"Timeline and Easing","children":null,"pathSegment":"timeline-and-easing"}],"pathSegment":"","isGrouper":true}]
@@ -59,7 +59,8 @@ export default function Rendrer({
59
59
  article.querySelectorAll('a').forEach((elem: HTMLAnchorElement) => {
60
60
  if (
61
61
  elem.getAttribute('href')?.startsWith('http://') ||
62
- elem.getAttribute('href')?.startsWith('https://')
62
+ elem.getAttribute('href')?.startsWith('https://') ||
63
+ !out.routes.find((r) => r.path === elem.getAttribute('href'))
63
64
  )
64
65
  return;
65
66