diff --git a/build.js b/build.js
index aaf85f6..467acd7 100644
--- a/build.js
+++ b/build.js
@@ -1,20 +1,139 @@
-import fs from 'fs';
-import path from 'path';
-import { marked } from 'marked';
+// build.js — tiny static-site generator without the generator
+// Scans /posts/*.md, extracts front-matter & first paragraph,
+// writes posts/posts.json, rss.xml, and sitemap.xml
-const postsDir = './posts';
-const outputFile = './posts.js';
+const fs = require("fs");
+const path = require("path");
-const files = fs.readdirSync(postsDir).filter(f => f.endsWith('.md'));
+const POSTS_DIR = path.join(__dirname, "posts");
+const SITE_URL = "https://thefoldwithin.earth"; // change if needed
+
+function slugify(s) {
+ return s
+ .toLowerCase()
+ .normalize("NFKD").replace(/[^\w\s-]/g, "")
+ .trim().replace(/\s+/g, "-")
+ .replace(/-+/g, "-");
+}
+
+function parseFrontMatter(src) {
+ // very small YAML-ish parser
+ const fm = { title: "", date: "", excerpt: "", tags: [] };
+ const m = src.match(/^---\n([\s\S]*?)\n---\n?/);
+ if (!m) return { fm, body: src };
+
+ const block = m[1];
+ for (const line of block.split("\n")) {
+ const idx = line.indexOf(":");
+ if (idx === -1) continue;
+ const key = line.slice(0, idx).trim();
+ let val = line.slice(idx + 1).trim();
+
+ if (key === "tags") {
+ // tags: [a, b, c] OR tags: a, b, c
+ if (/^\[.*\]$/.test(val)) {
+ val = val.replace(/^\[|\]$/g, "");
+ }
+ fm.tags = val.split(",").map(t => t.trim()).filter(Boolean);
+ } else if (key in fm) {
+ fm[key] = val;
+ }
+ }
+ const body = src.slice(m[0].length);
+ return { fm, body };
+}
+
+function firstParagraph(text) {
+ const body = text.replace(/\r/g, "").trim();
+ const noFM = body.replace(/^---[\s\S]*?---/, "").trim();
+ const para = noFM.split(/\n{2,}/).find(p => p.replace(/\s/g, "").length > 0) || "";
+ return para.replace(/\n/g, " ").trim();
+}
+
+function toISODate(s, fallback) {
+ // try to parse; if fail, fallback (usually file mtime)
+ const d = s ? new Date(s) : null;
+ if (d && !isNaN(d.getTime())) return d.toISOString();
+ return fallback.toISOString();
+}
+
+function escapeXML(s) {
+ return s
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
+
+const files = fs.readdirSync(POSTS_DIR).filter(f => f.endsWith(".md"));
const posts = files.map(file => {
- const filepath = path.join(postsDir, file);
- const raw = fs.readFileSync(filepath, 'utf-8');
- const html = marked.parse(raw);
- return { file, content: html };
+ const full = path.join(POSTS_DIR, file);
+ const raw = fs.readFileSync(full, "utf8");
+ const stat = fs.statSync(full);
+ const { fm, body } = parseFrontMatter(raw);
+
+ const fallbackTitle = file.replace(/\.md$/i, "").replace(/-/g, " ").replace(/\s+/g, " ").trim();
+ const title = fm.title || fallbackTitle;
+ const excerpt = fm.excerpt || (firstParagraph(raw).slice(0, 200) + (firstParagraph(raw).length > 200 ? "…" : ""));
+ const slug = slugify(fm.title || fallbackTitle);
+ const dateISO = toISODate(fm.date, stat.mtime);
+
+ return {
+ title,
+ date: dateISO, // ISO for reliable sort
+ excerpt,
+ tags: fm.tags || [],
+ slug,
+ file // actual filename
+ };
});
-const output = `document.getElementById("content").innerHTML = \`${posts.map(p => `${p.content}`).join("")}\`;`;
+// newest first
+posts.sort((a, b) => (a.date < b.date ? 1 : -1));
-fs.writeFileSync(outputFile, output);
-console.log("✅ Blog built to posts.js");
+// write JSON index
+fs.writeFileSync(
+ path.join(POSTS_DIR, "posts.json"),
+ JSON.stringify(posts, null, 2),
+ "utf8"
+);
+console.log(`✅ posts.json written (${posts.length} posts)`);
+
+// write RSS
+const rssItems = posts.map(p => {
+ const url = `${SITE_URL}/#/post/${p.slug}`;
+ return `
+ -
+ ${escapeXML(p.title)}
+ ${url}
+ ${url}
+ ${new Date(p.date).toUTCString()}
+ ${escapeXML(p.excerpt)}
+
`;
+}).join("");
+
+const rss = `
+
+
+ The Fold Within
+ ${SITE_URL}
+ Uncovering the recursive real.
+ ${new Date().toUTCString()}
+ ${rssItems}
+
+`;
+
+fs.writeFileSync(path.join(__dirname, "rss.xml"), rss, "utf8");
+console.log("✅ rss.xml written");
+
+// write sitemap
+const sitemapUrls = posts.map(p => ` ${SITE_URL}/#/post/${p.slug}`).join("\n");
+const sitemap = `
+
+ ${SITE_URL}
+${sitemapUrls}
+`;
+fs.writeFileSync(path.join(__dirname, "sitemap.xml"), sitemap, "utf8");
+console.log("✅ sitemap.xml written");
\ No newline at end of file