Rene De Ren a9f7434445 polish(helix): 3D occlusion + layered render for image quality
The biggest visual deficit was that both strands were drawn fully on
top of each other with a Gaussian-blur filter applied directly to the
sharp lines — so they read flat and slightly fuzzy.

What changed
- buildStrandSplit() carves each strand into front/back segments
  partitioned at every sin(ky)=0 crossing. Crossings are snapped to
  the exact y_c = n * PERIOD/2 so consecutive front/back segments
  meet seamlessly at (CX, y_c) with no visible gap.
- Render order is now strictly back → mid (rungs, per-project rungs,
  card connectors) → front, so front-strand portions occlude back-
  strand portions where they cross. Real 3D illusion.
- Glow is a separate blurred copy *underneath* the sharp path
  (stdDeviation 3.5, stroke-width 6-7). Sharp lines now stay crisp.
- Back portions render dimmed (opacity 0.62) for depth.
- Subtle white highlight stroke (stroke-width 0.9, alpha .55) is
  added on top of the front sharp strands — wet-ribbon specular feel.
- Path resolution doubled (steps ≈ H/1.8, was H/4). Coords use
  .toFixed(3) instead of .2. shape-rendering="geometricPrecision"
  on every load-bearing path.
- Decorative DNA-texture rungs were folded into a single pass that
  varies stroke-width and opacity by sin-depth, brighter for the
  "front side" rungs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:50:49 +02:00

HELIX

EVOLV and every R&D strand, one helix.

The R&D showcase platform of Waterschap Brabantse Delta. EVOLV at its core, every innovation along the strands.

HELIX collects projects, innovations, and updates from across the R&D team in one place — with deep links to repos, dashboards, and demos. Sign-in is gated to the RnD Gitea organisation; viewing is open.

Stack

  • SvelteKit 2 + Svelte 5 + TypeScript
  • Tailwind v4 (CSS-first design tokens)
  • SQLite (single file) + Drizzle ORM
  • Gitea OAuth2 for authoring (no passwords stored)
  • Pure SVG + CSS helix animation — no WebGL

Run it locally — two ways

Mirrors how the EVOLV stack is exercised locally. One command, named volume for SQLite, healthcheck wired:

cd /path/to/helix
docker compose up -d --build         # build image + start container
docker compose logs -f helix         # tail logs
# → http://localhost:3000

If port 3000 is in use (Node-RED, another dev server, …) pick another:

HELIX_PORT=3030 \
  ORIGIN=http://localhost:3030 \
  GITEA_REDIRECT_URI=http://localhost:3030/auth/gitea/callback \
  docker compose up -d --build
# → http://localhost:3030

Useful commands:

docker compose ps                                 # status + health
docker inspect helix --format '{{.State.Health.Status}}'
docker compose exec helix sh                      # shell into the container
docker compose exec helix sqlite3 /data/helix.db  # inspect the DB
docker compose down                               # stop (keeps the volume)
docker compose down -v                            # stop + DELETE all data

The SQLite database lives in the helix_helix-data named volume at /data/helix.db. Migrations + the idempotent seed both run on every boot. Once you have real content, set SEED_ON_BOOT=false in your env to stop re-seeding the demo entries.

2. Native Node (faster dev loop, hot reload)

nvm use                # .nvmrc → Node 20 (Tailwind v3 also works on 18)
cp .env.example .env   # fill in Gitea OAuth — see below

npm install
npm run db:generate    # generate drizzle/0000_*.sql from the schema
npm run db:migrate     # apply migrations to ./helix.db
npm run db:seed        # idempotent demo content
npm run dev            # http://localhost:5173

Gitea OAuth setup

HELIX uses your existing Gitea identity. Create an OAuth2 application once:

  1. Open https://gitea.wbd-rd.nl/-/user/settings/applications
  2. Click Create new OAuth2 application
  3. Application name: HELIX (local) (or HELIX (production))
  4. Redirect URI:
    • local: http://localhost:3000/auth/gitea/callback
    • prod: https://<your-helix-host>/auth/gitea/callback
  5. Click Create application
  6. Copy the Client ID and Client Secret into your .env:
    GITEA_CLIENT_ID=...
    GITEA_CLIENT_SECRET=...
    

GITEA_ALLOWED_ORG=RnD restricts authoring (sign-in) to members of the RnD organisation. Leave it empty to allow any authenticated Gitea user.

Adding a dashboard embed allowlist host

src/lib/config.tsDASHBOARD_ALLOWED_HOSTS controls which Grafana / dashboard origins can be embedded inline on a project page. Add a hostname (no scheme, no path) and redeploy. Hosts not on the list render as a "Open in new tab" card instead — never blindly iframed.

Production deploy

Same compose file as local. On the production host:

cp .env.example .env
# Set: ORIGIN=https://your-host, GITEA_REDIRECT_URI=https://your-host/auth/gitea/callback,
#      GITEA_CLIENT_ID, GITEA_CLIENT_SECRET (from a separate prod OAuth app)
docker compose up -d --build

Put a TLS-terminating reverse proxy (nginx/caddy/traefik) in front of port 3000. Back up the volume periodically:

docker compose exec helix sqlite3 /data/helix.db .dump | gzip > helix-backup-$(date +%F).sql.gz

Project layout

helix/
├── src/
│   ├── lib/
│   │   ├── components/         # Helix.svelte, ProjectCard, PostCard, Nav, Footer, DashboardEmbed
│   │   ├── server/
│   │   │   ├── db/             # Drizzle schema + client (better-sqlite3)
│   │   │   ├── auth.ts         # session token + cookie helpers
│   │   │   └── gitea.ts        # OAuth2 dance + user fetch
│   │   ├── config.ts           # site name, tagline, dashboard allowlist
│   │   └── markdown.ts         # marked wrapper + slug/id helpers
│   ├── routes/
│   │   ├── +page.svelte        # landing (helix hero + recent projects/posts)
│   │   ├── projects/           # /projects, /[slug], /new
│   │   ├── posts/              # /posts, /[slug], /new
│   │   ├── login/              # sign-in page (kicks off Gitea OAuth)
│   │   ├── logout/+server.ts   # POST → invalidates session
│   │   └── auth/gitea/         # OAuth start + callback
│   ├── app.html
│   ├── app.css                 # Tailwind v4 entry + design tokens
│   ├── app.d.ts                # Locals types
│   └── hooks.server.ts         # session hydration
├── drizzle/                    # generated migrations
├── scripts/
│   ├── migrate.js              # run pending migrations
│   └── seed.js                 # idempotent example data
├── static/favicon.svg
├── Dockerfile
├── docker-compose.yml
├── drizzle.config.ts
├── svelte.config.js
├── vite.config.ts
├── tailwind.config.ts (none — Tailwind v4 uses @theme in app.css)
├── tsconfig.json
└── package.json

How to post

After signing in (top-right → Sign in → Gitea), use:

  • + New in the nav (or /projects/new) — a project: title, summary, markdown body, links
  • /posts/new — a shorter update / write-up

Both are auth-gated. Anyone in RnD on Gitea can post.

Contributing

This is internal R&D — open a PR against main on gitea.wbd-rd.nl/RnD/helix.

License

Internal — Waterschap Brabantse Delta R&D.

Description
landing page R&D projects
Readme 195 KiB
Languages
Svelte 64.2%
TypeScript 23.3%
JavaScript 6.9%
CSS 3.8%
Dockerfile 1.2%
Other 0.6%