Reviewed-on: #37
🎨 Playground Frontend
This is the frontend of the Playground project. Built with Angular 21 and Angular Material, including a light/dark theme toggle and multi-language support (EN/DE) via ngx-translate.
The app is built as a static Single Page Application (SPA) served by NGINX, deployed at: 👉 https://app.andreas-dahm.eu
🧩 Tech Stack
| Component | Purpose |
|---|---|
| Angular 21 | Frontend framework (standalone components, signals, zoneless change detection) |
| Angular Material 21 | UI components & theming |
| Tailwind CSS 4 | Utility-first styling (CSS-first config, no tailwind.config.js) |
| ngx-translate 18 | i18n / instant translation |
| Babylon.js 9 | WebGL/WebGPU rendering for the algorithm demos |
| Swiper 14 | Image carousels in the project dialogs |
| Angular Service Worker | PWA / offline caching |
| NGINX | Serves the compiled SPA |
| Docker + Gitea Actions | Automated build, test & image publishing |
Requires Node.js 22.
📁 Project Structure
playground-frontend/
├─ src/
│ ├─ app/
│ │ ├─ layout/ # app shell, topbar, dialogs
│ │ ├─ pages/ # about, projects, algorithms, imprint, stopwatch, not-found
│ │ ├─ service/ # theme, language, SEO, GPU capability
│ │ ├─ shared/ # reusable components & helpers
│ │ ├─ constants/
│ │ ├─ app.config.ts
│ │ └─ app.routes.ts
│ ├─ assets/
│ │ ├─ i18n/ # en.json / de.json (keys must stay in sync)
│ │ ├─ logos/, flags/, icons/
│ │ └─ projects/ # project screenshots
│ ├─ tailwind.css # Tailwind entry + @theme tokens
│ ├─ styles.scss # Material theme setup & component overrides
│ └─ index.html
├─ scripts/check-i18n.mjs # fails the build on i18n key drift
├─ Dockerfile
├─ nginx.conf
├─ ngsw-config.json # service worker caching rules
├─ lighthouserc.json
└─ .gitea/workflows/build-Frontend-a.yml
🚀 Local Development
1. Install dependencies
npm install
2. Start development server
ng serve --open
App runs at http://localhost:4200
3. Docker build (local)
docker build -t playground-frontend:local .
docker run -p 8080:80 playground-frontend:local
Then open http://localhost:8080
🧪 Scripts
| Command | Purpose |
|---|---|
npm start |
Dev server |
npm run build |
Production build |
npm run watch |
Rebuild on change (development configuration) |
npm test |
Unit tests (Karma + Jasmine, headless Chrome) |
npm run lint |
ESLint over src/**/*.ts and src/**/*.html |
npm run i18n:check |
Verifies en.json and de.json share the exact same keys |
⚙️ Gitea Actions (CI/CD)
CI/CD runs on a self-hosted Gitea instance at git.andreas-dahm.eu.
Workflow file: .gitea/workflows/build-Frontend-a.yml
Triggered on every push to main and on pull requests targeting main.
Job 1 — quality-check (runs on both pushes and PRs):
- Lint & type check —
npm run lint - i18n key sync —
npm run i18n:check - Unit tests —
npx ng test --watch=false - Production build —
npx ng build --configuration production - Lighthouse audit —
npx lhci autorun(performance & SEO)
Job 2 — docker (only on a push to main, and only if quality-check passed):
Builds the image and pushes it to the Gitea container registry at git.andreas-dahm.eu
with these tags:
git.andreas-dahm.eu/<owner>/playground:frontend-a-<branch>
git.andreas-dahm.eu/<owner>/playground:frontend-a-<branch>-<short-sha>
git.andreas-dahm.eu/<owner>/playground:frontend-a-main
Required repository secret:
| Name | Description |
|---|---|
TOKEN_GITEA |
Gitea access token used to authenticate against the container registry |
🌐 Deployment
The built image is deployed via the playground-deploy repository on the Hostinger KVM
server using Traefik:
docker compose pull
docker compose up -d
✅ Live site at https://app.andreas-dahm.eu
🪄 Maintainer
Andreas Dahm 📧 andreas.dahm@gmail.com 🌐 https://andreas-dahm.eu