From 9a77bdb211ae30e7e2f7b97beeb0c1deeb581e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Fri, 7 Nov 2025 14:43:50 +0100 Subject: [PATCH] feat: add Pastel color palette generator to Kit stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added Pastel service with API and UI to the Kit toolkit: **New Services:** - pastel_api: Backend API for color palette generation - Image: ghcr.io/valknarness/pastel-api:latest - Routes: https://pastel.kit.pivoine.art/api - pastel_ui: Frontend UI for interactive palette generation - Image: ghcr.io/valknarness/pastel-ui:latest - Routes: https://pastel.kit.pivoine.art **Features:** - Color harmony algorithms - Interactive palette generation - Export in various formats - Programmatic API access - Path-based routing (UI on root, API on /api) **Configuration:** - Updated arty.yml with KIT_PASTEL_* variables - Updated documentation (CLAUDE.md, README.md) - Added Traefik labels with SSL, compression, security headers - Watchtower auto-update enabled Kit stack now includes 5 services: - Landing page (kit.pivoine.art) - Vert file converter (vert.kit.pivoine.art) - Paint image editor (paint.kit.pivoine.art) - Pastel color generator (pastel.kit.pivoine.art) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- CLAUDE.md | 29 ++++++++++++++++++++++++-- README.md | 14 +++++++++++-- arty.yml | 3 +++ kit/compose.yaml | 54 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1b6d721..435c1a3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -251,10 +251,11 @@ Joplin Server note-taking and synchronization platform: 5. Enter email and password created in step 1 ### Kit (kit/compose.yaml) -Unified toolkit with landing page, file conversion, and image editing using subdomain routing: +Unified toolkit with landing page, file conversion, image editing, and color palette generation using subdomain routing: - **Landing**: `kit.pivoine.art` - Toolkit landing page - **Vert**: `vert.kit.pivoine.art` - Universal file format converter - **Paint**: `paint.kit.pivoine.art` - Web-based image editor +- **Pastel**: `pastel.kit.pivoine.art` - Color palette generator (API + UI) #### Landing Page (kit.pivoine.art) Kit toolkit landing page: @@ -297,7 +298,31 @@ miniPaint web-based image editor built from GitHub: **Usage**: Access https://paint.kit.pivoine.art to use the image editor. All editing happens in the browser - images are not uploaded to the server. -**Note**: Both Kit services are stateless and don't require backups as no data is persisted. +#### Pastel Service (pastel.kit.pivoine.art) +Pastel color palette generator with API and UI: +- Generate beautiful color palettes +- API endpoint at `/api` for programmatic access +- Web UI for interactive palette generation +- Color harmony algorithms +- Export palettes in various formats +- Stateless architecture + +**Architecture**: +- **API**: Backend service handling color generation logic +- **UI**: Frontend application consuming the API + +**Images**: +- API: `ghcr.io/valknarness/pastel-api:latest` +- UI: `ghcr.io/valknarness/pastel-ui:latest` + +**Routing**: +- UI: `https://pastel.kit.pivoine.art` (root path) +- API: `https://pastel.kit.pivoine.art/api` (path prefix) + +**Usage**: +Access https://pastel.kit.pivoine.art to generate and explore color palettes interactively. + +**Note**: Kit services (Vert, Paint, Pastel) are stateless and don't require backups as no data is persisted. ### PairDrop (drop/compose.yaml) PairDrop peer-to-peer file sharing service: diff --git a/README.md b/README.md index 929766c..93ab3ee 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The **Falcon** is a state-of-the-art containerized starship, powered by Docker's | **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) | | **VAULT** | *Encrypted password vault* | [vault.pivoine.art](https://vault.pivoine.art) | | **JOPLIN** | *Note-taking server & sync hub* | [joplin.pivoine.art](https://joplin.pivoine.art) | -| **KIT** | *Toolkit hub with converter & editor* | [kit.pivoine.art](https://kit.pivoine.art) | +| **KIT** | *Toolkit hub with converter, editor & colors* | [kit.pivoine.art](https://kit.pivoine.art) | | **JELLY** | *Media streaming server* | [jelly.pivoine.art](https://jelly.pivoine.art) | | **DROP** | *Peer-to-peer file sharing* | [drop.pivoine.art](https://drop.pivoine.art) | | **RESTIC** | *Automated backup vault system* | [restic.pivoine.art](https://restic.pivoine.art) | @@ -222,6 +222,16 @@ arty env/sync # - Filters, drawing tools, text, shapes # - Supports PNG, JPG, GIF, WebP # - Client-side processing (no uploads) + +# Color Palette Generator (Pastel) +# URL: https://pastel.kit.pivoine.art +# API: https://pastel.kit.pivoine.art/api +# Features: +# - Generate beautiful color palettes +# - Color harmony algorithms +# - Interactive palette generation +# - Export in various formats +# - Programmatic API access ``` ### Backup Operations (RESTIC System) @@ -278,7 +288,7 @@ THE FALCON (falcon_network) │ ├─ Linkwarden Marks [links.pivoine.art] │ ├─ Vaultwarden Vault [vault.pivoine.art] │ ├─ Joplin Sync Server [joplin.pivoine.art] -│ ├─ Kit Toolkit [vert.kit.pivoine.art, paint.kit.pivoine.art] +│ ├─ Kit Toolkit [vert.kit.pivoine.art, paint.kit.pivoine.art, pastel.kit.pivoine.art] │ ├─ Jellyfin Media [jelly.pivoine.art] │ ├─ PairDrop Sharing [drop.pivoine.art] │ ├─ Backrest Backups [restic.pivoine.art] diff --git a/arty.yml b/arty.yml index 130e289..f502402 100644 --- a/arty.yml +++ b/arty.yml @@ -118,6 +118,9 @@ envs: KIT_VERT_IMAGE: ghcr.io/vert-sh/vert:latest KIT_VERT_TRAEFIK_HOST: vert.kit.pivoine.art KIT_PAINT_TRAEFIK_HOST: paint.kit.pivoine.art + KIT_PASTEL_API_IMAGE: ghcr.io/valknarness/pastel-api:latest + KIT_PASTEL_UI_IMAGE: ghcr.io/valknarness/pastel-ui:latest + KIT_PASTEL_TRAEFIK_HOST: pastel.kit.pivoine.art # Jellyfin JELLY_TRAEFIK_ENABLED: true JELLY_COMPOSE_PROJECT_NAME: jelly diff --git a/kit/compose.yaml b/kit/compose.yaml index a1bd24a..1e90342 100644 --- a/kit/compose.yaml +++ b/kit/compose.yaml @@ -69,7 +69,7 @@ services: - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web.middlewares=${KIT_COMPOSE_PROJECT_NAME}-paint-redirect-web-secure' - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web.rule=Host(`${KIT_PAINT_TRAEFIK_HOST}`)' - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web.entrypoints=web' - # HTTPS router with auth + # HTTPS router - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web-secure.rule=Host(`${KIT_PAINT_TRAEFIK_HOST}`)' - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-paint-web-secure.entrypoints=web-secure' @@ -81,6 +81,58 @@ services: # Watchtower - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + pastel_api: + image: ${KIT_PASTEL_API_IMAGE:-ghcr.io/valknarness/pastel-api:latest} + container_name: ${KIT_COMPOSE_PROJECT_NAME}_pastel_api + restart: unless-stopped + networks: + - compose_network + labels: + - 'traefik.enable=${KIT_TRAEFIK_ENABLED}' + # HTTP to HTTPS redirect + - 'traefik.http.middlewares.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-redirect-web-secure.redirectscheme.scheme=https' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web.middlewares=${KIT_COMPOSE_PROJECT_NAME}-pastel-api-redirect-web-secure' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web.rule=Host(`${KIT_PASTEL_TRAEFIK_HOST}`) && PathPrefix(`/api`)' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web.entrypoints=web' + # HTTPS router + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web-secure.rule=Host(`${KIT_PASTEL_TRAEFIK_HOST}`) && PathPrefix(`/api`)' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web-secure.tls.certresolver=resolver' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web-secure.entrypoints=web-secure' + - 'traefik.http.middlewares.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-compress.compress=true' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-api-web-secure.middlewares=${KIT_COMPOSE_PROJECT_NAME}-pastel-api-compress,security-headers@file' + # Service + - 'traefik.http.services.${KIT_COMPOSE_PROJECT_NAME}-pastel-api.loadbalancer.server.port=80' + - 'traefik.docker.network=${NETWORK_NAME}' + # Watchtower + - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + + pastel_ui: + image: ${KIT_PASTEL_UI_IMAGE:-ghcr.io/valknarness/pastel-ui:latest} + container_name: ${KIT_COMPOSE_PROJECT_NAME}_pastel_ui + restart: unless-stopped + networks: + - compose_network + labels: + - 'traefik.enable=${KIT_TRAEFIK_ENABLED}' + # HTTP to HTTPS redirect + - 'traefik.http.middlewares.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-redirect-web-secure.redirectscheme.scheme=https' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web.middlewares=${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-redirect-web-secure' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web.rule=Host(`${KIT_PASTEL_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web.entrypoints=web' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web.priority=1' + # HTTPS router + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web-secure.rule=Host(`${KIT_PASTEL_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web-secure.tls.certresolver=resolver' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web-secure.entrypoints=web-secure' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web-secure.priority=1' + - 'traefik.http.middlewares.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-compress.compress=true' + - 'traefik.http.routers.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-web-secure.middlewares=${KIT_COMPOSE_PROJECT_NAME}-pastel-ui-compress,security-headers@file' + # Service + - 'traefik.http.services.${KIT_COMPOSE_PROJECT_NAME}-pastel-ui.loadbalancer.server.port=80' + - 'traefik.docker.network=${NETWORK_NAME}' + # Watchtower + - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + networks: compose_network: name: ${NETWORK_NAME}