Bilingual (DE/EN) personal site of Philip Demole Lortz — short stories, screenplay work, contact. Built as a static SvelteKit site, prerendered at build time and served as plain files.
- SvelteKit + Svelte 5 — routing, SSR/prerender
- adapter-static — outputs a fully static site to
build/ - mdsvex — Markdown posts rendered as Svelte components (frontmatter parsed automatically)
- Vite 8 — dev server with HMR
- TypeScript
- pnpm
pnpm install
pnpm run dev # http://localhost:5173 (HMR)
pnpm run build # outputs to build/
pnpm run preview # serve build/ locally
pnpm run check # svelte-check type check
pnpm run deploy # build + push to lortz.pages.dev via wranglerdeploy uses pnpm dlx wrangler@latest pages deploy build --project-name=lortz.
Wrangler is fetched on demand, so no local install is needed — but you must be logged in once (pnpm dlx wrangler@latest login).
To serve the production build with any static server, e.g.:
python -m http.server 4173 --directory buildsrc/
app.css global styles (responsive rules, hamburger, cards)
app.html SvelteKit HTML shell
lib/
components/Header.svelte top nav + lang toggle + mobile hamburger
components/Footer.svelte legal links
i18n.ts Lang type, t(lang), pathPrefix(lang)
posts.ts getAllPosts(lang) — globs src/posts/**/*.md
params/lang.ts URL param matcher for /en/
posts/
de/*.md German posts (frontmatter + body)
en/*.md English posts
routes/
+layout.svelte Header + <slot/> + Footer
[[lang=lang]]/+page.svelte home (post grid)
[[lang=lang]]/post/[slug]/+page.svelte single post
[[lang=lang]]/work/+page.svelte work page
[[lang=lang]]/contact/+page.svelte contact page
datenschutz/+page.svelte privacy (DE legal)
impressum/+page.svelte imprint (DE legal)
static/
images/ cover art, work images
Posts live as Markdown files under src/posts/<lang>/<slug>.md.
<lang> is de or en — the folder name is the post's language.
Each post starts with YAML frontmatter:
---
title: "Die Katze"
date: "2025-11-15" # ISO, used for sorting
displayDate: "15. Nov. 2025" # shown in UI
author: "Philip Demole Lortz"
readingTime: "3 Min. Lesezeit"
excerpt: "…short teaser…"
cover: "/images/die-katze.webp" # path under static/
coverAlt: "Die Katze"
translationSlug: "die-katze-1" # slug of the counterpart in the other language (optional)
---
Body in Markdown / mdsvex…Posts are discovered at build time by src/lib/posts.ts via import.meta.glob('/src/posts/*/*.md').
No database, no CMS — add a file, rebuild, it shows up. Sorted by date descending.
- Drop the
.webpcover intostatic/images/. - Create
src/posts/de/my-slug.mdwith frontmatter above. - (Optional) Create the translated version at
src/posts/en/my-slug-1.mdand cross-link them viatranslationSlug. pnpm run build.
/→ German home,/en/→ English home./post/<slug>/→ German post,/en/post/<slug>/→ English post.- Language is derived from the URL via the
[[lang=lang]]optional param andsrc/params/lang.ts. pathPrefix(lang)returns''fordeand/enforen; used everywhere links are built.- The header's language toggle uses
translationSlugfrom the current post's frontmatter to switch to the matching post in the other language.
All styles are global in src/app.css. Key responsive breakpoint is max-width: 860px:
- Header collapses into a hamburger menu (see
.hamburger+.site-header.menu-open). - Post grid switches to single-column horizontal cards (small square cover on the left, text on the right).
Fonts: Anton (display) + Barlow Condensed (UI) via Google Fonts.