# Greg Kilmer — Profile & Portfolio Site A responsive, content-driven personal site for Greg Kilmer, built as **two wings of the same house**: a polished professional resume/portfolio on one side, and a warm, personality-driven interests hub on the other. Built with **Astro 7 + React Islands + TypeScript**, served by a **Node server** with API routes, ready to deploy as a container on a homelab Cosmos system. --- ## Highlights - **Astro 7** static-first core with React Islands for interactivity (mobile menu, theme toggle, animated hero background, contact form). - **Node backend** (`@astrojs/node`, standalone) with a typed `/api/contact` endpoint (SMTP via nodemailer + webhook fallback, Zod validation, rate limit). - **Section-aware theming**: the Professional wing reads dark/polished, the Interests wing reads warm/inviting, plus a global light/dark toggle. - **Rich motion**: animated mesh-gradient hero with an optional canvas particle field, IntersectionObserver scroll reveals, View Transitions page swaps, scroll-triggered nav blur. All `prefers-reduced-motion` aware. - **Content Collections** (typed): add projects and experience by dropping markdown/MDX files. - **mdi icons everywhere** (no emojis, per the spec), inlined at build time from `@iconify-json/mdi` for zero runtime cost. - **Self-hosted variable fonts** (Inter, Plus Jakarta Sans, JetBrains Mono). - **Accessible**: semantic landmarks, skip link, keyboard-operable menu, focus-visible rings, ARIA on interactive bits, WCAG-AA contrast targets. - **Deploy artifacts**: multi-stage `Dockerfile` + `docker-compose.yml`. --- ## Quickstart ```bash # 1. Install dependencies (Node 20+) npm install # 2. Start the dev server with hot reload npm run dev # -> http://localhost:4321 # 3. Production build (runs astro check + build) npm run build # 4. Run the built Node server npm run serve # -> http://localhost:4321 ``` Environment is optional for local dev. To enable contact-form delivery, copy `.env.example` to `.env` and fill in SMTP or webhook vars (see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)). --- ## Project structure ``` src/ ├── components/ │ ├── hero/ AnimatedBackground.tsx (gradient + canvas particles) │ ├── motion/ Reveal.astro (IntersectionObserver scroll reveals) │ ├── nav/ NavBar.astro, MobileMenu.tsx, ThemeToggle.tsx │ ├── cards/ InterestCard.astro │ ├── professional/ Timeline, SkillGrid, ProjectCard, SectionNav, ContactForm │ ├── layout/ Footer, SectionHeader, SplitTransition, InterestHero, │ │ RelatedInterests, Placeholder │ └── Icon.astro Inline mdi icon renderer (build-time) ├── content/ │ ├── projects/ Project collection entries (markdown/MDX) │ └── experience/ Experience collection entries ├── layouts/ │ └── BaseLayout.astro shell, head, fonts, theme init, nav, footer ├── pages/ │ ├── index.astro Home (hero + snapshot grid) │ ├── about.astro About + split transition fork │ ├── professional/index.astro Single long page: Summary, Experience, │ │ Skills, Projects, Education, Contact │ ├── interests/ Hub + 5 sub-pages │ │ ├── index.astro │ │ ├── ttrpgs / gaming / reading / making / pokemon .astro │ ├── contact.astro Two-column connect page + contact form │ └── api/contact.ts POST endpoint -> SMTP / webhook ├── content.config.ts Collection schemas (projects, experience) ├── lib/ site.ts (nav/socials), motion.ts, content helpers ├── styles/ global.css, themes.css, animations.css └── scripts/theme-init.ts No-FOUC theme boot (inlined in ) ``` --- ## The two wings (theming model) Theming has two independent axes (see [docs/THEMING.md](docs/THEMING.md)): 1. **Global light/dark** on ``, set before paint by an inline script, persisted to `localStorage`, toggleable via the nav button. 2. **Section tone** via `data-surface` on ``: - `neutral` (Home/About/Contact) — balanced middle ground - `professional` — dark slate, polished - `interest` — warm cream/amber, inviting Components only reference semantic CSS variables (`--surface`, `--text`, `--accent`...), so changing either axis restyles everything automatically. --- ## Adding content - **Projects / Experience:** drop a markdown or MDX file in `src/content/projects/` or `src/content/experience/`. Schemas and field reference are in [docs/CONTENT.md](docs/CONTENT.md). - **Interest pages:** hand-built `.astro` files under `src/pages/interests/`, each following the spec's template (Header, Overview, Highlights, Currently, Related). Edit copy in place. - **Placeholders:** every `[Greg to fill]` gap from the spec is a styled `Placeholder` slot with a TODO badge so you can find and replace them. --- ## Deployment (Cosmos homelab) The site runs as a Node server inside a container. Full walkthrough in [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md): ```bash docker compose up -d --build # Then point your reverse proxy at port 4321 with TLS for patiun.com. ``` --- ## Scripts | Script | Description | |---|---| | `npm run dev` | Dev server with hot reload | | `npm run build` | Type-check (`astro check`) then build the Node server | | `npm run serve` | Run the built server (`dist/server/entry.mjs`) | | `npm run preview` | Preview the build locally | | `npm run check` | Type-check only | --- ## Tech stack Astro 7, React 19, TypeScript 6, Tailwind CSS v4, Framer Motion, nodemailer, Zod, `@iconify-json/mdi`, Fontsource variable fonts, `@astrojs/node` standalone. --- ## License Personal site for Greg Kilmer. All rights reserved.