• TypeScript 73.3%
  • JavaScript 15.7%
  • CSS 10.5%
  • Dockerfile 0.5%
Find a file
Noah Arndt Serafim f8dee1b98a
All checks were successful
/ build-image (push) Successful in 43s
Reuse and preload the playground worker
2026-10-19 10:10:22 +02:00
.forgejo/workflows Add chatbot 2026-05-09 18:33:10 +02:00
app Add detlef project page and playground 2026-10-18 19:30:40 +02:00
components Reuse and preload the playground worker 2026-10-19 10:10:22 +02:00
lib Add detlef project page and playground 2026-10-18 19:30:40 +02:00
public Reuse and preload the playground worker 2026-10-19 10:10:22 +02:00
scripts Add detlef project page and playground 2026-10-18 19:30:40 +02:00
tests Reuse and preload the playground worker 2026-10-19 10:10:22 +02:00
.dockerignore Add detlef project page and playground 2026-10-18 19:30:40 +02:00
.gitignore Add detlef project page and playground 2026-10-18 19:30:40 +02:00
.npmrc Add chatbot 2026-05-09 18:33:10 +02:00
AGENTS.md Create next app 2026-04-19 12:34:27 +02:00
CLAUDE.md Create next app 2026-04-19 12:34:27 +02:00
components.json feat: initial commit 2026-04-19 12:37:46 +02:00
detlef-runtime.json Add detlef project page and playground 2026-10-18 19:30:40 +02:00
Dockerfile Fix args in wrong stage and hardcoded turnstile site key 2026-05-09 19:27:02 +02:00
eslint.config.mjs Add detlef project page and playground 2026-10-18 19:30:40 +02:00
LICENSE Add license 2026-05-09 20:03:09 +02:00
next.config.ts Add detlef project page and playground 2026-10-18 19:30:40 +02:00
package-lock.json Add chatbot 2026-05-09 18:33:10 +02:00
package.json Add detlef project page and playground 2026-10-18 19:30:40 +02:00
postcss.config.mjs Create next app 2026-04-19 12:34:27 +02:00
README.md Reuse and preload the playground worker 2026-10-19 10:10:22 +02:00
tsconfig.json Create next app 2026-04-19 12:34:27 +02:00

Personal Website

License

Personal portfolio website built with:

  • Next.js
  • TypeScript
  • Tailwind CSS
  • shadcn/ui

Includes:

  • portfolio/projects
  • blog/articles
  • chatbot integration
  • multilingual support

Development

Install dependencies:

npm install

Start development server:

npm run dev

Environment Variables

NEXT_PUBLIC_CHAT_API_URL=/api/chat
NEXT_PUBLIC_TURNSTILE_SITE_KEY=...

Production

The site is deployed as a Docker container behind Nginx.

Detlef playground

/projects/detlef runs the release-built Wasm interpreter in a browser worker. The console supports print() and read_line(), including empty lines and EOF. Each run starts a fresh interpreter instance while reusing the worker and loaded Wasm module. The worker starts loading when the playground mounts, before the first run. Program output comes only from explicit print() calls; expression results are not echoed. Programs can run until they finish or Stop is pressed. Stop terminates the worker and immediately preloads a replacement. Worker failures and Wasm traps terminate it; the next run loads a replacement. Normal completion and ordinary language errors reuse it.

detlef-runtime.json pins the Forgejo release archive and its SHA-256 checksum. npm run dev, npm run build, and npm run test:detlef prepare the runtime automatically through their npm pre-scripts. It can also be prepared explicitly:

npm run prepare:detlef

Preparation requires Node.js and tar (available on Windows, macOS, and in the Alpine Docker image). The first run downloads the pinned SDK over HTTPS and verifies its checksum before extracting only the JavaScript modules, browser bindings, Wasm binary, and license into public/detlef/runtime/. That directory and the archive cache in .cache/detlef/ are generated and ignored by Git. Verified installed files are reused offline; missing or modified files are restored from the verified cache. Download, checksum, and extraction failures stop preparation instead of falling back to another release. A corrupt cached archive can be removed from .cache/detlef/ before retrying.

To update Detlef, change the version, archive URL, and SHA-256 in detlef-runtime.json, using the matching entry from that release's SHA256SUMS. Then run npm run test:detlef and npm run build before committing the new pin. The Docker build performs the same preparation and ships the generated runtime in the final image; SDK files and downloads are not needed at container startup. The worker, website integrations, logos, and favicons remain website source assets.

The worker uses shared memory so the synchronous read_line() can wait without blocking React. Cross-origin isolation headers are configured only for this project page and its runtime files. They must also be retained by the production proxy. The project card uses a full navigation because client routing alone does not apply new document headers. Cross-origin embeds on this page must support its isolation policy. The Wasm build remains experimental.

The playground also exposes these site functions:

Function Behavior
set_design("light" / "dark" / "aero") Change the site theme.
get_design() Read the active theme (including the resolved system theme).
set_language("de" / "en") Change the site language.
get_language() Read the site language.
set_font("comic" / "impact" / "mono" / "wingdings" / "reset") Set or reset the bonus font.
clear_console() Clear the output, including text buffered in the worker.
barrel_roll() Spin the page, at most once per second.
retro(true) / retro(false) Enable or disable the playground's Windows 95 look.

Setters return none on success or a descriptive error string for invalid values; use optional(string) and is_none() to handle the result without stopping the program. Wrong argument types or arity still use normal Detlef diagnostics. Settings persist through the existing website controls. Site changes are limited to 128 per run. A separate shared-memory channel lets these synchronous functions wait for the browser's response while keeping the page responsive.

Retro mode affects only the playground and lasts across runs until the page is left or reloaded. Use retro(true) to enable it and retro(false) to restore the current site design. Repeating the same call keeps the requested state. Like the other setters, it returns none on success.