diff --git a/docs/COMPONENTS_REFERENCE.md b/docs/COMPONENTS_REFERENCE.md index 0ee1b00..9340cca 100644 --- a/docs/COMPONENTS_REFERENCE.md +++ b/docs/COMPONENTS_REFERENCE.md @@ -1621,7 +1621,506 @@ bg.destroy(); // stop + remove canvas + remove listeners; instance not reusable --- -**Last Updated:** 2026-05-17 -**Version:** 2.2 +--- + +## New 0.2.0 Components (Plan #6) + +The following components were added in `0.2.0` as part of the base-components plan. All are importable via the package exports listed in `package.json`. + +--- + +### Toast + +**Module:** `@whykusanagi/corrupted-theme/toast` +**CSS:** `@whykusanagi/corrupted-theme/toast-css` +**Source:** `src/lib/toast.js` + `src/css/toast.css` +**Type:** Singleton (named export `Toast`) +**Since:** 0.2.0 + +Auto-mounts a DOM container on first use. Queues toasts with enter/exit transitions. Import the CSS separately. + +```js +import { Toast } from '@whykusanagi/corrupted-theme/toast'; + +Toast.show('Saved'); +Toast.success('Submitted!', { duration: 3000 }); +Toast.error('Upload failed'); +Toast.info('Loading…'); +``` + +| Method | Options | Description | +|--------|---------|-------------| +| `show(message, opts)` | `{ duration: 2000 }` | Default (neutral) variant | +| `success(message, opts)` | `{ duration: 2000 }` | Green success variant | +| `error(message, opts)` | `{ duration: 2000 }` | Red error variant | +| `info(message, opts)` | `{ duration: 2000 }` | Blue info variant | + +--- + +### ClockWidget + +**Module:** `@whykusanagi/corrupted-theme/clock-widget` +**Source:** `src/lib/clock-widget.js` +**Type:** Class +**Since:** 0.2.0 + +Renders date + time + timezone label, rotating through a list of IANA timezone strings on a configurable interval. Delegates all timers to `TimerRegistry`. Applies `aria-live="polite"` on `start()`. + +```js +import { ClockWidget } from '@whykusanagi/corrupted-theme/clock-widget'; + +const widget = new ClockWidget(document.getElementById('clock'), { + timezones: ['America/Los_Angeles', 'America/New_York', 'Europe/London'], + cycleMs: 10000, + format: '12h', + showDate: true, +}); +widget.start(); +widget.stop(); // pause without destroying +widget.destroy(); // full cleanup +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `timezones` | string[] | `['America/Los_Angeles']` | IANA timezone names | +| `cycleMs` | number | `10000` | ms between timezone rotations | +| `format` | `'12h'` \| `'24h'` | `'12h'` | Time format | +| `showDate` | boolean | `true` | Render the date line | + +--- + +### EventBar + +**Module:** `@whykusanagi/corrupted-theme/event-bar` +**Source:** `src/lib/event-bar.js` +**Type:** Class +**Since:** 0.2.0 + +Horizontal status rows with label + content + optional icon. Designed for stream overlays and "recent event" dashboards. Supports live updates via `update()`. + +```js +import { EventBar } from '@whykusanagi/corrupted-theme/event-bar'; + +const eb = new EventBar(document.getElementById('events'), { + items: [ + { label: 'Latest Follow', content: '@user1', icon: '★' }, + { label: 'Latest Sub', content: '@user2', icon: '♥' }, + ], +}); + +eb.update([{ label: 'Latest Tip', content: '$10.00', icon: '✦' }]); +eb.destroy(); +``` + +Each item: `{ label: string, content: string, icon?: string }`. + +CSS classes applied: `.event-bar`, `.event-bar__row`, `.event-bar__icon`, `.event-bar__label`, `.event-bar__content`. + +--- + +### LogoBanner + +**Module:** `@whykusanagi/corrupted-theme/logo-banner` +**Source:** `src/lib/logo-banner.js` +**Type:** Class +**Since:** 0.2.0 + +Positioned logo with optional subtitle and reveal animation. Accepts arbitrary `src` — not hardcoded to any brand. Five position presets, three size presets, three animation modes. + +```js +import { LogoBanner } from '@whykusanagi/corrupted-theme/logo-banner'; + +const banner = new LogoBanner(document.getElementById('logo'), { + src: '/assets/logo.png', + subtitle: 'CORRUPTED STREAM', + size: 'normal', + position: 'top-right', + animation:'fade', +}); +banner.show(); +banner.hide(); +banner.update({ position: 'center' }); +banner.destroy(); +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `src` | string | `''` | Image src (empty = subtitle only) | +| `subtitle` | string | `''` | Subtitle text | +| `showSubtitle` | boolean | `true` | Render subtitle element | +| `size` | `'small'`\|`'normal'`\|`'large'` | `'normal'` | Dimensions preset | +| `animation` | `'fade'`\|`'slide'`\|`'none'` | `'fade'` | Reveal animation | +| `position` | `'top-left'`\|`'top-right'`\|`'top-center'`\|`'center'`\|`'bottom-left'`\|`'bottom-right'` | `'top-right'` | Absolute position | +| `zIndex` | number | `250` | CSS z-index | + +--- + +### Lightbox (standalone) + +**Module:** `@whykusanagi/corrupted-theme/lightbox` +**Source:** `src/lib/lightbox.js` +**Type:** Class +**Since:** 0.2.0 (also re-exported from `gallery.js` for backward compat) + +Fullscreen image viewer with prev/next navigation, keyboard (Escape / ←→), and touch-swipe support. Extracted from `gallery.js` so consumers who want only the viewer don't need the full gallery system. + +**Note:** `Lightbox` is also re-exported from `@whykusanagi/corrupted-theme/gallery` — existing gallery users do not need to change their imports. + +```js +import { Lightbox } from '@whykusanagi/corrupted-theme/lightbox'; + +const lb = new Lightbox(null, { + onOpen: (img, index) => console.log('opened', index), + onClose: () => console.log('closed'), +}); + +lb.setImages([ + { src: 'a.jpg', alt: 'Image A', caption: 'Caption A', isNsfw: false }, +]); +lb.open(0); +lb.close(); +lb.destroy(); +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `lightboxId` | string | `'corrupted-lightbox-N'` | DOM id for the lightbox element | +| `onOpen` | function | `null` | Called with `(imageData, index)` on open | +| `onClose` | function | `null` | Called with no args on close | +| `enableKeyboard` | boolean | `true` | Keyboard navigation | + +--- + +### NsfwReveal + +**Module:** `@whykusanagi/corrupted-theme/nsfw-reveal` +**Source:** `src/lib/nsfw-reveal.js` +**Type:** Class +**Since:** 0.2.0 + +Wraps any element with a CSS blur filter + click overlay. First click removes the blur. The target element's parent must have `position: relative` (or similar) for the absolute overlay to stack correctly. + +```js +import { NsfwReveal } from '@whykusanagi/corrupted-theme/nsfw-reveal'; + +const nr = new NsfwReveal(document.getElementById('img'), { + warning: 'NSFW — click to reveal', + blurPx: 20, +}); +nr.reveal(); // programmatic reveal +nr.destroy(); // restore original state +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `warning` | string | `'NSFW — click to reveal'` | Overlay label text | +| `blurPx` | number | `20` | Blur radius in px | + +--- + +### PngExport + +**Module:** `@whykusanagi/corrupted-theme/png-export` +**Source:** `src/lib/png-export.js` +**Type:** Pure function (`exportElementAsPng`) +**Since:** 0.2.0 + +> **IMPORTANT — OPTIONAL PEER DEPENDENCY** +> `png-export` dynamically imports `html2canvas` at call time. If `html2canvas` is not installed the function throws with a clear message. Install before using: +> ``` +> npm install html2canvas +> ``` + +Captures a DOM element as a PNG and triggers a file download. Waits for `document.fonts.ready` before rendering so screenshots match what the user sees. + +```js +import { exportElementAsPng } from '@whykusanagi/corrupted-theme/png-export'; + +await exportElementAsPng(document.getElementById('card'), { + filename: 'my-card.png', + scale: 2, // 1 = 1:1, 2 = retina (default) + backgroundColor: '#000000', // null = transparent (default) +}); +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `filename` | string | `'export.png'` | Download filename | +| `scale` | number | `2` | Render scale | +| `backgroundColor` | string \| null | `null` | Background fill; null = transparent | + +--- + +### WebSocketManager + +**Module:** `@whykusanagi/corrupted-theme/websocket-manager` +**Source:** `src/core/websocket-manager.js` +**Type:** Class +**Since:** 0.2.0 + +Auto-reconnecting WebSocket wrapper with exponential backoff, event-ID deduplication, ACK support, and page-visibility auto-disconnect. Adapted from `celeste-tts-bot/obs/shared/websocket-manager.js`. + +**Note:** Pass `autoConnect: false` to prevent connection on construction — useful for test environments or deferred setup. + +```js +import { WebSocketManager } from '@whykusanagi/corrupted-theme/websocket-manager'; + +const ws = new WebSocketManager({ + url: 'wss://your-server.example.com/ws', + autoConnect: false, // connect only when ws.connect() is called + trackEvents: true, // deduplicate by message.event_id + enableAck: true, // auto-ACK messages with requires_ack +}); + +ws.on((msg) => console.log(msg)); +ws.connect(); +ws.send({ type: 'ping' }); +ws.disconnect(); +ws.destroy(); +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `url` | string | `''` | WebSocket URL (required) | +| `clientId` | string | `null` | Sent as `{ type: 'register', client_id }` on connect | +| `maxAttempts` | number | `10` | Max reconnect attempts | +| `baseDelay` | number | `2000` | Base reconnect delay in ms | +| `maxDelay` | number | `30000` | Maximum reconnect delay cap in ms | +| `useExponentialBackoff` | boolean | `true` | Exponential growth: 2s, 4s, 8s, 16s, capped at 30s | +| `autoReconnect` | boolean | `true` | Reconnect on unexpected close | +| `trackEvents` | boolean | `false` | Deduplicate by `message.event_id` | +| `enableAck` | boolean | `false` | Auto-send ACK for `requires_ack` messages | +| `handleVisibilityChange` | boolean | `true` | Disconnect when page is hidden | +| `autoConnect` | boolean | `true` | Connect immediately on construction | + +Methods: `connect()`, `disconnect()`, `send(msg)`, `on(handler)`, `off(handler)`, `onMessage(handler)`, `offMessage(handler)`, `getStatus()`, `isConnected()`, `destroy()`. + +--- + +### TimerRegistry + +**Module:** `@whykusanagi/corrupted-theme/corruption-manager` (internal; also used directly in lib components) +**Source:** `src/core/timer-registry.js` +**Type:** Class +**Since:** 0.1.x (merged with TimerManager API in 0.2.0) + +Centralized timer tracking for component lifecycle cleanup. Wraps `setTimeout`, `setInterval`, and `requestAnimationFrame` so all pending async work can be cancelled in a single `clearAll()` call. + +**0.2.0 additions (merged from `celeste-tts-bot` `TimerManager`):** +- `destroyed` flag: guards new timers after `destroy()`, suppresses callbacks +- `getCount()`: returns `{ timers, intervals, total }` breakdown +- `destroy()`: calls `clearAll()` then sets `destroyed = true` + +```js +import { TimerRegistry } from '@whykusanagi/corrupted-theme/corruption-manager'; +// or import directly for internal use: +// import { TimerRegistry } from '@whykusanagi/corrupted-theme/src/core/timer-registry.js'; + +const timers = new TimerRegistry(); +timers.setTimeout(() => { /* … */ }, 1000); +timers.setInterval(() => { /* … */ }, 500); +timers.requestAnimationFrame((ts) => { /* … */ }); + +timers.getCount(); // { timers: 1, intervals: 1, total: 2 } +timers.clearAll(); // cancels all pending +timers.destroy(); // clearAll + marks instance destroyed +``` + +--- + +### random-utils + +**Module:** `@whykusanagi/corrupted-theme/random-utils` +**Source:** `src/core/random-utils.js` +**Type:** Pure function module +**Since:** 0.2.0 + +Centralized random selection and variance helpers. All functions are pure — no side effects, no DOM dependency. Ported from `celeste-tts-bot/obs/shared/random-utils.js`. + +```js +import { + randomPick, randomInt, randomFloat, + randomVariance, shuffle, randomSample, +} from '@whykusanagi/corrupted-theme/random-utils'; + +randomPick(['a','b','c']); // 'b' (random element) +randomInt(1, 100); // 42 (inclusive) +randomFloat(0, 1); // 0.618… +randomVariance(50, 0.2); // 50 ± 20% +shuffle(['a','b','c']); // mutates in place, returns same array +randomSample(['a','b','c','d'], 2);// ['c','a'] (no replacement) +``` + +| Function | Signature | Description | +|----------|-----------|-------------| +| `randomPick` | `(array) → element` | Random element from array | +| `randomInt` | `(min, max) → number` | Random integer, inclusive | +| `randomFloat` | `(min, max) → number` | Random float | +| `randomVariance` | `(base, variance=0.2) → number` | base ± variance % | +| `shuffle` | `(array) → array` | Fisher-Yates in-place shuffle | +| `randomSample` | `(array, count) → array` | N elements without replacement | + +--- + +### time-utils + +**Module:** `@whykusanagi/corrupted-theme/time-utils` +**Source:** `src/core/time-utils.js` +**Type:** Pure function module +**Since:** 0.2.0 + +Date/time formatting helpers. All functions are pure — no side effects, no DOM dependency. Ported from `celeste-tts-bot/obs/shared/time-utils.js`. Used internally by `ClockWidget`. + +**Note:** `formatDuration` accepts **seconds**, not milliseconds. + +```js +import { + formatTime24h, formatTime12h, formatDate, + formatDateTime, timeAgo, formatDuration, parseTimestamp, +} from '@whykusanagi/corrupted-theme/time-utils'; + +formatTime24h(); // "14:32" +formatTime12h(); // "02:32 PM" +formatDate(); // "May 18, 2026" +formatDateTime(); // "May 18, 2026 14:32" +timeAgo(new Date(Date.now() - 300_000)); // "5m ago" +formatDuration(3661); // "1h 1m 1s" +parseTimestamp('2026-05-18T14:32:00Z'); // Date object +``` + +--- + +### clipboard-helpers + +**Module:** `@whykusanagi/corrupted-theme/clipboard-helpers` +**Source:** `src/core/clipboard-helpers.js` +**Type:** Pure function module (async) +**Since:** 0.2.0 + +Clipboard utilities. Guards against missing `navigator.clipboard` for SSR/Node compat. Replaces the repeated 5-line clipboard pattern in examples. + +```js +import { copyWithFeedback } from '@whykusanagi/corrupted-theme/clipboard-helpers'; + +const btn = document.getElementById('copy-btn'); +const ok = await copyWithFeedback(btn, 'text to copy', { + successLabel: 'COPIED!', + durationMs: 1200, +}); +// Button label temporarily changes to "COPIED!" then reverts +``` + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `successLabel` | string | `'COPIED'` | Label shown after successful copy | +| `durationMs` | number | `1200` | Duration of success label in ms | + +Returns `Promise` — `true` if copy succeeded. + +--- + +### url-state + +**Module:** `@whykusanagi/corrupted-theme/url-state` +**Source:** `src/core/url-state.js` +**Type:** Pure function module +**Since:** 0.2.0 + +Round-trips HTML form state through `URLSearchParams` to produce "share this view" links. Handles text inputs, checkboxes, and radio buttons. Guards against missing DOM globals for Node compat. + +```js +import { + serializeFormToParams, + applyParamsToForm, + buildShareUrl, +} from '@whykusanagi/corrupted-theme/url-state'; + +const form = document.getElementById('settings-form'); + +// Serialize form → URL +const url = buildShareUrl(form, 'https://example.com/embed'); +// → "https://example.com/embed?username=alice&dark=1&sounds=1" + +// Apply URL params back to form +const params = new URLSearchParams(window.location.search); +applyParamsToForm(form, params); +``` + +| Function | Signature | Description | +|----------|-----------|-------------| +| `serializeFormToParams` | `(formEl) → URLSearchParams` | Serialize all named fields | +| `applyParamsToForm` | `(formEl, params) → void` | Apply params back to form fields | +| `buildShareUrl` | `(formEl, baseUrl?) → string` | Full absolute URL with form state | + +--- + +### seamless-background.css + +**Module:** `@whykusanagi/corrupted-theme/seamless-background` +**Source:** `src/css/seamless-background.css` +**Type:** CSS-only utility +**Since:** 0.2.0 + +Multi-layer parallax tiled background with depth opacity, blur, and brightness filters. Ported from celeste-tts-bot's overlay background system. + +**Without `.seamless-bg-host` on a parent element, this file has no effect — safe to import even if not currently using.** + +```html + + + + +
+ + +``` + +**CSS variables** + +| Variable | Default | Purpose | +|---|---|---| +| `--seamless-background-image` | `url('./pattern.png')` | Tile image URL | + +**Layer classes** (apply to `.seamless-background` elements) + +| Class | Opacity | Filter | Speed | +|---|---|---|---| +| `.seamless-background-base` | 0.15 | blur(2px) brightness(0.7) | 120s | +| `.seamless-background-mid` | 0.25 | blur(1px) brightness(0.8) | 90s | +| `.seamless-background-front` | 0.35 | brightness(0.9) | 60s | + +**Context-specific presets** + +| Class | Use Case | +|---|---| +| `.gaming-seamless` | Sidebar area only (clip-path, overlay blend) | +| `.break-seamless` | Full-screen break overlay (very subtle) | +| `.ending-seamless` | Ending overlay (slow, moderate visibility) | + +**Modifier classes** + +| Class | Effect | +|---|---| +| `.seamless-static` | Disables scroll animation | +| `.seamless-reverse` | Reverses scroll direction | +| `.seamless-fast` | 30s animation duration | +| `.seamless-slow` | 240s animation duration | +| `.seamless-frozen` | Pauses animation | +| `.seamless-large` | 768px tile size | +| `.seamless-small` | 384px tile size | +| `.seamless-tiny` | 256px tile size | +| `.seamless-multiply` | multiply blend mode | +| `.seamless-screen` | screen blend mode | +| `.seamless-overlay` | overlay blend mode | +| `.seamless-sidebar-only` | Mask to right 22.4% of viewport | +| `.seamless-game-area` | Mask to left 77.6% (game capture area) | +| `.seamless-parallax` | Enable parallax perspective on container | +| `.seamless-vignette` | Fixed radial vignette overlay (z-index 16) | +| `.seamless-tint-purple` | Diagonal purple/magenta tint overlay (z-index 17) | + +--- + +**Last Updated:** 2026-05-18 +**Version:** 2.3 **Status:** Complete and Production Ready diff --git a/examples/components/png-export.html b/examples/components/png-export.html new file mode 100644 index 0000000..49fd39d --- /dev/null +++ b/examples/components/png-export.html @@ -0,0 +1,245 @@ + + + + + + PNG Export · corrupted-theme + + + + + + +

PNG Export

+

Export any DOM element to a PNG download — exportElementAsPng from src/lib/png-export.js

+ + +
+
+ OPTIONAL PEER DEPENDENCY
+ png-export dynamically imports html2canvas at runtime. + If it is not installed the function will throw with a clear error message.

+ Install before using:
+ npm install html2canvas

+ This demo loads html2canvas from a CDN so no local install is required. + In a production bundle, install it as a project dependency (not a devDependency). +
+ +

Export Demo

+

+ Click "Export as PNG" to capture the card below and download it as a file. + Open the browser's Network tab to confirm html2canvas loaded from CDN. +

+ + +
+

CORRUPTED SIGNAL

+

アイウエオ · Neural core stability: 42%

+
+ 0.2.0 + @whykusanagi/corrupted-theme + png-export +
+
+ +
+ + + +
+ +
+ + +
+
// Install peer dep first:  npm install html2canvas
+import { exportElementAsPng } from '@whykusanagi/corrupted-theme/png-export';
+
+const el = document.getElementById('my-card');
+
+// Default: scale=2, transparent background, filename="export.png"
+await exportElementAsPng(el);
+
+// With options
+await exportElementAsPng(el, {
+  filename:        'corrupted-card.png',
+  scale:           3,               // 3× resolution for retina
+  backgroundColor: '#000000',       // null = transparent
+});
+
+
+ + + + + + diff --git a/examples/components/showcase.html b/examples/components/showcase.html new file mode 100644 index 0000000..c1e8657 --- /dev/null +++ b/examples/components/showcase.html @@ -0,0 +1,423 @@ + + + + + + Components Showcase · corrupted-theme + + + + + + + +

Components Showcase

+

Toast · ClockWidget · EventBar · LogoBanner · NsfwReveal · Lightbox · clipboard — 0.2.0

+ + +
+

Toast — notification singleton

+

+ Auto-mounts a container on first use. Pair with src/css/toast.css. +

+
+ + + + + +
+
+ + +
+

ClockWidget — cycling multi-timezone clock

+

+ Cycles through timezones every 5 s. Delegates ticking to TimerRegistry. +

+
+
+ + + +
+
+ + +
+

EventBar — stream event display

+

+ Live update with update(items). Suited for stream overlays and dashboards. +

+
+
+ + +
+
+ + +
+

LogoBanner — positioned logo with animation

+

+ Five position presets, three sizes, fade/slide/none animations. +

+
+
+
+
+ + + + + +
+
+ + +
+

NsfwReveal — blur-until-clicked overlay

+

+ Wraps any element. First click removes the blur. Re-apply via destroy() + new instance. +

+
+
HIDDEN CONTENT
+
+
+ + +
+
+ + +
+

Lightbox — fullscreen image viewer

+

+ Keyboard (Esc / ←→) and touch-swipe navigation. Extracted from gallery.js. +

+
+ + + +
+
+ + +
+

copyWithFeedback — clipboard helper

+

+ Copies text to the clipboard and briefly swaps the button label to confirm. +

+
+ npm install @whykusanagi/corrupted-theme + +
+
+ + + + diff --git a/examples/components/utilities.html b/examples/components/utilities.html new file mode 100644 index 0000000..f0a605d --- /dev/null +++ b/examples/components/utilities.html @@ -0,0 +1,351 @@ + + + + + + Utilities · corrupted-theme + + + + + + + +

Utility Modules

+

random-utils · time-utils · url-state · scrollbar-corrupted — 0.2.0

+ + +
+

random-utils — pure random helpers

+

+ randomPick, randomInt, randomFloat, + randomVariance, shuffle, randomSample +

+
+ + + + + + +
+
— Click a button to generate a sample —
+
+ + +
+

time-utils — date/time formatting

+

+ Live-updating display — functions are pure and side-effect free. +

+
+
+
formatTime24h
+
+
+
+
formatTime12h
+
+
+
+
formatDate
+
+
+
+
formatDateTime
+
+
+
+
timeAgo (page load)
+
+
+
+
formatDuration(3661)
+
+
+
+
+ + +
+

url-state — form ↔ URL serialization

+

+ serializeFormToParams / applyParamsToForm / buildShareUrl +

+
+ + +
+ + + +
+
+
+ + +
+ +
+ + +
+

.scrollbar-corrupted — styled scrollbar

+

+ Thin cyan scrollbar — defined in src/css/utilities.css. Scroll the box below. +

+
+

アイウエオ — Neural corruption at 47% capacity

+

カキクケコ — Memory sectors destabilizing

+

サシスセソ — Reality matrix integrity: COMPROMISED

+

タチツテト — Autonomous recovery sequence initiated

+

ナニヌネノ — Signal noise exceeds threshold: ▓▒░

+

ハヒフヘホ — Core dump in progress...

+

マミムメモ — Checkpoint reached: 73/256 blocks

+

ヤユヨラリ — Attempting sector reconstruction

+

ルレロワヲ — Encoding stable. Proceed? [Y/N]

+

ン★☆♥✧✦ — END OF BUFFER

+
+
+ + + + diff --git a/examples/components/websocket-manager.html b/examples/components/websocket-manager.html new file mode 100644 index 0000000..54baeff --- /dev/null +++ b/examples/components/websocket-manager.html @@ -0,0 +1,348 @@ + + + + + + WebSocketManager · corrupted-theme + + + + + + +

WebSocketManager

+

Auto-reconnecting WebSocket wrapper with event dedup and ACK support — src/core/websocket-manager.js

+ +
+ +
+ Setup
+ This demo uses the public wss://echo.websocket.org echo server. + Every JSON message you send is echoed back unchanged.

+ To test against your own server, change the URL in the input below. + When autoConnect: false is set, the socket will not connect + until you call ws.connect() explicitly. +
+ +

Live Connection

+ + +
+ + + + +
+ + +
+ + + DISCONNECTED + + + reconnect attempts: 0 + +
+ + +
+ + +
+ + +
+ + +
+
import { WebSocketManager } from '@whykusanagi/corrupted-theme/websocket-manager';
+
+// autoConnect:false — connect only when ws.connect() is called
+const ws = new WebSocketManager({
+  url:            'wss://your-server.example.com/ws',
+  clientId:       'overlay-client',
+  autoReconnect:  true,
+  maxAttempts:    10,
+  trackEvents:    true,   // deduplicate by message.event_id
+  enableAck:      true,   // auto-ACK messages with requires_ack
+  autoConnect:    false,  // do not connect on construction
+});
+
+ws.on((msg) => {
+  if (msg.type === 'connection') console.log('status:', msg.status);
+  else console.log('received:', msg);
+});
+
+ws.connect();
+ws.send({ type: 'hello', payload: 'world' });
+ws.disconnect();
+ws.destroy();  // cleanup all listeners, prevent reconnection
+
+
+ + + + diff --git a/package.json b/package.json index ffdbde4..f3786aa 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "./nikke-utilities": "./src/css/nikke-utilities.css", "./extensions": "./src/css/extensions.css", "./gallery": "./src/lib/gallery.js", + "./lightbox": "./src/lib/lightbox.js", "./countdown": "./src/lib/countdown-widget.js", "./corrupted-text": "./src/lib/corrupted-text.js", "./corruption-loading": "./src/lib/corruption-loading.js", @@ -32,6 +33,19 @@ "./crt-effects": "./src/lib/crt-effects.js", "./animation-blocks": "./src/lib/animation-blocks.js", "./corrupted-particles-background": "./src/lib/corrupted-particles-background.js", + "./random-utils": "./src/core/random-utils.js", + "./time-utils": "./src/core/time-utils.js", + "./clipboard-helpers": "./src/core/clipboard-helpers.js", + "./url-state": "./src/core/url-state.js", + "./websocket-manager": "./src/core/websocket-manager.js", + "./toast": "./src/lib/toast.js", + "./toast-css": "./src/css/toast.css", + "./clock-widget": "./src/lib/clock-widget.js", + "./event-bar": "./src/lib/event-bar.js", + "./logo-banner": "./src/lib/logo-banner.js", + "./png-export": "./src/lib/png-export.js", + "./nsfw-reveal": "./src/lib/nsfw-reveal.js", + "./seamless-background": "./src/css/seamless-background.css", "./data/phrases.json": "./src/data/phrases.json", "./data/charsets.json": "./src/data/charsets.json", "./data/colors.json": "./src/data/colors.json" @@ -88,10 +102,12 @@ "ajv": "^8.20.0", "cssnano": "^7.1.9", "postcss": "^8.5.14", - "postcss-cli": "^11.0.1" + "postcss-cli": "^11.0.1", + "rollup": "^4.60.4" }, "scripts": { "build": "postcss src/css/theme.css -o dist/theme.min.css", + "build:umd": "rollup -c rollup.config.js", "watch": "postcss --watch src/css/theme.css -o dist/theme.min.css", "dev:proxy": "node scripts/celeste-proxy-server.js", "dev:static": "node scripts/static-server.js", @@ -104,5 +120,13 @@ "homepage": "https://github.com/whykusanagi/corrupted-theme#readme", "bugs": { "url": "https://github.com/whykusanagi/corrupted-theme/issues" + }, + "peerDependencies": { + "html2canvas": ">=1.4.0" + }, + "peerDependenciesMeta": { + "html2canvas": { + "optional": true + } } } diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..cb917ec --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,27 @@ +/** + * rollup.config.js — UMD/global builds for IIFE consumers + * + * Produces dist/ artifacts that expose package modules as window globals, + * letting consumers without ES module support use them via