Personal website for Juan Karlo “JK” de Guzman. The site is intentionally personal rather than professional: it covers his interests, faith, teaching, technology, reading, ideas, and the questions he keeps returning to.
The project is an Astro application. The public page is prerendered, while the contact endpoint runs in the Cloudflare Workers adapter so Turnstile and Cloudflare Email Service secrets stay server-side. The page combines a shared Canvas 2D field, CSS-rendered section motifs, a small GSAP interaction layer, pointer/scroll response, and IntersectionObserver reveals.
Deployment: Cloudflare Workers is the only supported production target. A push to
maininItsAdventureTime/whoisjk-metriggers Cloudflare Workers Builds automatically. The former VPS, Podman, Caddy, Docker image, and Bunny material is historical and must not be used for releases.
- Astro
7.2.9with the@astrojs/cloudflareWorkers adapter. - Node.js
>=24.18.0. - pnpm
11.15.1, recorded inpackage.json. - TypeScript
6.0.3. - GSAP
3.15.0. - Wrangler
4.127.1. - Cloudflare Turnstile and Cloudflare Email Service.
- No database, remote font, or public email address.
src/pages/index.astro— page structure, copy, metadata, Canvas 2D script, and section state.app/globals.css— design tokens, responsive layout, motifs, surfaces, motion, and browser fallbacks.astro.config.mjs— Workers adapter configuration and canonical site URL.src/pages/api/contact.ts— same-origin JSON contact endpoint, Turnstile verification, validation, throttling, and Cloudflare Email Service delivery.wrangler.jsonc— Worker name, entrypoint, compatibility, rate limiter, and observability configuration.tests/rendered-html.test.mjs— build-output and design-invariant checks.CLOUDFLARE_WORKERS_DEPLOYMENT.md— Workers Builds setup and rollback runbook.RELEASE_WORKFLOW.md— local gate, commit, push, and automatic deployment workflow.scripts/sandbox-node.sh— pinned Node 24.18.0 runtime wrapper for local project checks inside Docker Sandbox.
Use the versions recorded in package.json and the lockfile. Run project
commands through the Docker Sandbox:
jk-sbx-project ensure
jk-sbx-project exec ./scripts/sandbox-node.sh node --version
jk-sbx-project exec ./scripts/sandbox-node.sh --with-pnpm pnpm --version
jk-sbx-project exec ./scripts/sandbox-node.sh --with-pnpm pnpm install --frozen-lockfile
jk-sbx-project exec ./scripts/sandbox-node.sh --with-pnpm pnpm devRun the source checks and rendered-output test before committing:
jk-sbx-project exec ./scripts/sandbox-node.sh --with-pnpm pnpm run check
jk-sbx-project exec ./scripts/sandbox-node.sh --with-pnpm pnpm testpnpm run check validates generated Worker types and Astro diagnostics.
pnpm test runs astro build and checks dist/client/index.html, important
copy, section motifs, the same-origin contact module, accessibility markers,
sensitive-content exclusions, email-address exclusions, and security headers.
For UI or interaction changes, also check desktop and narrow mobile widths, keyboard focus, active navigation, reduced motion, page overflow, and contact form pending/success/error feedback in a real browser.
The browser receives only the public Turnstile Site Key. The endpoint validates single-use tokens at Cloudflare before sending through Cloudflare Email Service, enforces field limits, rejects the honeypot and fast submissions, checks same-origin requests, and throttles forwarded client addresses. Message content and credentials are not logged.
In Cloudflare Dashboard → Workers & Pages → whoisjk-me → Settings →
Variables and Secrets, provision these plaintext environment variables:
TURNSTILE_SITE_KEYCONTACT_FROM
Provision these encrypted secrets:
TURNSTILE_SECRETCONTACT_TO
Also configure TURNSTILE_SITE_KEY in Settings → Builds → Build
variables and secrets; the prerendered homepage needs it at build time.
Never commit their values or put them in wrangler.jsonc. See
CLOUDFLARE_WORKERS_DEPLOYMENT.md for the
complete setup.
The UI follows WCAG 2.2 as its accessibility reference and preserves zoom,
reflow, source-order reading, visible focus, touch-safe targets, and reduced
motion. The page does not need Astro View Transitions or a client-side routing
layer. GSAP pointer motion and entrance transitions are scoped with
gsap.matchMedia(); ScrollTrigger is limited to the non-essential progress
indicator.
See DESIGN.md for the visual, content, responsive, motion, and
accessibility guide and SECURITY.md for the privacy and
release-scan policy.
The public copy reflects the latest personal-context review dated 2026-08-08. It adds JK’s early Windows 95-era curiosity, online English teaching since 2019, interdisciplinary interests, reading habits, social need for quiet, and the ongoing balance between open systems and practical convenience.
The site intentionally leaves out sensitive health and family-care details, exact city, birth year, age, unverified degree completion, credentials that are not needed for the personal introduction, and volatile device configuration. The source context file remains outside this public repository.
After every source, style, content, dependency, configuration, or documentation
change, follow RELEASE_WORKFLOW.md: run pnpm run check
and pnpm test in Docker Sandbox, review the diff, commit, and push to the
HTTPS origin on main. Cloudflare Workers Builds then builds and deploys the
connected Worker automatically.
The normal production domain is https://whoisjk.me/. The custom domain and
Worker secrets are managed in the Cloudflare Dashboard, never in Git.
- Use American English (
en-US) and a natural, conversational voice. - Keep sentences short, clear, and easy to scan.
- Keep the site personal; do not turn it into a résumé or generic portfolio.
- Do not publish JK’s age, year of birth, or personal email address.
- Use “Philippines,” not a more precise city.
- Preserve reduced-motion support, visible keyboard focus, and no-script access to the content.
- Keep the dark charcoal surfaces semi-transparent enough for the field to remain visible, but opaque enough for reading.
- No blur, backdrop blur, glow, or decorative shadow.