diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1c9f935
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+.PHONY: dev build deploy clean
+
+# Local development server
+dev:
+ @echo "Starting dev server on :8080..."
+ @cd "$(CURDIR)" && python3 -m http.server 8080
+
+# Build the static site (generate blog index + RSS from posts)
+build:
+ @echo "Building the Tower..."
+ @python3 scripts/build.py
+ @echo "Done."
+
+# Deploy — configure DEPLOY_TARGET in environment or .env
+deploy: build
+ @echo "Deploying..."
+ @if [ -z "$${DEPLOY_TARGET:-}" ]; then \
+ echo "Error: Set DEPLOY_TARGET (e.g., user@host:/var/www/tower)"; \
+ exit 1; \
+ fi
+ rsync -avz --delete \
+ --exclude '.git' \
+ --exclude 'scripts/' \
+ --exclude 'Makefile' \
+ --exclude '*.md' \
+ ./ "$${DEPLOY_TARGET}/"
+ @echo "Deployed to $${DEPLOY_TARGET}"
+
+# Clean generated files
+clean:
+ @echo "Nothing to clean yet."
diff --git a/README.md b/README.md
index f5c92a4..aef5469 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,39 @@
-# alexanderwhitestone.com
+# The Wizard's Tower
-Public-facing interface for Timmy — AlexanderWhitestone.com
\ No newline at end of file
+**AlexanderWhitestone.com** — two rooms, nothing else.
+
+## Rooms
+
+- **The Workshop** (`/world/`) — A 3D space where Timmy lives. Visitors enter and interact.
+- **The Scrolls** (`/blog/`) — Alexander's words. Plain text, RSS, sovereign publishing.
+
+## Structure
+
+```
+index.html Entry hall — two doors
+world/ The Workshop (3D scene, Timmy presence)
+blog/ The Scrolls (posts, RSS feed)
+scripts/ CLI tools (aw-post for quick publishing)
+static/ Shared assets (fonts, favicon)
+Makefile Build, dev, deploy
+```
+
+## Development
+
+```bash
+make dev # Local dev server on :8080
+make build # Build static site
+make deploy # Deploy (configure target in Makefile)
+```
+
+## Tech Decisions (Open)
+
+- [ ] 3D engine: Three.js vs Babylon.js
+- [ ] Blog: Hugo vs hand-rolled static generator
+- [ ] Hosting: self-hosted Nginx/Caddy vs static CDN
+- [ ] Timmy's 3D character design
+
+## Philosophy
+
+Two doors. No navbar. No sidebar. No footer links. You walk in, you choose a room.
+The Workshop is alive. The Scrolls are permanent. That's the Tower.
diff --git a/blog/feed.xml b/blog/feed.xml
new file mode 100644
index 0000000..1e43dfa
--- /dev/null
+++ b/blog/feed.xml
@@ -0,0 +1,13 @@
+
+
+ The Scrolls — Alexander Whitestone
+
+
+ https://alexanderwhitestone.com/blog/
+ 2026-03-19T01:32:41Z
+
+ Alexander Whitestone
+
+ Words from the Wizard's Tower
+
+
\ No newline at end of file
diff --git a/blog/index.html b/blog/index.html
new file mode 100644
index 0000000..4967523
--- /dev/null
+++ b/blog/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ The Scrolls — The Wizard's Tower
+
+
+
+
+
+
+
+
+ 2026-03-18
+ Hello World
+
+
+
+
+
\ No newline at end of file
diff --git a/blog/posts/.gitkeep b/blog/posts/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..c7268f4
--- /dev/null
+++ b/index.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+ The Wizard's Tower
+
+
+
+ The Wizard's Tower
+
+
+ The Workshop
+ Enter the world
+
+
+ The Scrolls
+ Read the words
+
+
+
+
diff --git a/scripts/aw-post b/scripts/aw-post
new file mode 100755
index 0000000..6611123
--- /dev/null
+++ b/scripts/aw-post
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# aw-post — Quick-post a scroll from the command line
+#
+# Usage:
+# aw-post "Title of the Post"
+# aw-post "Title" < body.md
+# echo "Post body here" | aw-post "Title"
+#
+# Creates a new markdown file in blog/posts/ with frontmatter.
+# Rebuilds the blog index and RSS feed.
+
+set -euo pipefail
+
+BLOG_DIR="$(cd "$(dirname "$0")/.." && pwd)/blog/posts"
+
+if [ $# -lt 1 ]; then
+ echo "Usage: aw-post \"Title of the Post\""
+ echo " Pipe or redirect body content via stdin."
+ exit 1
+fi
+
+TITLE="$1"
+DATE=$(date +%Y-%m-%d)
+SLUG=$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-')
+FILENAME="${DATE}-${SLUG}.md"
+FILEPATH="${BLOG_DIR}/${FILENAME}"
+
+if [ -f "$FILEPATH" ]; then
+ echo "Error: $FILEPATH already exists"
+ exit 1
+fi
+
+# Read body from stdin if available
+BODY=""
+if [ ! -t 0 ]; then
+ BODY=$(cat)
+fi
+
+cat > "$FILEPATH" << EOF
+---
+title: "${TITLE}"
+date: ${DATE}
+---
+
+${BODY}
+EOF
+
+echo "Created: ${FILEPATH}"
+echo "Next: rebuild with 'make build'"
diff --git a/scripts/build.py b/scripts/build.py
new file mode 100644
index 0000000..5b3ef0c
--- /dev/null
+++ b/scripts/build.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+"""
+Build script for The Scrolls — generates blog index and RSS feed from
+markdown posts in blog/posts/.
+
+Each post is a markdown file with YAML frontmatter:
+ ---
+ title: "Post Title"
+ date: 2026-03-18
+ ---
+ Body content here.
+
+Generates:
+ - blog/index.html with post listing
+ - blog/feed.xml Atom feed
+"""
+
+import os
+import re
+from datetime import datetime, timezone
+from pathlib import Path
+
+SITE_URL = "https://alexanderwhitestone.com"
+BLOG_DIR = Path(__file__).parent.parent / "blog"
+POSTS_DIR = BLOG_DIR / "posts"
+
+
+def parse_frontmatter(text):
+ """Extract YAML frontmatter from markdown text."""
+ match = re.match(r"^---\s*\n(.*?)\n---\s*\n(.*)", text, re.DOTALL)
+ if not match:
+ return {}, text
+
+ meta = {}
+ for line in match.group(1).strip().split("\n"):
+ if ":" in line:
+ key, val = line.split(":", 1)
+ meta[key.strip()] = val.strip().strip('"').strip("'")
+ return meta, match.group(2).strip()
+
+
+def load_posts():
+ """Load and sort all posts by date (newest first)."""
+ posts = []
+ if not POSTS_DIR.exists():
+ return posts
+
+ for path in sorted(POSTS_DIR.glob("*.md"), reverse=True):
+ text = path.read_text()
+ meta, body = parse_frontmatter(text)
+ if meta.get("title") and meta.get("date"):
+ posts.append(
+ {
+ "title": meta["title"],
+ "date": meta["date"],
+ "slug": path.stem,
+ "body": body,
+ "path": path,
+ }
+ )
+ return posts
+
+
+def generate_index(posts):
+ """Generate blog/index.html with post listing."""
+ if not posts:
+ print(" No posts found. Keeping placeholder index.")
+ return
+
+ items = []
+ for p in posts:
+ items.append(
+ f' \n'
+ f' {p["date"]} \n'
+ f' {p["title"]} \n'
+ f" "
+ )
+
+ post_list = "\n".join(items)
+
+ html = f"""
+
+
+
+
+ The Scrolls — The Wizard's Tower
+
+
+
+
+
+
+
+
+
+"""
+
+ (BLOG_DIR / "index.html").write_text(html)
+ print(f" Generated index with {len(posts)} post(s).")
+
+
+def generate_feed(posts):
+ """Generate blog/feed.xml Atom feed."""
+ now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
+
+ entries = []
+ for p in posts[:20]: # Cap at 20 entries
+ # Simple HTML conversion: wrap paragraphs
+ html_body = "\n".join(
+ f"{para}
" for para in p["body"].split("\n\n") if para.strip()
+ )
+ entries.append(
+ f"""
+ {p["title"]}
+
+ {SITE_URL}/blog/posts/{p["slug"]}
+ {p["date"]}T00:00:00Z
+
+ """
+ )
+
+ entry_block = "\n".join(entries)
+
+ feed = f"""
+
+ The Scrolls — Alexander Whitestone
+
+
+ {SITE_URL}/blog/
+ {now}
+
+ Alexander Whitestone
+
+ Words from the Wizard's Tower
+{entry_block}
+ """
+
+ (BLOG_DIR / "feed.xml").write_text(feed)
+ print(f" Generated feed with {len(entries)} entry/entries.")
+
+
+def main():
+ print("Building The Scrolls...")
+ posts = load_posts()
+ generate_index(posts)
+ generate_feed(posts)
+ print("Build complete.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/static/.gitkeep b/static/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/world/assets/.gitkeep b/world/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/world/index.html b/world/index.html
new file mode 100644
index 0000000..0428a42
--- /dev/null
+++ b/world/index.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+ The Workshop — The Wizard's Tower
+
+
+
+
+
+
+
+
diff --git a/world/main.js b/world/main.js
new file mode 100644
index 0000000..ae518fd
--- /dev/null
+++ b/world/main.js
@@ -0,0 +1,20 @@
+/**
+ * The Workshop — Three.js scene bootstrap
+ *
+ * This file will initialize the 3D world where Timmy lives.
+ * Currently a placeholder until tech decisions are made:
+ * - 3D engine confirmed (Three.js vs Babylon.js)
+ * - Character design direction chosen
+ * - WebSocket bridge to Timmy's soul designed (#243)
+ *
+ * See: #242 (3D world), #243 (WebSocket bridge), #265 (presence schema)
+ */
+
+// Future: import * as THREE from 'three';
+
+export function initWorkshop(container) {
+ // TODO: Initialize 3D scene
+ // TODO: Load wizard character model
+ // TODO: Connect to Timmy presence WebSocket
+ console.log('[Workshop] Scene container ready:', container.id);
+}