Further content updates

This commit is contained in:
Greg Kilmer
2026-07-04 14:21:51 -04:00
parent c298562266
commit db6ff9f213
13 changed files with 405 additions and 220 deletions
+7 -6
View File
@@ -27,7 +27,7 @@ const quickFacts = [
{ icon: "dice-multiple", text: "Running D&D & Daggerheart campaigns" },
{
icon: "book-open-variant",
text: "Currently reading: Heir of Fire by Sarah J. Maas",
text: "Currently tandem reading: Heir of Fire and Tower of Dawn by Sarah J. Maas",
},
{ icon: "tea", text: "Fueled by loose-leaf Chinese tea and Mountain Dew" },
];
@@ -64,11 +64,12 @@ const quickFacts = [
class="border-l-2 pl-5 font-sans text-xl leading-relaxed sm:text-2xl"
style="border-color: var(--color-accent); color: var(--color-text);"
>
I am Greg: a software developer based in Philadelphia who spends his
free time running tabletop RPGs, making resin dice and custom cards, 3D
printing anything I can, and reading his way through fantasy series at
an alarming rate. I live with my partner Krystina, our mini dachshund
Kashi, and more board games than any reasonable apartment should hold.
I am Greg: a software developer and technical team lead based in
Philadelphia who spends his free time running tabletop RPGs, making
resin dice and custom cards, 3D printing anything I can, and reading his
way through fantasy series at an alarming rate. I live with my partner
Krystina, our mini dachshund Kashi, and more board games than any
reasonable apartment should hold.
</p>
</Reveal>
</section>
+3 -3
View File
@@ -25,7 +25,7 @@ const cards = [
{
icon: "briefcase",
title: "Professional",
copy: "From SAP-adjacent cloud apps to full-stack mobile — a decade of building software that businesses actually use.",
copy: "From SAP-adjacent cloud to full-stack mobile, a decade of building software that businesses actually use.",
href: "/professional",
image: "/images/pro-workspace.jpg",
alt: "Developer workspace with code on screen",
@@ -33,7 +33,7 @@ const cards = [
{
icon: "dice-multiple",
title: "Tabletop",
copy: "Currently running two campaigns in Foundry VTT and playtesting MCDM's Crows. Always rolling dice.",
copy: "Currently obsessed with Spirit Island, Magic: The Gathering, and running campaigns in Foundry VTT. Always planning more; always rolling dice.",
href: "/interests/ttrpgs",
image: "/images/ttrpg-dice.jpg",
alt: "Polyhedral dice on a dark surface",
@@ -41,7 +41,7 @@ const cards = [
{
icon: "palette",
title: "Making",
copy: "Resin dice, 3D prints, and whatever else catches my eye. If it involves layers and precision, I am in.",
copy: "Resin dice, 3D prints, TCG proxies, and whatever else catches my eye. If it involves really nice cardboard or mastering a new craft, I am in.",
href: "/interests/making",
image: "/images/making-resin.jpg",
alt: "Resin crafting in progress",
+103 -35
View File
@@ -5,31 +5,55 @@
* Per-interest template: header + tagline, verbatim overview, platforms card
* grid, favorite genres, currently playing placeholder, and related interests.
*/
import BaseLayout from '@layouts/BaseLayout.astro';
import Reveal from '@components/motion/Reveal.astro';
import InterestHero from '@components/layout/InterestHero.astro';
import InterestCard from '@components/cards/InterestCard.astro';
import SectionHeader from '@components/layout/SectionHeader.astro';
import RelatedInterests from '@components/layout/RelatedInterests.astro';
import Placeholder from '@components/layout/Placeholder.astro';
import Icon from '@components/Icon.astro';
import BaseLayout from "@layouts/BaseLayout.astro";
import Reveal from "@components/motion/Reveal.astro";
import InterestHero from "@components/layout/InterestHero.astro";
import InterestCard from "@components/cards/InterestCard.astro";
import SectionHeader from "@components/layout/SectionHeader.astro";
import RelatedInterests from "@components/layout/RelatedInterests.astro";
import Placeholder from "@components/layout/Placeholder.astro";
import Icon from "@components/Icon.astro";
const platforms = [
{ icon: 'sony-playstation', title: 'PlayStation 5', body: 'Main console for AAA titles and exclusives.' },
{ icon: 'nintendo-switch', title: 'Nintendo Switch / Switch 2', body: 'Handheld and docked. Nintendo first-party plus indie gems.' },
{ icon: 'steam', title: 'Steam', body: 'The primary PC library. Strategy, RPGs, and an ever-growing backlog.' },
{
icon: "sony-playstation",
title: "PlayStation 5",
body: "Main console for AAA titles and exclusives.",
},
{
icon: "nintendo-switch",
title: "Nintendo Switch / Switch 2",
body: "Handheld and docked. Nintendo first-party plus indie gems.",
},
{
icon: "steam",
title: "Steam",
body: "The primary PC library. Strategy, RPGs, and an ever-growing backlog.",
},
];
const genres = [
'RPGs (both Western and JRPG)',
'Strategy and tactics',
'Open-world exploration',
'Indie darlings',
"RPGs (both Western and JRPG)",
"Strategy and tactics",
"Building and crafting",
"Automation",
"Open-world exploration",
"Indie darlings",
];
const related = [
{ href: '/interests/pokemon', title: 'Pokémon', icon: 'pokeball', blurb: 'Nintendo console overlap and a lifelong obsession.' },
{ href: '/interests/ttrpgs', title: 'TTRPGs & Tabletop', icon: 'dice-multiple', blurb: 'Digital RPGs as another expression of the same impulse.' },
{
href: "/interests/pokemon",
title: "Pokémon",
icon: "pokeball",
blurb: "Nintendo console overlap and a lifelong obsession.",
},
{
href: "/interests/ttrpgs",
title: "TTRPGs & Tabletop",
icon: "dice-multiple",
blurb: "Digital RPGs as another expression of the same impulse.",
},
];
---
@@ -48,48 +72,92 @@ const related = [
<div class="container-prose flex flex-col gap-20 py-12 sm:py-16">
{/* Overview */}
<section class="flex flex-col gap-5 text-lg leading-relaxed" style="color: var(--color-text-muted);">
<Reveal><p>Gaming is my other constant. I span console generations with a PlayStation 5, Nintendo Switch 2, and a Steam library that has gotten politely out of hand. I'm particularly drawn to RPGs, strategy games, and anything with a deeply layered world. If a game has lore compendiums, I'm reading them.</p></Reveal>
<section
class="flex flex-col gap-5 text-lg leading-relaxed"
style="color: var(--color-text-muted);"
>
<Reveal
><p>
Gaming is my other constant. I span console generations with a
PlayStation 5, Nintendo Switch 2, and a Steam library that has gotten
politely out of hand. I'm particularly drawn to RPGs, strategy games,
and anything with a deeply layered world. If a game has lore
compendiums, I'm reading them.
</p></Reveal
>
</section>
{/* Platforms */}
<section class="flex flex-col gap-6">
<Reveal><SectionHeader kicker="Platforms" icon="gamepad-variant" title="Where I play" /></Reveal>
<Reveal
><SectionHeader
kicker="Platforms"
icon="gamepad-variant"
title="Where I play"
/></Reveal
>
<div class="grid gap-5 sm:grid-cols-3">
{platforms.map((p, i) => (
<Reveal delay={i * 80}>
<InterestCard icon={p.icon} title={p.title}>{p.body}</InterestCard>
</Reveal>
))}
{
platforms.map((p, i) => (
<Reveal delay={i * 80}>
<InterestCard icon={p.icon} title={p.title}>
{p.body}
</InterestCard>
</Reveal>
))
}
</div>
</section>
{/* Genres */}
<section class="flex flex-col gap-5">
<Reveal><SectionHeader kicker="Tastes" icon="shape" title="Favorite genres" /></Reveal>
<Reveal
><SectionHeader
kicker="Tastes"
icon="shape"
title="Favorite genres"
/></Reveal
>
<Reveal delay={80}>
<ul class="flex flex-wrap gap-3">
{genres.map((g) => (
<li class="pill text-sm">
<Icon name="star-four-points" class="h-3.5 w-3.5" />
{g}
</li>
))}
{
genres.map((g) => (
<li class="pill text-sm">
<Icon name="star-four-points" class="h-3.5 w-3.5" />
{g}
</li>
))
}
</ul>
</Reveal>
</section>
{/* Currently */}
<section class="flex flex-col gap-6">
<Reveal><SectionHeader kicker="Currently" icon="calendar-clock" title="Now playing" /></Reveal>
<Reveal
><SectionHeader
kicker="Currently"
icon="calendar-clock"
title="Now playing"
/></Reveal
>
<div class="grid gap-4 sm:grid-cols-[1fr_1fr]">
<figure
class="relative overflow-hidden rounded-xl border"
style="border-color: color-mix(in srgb, var(--color-accent) 35%, transparent);"
>
<img src="/images/gaming-setup.jpg" alt="Gaming setup" loading="lazy" decoding="async" class="aspect-[4/3] w-full object-cover" />
<img
src="/images/gaming-setup.jpg"
alt="Gaming setup"
loading="lazy"
decoding="async"
class="aspect-[4/3] w-full object-cover"
/>
</figure>
<Placeholder label="Currently playing" hint="Add the games you are actively playing right now." />
<Placeholder
label="Currently playing"
hint="Add the games you are actively playing right now."
/>
</div>
</section>
+113 -72
View File
@@ -6,51 +6,56 @@
* sub-page, using the spec's taglines. Sets surface="interest" so the whole
* page reads warm (cream/amber) regardless of the global light/dark toggle.
*/
import BaseLayout from '@layouts/BaseLayout.astro';
import Reveal from '@components/motion/Reveal.astro';
import Icon from '@components/Icon.astro';
import SectionHeader from '@components/layout/SectionHeader.astro';
import AnimatedBackground from '@components/hero/AnimatedBackground.tsx';
import SacredGeometry from '@components/mystic/SacredGeometry.astro';
import ConstellationField from '@components/mystic/ConstellationField.tsx';
import BaseLayout from "@layouts/BaseLayout.astro";
import Reveal from "@components/motion/Reveal.astro";
import Icon from "@components/Icon.astro";
import SectionHeader from "@components/layout/SectionHeader.astro";
import AnimatedBackground from "@components/hero/AnimatedBackground.tsx";
import SacredGeometry from "@components/mystic/SacredGeometry.astro";
import ConstellationField from "@components/mystic/ConstellationField.tsx";
const interests = [
{
href: '/interests/ttrpgs',
icon: 'dice-multiple',
title: 'TTRPGs & Tabletop',
tagline: 'Three campaigns, two systems, one rolling table.',
blurb: 'Long-running D&D and Daggerheart campaigns on Foundry VTT, plus the Crows playtest. Worldbuilding, NPC relationships, and player-driven narrative.',
image: '/images/ttrpg-dice.jpg',
alt: 'Polyhedral dice on a dark surface',
href: "/interests/ttrpgs",
icon: "dice-multiple",
title: "TTRPGs & Tabletop",
tagline: "Have dice, will roll.",
blurb:
"Card Games, Board Games, and Long-running D&D and Daggerheart campaigns on Foundry VTT. Worldbuilding, NPC relationships, and player-driven narrative.",
image: "/images/ttrpg-dice.jpg",
alt: "Boardgame Shelf",
},
{
href: '/interests/gaming',
icon: 'sony-playstation',
title: 'Gaming',
tagline: 'If it has a screen or a controller, I have probably played it.',
blurb: 'PlayStation 5, Nintendo Switch 2, and a politely out-of-hand Steam library. RPGs, strategy, and anything with a deeply layered world.',
image: '/images/gaming-setup.jpg',
alt: 'Gaming setup with controller',
href: "/interests/gaming",
icon: "sony-playstation",
title: "Gaming",
tagline: "We do not talk about my backlog.",
blurb:
"PlayStation 5, Nintendo Switch 2, and a politely out-of-hand Steam library. RPGs, strategy, and anything with a deeply layered world.",
image: "/images/gaming-setup.jpg",
alt: "Gaming setup desk",
},
{
href: '/interests/reading',
icon: 'book-open-page-variant',
title: 'Reading & Media',
tagline: 'Perpetually three books ahead of my to-read list.',
blurb: 'The Cosmere, Dune, the Pendergast saga, and Throne of Glass. Plus light novels, manga, manhwa, anime, and film.',
image: '/images/fantasy-books.jpg',
alt: 'Fantasy bookshelf',
href: "/interests/reading",
icon: "book-open-page-variant",
title: "Reading & Media",
tagline: "Perpetually three books ahead of my to-read list.",
blurb:
"The Cosmere, Dune, the Pendergast saga, and Throne of Glass. Plus light novels, manga, manhwa, anime, and film.",
image: "/images/fantasy-books.jpg",
alt: "Fantasy bookshelf",
},
{
href: '/interests/making',
icon: 'palette',
title: 'Making & Creating',
tagline: 'If it involves layers and precision, I am in.',
blurb: 'Resin dice in a pressure pot, miniatures and terrain on the Elegoo Mars 4 and Bambu Labs P1S. Much of it ends up on the virtual table.',
image: '/images/making-resin.jpg',
alt: 'Resin crafting in progress',
},
href: "/interests/making",
icon: "palette",
title: "Making & Creating",
tagline:
"If it involves really nice cardboard or mastering a new craft, I am in.",
blurb:
"Resin dice in a pressure pot, fun and functional prints on the P1s, custom TCG proxies and decks. Passion and utility.",
image: "/images/making-resin.jpg",
alt: "Polyhedral dice on a dark bag",
} /*
{
href: '/interests/pokemon',
icon: 'pokeball',
@@ -59,7 +64,7 @@ const interests = [
blurb: 'A lifelong obsession from Red and Blue to modern competitive. Steel/Psychic, beautiful design, absolutely devastating in battle.',
image: '/images/pokemon-cards.jpg',
alt: 'Trading card collection',
},
},*/,
];
---
@@ -70,9 +75,13 @@ const interests = [
>
<!-- Hero -->
<section class="relative min-h-[60vh] overflow-hidden pt-28 sm:pt-32">
{/* Full animated Milky Way field + stars, matching the Home hero treatment. */}
{
/* Full animated Milky Way field + stars, matching the Home hero treatment. */
}
<AnimatedBackground client:idle transitionName="sky" />
<div class="container-prose relative z-10 flex flex-col items-start gap-6 py-16">
<div
class="container-prose relative z-10 flex flex-col items-start gap-6 py-16"
>
<Reveal>
<SectionHeader
kicker="The personal wing"
@@ -94,38 +103,59 @@ const interests = [
/>
<div class="container-prose relative z-10">
<div class="grid gap-5 md:grid-cols-2 lg:grid-cols-3">
{interests.map((item, i) => (
<Reveal delay={i * 80}>
<a href={item.href} class="card card-interactive group flex h-full flex-col gap-4 overflow-hidden p-0">
<div class="aspect-[16/10] w-full overflow-hidden">
<img
src={item.image}
alt={item.alt}
loading="lazy"
decoding="async"
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
/>
</div>
<div class="flex flex-col gap-3 px-5 pb-5">
<div class="flex items-center justify-between">
<span
class="inline-flex h-12 w-12 items-center justify-center rounded-xl"
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
aria-hidden="true"
{
interests.map((item, i) => (
<Reveal delay={i * 80}>
<a
href={item.href}
class="card card-interactive group flex h-full flex-col gap-4 overflow-hidden p-0"
>
<div class="aspect-[16/10] w-full overflow-hidden">
<img
src={item.image}
alt={item.alt}
loading="lazy"
decoding="async"
class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
/>
</div>
<div class="flex flex-col gap-3 px-5 pb-5">
<div class="flex items-center justify-between">
<span
class="inline-flex h-12 w-12 items-center justify-center rounded-xl"
style="background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent);"
aria-hidden="true"
>
<Icon name={item.icon} class="h-6 w-6" />
</span>
<Icon
name="arrow-right"
class="h-5 w-5 transition-transform group-hover:translate-x-1"
style="color: var(--color-accent);"
/>
</div>
<div class="flex flex-col gap-2">
<h3 class="font-sans" style="color: var(--color-text);">
{item.title}
</h3>
<p
class="font-sans text-sm italic"
style="color: var(--color-secondary);"
>
{item.tagline}
</p>
</div>
<p
class="grow text-sm leading-relaxed"
style="color: var(--color-text-muted);"
>
<Icon name={item.icon} class="h-6 w-6" />
</span>
<Icon name="arrow-right" class="h-5 w-5 transition-transform group-hover:translate-x-1" style="color: var(--color-accent);" />
{item.blurb}
</p>
</div>
<div class="flex flex-col gap-2">
<h3 class="font-sans" style="color: var(--color-text);">{item.title}</h3>
<p class="font-sans text-sm italic" style="color: var(--color-secondary);">{item.tagline}</p>
</div>
<p class="grow text-sm leading-relaxed" style="color: var(--color-text-muted);">{item.blurb}</p>
</div>
</a>
</Reveal>
))}
</a>
</Reveal>
))
}
{/* Cross-link back to professional wing */}
<Reveal delay={interests.length * 80}>
@@ -134,9 +164,20 @@ const interests = [
class="card card-interactive group flex h-full flex-col justify-center gap-2 border-dashed p-5 text-center"
style="border-color: color-mix(in srgb, var(--color-accent) 40%, transparent);"
>
<Icon name="briefcase" class="mx-auto h-7 w-7" style="color: var(--color-accent);" />
<p class="font-sans font-semibold" style="color: var(--color-text);">The other wing</p>
<p class="text-sm" style="color: var(--color-text-muted);">See where curiosity meets the day job.</p>
<Icon
name="briefcase"
class="mx-auto h-7 w-7"
style="color: var(--color-accent);"
/>
<p
class="font-sans font-semibold"
style="color: var(--color-text);"
>
The other wing
</p>
<p class="text-sm" style="color: var(--color-text-muted);">
See where curiosity meets the day job.
</p>
</a>
</Reveal>
</div>
+3 -7
View File
@@ -55,8 +55,8 @@ const projects = (await getCollection("projects")).sort(
<SectionHeader
kicker="Professional"
icon="briefcase"
title="Resume & portfolio"
subtitle="Clean, confident, skimmable. Browsable here, screenshot-able for a recruiter, printable if needed."
title="Resume & Portfolio"
subtitle="Clean, confident, skimmable."
/>
</Reveal>
<Reveal delay={80}>
@@ -152,7 +152,7 @@ const projects = (await getCollection("projects")).sort(
kicker="04"
icon="view-grid"
title="Projects"
subtitle="What I've built. Replace the placeholder with 3-6 of your own."
subtitle="What I've built. [TODO: Replace the placeholder with 3-6 of my projects]"
/>
</Reveal>
<div class="grid gap-5 sm:grid-cols-2">
@@ -164,10 +164,6 @@ const projects = (await getCollection("projects")).sort(
))
}
</div>
<Placeholder
label="Add 3-6 projects"
hint="Drop a new markdown file in src/content/projects/ for each notable project. See docs/CONTENT.md."
/>
</section>
{/* ===== 5. Education ===== */}