Public
Remixed
Basic HTML starter template based on Glitch's starter
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

James Maciej Krywin — Portfolio

A personal portfolio site with a header, hero photo, About / Experience / Projects / Contact sections, a subscribe modal that saves leads to a database, and a private admin page to email those subscribers a marketing campaign.

Pages & routes

RouteWhat it does
/Public portfolio. Hero "Stay in touch" button opens a modal that POSTs to /api/subscribe.
/adminPrivate campaign composer. Enter your admin token, write a subject + message, and send to all subscribers.
POST /api/subscribeValidates and saves { name, email } to the subscribers SQLite table.
POST /api/send-campaignAdmin-only (requires ADMIN_TOKEN). Emails every subscriber via Resend.
/sourceRedirects to the val's source code.

Files

FileRole
main.tsxHTTP server + API routes.
index.html / style.css / script.jsThe public site and subscribe modal.
admin.html / admin.jsThe private campaign page.
db.tsSQLite schema + addSubscriber().
marketing.tssendCampaign() — fans out emails through the Resend API.

Setup for sending email

Val Town's built-in std/email can only email you, so this uses Resend (free tier: 100/day, 3,000/month) to reach real subscribers. Three environment variables:

  1. RESEND_API_KEY — create a key at https://resend.com/api-keys.
  2. ADMIN_TOKEN — any long random string. It protects /api/send-campaign so only you can trigger a send. You'll type it into the /admin page.
  3. FROM_EMAIL (optional) — e.g. James <hello@yourdomain.com>. Requires a domain verified in Resend. Until then it defaults to onboarding@resend.dev, which only delivers to your own Resend account email (fine for testing).

Set them in the val's Environment Variables tab.

Personalization

In the campaign subject or body, {{name}} is replaced with each subscriber's name (falls back to "there" if empty).

Viewing subscribers

They live in this val's SQLite subscribers table (id, name, email, created_at) — browse it in the val's Database tab.

Structure

Rendering mermaid diagram...