@whykusanagi/corrupted-theme 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +339 -0
- package/Dockerfile +32 -0
- package/LICENSE +21 -0
- package/README.md +399 -0
- package/docker-entrypoint.sh +48 -0
- package/docs/COMPONENTS_REFERENCE.md +659 -0
- package/examples/.env.example +100 -0
- package/examples/button.html +436 -0
- package/examples/card.html +678 -0
- package/examples/form.html +555 -0
- package/examples/index.html +520 -0
- package/examples/layout.html +507 -0
- package/examples/nikke-team-builder.html +580 -0
- package/examples/showcase-complete.html +1071 -0
- package/examples/showcase.html +502 -0
- package/package.json +70 -0
- package/scripts/celeste-proxy-server.js +99 -0
- package/scripts/static-server.js +113 -0
- package/src/css/animations.css +649 -0
- package/src/css/components.css +1441 -0
- package/src/css/glassmorphism.css +217 -0
- package/src/css/nikke-utilities.css +530 -0
- package/src/css/theme.css +478 -0
- package/src/css/typography.css +198 -0
- package/src/css/utilities.css +239 -0
- package/src/css/variables.css +73 -0
- package/src/lib/celeste-proxy.js +215 -0
- package/src/lib/celeste-widget.js +1089 -0
- package/src/lib/corrupted-text.js +193 -0
- package/src/lib/corruption-loading.js +405 -0
package/README.md
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# Corrupted Theme
|
|
2
|
+
|
|
3
|
+
A production-ready glassmorphic design system for cinematic, cyberpunk-inspired applications. Built as a drop-in CSS framework with JS enhancements, Docker showcase, and npm distribution standards on par with Meta/Google/Netflix internal libraries.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Overview](#overview)
|
|
7
|
+
2. [Installation](#installation)
|
|
8
|
+
3. [Project Architecture](#project-architecture)
|
|
9
|
+
4. [Base Layout & Background](#base-layout--background)
|
|
10
|
+
5. [CSS & JS Imports](#css--js-imports)
|
|
11
|
+
6. [Component Quick Reference](#component-quick-reference)
|
|
12
|
+
7. [Animations & Experience Layer](#animations--experience-layer)
|
|
13
|
+
8. [Nikke Utilities](#nikke-utilities)
|
|
14
|
+
9. [Customization & Tokens](#customization--tokens)
|
|
15
|
+
10. [Coding Standards](#coding-standards)
|
|
16
|
+
11. [Development Workflow](#development-workflow)
|
|
17
|
+
12. [Testing & QA Expectations](#testing--qa-expectations)
|
|
18
|
+
13. [Support](#support)
|
|
19
|
+
14. [Celeste Widget Integration](#celeste-widget-integration-optional)
|
|
20
|
+
15. [License](#license)
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
- **Glassmorphism-first** visual language with layered depth, gradients, and scanlines.
|
|
24
|
+
- **Systemized tokens** (`src/css/variables.css`) for colors, typography, spacing, motion, and elevation.
|
|
25
|
+
- **Bootstrap-scale coverage** of components (navigation, forms, data display, API docs, Nikke-specific UI).
|
|
26
|
+
- **First-visit cinematic experiences** via `corrupted-text.js` and `corruption-loading.js`.
|
|
27
|
+
- **WCAG AA** compliance, motion safety, and keyboard support baked in.
|
|
28
|
+
- **Dockerized showcase** at `examples/showcase-complete.html` for instant QA.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
### npm (public registry)
|
|
32
|
+
```bash
|
|
33
|
+
npm install @whykusanagi/corrupted-theme
|
|
34
|
+
```
|
|
35
|
+
```css
|
|
36
|
+
@import '@whykusanagi/corrupted-theme';
|
|
37
|
+
/* or scoped imports */
|
|
38
|
+
@import '@whykusanagi/corrupted-theme/variables';
|
|
39
|
+
@import '@whykusanagi/corrupted-theme/components';
|
|
40
|
+
```
|
|
41
|
+
> Tip: make sure you are logged in with `npm login` if the package is private. No `.npmrc` token is needed for the public release.
|
|
42
|
+
|
|
43
|
+
### CDN (when mirrored)
|
|
44
|
+
```html
|
|
45
|
+
<link rel="stylesheet" href="https://s3.whykusanagi.xyz/corrupted-theme/theme.css">
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Manual Copy
|
|
49
|
+
Copy `src/css` into your project (or use `dist/theme.min.css`) and import it locally.
|
|
50
|
+
|
|
51
|
+
## Project Architecture
|
|
52
|
+
```
|
|
53
|
+
.
|
|
54
|
+
├── src/
|
|
55
|
+
│ ├── css/
|
|
56
|
+
│ │ ├── variables.css # design tokens
|
|
57
|
+
│ │ ├── typography.css # font stack + hierarchy
|
|
58
|
+
│ │ ├── glassmorphism.css # shared glass utilities
|
|
59
|
+
│ │ ├── animations.css # motion + corruption keyframes
|
|
60
|
+
│ │ ├── components.css # UI primitives + layouts
|
|
61
|
+
│ │ ├── utilities.css # spacing, flex, layout utilities
|
|
62
|
+
│ │ └── theme.css # entry point (imports all modules)
|
|
63
|
+
│ └── lib/
|
|
64
|
+
│ ├── corrupted-text.js # multi-language glitch animation
|
|
65
|
+
│ └── corruption-loading.js# cinematic loading curtain
|
|
66
|
+
├── dist/theme.min.css # postcss + cssnano build output
|
|
67
|
+
├── examples/showcase-complete.html
|
|
68
|
+
├── scripts/static-server.js # ESM static server (Docker)
|
|
69
|
+
└── docs/COMPONENTS_REFERENCE.md # exhaustive snippets
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**npm scripts**
|
|
73
|
+
- `npm run build` – compiles `dist/theme.min.css`
|
|
74
|
+
- `npm run watch` – rebuilds on change (dev use)
|
|
75
|
+
- `npm run dev:static` – serves `/examples` (port 8000)
|
|
76
|
+
- `npm run dev:proxy` – Celeste proxy (port 5000)
|
|
77
|
+
|
|
78
|
+
## Base Layout & Background
|
|
79
|
+
```html
|
|
80
|
+
<body>
|
|
81
|
+
<video class="background-media" autoplay muted loop playsinline>
|
|
82
|
+
<source src="/media/corruption-loop.mp4" type="video/mp4" />
|
|
83
|
+
</video>
|
|
84
|
+
<div class="glass-backdrop"></div>
|
|
85
|
+
<main class="app-shell"><!-- your glass UI --></main>
|
|
86
|
+
</body>
|
|
87
|
+
```
|
|
88
|
+
```css
|
|
89
|
+
html, body { min-height: 100vh; background: var(--bg); margin: 0; }
|
|
90
|
+
.background-media { position: fixed; inset: 0; object-fit: cover; z-index: -2; }
|
|
91
|
+
.glass-backdrop { position: fixed; inset: 0; background: linear-gradient(180deg, rgba(5,0,16,.85), rgba(10,10,10,.9)); z-index: -1; }
|
|
92
|
+
.app-shell { position: relative; z-index: 1; padding: clamp(1.5rem, 3vw, 3rem); backdrop-filter: blur(0); }
|
|
93
|
+
```
|
|
94
|
+
Use `.app-shell` as the only stacking context above the backdrop so containers never block the video/image layer.
|
|
95
|
+
|
|
96
|
+
## CSS & JS Imports
|
|
97
|
+
```html
|
|
98
|
+
<link rel="stylesheet" href="@whykusanagi/corrupted-theme/dist/theme.min.css">
|
|
99
|
+
<script type="module" src="@whykusanagi/corrupted-theme/src/lib/corrupted-text.js"></script>
|
|
100
|
+
<script type="module" src="@whykusanagi/corrupted-theme/src/lib/corruption-loading.js"></script>
|
|
101
|
+
```
|
|
102
|
+
```js
|
|
103
|
+
import { initCorruptedText } from '@whykusanagi/corrupted-theme/src/lib/corrupted-text.js';
|
|
104
|
+
import { showCorruptionLoading } from '@whykusanagi/corrupted-theme/src/lib/corruption-loading.js';
|
|
105
|
+
|
|
106
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
107
|
+
initCorruptedText(); // re-init if you stream new DOM
|
|
108
|
+
// showCorruptionLoading({ force: true }); // force-run outside 72h cadence
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Component Quick Reference
|
|
113
|
+
The snippets below mirror the canonical showcase. For the full catalog (tabs, modals, tables, API docs, Nikke cards, etc.) keep `docs/COMPONENTS_REFERENCE.md` open beside this README.
|
|
114
|
+
|
|
115
|
+
### Glass Kit
|
|
116
|
+
```html
|
|
117
|
+
<div class="glass-card p-xl">
|
|
118
|
+
<h3>Glass Card</h3>
|
|
119
|
+
<p>Enhanced glass depth layer.</p>
|
|
120
|
+
<input class="glass-input" placeholder="glass input" />
|
|
121
|
+
<button class="glass-button">Primary Action</button>
|
|
122
|
+
<pre class="glass-code">const example = 'Hello';</pre>
|
|
123
|
+
</div>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Buttons & Utilities
|
|
127
|
+
```html
|
|
128
|
+
<div class="flex-center gap-md">
|
|
129
|
+
<button class="btn">Primary</button>
|
|
130
|
+
<button class="btn secondary">Secondary</button>
|
|
131
|
+
<button class="btn ghost">Ghost</button>
|
|
132
|
+
<button class="btn sm">Compact</button>
|
|
133
|
+
<button class="btn lg block">Full Width</button>
|
|
134
|
+
</div>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Forms
|
|
138
|
+
```html
|
|
139
|
+
<form class="glass-card p-xl">
|
|
140
|
+
<label>Name</label>
|
|
141
|
+
<input type="text" class="glass-input" required>
|
|
142
|
+
<label>Message</label>
|
|
143
|
+
<textarea class="glass-input" rows="3"></textarea>
|
|
144
|
+
<button class="glass-button">Send</button>
|
|
145
|
+
</form>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Navigation
|
|
149
|
+
```html
|
|
150
|
+
<nav class="navbar">
|
|
151
|
+
<div class="navbar-content">
|
|
152
|
+
<a class="navbar-logo" href="/">whyku</a>
|
|
153
|
+
<ul class="navbar-links">
|
|
154
|
+
<li><a href="#glass" class="active">Glass</a></li>
|
|
155
|
+
<li><a href="#components">Components</a></li>
|
|
156
|
+
<li class="has-submenu">
|
|
157
|
+
<a href="#products">Products <i class="fas fa-chevron-down"></i></a>
|
|
158
|
+
<div class="submenu">
|
|
159
|
+
<a href="#one">Product 1</a>
|
|
160
|
+
<a href="#two">Product 2</a>
|
|
161
|
+
</div>
|
|
162
|
+
</li>
|
|
163
|
+
</ul>
|
|
164
|
+
</div>
|
|
165
|
+
</nav>
|
|
166
|
+
<button class="navbar-toggle" onclick="toggleNavbar(this)">
|
|
167
|
+
<span class="icon"><span></span><span></span><span></span></span>
|
|
168
|
+
</button>
|
|
169
|
+
<ul class="navbar-links"><!-- mobile nav --></ul>
|
|
170
|
+
```
|
|
171
|
+
```js
|
|
172
|
+
function toggleNavbar(button) {
|
|
173
|
+
const menu = document.querySelector('.navbar-links');
|
|
174
|
+
menu.classList.toggle('active');
|
|
175
|
+
button.classList.toggle('active');
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Dropdown
|
|
180
|
+
```html
|
|
181
|
+
<div class="dropdown">
|
|
182
|
+
<button class="dropdown-toggle" onclick="toggleDropdown(this)">Menu <i class="fas fa-chevron-down"></i></button>
|
|
183
|
+
<div class="dropdown-menu">
|
|
184
|
+
<a class="dropdown-item">Action</a>
|
|
185
|
+
<a class="dropdown-item">Settings</a>
|
|
186
|
+
<div class="dropdown-divider"></div>
|
|
187
|
+
<a class="dropdown-item">Logout</a>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
```
|
|
191
|
+
```js
|
|
192
|
+
function toggleDropdown(button) {
|
|
193
|
+
const menu = button.nextElementSibling;
|
|
194
|
+
const open = menu.classList.contains('active');
|
|
195
|
+
document.querySelectorAll('.dropdown-menu').forEach(m => m.classList.remove('active'));
|
|
196
|
+
document.querySelectorAll('.dropdown-toggle').forEach(b => b.classList.remove('active'));
|
|
197
|
+
if (!open) {
|
|
198
|
+
menu.classList.add('active');
|
|
199
|
+
button.classList.add('active');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
document.addEventListener('click', e => {
|
|
203
|
+
if (!e.target.closest('.dropdown')) {
|
|
204
|
+
document.querySelectorAll('.dropdown-menu').forEach(m => m.classList.remove('active'));
|
|
205
|
+
document.querySelectorAll('.dropdown-toggle').forEach(b => b.classList.remove('active'));
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Data & API
|
|
211
|
+
```html
|
|
212
|
+
<table class="table table-striped">
|
|
213
|
+
<thead><tr><th>Name</th><th>Email</th><th>Status</th></tr></thead>
|
|
214
|
+
<tbody>
|
|
215
|
+
<tr><td>Eve</td><td>eve@demo.com</td><td><span class="badge success">Active</span></td></tr>
|
|
216
|
+
<tr><td>Dan</td><td>dan@demo.com</td><td><span class="badge warning">Pending</span></td></tr>
|
|
217
|
+
</tbody>
|
|
218
|
+
</table>
|
|
219
|
+
|
|
220
|
+
<div class="api-endpoint">
|
|
221
|
+
<div class="flex items-center gap-md">
|
|
222
|
+
<span class="api-method get">GET</span>
|
|
223
|
+
<code class="api-path">/api/v1/units</code>
|
|
224
|
+
</div>
|
|
225
|
+
<p class="api-description">Retrieve a list of units.</p>
|
|
226
|
+
<div class="api-param">
|
|
227
|
+
<span class="api-param-name">element</span>
|
|
228
|
+
<span class="api-param-type">string</span>
|
|
229
|
+
<span class="api-param-required">optional</span>
|
|
230
|
+
<p class="api-param-description">Filter by element type.</p>
|
|
231
|
+
</div>
|
|
232
|
+
<div class="api-response">
|
|
233
|
+
<div class="api-response-title">200 OK</div>
|
|
234
|
+
<pre class="api-response-code">{"data": []}</pre>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Corrupted Text & Loader
|
|
240
|
+
```html
|
|
241
|
+
<span class="corrupted-text" data-text="CORRUPTED">CORRUPTED</span>
|
|
242
|
+
<span class="glitch-kanji">
|
|
243
|
+
<span class="glitch-word" data-text="CORRUPTED TEXT">CORRUPTED TEXT</span>
|
|
244
|
+
</span>
|
|
245
|
+
```
|
|
246
|
+
```html
|
|
247
|
+
<video class="background-media" autoplay muted loop playsinline>
|
|
248
|
+
<source src="/media/corruption-loop.mp4" type="video/mp4" />
|
|
249
|
+
</video>
|
|
250
|
+
<script type="module" src="@whykusanagi/corrupted-theme/src/lib/corruption-loading.js"></script>
|
|
251
|
+
<script>
|
|
252
|
+
showCorruptionLoading(); // auto once every 72h
|
|
253
|
+
// showCorruptionLoading({ force: true });
|
|
254
|
+
</script>
|
|
255
|
+
```
|
|
256
|
+
Japanese overlay text is sourced from the lewd phrase array inside `examples/showcase-complete.html`; supply your own by updating the data attribute or reusing the script snippet.
|
|
257
|
+
|
|
258
|
+
## Animations & Experience Layer
|
|
259
|
+
Class | Behavior
|
|
260
|
+
--- | ---
|
|
261
|
+
`.fade-in`, `.fade-up`, `.slide-in-left/right`, `.scale-in` | Standard entrance motions synchronized to `var(--transition)`
|
|
262
|
+
`.glitch-word`, `.glitch-kanji` | Fragmented glitch with horizontal scanlines + JP overlays
|
|
263
|
+
`.corrupted-text`, `.corrupted-strong` | Brute-force corruption effect for headings and pills
|
|
264
|
+
`.scanlines`, `.tear`, `.data-corrupt` | Utility effects inspired by whykusanagi.xyz hero
|
|
265
|
+
`.spinner`, `.loading-bar`, `.progress-bar` | Loading indicators with shimmer + accent variants
|
|
266
|
+
`.corruption-loading` (JS) | Full-screen loader with 72h replay timer
|
|
267
|
+
`.corrupted-multilang` (JS) | First-visit Japanese/English/Romaji cycling text
|
|
268
|
+
|
|
269
|
+
## Nikke Utilities
|
|
270
|
+
```html
|
|
271
|
+
<div class="element-pills">
|
|
272
|
+
<button class="element-pill water">Water</button>
|
|
273
|
+
<button class="element-pill wind active">Wind</button>
|
|
274
|
+
<button class="element-pill iron">Iron</button>
|
|
275
|
+
<button class="element-pill electric">Electric</button>
|
|
276
|
+
<button class="element-pill fire">Fire</button>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="team-position-cards">
|
|
279
|
+
<div class="position-card filled">
|
|
280
|
+
<div class="position-header">
|
|
281
|
+
<span class="position-number">1</span>
|
|
282
|
+
<span class="position-label">Front Left</span>
|
|
283
|
+
</div>
|
|
284
|
+
<div class="position-content">
|
|
285
|
+
<div class="unit-display">
|
|
286
|
+
<div class="unit-name">Scarlet Priest Abe</div>
|
|
287
|
+
</div>
|
|
288
|
+
<button class="remove-unit" aria-label="Remove unit">×</button>
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
```
|
|
293
|
+
All Nikke-specific helpers live alongside the main utilities (`src/css/nikke-utilities.css`) and observe the same token set, so there are no visual disconnects between game-specific and general UI.
|
|
294
|
+
|
|
295
|
+
## Customization & Tokens
|
|
296
|
+
Override only the tokens you need. The defaults intentionally mirror the showcase.
|
|
297
|
+
```css
|
|
298
|
+
:root {
|
|
299
|
+
--accent: #ff5fb0;
|
|
300
|
+
--accent-light: #ff8cd0;
|
|
301
|
+
--accent-dark: #c71c7d;
|
|
302
|
+
--glass: rgba(15, 10, 25, 0.65);
|
|
303
|
+
--glass-light: rgba(24, 14, 42, 0.45);
|
|
304
|
+
--glass-darker: rgba(10, 5, 20, 0.65);
|
|
305
|
+
--text: #f4e9ff;
|
|
306
|
+
--text-secondary: #b8afc8;
|
|
307
|
+
--transition-normal: 0.3s ease;
|
|
308
|
+
--transition-fast: 0.15s ease;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
Utilities (`src/css/utilities.css`) provide spacing (`.p-xl`, `.gap-md`), layout (`.flex`, `.grid`), and elevation helpers so you rarely write bespoke CSS.
|
|
312
|
+
|
|
313
|
+
## Coding Standards
|
|
314
|
+
These guidelines keep contributions aligned with enterprise frameworks:
|
|
315
|
+
- **CSS architecture**: component classes are flat (`.btn.secondary`), tokens live in `variables.css`, and utilities never override component styles.
|
|
316
|
+
- **Naming**: prefer descriptive nouns (e.g., `.api-endpoint`, `.glass-card`) and suffix modifiers with dot notation (`.btn.secondary`). Avoid chained hyphen variants unless the base class does not apply (`.badge-method`).
|
|
317
|
+
- **JavaScript**: all helper scripts are ES modules, side-effect-free, and expose initialization functions. Never mutate global scope outside a guarded `DOMContentLoaded` block.
|
|
318
|
+
- **Accessibility**: every interactive component includes focus styles, ARIA labels where relevant, and respects `prefers-reduced-motion` fallbacks.
|
|
319
|
+
- **Performance**: animations use `transform`/`opacity`, heavy filters are scoped to small elements, and layout thrashers are avoided.
|
|
320
|
+
- **Documentation**: README + `docs/COMPONENTS_REFERENCE.md` are the single sources of truth. Additions must include runnable snippets and token usage notes.
|
|
321
|
+
- **Versioning**: update `CHANGELOG.md` with semantic sections (`Added`, `Changed`, `Fixed`) before publishing.
|
|
322
|
+
|
|
323
|
+
## Development Workflow
|
|
324
|
+
```bash
|
|
325
|
+
npm install # install dependencies
|
|
326
|
+
npm run build # compile CSS bundle
|
|
327
|
+
npm run watch # dev rebuild loop
|
|
328
|
+
npm run dev:static # serve /examples on :8000
|
|
329
|
+
npm run dev:proxy # optional Celeste proxy on :5000
|
|
330
|
+
|
|
331
|
+
# Docker showcase
|
|
332
|
+
docker build -t corrupted-theme:latest .
|
|
333
|
+
docker run -d -p 8000:8000 --name corrupted-theme corrupted-theme:latest
|
|
334
|
+
```
|
|
335
|
+
- The Docker container automatically serves `examples/showcase-complete.html`.
|
|
336
|
+
- Provide `CELESTE_*` env vars to exercise the widget proxy inside the same container.
|
|
337
|
+
|
|
338
|
+
## Testing & QA Expectations
|
|
339
|
+
- **Visual regression**: validate against `examples/showcase-complete.html` in latest Chrome, Firefox, Safari, and a mobile viewport.
|
|
340
|
+
- **Accessibility**: run `tab` sweeps, screen reader spot checks, and `prefers-reduced-motion` toggles.
|
|
341
|
+
- **Performance**: Lighthouse performance budget ≥ 90, no long-running animations on background threads.
|
|
342
|
+
- **Animation review**: ensure the first-visit corrupted text + loader remain opt-in via JS flags for SPA integrations.
|
|
343
|
+
|
|
344
|
+
## Support
|
|
345
|
+
- GitHub Issues: [corrupted-theme/issues](https://github.com/whykusanagi/corrupted-theme/issues)
|
|
346
|
+
- Email: contact@whykusanagi.xyz
|
|
347
|
+
|
|
348
|
+
## Celeste Widget Integration (Secure Proxy)
|
|
349
|
+
The theme ships with an optional Celeste AI widget that **never exposes credentials to the browser**. It relies on the hardened proxy bundle located in `celeste_widget_pack/`.
|
|
350
|
+
|
|
351
|
+
### Environment Variables (required)
|
|
352
|
+
| Variable | Purpose |
|
|
353
|
+
|----------|---------|
|
|
354
|
+
| `CELESTE_AGENT_KEY` | Bearer token for the Celeste API |
|
|
355
|
+
| `CELESTE_AGENT_ID` | Agent identifier (UUID) |
|
|
356
|
+
| `CELESTE_AGENT_BASE_URL` | API endpoint root |
|
|
357
|
+
|
|
358
|
+
> Store these via your platform’s secret manager (Vault, Doppler, AWS Secrets Manager, etc.). Never commit them or inject them into client-side code.
|
|
359
|
+
|
|
360
|
+
### Docker Workflow
|
|
361
|
+
```bash
|
|
362
|
+
docker build -t corrupted-theme:latest .
|
|
363
|
+
|
|
364
|
+
docker run -d \
|
|
365
|
+
-p 8000:8000 \ # static showcase
|
|
366
|
+
-p 5001:5000 \ # exposes proxy externally
|
|
367
|
+
-e CELESTE_AGENT_KEY="$CELESTE_AGENT_KEY" \
|
|
368
|
+
-e CELESTE_AGENT_ID="$CELESTE_AGENT_ID" \
|
|
369
|
+
-e CELESTE_AGENT_BASE_URL="https://api.your-domain.com" \
|
|
370
|
+
corrupted-theme:latest
|
|
371
|
+
|
|
372
|
+
# Visit http://localhost:8000 (UI) and http://localhost:5001/api/health (proxy)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Local Development (split processes)
|
|
376
|
+
```bash
|
|
377
|
+
# Terminal 1 – proxy server (port defaults to 5000 inside container)
|
|
378
|
+
CELESTE_AGENT_KEY="..." \
|
|
379
|
+
CELESTE_AGENT_ID="..." \
|
|
380
|
+
CELESTE_AGENT_BASE_URL="..." \
|
|
381
|
+
PROXY_PORT=5000 node scripts/celeste-proxy-server.js
|
|
382
|
+
|
|
383
|
+
# Terminal 2 – static showcase
|
|
384
|
+
STATIC_PORT=8000 node scripts/static-server.js
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Security Guarantees
|
|
388
|
+
- Browser never receives `CELESTE_*` variables (verified via DevTools/HTML scans)
|
|
389
|
+
- All outbound API calls originate from the proxy (`/api/chat`, `/api/health`)
|
|
390
|
+
- Health endpoint surfaces status without leaking secrets
|
|
391
|
+
- Ready for Cloudflare Worker / Pages deployment (see secure pack doc)
|
|
392
|
+
|
|
393
|
+
For the full hardening guide—including architecture diagrams, Cloudflare steps, and troubleshooting—see `celeste_widget_pack/docs/CELESTE_WIDGET_SECURE_SETUP.md`.
|
|
394
|
+
|
|
395
|
+
## License
|
|
396
|
+
MIT © whykusanagi
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
Made with 💎 by [whykusanagi](https://whykusanagi.xyz)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Docker entrypoint script for whykusanagi.xyz
|
|
3
|
+
# Starts the Celeste API proxy and static file server (both in Node.js)
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "[Docker] Starting whykusanagi.xyz site"
|
|
8
|
+
|
|
9
|
+
# Check if Celeste environment variables are provided
|
|
10
|
+
if [ -z "$CELESTE_AGENT_KEY" ] || [ -z "$CELESTE_AGENT_ID" ] || [ -z "$CELESTE_AGENT_BASE_URL" ]; then
|
|
11
|
+
echo "[Celeste] ⚠️ Warning: One or more required environment variables are missing!"
|
|
12
|
+
echo "[Celeste] Required: CELESTE_AGENT_KEY, CELESTE_AGENT_ID, CELESTE_AGENT_BASE_URL"
|
|
13
|
+
echo "[Celeste] The Celeste widget API proxy will not start, but static site will serve."
|
|
14
|
+
echo "[Celeste] To enable the widget, provide these environment variables."
|
|
15
|
+
|
|
16
|
+
# Start only HTTP server (no widget API)
|
|
17
|
+
echo "[Docker] Starting static file server on http://0.0.0.0:8000"
|
|
18
|
+
exec node scripts/static-server.js
|
|
19
|
+
else
|
|
20
|
+
echo "[Celeste] ✅ Configuration validated"
|
|
21
|
+
echo "[Celeste] Agent ID: ${CELESTE_AGENT_ID:0:8}..."
|
|
22
|
+
echo "[Celeste] Base URL: ${CELESTE_AGENT_BASE_URL}"
|
|
23
|
+
|
|
24
|
+
# Start the API proxy in the background
|
|
25
|
+
echo "[Docker] Starting Celeste API proxy on http://0.0.0.0:5000"
|
|
26
|
+
PROXY_PORT=5000 STATIC_PORT=8000 node scripts/celeste-proxy-server.js &
|
|
27
|
+
PROXY_PID=$!
|
|
28
|
+
|
|
29
|
+
# Give proxy time to start
|
|
30
|
+
sleep 2
|
|
31
|
+
|
|
32
|
+
# Check if proxy started successfully
|
|
33
|
+
if ! kill -0 $PROXY_PID 2>/dev/null; then
|
|
34
|
+
echo "[Docker] ❌ Failed to start Celeste API proxy"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
echo "[Docker] ✅ Celeste API proxy started (PID: $PROXY_PID)"
|
|
39
|
+
|
|
40
|
+
# Start the static file server in foreground
|
|
41
|
+
echo "[Docker] Starting static file server on http://0.0.0.0:8000"
|
|
42
|
+
|
|
43
|
+
# Trap signals to clean up proxy when container stops
|
|
44
|
+
trap "kill $PROXY_PID 2>/dev/null || true" EXIT INT TERM
|
|
45
|
+
|
|
46
|
+
# Serve static files
|
|
47
|
+
exec node scripts/static-server.js
|
|
48
|
+
fi
|