2026-07-04 19:13:54 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 07:42:24 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 07:42:24 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 07:42:24 -04:00
2026-07-04 07:42:24 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 19:13:54 -04:00
2026-07-04 07:42:24 -04:00

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

# 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).


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  <html> 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 <head>)

The two wings (theming model)

Theming has two independent axes (see docs/THEMING.md):

  1. Global light/dark on <html data-theme>, set before paint by an inline script, persisted to localStorage, toggleable via the nav button.
  2. Section tone via data-surface on <body>:
    • 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.
  • 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:

docker compose up -d --build
# Then point your reverse proxy at port 4321 with TLS for gregkilmer.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.

S
Description
No description provided
Readme 64 MiB
Languages
TypeScript 53.3%
Astro 40%
CSS 3.1%
JavaScript 2.9%
Dockerfile 0.4%
Other 0.3%