🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

danmaku-lite

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

danmaku-lite - npm Package Compare versions

Comparing version
0.2.2
to
0.2.3
+165
dist/engine-D9OmRc0L.d.ts
/** Bridge between the danmaku engine and the host media player. */
interface PlayerAdapter {
/** Current playback position in seconds. Read every frame. */
readonly position: number;
/** Whether playback is currently paused. Read every frame. */
readonly paused: boolean;
/** Total media duration in seconds. Optional (e.g. live streams). */
readonly duration?: number;
}
/** Danmaku display mode constants (matches Bilibili convention). */
declare const enum DanmakuMode {
/** Right-to-left scrolling (standard) */
Scroll = 1,
/** Top-center fixed */
Top = 5,
/** Bottom-center fixed */
Bottom = 6
}
interface DanmakuItem {
/** Unique identifier. Used for deduplication on load(). */
id: number | string;
/** Display text. Plain string — no HTML. */
text: string;
/** Emission time in seconds (media time, not wall time). */
time: number;
/** Display mode. @see DanmakuMode */
mode: DanmakuMode;
/** 24-bit RGB color (e.g. 0xFFFFFF). */
color: number;
/** Font size in CSS pixels for this item. Overrides engine default if set. */
font_size?: number;
}
/**
* Adapter for streaming danmaku data from a remote source.
* The host application provides a fetch implementation that
* calls their backend API or reads from local storage.
*/
interface DataSourceAdapter {
/**
* Fetch danmaku items for a given time range.
*
* @param start - Start time in seconds (inclusive)
* @param end - End time in seconds (exclusive). May be Infinity
* for live streaming where the end is unknown.
* @returns Promise resolving to the danmaku items in this range.
* Items do NOT need to be sorted — the engine sorts them.
* May be empty if no items exist in this range.
*/
fetch(start: number, end: number): Promise<DanmakuItem[]>;
}
type EngineType = 'canvas' | 'dom';
type OverflowStrategy = 'drop' | 'none';
interface DanmakuOptions {
/** The DOM element the engine renders into. Must have non-zero dimensions. */
container: HTMLElement;
/** Adapter bridging the engine to the host media player. */
adapter: PlayerAdapter;
/** Whether rendering is enabled. When false, loop runs but nothing is drawn. Default: true */
enabled?: boolean;
/** Target frames per second for the render loop. Default: 60 */
fps?: number;
/** Fraction of container height used for danmaku (0–1). Default: 0.75 */
area?: number;
/** CSS font-family string. Default: 'sans-serif' */
fontFamily?: string;
/** Base font size in CSS pixels. Individual items can override via font_size. Default: 25 */
fontSize?: number;
/** CSS font-weight value. Default: 'bold' */
fontWeight?: string;
/** Global opacity for all danmaku (0–1). Default: 1.0 */
opacity?: number;
/** Text bitmap padding in CSS pixels. Affects horizontal spacing. Default: 4 */
padding?: number;
/** Text outline stroke width in CSS pixels. Default: 1.25 */
strokeWidth?: number;
/** Stroke color as 0xRRGGBB. Default: 0x000000 (black) */
strokeColor?: number;
/** Minimum position jump (seconds) that triggers seek handling. Default: 0.2 */
seekThreshold?: number;
/** Gap between consecutive scroll danmaku, in pixels at reference width 1920. Scaled proportionally to container width. Default: 96 */
scrollGap?: number;
/** Playback speed multiplier. Affects scroll velocity. Default: 1.0 */
speed?: number;
/** Fixed danmaku (mode 5/6) display duration in seconds. Default: 4 */
duration?: number;
/** Behavior when no free track is available. 'drop' discards silently, 'none' forces emission. Default: 'drop' */
overflow?: OverflowStrategy;
/** Maximum simultaneously visible danmaku. 0 = unlimited. Default: 0 */
maxVisible?: number;
/** Maximum number of cached ImageBitmap objects. Default: 500 */
maxCache?: number;
/** Number of items to pre-cache ahead of playback position. Default: 50 */
preCacheCount?: number;
/** Enable imageSmoothingEnabled on the canvas context. Default: true */
smoothing?: boolean;
/** Add will-change: transform to danmaku elements. Disable to reduce GPU memory. Default: true */
willChange?: boolean;
/** Use text-shadow multi-directional offset to simulate stroke. Disable for plain text. Default: true */
useTextShadow?: boolean;
/** Called when a streaming fetch error occurs. If not set, errors are silently retried. */
onError?: (error: Error) => void;
/**
* Adapter for streaming danmaku data from a backend.
* When provided, the engine manages data fetching automatically.
* When omitted, the consumer must call load() explicitly.
*/
dataSource?: DataSourceAdapter;
/**
* Seconds of danmaku data to pre-buffer ahead of playback position.
* Only used when dataSource is set. Default: 60
*/
preBuffer?: number;
/**
* Seconds of danmaku data to retain behind playback position.
* Data older than (position - leadTime) is evicted from memory.
* Default: 0 (keep all). Set to >0 for memory-constrained long sessions (e.g. live streaming).
*/
leadTime?: number;
}
/** Contract fulfilled by both CanvasEngine and DOMEngine. */
interface DanmakuEngine {
/** Load (replace) the entire danmaku list. Sorted by time internally. */
load(items: readonly DanmakuItem[]): void;
/** Remove all loaded danmaku and clear visible elements. */
clear(): void;
/** Recalculate dimensions after container resize. Consumer must call this. */
resize(): void;
/** Permanently destroy the engine. Frees all resources. Idempotent. */
destroy(): void;
/** Whether destroy() has been called. */
readonly isDestroyed: boolean;
setEnabled(v: boolean): void;
setFps(v: number): void;
setArea(v: number): void;
setOpacity(v: number): void;
setSpeed(v: number): void;
setFontFamily(v: string): void;
setFontSize(v: number): void;
setFontWeight(v: string): void;
setStrokeWidth(v: number): void;
setStrokeColor(v: number): void;
setPadding(v: number): void;
setScrollGap(v: number): void;
setDuration(v: number): void;
setOverflow(v: OverflowStrategy): void;
setMaxVisible(v: number): void;
setMaxCache(v: number): void;
setPreCacheCount(v: number): void;
setSmoothing(v: boolean): void;
setWillChange(v: boolean): void;
setUseTextShadow(v: boolean): void;
/**
* Immediately display a single danmaku at the current playback position.
* Bypasses the scheduler — the item is rendered regardless of its time field.
* Always shows (skips maxVisible and overflow checks).
* Use for user-sent messages or real-time notifications on send success.
*/
send(item: DanmakuItem): void;
}
export { type DanmakuOptions as D, type EngineType as E, type OverflowStrategy as O, type PlayerAdapter as P, type DanmakuEngine as a, type DanmakuItem as b, DanmakuMode as c, type DataSourceAdapter as d };
+2
-2

@@ -1,3 +0,3 @@

import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-DQHkoud-.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-DQHkoud-.js';
import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-D9OmRc0L.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-D9OmRc0L.js';

@@ -4,0 +4,0 @@ declare function createEngine(type: EngineType, options: DanmakuOptions): DanmakuEngine;

@@ -26,59 +26,2 @@ var __typeError = (msg) => {

// src/engine/canvas/renderer.ts
var CanvasRenderer = class {
constructor(container) {
this.W = 0;
this.H = 0;
this.dpr = 1;
this.container = container;
const canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.inset = "0";
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.pointerEvents = "none";
container.appendChild(canvas);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.updateDimensions();
}
/** Re-measure container and resize the canvas backing store. */
updateDimensions() {
const dpr = window.devicePixelRatio || 1;
const W = this.container.clientWidth;
const H = this.container.clientHeight;
if (W === 0 || H === 0) return false;
this.dpr = dpr;
this.W = W;
this.H = H;
this.canvas.width = W * dpr;
this.canvas.height = H * dpr;
this.canvas.style.width = W + "px";
this.canvas.style.height = H + "px";
this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
return true;
}
get width() {
return this.W;
}
get height() {
return this.H;
}
get devicePixelRatio() {
return this.dpr;
}
clear() {
this.ctx.clearRect(0, 0, this.W, this.H);
}
setSmoothing(enabled) {
this.ctx.imageSmoothingEnabled = enabled;
}
setGlobalAlpha(alpha) {
this.ctx.globalAlpha = alpha;
}
destroy() {
this.canvas.remove();
}
};
// src/core/track-manager.ts

@@ -123,3 +66,3 @@ var TrackManager = class {

// ---- Scroll track allocation (mode 1) ----
acquireScroll(currentTime, danmakuWidth, speed, _containerWidth) {
acquireScroll(currentTime, danmakuWidth, speed, containerWidth, scrollGap) {
const deferred = [];

@@ -129,3 +72,3 @@ while (this.scrollFree.length > 0) {

if (this.scrollExit[t] <= currentTime) {
this.scrollExit[t] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[t] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
for (const d of deferred) this.scrollFree.push(d);

@@ -141,3 +84,3 @@ return { track: t, y: this.scrollY(t) };

if (this.scrollExit[i] <= currentTime) {
this.scrollExit[i] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[i] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
const idx = this.scrollFree.indexOf(i);

@@ -239,166 +182,2 @@ if (idx !== -1) this.scrollFree.splice(idx, 1);

// src/engine/canvas/pool.ts
var MAX_POOL_SIZE = 512;
var ObjectPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : {};
}
release(v) {
if (this.pool.length < MAX_POOL_SIZE) {
v.bmp = void 0;
v.el = void 0;
this.pool.push(v);
}
}
releaseAll(visible) {
for (let i = 0; i < visible.length; i++) {
this.release(visible[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/engine/canvas/bitmap-cache.ts
var BitmapCache = class {
constructor(maxCache = 500) {
// Text measurement cache
this.textWidths = /* @__PURE__ */ new Map();
// ImageBitmap LRU cache
this.bitmaps = /* @__PURE__ */ new Map();
this.aliveBitmaps = /* @__PURE__ */ new Set();
this.accessCounter = 0;
this.dpr = 1;
// Cache for buildFont result
this.cachedFont = "";
this.fontFamily = "";
this.fontSize = 0;
this.fontWeight = "";
this.maxCache = maxCache;
}
// ---- Text measurement ----
measure(text, fontFamily, fontSize, fontWeight, ctx) {
const key = `${text}|${fontFamily}|${fontSize}|${fontWeight}`;
const cached = this.textWidths.get(key);
if (cached !== void 0) return cached;
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
const w = ctx.measureText(text).width;
this.textWidths.set(key, w);
return w;
}
invalidateTextCache() {
this.textWidths.clear();
}
// ---- ImageBitmap cache ----
getBitmap(text, fontSize, color, strokeWidth, strokeColor, fontFamily, fontWeight, dpr, padding) {
const key = `${text}|${fontSize}|${color}|${strokeWidth}|${strokeColor}|${fontFamily}|${fontWeight}|${dpr}`;
const hit = this.bitmaps.get(key);
if (hit) {
hit.accessId = ++this.accessCounter;
return hit.bitmap;
}
if (fontFamily !== this.fontFamily || fontSize !== this.fontSize || fontWeight !== this.fontWeight) {
this.fontFamily = fontFamily;
this.fontSize = fontSize;
this.fontWeight = fontWeight;
this.cachedFont = buildFont({ fontFamily, fontSize, fontWeight });
}
const tw = this.textWidths.get(`${text}|${fontFamily}|${fontSize}|${fontWeight}`);
if (tw === void 0) {
throw new Error(`Text width not cached for "${text}". Call measure() first.`);
}
const bmpW = Math.ceil(tw) + padding * 2;
const bmpH = fontSize + padding * 2;
const physW = bmpW * dpr | 0;
const physH = bmpH * dpr | 0;
const physPad = padding * dpr;
const physCenterY = physH / 2;
const off = new OffscreenCanvas(physW, physH);
const c = off.getContext("2d");
c.font = `${fontWeight} ${fontSize * dpr}px ${fontFamily}`;
c.lineWidth = strokeWidth * dpr;
c.lineJoin = "round";
c.textBaseline = "middle";
c.textAlign = "left";
c.strokeStyle = toCss(strokeColor);
c.strokeText(text, physPad, physCenterY);
c.fillStyle = toCss(color);
c.fillText(text, physPad, physCenterY);
const bmp = off.transferToImageBitmap();
this.bitmaps.set(key, { bitmap: bmp, accessId: ++this.accessCounter });
this.aliveBitmaps.add(bmp);
if (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
return bmp;
}
evictOne() {
let minKey = "";
let minAccess = Infinity;
for (const [k, v] of this.bitmaps) {
if (v.accessId < minAccess) {
minAccess = v.accessId;
minKey = k;
}
}
if (minKey) {
const entry = this.bitmaps.get(minKey);
if (entry) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
this.bitmaps.delete(minKey);
}
}
}
/** Returns true if the given bitmap is still cached (not evicted/closed). */
isAlive(bmp) {
return this.aliveBitmaps.has(bmp);
}
// ---- Configuration ----
setMaxCache(n) {
this.maxCache = n;
while (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
}
setDpr(dpr) {
if (this.dpr !== dpr) {
this.dpr = dpr;
this.clearBitmaps();
}
}
// ---- Cleanup ----
clearBitmaps() {
for (const [, entry] of this.bitmaps) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
}
this.bitmaps.clear();
}
clearAll() {
this.clearBitmaps();
this.textWidths.clear();
}
get bitmapCount() {
return this.bitmaps.size;
}
};
// src/core/raf-loop.ts

@@ -583,61 +362,2 @@ var _rafCallback;

// src/polyfills/requestIdleCallback.ts
var _ids = /* @__PURE__ */ new Map();
if (typeof window !== "undefined" && !window.requestIdleCallback) {
window.requestIdleCallback = function(callback, options) {
const timeout = options?.timeout;
let start = Date.now();
let timerId = 0;
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
};
if (timeout != null) {
timerId = setTimeout(() => {
idleDeadline.didTimeout = true;
start = Date.now();
callback(idleDeadline);
}, timeout);
}
const rafId = requestAnimationFrame(() => {
if (timeout != null) clearTimeout(timerId);
if (idleDeadline.didTimeout) return;
start = Date.now();
callback(idleDeadline);
});
const handle = Date.now() + Math.random();
_ids.set(handle, { rafId, timeoutId: timerId });
return handle;
};
window.cancelIdleCallback = function(handle) {
const ids = _ids.get(handle);
if (ids) {
cancelAnimationFrame(ids.rafId);
if (ids.timeoutId) clearTimeout(ids.timeoutId);
_ids.delete(handle);
}
};
}
// src/core/pre-cache.ts
function schedulePreCache(items, startIdx, count, fn) {
let idleHandle = 0;
let idx = startIdx;
function process(deadline) {
const end = Math.min(startIdx + count, items.length);
let processed = 0;
while (idx < end && (deadline.timeRemaining() > 1 || processed < 5)) {
const item = items[idx];
if (item) fn(item);
idx++;
processed++;
}
if (idx < end) {
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
}
}
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
return () => cancelIdleCallback(idleHandle);
}
// src/core/defaults.ts

@@ -655,2 +375,3 @@ var SHARED_DEFAULTS = {

strokeColor: 0,
scrollGap: 96,
speed: 1,

@@ -796,18 +517,18 @@ seekThreshold: 0.2,

// src/engine/canvas/index.ts
var _destroyed, _config, _renderer, _tracks, _pool, _cache, _loop, _scheduler, _visible, _lastTs, _cancelPreCache, _adapter2, _streamLoader, _lastPos, _tick, _CanvasEngine_instances, emit_fn, schedulePreCache_fn, resizeTracks_fn;
var CanvasEngine = class {
// src/engine/base.ts
var _destroyed, _config, _tracks, _scheduler, _loop, _visible, _lastTs, _lastPos, _adapter2, _streamLoader, _tick, _DanmakuEngineBase_instances, emit_fn, resizeTracks_fn;
var DanmakuEngineBase = class {
// ==================================================================
// Constructor
// ==================================================================
constructor(options) {
__privateAdd(this, _CanvasEngine_instances);
__privateAdd(this, _DanmakuEngineBase_instances);
__privateAdd(this, _destroyed, false);
__privateAdd(this, _config);
__privateAdd(this, _renderer);
__privateAdd(this, _tracks);
__privateAdd(this, _pool);
__privateAdd(this, _cache);
__privateAdd(this, _tracks, new TrackManager());
__privateAdd(this, _scheduler, new Scheduler());
__privateAdd(this, _loop);
__privateAdd(this, _scheduler);
__privateAdd(this, _visible, []);
__privateAdd(this, _lastTs, 0);
__privateAdd(this, _cancelPreCache, null);
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _adapter2);

@@ -818,10 +539,9 @@ __privateAdd(this, _streamLoader, null);

// ==================================================================
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _tick, (ts) => {
const pos = __privateGet(this, _adapter2).position;
const paused = __privateGet(this, _adapter2).paused;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (!__privateGet(this, _config).enabled || W === 0) {
__privateGet(this, _renderer).clear();
this.clearRenderer();
return;

@@ -834,9 +554,9 @@ }

const v = __privateGet(this, _visible)[i];
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks).releaseBottom(v.track);
__privateGet(this, _pool).release(v);
}
__privateSet(this, _visible, []);
__privateGet(this, _renderer).clear();
this.clearRenderer();
__privateGet(this, _streamLoader)?.reset();

@@ -853,42 +573,14 @@ }

for (let i = 0; i < batch.length; i++) {
__privateMethod(this, _CanvasEngine_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
}
const now = performance.now() / 1e3;
const onRemove = (v) => {
if (v.mode === 1 /* Scroll */) {
__privateGet(this, _tracks).releaseScroll(v.track);
} else if (v.mode === 5 /* Top */) {
__privateGet(this, _tracks).releaseTop(v.track);
} else if (v.mode === 6 /* Bottom */) {
__privateGet(this, _tracks).releaseBottom(v.track);
}
__privateGet(this, _pool).release(v);
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks).releaseBottom(v.track);
};
__privateGet(this, _visible).length = __privateGet(this, _scheduler).compact(__privateGet(this, _visible), now, dt, scrollSpeed, onRemove);
__privateGet(this, _renderer).clear();
__privateGet(this, _renderer).setGlobalAlpha(__privateGet(this, _config).opacity);
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const pad = __privateGet(this, _config).padding;
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const v = __privateGet(this, _visible)[i];
const bmp = v.bmp;
if (!bmp) continue;
if (!__privateGet(this, _cache).isAlive(bmp)) {
v.bmp = void 0;
continue;
}
const dx = v.x | 0;
const dy = v.y | 0;
const sw = bmp.width;
const sh = bmp.height;
const dw = sw / dpr;
const dh = sh / dpr;
const ctx = __privateGet(this, _renderer).ctx;
if (v.mode === 1 /* Scroll */) {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - pad, dy - dh / 2 | 0, dw, dh);
} else {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - dw / 2 | 0, dy - dh / 2 | 0, dw, dh);
}
}
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
this.drawFrame(W, H);
this.onAfterTick();
__privateGet(this, _streamLoader)?.probe(pos, __privateGet(this, _scheduler));

@@ -904,8 +596,2 @@ });

__privateSet(this, _adapter2, options.adapter);
__privateSet(this, _renderer, new CanvasRenderer(options.container));
__privateGet(this, _renderer).setSmoothing(__privateGet(this, _config).smoothing);
__privateSet(this, _tracks, new TrackManager());
__privateSet(this, _pool, new ObjectPool());
__privateSet(this, _cache, new BitmapCache(__privateGet(this, _config).maxCache));
__privateSet(this, _scheduler, new Scheduler());
if (options.dataSource) {

@@ -920,6 +606,34 @@ __privateSet(this, _streamLoader, new StreamLoader(

}
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateSet(this, _loop, new RafLoop(__privateGet(this, _config).fps, __privateGet(this, _tick)));
}
// ==================================================================
// Optional hooks
// ==================================================================
/** Called after load() completes. Canvas uses for pre-cache scheduling. */
onAfterLoad() {
}
/** Called after each tick(). Canvas uses for pre-cache scheduling. */
onAfterTick() {
}
/** Create a VisibleDanmaku object. Canvas overrides for object pooling. */
acquireVisibleDanmaku() {
return {};
}
// ==================================================================
// Protected accessors for subclasses
// ==================================================================
get cfg() {
return __privateGet(this, _config);
}
get visible() {
return __privateGet(this, _visible);
}
getPreCacheInfo() {
return __privateGet(this, _scheduler).preCacheInfo();
}
/** Must be called by subclass constructors after renderer is initialized. */
initTracks() {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
// ==================================================================
// Lifecycle

@@ -931,12 +645,8 @@ // ==================================================================

load(items) {
var _a;
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _cache).clearAll();
__privateGet(this, _streamLoader)?.reset();
__privateGet(this, _scheduler).load(items);
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateSet(this, _cancelPreCache, null);
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
this.onAfterLoad();
}

@@ -946,4 +656,4 @@ send(item) {

const pos = __privateGet(this, _adapter2).position;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (W === 0 || H === 0) return;

@@ -954,35 +664,28 @@ const scrollSpeed = W / 8 * __privateGet(this, _config).speed;

const sent = { ...item, time: pos };
__privateMethod(this, _CanvasEngine_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
}
clear() {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _scheduler).clear();
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).clear();
this.clearRenderer();
}
resize() {
if (__privateGet(this, _destroyed)) return;
const ok = __privateGet(this, _renderer).updateDimensions();
if (ok) {
__privateGet(this, _cache).setDpr(__privateGet(this, _renderer).devicePixelRatio);
__privateGet(this, _cache).invalidateTextCache();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
if (this.updateDimensions()) {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
}
destroy() {
var _a;
if (__privateGet(this, _destroyed)) return;
__privateSet(this, _destroyed, true);
__privateGet(this, _loop).stop();
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateGet(this, _streamLoader)?.destroy();
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).destroy();
this.destroyRenderer();
}
// ==================================================================
// Runtime setters
// Runtime setters — shared logic
// ==================================================================

@@ -992,3 +695,2 @@ setEnabled(v) {

__privateGet(this, _config).enabled = v;
if (!v) __privateGet(this, _renderer).clear();
}

@@ -1003,3 +705,3 @@ setFps(v) {

__privateGet(this, _config).area = clamp(v, 0, 1);
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -1017,4 +719,2 @@ setOpacity(v) {

__privateGet(this, _config).fontFamily = v;
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
}

@@ -1024,5 +724,3 @@ setFontSize(v) {

__privateGet(this, _config).fontSize = clamp(v, 8, 128);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -1032,4 +730,2 @@ setFontWeight(v) {

__privateGet(this, _config).fontWeight = v;
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
}

@@ -1039,3 +735,2 @@ setStrokeWidth(v) {

__privateGet(this, _config).strokeWidth = Math.max(0, v);
__privateGet(this, _cache).clearBitmaps();
}

@@ -1045,3 +740,2 @@ setStrokeColor(v) {

__privateGet(this, _config).strokeColor = v & 16777215;
__privateGet(this, _cache).clearBitmaps();
}

@@ -1051,8 +745,17 @@ setPadding(v) {

__privateGet(this, _config).padding = Math.max(0, v);
__privateGet(this, _cache).clearBitmaps();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
setScrollGap(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).scrollGap = Math.max(0, v);
}
setDuration(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).duration = Math.max(0.5, v);
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const d = __privateGet(this, _visible)[i];
if (d.mode !== 1 /* Scroll */) {
d.duration = __privateGet(this, _config).duration;
}
}
}

@@ -1067,17 +770,9 @@ setOverflow(v) {

}
setMaxCache(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).maxCache = Math.max(10, v);
__privateGet(this, _cache).setMaxCache(__privateGet(this, _config).maxCache);
// Engine-specific setters — default no-ops, overridden by subclasses
setMaxCache(_v) {
}
setPreCacheCount(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).preCacheCount = Math.max(0, v);
setPreCacheCount(_v) {
}
setSmoothing(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).smoothing = v;
__privateGet(this, _renderer).setSmoothing(v);
setSmoothing(_v) {
}
// DOM-only setters — no-ops for canvas engine
setWillChange(_v) {

@@ -1090,16 +785,12 @@ }

_config = new WeakMap();
_renderer = new WeakMap();
_tracks = new WeakMap();
_pool = new WeakMap();
_cache = new WeakMap();
_scheduler = new WeakMap();
_loop = new WeakMap();
_scheduler = new WeakMap();
_visible = new WeakMap();
_lastTs = new WeakMap();
_cancelPreCache = new WeakMap();
_lastPos = new WeakMap();
_adapter2 = new WeakMap();
_streamLoader = new WeakMap();
_lastPos = new WeakMap();
_tick = new WeakMap();
_CanvasEngine_instances = new WeakSet();
_DanmakuEngineBase_instances = new WeakSet();
// ==================================================================

@@ -1115,4 +806,3 @@ // Internal: emit a single danmaku item

const cfg = __privateGet(this, _config);
const ctx = __privateGet(this, _renderer).ctx;
const tw = __privateGet(this, _cache).measure(text, cfg.fontFamily, fs, cfg.fontWeight, ctx);
const tw = this.measureTextWidth(text, cfg.fontFamily, fs, cfg.fontWeight);
const w = tw + cfg.padding * 2;

@@ -1125,3 +815,3 @@ const h = fs;

if (mode === 1 /* Scroll */) {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -1147,3 +837,3 @@ if (cfg.overflow === "drop" && !force) return;

} else {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -1158,14 +848,3 @@ if (force) {

}
const bmp = __privateGet(this, _cache).getBitmap(
text,
fs,
color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
__privateGet(this, _renderer).devicePixelRatio,
cfg.padding
);
const v = __privateGet(this, _pool).acquire();
const v = this.acquireVisibleDanmaku();
v.id = item.id;

@@ -1183,12 +862,495 @@ v.text = text;

v.duration = cfg.duration;
v.bmp = bmp;
this.renderDanmaku(v);
__privateGet(this, _visible).push(v);
};
// ==================================================================
// Internal: resize tracks
// ==================================================================
resizeTracks_fn = function() {
const H = this.rendererHeight;
if (H === 0) return;
const cfg = __privateGet(this, _config);
const gap = Math.max(2, Math.ceil(cfg.fontSize * 0.2));
const th = cfg.fontSize + cfg.padding * 2 + gap;
__privateGet(this, _tracks).resize(H, cfg.area, th);
};
// src/engine/canvas/renderer.ts
var CanvasRenderer = class {
constructor(container) {
this.W = 0;
this.H = 0;
this.dpr = 1;
this.container = container;
const canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.inset = "0";
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.pointerEvents = "none";
container.appendChild(canvas);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.updateDimensions();
}
/** Re-measure container and resize the canvas backing store. */
updateDimensions() {
const dpr = window.devicePixelRatio || 1;
const W = this.container.clientWidth;
const H = this.container.clientHeight;
if (W === 0 || H === 0) return false;
this.dpr = dpr;
this.W = W;
this.H = H;
this.canvas.width = W * dpr;
this.canvas.height = H * dpr;
this.canvas.style.width = W + "px";
this.canvas.style.height = H + "px";
this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
return true;
}
get width() {
return this.W;
}
get height() {
return this.H;
}
get devicePixelRatio() {
return this.dpr;
}
clear() {
this.ctx.clearRect(0, 0, this.W, this.H);
}
setSmoothing(enabled) {
this.ctx.imageSmoothingEnabled = enabled;
}
setGlobalAlpha(alpha) {
this.ctx.globalAlpha = alpha;
}
destroy() {
this.canvas.remove();
}
};
// src/engine/canvas/pool.ts
var MAX_POOL_SIZE = 512;
var ObjectPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : {};
}
release(v) {
if (this.pool.length < MAX_POOL_SIZE) {
v.bmp = void 0;
v.el = void 0;
this.pool.push(v);
}
}
releaseAll(visible) {
for (let i = 0; i < visible.length; i++) {
this.release(visible[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/engine/canvas/bitmap-cache.ts
var BitmapCache = class {
constructor(maxCache = 500) {
// Text measurement cache
this.textWidths = /* @__PURE__ */ new Map();
// ImageBitmap LRU cache
this.bitmaps = /* @__PURE__ */ new Map();
this.aliveBitmaps = /* @__PURE__ */ new Set();
this.accessCounter = 0;
this.dpr = 1;
// Cache for buildFont result
this.cachedFont = "";
this.fontFamily = "";
this.fontSize = 0;
this.fontWeight = "";
this.maxCache = maxCache;
}
// ---- Text measurement ----
measure(text, fontFamily, fontSize, fontWeight, ctx) {
const key = `${text}|${fontFamily}|${fontSize}|${fontWeight}`;
const cached = this.textWidths.get(key);
if (cached !== void 0) return cached;
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
const w = ctx.measureText(text).width;
this.textWidths.set(key, w);
return w;
}
invalidateTextCache() {
this.textWidths.clear();
}
// ---- ImageBitmap cache ----
getBitmap(text, fontSize, color, strokeWidth, strokeColor, fontFamily, fontWeight, dpr, padding) {
const key = `${text}|${fontSize}|${color}|${strokeWidth}|${strokeColor}|${fontFamily}|${fontWeight}|${dpr}`;
const hit = this.bitmaps.get(key);
if (hit) {
hit.accessId = ++this.accessCounter;
return hit.bitmap;
}
if (fontFamily !== this.fontFamily || fontSize !== this.fontSize || fontWeight !== this.fontWeight) {
this.fontFamily = fontFamily;
this.fontSize = fontSize;
this.fontWeight = fontWeight;
this.cachedFont = buildFont({ fontFamily, fontSize, fontWeight });
}
const tw = this.textWidths.get(`${text}|${fontFamily}|${fontSize}|${fontWeight}`);
if (tw === void 0) {
throw new Error(`Text width not cached for "${text}". Call measure() first.`);
}
const bmpW = Math.ceil(tw) + padding * 2;
const bmpH = fontSize + padding * 2;
const physW = bmpW * dpr | 0;
const physH = bmpH * dpr | 0;
const physPad = padding * dpr;
const physCenterY = physH / 2;
const off = new OffscreenCanvas(physW, physH);
const c = off.getContext("2d");
c.font = `${fontWeight} ${fontSize * dpr}px ${fontFamily}`;
c.lineWidth = strokeWidth * dpr;
c.lineJoin = "round";
c.textBaseline = "middle";
c.textAlign = "left";
c.strokeStyle = toCss(strokeColor);
c.strokeText(text, physPad, physCenterY);
c.fillStyle = toCss(color);
c.fillText(text, physPad, physCenterY);
const bmp = off.transferToImageBitmap();
this.bitmaps.set(key, { bitmap: bmp, accessId: ++this.accessCounter });
this.aliveBitmaps.add(bmp);
if (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
return bmp;
}
evictOne() {
let minKey = "";
let minAccess = Infinity;
for (const [k, v] of this.bitmaps) {
if (v.accessId < minAccess) {
minAccess = v.accessId;
minKey = k;
}
}
if (minKey) {
const entry = this.bitmaps.get(minKey);
if (entry) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
this.bitmaps.delete(minKey);
}
}
}
/** Returns true if the given bitmap is still cached (not evicted/closed). */
isAlive(bmp) {
return this.aliveBitmaps.has(bmp);
}
// ---- Configuration ----
setMaxCache(n) {
this.maxCache = n;
while (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
}
setDpr(dpr) {
if (this.dpr !== dpr) {
this.dpr = dpr;
this.clearBitmaps();
}
}
// ---- Cleanup ----
clearBitmaps() {
for (const [, entry] of this.bitmaps) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
}
this.bitmaps.clear();
}
clearAll() {
this.clearBitmaps();
this.textWidths.clear();
}
get bitmapCount() {
return this.bitmaps.size;
}
};
// src/polyfills/requestIdleCallback.ts
var _ids = /* @__PURE__ */ new Map();
if (typeof window !== "undefined" && !window.requestIdleCallback) {
window.requestIdleCallback = function(callback, options) {
const timeout = options?.timeout;
let start = Date.now();
let timerId = 0;
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
};
if (timeout != null) {
timerId = setTimeout(() => {
idleDeadline.didTimeout = true;
start = Date.now();
callback(idleDeadline);
}, timeout);
}
const rafId = requestAnimationFrame(() => {
if (timeout != null) clearTimeout(timerId);
if (idleDeadline.didTimeout) return;
start = Date.now();
callback(idleDeadline);
});
const handle = Date.now() + Math.random();
_ids.set(handle, { rafId, timeoutId: timerId });
return handle;
};
window.cancelIdleCallback = function(handle) {
const ids = _ids.get(handle);
if (ids) {
cancelAnimationFrame(ids.rafId);
if (ids.timeoutId) clearTimeout(ids.timeoutId);
_ids.delete(handle);
}
};
}
// src/core/pre-cache.ts
function schedulePreCache(items, startIdx, count, fn) {
let idleHandle = 0;
let idx = startIdx;
function process(deadline) {
const end = Math.min(startIdx + count, items.length);
let processed = 0;
while (idx < end && (deadline.timeRemaining() > 1 || processed < 5)) {
const item = items[idx];
if (item) fn(item);
idx++;
processed++;
}
if (idx < end) {
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
}
}
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
return () => cancelIdleCallback(idleHandle);
}
// src/engine/canvas/index.ts
var _renderer, _pool, _cache, _cancelPreCache, _CanvasEngine_instances, schedulePreCache_fn;
var CanvasEngine = class extends DanmakuEngineBase {
constructor(options) {
super(options);
__privateAdd(this, _CanvasEngine_instances);
__privateAdd(this, _renderer);
__privateAdd(this, _pool, new ObjectPool());
__privateAdd(this, _cache);
__privateAdd(this, _cancelPreCache, null);
__privateSet(this, _renderer, new CanvasRenderer(options.container));
__privateGet(this, _renderer).setSmoothing(this.cfg.smoothing);
__privateSet(this, _cache, new BitmapCache(this.cfg.maxCache));
this.initTracks();
}
// ==================================================================
// Abstract hook implementations
// ==================================================================
get rendererWidth() {
return __privateGet(this, _renderer).width;
}
get rendererHeight() {
return __privateGet(this, _renderer).height;
}
clearRenderer() {
__privateGet(this, _renderer).clear();
}
destroyRenderer() {
__privateGet(this, _renderer).destroy();
}
updateDimensions() {
const ok = __privateGet(this, _renderer).updateDimensions();
if (ok) {
__privateGet(this, _cache).setDpr(__privateGet(this, _renderer).devicePixelRatio);
__privateGet(this, _cache).invalidateTextCache();
}
return ok;
}
measureTextWidth(text, family, size, weight) {
return __privateGet(this, _cache).measure(text, family, size, weight, __privateGet(this, _renderer).ctx);
}
renderDanmaku(v) {
const cfg = this.cfg;
v.bmp = __privateGet(this, _cache).getBitmap(
v.text,
v.fontSize,
v.color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
__privateGet(this, _renderer).devicePixelRatio,
cfg.padding
);
}
releaseVisibleResource(v) {
__privateGet(this, _pool).release(v);
}
releaseAllVisibleResources() {
__privateGet(this, _pool).releaseAll(this.visible);
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).clear();
}
refreshVisibleDanmaku() {
const ctx = __privateGet(this, _renderer).ctx;
const cfg = this.cfg;
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
const fs = v.fontSize;
const tw = __privateGet(this, _cache).measure(v.text, cfg.fontFamily, fs, cfg.fontWeight, ctx);
v.w = tw + cfg.padding * 2;
v.h = fs;
v.bmp = __privateGet(this, _cache).getBitmap(
v.text,
fs,
v.color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
dpr,
cfg.padding
);
}
}
drawFrame(W, _H) {
__privateGet(this, _renderer).clear();
__privateGet(this, _renderer).setGlobalAlpha(this.cfg.opacity);
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const pad = this.cfg.padding;
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
const bmp = v.bmp;
if (!bmp) continue;
if (!__privateGet(this, _cache).isAlive(bmp)) {
v.bmp = void 0;
continue;
}
const dx = v.x | 0;
const dy = v.y | 0;
const sw = bmp.width;
const sh = bmp.height;
const dw = sw / dpr;
const dh = sh / dpr;
const ctx = __privateGet(this, _renderer).ctx;
if (v.mode === 1) {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - pad, dy - dh / 2 | 0, dw, dh);
} else {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - dw / 2 | 0, dy - dh / 2 | 0, dw, dh);
}
}
}
acquireVisibleDanmaku() {
return __privateGet(this, _pool).acquire();
}
onAfterLoad() {
var _a;
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateSet(this, _cancelPreCache, null);
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
}
onAfterTick() {
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
}
// ==================================================================
// Override setters — add canvas-specific cache invalidation + refresh
// ==================================================================
setEnabled(v) {
super.setEnabled(v);
if (!v) __privateGet(this, _renderer).clear();
}
setFontFamily(v) {
super.setFontFamily(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setFontSize(v) {
super.setFontSize(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setFontWeight(v) {
super.setFontWeight(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setStrokeWidth(v) {
super.setStrokeWidth(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setStrokeColor(v) {
super.setStrokeColor(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setPadding(v) {
super.setPadding(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setScrollGap(v) {
super.setScrollGap(v);
this.refreshVisibleDanmaku();
}
setMaxCache(v) {
if (this.isDestroyed) return;
this.cfg.maxCache = Math.max(10, v);
__privateGet(this, _cache).setMaxCache(this.cfg.maxCache);
}
setPreCacheCount(v) {
if (this.isDestroyed) return;
this.cfg.preCacheCount = Math.max(0, v);
}
setSmoothing(v) {
if (this.isDestroyed) return;
this.cfg.smoothing = v;
__privateGet(this, _renderer).setSmoothing(v);
}
};
_renderer = new WeakMap();
_pool = new WeakMap();
_cache = new WeakMap();
_cancelPreCache = new WeakMap();
_CanvasEngine_instances = new WeakSet();
// ==================================================================
// Internal: pre-cache scheduling
// ==================================================================
schedulePreCache_fn = function() {
if (__privateGet(this, _cancelPreCache) || __privateGet(this, _destroyed)) return;
const { pool, cursor } = __privateGet(this, _scheduler).preCacheInfo();
const cfg = __privateGet(this, _config);
if (__privateGet(this, _cancelPreCache) || this.isDestroyed) return;
const { pool, cursor } = this.getPreCacheInfo();
const cfg = this.cfg;
__privateSet(this, _cancelPreCache, schedulePreCache(

@@ -1220,13 +1382,2 @@ pool,

};
// ==================================================================
// Internal: resize tracks
// ==================================================================
resizeTracks_fn = function() {
const H = __privateGet(this, _renderer).height;
if (H === 0) return;
const cfg = __privateGet(this, _config);
const gap = Math.max(2, Math.ceil(cfg.fontSize * 0.2));
const th = cfg.fontSize + cfg.padding * 2 + gap;
__privateGet(this, _tracks).resize(H, cfg.area, th);
};

@@ -1233,0 +1384,0 @@ // src/canvas.ts

@@ -1,2 +0,2 @@

var wt=h=>{throw TypeError(h)};var ft=(h,t,i)=>t.has(h)||wt("Cannot "+i);var e=(h,t,i)=>(ft(h,t,"read from private field"),i?i.call(h):t.get(h)),p=(h,t,i)=>t.has(h)?wt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(h):t.set(h,i),u=(h,t,i,r)=>(ft(h,t,"write to private field"),t.set(h,i),i),I=(h,t,i)=>(ft(h,t,"access private method"),i);var bt=(h,t,i,r)=>({set _(o){u(h,t,o);},get _(){return e(h,t,r)}});var et=(r=>(r[r.Scroll=1]="Scroll",r[r.Top=5]="Top",r[r.Bottom=6]="Bottom",r))(et||{});var it=class{constructor(t){this.W=0;this.H=0;this.dpr=1;this.container=t;let i=document.createElement("canvas");i.style.position="absolute",i.style.inset="0",i.style.width="100%",i.style.height="100%",i.style.pointerEvents="none",t.appendChild(i),this.canvas=i,this.ctx=i.getContext("2d"),this.updateDimensions();}updateDimensions(){let t=window.devicePixelRatio||1,i=this.container.clientWidth,r=this.container.clientHeight;return i===0||r===0?false:(this.dpr=t,this.W=i,this.H=r,this.canvas.width=i*t,this.canvas.height=r*t,this.canvas.style.width=i+"px",this.canvas.style.height=r+"px",this.ctx.setTransform(t,0,0,t,0,0),true)}get width(){return this.W}get height(){return this.H}get devicePixelRatio(){return this.dpr}clear(){this.ctx.clearRect(0,0,this.W,this.H);}setSmoothing(t){this.ctx.imageSmoothingEnabled=t;}setGlobalAlpha(t){this.ctx.globalAlpha=t;}destroy(){this.canvas.remove();}};var rt=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(t,i,r){this.H=t,this.th=r,this.areaFraction=i;let o=t*i,s=Math.max(1,Math.floor(o/r)),n=Math.max(1,Math.floor(o*.48/r));this.scrollCount=s,this.topCount=n,this.bottomCount=n,this.scrollExit=new Float64Array(s).fill(-1/0),this.topExit=new Float64Array(n).fill(-1/0),this.bottomExit=new Float64Array(n).fill(-1/0),this.scrollFree=Array.from({length:s},(a,l)=>l),this.topFree=Array.from({length:n},(a,l)=>l),this.bottomFree=Array.from({length:n},(a,l)=>l);}acquireScroll(t,i,r,o){let s=[];for(;this.scrollFree.length>0;){let a=this.scrollFree.pop();if(this.scrollExit[a]<=t){this.scrollExit[a]=t+i*1.2/r;for(let l of s)this.scrollFree.push(l);return {track:a,y:this.scrollY(a)}}s.push(a);}for(let a of s)this.scrollFree.push(a);let n=Math.random()*this.scrollCount|0;for(let a=0;a<this.scrollCount;a++){let l=(n+a)%this.scrollCount;if(this.scrollExit[l]<=t){this.scrollExit[l]=t+i*1.2/r;let w=this.scrollFree.indexOf(l);return w!==-1&&this.scrollFree.splice(w,1),{track:l,y:this.scrollY(l)}}}return null}releaseScroll(t){this.scrollExit[t]=-1/0,this.scrollFree.includes(t)||this.scrollFree.push(t);}acquireTop(t,i){let r=[];for(;this.topFree.length>0;){let s=this.topFree.pop();if(this.topExit[s]<=t){this.topExit[s]=t+i;for(let n of r)this.topFree.push(n);return {track:s,y:this.fixedY(s,true)}}r.push(s);}for(let s of r)this.topFree.push(s);let o=Math.random()*this.topCount|0;for(let s=0;s<this.topCount;s++){let n=(o+s)%this.topCount;if(this.topExit[n]<=t){this.topExit[n]=t+i;let a=this.topFree.indexOf(n);return a!==-1&&this.topFree.splice(a,1),{track:n,y:this.fixedY(n,true)}}}return null}releaseTop(t){this.topExit[t]=-1/0,this.topFree.includes(t)||this.topFree.push(t);}acquireBottom(t,i){let r=[];for(;this.bottomFree.length>0;){let s=this.bottomFree.pop();if(this.bottomExit[s]<=t){this.bottomExit[s]=t+i;for(let n of r)this.bottomFree.push(n);return {track:s,y:this.fixedY(s,false)}}r.push(s);}for(let s of r)this.bottomFree.push(s);let o=Math.random()*this.bottomCount|0;for(let s=0;s<this.bottomCount;s++){let n=(o+s)%this.bottomCount;if(this.bottomExit[n]<=t){this.bottomExit[n]=t+i;let a=this.bottomFree.indexOf(n);return a!==-1&&this.bottomFree.splice(a,1),{track:n,y:this.fixedY(n,false)}}}return null}releaseBottom(t){this.bottomExit[t]=-1/0,this.bottomFree.includes(t)||this.bottomFree.push(t);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(t){return (t+.5)*this.th}fixedY(t,i){return i?(t+.5)*this.th:this.H*this.areaFraction-(t+.5)*this.th}};var st=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():{}}release(t){this.pool.length<512&&(t.bmp=void 0,t.el=void 0,this.pool.push(t));}releaseAll(t){for(let i=0;i<t.length;i++)this.release(t[i]);}get size(){return this.pool.length}};function vt(h){return h<0||h>16777215||!Number.isFinite(h)?"#000000":"#"+h.toString(16).padStart(6,"0")}function gt({fontFamily:h,fontSize:t,fontWeight:i}){return `${i} ${t}px ${h}`}var ot=class{constructor(t=500){this.textWidths=new Map;this.bitmaps=new Map;this.aliveBitmaps=new Set;this.accessCounter=0;this.dpr=1;this.cachedFont="";this.fontFamily="";this.fontSize=0;this.fontWeight="";this.maxCache=t;}measure(t,i,r,o,s){let n=`${t}|${i}|${r}|${o}`,a=this.textWidths.get(n);if(a!==void 0)return a;s.font=gt({fontFamily:i,fontSize:r,fontWeight:o});let l=s.measureText(t).width;return this.textWidths.set(n,l),l}invalidateTextCache(){this.textWidths.clear();}getBitmap(t,i,r,o,s,n,a,l,w){let T=`${t}|${i}|${r}|${o}|${s}|${n}|${a}|${l}`,S=this.bitmaps.get(T);if(S)return S.accessId=++this.accessCounter,S.bitmap;(n!==this.fontFamily||i!==this.fontSize||a!==this.fontWeight)&&(this.fontFamily=n,this.fontSize=i,this.fontWeight=a,this.cachedFont=gt({fontFamily:n,fontSize:i,fontWeight:a}));let b=this.textWidths.get(`${t}|${n}|${i}|${a}`);if(b===void 0)throw new Error(`Text width not cached for "${t}". Call measure() first.`);let G=Math.ceil(b)+w*2,Q=i+w*2,A=G*l|0,z=Q*l|0,c=w*l,C=z/2,v=new OffscreenCanvas(A,z),g=v.getContext("2d");g.font=`${a} ${i*l}px ${n}`,g.lineWidth=o*l,g.lineJoin="round",g.textBaseline="middle",g.textAlign="left",g.strokeStyle=vt(s),g.strokeText(t,c,C),g.fillStyle=vt(r),g.fillText(t,c,C);let V=v.transferToImageBitmap();return this.bitmaps.set(T,{bitmap:V,accessId:++this.accessCounter}),this.aliveBitmaps.add(V),this.bitmaps.size>this.maxCache&&this.evictOne(),V}evictOne(){let t="",i=1/0;for(let[r,o]of this.bitmaps)o.accessId<i&&(i=o.accessId,t=r);if(t){let r=this.bitmaps.get(t);r&&(this.aliveBitmaps.delete(r.bitmap),r.bitmap.close(),this.bitmaps.delete(t));}}isAlive(t){return this.aliveBitmaps.has(t)}setMaxCache(t){for(this.maxCache=t;this.bitmaps.size>this.maxCache;)this.evictOne();}setDpr(t){this.dpr!==t&&(this.dpr=t,this.clearBitmaps());}clearBitmaps(){for(let[,t]of this.bitmaps)this.aliveBitmaps.delete(t.bitmap),t.bitmap.close();this.bitmaps.clear();}clearAll(){this.clearBitmaps(),this.textWidths.clear();}get bitmapCount(){return this.bitmaps.size}};var U,nt=class{constructor(t,i,r=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;p(this,U,t=>{this.stopped||(this.tick(t),this.rafId=requestAnimationFrame(e(this,U)));});this.frameInterval=1e3/t,this.callback=i,r&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(e(this,U)));}tick(t){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=t,this.callback(t),true;let i=t-this.lastFrameTime;return i>=this.frameInterval?(this.lastFrameTime=t-i%this.frameInterval,this.callback(t),true):false}setFps(t){this.frameInterval=1e3/t;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};U=new WeakMap;function J(h,t,i){return h<t?t:h>i?i:h}function at(h,t,i,r=0,o=h.length){for(;r<o;){let s=r+o>>1;i(h[s])<=t?r=s+1:o=s;}return r}var ht=class{constructor(){this.pool=[];this.cursor=0;}load(t){this.pool=[...t].sort((i,r)=>i.time-r.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(t){if(this.pool.length===0)return [];let i=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(t<i-200&&(this.cursor=at(this.pool,t,s=>(s.time??0)*1e3)),this.cursor>=this.pool.length)return [];let r=at(this.pool,t,s=>(s.time??0)*1e3);if(r<=this.cursor)return [];let o=this.pool.slice(this.cursor,r);return this.cursor=r,o}compact(t,i,r,o,s){let n=0;for(let a=0;a<t.length;a++){let l=t[a];if(l.mode===1){if(l.x-=o*r,l.x+l.w<-10){s(l);continue}}else if(i-l.born>=l.duration){s(l);continue}n!==a&&(t[n]=t[a]),n++;}return n}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(t){if(t.length===0)return;let i=new Set;for(let a=0;a<this.pool.length;a++)i.add(this.pool[a].id);let r=[...t].filter(a=>!i.has(a.id)).sort((a,l)=>a.time-l.time);if(r.length===0)return;let o=[],s=0,n=0;for(;s<this.pool.length&&n<r.length;)this.pool[s].time<=r[n].time?(o.push(this.pool[s]),s++):(o.push(r[n]),n++);for(;s<this.pool.length;)o.push(this.pool[s++]);for(;n<r.length;)o.push(r[n++]);this.pool=o;}evictBefore(t){if(this.pool.length===0)return;let i=at(this.pool,t*1e3-.1,r=>(r.time??0)*1e3);i!==0&&(this.pool.splice(0,i),this.cursor=Math.max(0,this.cursor-i));}};var xt=new Map;typeof window<"u"&&!window.requestIdleCallback&&(window.requestIdleCallback=function(h,t){let i=t?.timeout,r=Date.now(),o=0,s={didTimeout:false,timeRemaining:()=>Math.max(0,50-(Date.now()-r))};i!=null&&(o=setTimeout(()=>{s.didTimeout=true,r=Date.now(),h(s);},i));let n=requestAnimationFrame(()=>{i!=null&&clearTimeout(o),!s.didTimeout&&(r=Date.now(),h(s));}),a=Date.now()+Math.random();return xt.set(a,{rafId:n,timeoutId:o}),a},window.cancelIdleCallback=function(h){let t=xt.get(h);t&&(cancelAnimationFrame(t.rafId),t.timeoutId&&clearTimeout(t.timeoutId),xt.delete(h));});function It(h,t,i,r){let o=0,s=t;function n(a){let l=Math.min(t+i,h.length),w=0;for(;s<l&&(a.timeRemaining()>1||w<5);){let T=h[s];T&&r(T),s++,w++;}s<l&&(o=requestIdleCallback(n,{timeout:2e3}));}return o=requestIdleCallback(n,{timeout:2e3}),()=>cancelIdleCallback(o)}var Ft={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var X,Z,q,K,N,D,H,B,P,R,Dt,Tt,St,lt=class{constructor(t,i,r,o,s){p(this,R);p(this,X);p(this,Z);p(this,q);p(this,K);p(this,N);p(this,D,[]);p(this,H,0);p(this,B,null);p(this,P,-1);u(this,X,t),u(this,Z,Math.max(1,i)),u(this,q,Math.max(0,r)),u(this,K,Math.max(.5,o*2.5)),u(this,N,s);}probe(t,i){if(e(this,P)>=0&&Math.abs(t-e(this,P))>e(this,K)&&this.reset(),u(this,P,t),e(this,q)>0){let s=t-e(this,q);i.evictBefore(s),u(this,D,e(this,D).filter(n=>n.end>s));}if(e(this,B))return;let r=t+e(this,Z),o=I(this,R,Dt).call(this,t,r);o&&I(this,R,Tt).call(this,o.start,o.end,i);}reset(){bt(this,H)._++,u(this,B,null),u(this,D,[]),u(this,P,-1);}destroy(){this.reset();}};X=new WeakMap,Z=new WeakMap,q=new WeakMap,K=new WeakMap,N=new WeakMap,D=new WeakMap,H=new WeakMap,B=new WeakMap,P=new WeakMap,R=new WeakSet,Dt=function(t,i){let r=t;for(let o of e(this,D))if(o.start<=r&&r<o.end){if(r=o.end,r>=i)return null}else if(o.start>r)return {start:r,end:Math.min(o.start,i)};return r<i?{start:r,end:i}:null},Tt=function(t,i,r){let o=++bt(this,H)._;u(this,B,e(this,X).fetch(t,i).then(s=>{o===e(this,H)&&(u(this,B,null),s.length>0&&r.add(s),I(this,R,St).call(this,{start:t,end:i}));}).catch(s=>{var n;o===e(this,H)&&(u(this,B,null),(n=e(this,N))==null||n.call(this,s instanceof Error?s:new Error(String(s))));}));},St=function(t){e(this,D).push(t),e(this,D).sort((r,o)=>r.start-o.start);let i=[];for(let r of e(this,D)){let o=i[i.length-1];o&&o.end>=r.start?o.end=Math.max(o.end,r.end):i.push({...r});}u(this,D,i);};var d,m,f,y,E,x,L,M,k,Y,O,$,W,j,ct,F,yt,Ct,_,mt=class{constructor(t){p(this,F);p(this,d,false);p(this,m);p(this,f);p(this,y);p(this,E);p(this,x);p(this,L);p(this,M);p(this,k,[]);p(this,Y,0);p(this,O,null);p(this,$);p(this,W,null);p(this,j,-1);p(this,ct,t=>{let i=e(this,$).position,r=e(this,$).paused,o=e(this,f).width,s=e(this,f).height;if(!e(this,m).enabled||o===0){e(this,f).clear();return}if(r)return;let n=Math.abs(i-e(this,j));if(e(this,j)>=0&&n>e(this,m).seekThreshold){for(let c=0;c<e(this,k).length;c++){let C=e(this,k)[c];C.mode===1?e(this,y).releaseScroll(C.track):C.mode===5?e(this,y).releaseTop(C.track):C.mode===6&&e(this,y).releaseBottom(C.track),e(this,E).release(C);}u(this,k,[]),e(this,f).clear(),e(this,W)?.reset();}u(this,j,i);let a=e(this,Y)?Math.min((t-e(this,Y))/1e3,.05):0;u(this,Y,t);let l=o/8*e(this,m).speed,w=Math.max(2,Math.ceil(e(this,m).fontSize*.2)),T=e(this,m).fontSize+e(this,m).padding*2+w,S=i*1e3,b=e(this,M).emitBatch(S);for(let c=0;c<b.length;c++)I(this,F,yt).call(this,b[c],i,l,T,o,s);let G=performance.now()/1e3,Q=c=>{c.mode===1?e(this,y).releaseScroll(c.track):c.mode===5?e(this,y).releaseTop(c.track):c.mode===6&&e(this,y).releaseBottom(c.track),e(this,E).release(c);};e(this,k).length=e(this,M).compact(e(this,k),G,a,l,Q),e(this,f).clear(),e(this,f).setGlobalAlpha(e(this,m).opacity);let A=e(this,f).devicePixelRatio,z=e(this,m).padding;for(let c=0;c<e(this,k).length;c++){let C=e(this,k)[c],v=C.bmp;if(!v)continue;if(!e(this,x).isAlive(v)){C.bmp=void 0;continue}let g=C.x|0,V=C.y|0,ut=v.width,pt=v.height,dt=ut/A,tt=pt/A,kt=e(this,f).ctx;C.mode===1?kt.drawImage(v,0,0,ut,pt,g-z,V-tt/2|0,dt,tt):kt.drawImage(v,0,0,ut,pt,g-dt/2|0,V-tt/2|0,dt,tt);}I(this,F,Ct).call(this),e(this,W)?.probe(i,e(this,M));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");u(this,m,{...Ft,...t}),u(this,$,t.adapter),u(this,f,new it(t.container)),e(this,f).setSmoothing(e(this,m).smoothing),u(this,y,new rt),u(this,E,new st),u(this,x,new ot(e(this,m).maxCache)),u(this,M,new ht),t.dataSource&&u(this,W,new lt(t.dataSource,e(this,m).preBuffer,e(this,m).leadTime,e(this,m).seekThreshold,t.onError)),I(this,F,_).call(this),u(this,L,new nt(e(this,m).fps,e(this,ct)));}get isDestroyed(){return e(this,d)}load(t){var i;e(this,d)||(e(this,E).releaseAll(e(this,k)),u(this,k,[]),e(this,x).clearAll(),e(this,W)?.reset(),e(this,M).load(t),(i=e(this,O))==null||i.call(this),u(this,O,null),I(this,F,Ct).call(this));}send(t){if(e(this,d)||!e(this,m).enabled)return;let i=e(this,$).position,r=e(this,f).width,o=e(this,f).height;if(r===0||o===0)return;let s=r/8*e(this,m).speed,n=Math.max(2,Math.ceil(e(this,m).fontSize*.2)),a=e(this,m).fontSize+e(this,m).padding*2+n,l={...t,time:i};I(this,F,yt).call(this,l,i,s,a,r,o,true);}clear(){e(this,d)||(e(this,E).releaseAll(e(this,k)),u(this,k,[]),e(this,M).clear(),e(this,x).clearAll(),e(this,f).clear());}resize(){if(e(this,d))return;e(this,f).updateDimensions()&&(e(this,x).setDpr(e(this,f).devicePixelRatio),e(this,x).invalidateTextCache(),I(this,F,_).call(this));}destroy(){var t;e(this,d)||(u(this,d,true),e(this,L).stop(),(t=e(this,O))==null||t.call(this),e(this,W)?.destroy(),e(this,E).releaseAll(e(this,k)),u(this,k,[]),e(this,x).clearAll(),e(this,f).destroy());}setEnabled(t){e(this,d)||(e(this,m).enabled=t,t||e(this,f).clear());}setFps(t){e(this,d)||(e(this,m).fps=J(t,1,120),e(this,L).setFps(e(this,m).fps));}setArea(t){e(this,d)||(e(this,m).area=J(t,0,1),I(this,F,_).call(this));}setOpacity(t){e(this,d)||(e(this,m).opacity=J(t,0,1));}setSpeed(t){e(this,d)||(e(this,m).speed=Math.max(.1,t));}setFontFamily(t){e(this,d)||(e(this,m).fontFamily=t,e(this,x).invalidateTextCache(),e(this,x).clearBitmaps());}setFontSize(t){e(this,d)||(e(this,m).fontSize=J(t,8,128),e(this,x).invalidateTextCache(),e(this,x).clearBitmaps(),I(this,F,_).call(this));}setFontWeight(t){e(this,d)||(e(this,m).fontWeight=t,e(this,x).invalidateTextCache(),e(this,x).clearBitmaps());}setStrokeWidth(t){e(this,d)||(e(this,m).strokeWidth=Math.max(0,t),e(this,x).clearBitmaps());}setStrokeColor(t){e(this,d)||(e(this,m).strokeColor=t&16777215,e(this,x).clearBitmaps());}setPadding(t){e(this,d)||(e(this,m).padding=Math.max(0,t),e(this,x).clearBitmaps(),I(this,F,_).call(this));}setDuration(t){e(this,d)||(e(this,m).duration=Math.max(.5,t));}setOverflow(t){e(this,d)||(e(this,m).overflow=t);}setMaxVisible(t){e(this,d)||(e(this,m).maxVisible=Math.max(0,t));}setMaxCache(t){e(this,d)||(e(this,m).maxCache=Math.max(10,t),e(this,x).setMaxCache(e(this,m).maxCache));}setPreCacheCount(t){e(this,d)||(e(this,m).preCacheCount=Math.max(0,t));}setSmoothing(t){e(this,d)||(e(this,m).smoothing=t,e(this,f).setSmoothing(t));}setWillChange(t){}setUseTextShadow(t){}};d=new WeakMap,m=new WeakMap,f=new WeakMap,y=new WeakMap,E=new WeakMap,x=new WeakMap,L=new WeakMap,M=new WeakMap,k=new WeakMap,Y=new WeakMap,O=new WeakMap,$=new WeakMap,W=new WeakMap,j=new WeakMap,ct=new WeakMap,F=new WeakSet,yt=function(t,i,r,o,s,n,a){let l=t.mode??1,w=t.text??"";if(!w)return;let T=t.color??16777215,S=t.font_size??e(this,m).fontSize,b=e(this,m),G=e(this,f).ctx,A=e(this,x).measure(w,b.fontFamily,S,b.fontWeight,G)+b.padding*2,z=S;if(!a&&b.maxVisible>0&&e(this,k).length>=b.maxVisible&&b.overflow==="drop")return;let c=null;if(l===1){if(c=e(this,y).acquireScroll(i,A,r,s),!c){if(b.overflow==="drop"&&!a)return;let g=Math.random()*e(this,y).scrollTrackCount|0;c={track:g,y:(g+.5)*o};}}else if(l===5){if(c=e(this,y).acquireTop(i,b.duration),!c){if(b.overflow==="drop"&&!a)return;let g=Math.random()*e(this,y).topTrackCount|0;c={track:g,y:(g+.5)*o};}}else if(l===6){if(c=e(this,y).acquireBottom(i,b.duration),!c){if(b.overflow==="drop"&&!a)return;let g=Math.random()*e(this,y).bottomTrackCount|0;c={track:g,y:n*b.area-(g+.5)*o};}}else if(c=e(this,y).acquireScroll(i,A,r,s),!c)if(a){let g=Math.random()*e(this,y).scrollTrackCount|0;c={track:g,y:(g+.5)*o};}else return;let C=e(this,x).getBitmap(w,S,T,b.strokeWidth,b.strokeColor,b.fontFamily,b.fontWeight,e(this,f).devicePixelRatio,b.padding),v=e(this,E).acquire();v.id=t.id,v.text=w,v.mode=l,v.color=T,v.fontSize=S,v.x=l===1?s:s/2,v.y=c.y,v.track=c.track,v.w=A,v.h=z,v.born=performance.now()/1e3,v.duration=b.duration,v.bmp=C,e(this,k).push(v);},Ct=function(){if(e(this,O)||e(this,d))return;let{pool:t,cursor:i}=e(this,M).preCacheInfo(),r=e(this,m);u(this,O,It(t,i,r.preCacheCount,o=>{let s=o.text??"",n=o.font_size??r.fontSize,a=o.color??16777215;e(this,x).measure(s,r.fontFamily,n,r.fontWeight,e(this,f).ctx);try{e(this,x).getBitmap(s,n,a,r.strokeWidth,r.strokeColor,r.fontFamily,r.fontWeight,e(this,f).devicePixelRatio,r.padding);}catch{}}));},_=function(){let t=e(this,f).height;if(t===0)return;let i=e(this,m),r=Math.max(2,Math.ceil(i.fontSize*.2)),o=i.fontSize+i.padding*2+r;e(this,y).resize(t,i.area,o);};function ce(h,t){if(h!=="canvas")throw new TypeError("other engines are not available in canvas-only package");if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(t.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');return new mt(t)}export{et as DanmakuMode,ce as createEngine};//# sourceMappingURL=canvas.min.js.map
var yt=l=>{throw TypeError(l)};var ut=(l,t,e)=>t.has(l)||yt("Cannot "+e);var i=(l,t,e)=>(ut(l,t,"read from private field"),e?e.call(l):t.get(l)),u=(l,t,e)=>t.has(l)?yt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(l):t.set(l,e),m=(l,t,e,r)=>(ut(l,t,"write to private field"),t.set(l,e),e),w=(l,t,e)=>(ut(l,t,"access private method"),e);var dt=(l,t,e,r)=>({set _(o){m(l,t,o);},get _(){return i(l,t,r)}});var Q=(r=>(r[r.Scroll=1]="Scroll",r[r.Top=5]="Top",r[r.Bottom=6]="Bottom",r))(Q||{});var tt=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(t,e,r){this.H=t,this.th=r,this.areaFraction=e;let o=t*e,s=Math.max(1,Math.floor(o/r)),n=Math.max(1,Math.floor(o*.48/r));this.scrollCount=s,this.topCount=n,this.bottomCount=n,this.scrollExit=new Float64Array(s).fill(-1/0),this.topExit=new Float64Array(n).fill(-1/0),this.bottomExit=new Float64Array(n).fill(-1/0),this.scrollFree=Array.from({length:s},(a,h)=>h),this.topFree=Array.from({length:n},(a,h)=>h),this.bottomFree=Array.from({length:n},(a,h)=>h);}acquireScroll(t,e,r,o,s){let n=[];for(;this.scrollFree.length>0;){let h=this.scrollFree.pop();if(this.scrollExit[h]<=t){this.scrollExit[h]=t+(e+s*o/1920)/r;for(let d of n)this.scrollFree.push(d);return {track:h,y:this.scrollY(h)}}n.push(h);}for(let h of n)this.scrollFree.push(h);let a=Math.random()*this.scrollCount|0;for(let h=0;h<this.scrollCount;h++){let d=(a+h)%this.scrollCount;if(this.scrollExit[d]<=t){this.scrollExit[d]=t+(e+s*o/1920)/r;let D=this.scrollFree.indexOf(d);return D!==-1&&this.scrollFree.splice(D,1),{track:d,y:this.scrollY(d)}}}return null}releaseScroll(t){this.scrollExit[t]=-1/0,this.scrollFree.includes(t)||this.scrollFree.push(t);}acquireTop(t,e){let r=[];for(;this.topFree.length>0;){let s=this.topFree.pop();if(this.topExit[s]<=t){this.topExit[s]=t+e;for(let n of r)this.topFree.push(n);return {track:s,y:this.fixedY(s,true)}}r.push(s);}for(let s of r)this.topFree.push(s);let o=Math.random()*this.topCount|0;for(let s=0;s<this.topCount;s++){let n=(o+s)%this.topCount;if(this.topExit[n]<=t){this.topExit[n]=t+e;let a=this.topFree.indexOf(n);return a!==-1&&this.topFree.splice(a,1),{track:n,y:this.fixedY(n,true)}}}return null}releaseTop(t){this.topExit[t]=-1/0,this.topFree.includes(t)||this.topFree.push(t);}acquireBottom(t,e){let r=[];for(;this.bottomFree.length>0;){let s=this.bottomFree.pop();if(this.bottomExit[s]<=t){this.bottomExit[s]=t+e;for(let n of r)this.bottomFree.push(n);return {track:s,y:this.fixedY(s,false)}}r.push(s);}for(let s of r)this.bottomFree.push(s);let o=Math.random()*this.bottomCount|0;for(let s=0;s<this.bottomCount;s++){let n=(o+s)%this.bottomCount;if(this.bottomExit[n]<=t){this.bottomExit[n]=t+e;let a=this.bottomFree.indexOf(n);return a!==-1&&this.bottomFree.splice(a,1),{track:n,y:this.fixedY(n,false)}}}return null}releaseBottom(t){this.bottomExit[t]=-1/0,this.bottomFree.includes(t)||this.bottomFree.push(t);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(t){return (t+.5)*this.th}fixedY(t,e){return e?(t+.5)*this.th:this.H*this.areaFraction-(t+.5)*this.th}};var j,et=class{constructor(t,e,r=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;u(this,j,t=>{this.stopped||(this.tick(t),this.rafId=requestAnimationFrame(i(this,j)));});this.frameInterval=1e3/t,this.callback=e,r&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(i(this,j)));}tick(t){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=t,this.callback(t),true;let e=t-this.lastFrameTime;return e>=this.frameInterval?(this.lastFrameTime=t-e%this.frameInterval,this.callback(t),true):false}setFps(t){this.frameInterval=1e3/t;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};j=new WeakMap;function U(l,t,e){return l<t?t:l>e?e:l}function it(l,t,e,r=0,o=l.length){for(;r<o;){let s=r+o>>1;e(l[s])<=t?r=s+1:o=s;}return r}var rt=class{constructor(){this.pool=[];this.cursor=0;}load(t){this.pool=[...t].sort((e,r)=>e.time-r.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(t){if(this.pool.length===0)return [];let e=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(t<e-200&&(this.cursor=it(this.pool,t,s=>(s.time??0)*1e3)),this.cursor>=this.pool.length)return [];let r=it(this.pool,t,s=>(s.time??0)*1e3);if(r<=this.cursor)return [];let o=this.pool.slice(this.cursor,r);return this.cursor=r,o}compact(t,e,r,o,s){let n=0;for(let a=0;a<t.length;a++){let h=t[a];if(h.mode===1){if(h.x-=o*r,h.x+h.w<-10){s(h);continue}}else if(e-h.born>=h.duration){s(h);continue}n!==a&&(t[n]=t[a]),n++;}return n}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(t){if(t.length===0)return;let e=new Set;for(let a=0;a<this.pool.length;a++)e.add(this.pool[a].id);let r=[...t].filter(a=>!e.has(a.id)).sort((a,h)=>a.time-h.time);if(r.length===0)return;let o=[],s=0,n=0;for(;s<this.pool.length&&n<r.length;)this.pool[s].time<=r[n].time?(o.push(this.pool[s]),s++):(o.push(r[n]),n++);for(;s<this.pool.length;)o.push(this.pool[s++]);for(;n<r.length;)o.push(r[n++]);this.pool=o;}evictBefore(t){if(this.pool.length===0)return;let e=it(this.pool,t*1e3-.1,r=>(r.time??0)*1e3);e!==0&&(this.pool.splice(0,e),this.cursor=Math.max(0,this.cursor-e));}};var kt={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,scrollGap:96,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var J,X,$,Z,K,S,H,V,O,B,Ct,Dt,wt,st=class{constructor(t,e,r,o,s){u(this,B);u(this,J);u(this,X);u(this,$);u(this,Z);u(this,K);u(this,S,[]);u(this,H,0);u(this,V,null);u(this,O,-1);m(this,J,t),m(this,X,Math.max(1,e)),m(this,$,Math.max(0,r)),m(this,Z,Math.max(.5,o*2.5)),m(this,K,s);}probe(t,e){if(i(this,O)>=0&&Math.abs(t-i(this,O))>i(this,Z)&&this.reset(),m(this,O,t),i(this,$)>0){let s=t-i(this,$);e.evictBefore(s),m(this,S,i(this,S).filter(n=>n.end>s));}if(i(this,V))return;let r=t+i(this,X),o=w(this,B,Ct).call(this,t,r);o&&w(this,B,Dt).call(this,o.start,o.end,e);}reset(){dt(this,H)._++,m(this,V,null),m(this,S,[]),m(this,O,-1);}destroy(){this.reset();}};J=new WeakMap,X=new WeakMap,$=new WeakMap,Z=new WeakMap,K=new WeakMap,S=new WeakMap,H=new WeakMap,V=new WeakMap,O=new WeakMap,B=new WeakSet,Ct=function(t,e){let r=t;for(let o of i(this,S))if(o.start<=r&&r<o.end){if(r=o.end,r>=e)return null}else if(o.start>r)return {start:r,end:Math.min(o.start,e)};return r<e?{start:r,end:e}:null},Dt=function(t,e,r){let o=++dt(this,H)._;m(this,V,i(this,J).fetch(t,e).then(s=>{o===i(this,H)&&(m(this,V,null),s.length>0&&r.add(s),w(this,B,wt).call(this,{start:t,end:e}));}).catch(s=>{var n;o===i(this,H)&&(m(this,V,null),(n=i(this,K))==null||n.call(this,s instanceof Error?s:new Error(String(s))));}));},wt=function(t){i(this,S).push(t),i(this,S).sort((r,o)=>r.start-o.start);let e=[];for(let r of i(this,S)){let o=e[e.length-1];o&&o.end>=r.start?o.end=Math.max(o.end,r.end):e.push({...r});}m(this,S,e);};var b,c,y,A,_,C,L,G,P,W,nt,E,pt,q,ot=class{constructor(t){u(this,E);u(this,b,false);u(this,c);u(this,y,new tt);u(this,A,new rt);u(this,_);u(this,C,[]);u(this,L,0);u(this,G,-1);u(this,P);u(this,W,null);u(this,nt,t=>{let e=i(this,P).position,r=i(this,P).paused,o=this.rendererWidth,s=this.rendererHeight;if(!i(this,c).enabled||o===0){this.clearRenderer();return}if(r)return;let n=Math.abs(e-i(this,G));if(i(this,G)>=0&&n>i(this,c).seekThreshold){for(let v=0;v<i(this,C).length;v++){let p=i(this,C)[v];this.releaseVisibleResource(p),p.mode===1?i(this,y).releaseScroll(p.track):p.mode===5?i(this,y).releaseTop(p.track):p.mode===6&&i(this,y).releaseBottom(p.track);}m(this,C,[]),this.clearRenderer(),i(this,W)?.reset();}m(this,G,e);let a=i(this,L)?Math.min((t-i(this,L))/1e3,.05):0;m(this,L,t);let h=o/8*i(this,c).speed,d=Math.max(2,Math.ceil(i(this,c).fontSize*.2)),D=i(this,c).fontSize+i(this,c).padding*2+d,I=e*1e3,f=i(this,A).emitBatch(I);for(let v=0;v<f.length;v++)w(this,E,pt).call(this,f[v],e,h,D,o,s);let R=performance.now()/1e3,T=v=>{this.releaseVisibleResource(v),v.mode===1?i(this,y).releaseScroll(v.track):v.mode===5?i(this,y).releaseTop(v.track):v.mode===6&&i(this,y).releaseBottom(v.track);};i(this,C).length=i(this,A).compact(i(this,C),R,a,h,T),this.drawFrame(o,s),this.onAfterTick(),i(this,W)?.probe(e,i(this,A));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");m(this,c,{...kt,...t}),m(this,P,t.adapter),t.dataSource&&m(this,W,new st(t.dataSource,i(this,c).preBuffer,i(this,c).leadTime,i(this,c).seekThreshold,t.onError)),m(this,_,new et(i(this,c).fps,i(this,nt)));}onAfterLoad(){}onAfterTick(){}acquireVisibleDanmaku(){return {}}get cfg(){return i(this,c)}get visible(){return i(this,C)}getPreCacheInfo(){return i(this,A).preCacheInfo()}initTracks(){w(this,E,q).call(this);}get isDestroyed(){return i(this,b)}load(t){i(this,b)||(this.releaseAllVisibleResources(),m(this,C,[]),i(this,W)?.reset(),i(this,A).load(t),this.onAfterLoad());}send(t){if(i(this,b)||!i(this,c).enabled)return;let e=i(this,P).position,r=this.rendererWidth,o=this.rendererHeight;if(r===0||o===0)return;let s=r/8*i(this,c).speed,n=Math.max(2,Math.ceil(i(this,c).fontSize*.2)),a=i(this,c).fontSize+i(this,c).padding*2+n,h={...t,time:e};w(this,E,pt).call(this,h,e,s,a,r,o,true);}clear(){i(this,b)||(this.releaseAllVisibleResources(),m(this,C,[]),i(this,A).clear(),this.clearRenderer());}resize(){i(this,b)||this.updateDimensions()&&w(this,E,q).call(this);}destroy(){i(this,b)||(m(this,b,true),i(this,_).stop(),i(this,W)?.destroy(),this.releaseAllVisibleResources(),m(this,C,[]),this.destroyRenderer());}setEnabled(t){i(this,b)||(i(this,c).enabled=t);}setFps(t){i(this,b)||(i(this,c).fps=U(t,1,120),i(this,_).setFps(i(this,c).fps));}setArea(t){i(this,b)||(i(this,c).area=U(t,0,1),w(this,E,q).call(this));}setOpacity(t){i(this,b)||(i(this,c).opacity=U(t,0,1));}setSpeed(t){i(this,b)||(i(this,c).speed=Math.max(.1,t));}setFontFamily(t){i(this,b)||(i(this,c).fontFamily=t);}setFontSize(t){i(this,b)||(i(this,c).fontSize=U(t,8,128),w(this,E,q).call(this));}setFontWeight(t){i(this,b)||(i(this,c).fontWeight=t);}setStrokeWidth(t){i(this,b)||(i(this,c).strokeWidth=Math.max(0,t));}setStrokeColor(t){i(this,b)||(i(this,c).strokeColor=t&16777215);}setPadding(t){i(this,b)||(i(this,c).padding=Math.max(0,t),w(this,E,q).call(this));}setScrollGap(t){i(this,b)||(i(this,c).scrollGap=Math.max(0,t));}setDuration(t){if(!i(this,b)){i(this,c).duration=Math.max(.5,t);for(let e=0;e<i(this,C).length;e++){let r=i(this,C)[e];r.mode!==1&&(r.duration=i(this,c).duration);}}}setOverflow(t){i(this,b)||(i(this,c).overflow=t);}setMaxVisible(t){i(this,b)||(i(this,c).maxVisible=Math.max(0,t));}setMaxCache(t){}setPreCacheCount(t){}setSmoothing(t){}setWillChange(t){}setUseTextShadow(t){}};b=new WeakMap,c=new WeakMap,y=new WeakMap,A=new WeakMap,_=new WeakMap,C=new WeakMap,L=new WeakMap,G=new WeakMap,P=new WeakMap,W=new WeakMap,nt=new WeakMap,E=new WeakSet,pt=function(t,e,r,o,s,n,a){let h=t.mode??1,d=t.text??"";if(!d)return;let D=t.color??16777215,I=t.font_size??i(this,c).fontSize,f=i(this,c),T=this.measureTextWidth(d,f.fontFamily,I,f.fontWeight)+f.padding*2,v=I;if(!a&&f.maxVisible>0&&i(this,C).length>=f.maxVisible&&f.overflow==="drop")return;let p=null;if(h===1){if(p=i(this,y).acquireScroll(e,T,r,s,f.scrollGap),!p){if(f.overflow==="drop"&&!a)return;let F=Math.random()*i(this,y).scrollTrackCount|0;p={track:F,y:(F+.5)*o};}}else if(h===5){if(p=i(this,y).acquireTop(e,f.duration),!p){if(f.overflow==="drop"&&!a)return;let F=Math.random()*i(this,y).topTrackCount|0;p={track:F,y:(F+.5)*o};}}else if(h===6){if(p=i(this,y).acquireBottom(e,f.duration),!p){if(f.overflow==="drop"&&!a)return;let F=Math.random()*i(this,y).bottomTrackCount|0;p={track:F,y:n*f.area-(F+.5)*o};}}else if(p=i(this,y).acquireScroll(e,T,r,s,f.scrollGap),!p)if(a){let F=Math.random()*i(this,y).scrollTrackCount|0;p={track:F,y:(F+.5)*o};}else return;let k=this.acquireVisibleDanmaku();k.id=t.id,k.text=d,k.mode=h,k.color=D,k.fontSize=I,k.x=h===1?s:s/2,k.y=p.y,k.track=p.track,k.w=T,k.h=v,k.born=performance.now()/1e3,k.duration=f.duration,this.renderDanmaku(k),i(this,C).push(k);},q=function(){let t=this.rendererHeight;if(t===0)return;let e=i(this,c),r=Math.max(2,Math.ceil(e.fontSize*.2)),o=e.fontSize+e.padding*2+r;i(this,y).resize(t,e.area,o);};var at=class{constructor(t){this.W=0;this.H=0;this.dpr=1;this.container=t;let e=document.createElement("canvas");e.style.position="absolute",e.style.inset="0",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="none",t.appendChild(e),this.canvas=e,this.ctx=e.getContext("2d"),this.updateDimensions();}updateDimensions(){let t=window.devicePixelRatio||1,e=this.container.clientWidth,r=this.container.clientHeight;return e===0||r===0?false:(this.dpr=t,this.W=e,this.H=r,this.canvas.width=e*t,this.canvas.height=r*t,this.canvas.style.width=e+"px",this.canvas.style.height=r+"px",this.ctx.setTransform(t,0,0,t,0,0),true)}get width(){return this.W}get height(){return this.H}get devicePixelRatio(){return this.dpr}clear(){this.ctx.clearRect(0,0,this.W,this.H);}setSmoothing(t){this.ctx.imageSmoothingEnabled=t;}setGlobalAlpha(t){this.ctx.globalAlpha=t;}destroy(){this.canvas.remove();}};var ht=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():{}}release(t){this.pool.length<512&&(t.bmp=void 0,t.el=void 0,this.pool.push(t));}releaseAll(t){for(let e=0;e<t.length;e++)this.release(t[e]);}get size(){return this.pool.length}};function ft(l){return l<0||l>16777215||!Number.isFinite(l)?"#000000":"#"+l.toString(16).padStart(6,"0")}function bt({fontFamily:l,fontSize:t,fontWeight:e}){return `${e} ${t}px ${l}`}var lt=class{constructor(t=500){this.textWidths=new Map;this.bitmaps=new Map;this.aliveBitmaps=new Set;this.accessCounter=0;this.dpr=1;this.cachedFont="";this.fontFamily="";this.fontSize=0;this.fontWeight="";this.maxCache=t;}measure(t,e,r,o,s){let n=`${t}|${e}|${r}|${o}`,a=this.textWidths.get(n);if(a!==void 0)return a;s.font=bt({fontFamily:e,fontSize:r,fontWeight:o});let h=s.measureText(t).width;return this.textWidths.set(n,h),h}invalidateTextCache(){this.textWidths.clear();}getBitmap(t,e,r,o,s,n,a,h,d){let D=`${t}|${e}|${r}|${o}|${s}|${n}|${a}|${h}`,I=this.bitmaps.get(D);if(I)return I.accessId=++this.accessCounter,I.bitmap;(n!==this.fontFamily||e!==this.fontSize||a!==this.fontWeight)&&(this.fontFamily=n,this.fontSize=e,this.fontWeight=a,this.cachedFont=bt({fontFamily:n,fontSize:e,fontWeight:a}));let f=this.textWidths.get(`${t}|${n}|${e}|${a}`);if(f===void 0)throw new Error(`Text width not cached for "${t}". Call measure() first.`);let R=Math.ceil(f)+d*2,T=e+d*2,v=R*h|0,p=T*h|0,k=d*h,F=p/2,xt=new OffscreenCanvas(v,p),M=xt.getContext("2d");M.font=`${a} ${e*h}px ${n}`,M.lineWidth=o*h,M.lineJoin="round",M.textBaseline="middle",M.textAlign="left",M.strokeStyle=ft(s),M.strokeText(t,k,F),M.fillStyle=ft(r),M.fillText(t,k,F);let mt=xt.transferToImageBitmap();return this.bitmaps.set(D,{bitmap:mt,accessId:++this.accessCounter}),this.aliveBitmaps.add(mt),this.bitmaps.size>this.maxCache&&this.evictOne(),mt}evictOne(){let t="",e=1/0;for(let[r,o]of this.bitmaps)o.accessId<e&&(e=o.accessId,t=r);if(t){let r=this.bitmaps.get(t);r&&(this.aliveBitmaps.delete(r.bitmap),r.bitmap.close(),this.bitmaps.delete(t));}}isAlive(t){return this.aliveBitmaps.has(t)}setMaxCache(t){for(this.maxCache=t;this.bitmaps.size>this.maxCache;)this.evictOne();}setDpr(t){this.dpr!==t&&(this.dpr=t,this.clearBitmaps());}clearBitmaps(){for(let[,t]of this.bitmaps)this.aliveBitmaps.delete(t.bitmap),t.bitmap.close();this.bitmaps.clear();}clearAll(){this.clearBitmaps(),this.textWidths.clear();}get bitmapCount(){return this.bitmaps.size}};var vt=new Map;typeof window<"u"&&!window.requestIdleCallback&&(window.requestIdleCallback=function(l,t){let e=t?.timeout,r=Date.now(),o=0,s={didTimeout:false,timeRemaining:()=>Math.max(0,50-(Date.now()-r))};e!=null&&(o=setTimeout(()=>{s.didTimeout=true,r=Date.now(),l(s);},e));let n=requestAnimationFrame(()=>{e!=null&&clearTimeout(o),!s.didTimeout&&(r=Date.now(),l(s));}),a=Date.now()+Math.random();return vt.set(a,{rafId:n,timeoutId:o}),a},window.cancelIdleCallback=function(l){let t=vt.get(l);t&&(cancelAnimationFrame(t.rafId),t.timeoutId&&clearTimeout(t.timeoutId),vt.delete(l));});function Ft(l,t,e,r){let o=0,s=t;function n(a){let h=Math.min(t+e,l.length),d=0;for(;s<h&&(a.timeRemaining()>1||d<5);){let D=l[s];D&&r(D),s++,d++;}s<h&&(o=requestIdleCallback(n,{timeout:2e3}));}return o=requestIdleCallback(n,{timeout:2e3}),()=>cancelIdleCallback(o)}var g,Y,x,z,N,gt,ct=class extends ot{constructor(e){super(e);u(this,N);u(this,g);u(this,Y,new ht);u(this,x);u(this,z,null);m(this,g,new at(e.container)),i(this,g).setSmoothing(this.cfg.smoothing),m(this,x,new lt(this.cfg.maxCache)),this.initTracks();}get rendererWidth(){return i(this,g).width}get rendererHeight(){return i(this,g).height}clearRenderer(){i(this,g).clear();}destroyRenderer(){i(this,g).destroy();}updateDimensions(){let e=i(this,g).updateDimensions();return e&&(i(this,x).setDpr(i(this,g).devicePixelRatio),i(this,x).invalidateTextCache()),e}measureTextWidth(e,r,o,s){return i(this,x).measure(e,r,o,s,i(this,g).ctx)}renderDanmaku(e){let r=this.cfg;e.bmp=i(this,x).getBitmap(e.text,e.fontSize,e.color,r.strokeWidth,r.strokeColor,r.fontFamily,r.fontWeight,i(this,g).devicePixelRatio,r.padding);}releaseVisibleResource(e){i(this,Y).release(e);}releaseAllVisibleResources(){i(this,Y).releaseAll(this.visible),i(this,x).clearAll(),i(this,g).clear();}refreshVisibleDanmaku(){let e=i(this,g).ctx,r=this.cfg,o=i(this,g).devicePixelRatio,s=this.visible;for(let n=0;n<s.length;n++){let a=s[n],h=a.fontSize,d=i(this,x).measure(a.text,r.fontFamily,h,r.fontWeight,e);a.w=d+r.padding*2,a.h=h,a.bmp=i(this,x).getBitmap(a.text,h,a.color,r.strokeWidth,r.strokeColor,r.fontFamily,r.fontWeight,o,r.padding);}}drawFrame(e,r){i(this,g).clear(),i(this,g).setGlobalAlpha(this.cfg.opacity);let o=i(this,g).devicePixelRatio,s=this.cfg.padding,n=this.visible;for(let a=0;a<n.length;a++){let h=n[a],d=h.bmp;if(!d)continue;if(!i(this,x).isAlive(d)){h.bmp=void 0;continue}let D=h.x|0,I=h.y|0,f=d.width,R=d.height,T=f/o,v=R/o,p=i(this,g).ctx;h.mode===1?p.drawImage(d,0,0,f,R,D-s,I-v/2|0,T,v):p.drawImage(d,0,0,f,R,D-T/2|0,I-v/2|0,T,v);}}acquireVisibleDanmaku(){return i(this,Y).acquire()}onAfterLoad(){var e;(e=i(this,z))==null||e.call(this),m(this,z,null),w(this,N,gt).call(this);}onAfterTick(){w(this,N,gt).call(this);}setEnabled(e){super.setEnabled(e),e||i(this,g).clear();}setFontFamily(e){super.setFontFamily(e),i(this,x).invalidateTextCache(),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setFontSize(e){super.setFontSize(e),i(this,x).invalidateTextCache(),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setFontWeight(e){super.setFontWeight(e),i(this,x).invalidateTextCache(),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setStrokeWidth(e){super.setStrokeWidth(e),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setStrokeColor(e){super.setStrokeColor(e),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setPadding(e){super.setPadding(e),i(this,x).clearBitmaps(),this.refreshVisibleDanmaku();}setScrollGap(e){super.setScrollGap(e),this.refreshVisibleDanmaku();}setMaxCache(e){this.isDestroyed||(this.cfg.maxCache=Math.max(10,e),i(this,x).setMaxCache(this.cfg.maxCache));}setPreCacheCount(e){this.isDestroyed||(this.cfg.preCacheCount=Math.max(0,e));}setSmoothing(e){this.isDestroyed||(this.cfg.smoothing=e,i(this,g).setSmoothing(e));}};g=new WeakMap,Y=new WeakMap,x=new WeakMap,z=new WeakMap,N=new WeakSet,gt=function(){if(i(this,z)||this.isDestroyed)return;let{pool:e,cursor:r}=this.getPreCacheInfo(),o=this.cfg;m(this,z,Ft(e,r,o.preCacheCount,s=>{let n=s.text??"",a=s.font_size??o.fontSize,h=s.color??16777215;i(this,x).measure(n,o.fontFamily,a,o.fontWeight,i(this,g).ctx);try{i(this,x).getBitmap(n,a,h,o.strokeWidth,o.strokeColor,o.fontFamily,o.fontWeight,i(this,g).devicePixelRatio,o.padding);}catch{}}));};function me(l,t){if(l!=="canvas")throw new TypeError("other engines are not available in canvas-only package");if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(t.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');return new ct(t)}export{Q as DanmakuMode,me as createEngine};//# sourceMappingURL=canvas.min.js.map
//# sourceMappingURL=canvas.min.js.map

@@ -1,3 +0,3 @@

import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-DQHkoud-.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-DQHkoud-.js';
import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-D9OmRc0L.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-D9OmRc0L.js';

@@ -4,0 +4,0 @@ declare function createEngine(type: EngineType, options: DanmakuOptions): DanmakuEngine;

+422
-263

@@ -26,125 +26,2 @@ var __typeError = (msg) => {

// src/engine/dom/renderer.ts
function buildTextShadow(width, strokeColor) {
const s = width;
return [
`-${s}px -${s}px 0 ${strokeColor}`,
`0px -${s}px 0 ${strokeColor}`,
`${s}px -${s}px 0 ${strokeColor}`,
`-${s}px 0px 0 ${strokeColor}`,
`${s}px 0px 0 ${strokeColor}`,
`-${s}px ${s}px 0 ${strokeColor}`,
`0px ${s}px 0 ${strokeColor}`,
`${s}px ${s}px 0 ${strokeColor}`
].join(",");
}
function buildDomFont(fontFamily, fontSize, fontWeight) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
var DOMRenderer = class {
constructor(container) {
this.container = container;
const root = document.createElement("div");
root.style.position = "absolute";
root.style.inset = "0";
root.style.overflow = "hidden";
root.style.pointerEvents = "none";
root.style.userSelect = "none";
container.appendChild(root);
this.root = root;
}
get width() {
return this.container.clientWidth;
}
get height() {
return this.container.clientHeight;
}
/**
* Create a new danmaku DOM element pre-styled for reuse.
*/
createElement(style) {
const el = document.createElement("div");
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.font = style.font;
el.style.color = style.fillColor;
el.style.textShadow = style.textShadow;
el.style.willChange = style.willChange;
el.style.pointerEvents = "none";
el.style.userSelect = "none";
return el;
}
/**
* Update a reused element's styling to match a new danmaku.
*/
configureElement(el, text, style) {
el.textContent = text;
el.style.font = style.font;
el.style.color = style.fillColor;
el.style.textShadow = style.textShadow;
el.style.willChange = style.willChange;
}
/**
* Position the element using GPU-accelerated transform.
* Mode 1 (scroll): x is the left edge.
* Mode 5/6 (fixed): x is the horizontal center; we center via translate + left: 50%.
*/
positionElement(el, x, y, mode, height) {
const rx = Math.round(x);
const ry = Math.round(y - height / 2);
if (mode === 1) {
el.style.transform = `translate3d(${rx}px, ${ry}px, 0)`;
} else {
el.style.transform = `translate3d(${rx}px, ${ry}px, 0) translateX(-50%)`;
}
}
hideElement(el) {
el.style.display = "none";
}
showElement(el) {
el.style.display = "";
}
appendElement(el) {
this.root.appendChild(el);
}
removeElement(el) {
if (el.parentNode === this.root) {
this.root.removeChild(el);
}
}
destroy() {
this.root.remove();
}
};
// src/engine/dom/pool.ts
var MAX_POOL_SIZE = 512;
var DOMPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : document.createElement("div");
}
release(el) {
if (this.pool.length < MAX_POOL_SIZE) {
el.style.display = "none";
if (el.parentNode) el.parentNode.removeChild(el);
el.style.transform = "";
el.textContent = "";
this.pool.push(el);
}
}
releaseAll(elements) {
for (let i = 0; i < elements.length; i++) {
this.release(elements[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/core/track-manager.ts

@@ -189,3 +66,3 @@ var TrackManager = class {

// ---- Scroll track allocation (mode 1) ----
acquireScroll(currentTime, danmakuWidth, speed, _containerWidth) {
acquireScroll(currentTime, danmakuWidth, speed, containerWidth, scrollGap) {
const deferred = [];

@@ -195,3 +72,3 @@ while (this.scrollFree.length > 0) {

if (this.scrollExit[t] <= currentTime) {
this.scrollExit[t] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[t] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
for (const d of deferred) this.scrollFree.push(d);

@@ -207,3 +84,3 @@ return { track: t, y: this.scrollY(t) };

if (this.scrollExit[i] <= currentTime) {
this.scrollExit[i] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[i] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
const idx = this.scrollFree.indexOf(i);

@@ -496,2 +373,3 @@ if (idx !== -1) this.scrollFree.splice(idx, 1);

strokeColor: 0,
scrollGap: 96,
speed: 1,

@@ -637,45 +515,18 @@ seekThreshold: 0.2,

// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/utils/text-measure.ts
var _ctx = null;
function getCtx() {
if (!_ctx) {
const c = document.createElement("canvas");
c.width = c.height = 1;
_ctx = c.getContext("2d");
}
return _ctx;
}
function measureTextWidth(text, fontFamily, fontSize, fontWeight) {
const ctx = getCtx();
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
return ctx.measureText(text).width;
}
// src/engine/dom/index.ts
var _destroyed, _config, _renderer, _tracks, _pool, _loop, _scheduler, _visible, _lastTs, _adapter2, _streamLoader, _lastPos, _tick, _DOMEngine_instances, emit_fn, resizeTracks_fn;
var DOMEngine = class {
// src/engine/base.ts
var _destroyed, _config, _tracks, _scheduler, _loop, _visible, _lastTs, _lastPos, _adapter2, _streamLoader, _tick, _DanmakuEngineBase_instances, emit_fn, resizeTracks_fn;
var DanmakuEngineBase = class {
// ==================================================================
// Constructor
// ==================================================================
constructor(options) {
__privateAdd(this, _DOMEngine_instances);
__privateAdd(this, _DanmakuEngineBase_instances);
__privateAdd(this, _destroyed, false);
__privateAdd(this, _config);
__privateAdd(this, _renderer);
__privateAdd(this, _tracks);
__privateAdd(this, _pool);
__privateAdd(this, _tracks, new TrackManager());
__privateAdd(this, _scheduler, new Scheduler());
__privateAdd(this, _loop);
__privateAdd(this, _scheduler);
__privateAdd(this, _visible, []);
__privateAdd(this, _lastTs, 0);
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _adapter2);

@@ -686,9 +537,9 @@ __privateAdd(this, _streamLoader, null);

// ==================================================================
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _tick, (ts) => {
const pos = __privateGet(this, _adapter2).position;
const paused = __privateGet(this, _adapter2).paused;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (!__privateGet(this, _config).enabled || W === 0) {
this.clearRenderer();
return;

@@ -701,6 +552,3 @@ }

const v = __privateGet(this, _visible)[i];
if (v.el) {
__privateGet(this, _renderer).removeElement(v.el);
__privateGet(this, _pool).release(v.el);
}
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);

@@ -711,2 +559,3 @@ else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);

__privateSet(this, _visible, []);
this.clearRenderer();
__privateGet(this, _streamLoader)?.reset();

@@ -723,28 +572,14 @@ }

for (let i = 0; i < batch.length; i++) {
__privateMethod(this, _DOMEngine_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
}
const now = performance.now() / 1e3;
const onRemove = (v) => {
if (v.el) {
__privateGet(this, _renderer).hideElement(v.el);
__privateGet(this, _renderer).removeElement(v.el);
__privateGet(this, _pool).release(v.el);
v.el = void 0;
}
if (v.mode === 1 /* Scroll */) {
__privateGet(this, _tracks).releaseScroll(v.track);
} else if (v.mode === 5 /* Top */) {
__privateGet(this, _tracks).releaseTop(v.track);
} else if (v.mode === 6 /* Bottom */) {
__privateGet(this, _tracks).releaseBottom(v.track);
}
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks).releaseBottom(v.track);
};
const newLen = __privateGet(this, _scheduler).compact(__privateGet(this, _visible), now, dt, scrollSpeed, onRemove);
__privateGet(this, _visible).length = newLen;
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const v = __privateGet(this, _visible)[i];
if (v.el) {
__privateGet(this, _renderer).positionElement(v.el, v.x, v.y, v.mode, v.h);
}
}
__privateGet(this, _visible).length = __privateGet(this, _scheduler).compact(__privateGet(this, _visible), now, dt, scrollSpeed, onRemove);
this.drawFrame(W, H);
this.onAfterTick();
__privateGet(this, _streamLoader)?.probe(pos, __privateGet(this, _scheduler));

@@ -760,6 +595,2 @@ });

__privateSet(this, _adapter2, options.adapter);
__privateSet(this, _renderer, new DOMRenderer(options.container));
__privateSet(this, _tracks, new TrackManager());
__privateSet(this, _pool, new DOMPool());
__privateSet(this, _scheduler, new Scheduler());
if (options.dataSource) {

@@ -774,6 +605,34 @@ __privateSet(this, _streamLoader, new StreamLoader(

}
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn).call(this);
__privateSet(this, _loop, new RafLoop(__privateGet(this, _config).fps, __privateGet(this, _tick)));
}
// ==================================================================
// Optional hooks
// ==================================================================
/** Called after load() completes. Canvas uses for pre-cache scheduling. */
onAfterLoad() {
}
/** Called after each tick(). Canvas uses for pre-cache scheduling. */
onAfterTick() {
}
/** Create a VisibleDanmaku object. Canvas overrides for object pooling. */
acquireVisibleDanmaku() {
return {};
}
// ==================================================================
// Protected accessors for subclasses
// ==================================================================
get cfg() {
return __privateGet(this, _config);
}
get visible() {
return __privateGet(this, _visible);
}
getPreCacheInfo() {
return __privateGet(this, _scheduler).preCacheInfo();
}
/** Must be called by subclass constructors after renderer is initialized. */
initTracks() {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
// ==================================================================
// Lifecycle

@@ -786,6 +645,7 @@ // ==================================================================

if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible).map((v) => v.el).filter(Boolean));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _streamLoader)?.reset();
__privateGet(this, _scheduler).load(items);
this.onAfterLoad();
}

@@ -795,4 +655,4 @@ send(item) {

const pos = __privateGet(this, _adapter2).position;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (W === 0 || H === 0) return;

@@ -803,14 +663,15 @@ const scrollSpeed = W / 8 * __privateGet(this, _config).speed;

const sent = { ...item, time: pos };
__privateMethod(this, _DOMEngine_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
}
clear() {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible).map((v) => v.el).filter(Boolean));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _scheduler).clear();
this.clearRenderer();
}
resize() {
if (__privateGet(this, _destroyed)) return;
if (__privateGet(this, _renderer).width > 0) {
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn).call(this);
if (this.updateDimensions()) {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -823,8 +684,8 @@ }

__privateGet(this, _streamLoader)?.destroy();
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible).map((v) => v.el).filter(Boolean));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _renderer).destroy();
this.destroyRenderer();
}
// ==================================================================
// Runtime setters
// Runtime setters — shared logic
// ==================================================================

@@ -834,3 +695,2 @@ setEnabled(v) {

__privateGet(this, _config).enabled = v;
__privateGet(this, _renderer).root.style.display = v ? "" : "none";
}

@@ -845,3 +705,3 @@ setFps(v) {

__privateGet(this, _config).area = clamp(v, 0, 1);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -851,3 +711,2 @@ setOpacity(v) {

__privateGet(this, _config).opacity = clamp(v, 0, 1);
__privateGet(this, _renderer).root.style.opacity = String(__privateGet(this, _config).opacity);
}

@@ -859,2 +718,3 @@ setSpeed(v) {

setFontFamily(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).fontFamily = v;

@@ -865,11 +725,14 @@ }

__privateGet(this, _config).fontSize = clamp(v, 8, 128);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
setFontWeight(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).fontWeight = v;
}
setStrokeWidth(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).strokeWidth = Math.max(0, v);
}
setStrokeColor(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).strokeColor = v & 16777215;

@@ -880,14 +743,27 @@ }

__privateGet(this, _config).padding = Math.max(0, v);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
setScrollGap(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).scrollGap = Math.max(0, v);
}
setDuration(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).duration = Math.max(0.5, v);
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const d = __privateGet(this, _visible)[i];
if (d.mode !== 1 /* Scroll */) {
d.duration = __privateGet(this, _config).duration;
}
}
}
setOverflow(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).overflow = v;
}
setMaxVisible(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).maxVisible = Math.max(0, v);
}
// No-ops for DOM (no bitmap cache)
// Engine-specific setters — default no-ops, overridden by subclasses
setMaxCache(_v) {

@@ -897,12 +773,7 @@ }

}
// Canvas-only — no-ops for DOM
setSmoothing(_v) {
}
setWillChange(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).willChange = v;
setWillChange(_v) {
}
setUseTextShadow(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).useTextShadow = v;
setUseTextShadow(_v) {
}

@@ -912,16 +783,14 @@ };

_config = new WeakMap();
_renderer = new WeakMap();
_tracks = new WeakMap();
_pool = new WeakMap();
_scheduler = new WeakMap();
_loop = new WeakMap();
_scheduler = new WeakMap();
_visible = new WeakMap();
_lastTs = new WeakMap();
_lastPos = new WeakMap();
_adapter2 = new WeakMap();
_streamLoader = new WeakMap();
_lastPos = new WeakMap();
_tick = new WeakMap();
_DOMEngine_instances = new WeakSet();
_DanmakuEngineBase_instances = new WeakSet();
// ==================================================================
// Internal: emit
// Internal: emit a single danmaku item
// ==================================================================

@@ -935,3 +804,3 @@ emit_fn = function(item, currentTime, scrollSpeed, th, W, H, force) {

const cfg = __privateGet(this, _config);
const tw = measureTextWidth(text, cfg.fontFamily, fs, cfg.fontWeight);
const tw = this.measureTextWidth(text, cfg.fontFamily, fs, cfg.fontWeight);
const w = tw + cfg.padding * 2;

@@ -944,3 +813,3 @@ const h = fs;

if (mode === 1 /* Scroll */) {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -966,3 +835,3 @@ if (cfg.overflow === "drop" && !force) return;

} else {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -977,35 +846,16 @@ if (force) {

}
const font = buildDomFont(cfg.fontFamily, fs, cfg.fontWeight);
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const el = __privateGet(this, _pool).acquire();
el.textContent = text;
el.style.font = font;
el.style.color = toCss(color);
el.style.textShadow = textShadow;
el.style.willChange = willChange;
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.pointerEvents = "none";
el.style.userSelect = "none";
el.style.display = "";
el.style.opacity = String(cfg.opacity);
__privateGet(this, _renderer).appendElement(el);
const v = {
id: item.id,
text,
mode,
color,
fontSize: fs,
x: mode === 1 /* Scroll */ ? W : W / 2,
y: trackResult.y,
track: trackResult.track,
w,
h,
born: performance.now() / 1e3,
duration: cfg.duration,
el
};
const v = this.acquireVisibleDanmaku();
v.id = item.id;
v.text = text;
v.mode = mode;
v.color = color;
v.fontSize = fs;
v.x = mode === 1 /* Scroll */ ? W : W / 2;
v.y = trackResult.y;
v.track = trackResult.track;
v.w = w;
v.h = h;
v.born = performance.now() / 1e3;
v.duration = cfg.duration;
this.renderDanmaku(v);
__privateGet(this, _visible).push(v);

@@ -1017,3 +867,3 @@ };

resizeTracks_fn = function() {
const H = __privateGet(this, _renderer).height;
const H = this.rendererHeight;
if (H === 0) return;

@@ -1026,2 +876,311 @@ const cfg = __privateGet(this, _config);

// src/engine/dom/renderer.ts
function buildTextShadow(width, strokeColor) {
const s = width;
return [
`-${s}px -${s}px 0 ${strokeColor}`,
`0px -${s}px 0 ${strokeColor}`,
`${s}px -${s}px 0 ${strokeColor}`,
`-${s}px 0px 0 ${strokeColor}`,
`${s}px 0px 0 ${strokeColor}`,
`-${s}px ${s}px 0 ${strokeColor}`,
`0px ${s}px 0 ${strokeColor}`,
`${s}px ${s}px 0 ${strokeColor}`
].join(",");
}
function buildDomFont(fontFamily, fontSize, fontWeight) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
var DOMRenderer = class {
constructor(container) {
this.container = container;
const root = document.createElement("div");
root.style.position = "absolute";
root.style.inset = "0";
root.style.overflow = "hidden";
root.style.pointerEvents = "none";
root.style.userSelect = "none";
container.appendChild(root);
this.root = root;
}
get width() {
return this.container.clientWidth;
}
get height() {
return this.container.clientHeight;
}
/**
* Create a new danmaku DOM element pre-styled for reuse.
*/
createElement(style) {
const el = document.createElement("div");
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.font = style.font;
el.style.color = style.fillColor;
el.style.textShadow = style.textShadow;
el.style.willChange = style.willChange;
el.style.pointerEvents = "none";
el.style.userSelect = "none";
return el;
}
/**
* Update a reused element's styling to match a new danmaku.
*/
configureElement(el, text, style) {
el.textContent = text;
el.style.font = style.font;
el.style.color = style.fillColor;
el.style.textShadow = style.textShadow;
el.style.willChange = style.willChange;
}
/**
* Position the element using GPU-accelerated transform.
* Mode 1 (scroll): x is the left edge.
* Mode 5/6 (fixed): x is the horizontal center; we center via translate + left: 50%.
*/
positionElement(el, x, y, mode, height) {
const rx = Math.round(x);
const ry = Math.round(y - height / 2);
if (mode === 1) {
el.style.transform = `translate3d(${rx}px, ${ry}px, 0)`;
} else {
el.style.transform = `translate3d(${rx}px, ${ry}px, 0) translateX(-50%)`;
}
}
hideElement(el) {
el.style.display = "none";
}
showElement(el) {
el.style.display = "";
}
appendElement(el) {
this.root.appendChild(el);
}
removeElement(el) {
if (el.parentNode === this.root) {
this.root.removeChild(el);
}
}
destroy() {
this.root.remove();
}
};
// src/engine/dom/pool.ts
var MAX_POOL_SIZE = 512;
var DOMPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : document.createElement("div");
}
release(el) {
if (this.pool.length < MAX_POOL_SIZE) {
el.style.display = "none";
if (el.parentNode) el.parentNode.removeChild(el);
el.style.transform = "";
el.textContent = "";
this.pool.push(el);
}
}
releaseAll(elements) {
for (let i = 0; i < elements.length; i++) {
this.release(elements[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/utils/text-measure.ts
var _ctx = null;
function getCtx() {
if (!_ctx) {
const c = document.createElement("canvas");
c.width = c.height = 1;
_ctx = c.getContext("2d");
}
return _ctx;
}
function measureTextWidth(text, fontFamily, fontSize, fontWeight) {
const ctx = getCtx();
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
return ctx.measureText(text).width;
}
// src/engine/dom/index.ts
var _renderer, _pool;
var DOMEngine = class extends DanmakuEngineBase {
constructor(options) {
super(options);
__privateAdd(this, _renderer);
__privateAdd(this, _pool, new DOMPool());
__privateSet(this, _renderer, new DOMRenderer(options.container));
this.initTracks();
}
// ==================================================================
// Abstract hook implementations
// ==================================================================
get rendererWidth() {
return __privateGet(this, _renderer).width;
}
get rendererHeight() {
return __privateGet(this, _renderer).height;
}
clearRenderer() {
}
destroyRenderer() {
__privateGet(this, _renderer).destroy();
}
updateDimensions() {
return __privateGet(this, _renderer).width > 0;
}
measureTextWidth(text, family, size, weight) {
return measureTextWidth(text, family, size, weight);
}
renderDanmaku(v) {
const cfg = this.cfg;
const font = buildDomFont(cfg.fontFamily, v.fontSize, cfg.fontWeight);
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const el = __privateGet(this, _pool).acquire();
el.textContent = v.text;
el.style.font = font;
el.style.color = toCss(v.color);
el.style.textShadow = textShadow;
el.style.willChange = willChange;
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.pointerEvents = "none";
el.style.userSelect = "none";
el.style.display = "";
el.style.opacity = String(cfg.opacity);
__privateGet(this, _renderer).appendElement(el);
v.el = el;
}
releaseVisibleResource(v) {
if (v.el) {
__privateGet(this, _renderer).hideElement(v.el);
__privateGet(this, _renderer).removeElement(v.el);
__privateGet(this, _pool).release(v.el);
v.el = void 0;
}
}
releaseAllVisibleResources() {
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (v.el) {
__privateGet(this, _renderer).hideElement(v.el);
__privateGet(this, _renderer).removeElement(v.el);
__privateGet(this, _pool).release(v.el);
v.el = void 0;
}
}
}
refreshVisibleDanmaku() {
const cfg = this.cfg;
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (!v.el) continue;
const fs = v.fontSize;
v.el.style.font = buildDomFont(cfg.fontFamily, fs, cfg.fontWeight);
v.el.style.color = toCss(v.color);
v.el.style.textShadow = textShadow;
v.el.style.willChange = willChange;
v.el.style.opacity = String(cfg.opacity);
v.w = measureTextWidth(v.text, cfg.fontFamily, fs, cfg.fontWeight) + cfg.padding * 2;
v.fontSize = cfg.fontSize;
}
}
drawFrame(_W, _H) {
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (v.el) {
__privateGet(this, _renderer).positionElement(v.el, v.x, v.y, v.mode, v.h);
}
}
}
// ==================================================================
// Override setters with DOM-specific side effects
// ==================================================================
setEnabled(v) {
super.setEnabled(v);
__privateGet(this, _renderer).root.style.display = v ? "" : "none";
}
setOpacity(v) {
super.setOpacity(v);
__privateGet(this, _renderer).root.style.opacity = String(this.cfg.opacity);
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const d = visible[i];
if (d.el) d.el.style.opacity = String(this.cfg.opacity);
}
}
setFontFamily(v) {
super.setFontFamily(v);
this.refreshVisibleDanmaku();
}
setFontSize(v) {
super.setFontSize(v);
this.refreshVisibleDanmaku();
}
setFontWeight(v) {
super.setFontWeight(v);
this.refreshVisibleDanmaku();
}
setStrokeWidth(v) {
super.setStrokeWidth(v);
this.refreshVisibleDanmaku();
}
setStrokeColor(v) {
super.setStrokeColor(v);
this.refreshVisibleDanmaku();
}
setPadding(v) {
super.setPadding(v);
this.refreshVisibleDanmaku();
}
setScrollGap(v) {
super.setScrollGap(v);
this.refreshVisibleDanmaku();
}
setWillChange(v) {
if (this.isDestroyed) return;
this.cfg.willChange = v;
this.refreshVisibleDanmaku();
}
setUseTextShadow(v) {
if (this.isDestroyed) return;
this.cfg.useTextShadow = v;
this.refreshVisibleDanmaku();
}
};
_renderer = new WeakMap();
_pool = new WeakMap();
// src/dom.ts

@@ -1028,0 +1187,0 @@ function createEngine(type, options) {

@@ -1,2 +0,2 @@

var ut=s=>{throw TypeError(s)};var nt=(s,t,r)=>t.has(s)||ut("Cannot "+r);var e=(s,t,r)=>(nt(s,t,"read from private field"),r?r.call(s):t.get(s)),f=(s,t,r)=>t.has(s)?ut("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(s):t.set(s,r),p=(s,t,r,i)=>(nt(s,t,"write to private field"),t.set(s,r),r),E=(s,t,r)=>(nt(s,t,"access private method"),r);var st=(s,t,r,i)=>({set _(n){p(s,t,n);},get _(){return e(s,t,i)}});var X=(i=>(i[i.Scroll=1]="Scroll",i[i.Top=5]="Top",i[i.Bottom=6]="Bottom",i))(X||{});function pt(s,t){let r=s;return [`-${r}px -${r}px 0 ${t}`,`0px -${r}px 0 ${t}`,`${r}px -${r}px 0 ${t}`,`-${r}px 0px 0 ${t}`,`${r}px 0px 0 ${t}`,`-${r}px ${r}px 0 ${t}`,`0px ${r}px 0 ${t}`,`${r}px ${r}px 0 ${t}`].join(",")}function ft(s,t,r){return `${r} ${t}px ${s}`}var Z=class{constructor(t){this.container=t;let r=document.createElement("div");r.style.position="absolute",r.style.inset="0",r.style.overflow="hidden",r.style.pointerEvents="none",r.style.userSelect="none",t.appendChild(r),this.root=r;}get width(){return this.container.clientWidth}get height(){return this.container.clientHeight}createElement(t){let r=document.createElement("div");return r.style.position="absolute",r.style.left="0",r.style.top="0",r.style.whiteSpace="nowrap",r.style.font=t.font,r.style.color=t.fillColor,r.style.textShadow=t.textShadow,r.style.willChange=t.willChange,r.style.pointerEvents="none",r.style.userSelect="none",r}configureElement(t,r,i){t.textContent=r,t.style.font=i.font,t.style.color=i.fillColor,t.style.textShadow=i.textShadow,t.style.willChange=i.willChange;}positionElement(t,r,i,n,o){let a=Math.round(r),l=Math.round(i-o/2);n===1?t.style.transform=`translate3d(${a}px, ${l}px, 0)`:t.style.transform=`translate3d(${a}px, ${l}px, 0) translateX(-50%)`;}hideElement(t){t.style.display="none";}showElement(t){t.style.display="";}appendElement(t){this.root.appendChild(t);}removeElement(t){t.parentNode===this.root&&this.root.removeChild(t);}destroy(){this.root.remove();}};var G=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():document.createElement("div")}release(t){this.pool.length<512&&(t.style.display="none",t.parentNode&&t.parentNode.removeChild(t),t.style.transform="",t.textContent="",this.pool.push(t));}releaseAll(t){for(let r=0;r<t.length;r++)this.release(t[r]);}get size(){return this.pool.length}};var J=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(t,r,i){this.H=t,this.th=i,this.areaFraction=r;let n=t*r,o=Math.max(1,Math.floor(n/i)),a=Math.max(1,Math.floor(n*.48/i));this.scrollCount=o,this.topCount=a,this.bottomCount=a,this.scrollExit=new Float64Array(o).fill(-1/0),this.topExit=new Float64Array(a).fill(-1/0),this.bottomExit=new Float64Array(a).fill(-1/0),this.scrollFree=Array.from({length:o},(l,u)=>u),this.topFree=Array.from({length:a},(l,u)=>u),this.bottomFree=Array.from({length:a},(l,u)=>u);}acquireScroll(t,r,i,n){let o=[];for(;this.scrollFree.length>0;){let l=this.scrollFree.pop();if(this.scrollExit[l]<=t){this.scrollExit[l]=t+r*1.2/i;for(let u of o)this.scrollFree.push(u);return {track:l,y:this.scrollY(l)}}o.push(l);}for(let l of o)this.scrollFree.push(l);let a=Math.random()*this.scrollCount|0;for(let l=0;l<this.scrollCount;l++){let u=(a+l)%this.scrollCount;if(this.scrollExit[u]<=t){this.scrollExit[u]=t+r*1.2/i;let C=this.scrollFree.indexOf(u);return C!==-1&&this.scrollFree.splice(C,1),{track:u,y:this.scrollY(u)}}}return null}releaseScroll(t){this.scrollExit[t]=-1/0,this.scrollFree.includes(t)||this.scrollFree.push(t);}acquireTop(t,r){let i=[];for(;this.topFree.length>0;){let o=this.topFree.pop();if(this.topExit[o]<=t){this.topExit[o]=t+r;for(let a of i)this.topFree.push(a);return {track:o,y:this.fixedY(o,true)}}i.push(o);}for(let o of i)this.topFree.push(o);let n=Math.random()*this.topCount|0;for(let o=0;o<this.topCount;o++){let a=(n+o)%this.topCount;if(this.topExit[a]<=t){this.topExit[a]=t+r;let l=this.topFree.indexOf(a);return l!==-1&&this.topFree.splice(l,1),{track:a,y:this.fixedY(a,true)}}}return null}releaseTop(t){this.topExit[t]=-1/0,this.topFree.includes(t)||this.topFree.push(t);}acquireBottom(t,r){let i=[];for(;this.bottomFree.length>0;){let o=this.bottomFree.pop();if(this.bottomExit[o]<=t){this.bottomExit[o]=t+r;for(let a of i)this.bottomFree.push(a);return {track:o,y:this.fixedY(o,false)}}i.push(o);}for(let o of i)this.bottomFree.push(o);let n=Math.random()*this.bottomCount|0;for(let o=0;o<this.bottomCount;o++){let a=(n+o)%this.bottomCount;if(this.bottomExit[a]<=t){this.bottomExit[a]=t+r;let l=this.bottomFree.indexOf(a);return l!==-1&&this.bottomFree.splice(l,1),{track:a,y:this.fixedY(a,false)}}}return null}releaseBottom(t){this.bottomExit[t]=-1/0,this.bottomFree.includes(t)||this.bottomFree.push(t);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(t){return (t+.5)*this.th}fixedY(t,r){return r?(t+.5)*this.th:this.H*this.areaFraction-(t+.5)*this.th}};var W,K=class{constructor(t,r,i=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;f(this,W,t=>{this.stopped||(this.tick(t),this.rafId=requestAnimationFrame(e(this,W)));});this.frameInterval=1e3/t,this.callback=r,i&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(e(this,W)));}tick(t){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=t,this.callback(t),true;let r=t-this.lastFrameTime;return r>=this.frameInterval?(this.lastFrameTime=t-r%this.frameInterval,this.callback(t),true):false}setFps(t){this.frameInterval=1e3/t;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};W=new WeakMap;function q(s,t,r){return s<t?t:s>r?r:s}function Q(s,t,r,i=0,n=s.length){for(;i<n;){let o=i+n>>1;r(s[o])<=t?i=o+1:n=o;}return i}var tt=class{constructor(){this.pool=[];this.cursor=0;}load(t){this.pool=[...t].sort((r,i)=>r.time-i.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(t){if(this.pool.length===0)return [];let r=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(t<r-200&&(this.cursor=Q(this.pool,t,o=>(o.time??0)*1e3)),this.cursor>=this.pool.length)return [];let i=Q(this.pool,t,o=>(o.time??0)*1e3);if(i<=this.cursor)return [];let n=this.pool.slice(this.cursor,i);return this.cursor=i,n}compact(t,r,i,n,o){let a=0;for(let l=0;l<t.length;l++){let u=t[l];if(u.mode===1){if(u.x-=n*i,u.x+u.w<-10){o(u);continue}}else if(r-u.born>=u.duration){o(u);continue}a!==l&&(t[a]=t[l]),a++;}return a}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(t){if(t.length===0)return;let r=new Set;for(let l=0;l<this.pool.length;l++)r.add(this.pool[l].id);let i=[...t].filter(l=>!r.has(l.id)).sort((l,u)=>l.time-u.time);if(i.length===0)return;let n=[],o=0,a=0;for(;o<this.pool.length&&a<i.length;)this.pool[o].time<=i[a].time?(n.push(this.pool[o]),o++):(n.push(i[a]),a++);for(;o<this.pool.length;)n.push(this.pool[o++]);for(;a<i.length;)n.push(i[a++]);this.pool=n;}evictBefore(t){if(this.pool.length===0)return;let r=Q(this.pool,t*1e3-.1,i=>(i.time??0)*1e3);r!==0&&(this.pool.splice(0,r),this.cursor=Math.max(0,this.cursor-r));}};var dt={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var P,Y,O,j,N,S,A,T,$,M,ct,bt,yt,et=class{constructor(t,r,i,n,o){f(this,M);f(this,P);f(this,Y);f(this,O);f(this,j);f(this,N);f(this,S,[]);f(this,A,0);f(this,T,null);f(this,$,-1);p(this,P,t),p(this,Y,Math.max(1,r)),p(this,O,Math.max(0,i)),p(this,j,Math.max(.5,n*2.5)),p(this,N,o);}probe(t,r){if(e(this,$)>=0&&Math.abs(t-e(this,$))>e(this,j)&&this.reset(),p(this,$,t),e(this,O)>0){let o=t-e(this,O);r.evictBefore(o),p(this,S,e(this,S).filter(a=>a.end>o));}if(e(this,T))return;let i=t+e(this,Y),n=E(this,M,ct).call(this,t,i);n&&E(this,M,bt).call(this,n.start,n.end,r);}reset(){st(this,A)._++,p(this,T,null),p(this,S,[]),p(this,$,-1);}destroy(){this.reset();}};P=new WeakMap,Y=new WeakMap,O=new WeakMap,j=new WeakMap,N=new WeakMap,S=new WeakMap,A=new WeakMap,T=new WeakMap,$=new WeakMap,M=new WeakSet,ct=function(t,r){let i=t;for(let n of e(this,S))if(n.start<=i&&i<n.end){if(i=n.end,i>=r)return null}else if(n.start>i)return {start:i,end:Math.min(n.start,r)};return i<r?{start:i,end:r}:null},bt=function(t,r,i){let n=++st(this,A)._;p(this,T,e(this,P).fetch(t,r).then(o=>{n===e(this,A)&&(p(this,T,null),o.length>0&&i.add(o),E(this,M,yt).call(this,{start:t,end:r}));}).catch(o=>{var a;n===e(this,A)&&(p(this,T,null),(a=e(this,N))==null||a.call(this,o instanceof Error?o:new Error(String(o))));}));},yt=function(t){e(this,S).push(t),e(this,S).sort((i,n)=>i.start-n.start);let r=[];for(let i of e(this,S)){let n=r[r.length-1];n&&n.end>=i.start?n.end=Math.max(n.end,i.end):r.push({...i});}p(this,S,r);};function at(s){return s<0||s>16777215||!Number.isFinite(s)?"#000000":"#"+s.toString(16).padStart(6,"0")}function xt({fontFamily:s,fontSize:t,fontWeight:r}){return `${r} ${t}px ${s}`}var lt=null;function St(){if(!lt){let s=document.createElement("canvas");s.width=s.height=1,lt=s.getContext("2d");}return lt}function vt(s,t,r,i){let n=St();return n.font=xt({fontFamily:t,fontSize:r,fontWeight:i}),n.measureText(s).width}var c,h,x,b,F,B,D,v,R,L,I,_,it,k,ht,z,rt=class{constructor(t){f(this,k);f(this,c,false);f(this,h);f(this,x);f(this,b);f(this,F);f(this,B);f(this,D);f(this,v,[]);f(this,R,0);f(this,L);f(this,I,null);f(this,_,-1);f(this,it,t=>{let r=e(this,L).position,i=e(this,L).paused,n=e(this,x).width,o=e(this,x).height;if(!e(this,h).enabled||n===0||i)return;let a=Math.abs(r-e(this,_));if(e(this,_)>=0&&a>e(this,h).seekThreshold){for(let m=0;m<e(this,v).length;m++){let y=e(this,v)[m];y.el&&(e(this,x).removeElement(y.el),e(this,F).release(y.el)),y.mode===1?e(this,b).releaseScroll(y.track):y.mode===5?e(this,b).releaseTop(y.track):y.mode===6&&e(this,b).releaseBottom(y.track);}p(this,v,[]),e(this,I)?.reset();}p(this,_,r);let l=e(this,R)?Math.min((t-e(this,R))/1e3,.05):0;p(this,R,t);let u=n/8*e(this,h).speed,C=Math.max(2,Math.ceil(e(this,h).fontSize*.2)),U=e(this,h).fontSize+e(this,h).padding*2+C,H=r*1e3,d=e(this,D).emitBatch(H);for(let m=0;m<d.length;m++)E(this,k,ht).call(this,d[m],r,u,U,n,o);let mt=performance.now()/1e3,V=m=>{m.el&&(e(this,x).hideElement(m.el),e(this,x).removeElement(m.el),e(this,F).release(m.el),m.el=void 0),m.mode===1?e(this,b).releaseScroll(m.track):m.mode===5?e(this,b).releaseTop(m.track):m.mode===6&&e(this,b).releaseBottom(m.track);},ot=e(this,D).compact(e(this,v),mt,l,u,V);e(this,v).length=ot;for(let m=0;m<e(this,v).length;m++){let y=e(this,v)[m];y.el&&e(this,x).positionElement(y.el,y.x,y.y,y.mode,y.h);}e(this,I)?.probe(r,e(this,D));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");p(this,h,{...dt,...t}),p(this,L,t.adapter),p(this,x,new Z(t.container)),p(this,b,new J),p(this,F,new G),p(this,D,new tt),t.dataSource&&p(this,I,new et(t.dataSource,e(this,h).preBuffer,e(this,h).leadTime,e(this,h).seekThreshold,t.onError)),E(this,k,z).call(this),p(this,B,new K(e(this,h).fps,e(this,it)));}get isDestroyed(){return e(this,c)}load(t){e(this,c)||(e(this,F).releaseAll(e(this,v).map(r=>r.el).filter(Boolean)),p(this,v,[]),e(this,I)?.reset(),e(this,D).load(t));}send(t){if(e(this,c)||!e(this,h).enabled)return;let r=e(this,L).position,i=e(this,x).width,n=e(this,x).height;if(i===0||n===0)return;let o=i/8*e(this,h).speed,a=Math.max(2,Math.ceil(e(this,h).fontSize*.2)),l=e(this,h).fontSize+e(this,h).padding*2+a,u={...t,time:r};E(this,k,ht).call(this,u,r,o,l,i,n,true);}clear(){e(this,c)||(e(this,F).releaseAll(e(this,v).map(t=>t.el).filter(Boolean)),p(this,v,[]),e(this,D).clear());}resize(){e(this,c)||e(this,x).width>0&&E(this,k,z).call(this);}destroy(){e(this,c)||(p(this,c,true),e(this,B).stop(),e(this,I)?.destroy(),e(this,F).releaseAll(e(this,v).map(t=>t.el).filter(Boolean)),p(this,v,[]),e(this,x).destroy());}setEnabled(t){e(this,c)||(e(this,h).enabled=t,e(this,x).root.style.display=t?"":"none");}setFps(t){e(this,c)||(e(this,h).fps=q(t,1,120),e(this,B).setFps(e(this,h).fps));}setArea(t){e(this,c)||(e(this,h).area=q(t,0,1),E(this,k,z).call(this));}setOpacity(t){e(this,c)||(e(this,h).opacity=q(t,0,1),e(this,x).root.style.opacity=String(e(this,h).opacity));}setSpeed(t){e(this,c)||(e(this,h).speed=Math.max(.1,t));}setFontFamily(t){e(this,h).fontFamily=t;}setFontSize(t){e(this,c)||(e(this,h).fontSize=q(t,8,128),E(this,k,z).call(this));}setFontWeight(t){e(this,h).fontWeight=t;}setStrokeWidth(t){e(this,h).strokeWidth=Math.max(0,t);}setStrokeColor(t){e(this,h).strokeColor=t&16777215;}setPadding(t){e(this,c)||(e(this,h).padding=Math.max(0,t),E(this,k,z).call(this));}setDuration(t){e(this,h).duration=Math.max(.5,t);}setOverflow(t){e(this,h).overflow=t;}setMaxVisible(t){e(this,h).maxVisible=Math.max(0,t);}setMaxCache(t){}setPreCacheCount(t){}setSmoothing(t){}setWillChange(t){e(this,c)||(e(this,h).willChange=t);}setUseTextShadow(t){e(this,c)||(e(this,h).useTextShadow=t);}};c=new WeakMap,h=new WeakMap,x=new WeakMap,b=new WeakMap,F=new WeakMap,B=new WeakMap,D=new WeakMap,v=new WeakMap,R=new WeakMap,L=new WeakMap,I=new WeakMap,_=new WeakMap,it=new WeakMap,k=new WeakSet,ht=function(t,r,i,n,o,a,l){let u=t.mode??1,C=t.text??"";if(!C)return;let U=t.color??16777215,H=t.font_size??e(this,h).fontSize,d=e(this,h),V=vt(C,d.fontFamily,H,d.fontWeight)+d.padding*2,ot=H;if(!l&&d.maxVisible>0&&e(this,v).length>=d.maxVisible&&d.overflow==="drop")return;let m=null;if(u===1){if(m=e(this,b).acquireScroll(r,V,i,o),!m){if(d.overflow==="drop"&&!l)return;let w=Math.random()*e(this,b).scrollTrackCount|0;m={track:w,y:(w+.5)*n};}}else if(u===5){if(m=e(this,b).acquireTop(r,d.duration),!m){if(d.overflow==="drop"&&!l)return;let w=Math.random()*e(this,b).topTrackCount|0;m={track:w,y:(w+.5)*n};}}else if(u===6){if(m=e(this,b).acquireBottom(r,d.duration),!m){if(d.overflow==="drop"&&!l)return;let w=Math.random()*e(this,b).bottomTrackCount|0;m={track:w,y:a*d.area-(w+.5)*n};}}else if(m=e(this,b).acquireScroll(r,V,i,o),!m)if(l){let w=Math.random()*e(this,b).scrollTrackCount|0;m={track:w,y:(w+.5)*n};}else return;let y=ft(d.fontFamily,H,d.fontWeight),gt=d.useTextShadow?pt(d.strokeWidth*.7,at(d.strokeColor)):"none",Et=d.willChange?"transform":"auto",g=e(this,F).acquire();g.textContent=C,g.style.font=y,g.style.color=at(U),g.style.textShadow=gt,g.style.willChange=Et,g.style.position="absolute",g.style.left="0",g.style.top="0",g.style.whiteSpace="nowrap",g.style.pointerEvents="none",g.style.userSelect="none",g.style.display="",g.style.opacity=String(d.opacity),e(this,x).appendElement(g);let wt={id:t.id,text:C,mode:u,color:U,fontSize:H,x:u===1?o:o/2,y:m.y,track:m.track,w:V,h:ot,born:performance.now()/1e3,duration:d.duration,el:g};e(this,v).push(wt);},z=function(){let t=e(this,x).height;if(t===0)return;let r=e(this,h),i=Math.max(2,Math.ceil(r.fontSize*.2)),n=r.fontSize+r.padding*2+i;e(this,b).resize(t,r.area,n);};function ie(s,t){if(s!=="dom")throw new TypeError("other engines are not available in dom-only package");if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(t.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');return new rt(t)}export{X as DanmakuMode,ie as createEngine};//# sourceMappingURL=dom.min.js.map
var pt=l=>{throw TypeError(l)};var nt=(l,t,e)=>t.has(l)||pt("Cannot "+e);var r=(l,t,e)=>(nt(l,t,"read from private field"),e?e.call(l):t.get(l)),d=(l,t,e)=>t.has(l)?pt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(l):t.set(l,e),m=(l,t,e,i)=>(nt(l,t,"write to private field"),t.set(l,e),e),S=(l,t,e)=>(nt(l,t,"access private method"),e);var at=(l,t,e,i)=>({set _(o){m(l,t,o);},get _(){return r(l,t,i)}});var X=(i=>(i[i.Scroll=1]="Scroll",i[i.Top=5]="Top",i[i.Bottom=6]="Bottom",i))(X||{});var Z=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(t,e,i){this.H=t,this.th=i,this.areaFraction=e;let o=t*e,s=Math.max(1,Math.floor(o/i)),n=Math.max(1,Math.floor(o*.48/i));this.scrollCount=s,this.topCount=n,this.bottomCount=n,this.scrollExit=new Float64Array(s).fill(-1/0),this.topExit=new Float64Array(n).fill(-1/0),this.bottomExit=new Float64Array(n).fill(-1/0),this.scrollFree=Array.from({length:s},(a,h)=>h),this.topFree=Array.from({length:n},(a,h)=>h),this.bottomFree=Array.from({length:n},(a,h)=>h);}acquireScroll(t,e,i,o,s){let n=[];for(;this.scrollFree.length>0;){let h=this.scrollFree.pop();if(this.scrollExit[h]<=t){this.scrollExit[h]=t+(e+s*o/1920)/i;for(let k of n)this.scrollFree.push(k);return {track:h,y:this.scrollY(h)}}n.push(h);}for(let h of n)this.scrollFree.push(h);let a=Math.random()*this.scrollCount|0;for(let h=0;h<this.scrollCount;h++){let k=(a+h)%this.scrollCount;if(this.scrollExit[k]<=t){this.scrollExit[k]=t+(e+s*o/1920)/i;let R=this.scrollFree.indexOf(k);return R!==-1&&this.scrollFree.splice(R,1),{track:k,y:this.scrollY(k)}}}return null}releaseScroll(t){this.scrollExit[t]=-1/0,this.scrollFree.includes(t)||this.scrollFree.push(t);}acquireTop(t,e){let i=[];for(;this.topFree.length>0;){let s=this.topFree.pop();if(this.topExit[s]<=t){this.topExit[s]=t+e;for(let n of i)this.topFree.push(n);return {track:s,y:this.fixedY(s,true)}}i.push(s);}for(let s of i)this.topFree.push(s);let o=Math.random()*this.topCount|0;for(let s=0;s<this.topCount;s++){let n=(o+s)%this.topCount;if(this.topExit[n]<=t){this.topExit[n]=t+e;let a=this.topFree.indexOf(n);return a!==-1&&this.topFree.splice(a,1),{track:n,y:this.fixedY(n,true)}}}return null}releaseTop(t){this.topExit[t]=-1/0,this.topFree.includes(t)||this.topFree.push(t);}acquireBottom(t,e){let i=[];for(;this.bottomFree.length>0;){let s=this.bottomFree.pop();if(this.bottomExit[s]<=t){this.bottomExit[s]=t+e;for(let n of i)this.bottomFree.push(n);return {track:s,y:this.fixedY(s,false)}}i.push(s);}for(let s of i)this.bottomFree.push(s);let o=Math.random()*this.bottomCount|0;for(let s=0;s<this.bottomCount;s++){let n=(o+s)%this.bottomCount;if(this.bottomExit[n]<=t){this.bottomExit[n]=t+e;let a=this.bottomFree.indexOf(n);return a!==-1&&this.bottomFree.splice(a,1),{track:n,y:this.fixedY(n,false)}}}return null}releaseBottom(t){this.bottomExit[t]=-1/0,this.bottomFree.includes(t)||this.bottomFree.push(t);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(t){return (t+.5)*this.th}fixedY(t,e){return e?(t+.5)*this.th:this.H*this.areaFraction-(t+.5)*this.th}};var q,J=class{constructor(t,e,i=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;d(this,q,t=>{this.stopped||(this.tick(t),this.rafId=requestAnimationFrame(r(this,q)));});this.frameInterval=1e3/t,this.callback=e,i&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(r(this,q)));}tick(t){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=t,this.callback(t),true;let e=t-this.lastFrameTime;return e>=this.frameInterval?(this.lastFrameTime=t-e%this.frameInterval,this.callback(t),true):false}setFps(t){this.frameInterval=1e3/t;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};q=new WeakMap;function P(l,t,e){return l<t?t:l>e?e:l}function K(l,t,e,i=0,o=l.length){for(;i<o;){let s=i+o>>1;e(l[s])<=t?i=s+1:o=s;}return i}var Q=class{constructor(){this.pool=[];this.cursor=0;}load(t){this.pool=[...t].sort((e,i)=>e.time-i.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(t){if(this.pool.length===0)return [];let e=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(t<e-200&&(this.cursor=K(this.pool,t,s=>(s.time??0)*1e3)),this.cursor>=this.pool.length)return [];let i=K(this.pool,t,s=>(s.time??0)*1e3);if(i<=this.cursor)return [];let o=this.pool.slice(this.cursor,i);return this.cursor=i,o}compact(t,e,i,o,s){let n=0;for(let a=0;a<t.length;a++){let h=t[a];if(h.mode===1){if(h.x-=o*i,h.x+h.w<-10){s(h);continue}}else if(e-h.born>=h.duration){s(h);continue}n!==a&&(t[n]=t[a]),n++;}return n}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(t){if(t.length===0)return;let e=new Set;for(let a=0;a<this.pool.length;a++)e.add(this.pool[a].id);let i=[...t].filter(a=>!e.has(a.id)).sort((a,h)=>a.time-h.time);if(i.length===0)return;let o=[],s=0,n=0;for(;s<this.pool.length&&n<i.length;)this.pool[s].time<=i[n].time?(o.push(this.pool[s]),s++):(o.push(i[n]),n++);for(;s<this.pool.length;)o.push(this.pool[s++]);for(;n<i.length;)o.push(i[n++]);this.pool=o;}evictBefore(t){if(this.pool.length===0)return;let e=K(this.pool,t*1e3-.1,i=>(i.time??0)*1e3);e!==0&&(this.pool.splice(0,e),this.cursor=Math.max(0,this.cursor-e));}};var ft={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,scrollGap:96,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var Y,G,H,j,N,D,I,C,V,T,bt,gt,vt,tt=class{constructor(t,e,i,o,s){d(this,T);d(this,Y);d(this,G);d(this,H);d(this,j);d(this,N);d(this,D,[]);d(this,I,0);d(this,C,null);d(this,V,-1);m(this,Y,t),m(this,G,Math.max(1,e)),m(this,H,Math.max(0,i)),m(this,j,Math.max(.5,o*2.5)),m(this,N,s);}probe(t,e){if(r(this,V)>=0&&Math.abs(t-r(this,V))>r(this,j)&&this.reset(),m(this,V,t),r(this,H)>0){let s=t-r(this,H);e.evictBefore(s),m(this,D,r(this,D).filter(n=>n.end>s));}if(r(this,C))return;let i=t+r(this,G),o=S(this,T,bt).call(this,t,i);o&&S(this,T,gt).call(this,o.start,o.end,e);}reset(){at(this,I)._++,m(this,C,null),m(this,D,[]),m(this,V,-1);}destroy(){this.reset();}};Y=new WeakMap,G=new WeakMap,H=new WeakMap,j=new WeakMap,N=new WeakMap,D=new WeakMap,I=new WeakMap,C=new WeakMap,V=new WeakMap,T=new WeakSet,bt=function(t,e){let i=t;for(let o of r(this,D))if(o.start<=i&&i<o.end){if(i=o.end,i>=e)return null}else if(o.start>i)return {start:i,end:Math.min(o.start,e)};return i<e?{start:i,end:e}:null},gt=function(t,e,i){let o=++at(this,I)._;m(this,C,r(this,Y).fetch(t,e).then(s=>{o===r(this,I)&&(m(this,C,null),s.length>0&&i.add(s),S(this,T,vt).call(this,{start:t,end:e}));}).catch(s=>{var n;o===r(this,I)&&(m(this,C,null),(n=r(this,N))==null||n.call(this,s instanceof Error?s:new Error(String(s))));}));},vt=function(t){r(this,D).push(t),r(this,D).sort((i,o)=>i.start-o.start);let e=[];for(let i of r(this,D)){let o=e[e.length-1];o&&o.end>=i.start?o.end=Math.max(o.end,i.end):e.push({...i});}m(this,D,e);};var c,u,b,F,W,v,L,O,A,M,rt,E,lt,$,et=class{constructor(t){d(this,E);d(this,c,false);d(this,u);d(this,b,new Z);d(this,F,new Q);d(this,W);d(this,v,[]);d(this,L,0);d(this,O,-1);d(this,A);d(this,M,null);d(this,rt,t=>{let e=r(this,A).position,i=r(this,A).paused,o=this.rendererWidth,s=this.rendererHeight;if(!r(this,u).enabled||o===0){this.clearRenderer();return}if(i)return;let n=Math.abs(e-r(this,O));if(r(this,O)>=0&&n>r(this,u).seekThreshold){for(let g=0;g<r(this,v).length;g++){let p=r(this,v)[g];this.releaseVisibleResource(p),p.mode===1?r(this,b).releaseScroll(p.track):p.mode===5?r(this,b).releaseTop(p.track):p.mode===6&&r(this,b).releaseBottom(p.track);}m(this,v,[]),this.clearRenderer(),r(this,M)?.reset();}m(this,O,e);let a=r(this,L)?Math.min((t-r(this,L))/1e3,.05):0;m(this,L,t);let h=o/8*r(this,u).speed,k=Math.max(2,Math.ceil(r(this,u).fontSize*.2)),R=r(this,u).fontSize+r(this,u).padding*2+k,_=e*1e3,f=r(this,F).emitBatch(_);for(let g=0;g<f.length;g++)S(this,E,lt).call(this,f[g],e,h,R,o,s);let ct=performance.now()/1e3,B=g=>{this.releaseVisibleResource(g),g.mode===1?r(this,b).releaseScroll(g.track):g.mode===5?r(this,b).releaseTop(g.track):g.mode===6&&r(this,b).releaseBottom(g.track);};r(this,v).length=r(this,F).compact(r(this,v),ct,a,h,B),this.drawFrame(o,s),this.onAfterTick(),r(this,M)?.probe(e,r(this,F));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");m(this,u,{...ft,...t}),m(this,A,t.adapter),t.dataSource&&m(this,M,new tt(t.dataSource,r(this,u).preBuffer,r(this,u).leadTime,r(this,u).seekThreshold,t.onError)),m(this,W,new J(r(this,u).fps,r(this,rt)));}onAfterLoad(){}onAfterTick(){}acquireVisibleDanmaku(){return {}}get cfg(){return r(this,u)}get visible(){return r(this,v)}getPreCacheInfo(){return r(this,F).preCacheInfo()}initTracks(){S(this,E,$).call(this);}get isDestroyed(){return r(this,c)}load(t){r(this,c)||(this.releaseAllVisibleResources(),m(this,v,[]),r(this,M)?.reset(),r(this,F).load(t),this.onAfterLoad());}send(t){if(r(this,c)||!r(this,u).enabled)return;let e=r(this,A).position,i=this.rendererWidth,o=this.rendererHeight;if(i===0||o===0)return;let s=i/8*r(this,u).speed,n=Math.max(2,Math.ceil(r(this,u).fontSize*.2)),a=r(this,u).fontSize+r(this,u).padding*2+n,h={...t,time:e};S(this,E,lt).call(this,h,e,s,a,i,o,true);}clear(){r(this,c)||(this.releaseAllVisibleResources(),m(this,v,[]),r(this,F).clear(),this.clearRenderer());}resize(){r(this,c)||this.updateDimensions()&&S(this,E,$).call(this);}destroy(){r(this,c)||(m(this,c,true),r(this,W).stop(),r(this,M)?.destroy(),this.releaseAllVisibleResources(),m(this,v,[]),this.destroyRenderer());}setEnabled(t){r(this,c)||(r(this,u).enabled=t);}setFps(t){r(this,c)||(r(this,u).fps=P(t,1,120),r(this,W).setFps(r(this,u).fps));}setArea(t){r(this,c)||(r(this,u).area=P(t,0,1),S(this,E,$).call(this));}setOpacity(t){r(this,c)||(r(this,u).opacity=P(t,0,1));}setSpeed(t){r(this,c)||(r(this,u).speed=Math.max(.1,t));}setFontFamily(t){r(this,c)||(r(this,u).fontFamily=t);}setFontSize(t){r(this,c)||(r(this,u).fontSize=P(t,8,128),S(this,E,$).call(this));}setFontWeight(t){r(this,c)||(r(this,u).fontWeight=t);}setStrokeWidth(t){r(this,c)||(r(this,u).strokeWidth=Math.max(0,t));}setStrokeColor(t){r(this,c)||(r(this,u).strokeColor=t&16777215);}setPadding(t){r(this,c)||(r(this,u).padding=Math.max(0,t),S(this,E,$).call(this));}setScrollGap(t){r(this,c)||(r(this,u).scrollGap=Math.max(0,t));}setDuration(t){if(!r(this,c)){r(this,u).duration=Math.max(.5,t);for(let e=0;e<r(this,v).length;e++){let i=r(this,v)[e];i.mode!==1&&(i.duration=r(this,u).duration);}}}setOverflow(t){r(this,c)||(r(this,u).overflow=t);}setMaxVisible(t){r(this,c)||(r(this,u).maxVisible=Math.max(0,t));}setMaxCache(t){}setPreCacheCount(t){}setSmoothing(t){}setWillChange(t){}setUseTextShadow(t){}};c=new WeakMap,u=new WeakMap,b=new WeakMap,F=new WeakMap,W=new WeakMap,v=new WeakMap,L=new WeakMap,O=new WeakMap,A=new WeakMap,M=new WeakMap,rt=new WeakMap,E=new WeakSet,lt=function(t,e,i,o,s,n,a){let h=t.mode??1,k=t.text??"";if(!k)return;let R=t.color??16777215,_=t.font_size??r(this,u).fontSize,f=r(this,u),B=this.measureTextWidth(k,f.fontFamily,_,f.fontWeight)+f.padding*2,g=_;if(!a&&f.maxVisible>0&&r(this,v).length>=f.maxVisible&&f.overflow==="drop")return;let p=null;if(h===1){if(p=r(this,b).acquireScroll(e,B,i,s,f.scrollGap),!p){if(f.overflow==="drop"&&!a)return;let w=Math.random()*r(this,b).scrollTrackCount|0;p={track:w,y:(w+.5)*o};}}else if(h===5){if(p=r(this,b).acquireTop(e,f.duration),!p){if(f.overflow==="drop"&&!a)return;let w=Math.random()*r(this,b).topTrackCount|0;p={track:w,y:(w+.5)*o};}}else if(h===6){if(p=r(this,b).acquireBottom(e,f.duration),!p){if(f.overflow==="drop"&&!a)return;let w=Math.random()*r(this,b).bottomTrackCount|0;p={track:w,y:n*f.area-(w+.5)*o};}}else if(p=r(this,b).acquireScroll(e,B,i,s,f.scrollGap),!p)if(a){let w=Math.random()*r(this,b).scrollTrackCount|0;p={track:w,y:(w+.5)*o};}else return;let x=this.acquireVisibleDanmaku();x.id=t.id,x.text=k,x.mode=h,x.color=R,x.fontSize=_,x.x=h===1?s:s/2,x.y=p.y,x.track=p.track,x.w=B,x.h=g,x.born=performance.now()/1e3,x.duration=f.duration,this.renderDanmaku(x),r(this,v).push(x);},$=function(){let t=this.rendererHeight;if(t===0)return;let e=r(this,u),i=Math.max(2,Math.ceil(e.fontSize*.2)),o=e.fontSize+e.padding*2+i;r(this,b).resize(t,e.area,o);};function ht(l,t){let e=l;return [`-${e}px -${e}px 0 ${t}`,`0px -${e}px 0 ${t}`,`${e}px -${e}px 0 ${t}`,`-${e}px 0px 0 ${t}`,`${e}px 0px 0 ${t}`,`-${e}px ${e}px 0 ${t}`,`0px ${e}px 0 ${t}`,`${e}px ${e}px 0 ${t}`].join(",")}function ut(l,t,e){return `${e} ${t}px ${l}`}var it=class{constructor(t){this.container=t;let e=document.createElement("div");e.style.position="absolute",e.style.inset="0",e.style.overflow="hidden",e.style.pointerEvents="none",e.style.userSelect="none",t.appendChild(e),this.root=e;}get width(){return this.container.clientWidth}get height(){return this.container.clientHeight}createElement(t){let e=document.createElement("div");return e.style.position="absolute",e.style.left="0",e.style.top="0",e.style.whiteSpace="nowrap",e.style.font=t.font,e.style.color=t.fillColor,e.style.textShadow=t.textShadow,e.style.willChange=t.willChange,e.style.pointerEvents="none",e.style.userSelect="none",e}configureElement(t,e,i){t.textContent=e,t.style.font=i.font,t.style.color=i.fillColor,t.style.textShadow=i.textShadow,t.style.willChange=i.willChange;}positionElement(t,e,i,o,s){let n=Math.round(e),a=Math.round(i-s/2);o===1?t.style.transform=`translate3d(${n}px, ${a}px, 0)`:t.style.transform=`translate3d(${n}px, ${a}px, 0) translateX(-50%)`;}hideElement(t){t.style.display="none";}showElement(t){t.style.display="";}appendElement(t){this.root.appendChild(t);}removeElement(t){t.parentNode===this.root&&this.root.removeChild(t);}destroy(){this.root.remove();}};var ot=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():document.createElement("div")}release(t){this.pool.length<512&&(t.style.display="none",t.parentNode&&t.parentNode.removeChild(t),t.style.transform="",t.textContent="",this.pool.push(t));}releaseAll(t){for(let e=0;e<t.length;e++)this.release(t[e]);}get size(){return this.pool.length}};function U(l){return l<0||l>16777215||!Number.isFinite(l)?"#000000":"#"+l.toString(16).padStart(6,"0")}function yt({fontFamily:l,fontSize:t,fontWeight:e}){return `${e} ${t}px ${l}`}var mt=null;function xt(){if(!mt){let l=document.createElement("canvas");l.width=l.height=1,mt=l.getContext("2d");}return mt}function dt(l,t,e,i){let o=xt();return o.font=yt({fontFamily:t,fontSize:e,fontWeight:i}),o.measureText(l).width}var y,z,st=class extends et{constructor(e){super(e);d(this,y);d(this,z,new ot);m(this,y,new it(e.container)),this.initTracks();}get rendererWidth(){return r(this,y).width}get rendererHeight(){return r(this,y).height}clearRenderer(){}destroyRenderer(){r(this,y).destroy();}updateDimensions(){return r(this,y).width>0}measureTextWidth(e,i,o,s){return dt(e,i,o,s)}renderDanmaku(e){let i=this.cfg,o=ut(i.fontFamily,e.fontSize,i.fontWeight),s=i.useTextShadow?ht(i.strokeWidth*.7,U(i.strokeColor)):"none",n=i.willChange?"transform":"auto",a=r(this,z).acquire();a.textContent=e.text,a.style.font=o,a.style.color=U(e.color),a.style.textShadow=s,a.style.willChange=n,a.style.position="absolute",a.style.left="0",a.style.top="0",a.style.whiteSpace="nowrap",a.style.pointerEvents="none",a.style.userSelect="none",a.style.display="",a.style.opacity=String(i.opacity),r(this,y).appendElement(a),e.el=a;}releaseVisibleResource(e){e.el&&(r(this,y).hideElement(e.el),r(this,y).removeElement(e.el),r(this,z).release(e.el),e.el=void 0);}releaseAllVisibleResources(){let e=this.visible;for(let i=0;i<e.length;i++){let o=e[i];o.el&&(r(this,y).hideElement(o.el),r(this,y).removeElement(o.el),r(this,z).release(o.el),o.el=void 0);}}refreshVisibleDanmaku(){let e=this.cfg,i=e.useTextShadow?ht(e.strokeWidth*.7,U(e.strokeColor)):"none",o=e.willChange?"transform":"auto",s=this.visible;for(let n=0;n<s.length;n++){let a=s[n];if(!a.el)continue;let h=a.fontSize;a.el.style.font=ut(e.fontFamily,h,e.fontWeight),a.el.style.color=U(a.color),a.el.style.textShadow=i,a.el.style.willChange=o,a.el.style.opacity=String(e.opacity),a.w=dt(a.text,e.fontFamily,h,e.fontWeight)+e.padding*2,a.fontSize=e.fontSize;}}drawFrame(e,i){let o=this.visible;for(let s=0;s<o.length;s++){let n=o[s];n.el&&r(this,y).positionElement(n.el,n.x,n.y,n.mode,n.h);}}setEnabled(e){super.setEnabled(e),r(this,y).root.style.display=e?"":"none";}setOpacity(e){super.setOpacity(e),r(this,y).root.style.opacity=String(this.cfg.opacity);let i=this.visible;for(let o=0;o<i.length;o++){let s=i[o];s.el&&(s.el.style.opacity=String(this.cfg.opacity));}}setFontFamily(e){super.setFontFamily(e),this.refreshVisibleDanmaku();}setFontSize(e){super.setFontSize(e),this.refreshVisibleDanmaku();}setFontWeight(e){super.setFontWeight(e),this.refreshVisibleDanmaku();}setStrokeWidth(e){super.setStrokeWidth(e),this.refreshVisibleDanmaku();}setStrokeColor(e){super.setStrokeColor(e),this.refreshVisibleDanmaku();}setPadding(e){super.setPadding(e),this.refreshVisibleDanmaku();}setScrollGap(e){super.setScrollGap(e),this.refreshVisibleDanmaku();}setWillChange(e){this.isDestroyed||(this.cfg.willChange=e,this.refreshVisibleDanmaku());}setUseTextShadow(e){this.isDestroyed||(this.cfg.useTextShadow=e,this.refreshVisibleDanmaku());}};y=new WeakMap,z=new WeakMap;function ie(l,t){if(l!=="dom")throw new TypeError("other engines are not available in dom-only package");if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(t.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');return new st(t)}export{X as DanmakuMode,ie as createEngine};//# sourceMappingURL=dom.min.js.map
//# sourceMappingURL=dom.min.js.map

@@ -1,3 +0,3 @@

import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-DQHkoud-.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-DQHkoud-.js';
import { E as EngineType, D as DanmakuOptions, a as DanmakuEngine } from './engine-D9OmRc0L.js';
export { b as DanmakuItem, c as DanmakuMode, d as DataSourceAdapter, O as OverflowStrategy, P as PlayerAdapter } from './engine-D9OmRc0L.js';

@@ -4,0 +4,0 @@ /**

@@ -26,59 +26,2 @@ var __typeError = (msg) => {

// src/engine/canvas/renderer.ts
var CanvasRenderer = class {
constructor(container) {
this.W = 0;
this.H = 0;
this.dpr = 1;
this.container = container;
const canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.inset = "0";
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.pointerEvents = "none";
container.appendChild(canvas);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.updateDimensions();
}
/** Re-measure container and resize the canvas backing store. */
updateDimensions() {
const dpr = window.devicePixelRatio || 1;
const W = this.container.clientWidth;
const H = this.container.clientHeight;
if (W === 0 || H === 0) return false;
this.dpr = dpr;
this.W = W;
this.H = H;
this.canvas.width = W * dpr;
this.canvas.height = H * dpr;
this.canvas.style.width = W + "px";
this.canvas.style.height = H + "px";
this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
return true;
}
get width() {
return this.W;
}
get height() {
return this.H;
}
get devicePixelRatio() {
return this.dpr;
}
clear() {
this.ctx.clearRect(0, 0, this.W, this.H);
}
setSmoothing(enabled) {
this.ctx.imageSmoothingEnabled = enabled;
}
setGlobalAlpha(alpha) {
this.ctx.globalAlpha = alpha;
}
destroy() {
this.canvas.remove();
}
};
// src/core/track-manager.ts

@@ -123,3 +66,3 @@ var TrackManager = class {

// ---- Scroll track allocation (mode 1) ----
acquireScroll(currentTime, danmakuWidth, speed, _containerWidth) {
acquireScroll(currentTime, danmakuWidth, speed, containerWidth, scrollGap) {
const deferred = [];

@@ -129,3 +72,3 @@ while (this.scrollFree.length > 0) {

if (this.scrollExit[t] <= currentTime) {
this.scrollExit[t] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[t] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
for (const d of deferred) this.scrollFree.push(d);

@@ -141,3 +84,3 @@ return { track: t, y: this.scrollY(t) };

if (this.scrollExit[i] <= currentTime) {
this.scrollExit[i] = currentTime + danmakuWidth * 1.2 / speed;
this.scrollExit[i] = currentTime + (danmakuWidth + scrollGap * containerWidth / 1920) / speed;
const idx = this.scrollFree.indexOf(i);

@@ -239,166 +182,2 @@ if (idx !== -1) this.scrollFree.splice(idx, 1);

// src/engine/canvas/pool.ts
var MAX_POOL_SIZE = 512;
var ObjectPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : {};
}
release(v) {
if (this.pool.length < MAX_POOL_SIZE) {
v.bmp = void 0;
v.el = void 0;
this.pool.push(v);
}
}
releaseAll(visible) {
for (let i = 0; i < visible.length; i++) {
this.release(visible[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/engine/canvas/bitmap-cache.ts
var BitmapCache = class {
constructor(maxCache = 500) {
// Text measurement cache
this.textWidths = /* @__PURE__ */ new Map();
// ImageBitmap LRU cache
this.bitmaps = /* @__PURE__ */ new Map();
this.aliveBitmaps = /* @__PURE__ */ new Set();
this.accessCounter = 0;
this.dpr = 1;
// Cache for buildFont result
this.cachedFont = "";
this.fontFamily = "";
this.fontSize = 0;
this.fontWeight = "";
this.maxCache = maxCache;
}
// ---- Text measurement ----
measure(text, fontFamily, fontSize, fontWeight, ctx) {
const key = `${text}|${fontFamily}|${fontSize}|${fontWeight}`;
const cached = this.textWidths.get(key);
if (cached !== void 0) return cached;
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
const w = ctx.measureText(text).width;
this.textWidths.set(key, w);
return w;
}
invalidateTextCache() {
this.textWidths.clear();
}
// ---- ImageBitmap cache ----
getBitmap(text, fontSize, color, strokeWidth, strokeColor, fontFamily, fontWeight, dpr, padding) {
const key = `${text}|${fontSize}|${color}|${strokeWidth}|${strokeColor}|${fontFamily}|${fontWeight}|${dpr}`;
const hit = this.bitmaps.get(key);
if (hit) {
hit.accessId = ++this.accessCounter;
return hit.bitmap;
}
if (fontFamily !== this.fontFamily || fontSize !== this.fontSize || fontWeight !== this.fontWeight) {
this.fontFamily = fontFamily;
this.fontSize = fontSize;
this.fontWeight = fontWeight;
this.cachedFont = buildFont({ fontFamily, fontSize, fontWeight });
}
const tw = this.textWidths.get(`${text}|${fontFamily}|${fontSize}|${fontWeight}`);
if (tw === void 0) {
throw new Error(`Text width not cached for "${text}". Call measure() first.`);
}
const bmpW = Math.ceil(tw) + padding * 2;
const bmpH = fontSize + padding * 2;
const physW = bmpW * dpr | 0;
const physH = bmpH * dpr | 0;
const physPad = padding * dpr;
const physCenterY = physH / 2;
const off = new OffscreenCanvas(physW, physH);
const c = off.getContext("2d");
c.font = `${fontWeight} ${fontSize * dpr}px ${fontFamily}`;
c.lineWidth = strokeWidth * dpr;
c.lineJoin = "round";
c.textBaseline = "middle";
c.textAlign = "left";
c.strokeStyle = toCss(strokeColor);
c.strokeText(text, physPad, physCenterY);
c.fillStyle = toCss(color);
c.fillText(text, physPad, physCenterY);
const bmp = off.transferToImageBitmap();
this.bitmaps.set(key, { bitmap: bmp, accessId: ++this.accessCounter });
this.aliveBitmaps.add(bmp);
if (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
return bmp;
}
evictOne() {
let minKey = "";
let minAccess = Infinity;
for (const [k, v] of this.bitmaps) {
if (v.accessId < minAccess) {
minAccess = v.accessId;
minKey = k;
}
}
if (minKey) {
const entry = this.bitmaps.get(minKey);
if (entry) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
this.bitmaps.delete(minKey);
}
}
}
/** Returns true if the given bitmap is still cached (not evicted/closed). */
isAlive(bmp) {
return this.aliveBitmaps.has(bmp);
}
// ---- Configuration ----
setMaxCache(n) {
this.maxCache = n;
while (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
}
setDpr(dpr) {
if (this.dpr !== dpr) {
this.dpr = dpr;
this.clearBitmaps();
}
}
// ---- Cleanup ----
clearBitmaps() {
for (const [, entry] of this.bitmaps) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
}
this.bitmaps.clear();
}
clearAll() {
this.clearBitmaps();
this.textWidths.clear();
}
get bitmapCount() {
return this.bitmaps.size;
}
};
// src/core/raf-loop.ts

@@ -583,61 +362,2 @@ var _rafCallback;

// src/polyfills/requestIdleCallback.ts
var _ids = /* @__PURE__ */ new Map();
if (typeof window !== "undefined" && !window.requestIdleCallback) {
window.requestIdleCallback = function(callback, options) {
const timeout = options?.timeout;
let start = Date.now();
let timerId = 0;
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
};
if (timeout != null) {
timerId = setTimeout(() => {
idleDeadline.didTimeout = true;
start = Date.now();
callback(idleDeadline);
}, timeout);
}
const rafId = requestAnimationFrame(() => {
if (timeout != null) clearTimeout(timerId);
if (idleDeadline.didTimeout) return;
start = Date.now();
callback(idleDeadline);
});
const handle = Date.now() + Math.random();
_ids.set(handle, { rafId, timeoutId: timerId });
return handle;
};
window.cancelIdleCallback = function(handle) {
const ids = _ids.get(handle);
if (ids) {
cancelAnimationFrame(ids.rafId);
if (ids.timeoutId) clearTimeout(ids.timeoutId);
_ids.delete(handle);
}
};
}
// src/core/pre-cache.ts
function schedulePreCache(items, startIdx, count, fn) {
let idleHandle = 0;
let idx = startIdx;
function process(deadline) {
const end = Math.min(startIdx + count, items.length);
let processed = 0;
while (idx < end && (deadline.timeRemaining() > 1 || processed < 5)) {
const item = items[idx];
if (item) fn(item);
idx++;
processed++;
}
if (idx < end) {
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
}
}
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
return () => cancelIdleCallback(idleHandle);
}
// src/core/defaults.ts

@@ -655,2 +375,3 @@ var SHARED_DEFAULTS = {

strokeColor: 0,
scrollGap: 96,
speed: 1,

@@ -796,18 +517,18 @@ seekThreshold: 0.2,

// src/engine/canvas/index.ts
var _destroyed, _config, _renderer, _tracks, _pool, _cache, _loop, _scheduler, _visible, _lastTs, _cancelPreCache, _adapter2, _streamLoader, _lastPos, _tick, _CanvasEngine_instances, emit_fn, schedulePreCache_fn, resizeTracks_fn;
var CanvasEngine = class {
// src/engine/base.ts
var _destroyed, _config, _tracks, _scheduler, _loop, _visible, _lastTs, _lastPos, _adapter2, _streamLoader, _tick, _DanmakuEngineBase_instances, emit_fn, resizeTracks_fn;
var DanmakuEngineBase = class {
// ==================================================================
// Constructor
// ==================================================================
constructor(options) {
__privateAdd(this, _CanvasEngine_instances);
__privateAdd(this, _DanmakuEngineBase_instances);
__privateAdd(this, _destroyed, false);
__privateAdd(this, _config);
__privateAdd(this, _renderer);
__privateAdd(this, _tracks);
__privateAdd(this, _pool);
__privateAdd(this, _cache);
__privateAdd(this, _tracks, new TrackManager());
__privateAdd(this, _scheduler, new Scheduler());
__privateAdd(this, _loop);
__privateAdd(this, _scheduler);
__privateAdd(this, _visible, []);
__privateAdd(this, _lastTs, 0);
__privateAdd(this, _cancelPreCache, null);
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _adapter2);

@@ -818,10 +539,9 @@ __privateAdd(this, _streamLoader, null);

// ==================================================================
__privateAdd(this, _lastPos, -1);
__privateAdd(this, _tick, (ts) => {
const pos = __privateGet(this, _adapter2).position;
const paused = __privateGet(this, _adapter2).paused;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (!__privateGet(this, _config).enabled || W === 0) {
__privateGet(this, _renderer).clear();
this.clearRenderer();
return;

@@ -834,9 +554,9 @@ }

const v = __privateGet(this, _visible)[i];
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks).releaseBottom(v.track);
__privateGet(this, _pool).release(v);
}
__privateSet(this, _visible, []);
__privateGet(this, _renderer).clear();
this.clearRenderer();
__privateGet(this, _streamLoader)?.reset();

@@ -853,42 +573,14 @@ }

for (let i = 0; i < batch.length; i++) {
__privateMethod(this, _CanvasEngine_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, batch[i], pos, scrollSpeed, th, W, H);
}
const now = performance.now() / 1e3;
const onRemove = (v) => {
if (v.mode === 1 /* Scroll */) {
__privateGet(this, _tracks).releaseScroll(v.track);
} else if (v.mode === 5 /* Top */) {
__privateGet(this, _tracks).releaseTop(v.track);
} else if (v.mode === 6 /* Bottom */) {
__privateGet(this, _tracks).releaseBottom(v.track);
}
__privateGet(this, _pool).release(v);
this.releaseVisibleResource(v);
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks).releaseBottom(v.track);
};
__privateGet(this, _visible).length = __privateGet(this, _scheduler).compact(__privateGet(this, _visible), now, dt, scrollSpeed, onRemove);
__privateGet(this, _renderer).clear();
__privateGet(this, _renderer).setGlobalAlpha(__privateGet(this, _config).opacity);
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const pad = __privateGet(this, _config).padding;
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const v = __privateGet(this, _visible)[i];
const bmp = v.bmp;
if (!bmp) continue;
if (!__privateGet(this, _cache).isAlive(bmp)) {
v.bmp = void 0;
continue;
}
const dx = v.x | 0;
const dy = v.y | 0;
const sw = bmp.width;
const sh = bmp.height;
const dw = sw / dpr;
const dh = sh / dpr;
const ctx = __privateGet(this, _renderer).ctx;
if (v.mode === 1 /* Scroll */) {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - pad, dy - dh / 2 | 0, dw, dh);
} else {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - dw / 2 | 0, dy - dh / 2 | 0, dw, dh);
}
}
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
this.drawFrame(W, H);
this.onAfterTick();
__privateGet(this, _streamLoader)?.probe(pos, __privateGet(this, _scheduler));

@@ -904,8 +596,2 @@ });

__privateSet(this, _adapter2, options.adapter);
__privateSet(this, _renderer, new CanvasRenderer(options.container));
__privateGet(this, _renderer).setSmoothing(__privateGet(this, _config).smoothing);
__privateSet(this, _tracks, new TrackManager());
__privateSet(this, _pool, new ObjectPool());
__privateSet(this, _cache, new BitmapCache(__privateGet(this, _config).maxCache));
__privateSet(this, _scheduler, new Scheduler());
if (options.dataSource) {

@@ -920,6 +606,34 @@ __privateSet(this, _streamLoader, new StreamLoader(

}
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateSet(this, _loop, new RafLoop(__privateGet(this, _config).fps, __privateGet(this, _tick)));
}
// ==================================================================
// Optional hooks
// ==================================================================
/** Called after load() completes. Canvas uses for pre-cache scheduling. */
onAfterLoad() {
}
/** Called after each tick(). Canvas uses for pre-cache scheduling. */
onAfterTick() {
}
/** Create a VisibleDanmaku object. Canvas overrides for object pooling. */
acquireVisibleDanmaku() {
return {};
}
// ==================================================================
// Protected accessors for subclasses
// ==================================================================
get cfg() {
return __privateGet(this, _config);
}
get visible() {
return __privateGet(this, _visible);
}
getPreCacheInfo() {
return __privateGet(this, _scheduler).preCacheInfo();
}
/** Must be called by subclass constructors after renderer is initialized. */
initTracks() {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
// ==================================================================
// Lifecycle

@@ -931,12 +645,8 @@ // ==================================================================

load(items) {
var _a;
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _cache).clearAll();
__privateGet(this, _streamLoader)?.reset();
__privateGet(this, _scheduler).load(items);
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateSet(this, _cancelPreCache, null);
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
this.onAfterLoad();
}

@@ -946,4 +656,4 @@ send(item) {

const pos = __privateGet(this, _adapter2).position;
const W = __privateGet(this, _renderer).width;
const H = __privateGet(this, _renderer).height;
const W = this.rendererWidth;
const H = this.rendererHeight;
if (W === 0 || H === 0) return;

@@ -954,35 +664,28 @@ const scrollSpeed = W / 8 * __privateGet(this, _config).speed;

const sent = { ...item, time: pos };
__privateMethod(this, _CanvasEngine_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
__privateMethod(this, _DanmakuEngineBase_instances, emit_fn).call(this, sent, pos, scrollSpeed, th, W, H, true);
}
clear() {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _scheduler).clear();
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).clear();
this.clearRenderer();
}
resize() {
if (__privateGet(this, _destroyed)) return;
const ok = __privateGet(this, _renderer).updateDimensions();
if (ok) {
__privateGet(this, _cache).setDpr(__privateGet(this, _renderer).devicePixelRatio);
__privateGet(this, _cache).invalidateTextCache();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
if (this.updateDimensions()) {
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
}
destroy() {
var _a;
if (__privateGet(this, _destroyed)) return;
__privateSet(this, _destroyed, true);
__privateGet(this, _loop).stop();
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateGet(this, _streamLoader)?.destroy();
__privateGet(this, _pool).releaseAll(__privateGet(this, _visible));
this.releaseAllVisibleResources();
__privateSet(this, _visible, []);
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).destroy();
this.destroyRenderer();
}
// ==================================================================
// Runtime setters
// Runtime setters — shared logic
// ==================================================================

@@ -992,3 +695,2 @@ setEnabled(v) {

__privateGet(this, _config).enabled = v;
if (!v) __privateGet(this, _renderer).clear();
}

@@ -1003,3 +705,3 @@ setFps(v) {

__privateGet(this, _config).area = clamp(v, 0, 1);
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -1017,4 +719,2 @@ setOpacity(v) {

__privateGet(this, _config).fontFamily = v;
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
}

@@ -1024,5 +724,3 @@ setFontSize(v) {

__privateGet(this, _config).fontSize = clamp(v, 8, 128);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}

@@ -1032,4 +730,2 @@ setFontWeight(v) {

__privateGet(this, _config).fontWeight = v;
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
}

@@ -1039,3 +735,2 @@ setStrokeWidth(v) {

__privateGet(this, _config).strokeWidth = Math.max(0, v);
__privateGet(this, _cache).clearBitmaps();
}

@@ -1045,3 +740,2 @@ setStrokeColor(v) {

__privateGet(this, _config).strokeColor = v & 16777215;
__privateGet(this, _cache).clearBitmaps();
}

@@ -1051,8 +745,17 @@ setPadding(v) {

__privateGet(this, _config).padding = Math.max(0, v);
__privateGet(this, _cache).clearBitmaps();
__privateMethod(this, _CanvasEngine_instances, resizeTracks_fn).call(this);
__privateMethod(this, _DanmakuEngineBase_instances, resizeTracks_fn).call(this);
}
setScrollGap(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).scrollGap = Math.max(0, v);
}
setDuration(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).duration = Math.max(0.5, v);
for (let i = 0; i < __privateGet(this, _visible).length; i++) {
const d = __privateGet(this, _visible)[i];
if (d.mode !== 1 /* Scroll */) {
d.duration = __privateGet(this, _config).duration;
}
}
}

@@ -1067,17 +770,9 @@ setOverflow(v) {

}
setMaxCache(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).maxCache = Math.max(10, v);
__privateGet(this, _cache).setMaxCache(__privateGet(this, _config).maxCache);
// Engine-specific setters — default no-ops, overridden by subclasses
setMaxCache(_v) {
}
setPreCacheCount(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).preCacheCount = Math.max(0, v);
setPreCacheCount(_v) {
}
setSmoothing(v) {
if (__privateGet(this, _destroyed)) return;
__privateGet(this, _config).smoothing = v;
__privateGet(this, _renderer).setSmoothing(v);
setSmoothing(_v) {
}
// DOM-only setters — no-ops for canvas engine
setWillChange(_v) {

@@ -1090,16 +785,12 @@ }

_config = new WeakMap();
_renderer = new WeakMap();
_tracks = new WeakMap();
_pool = new WeakMap();
_cache = new WeakMap();
_scheduler = new WeakMap();
_loop = new WeakMap();
_scheduler = new WeakMap();
_visible = new WeakMap();
_lastTs = new WeakMap();
_cancelPreCache = new WeakMap();
_lastPos = new WeakMap();
_adapter2 = new WeakMap();
_streamLoader = new WeakMap();
_lastPos = new WeakMap();
_tick = new WeakMap();
_CanvasEngine_instances = new WeakSet();
_DanmakuEngineBase_instances = new WeakSet();
// ==================================================================

@@ -1115,4 +806,3 @@ // Internal: emit a single danmaku item

const cfg = __privateGet(this, _config);
const ctx = __privateGet(this, _renderer).ctx;
const tw = __privateGet(this, _cache).measure(text, cfg.fontFamily, fs, cfg.fontWeight, ctx);
const tw = this.measureTextWidth(text, cfg.fontFamily, fs, cfg.fontWeight);
const w = tw + cfg.padding * 2;

@@ -1125,3 +815,3 @@ const h = fs;

if (mode === 1 /* Scroll */) {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -1147,3 +837,3 @@ if (cfg.overflow === "drop" && !force) return;

} else {
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W);
trackResult = __privateGet(this, _tracks).acquireScroll(currentTime, w, scrollSpeed, W, cfg.scrollGap);
if (!trackResult) {

@@ -1158,14 +848,3 @@ if (force) {

}
const bmp = __privateGet(this, _cache).getBitmap(
text,
fs,
color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
__privateGet(this, _renderer).devicePixelRatio,
cfg.padding
);
const v = __privateGet(this, _pool).acquire();
const v = this.acquireVisibleDanmaku();
v.id = item.id;

@@ -1183,12 +862,495 @@ v.text = text;

v.duration = cfg.duration;
v.bmp = bmp;
this.renderDanmaku(v);
__privateGet(this, _visible).push(v);
};
// ==================================================================
// Internal: resize tracks
// ==================================================================
resizeTracks_fn = function() {
const H = this.rendererHeight;
if (H === 0) return;
const cfg = __privateGet(this, _config);
const gap = Math.max(2, Math.ceil(cfg.fontSize * 0.2));
const th = cfg.fontSize + cfg.padding * 2 + gap;
__privateGet(this, _tracks).resize(H, cfg.area, th);
};
// src/engine/canvas/renderer.ts
var CanvasRenderer = class {
constructor(container) {
this.W = 0;
this.H = 0;
this.dpr = 1;
this.container = container;
const canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.inset = "0";
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.style.pointerEvents = "none";
container.appendChild(canvas);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.updateDimensions();
}
/** Re-measure container and resize the canvas backing store. */
updateDimensions() {
const dpr = window.devicePixelRatio || 1;
const W = this.container.clientWidth;
const H = this.container.clientHeight;
if (W === 0 || H === 0) return false;
this.dpr = dpr;
this.W = W;
this.H = H;
this.canvas.width = W * dpr;
this.canvas.height = H * dpr;
this.canvas.style.width = W + "px";
this.canvas.style.height = H + "px";
this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
return true;
}
get width() {
return this.W;
}
get height() {
return this.H;
}
get devicePixelRatio() {
return this.dpr;
}
clear() {
this.ctx.clearRect(0, 0, this.W, this.H);
}
setSmoothing(enabled) {
this.ctx.imageSmoothingEnabled = enabled;
}
setGlobalAlpha(alpha) {
this.ctx.globalAlpha = alpha;
}
destroy() {
this.canvas.remove();
}
};
// src/engine/canvas/pool.ts
var MAX_POOL_SIZE = 512;
var ObjectPool = class {
constructor() {
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : {};
}
release(v) {
if (this.pool.length < MAX_POOL_SIZE) {
v.bmp = void 0;
v.el = void 0;
this.pool.push(v);
}
}
releaseAll(visible) {
for (let i = 0; i < visible.length; i++) {
this.release(visible[i]);
}
}
get size() {
return this.pool.length;
}
};
// src/utils/color.ts
function toCss(color) {
if (color < 0 || color > 16777215 || !Number.isFinite(color)) {
return "#000000";
}
return "#" + color.toString(16).padStart(6, "0");
}
// src/utils/font.ts
function buildFont({ fontFamily, fontSize, fontWeight }) {
return `${fontWeight} ${fontSize}px ${fontFamily}`;
}
// src/engine/canvas/bitmap-cache.ts
var BitmapCache = class {
constructor(maxCache = 500) {
// Text measurement cache
this.textWidths = /* @__PURE__ */ new Map();
// ImageBitmap LRU cache
this.bitmaps = /* @__PURE__ */ new Map();
this.aliveBitmaps = /* @__PURE__ */ new Set();
this.accessCounter = 0;
this.dpr = 1;
// Cache for buildFont result
this.cachedFont = "";
this.fontFamily = "";
this.fontSize = 0;
this.fontWeight = "";
this.maxCache = maxCache;
}
// ---- Text measurement ----
measure(text, fontFamily, fontSize, fontWeight, ctx) {
const key = `${text}|${fontFamily}|${fontSize}|${fontWeight}`;
const cached = this.textWidths.get(key);
if (cached !== void 0) return cached;
ctx.font = buildFont({ fontFamily, fontSize, fontWeight });
const w = ctx.measureText(text).width;
this.textWidths.set(key, w);
return w;
}
invalidateTextCache() {
this.textWidths.clear();
}
// ---- ImageBitmap cache ----
getBitmap(text, fontSize, color, strokeWidth, strokeColor, fontFamily, fontWeight, dpr, padding) {
const key = `${text}|${fontSize}|${color}|${strokeWidth}|${strokeColor}|${fontFamily}|${fontWeight}|${dpr}`;
const hit = this.bitmaps.get(key);
if (hit) {
hit.accessId = ++this.accessCounter;
return hit.bitmap;
}
if (fontFamily !== this.fontFamily || fontSize !== this.fontSize || fontWeight !== this.fontWeight) {
this.fontFamily = fontFamily;
this.fontSize = fontSize;
this.fontWeight = fontWeight;
this.cachedFont = buildFont({ fontFamily, fontSize, fontWeight });
}
const tw = this.textWidths.get(`${text}|${fontFamily}|${fontSize}|${fontWeight}`);
if (tw === void 0) {
throw new Error(`Text width not cached for "${text}". Call measure() first.`);
}
const bmpW = Math.ceil(tw) + padding * 2;
const bmpH = fontSize + padding * 2;
const physW = bmpW * dpr | 0;
const physH = bmpH * dpr | 0;
const physPad = padding * dpr;
const physCenterY = physH / 2;
const off = new OffscreenCanvas(physW, physH);
const c = off.getContext("2d");
c.font = `${fontWeight} ${fontSize * dpr}px ${fontFamily}`;
c.lineWidth = strokeWidth * dpr;
c.lineJoin = "round";
c.textBaseline = "middle";
c.textAlign = "left";
c.strokeStyle = toCss(strokeColor);
c.strokeText(text, physPad, physCenterY);
c.fillStyle = toCss(color);
c.fillText(text, physPad, physCenterY);
const bmp = off.transferToImageBitmap();
this.bitmaps.set(key, { bitmap: bmp, accessId: ++this.accessCounter });
this.aliveBitmaps.add(bmp);
if (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
return bmp;
}
evictOne() {
let minKey = "";
let minAccess = Infinity;
for (const [k, v] of this.bitmaps) {
if (v.accessId < minAccess) {
minAccess = v.accessId;
minKey = k;
}
}
if (minKey) {
const entry = this.bitmaps.get(minKey);
if (entry) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
this.bitmaps.delete(minKey);
}
}
}
/** Returns true if the given bitmap is still cached (not evicted/closed). */
isAlive(bmp) {
return this.aliveBitmaps.has(bmp);
}
// ---- Configuration ----
setMaxCache(n) {
this.maxCache = n;
while (this.bitmaps.size > this.maxCache) {
this.evictOne();
}
}
setDpr(dpr) {
if (this.dpr !== dpr) {
this.dpr = dpr;
this.clearBitmaps();
}
}
// ---- Cleanup ----
clearBitmaps() {
for (const [, entry] of this.bitmaps) {
this.aliveBitmaps.delete(entry.bitmap);
entry.bitmap.close();
}
this.bitmaps.clear();
}
clearAll() {
this.clearBitmaps();
this.textWidths.clear();
}
get bitmapCount() {
return this.bitmaps.size;
}
};
// src/polyfills/requestIdleCallback.ts
var _ids = /* @__PURE__ */ new Map();
if (typeof window !== "undefined" && !window.requestIdleCallback) {
window.requestIdleCallback = function(callback, options) {
const timeout = options?.timeout;
let start = Date.now();
let timerId = 0;
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
};
if (timeout != null) {
timerId = setTimeout(() => {
idleDeadline.didTimeout = true;
start = Date.now();
callback(idleDeadline);
}, timeout);
}
const rafId = requestAnimationFrame(() => {
if (timeout != null) clearTimeout(timerId);
if (idleDeadline.didTimeout) return;
start = Date.now();
callback(idleDeadline);
});
const handle = Date.now() + Math.random();
_ids.set(handle, { rafId, timeoutId: timerId });
return handle;
};
window.cancelIdleCallback = function(handle) {
const ids = _ids.get(handle);
if (ids) {
cancelAnimationFrame(ids.rafId);
if (ids.timeoutId) clearTimeout(ids.timeoutId);
_ids.delete(handle);
}
};
}
// src/core/pre-cache.ts
function schedulePreCache(items, startIdx, count, fn) {
let idleHandle = 0;
let idx = startIdx;
function process(deadline) {
const end = Math.min(startIdx + count, items.length);
let processed = 0;
while (idx < end && (deadline.timeRemaining() > 1 || processed < 5)) {
const item = items[idx];
if (item) fn(item);
idx++;
processed++;
}
if (idx < end) {
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
}
}
idleHandle = requestIdleCallback(process, { timeout: 2e3 });
return () => cancelIdleCallback(idleHandle);
}
// src/engine/canvas/index.ts
var _renderer, _pool, _cache, _cancelPreCache, _CanvasEngine_instances, schedulePreCache_fn;
var CanvasEngine = class extends DanmakuEngineBase {
constructor(options) {
super(options);
__privateAdd(this, _CanvasEngine_instances);
__privateAdd(this, _renderer);
__privateAdd(this, _pool, new ObjectPool());
__privateAdd(this, _cache);
__privateAdd(this, _cancelPreCache, null);
__privateSet(this, _renderer, new CanvasRenderer(options.container));
__privateGet(this, _renderer).setSmoothing(this.cfg.smoothing);
__privateSet(this, _cache, new BitmapCache(this.cfg.maxCache));
this.initTracks();
}
// ==================================================================
// Abstract hook implementations
// ==================================================================
get rendererWidth() {
return __privateGet(this, _renderer).width;
}
get rendererHeight() {
return __privateGet(this, _renderer).height;
}
clearRenderer() {
__privateGet(this, _renderer).clear();
}
destroyRenderer() {
__privateGet(this, _renderer).destroy();
}
updateDimensions() {
const ok = __privateGet(this, _renderer).updateDimensions();
if (ok) {
__privateGet(this, _cache).setDpr(__privateGet(this, _renderer).devicePixelRatio);
__privateGet(this, _cache).invalidateTextCache();
}
return ok;
}
measureTextWidth(text, family, size, weight) {
return __privateGet(this, _cache).measure(text, family, size, weight, __privateGet(this, _renderer).ctx);
}
renderDanmaku(v) {
const cfg = this.cfg;
v.bmp = __privateGet(this, _cache).getBitmap(
v.text,
v.fontSize,
v.color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
__privateGet(this, _renderer).devicePixelRatio,
cfg.padding
);
}
releaseVisibleResource(v) {
__privateGet(this, _pool).release(v);
}
releaseAllVisibleResources() {
__privateGet(this, _pool).releaseAll(this.visible);
__privateGet(this, _cache).clearAll();
__privateGet(this, _renderer).clear();
}
refreshVisibleDanmaku() {
const ctx = __privateGet(this, _renderer).ctx;
const cfg = this.cfg;
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
const fs = v.fontSize;
const tw = __privateGet(this, _cache).measure(v.text, cfg.fontFamily, fs, cfg.fontWeight, ctx);
v.w = tw + cfg.padding * 2;
v.h = fs;
v.bmp = __privateGet(this, _cache).getBitmap(
v.text,
fs,
v.color,
cfg.strokeWidth,
cfg.strokeColor,
cfg.fontFamily,
cfg.fontWeight,
dpr,
cfg.padding
);
}
}
drawFrame(W, _H) {
__privateGet(this, _renderer).clear();
__privateGet(this, _renderer).setGlobalAlpha(this.cfg.opacity);
const dpr = __privateGet(this, _renderer).devicePixelRatio;
const pad = this.cfg.padding;
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
const bmp = v.bmp;
if (!bmp) continue;
if (!__privateGet(this, _cache).isAlive(bmp)) {
v.bmp = void 0;
continue;
}
const dx = v.x | 0;
const dy = v.y | 0;
const sw = bmp.width;
const sh = bmp.height;
const dw = sw / dpr;
const dh = sh / dpr;
const ctx = __privateGet(this, _renderer).ctx;
if (v.mode === 1) {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - pad, dy - dh / 2 | 0, dw, dh);
} else {
ctx.drawImage(bmp, 0, 0, sw, sh, dx - dw / 2 | 0, dy - dh / 2 | 0, dw, dh);
}
}
}
acquireVisibleDanmaku() {
return __privateGet(this, _pool).acquire();
}
onAfterLoad() {
var _a;
(_a = __privateGet(this, _cancelPreCache)) == null ? void 0 : _a.call(this);
__privateSet(this, _cancelPreCache, null);
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
}
onAfterTick() {
__privateMethod(this, _CanvasEngine_instances, schedulePreCache_fn).call(this);
}
// ==================================================================
// Override setters — add canvas-specific cache invalidation + refresh
// ==================================================================
setEnabled(v) {
super.setEnabled(v);
if (!v) __privateGet(this, _renderer).clear();
}
setFontFamily(v) {
super.setFontFamily(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setFontSize(v) {
super.setFontSize(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setFontWeight(v) {
super.setFontWeight(v);
__privateGet(this, _cache).invalidateTextCache();
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setStrokeWidth(v) {
super.setStrokeWidth(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setStrokeColor(v) {
super.setStrokeColor(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setPadding(v) {
super.setPadding(v);
__privateGet(this, _cache).clearBitmaps();
this.refreshVisibleDanmaku();
}
setScrollGap(v) {
super.setScrollGap(v);
this.refreshVisibleDanmaku();
}
setMaxCache(v) {
if (this.isDestroyed) return;
this.cfg.maxCache = Math.max(10, v);
__privateGet(this, _cache).setMaxCache(this.cfg.maxCache);
}
setPreCacheCount(v) {
if (this.isDestroyed) return;
this.cfg.preCacheCount = Math.max(0, v);
}
setSmoothing(v) {
if (this.isDestroyed) return;
this.cfg.smoothing = v;
__privateGet(this, _renderer).setSmoothing(v);
}
};
_renderer = new WeakMap();
_pool = new WeakMap();
_cache = new WeakMap();
_cancelPreCache = new WeakMap();
_CanvasEngine_instances = new WeakSet();
// ==================================================================
// Internal: pre-cache scheduling
// ==================================================================
schedulePreCache_fn = function() {
if (__privateGet(this, _cancelPreCache) || __privateGet(this, _destroyed)) return;
const { pool, cursor } = __privateGet(this, _scheduler).preCacheInfo();
const cfg = __privateGet(this, _config);
if (__privateGet(this, _cancelPreCache) || this.isDestroyed) return;
const { pool, cursor } = this.getPreCacheInfo();
const cfg = this.cfg;
__privateSet(this, _cancelPreCache, schedulePreCache(

@@ -1220,13 +1382,2 @@ pool,

};
// ==================================================================
// Internal: resize tracks
// ==================================================================
resizeTracks_fn = function() {
const H = __privateGet(this, _renderer).height;
if (H === 0) return;
const cfg = __privateGet(this, _config);
const gap = Math.max(2, Math.ceil(cfg.fontSize * 0.2));
const th = cfg.fontSize + cfg.padding * 2 + gap;
__privateGet(this, _tracks).resize(H, cfg.area, th);
};

@@ -1373,336 +1524,157 @@ // src/engine/dom/renderer.ts

// src/engine/dom/index.ts
var _destroyed2, _config2, _renderer2, _tracks2, _pool2, _loop2, _scheduler2, _visible2, _lastTs2, _adapter3, _streamLoader2, _lastPos2, _tick2, _DOMEngine_instances, emit_fn2, resizeTracks_fn2;
var DOMEngine = class {
var _renderer2, _pool2;
var DOMEngine = class extends DanmakuEngineBase {
constructor(options) {
__privateAdd(this, _DOMEngine_instances);
__privateAdd(this, _destroyed2, false);
__privateAdd(this, _config2);
super(options);
__privateAdd(this, _renderer2);
__privateAdd(this, _tracks2);
__privateAdd(this, _pool2);
__privateAdd(this, _loop2);
__privateAdd(this, _scheduler2);
__privateAdd(this, _visible2, []);
__privateAdd(this, _lastTs2, 0);
__privateAdd(this, _adapter3);
__privateAdd(this, _streamLoader2, null);
// ==================================================================
// Internal: RAF tick
// ==================================================================
__privateAdd(this, _lastPos2, -1);
__privateAdd(this, _tick2, (ts) => {
const pos = __privateGet(this, _adapter3).position;
const paused = __privateGet(this, _adapter3).paused;
const W = __privateGet(this, _renderer2).width;
const H = __privateGet(this, _renderer2).height;
if (!__privateGet(this, _config2).enabled || W === 0) {
return;
}
if (paused) return;
const posJump = Math.abs(pos - __privateGet(this, _lastPos2));
if (__privateGet(this, _lastPos2) >= 0 && posJump > __privateGet(this, _config2).seekThreshold) {
for (let i = 0; i < __privateGet(this, _visible2).length; i++) {
const v = __privateGet(this, _visible2)[i];
if (v.el) {
__privateGet(this, _renderer2).removeElement(v.el);
__privateGet(this, _pool2).release(v.el);
}
if (v.mode === 1 /* Scroll */) __privateGet(this, _tracks2).releaseScroll(v.track);
else if (v.mode === 5 /* Top */) __privateGet(this, _tracks2).releaseTop(v.track);
else if (v.mode === 6 /* Bottom */) __privateGet(this, _tracks2).releaseBottom(v.track);
}
__privateSet(this, _visible2, []);
__privateGet(this, _streamLoader2)?.reset();
}
__privateSet(this, _lastPos2, pos);
const dt = __privateGet(this, _lastTs2) ? Math.min((ts - __privateGet(this, _lastTs2)) / 1e3, 0.05) : 0;
__privateSet(this, _lastTs2, ts);
const scrollSpeed = W / 8 * __privateGet(this, _config2).speed;
const gap = Math.max(2, Math.ceil(__privateGet(this, _config2).fontSize * 0.2));
const th = __privateGet(this, _config2).fontSize + __privateGet(this, _config2).padding * 2 + gap;
const posMs = pos * 1e3;
const batch = __privateGet(this, _scheduler2).emitBatch(posMs);
for (let i = 0; i < batch.length; i++) {
__privateMethod(this, _DOMEngine_instances, emit_fn2).call(this, batch[i], pos, scrollSpeed, th, W, H);
}
const now = performance.now() / 1e3;
const onRemove = (v) => {
if (v.el) {
__privateGet(this, _renderer2).hideElement(v.el);
__privateGet(this, _renderer2).removeElement(v.el);
__privateGet(this, _pool2).release(v.el);
v.el = void 0;
}
if (v.mode === 1 /* Scroll */) {
__privateGet(this, _tracks2).releaseScroll(v.track);
} else if (v.mode === 5 /* Top */) {
__privateGet(this, _tracks2).releaseTop(v.track);
} else if (v.mode === 6 /* Bottom */) {
__privateGet(this, _tracks2).releaseBottom(v.track);
}
};
const newLen = __privateGet(this, _scheduler2).compact(__privateGet(this, _visible2), now, dt, scrollSpeed, onRemove);
__privateGet(this, _visible2).length = newLen;
for (let i = 0; i < __privateGet(this, _visible2).length; i++) {
const v = __privateGet(this, _visible2)[i];
if (v.el) {
__privateGet(this, _renderer2).positionElement(v.el, v.x, v.y, v.mode, v.h);
}
}
__privateGet(this, _streamLoader2)?.probe(pos, __privateGet(this, _scheduler2));
});
if (!(options.container instanceof HTMLElement)) {
throw new TypeError("container must be an HTMLElement");
}
if (!options.adapter) {
throw new TypeError("adapter is required");
}
__privateSet(this, _config2, { ...SHARED_DEFAULTS, ...options });
__privateSet(this, _adapter3, options.adapter);
__privateAdd(this, _pool2, new DOMPool());
__privateSet(this, _renderer2, new DOMRenderer(options.container));
__privateSet(this, _tracks2, new TrackManager());
__privateSet(this, _pool2, new DOMPool());
__privateSet(this, _scheduler2, new Scheduler());
if (options.dataSource) {
__privateSet(this, _streamLoader2, new StreamLoader(
options.dataSource,
__privateGet(this, _config2).preBuffer,
__privateGet(this, _config2).leadTime,
__privateGet(this, _config2).seekThreshold,
options.onError
));
}
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn2).call(this);
__privateSet(this, _loop2, new RafLoop(__privateGet(this, _config2).fps, __privateGet(this, _tick2)));
this.initTracks();
}
// ==================================================================
// Lifecycle
// Abstract hook implementations
// ==================================================================
get isDestroyed() {
return __privateGet(this, _destroyed2);
get rendererWidth() {
return __privateGet(this, _renderer2).width;
}
load(items) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _pool2).releaseAll(__privateGet(this, _visible2).map((v) => v.el).filter(Boolean));
__privateSet(this, _visible2, []);
__privateGet(this, _streamLoader2)?.reset();
__privateGet(this, _scheduler2).load(items);
get rendererHeight() {
return __privateGet(this, _renderer2).height;
}
send(item) {
if (__privateGet(this, _destroyed2) || !__privateGet(this, _config2).enabled) return;
const pos = __privateGet(this, _adapter3).position;
const W = __privateGet(this, _renderer2).width;
const H = __privateGet(this, _renderer2).height;
if (W === 0 || H === 0) return;
const scrollSpeed = W / 8 * __privateGet(this, _config2).speed;
const gap = Math.max(2, Math.ceil(__privateGet(this, _config2).fontSize * 0.2));
const th = __privateGet(this, _config2).fontSize + __privateGet(this, _config2).padding * 2 + gap;
const sent = { ...item, time: pos };
__privateMethod(this, _DOMEngine_instances, emit_fn2).call(this, sent, pos, scrollSpeed, th, W, H, true);
clearRenderer() {
}
clear() {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _pool2).releaseAll(__privateGet(this, _visible2).map((v) => v.el).filter(Boolean));
__privateSet(this, _visible2, []);
__privateGet(this, _scheduler2).clear();
destroyRenderer() {
__privateGet(this, _renderer2).destroy();
}
resize() {
if (__privateGet(this, _destroyed2)) return;
if (__privateGet(this, _renderer2).width > 0) {
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn2).call(this);
updateDimensions() {
return __privateGet(this, _renderer2).width > 0;
}
measureTextWidth(text, family, size, weight) {
return measureTextWidth(text, family, size, weight);
}
renderDanmaku(v) {
const cfg = this.cfg;
const font = buildDomFont(cfg.fontFamily, v.fontSize, cfg.fontWeight);
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const el = __privateGet(this, _pool2).acquire();
el.textContent = v.text;
el.style.font = font;
el.style.color = toCss(v.color);
el.style.textShadow = textShadow;
el.style.willChange = willChange;
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.pointerEvents = "none";
el.style.userSelect = "none";
el.style.display = "";
el.style.opacity = String(cfg.opacity);
__privateGet(this, _renderer2).appendElement(el);
v.el = el;
}
releaseVisibleResource(v) {
if (v.el) {
__privateGet(this, _renderer2).hideElement(v.el);
__privateGet(this, _renderer2).removeElement(v.el);
__privateGet(this, _pool2).release(v.el);
v.el = void 0;
}
}
destroy() {
if (__privateGet(this, _destroyed2)) return;
__privateSet(this, _destroyed2, true);
__privateGet(this, _loop2).stop();
__privateGet(this, _streamLoader2)?.destroy();
__privateGet(this, _pool2).releaseAll(__privateGet(this, _visible2).map((v) => v.el).filter(Boolean));
__privateSet(this, _visible2, []);
__privateGet(this, _renderer2).destroy();
releaseAllVisibleResources() {
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (v.el) {
__privateGet(this, _renderer2).hideElement(v.el);
__privateGet(this, _renderer2).removeElement(v.el);
__privateGet(this, _pool2).release(v.el);
v.el = void 0;
}
}
}
refreshVisibleDanmaku() {
const cfg = this.cfg;
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (!v.el) continue;
const fs = v.fontSize;
v.el.style.font = buildDomFont(cfg.fontFamily, fs, cfg.fontWeight);
v.el.style.color = toCss(v.color);
v.el.style.textShadow = textShadow;
v.el.style.willChange = willChange;
v.el.style.opacity = String(cfg.opacity);
v.w = measureTextWidth(v.text, cfg.fontFamily, fs, cfg.fontWeight) + cfg.padding * 2;
v.fontSize = cfg.fontSize;
}
}
drawFrame(_W, _H) {
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const v = visible[i];
if (v.el) {
__privateGet(this, _renderer2).positionElement(v.el, v.x, v.y, v.mode, v.h);
}
}
}
// ==================================================================
// Runtime setters
// Override setters with DOM-specific side effects
// ==================================================================
setEnabled(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).enabled = v;
super.setEnabled(v);
__privateGet(this, _renderer2).root.style.display = v ? "" : "none";
}
setFps(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).fps = clamp(v, 1, 120);
__privateGet(this, _loop2).setFps(__privateGet(this, _config2).fps);
}
setArea(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).area = clamp(v, 0, 1);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn2).call(this);
}
setOpacity(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).opacity = clamp(v, 0, 1);
__privateGet(this, _renderer2).root.style.opacity = String(__privateGet(this, _config2).opacity);
super.setOpacity(v);
__privateGet(this, _renderer2).root.style.opacity = String(this.cfg.opacity);
const visible = this.visible;
for (let i = 0; i < visible.length; i++) {
const d = visible[i];
if (d.el) d.el.style.opacity = String(this.cfg.opacity);
}
}
setSpeed(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).speed = Math.max(0.1, v);
}
setFontFamily(v) {
__privateGet(this, _config2).fontFamily = v;
super.setFontFamily(v);
this.refreshVisibleDanmaku();
}
setFontSize(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).fontSize = clamp(v, 8, 128);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn2).call(this);
super.setFontSize(v);
this.refreshVisibleDanmaku();
}
setFontWeight(v) {
__privateGet(this, _config2).fontWeight = v;
super.setFontWeight(v);
this.refreshVisibleDanmaku();
}
setStrokeWidth(v) {
__privateGet(this, _config2).strokeWidth = Math.max(0, v);
super.setStrokeWidth(v);
this.refreshVisibleDanmaku();
}
setStrokeColor(v) {
__privateGet(this, _config2).strokeColor = v & 16777215;
super.setStrokeColor(v);
this.refreshVisibleDanmaku();
}
setPadding(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).padding = Math.max(0, v);
__privateMethod(this, _DOMEngine_instances, resizeTracks_fn2).call(this);
super.setPadding(v);
this.refreshVisibleDanmaku();
}
setDuration(v) {
__privateGet(this, _config2).duration = Math.max(0.5, v);
setScrollGap(v) {
super.setScrollGap(v);
this.refreshVisibleDanmaku();
}
setOverflow(v) {
__privateGet(this, _config2).overflow = v;
}
setMaxVisible(v) {
__privateGet(this, _config2).maxVisible = Math.max(0, v);
}
// No-ops for DOM (no bitmap cache)
setMaxCache(_v) {
}
setPreCacheCount(_v) {
}
// Canvas-only — no-ops for DOM
setSmoothing(_v) {
}
setWillChange(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).willChange = v;
if (this.isDestroyed) return;
this.cfg.willChange = v;
this.refreshVisibleDanmaku();
}
setUseTextShadow(v) {
if (__privateGet(this, _destroyed2)) return;
__privateGet(this, _config2).useTextShadow = v;
if (this.isDestroyed) return;
this.cfg.useTextShadow = v;
this.refreshVisibleDanmaku();
}
};
_destroyed2 = new WeakMap();
_config2 = new WeakMap();
_renderer2 = new WeakMap();
_tracks2 = new WeakMap();
_pool2 = new WeakMap();
_loop2 = new WeakMap();
_scheduler2 = new WeakMap();
_visible2 = new WeakMap();
_lastTs2 = new WeakMap();
_adapter3 = new WeakMap();
_streamLoader2 = new WeakMap();
_lastPos2 = new WeakMap();
_tick2 = new WeakMap();
_DOMEngine_instances = new WeakSet();
// ==================================================================
// Internal: emit
// ==================================================================
emit_fn2 = function(item, currentTime, scrollSpeed, th, W, H, force) {
const mode = item.mode ?? 1 /* Scroll */;
const text = item.text ?? "";
if (!text) return;
const color = item.color ?? 16777215;
const fs = item.font_size ?? __privateGet(this, _config2).fontSize;
const cfg = __privateGet(this, _config2);
const tw = measureTextWidth(text, cfg.fontFamily, fs, cfg.fontWeight);
const w = tw + cfg.padding * 2;
const h = fs;
if (!force && cfg.maxVisible > 0 && __privateGet(this, _visible2).length >= cfg.maxVisible) {
if (cfg.overflow === "drop") return;
}
let trackResult = null;
if (mode === 1 /* Scroll */) {
trackResult = __privateGet(this, _tracks2).acquireScroll(currentTime, w, scrollSpeed, W);
if (!trackResult) {
if (cfg.overflow === "drop" && !force) return;
const track = Math.random() * __privateGet(this, _tracks2).scrollTrackCount | 0;
trackResult = { track, y: (track + 0.5) * th };
}
} else if (mode === 5 /* Top */) {
trackResult = __privateGet(this, _tracks2).acquireTop(currentTime, cfg.duration);
if (!trackResult) {
if (cfg.overflow === "drop" && !force) return;
const track = Math.random() * __privateGet(this, _tracks2).topTrackCount | 0;
trackResult = { track, y: (track + 0.5) * th };
}
} else if (mode === 6 /* Bottom */) {
trackResult = __privateGet(this, _tracks2).acquireBottom(currentTime, cfg.duration);
if (!trackResult) {
if (cfg.overflow === "drop" && !force) return;
const track = Math.random() * __privateGet(this, _tracks2).bottomTrackCount | 0;
trackResult = { track, y: H * cfg.area - (track + 0.5) * th };
}
} else {
trackResult = __privateGet(this, _tracks2).acquireScroll(currentTime, w, scrollSpeed, W);
if (!trackResult) {
if (force) {
const track = Math.random() * __privateGet(this, _tracks2).scrollTrackCount | 0;
trackResult = { track, y: (track + 0.5) * th };
} else {
return;
}
}
}
const font = buildDomFont(cfg.fontFamily, fs, cfg.fontWeight);
const textShadow = cfg.useTextShadow ? buildTextShadow(cfg.strokeWidth * 0.7, toCss(cfg.strokeColor)) : "none";
const willChange = cfg.willChange ? "transform" : "auto";
const el = __privateGet(this, _pool2).acquire();
el.textContent = text;
el.style.font = font;
el.style.color = toCss(color);
el.style.textShadow = textShadow;
el.style.willChange = willChange;
el.style.position = "absolute";
el.style.left = "0";
el.style.top = "0";
el.style.whiteSpace = "nowrap";
el.style.pointerEvents = "none";
el.style.userSelect = "none";
el.style.display = "";
el.style.opacity = String(cfg.opacity);
__privateGet(this, _renderer2).appendElement(el);
const v = {
id: item.id,
text,
mode,
color,
fontSize: fs,
x: mode === 1 /* Scroll */ ? W : W / 2,
y: trackResult.y,
track: trackResult.track,
w,
h,
born: performance.now() / 1e3,
duration: cfg.duration,
el
};
__privateGet(this, _visible2).push(v);
};
// ==================================================================
// Internal: resize tracks
// ==================================================================
resizeTracks_fn2 = function() {
const H = __privateGet(this, _renderer2).height;
if (H === 0) return;
const cfg = __privateGet(this, _config2);
const gap = Math.max(2, Math.ceil(cfg.fontSize * 0.2));
const th = cfg.fontSize + cfg.padding * 2 + gap;
__privateGet(this, _tracks2).resize(H, cfg.area, th);
};

@@ -1709,0 +1681,0 @@ // src/engine/index.ts

@@ -1,2 +0,2 @@

var Yt=h=>{throw TypeError(h)};var Rt=(h,t,i)=>t.has(h)||Yt("Cannot "+i);var e=(h,t,i)=>(Rt(h,t,"read from private field"),i?i.call(h):t.get(h)),f=(h,t,i)=>t.has(h)?Yt("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(h):t.set(h,i),c=(h,t,i,s)=>(Rt(h,t,"write to private field"),t.set(h,i),i),C=(h,t,i)=>(Rt(h,t,"access private method"),i);var Lt=(h,t,i,s)=>({set _(o){c(h,t,o);},get _(){return e(h,t,s)}});var ft=(s=>(s[s.Scroll=1]="Scroll",s[s.Top=5]="Top",s[s.Bottom=6]="Bottom",s))(ft||{});var Ct=class{constructor(t){this.W=0;this.H=0;this.dpr=1;this.container=t;let i=document.createElement("canvas");i.style.position="absolute",i.style.inset="0",i.style.width="100%",i.style.height="100%",i.style.pointerEvents="none",t.appendChild(i),this.canvas=i,this.ctx=i.getContext("2d"),this.updateDimensions();}updateDimensions(){let t=window.devicePixelRatio||1,i=this.container.clientWidth,s=this.container.clientHeight;return i===0||s===0?false:(this.dpr=t,this.W=i,this.H=s,this.canvas.width=i*t,this.canvas.height=s*t,this.canvas.style.width=i+"px",this.canvas.style.height=s+"px",this.ctx.setTransform(t,0,0,t,0,0),true)}get width(){return this.W}get height(){return this.H}get devicePixelRatio(){return this.dpr}clear(){this.ctx.clearRect(0,0,this.W,this.H);}setSmoothing(t){this.ctx.imageSmoothingEnabled=t;}setGlobalAlpha(t){this.ctx.globalAlpha=t;}destroy(){this.canvas.remove();}};var et=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(t,i,s){this.H=t,this.th=s,this.areaFraction=i;let o=t*i,r=Math.max(1,Math.floor(o/s)),n=Math.max(1,Math.floor(o*.48/s));this.scrollCount=r,this.topCount=n,this.bottomCount=n,this.scrollExit=new Float64Array(r).fill(-1/0),this.topExit=new Float64Array(n).fill(-1/0),this.bottomExit=new Float64Array(n).fill(-1/0),this.scrollFree=Array.from({length:r},(a,l)=>l),this.topFree=Array.from({length:n},(a,l)=>l),this.bottomFree=Array.from({length:n},(a,l)=>l);}acquireScroll(t,i,s,o){let r=[];for(;this.scrollFree.length>0;){let a=this.scrollFree.pop();if(this.scrollExit[a]<=t){this.scrollExit[a]=t+i*1.2/s;for(let l of r)this.scrollFree.push(l);return {track:a,y:this.scrollY(a)}}r.push(a);}for(let a of r)this.scrollFree.push(a);let n=Math.random()*this.scrollCount|0;for(let a=0;a<this.scrollCount;a++){let l=(n+a)%this.scrollCount;if(this.scrollExit[l]<=t){this.scrollExit[l]=t+i*1.2/s;let k=this.scrollFree.indexOf(l);return k!==-1&&this.scrollFree.splice(k,1),{track:l,y:this.scrollY(l)}}}return null}releaseScroll(t){this.scrollExit[t]=-1/0,this.scrollFree.includes(t)||this.scrollFree.push(t);}acquireTop(t,i){let s=[];for(;this.topFree.length>0;){let r=this.topFree.pop();if(this.topExit[r]<=t){this.topExit[r]=t+i;for(let n of s)this.topFree.push(n);return {track:r,y:this.fixedY(r,true)}}s.push(r);}for(let r of s)this.topFree.push(r);let o=Math.random()*this.topCount|0;for(let r=0;r<this.topCount;r++){let n=(o+r)%this.topCount;if(this.topExit[n]<=t){this.topExit[n]=t+i;let a=this.topFree.indexOf(n);return a!==-1&&this.topFree.splice(a,1),{track:n,y:this.fixedY(n,true)}}}return null}releaseTop(t){this.topExit[t]=-1/0,this.topFree.includes(t)||this.topFree.push(t);}acquireBottom(t,i){let s=[];for(;this.bottomFree.length>0;){let r=this.bottomFree.pop();if(this.bottomExit[r]<=t){this.bottomExit[r]=t+i;for(let n of s)this.bottomFree.push(n);return {track:r,y:this.fixedY(r,false)}}s.push(r);}for(let r of s)this.bottomFree.push(r);let o=Math.random()*this.bottomCount|0;for(let r=0;r<this.bottomCount;r++){let n=(o+r)%this.bottomCount;if(this.bottomExit[n]<=t){this.bottomExit[n]=t+i;let a=this.bottomFree.indexOf(n);return a!==-1&&this.bottomFree.splice(a,1),{track:n,y:this.fixedY(n,false)}}}return null}releaseBottom(t){this.bottomExit[t]=-1/0,this.bottomFree.includes(t)||this.bottomFree.push(t);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(t){return (t+.5)*this.th}fixedY(t,i){return i?(t+.5)*this.th:this.H*this.areaFraction-(t+.5)*this.th}};var St=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():{}}release(t){this.pool.length<512&&(t.bmp=void 0,t.el=void 0,this.pool.push(t));}releaseAll(t){for(let i=0;i<t.length;i++)this.release(t[i]);}get size(){return this.pool.length}};function it(h){return h<0||h>16777215||!Number.isFinite(h)?"#000000":"#"+h.toString(16).padStart(6,"0")}function bt({fontFamily:h,fontSize:t,fontWeight:i}){return `${i} ${t}px ${h}`}var Dt=class{constructor(t=500){this.textWidths=new Map;this.bitmaps=new Map;this.aliveBitmaps=new Set;this.accessCounter=0;this.dpr=1;this.cachedFont="";this.fontFamily="";this.fontSize=0;this.fontWeight="";this.maxCache=t;}measure(t,i,s,o,r){let n=`${t}|${i}|${s}|${o}`,a=this.textWidths.get(n);if(a!==void 0)return a;r.font=bt({fontFamily:i,fontSize:s,fontWeight:o});let l=r.measureText(t).width;return this.textWidths.set(n,l),l}invalidateTextCache(){this.textWidths.clear();}getBitmap(t,i,s,o,r,n,a,l,k){let B=`${t}|${i}|${s}|${o}|${r}|${n}|${a}|${l}`,A=this.bitmaps.get(B);if(A)return A.accessId=++this.accessCounter,A.bitmap;(n!==this.fontFamily||i!==this.fontSize||a!==this.fontWeight)&&(this.fontFamily=n,this.fontSize=i,this.fontWeight=a,this.cachedFont=bt({fontFamily:n,fontSize:i,fontWeight:a}));let u=this.textWidths.get(`${t}|${n}|${i}|${a}`);if(u===void 0)throw new Error(`Text width not cached for "${t}". Call measure() first.`);let Y=Math.ceil(u)+k*2,z=i+k*2,O=Y*l|0,p=z*l|0,m=k*l,S=p/2,x=new OffscreenCanvas(O,p),b=x.getContext("2d");b.font=`${a} ${i*l}px ${n}`,b.lineWidth=o*l,b.lineJoin="round",b.textBaseline="middle",b.textAlign="left",b.strokeStyle=it(r),b.strokeText(t,m,S),b.fillStyle=it(s),b.fillText(t,m,S);let U=x.transferToImageBitmap();return this.bitmaps.set(B,{bitmap:U,accessId:++this.accessCounter}),this.aliveBitmaps.add(U),this.bitmaps.size>this.maxCache&&this.evictOne(),U}evictOne(){let t="",i=1/0;for(let[s,o]of this.bitmaps)o.accessId<i&&(i=o.accessId,t=s);if(t){let s=this.bitmaps.get(t);s&&(this.aliveBitmaps.delete(s.bitmap),s.bitmap.close(),this.bitmaps.delete(t));}}isAlive(t){return this.aliveBitmaps.has(t)}setMaxCache(t){for(this.maxCache=t;this.bitmaps.size>this.maxCache;)this.evictOne();}setDpr(t){this.dpr!==t&&(this.dpr=t,this.clearBitmaps());}clearBitmaps(){for(let[,t]of this.bitmaps)this.aliveBitmaps.delete(t.bitmap),t.bitmap.close();this.bitmaps.clear();}clearAll(){this.clearBitmaps(),this.textWidths.clear();}get bitmapCount(){return this.bitmaps.size}};var vt,st=class{constructor(t,i,s=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;f(this,vt,t=>{this.stopped||(this.tick(t),this.rafId=requestAnimationFrame(e(this,vt)));});this.frameInterval=1e3/t,this.callback=i,s&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(e(this,vt)));}tick(t){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=t,this.callback(t),true;let i=t-this.lastFrameTime;return i>=this.frameInterval?(this.lastFrameTime=t-i%this.frameInterval,this.callback(t),true):false}setFps(t){this.frameInterval=1e3/t;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};vt=new WeakMap;function W(h,t,i){return h<t?t:h>i?i:h}function Tt(h,t,i,s=0,o=h.length){for(;s<o;){let r=s+o>>1;i(h[r])<=t?s=r+1:o=r;}return s}var rt=class{constructor(){this.pool=[];this.cursor=0;}load(t){this.pool=[...t].sort((i,s)=>i.time-s.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(t){if(this.pool.length===0)return [];let i=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(t<i-200&&(this.cursor=Tt(this.pool,t,r=>(r.time??0)*1e3)),this.cursor>=this.pool.length)return [];let s=Tt(this.pool,t,r=>(r.time??0)*1e3);if(s<=this.cursor)return [];let o=this.pool.slice(this.cursor,s);return this.cursor=s,o}compact(t,i,s,o,r){let n=0;for(let a=0;a<t.length;a++){let l=t[a];if(l.mode===1){if(l.x-=o*s,l.x+l.w<-10){r(l);continue}}else if(i-l.born>=l.duration){r(l);continue}n!==a&&(t[n]=t[a]),n++;}return n}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(t){if(t.length===0)return;let i=new Set;for(let a=0;a<this.pool.length;a++)i.add(this.pool[a].id);let s=[...t].filter(a=>!i.has(a.id)).sort((a,l)=>a.time-l.time);if(s.length===0)return;let o=[],r=0,n=0;for(;r<this.pool.length&&n<s.length;)this.pool[r].time<=s[n].time?(o.push(this.pool[r]),r++):(o.push(s[n]),n++);for(;r<this.pool.length;)o.push(this.pool[r++]);for(;n<s.length;)o.push(s[n++]);this.pool=o;}evictBefore(t){if(this.pool.length===0)return;let i=Tt(this.pool,t*1e3-.1,s=>(s.time??0)*1e3);i!==0&&(this.pool.splice(0,i),this.cursor=Math.max(0,this.cursor-i));}};var zt=new Map;typeof window<"u"&&!window.requestIdleCallback&&(window.requestIdleCallback=function(h,t){let i=t?.timeout,s=Date.now(),o=0,r={didTimeout:false,timeRemaining:()=>Math.max(0,50-(Date.now()-s))};i!=null&&(o=setTimeout(()=>{r.didTimeout=true,s=Date.now(),h(r);},i));let n=requestAnimationFrame(()=>{i!=null&&clearTimeout(o),!r.didTimeout&&(s=Date.now(),h(r));}),a=Date.now()+Math.random();return zt.set(a,{rafId:n,timeoutId:o}),a},window.cancelIdleCallback=function(h){let t=zt.get(h);t&&(cancelAnimationFrame(t.rafId),t.timeoutId&&clearTimeout(t.timeoutId),zt.delete(h));});function Ut(h,t,i,s){let o=0,r=t;function n(a){let l=Math.min(t+i,h.length),k=0;for(;r<l&&(a.timeRemaining()>1||k<5);){let B=h[r];B&&s(B),r++,k++;}r<l&&(o=requestIdleCallback(n,{timeout:2e3}));}return o=requestIdleCallback(n,{timeout:2e3}),()=>cancelIdleCallback(o)}var Et={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var gt,xt,ot,yt,wt,R,J,j,K,X,jt,Xt,Nt,nt=class{constructor(t,i,s,o,r){f(this,X);f(this,gt);f(this,xt);f(this,ot);f(this,yt);f(this,wt);f(this,R,[]);f(this,J,0);f(this,j,null);f(this,K,-1);c(this,gt,t),c(this,xt,Math.max(1,i)),c(this,ot,Math.max(0,s)),c(this,yt,Math.max(.5,o*2.5)),c(this,wt,r);}probe(t,i){if(e(this,K)>=0&&Math.abs(t-e(this,K))>e(this,yt)&&this.reset(),c(this,K,t),e(this,ot)>0){let r=t-e(this,ot);i.evictBefore(r),c(this,R,e(this,R).filter(n=>n.end>r));}if(e(this,j))return;let s=t+e(this,xt),o=C(this,X,jt).call(this,t,s);o&&C(this,X,Xt).call(this,o.start,o.end,i);}reset(){Lt(this,J)._++,c(this,j,null),c(this,R,[]),c(this,K,-1);}destroy(){this.reset();}};gt=new WeakMap,xt=new WeakMap,ot=new WeakMap,yt=new WeakMap,wt=new WeakMap,R=new WeakMap,J=new WeakMap,j=new WeakMap,K=new WeakMap,X=new WeakSet,jt=function(t,i){let s=t;for(let o of e(this,R))if(o.start<=s&&s<o.end){if(s=o.end,s>=i)return null}else if(o.start>s)return {start:s,end:Math.min(o.start,i)};return s<i?{start:s,end:i}:null},Xt=function(t,i,s){let o=++Lt(this,J)._;c(this,j,e(this,gt).fetch(t,i).then(r=>{o===e(this,J)&&(c(this,j,null),r.length>0&&s.add(r),C(this,X,Nt).call(this,{start:t,end:i}));}).catch(r=>{var n;o===e(this,J)&&(c(this,j,null),(n=e(this,wt))==null||n.call(this,r instanceof Error?r:new Error(String(r))));}));},Nt=function(t){e(this,R).push(t),e(this,R).sort((s,o)=>s.start-o.start);let i=[];for(let s of e(this,R)){let o=i[i.length-1];o&&o.end>=s.start?o.end=Math.max(o.end,s.end):i.push({...s});}c(this,R,i);};var g,d,y,D,P,w,ht,V,M,lt,N,Q,Z,mt,Ft,H,Wt,Pt,at,Mt=class{constructor(t){f(this,H);f(this,g,false);f(this,d);f(this,y);f(this,D);f(this,P);f(this,w);f(this,ht);f(this,V);f(this,M,[]);f(this,lt,0);f(this,N,null);f(this,Q);f(this,Z,null);f(this,mt,-1);f(this,Ft,t=>{let i=e(this,Q).position,s=e(this,Q).paused,o=e(this,y).width,r=e(this,y).height;if(!e(this,d).enabled||o===0){e(this,y).clear();return}if(s)return;let n=Math.abs(i-e(this,mt));if(e(this,mt)>=0&&n>e(this,d).seekThreshold){for(let m=0;m<e(this,M).length;m++){let S=e(this,M)[m];S.mode===1?e(this,D).releaseScroll(S.track):S.mode===5?e(this,D).releaseTop(S.track):S.mode===6&&e(this,D).releaseBottom(S.track),e(this,P).release(S);}c(this,M,[]),e(this,y).clear(),e(this,Z)?.reset();}c(this,mt,i);let a=e(this,lt)?Math.min((t-e(this,lt))/1e3,.05):0;c(this,lt,t);let l=o/8*e(this,d).speed,k=Math.max(2,Math.ceil(e(this,d).fontSize*.2)),B=e(this,d).fontSize+e(this,d).padding*2+k,A=i*1e3,u=e(this,V).emitBatch(A);for(let m=0;m<u.length;m++)C(this,H,Wt).call(this,u[m],i,l,B,o,r);let Y=performance.now()/1e3,z=m=>{m.mode===1?e(this,D).releaseScroll(m.track):m.mode===5?e(this,D).releaseTop(m.track):m.mode===6&&e(this,D).releaseBottom(m.track),e(this,P).release(m);};e(this,M).length=e(this,V).compact(e(this,M),Y,a,l,z),e(this,y).clear(),e(this,y).setGlobalAlpha(e(this,d).opacity);let O=e(this,y).devicePixelRatio,p=e(this,d).padding;for(let m=0;m<e(this,M).length;m++){let S=e(this,M)[m],x=S.bmp;if(!x)continue;if(!e(this,w).isAlive(x)){S.bmp=void 0;continue}let b=S.x|0,U=S.y|0,$=x.width,Ht=x.height,Ot=$/O,kt=Ht/O,qt=e(this,y).ctx;S.mode===1?qt.drawImage(x,0,0,$,Ht,b-p,U-kt/2|0,Ot,kt):qt.drawImage(x,0,0,$,Ht,b-Ot/2|0,U-kt/2|0,Ot,kt);}C(this,H,Pt).call(this),e(this,Z)?.probe(i,e(this,V));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");c(this,d,{...Et,...t}),c(this,Q,t.adapter),c(this,y,new Ct(t.container)),e(this,y).setSmoothing(e(this,d).smoothing),c(this,D,new et),c(this,P,new St),c(this,w,new Dt(e(this,d).maxCache)),c(this,V,new rt),t.dataSource&&c(this,Z,new nt(t.dataSource,e(this,d).preBuffer,e(this,d).leadTime,e(this,d).seekThreshold,t.onError)),C(this,H,at).call(this),c(this,ht,new st(e(this,d).fps,e(this,Ft)));}get isDestroyed(){return e(this,g)}load(t){var i;e(this,g)||(e(this,P).releaseAll(e(this,M)),c(this,M,[]),e(this,w).clearAll(),e(this,Z)?.reset(),e(this,V).load(t),(i=e(this,N))==null||i.call(this),c(this,N,null),C(this,H,Pt).call(this));}send(t){if(e(this,g)||!e(this,d).enabled)return;let i=e(this,Q).position,s=e(this,y).width,o=e(this,y).height;if(s===0||o===0)return;let r=s/8*e(this,d).speed,n=Math.max(2,Math.ceil(e(this,d).fontSize*.2)),a=e(this,d).fontSize+e(this,d).padding*2+n,l={...t,time:i};C(this,H,Wt).call(this,l,i,r,a,s,o,true);}clear(){e(this,g)||(e(this,P).releaseAll(e(this,M)),c(this,M,[]),e(this,V).clear(),e(this,w).clearAll(),e(this,y).clear());}resize(){if(e(this,g))return;e(this,y).updateDimensions()&&(e(this,w).setDpr(e(this,y).devicePixelRatio),e(this,w).invalidateTextCache(),C(this,H,at).call(this));}destroy(){var t;e(this,g)||(c(this,g,true),e(this,ht).stop(),(t=e(this,N))==null||t.call(this),e(this,Z)?.destroy(),e(this,P).releaseAll(e(this,M)),c(this,M,[]),e(this,w).clearAll(),e(this,y).destroy());}setEnabled(t){e(this,g)||(e(this,d).enabled=t,t||e(this,y).clear());}setFps(t){e(this,g)||(e(this,d).fps=W(t,1,120),e(this,ht).setFps(e(this,d).fps));}setArea(t){e(this,g)||(e(this,d).area=W(t,0,1),C(this,H,at).call(this));}setOpacity(t){e(this,g)||(e(this,d).opacity=W(t,0,1));}setSpeed(t){e(this,g)||(e(this,d).speed=Math.max(.1,t));}setFontFamily(t){e(this,g)||(e(this,d).fontFamily=t,e(this,w).invalidateTextCache(),e(this,w).clearBitmaps());}setFontSize(t){e(this,g)||(e(this,d).fontSize=W(t,8,128),e(this,w).invalidateTextCache(),e(this,w).clearBitmaps(),C(this,H,at).call(this));}setFontWeight(t){e(this,g)||(e(this,d).fontWeight=t,e(this,w).invalidateTextCache(),e(this,w).clearBitmaps());}setStrokeWidth(t){e(this,g)||(e(this,d).strokeWidth=Math.max(0,t),e(this,w).clearBitmaps());}setStrokeColor(t){e(this,g)||(e(this,d).strokeColor=t&16777215,e(this,w).clearBitmaps());}setPadding(t){e(this,g)||(e(this,d).padding=Math.max(0,t),e(this,w).clearBitmaps(),C(this,H,at).call(this));}setDuration(t){e(this,g)||(e(this,d).duration=Math.max(.5,t));}setOverflow(t){e(this,g)||(e(this,d).overflow=t);}setMaxVisible(t){e(this,g)||(e(this,d).maxVisible=Math.max(0,t));}setMaxCache(t){e(this,g)||(e(this,d).maxCache=Math.max(10,t),e(this,w).setMaxCache(e(this,d).maxCache));}setPreCacheCount(t){e(this,g)||(e(this,d).preCacheCount=Math.max(0,t));}setSmoothing(t){e(this,g)||(e(this,d).smoothing=t,e(this,y).setSmoothing(t));}setWillChange(t){}setUseTextShadow(t){}};g=new WeakMap,d=new WeakMap,y=new WeakMap,D=new WeakMap,P=new WeakMap,w=new WeakMap,ht=new WeakMap,V=new WeakMap,M=new WeakMap,lt=new WeakMap,N=new WeakMap,Q=new WeakMap,Z=new WeakMap,mt=new WeakMap,Ft=new WeakMap,H=new WeakSet,Wt=function(t,i,s,o,r,n,a){let l=t.mode??1,k=t.text??"";if(!k)return;let B=t.color??16777215,A=t.font_size??e(this,d).fontSize,u=e(this,d),Y=e(this,y).ctx,O=e(this,w).measure(k,u.fontFamily,A,u.fontWeight,Y)+u.padding*2,p=A;if(!a&&u.maxVisible>0&&e(this,M).length>=u.maxVisible&&u.overflow==="drop")return;let m=null;if(l===1){if(m=e(this,D).acquireScroll(i,O,s,r),!m){if(u.overflow==="drop"&&!a)return;let b=Math.random()*e(this,D).scrollTrackCount|0;m={track:b,y:(b+.5)*o};}}else if(l===5){if(m=e(this,D).acquireTop(i,u.duration),!m){if(u.overflow==="drop"&&!a)return;let b=Math.random()*e(this,D).topTrackCount|0;m={track:b,y:(b+.5)*o};}}else if(l===6){if(m=e(this,D).acquireBottom(i,u.duration),!m){if(u.overflow==="drop"&&!a)return;let b=Math.random()*e(this,D).bottomTrackCount|0;m={track:b,y:n*u.area-(b+.5)*o};}}else if(m=e(this,D).acquireScroll(i,O,s,r),!m)if(a){let b=Math.random()*e(this,D).scrollTrackCount|0;m={track:b,y:(b+.5)*o};}else return;let S=e(this,w).getBitmap(k,A,B,u.strokeWidth,u.strokeColor,u.fontFamily,u.fontWeight,e(this,y).devicePixelRatio,u.padding),x=e(this,P).acquire();x.id=t.id,x.text=k,x.mode=l,x.color=B,x.fontSize=A,x.x=l===1?r:r/2,x.y=m.y,x.track=m.track,x.w=O,x.h=p,x.born=performance.now()/1e3,x.duration=u.duration,x.bmp=S,e(this,M).push(x);},Pt=function(){if(e(this,N)||e(this,g))return;let{pool:t,cursor:i}=e(this,V).preCacheInfo(),s=e(this,d);c(this,N,Ut(t,i,s.preCacheCount,o=>{let r=o.text??"",n=o.font_size??s.fontSize,a=o.color??16777215;e(this,w).measure(r,s.fontFamily,n,s.fontWeight,e(this,y).ctx);try{e(this,w).getBitmap(r,n,a,s.strokeWidth,s.strokeColor,s.fontFamily,s.fontWeight,e(this,y).devicePixelRatio,s.padding);}catch{}}));},at=function(){let t=e(this,y).height;if(t===0)return;let i=e(this,d),s=Math.max(2,Math.ceil(i.fontSize*.2)),o=i.fontSize+i.padding*2+s;e(this,D).resize(t,i.area,o);};function Zt(h,t){let i=h;return [`-${i}px -${i}px 0 ${t}`,`0px -${i}px 0 ${t}`,`${i}px -${i}px 0 ${t}`,`-${i}px 0px 0 ${t}`,`${i}px 0px 0 ${t}`,`-${i}px ${i}px 0 ${t}`,`0px ${i}px 0 ${t}`,`${i}px ${i}px 0 ${t}`].join(",")}function Gt(h,t,i){return `${i} ${t}px ${h}`}var It=class{constructor(t){this.container=t;let i=document.createElement("div");i.style.position="absolute",i.style.inset="0",i.style.overflow="hidden",i.style.pointerEvents="none",i.style.userSelect="none",t.appendChild(i),this.root=i;}get width(){return this.container.clientWidth}get height(){return this.container.clientHeight}createElement(t){let i=document.createElement("div");return i.style.position="absolute",i.style.left="0",i.style.top="0",i.style.whiteSpace="nowrap",i.style.font=t.font,i.style.color=t.fillColor,i.style.textShadow=t.textShadow,i.style.willChange=t.willChange,i.style.pointerEvents="none",i.style.userSelect="none",i}configureElement(t,i,s){t.textContent=i,t.style.font=s.font,t.style.color=s.fillColor,t.style.textShadow=s.textShadow,t.style.willChange=s.willChange;}positionElement(t,i,s,o,r){let n=Math.round(i),a=Math.round(s-r/2);o===1?t.style.transform=`translate3d(${n}px, ${a}px, 0)`:t.style.transform=`translate3d(${n}px, ${a}px, 0) translateX(-50%)`;}hideElement(t){t.style.display="none";}showElement(t){t.style.display="";}appendElement(t){this.root.appendChild(t);}removeElement(t){t.parentNode===this.root&&this.root.removeChild(t);}destroy(){this.root.remove();}};var At=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():document.createElement("div")}release(t){this.pool.length<512&&(t.style.display="none",t.parentNode&&t.parentNode.removeChild(t),t.style.transform="",t.textContent="",this.pool.push(t));}releaseAll(t){for(let i=0;i<t.length;i++)this.release(t[i]);}get size(){return this.pool.length}};var Vt=null;function Kt(){if(!Vt){let h=document.createElement("canvas");h.width=h.height=1,Vt=h.getContext("2d");}return Vt}function Jt(h,t,i,s){let o=Kt();return o.font=bt({fontFamily:t,fontSize:i,fontWeight:s}),o.measureText(h).width}var T,v,F,E,_,ut,q,I,dt,tt,G,pt,$t,L,_t,ct,Bt=class{constructor(t){f(this,L);f(this,T,false);f(this,v);f(this,F);f(this,E);f(this,_);f(this,ut);f(this,q);f(this,I,[]);f(this,dt,0);f(this,tt);f(this,G,null);f(this,pt,-1);f(this,$t,t=>{let i=e(this,tt).position,s=e(this,tt).paused,o=e(this,F).width,r=e(this,F).height;if(!e(this,v).enabled||o===0||s)return;let n=Math.abs(i-e(this,pt));if(e(this,pt)>=0&&n>e(this,v).seekThreshold){for(let p=0;p<e(this,I).length;p++){let m=e(this,I)[p];m.el&&(e(this,F).removeElement(m.el),e(this,_).release(m.el)),m.mode===1?e(this,E).releaseScroll(m.track):m.mode===5?e(this,E).releaseTop(m.track):m.mode===6&&e(this,E).releaseBottom(m.track);}c(this,I,[]),e(this,G)?.reset();}c(this,pt,i);let a=e(this,dt)?Math.min((t-e(this,dt))/1e3,.05):0;c(this,dt,t);let l=o/8*e(this,v).speed,k=Math.max(2,Math.ceil(e(this,v).fontSize*.2)),B=e(this,v).fontSize+e(this,v).padding*2+k,A=i*1e3,u=e(this,q).emitBatch(A);for(let p=0;p<u.length;p++)C(this,L,_t).call(this,u[p],i,l,B,o,r);let Y=performance.now()/1e3,z=p=>{p.el&&(e(this,F).hideElement(p.el),e(this,F).removeElement(p.el),e(this,_).release(p.el),p.el=void 0),p.mode===1?e(this,E).releaseScroll(p.track):p.mode===5?e(this,E).releaseTop(p.track):p.mode===6&&e(this,E).releaseBottom(p.track);},O=e(this,q).compact(e(this,I),Y,a,l,z);e(this,I).length=O;for(let p=0;p<e(this,I).length;p++){let m=e(this,I)[p];m.el&&e(this,F).positionElement(m.el,m.x,m.y,m.mode,m.h);}e(this,G)?.probe(i,e(this,q));});if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!t.adapter)throw new TypeError("adapter is required");c(this,v,{...Et,...t}),c(this,tt,t.adapter),c(this,F,new It(t.container)),c(this,E,new et),c(this,_,new At),c(this,q,new rt),t.dataSource&&c(this,G,new nt(t.dataSource,e(this,v).preBuffer,e(this,v).leadTime,e(this,v).seekThreshold,t.onError)),C(this,L,ct).call(this),c(this,ut,new st(e(this,v).fps,e(this,$t)));}get isDestroyed(){return e(this,T)}load(t){e(this,T)||(e(this,_).releaseAll(e(this,I).map(i=>i.el).filter(Boolean)),c(this,I,[]),e(this,G)?.reset(),e(this,q).load(t));}send(t){if(e(this,T)||!e(this,v).enabled)return;let i=e(this,tt).position,s=e(this,F).width,o=e(this,F).height;if(s===0||o===0)return;let r=s/8*e(this,v).speed,n=Math.max(2,Math.ceil(e(this,v).fontSize*.2)),a=e(this,v).fontSize+e(this,v).padding*2+n,l={...t,time:i};C(this,L,_t).call(this,l,i,r,a,s,o,true);}clear(){e(this,T)||(e(this,_).releaseAll(e(this,I).map(t=>t.el).filter(Boolean)),c(this,I,[]),e(this,q).clear());}resize(){e(this,T)||e(this,F).width>0&&C(this,L,ct).call(this);}destroy(){e(this,T)||(c(this,T,true),e(this,ut).stop(),e(this,G)?.destroy(),e(this,_).releaseAll(e(this,I).map(t=>t.el).filter(Boolean)),c(this,I,[]),e(this,F).destroy());}setEnabled(t){e(this,T)||(e(this,v).enabled=t,e(this,F).root.style.display=t?"":"none");}setFps(t){e(this,T)||(e(this,v).fps=W(t,1,120),e(this,ut).setFps(e(this,v).fps));}setArea(t){e(this,T)||(e(this,v).area=W(t,0,1),C(this,L,ct).call(this));}setOpacity(t){e(this,T)||(e(this,v).opacity=W(t,0,1),e(this,F).root.style.opacity=String(e(this,v).opacity));}setSpeed(t){e(this,T)||(e(this,v).speed=Math.max(.1,t));}setFontFamily(t){e(this,v).fontFamily=t;}setFontSize(t){e(this,T)||(e(this,v).fontSize=W(t,8,128),C(this,L,ct).call(this));}setFontWeight(t){e(this,v).fontWeight=t;}setStrokeWidth(t){e(this,v).strokeWidth=Math.max(0,t);}setStrokeColor(t){e(this,v).strokeColor=t&16777215;}setPadding(t){e(this,T)||(e(this,v).padding=Math.max(0,t),C(this,L,ct).call(this));}setDuration(t){e(this,v).duration=Math.max(.5,t);}setOverflow(t){e(this,v).overflow=t;}setMaxVisible(t){e(this,v).maxVisible=Math.max(0,t);}setMaxCache(t){}setPreCacheCount(t){}setSmoothing(t){}setWillChange(t){e(this,T)||(e(this,v).willChange=t);}setUseTextShadow(t){e(this,T)||(e(this,v).useTextShadow=t);}};T=new WeakMap,v=new WeakMap,F=new WeakMap,E=new WeakMap,_=new WeakMap,ut=new WeakMap,q=new WeakMap,I=new WeakMap,dt=new WeakMap,tt=new WeakMap,G=new WeakMap,pt=new WeakMap,$t=new WeakMap,L=new WeakSet,_t=function(t,i,s,o,r,n,a){let l=t.mode??1,k=t.text??"";if(!k)return;let B=t.color??16777215,A=t.font_size??e(this,v).fontSize,u=e(this,v),z=Jt(k,u.fontFamily,A,u.fontWeight)+u.padding*2,O=A;if(!a&&u.maxVisible>0&&e(this,I).length>=u.maxVisible&&u.overflow==="drop")return;let p=null;if(l===1){if(p=e(this,E).acquireScroll(i,z,s,r),!p){if(u.overflow==="drop"&&!a)return;let $=Math.random()*e(this,E).scrollTrackCount|0;p={track:$,y:($+.5)*o};}}else if(l===5){if(p=e(this,E).acquireTop(i,u.duration),!p){if(u.overflow==="drop"&&!a)return;let $=Math.random()*e(this,E).topTrackCount|0;p={track:$,y:($+.5)*o};}}else if(l===6){if(p=e(this,E).acquireBottom(i,u.duration),!p){if(u.overflow==="drop"&&!a)return;let $=Math.random()*e(this,E).bottomTrackCount|0;p={track:$,y:n*u.area-($+.5)*o};}}else if(p=e(this,E).acquireScroll(i,z,s,r),!p)if(a){let $=Math.random()*e(this,E).scrollTrackCount|0;p={track:$,y:($+.5)*o};}else return;let m=Gt(u.fontFamily,A,u.fontWeight),S=u.useTextShadow?Zt(u.strokeWidth*.7,it(u.strokeColor)):"none",x=u.willChange?"transform":"auto",b=e(this,_).acquire();b.textContent=k,b.style.font=m,b.style.color=it(B),b.style.textShadow=S,b.style.willChange=x,b.style.position="absolute",b.style.left="0",b.style.top="0",b.style.whiteSpace="nowrap",b.style.pointerEvents="none",b.style.userSelect="none",b.style.display="",b.style.opacity=String(u.opacity),e(this,F).appendElement(b);let U={id:t.id,text:k,mode:l,color:B,fontSize:A,x:l===1?r:r/2,y:p.y,track:p.track,w:z,h:O,born:performance.now()/1e3,duration:u.duration,el:b};e(this,I).push(U);},ct=function(){let t=e(this,F).height;if(t===0)return;let i=e(this,v),s=Math.max(2,Math.ceil(i.fontSize*.2)),o=i.fontSize+i.padding*2+s;e(this,E).resize(t,i.area,o);};function Qt(h,t){if(!(t.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(t.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');switch(h){case "canvas":return new Mt(t);case "dom":return new Bt(t);default:throw new TypeError(`Unknown engine type: "${h}". Use "canvas" or "dom".`)}}export{ft as DanmakuMode,Qt as createEngine};//# sourceMappingURL=index.min.js.map
var It=l=>{throw TypeError(l)};var yt=(l,e,t)=>e.has(l)||It("Cannot "+t);var i=(l,e,t)=>(yt(l,e,"read from private field"),t?t.call(l):e.get(l)),c=(l,e,t)=>e.has(l)?It("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(l):e.set(l,t),d=(l,e,t,r)=>(yt(l,e,"write to private field"),e.set(l,t),t),S=(l,e,t)=>(yt(l,e,"access private method"),t);var xt=(l,e,t,r)=>({set _(s){d(l,e,s);},get _(){return i(l,e,r)}});var st=(r=>(r[r.Scroll=1]="Scroll",r[r.Top=5]="Top",r[r.Bottom=6]="Bottom",r))(st||{});var ot=class{constructor(){this.scrollCount=0;this.scrollFree=[];this.scrollExit=new Float64Array(0);this.topCount=0;this.topFree=[];this.topExit=new Float64Array(0);this.bottomCount=0;this.bottomFree=[];this.bottomExit=new Float64Array(0);this.H=0;this.th=0;this.areaFraction=.75;}resize(e,t,r){this.H=e,this.th=r,this.areaFraction=t;let s=e*t,o=Math.max(1,Math.floor(s/r)),a=Math.max(1,Math.floor(s*.48/r));this.scrollCount=o,this.topCount=a,this.bottomCount=a,this.scrollExit=new Float64Array(o).fill(-1/0),this.topExit=new Float64Array(a).fill(-1/0),this.bottomExit=new Float64Array(a).fill(-1/0),this.scrollFree=Array.from({length:o},(n,h)=>h),this.topFree=Array.from({length:a},(n,h)=>h),this.bottomFree=Array.from({length:a},(n,h)=>h);}acquireScroll(e,t,r,s,o){let a=[];for(;this.scrollFree.length>0;){let h=this.scrollFree.pop();if(this.scrollExit[h]<=e){this.scrollExit[h]=e+(t+o*s/1920)/r;for(let u of a)this.scrollFree.push(u);return {track:h,y:this.scrollY(h)}}a.push(h);}for(let h of a)this.scrollFree.push(h);let n=Math.random()*this.scrollCount|0;for(let h=0;h<this.scrollCount;h++){let u=(n+h)%this.scrollCount;if(this.scrollExit[u]<=e){this.scrollExit[u]=e+(t+o*s/1920)/r;let C=this.scrollFree.indexOf(u);return C!==-1&&this.scrollFree.splice(C,1),{track:u,y:this.scrollY(u)}}}return null}releaseScroll(e){this.scrollExit[e]=-1/0,this.scrollFree.includes(e)||this.scrollFree.push(e);}acquireTop(e,t){let r=[];for(;this.topFree.length>0;){let o=this.topFree.pop();if(this.topExit[o]<=e){this.topExit[o]=e+t;for(let a of r)this.topFree.push(a);return {track:o,y:this.fixedY(o,true)}}r.push(o);}for(let o of r)this.topFree.push(o);let s=Math.random()*this.topCount|0;for(let o=0;o<this.topCount;o++){let a=(s+o)%this.topCount;if(this.topExit[a]<=e){this.topExit[a]=e+t;let n=this.topFree.indexOf(a);return n!==-1&&this.topFree.splice(n,1),{track:a,y:this.fixedY(a,true)}}}return null}releaseTop(e){this.topExit[e]=-1/0,this.topFree.includes(e)||this.topFree.push(e);}acquireBottom(e,t){let r=[];for(;this.bottomFree.length>0;){let o=this.bottomFree.pop();if(this.bottomExit[o]<=e){this.bottomExit[o]=e+t;for(let a of r)this.bottomFree.push(a);return {track:o,y:this.fixedY(o,false)}}r.push(o);}for(let o of r)this.bottomFree.push(o);let s=Math.random()*this.bottomCount|0;for(let o=0;o<this.bottomCount;o++){let a=(s+o)%this.bottomCount;if(this.bottomExit[a]<=e){this.bottomExit[a]=e+t;let n=this.bottomFree.indexOf(a);return n!==-1&&this.bottomFree.splice(n,1),{track:a,y:this.fixedY(a,false)}}}return null}releaseBottom(e){this.bottomExit[e]=-1/0,this.bottomFree.includes(e)||this.bottomFree.push(e);}get scrollTrackCount(){return this.scrollCount}get topTrackCount(){return this.topCount}get bottomTrackCount(){return this.bottomCount}scrollY(e){return (e+.5)*this.th}fixedY(e,t){return t?(e+.5)*this.th:this.H*this.areaFraction-(e+.5)*this.th}};var Z,nt=class{constructor(e,t,r=true){this.rafId=0;this.lastFrameTime=-1;this.stopped=false;c(this,Z,e=>{this.stopped||(this.tick(e),this.rafId=requestAnimationFrame(i(this,Z)));});this.frameInterval=1e3/e,this.callback=t,r&&this.start();}start(){this.rafId!==0||this.stopped||(this.rafId=requestAnimationFrame(i(this,Z)));}tick(e){if(this.stopped)return false;if(this.lastFrameTime<0)return this.lastFrameTime=e,this.callback(e),true;let t=e-this.lastFrameTime;return t>=this.frameInterval?(this.lastFrameTime=e-t%this.frameInterval,this.callback(e),true):false}setFps(e){this.frameInterval=1e3/e;}stop(){this.stopped=true,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0);}};Z=new WeakMap;function J(l,e,t){return l<e?e:l>t?t:l}function at(l,e,t,r=0,s=l.length){for(;r<s;){let o=r+s>>1;t(l[o])<=e?r=o+1:s=o;}return r}var lt=class{constructor(){this.pool=[];this.cursor=0;}load(e){this.pool=[...e].sort((t,r)=>t.time-r.time),this.cursor=0;}clear(){this.pool=[],this.cursor=0;}emitBatch(e){if(this.pool.length===0)return [];let t=this.cursor<this.pool.length?(this.pool[this.cursor]?.time??0)*1e3:1/0;if(e<t-200&&(this.cursor=at(this.pool,e,o=>(o.time??0)*1e3)),this.cursor>=this.pool.length)return [];let r=at(this.pool,e,o=>(o.time??0)*1e3);if(r<=this.cursor)return [];let s=this.pool.slice(this.cursor,r);return this.cursor=r,s}compact(e,t,r,s,o){let a=0;for(let n=0;n<e.length;n++){let h=e[n];if(h.mode===1){if(h.x-=s*r,h.x+h.w<-10){o(h);continue}}else if(t-h.born>=h.duration){o(h);continue}a!==n&&(e[a]=e[n]),a++;}return a}preCacheInfo(){return {pool:this.pool,cursor:this.cursor}}add(e){if(e.length===0)return;let t=new Set;for(let n=0;n<this.pool.length;n++)t.add(this.pool[n].id);let r=[...e].filter(n=>!t.has(n.id)).sort((n,h)=>n.time-h.time);if(r.length===0)return;let s=[],o=0,a=0;for(;o<this.pool.length&&a<r.length;)this.pool[o].time<=r[a].time?(s.push(this.pool[o]),o++):(s.push(r[a]),a++);for(;o<this.pool.length;)s.push(this.pool[o++]);for(;a<r.length;)s.push(r[a++]);this.pool=s;}evictBefore(e){if(this.pool.length===0)return;let t=at(this.pool,e*1e3-.1,r=>(r.time??0)*1e3);t!==0&&(this.pool.splice(0,t),this.cursor=Math.max(0,this.cursor-t));}};var Mt={enabled:true,fps:60,area:.75,fontFamily:"sans-serif",fontSize:25,fontWeight:"bold",opacity:1,padding:4,strokeWidth:1.25,strokeColor:0,scrollGap:96,speed:1,seekThreshold:.2,duration:4,overflow:"drop",maxVisible:0,maxCache:500,preCacheCount:50,smoothing:true,willChange:true,useTextShadow:true,preBuffer:60,leadTime:0};var K,Q,_,tt,et,I,O,W,L,$,Vt,At,Rt,ht=class{constructor(e,t,r,s,o){c(this,$);c(this,K);c(this,Q);c(this,_);c(this,tt);c(this,et);c(this,I,[]);c(this,O,0);c(this,W,null);c(this,L,-1);d(this,K,e),d(this,Q,Math.max(1,t)),d(this,_,Math.max(0,r)),d(this,tt,Math.max(.5,s*2.5)),d(this,et,o);}probe(e,t){if(i(this,L)>=0&&Math.abs(e-i(this,L))>i(this,tt)&&this.reset(),d(this,L,e),i(this,_)>0){let o=e-i(this,_);t.evictBefore(o),d(this,I,i(this,I).filter(a=>a.end>o));}if(i(this,W))return;let r=e+i(this,Q),s=S(this,$,Vt).call(this,e,r);s&&S(this,$,At).call(this,s.start,s.end,t);}reset(){xt(this,O)._++,d(this,W,null),d(this,I,[]),d(this,L,-1);}destroy(){this.reset();}};K=new WeakMap,Q=new WeakMap,_=new WeakMap,tt=new WeakMap,et=new WeakMap,I=new WeakMap,O=new WeakMap,W=new WeakMap,L=new WeakMap,$=new WeakSet,Vt=function(e,t){let r=e;for(let s of i(this,I))if(s.start<=r&&r<s.end){if(r=s.end,r>=t)return null}else if(s.start>r)return {start:r,end:Math.min(s.start,t)};return r<t?{start:r,end:t}:null},At=function(e,t,r){let s=++xt(this,O)._;d(this,W,i(this,K).fetch(e,t).then(o=>{s===i(this,O)&&(d(this,W,null),o.length>0&&r.add(o),S(this,$,Rt).call(this,{start:e,end:t}));}).catch(o=>{var a;s===i(this,O)&&(d(this,W,null),(a=i(this,et))==null||a.call(this,o instanceof Error?o:new Error(String(o))));}));},Rt=function(e){i(this,I).push(e),i(this,I).sort((r,s)=>r.start-s.start);let t=[];for(let r of i(this,I)){let s=t[t.length-1];s&&s.end>=r.start?s.end=Math.max(s.end,r.end):t.push({...r});}d(this,I,t);};var b,m,x,A,G,D,Y,U,z,H,mt,M,kt,q,X=class{constructor(e){c(this,M);c(this,b,false);c(this,m);c(this,x,new ot);c(this,A,new lt);c(this,G);c(this,D,[]);c(this,Y,0);c(this,U,-1);c(this,z);c(this,H,null);c(this,mt,e=>{let t=i(this,z).position,r=i(this,z).paused,s=this.rendererWidth,o=this.rendererHeight;if(!i(this,m).enabled||s===0){this.clearRenderer();return}if(r)return;let a=Math.abs(t-i(this,U));if(i(this,U)>=0&&a>i(this,m).seekThreshold){for(let g=0;g<i(this,D).length;g++){let p=i(this,D)[g];this.releaseVisibleResource(p),p.mode===1?i(this,x).releaseScroll(p.track):p.mode===5?i(this,x).releaseTop(p.track):p.mode===6&&i(this,x).releaseBottom(p.track);}d(this,D,[]),this.clearRenderer(),i(this,H)?.reset();}d(this,U,t);let n=i(this,Y)?Math.min((e-i(this,Y))/1e3,.05):0;d(this,Y,e);let h=s/8*i(this,m).speed,u=Math.max(2,Math.ceil(i(this,m).fontSize*.2)),C=i(this,m).fontSize+i(this,m).padding*2+u,F=t*1e3,f=i(this,A).emitBatch(F);for(let g=0;g<f.length;g++)S(this,M,kt).call(this,f[g],t,h,C,s,o);let R=performance.now()/1e3,T=g=>{this.releaseVisibleResource(g),g.mode===1?i(this,x).releaseScroll(g.track):g.mode===5?i(this,x).releaseTop(g.track):g.mode===6&&i(this,x).releaseBottom(g.track);};i(this,D).length=i(this,A).compact(i(this,D),R,n,h,T),this.drawFrame(s,o),this.onAfterTick(),i(this,H)?.probe(t,i(this,A));});if(!(e.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(!e.adapter)throw new TypeError("adapter is required");d(this,m,{...Mt,...e}),d(this,z,e.adapter),e.dataSource&&d(this,H,new ht(e.dataSource,i(this,m).preBuffer,i(this,m).leadTime,i(this,m).seekThreshold,e.onError)),d(this,G,new nt(i(this,m).fps,i(this,mt)));}onAfterLoad(){}onAfterTick(){}acquireVisibleDanmaku(){return {}}get cfg(){return i(this,m)}get visible(){return i(this,D)}getPreCacheInfo(){return i(this,A).preCacheInfo()}initTracks(){S(this,M,q).call(this);}get isDestroyed(){return i(this,b)}load(e){i(this,b)||(this.releaseAllVisibleResources(),d(this,D,[]),i(this,H)?.reset(),i(this,A).load(e),this.onAfterLoad());}send(e){if(i(this,b)||!i(this,m).enabled)return;let t=i(this,z).position,r=this.rendererWidth,s=this.rendererHeight;if(r===0||s===0)return;let o=r/8*i(this,m).speed,a=Math.max(2,Math.ceil(i(this,m).fontSize*.2)),n=i(this,m).fontSize+i(this,m).padding*2+a,h={...e,time:t};S(this,M,kt).call(this,h,t,o,n,r,s,true);}clear(){i(this,b)||(this.releaseAllVisibleResources(),d(this,D,[]),i(this,A).clear(),this.clearRenderer());}resize(){i(this,b)||this.updateDimensions()&&S(this,M,q).call(this);}destroy(){i(this,b)||(d(this,b,true),i(this,G).stop(),i(this,H)?.destroy(),this.releaseAllVisibleResources(),d(this,D,[]),this.destroyRenderer());}setEnabled(e){i(this,b)||(i(this,m).enabled=e);}setFps(e){i(this,b)||(i(this,m).fps=J(e,1,120),i(this,G).setFps(i(this,m).fps));}setArea(e){i(this,b)||(i(this,m).area=J(e,0,1),S(this,M,q).call(this));}setOpacity(e){i(this,b)||(i(this,m).opacity=J(e,0,1));}setSpeed(e){i(this,b)||(i(this,m).speed=Math.max(.1,e));}setFontFamily(e){i(this,b)||(i(this,m).fontFamily=e);}setFontSize(e){i(this,b)||(i(this,m).fontSize=J(e,8,128),S(this,M,q).call(this));}setFontWeight(e){i(this,b)||(i(this,m).fontWeight=e);}setStrokeWidth(e){i(this,b)||(i(this,m).strokeWidth=Math.max(0,e));}setStrokeColor(e){i(this,b)||(i(this,m).strokeColor=e&16777215);}setPadding(e){i(this,b)||(i(this,m).padding=Math.max(0,e),S(this,M,q).call(this));}setScrollGap(e){i(this,b)||(i(this,m).scrollGap=Math.max(0,e));}setDuration(e){if(!i(this,b)){i(this,m).duration=Math.max(.5,e);for(let t=0;t<i(this,D).length;t++){let r=i(this,D)[t];r.mode!==1&&(r.duration=i(this,m).duration);}}}setOverflow(e){i(this,b)||(i(this,m).overflow=e);}setMaxVisible(e){i(this,b)||(i(this,m).maxVisible=Math.max(0,e));}setMaxCache(e){}setPreCacheCount(e){}setSmoothing(e){}setWillChange(e){}setUseTextShadow(e){}};b=new WeakMap,m=new WeakMap,x=new WeakMap,A=new WeakMap,G=new WeakMap,D=new WeakMap,Y=new WeakMap,U=new WeakMap,z=new WeakMap,H=new WeakMap,mt=new WeakMap,M=new WeakSet,kt=function(e,t,r,s,o,a,n){let h=e.mode??1,u=e.text??"";if(!u)return;let C=e.color??16777215,F=e.font_size??i(this,m).fontSize,f=i(this,m),T=this.measureTextWidth(u,f.fontFamily,F,f.fontWeight)+f.padding*2,g=F;if(!n&&f.maxVisible>0&&i(this,D).length>=f.maxVisible&&f.overflow==="drop")return;let p=null;if(h===1){if(p=i(this,x).acquireScroll(t,T,r,o,f.scrollGap),!p){if(f.overflow==="drop"&&!n)return;let E=Math.random()*i(this,x).scrollTrackCount|0;p={track:E,y:(E+.5)*s};}}else if(h===5){if(p=i(this,x).acquireTop(t,f.duration),!p){if(f.overflow==="drop"&&!n)return;let E=Math.random()*i(this,x).topTrackCount|0;p={track:E,y:(E+.5)*s};}}else if(h===6){if(p=i(this,x).acquireBottom(t,f.duration),!p){if(f.overflow==="drop"&&!n)return;let E=Math.random()*i(this,x).bottomTrackCount|0;p={track:E,y:a*f.area-(E+.5)*s};}}else if(p=i(this,x).acquireScroll(t,T,r,o,f.scrollGap),!p)if(n){let E=Math.random()*i(this,x).scrollTrackCount|0;p={track:E,y:(E+.5)*s};}else return;let k=this.acquireVisibleDanmaku();k.id=e.id,k.text=u,k.mode=h,k.color=C,k.fontSize=F,k.x=h===1?o:o/2,k.y=p.y,k.track=p.track,k.w=T,k.h=g,k.born=performance.now()/1e3,k.duration=f.duration,this.renderDanmaku(k),i(this,D).push(k);},q=function(){let e=this.rendererHeight;if(e===0)return;let t=i(this,m),r=Math.max(2,Math.ceil(t.fontSize*.2)),s=t.fontSize+t.padding*2+r;i(this,x).resize(e,t.area,s);};var ct=class{constructor(e){this.W=0;this.H=0;this.dpr=1;this.container=e;let t=document.createElement("canvas");t.style.position="absolute",t.style.inset="0",t.style.width="100%",t.style.height="100%",t.style.pointerEvents="none",e.appendChild(t),this.canvas=t,this.ctx=t.getContext("2d"),this.updateDimensions();}updateDimensions(){let e=window.devicePixelRatio||1,t=this.container.clientWidth,r=this.container.clientHeight;return t===0||r===0?false:(this.dpr=e,this.W=t,this.H=r,this.canvas.width=t*e,this.canvas.height=r*e,this.canvas.style.width=t+"px",this.canvas.style.height=r+"px",this.ctx.setTransform(e,0,0,e,0,0),true)}get width(){return this.W}get height(){return this.H}get devicePixelRatio(){return this.dpr}clear(){this.ctx.clearRect(0,0,this.W,this.H);}setSmoothing(e){this.ctx.imageSmoothingEnabled=e;}setGlobalAlpha(e){this.ctx.globalAlpha=e;}destroy(){this.canvas.remove();}};var dt=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():{}}release(e){this.pool.length<512&&(e.bmp=void 0,e.el=void 0,this.pool.push(e));}releaseAll(e){for(let t=0;t<e.length;t++)this.release(e[t]);}get size(){return this.pool.length}};function B(l){return l<0||l>16777215||!Number.isFinite(l)?"#000000":"#"+l.toString(16).padStart(6,"0")}function it({fontFamily:l,fontSize:e,fontWeight:t}){return `${t} ${e}px ${l}`}var ut=class{constructor(e=500){this.textWidths=new Map;this.bitmaps=new Map;this.aliveBitmaps=new Set;this.accessCounter=0;this.dpr=1;this.cachedFont="";this.fontFamily="";this.fontSize=0;this.fontWeight="";this.maxCache=e;}measure(e,t,r,s,o){let a=`${e}|${t}|${r}|${s}`,n=this.textWidths.get(a);if(n!==void 0)return n;o.font=it({fontFamily:t,fontSize:r,fontWeight:s});let h=o.measureText(e).width;return this.textWidths.set(a,h),h}invalidateTextCache(){this.textWidths.clear();}getBitmap(e,t,r,s,o,a,n,h,u){let C=`${e}|${t}|${r}|${s}|${o}|${a}|${n}|${h}`,F=this.bitmaps.get(C);if(F)return F.accessId=++this.accessCounter,F.bitmap;(a!==this.fontFamily||t!==this.fontSize||n!==this.fontWeight)&&(this.fontFamily=a,this.fontSize=t,this.fontWeight=n,this.cachedFont=it({fontFamily:a,fontSize:t,fontWeight:n}));let f=this.textWidths.get(`${e}|${a}|${t}|${n}`);if(f===void 0)throw new Error(`Text width not cached for "${e}". Call measure() first.`);let R=Math.ceil(f)+u*2,T=t+u*2,g=R*h|0,p=T*h|0,k=u*h,E=p/2,Tt=new OffscreenCanvas(g,p),V=Tt.getContext("2d");V.font=`${n} ${t*h}px ${a}`,V.lineWidth=s*h,V.lineJoin="round",V.textBaseline="middle",V.textAlign="left",V.strokeStyle=B(o),V.strokeText(e,k,E),V.fillStyle=B(r),V.fillText(e,k,E);let vt=Tt.transferToImageBitmap();return this.bitmaps.set(C,{bitmap:vt,accessId:++this.accessCounter}),this.aliveBitmaps.add(vt),this.bitmaps.size>this.maxCache&&this.evictOne(),vt}evictOne(){let e="",t=1/0;for(let[r,s]of this.bitmaps)s.accessId<t&&(t=s.accessId,e=r);if(e){let r=this.bitmaps.get(e);r&&(this.aliveBitmaps.delete(r.bitmap),r.bitmap.close(),this.bitmaps.delete(e));}}isAlive(e){return this.aliveBitmaps.has(e)}setMaxCache(e){for(this.maxCache=e;this.bitmaps.size>this.maxCache;)this.evictOne();}setDpr(e){this.dpr!==e&&(this.dpr=e,this.clearBitmaps());}clearBitmaps(){for(let[,e]of this.bitmaps)this.aliveBitmaps.delete(e.bitmap),e.bitmap.close();this.bitmaps.clear();}clearAll(){this.clearBitmaps(),this.textWidths.clear();}get bitmapCount(){return this.bitmaps.size}};var Dt=new Map;typeof window<"u"&&!window.requestIdleCallback&&(window.requestIdleCallback=function(l,e){let t=e?.timeout,r=Date.now(),s=0,o={didTimeout:false,timeRemaining:()=>Math.max(0,50-(Date.now()-r))};t!=null&&(s=setTimeout(()=>{o.didTimeout=true,r=Date.now(),l(o);},t));let a=requestAnimationFrame(()=>{t!=null&&clearTimeout(s),!o.didTimeout&&(r=Date.now(),l(o));}),n=Date.now()+Math.random();return Dt.set(n,{rafId:a,timeoutId:s}),n},window.cancelIdleCallback=function(l){let e=Dt.get(l);e&&(cancelAnimationFrame(e.rafId),e.timeoutId&&clearTimeout(e.timeoutId),Dt.delete(l));});function Wt(l,e,t,r){let s=0,o=e;function a(n){let h=Math.min(e+t,l.length),u=0;for(;o<h&&(n.timeRemaining()>1||u<5);){let C=l[o];C&&r(C),o++,u++;}o<h&&(s=requestIdleCallback(a,{timeout:2e3}));}return s=requestIdleCallback(a,{timeout:2e3}),()=>cancelIdleCallback(s)}var v,j,y,P,rt,wt,pt=class extends X{constructor(t){super(t);c(this,rt);c(this,v);c(this,j,new dt);c(this,y);c(this,P,null);d(this,v,new ct(t.container)),i(this,v).setSmoothing(this.cfg.smoothing),d(this,y,new ut(this.cfg.maxCache)),this.initTracks();}get rendererWidth(){return i(this,v).width}get rendererHeight(){return i(this,v).height}clearRenderer(){i(this,v).clear();}destroyRenderer(){i(this,v).destroy();}updateDimensions(){let t=i(this,v).updateDimensions();return t&&(i(this,y).setDpr(i(this,v).devicePixelRatio),i(this,y).invalidateTextCache()),t}measureTextWidth(t,r,s,o){return i(this,y).measure(t,r,s,o,i(this,v).ctx)}renderDanmaku(t){let r=this.cfg;t.bmp=i(this,y).getBitmap(t.text,t.fontSize,t.color,r.strokeWidth,r.strokeColor,r.fontFamily,r.fontWeight,i(this,v).devicePixelRatio,r.padding);}releaseVisibleResource(t){i(this,j).release(t);}releaseAllVisibleResources(){i(this,j).releaseAll(this.visible),i(this,y).clearAll(),i(this,v).clear();}refreshVisibleDanmaku(){let t=i(this,v).ctx,r=this.cfg,s=i(this,v).devicePixelRatio,o=this.visible;for(let a=0;a<o.length;a++){let n=o[a],h=n.fontSize,u=i(this,y).measure(n.text,r.fontFamily,h,r.fontWeight,t);n.w=u+r.padding*2,n.h=h,n.bmp=i(this,y).getBitmap(n.text,h,n.color,r.strokeWidth,r.strokeColor,r.fontFamily,r.fontWeight,s,r.padding);}}drawFrame(t,r){i(this,v).clear(),i(this,v).setGlobalAlpha(this.cfg.opacity);let s=i(this,v).devicePixelRatio,o=this.cfg.padding,a=this.visible;for(let n=0;n<a.length;n++){let h=a[n],u=h.bmp;if(!u)continue;if(!i(this,y).isAlive(u)){h.bmp=void 0;continue}let C=h.x|0,F=h.y|0,f=u.width,R=u.height,T=f/s,g=R/s,p=i(this,v).ctx;h.mode===1?p.drawImage(u,0,0,f,R,C-o,F-g/2|0,T,g):p.drawImage(u,0,0,f,R,C-T/2|0,F-g/2|0,T,g);}}acquireVisibleDanmaku(){return i(this,j).acquire()}onAfterLoad(){var t;(t=i(this,P))==null||t.call(this),d(this,P,null),S(this,rt,wt).call(this);}onAfterTick(){S(this,rt,wt).call(this);}setEnabled(t){super.setEnabled(t),t||i(this,v).clear();}setFontFamily(t){super.setFontFamily(t),i(this,y).invalidateTextCache(),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setFontSize(t){super.setFontSize(t),i(this,y).invalidateTextCache(),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setFontWeight(t){super.setFontWeight(t),i(this,y).invalidateTextCache(),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setStrokeWidth(t){super.setStrokeWidth(t),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setStrokeColor(t){super.setStrokeColor(t),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setPadding(t){super.setPadding(t),i(this,y).clearBitmaps(),this.refreshVisibleDanmaku();}setScrollGap(t){super.setScrollGap(t),this.refreshVisibleDanmaku();}setMaxCache(t){this.isDestroyed||(this.cfg.maxCache=Math.max(10,t),i(this,y).setMaxCache(this.cfg.maxCache));}setPreCacheCount(t){this.isDestroyed||(this.cfg.preCacheCount=Math.max(0,t));}setSmoothing(t){this.isDestroyed||(this.cfg.smoothing=t,i(this,v).setSmoothing(t));}};v=new WeakMap,j=new WeakMap,y=new WeakMap,P=new WeakMap,rt=new WeakSet,wt=function(){if(i(this,P)||this.isDestroyed)return;let{pool:t,cursor:r}=this.getPreCacheInfo(),s=this.cfg;d(this,P,Wt(t,r,s.preCacheCount,o=>{let a=o.text??"",n=o.font_size??s.fontSize,h=o.color??16777215;i(this,y).measure(a,s.fontFamily,n,s.fontWeight,i(this,v).ctx);try{i(this,y).getBitmap(a,n,h,s.strokeWidth,s.strokeColor,s.fontFamily,s.fontWeight,i(this,v).devicePixelRatio,s.padding);}catch{}}));};function Ct(l,e){let t=l;return [`-${t}px -${t}px 0 ${e}`,`0px -${t}px 0 ${e}`,`${t}px -${t}px 0 ${e}`,`-${t}px 0px 0 ${e}`,`${t}px 0px 0 ${e}`,`-${t}px ${t}px 0 ${e}`,`0px ${t}px 0 ${e}`,`${t}px ${t}px 0 ${e}`].join(",")}function St(l,e,t){return `${t} ${e}px ${l}`}var ft=class{constructor(e){this.container=e;let t=document.createElement("div");t.style.position="absolute",t.style.inset="0",t.style.overflow="hidden",t.style.pointerEvents="none",t.style.userSelect="none",e.appendChild(t),this.root=t;}get width(){return this.container.clientWidth}get height(){return this.container.clientHeight}createElement(e){let t=document.createElement("div");return t.style.position="absolute",t.style.left="0",t.style.top="0",t.style.whiteSpace="nowrap",t.style.font=e.font,t.style.color=e.fillColor,t.style.textShadow=e.textShadow,t.style.willChange=e.willChange,t.style.pointerEvents="none",t.style.userSelect="none",t}configureElement(e,t,r){e.textContent=t,e.style.font=r.font,e.style.color=r.fillColor,e.style.textShadow=r.textShadow,e.style.willChange=r.willChange;}positionElement(e,t,r,s,o){let a=Math.round(t),n=Math.round(r-o/2);s===1?e.style.transform=`translate3d(${a}px, ${n}px, 0)`:e.style.transform=`translate3d(${a}px, ${n}px, 0) translateX(-50%)`;}hideElement(e){e.style.display="none";}showElement(e){e.style.display="";}appendElement(e){this.root.appendChild(e);}removeElement(e){e.parentNode===this.root&&this.root.removeChild(e);}destroy(){this.root.remove();}};var bt=class{constructor(){this.pool=[];}acquire(){return this.pool.length>0?this.pool.pop():document.createElement("div")}release(e){this.pool.length<512&&(e.style.display="none",e.parentNode&&e.parentNode.removeChild(e),e.style.transform="",e.textContent="",this.pool.push(e));}releaseAll(e){for(let t=0;t<e.length;t++)this.release(e[t]);}get size(){return this.pool.length}};var Et=null;function $t(){if(!Et){let l=document.createElement("canvas");l.width=l.height=1,Et=l.getContext("2d");}return Et}function Ft(l,e,t,r){let s=$t();return s.font=it({fontFamily:e,fontSize:t,fontWeight:r}),s.measureText(l).width}var w,N,gt=class extends X{constructor(t){super(t);c(this,w);c(this,N,new bt);d(this,w,new ft(t.container)),this.initTracks();}get rendererWidth(){return i(this,w).width}get rendererHeight(){return i(this,w).height}clearRenderer(){}destroyRenderer(){i(this,w).destroy();}updateDimensions(){return i(this,w).width>0}measureTextWidth(t,r,s,o){return Ft(t,r,s,o)}renderDanmaku(t){let r=this.cfg,s=St(r.fontFamily,t.fontSize,r.fontWeight),o=r.useTextShadow?Ct(r.strokeWidth*.7,B(r.strokeColor)):"none",a=r.willChange?"transform":"auto",n=i(this,N).acquire();n.textContent=t.text,n.style.font=s,n.style.color=B(t.color),n.style.textShadow=o,n.style.willChange=a,n.style.position="absolute",n.style.left="0",n.style.top="0",n.style.whiteSpace="nowrap",n.style.pointerEvents="none",n.style.userSelect="none",n.style.display="",n.style.opacity=String(r.opacity),i(this,w).appendElement(n),t.el=n;}releaseVisibleResource(t){t.el&&(i(this,w).hideElement(t.el),i(this,w).removeElement(t.el),i(this,N).release(t.el),t.el=void 0);}releaseAllVisibleResources(){let t=this.visible;for(let r=0;r<t.length;r++){let s=t[r];s.el&&(i(this,w).hideElement(s.el),i(this,w).removeElement(s.el),i(this,N).release(s.el),s.el=void 0);}}refreshVisibleDanmaku(){let t=this.cfg,r=t.useTextShadow?Ct(t.strokeWidth*.7,B(t.strokeColor)):"none",s=t.willChange?"transform":"auto",o=this.visible;for(let a=0;a<o.length;a++){let n=o[a];if(!n.el)continue;let h=n.fontSize;n.el.style.font=St(t.fontFamily,h,t.fontWeight),n.el.style.color=B(n.color),n.el.style.textShadow=r,n.el.style.willChange=s,n.el.style.opacity=String(t.opacity),n.w=Ft(n.text,t.fontFamily,h,t.fontWeight)+t.padding*2,n.fontSize=t.fontSize;}}drawFrame(t,r){let s=this.visible;for(let o=0;o<s.length;o++){let a=s[o];a.el&&i(this,w).positionElement(a.el,a.x,a.y,a.mode,a.h);}}setEnabled(t){super.setEnabled(t),i(this,w).root.style.display=t?"":"none";}setOpacity(t){super.setOpacity(t),i(this,w).root.style.opacity=String(this.cfg.opacity);let r=this.visible;for(let s=0;s<r.length;s++){let o=r[s];o.el&&(o.el.style.opacity=String(this.cfg.opacity));}}setFontFamily(t){super.setFontFamily(t),this.refreshVisibleDanmaku();}setFontSize(t){super.setFontSize(t),this.refreshVisibleDanmaku();}setFontWeight(t){super.setFontWeight(t),this.refreshVisibleDanmaku();}setStrokeWidth(t){super.setStrokeWidth(t),this.refreshVisibleDanmaku();}setStrokeColor(t){super.setStrokeColor(t),this.refreshVisibleDanmaku();}setPadding(t){super.setPadding(t),this.refreshVisibleDanmaku();}setScrollGap(t){super.setScrollGap(t),this.refreshVisibleDanmaku();}setWillChange(t){this.isDestroyed||(this.cfg.willChange=t,this.refreshVisibleDanmaku());}setUseTextShadow(t){this.isDestroyed||(this.cfg.useTextShadow=t,this.refreshVisibleDanmaku());}};w=new WeakMap,N=new WeakMap;function Ht(l,e){if(!(e.container instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");if(e.container instanceof HTMLVideoElement)throw new TypeError('container cannot be a <video> element. Video uses a native rendering surface that hides child elements. Wrap the video in a <div> and use that as the container. Example: <div style="position:relative"><video .../><div id="overlay"></div></div>');switch(l){case "canvas":return new pt(e);case "dom":return new gt(e);default:throw new TypeError(`Unknown engine type: "${l}". Use "canvas" or "dom".`)}}export{st as DanmakuMode,Ht as createEngine};//# sourceMappingURL=index.min.js.map
//# sourceMappingURL=index.min.js.map
{
"name": "danmaku-lite",
"version": "0.2.2",
"version": "0.2.3",
"description": "Framework-agnostic, player-agnostic danmaku (bullet chat) rendering engine with dual Canvas/DOM backends",

@@ -5,0 +5,0 @@ "type": "module",

+32
-17

@@ -1,3 +0,9 @@

# danmaku-lite
# Danmaku Lite
[![npm version](https://img.shields.io/npm/v/danmaku-lite?color=58a6ff)](https://www.npmjs.com/package/danmaku-lite)
[![minzip size](https://img.shields.io/bundlephobia/minzip/danmaku-lite)](https://bundlephobia.com/package/danmaku-lite)
[![license](https://img.shields.io/npm/l/danmaku-lite)](LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178c6?logo=typescript)](https://www.typescriptlang.org/)
[![ESM only](https://img.shields.io/badge/ESM-only-f7df1e?logo=javascript)](https://nodejs.org/api/esm.html)
Framework-agnostic, player-agnostic danmaku (bullet chat / 弹幕) rendering engine with dual Canvas/DOM backends. Zero dependencies. ESM only.

@@ -10,6 +16,6 @@

- **Dual engine** — Canvas 2D (high performance, 500+ concurrent danmaku) or DOM (simple, CSS-based)
- **24 configurable parameters** — font family, stroke, speed, frame rate, area, overflow, and more
- **25 configurable parameters** — font, stroke, speed, scroll gap, frame rate, area, overflow, and more
- **HiDPI** — automatic devicePixelRatio scaling on Canvas
- **O(1) track allocation** — free-track stacks with random-rotation fallback for even distribution
- **Gap-based track reuse** — tracks free up based on horizontal spacing, allowing dense danmaku
- **Configurable scroll gap** — reference-width-based gap between scroll danmaku, scaled proportionally to container
- **ImageBitmap GPU cache** — pre-rendered bitmaps with LRU eviction + alive-set leak guard

@@ -21,10 +27,15 @@ - **Seek-safe** — automatic cursor rewind on backward seeks, visible cleanup on position jumps

## Install
## Quick Start
### Install
```bash
#npm
npm install danmaku-lite
# pnpm
pnpm add danmaku-lite
# yarn
yarn add danmaku-lite
```
## Quick Start
### Static Loading (VOD / local playback)

@@ -130,2 +141,3 @@

| `padding` | `number` | `4` | Canvas — text bitmap padding (px) |
| `scrollGap` | `number` | `96` | Both — scroll danmaku gap at reference width 1920px, scaled proportionally |
| `strokeWidth` | `number` | `1.25` | Both — outline width (px) |

@@ -171,3 +183,3 @@ | `strokeColor` | `number` | `0x000000` | Both — outline color (0xRRGGBB) |

`setEnabled` `setFps` `setArea` `setOpacity` `setSpeed` `setFontFamily` `setFontSize` `setFontWeight` `setStrokeWidth` `setStrokeColor` `setPadding` `setDuration` `setOverflow` `setMaxVisible` `setMaxCache` `setPreCacheCount` `setSmoothing` `setWillChange` `setUseTextShadow`
`setEnabled` `setFps` `setArea` `setOpacity` `setSpeed` `setFontFamily` `setFontSize` `setFontWeight` `setStrokeWidth` `setStrokeColor` `setPadding` `setScrollGap` `setDuration` `setOverflow` `setMaxVisible` `setMaxCache` `setPreCacheCount` `setSmoothing` `setWillChange` `setUseTextShadow`

@@ -235,2 +247,5 @@ ### `DanmakuItem`

## Tree-shakeable Entry Points
![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/danmaku-lite?label=full)
![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/danmaku-lite%2Fcanvas?label=canvas)
![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/danmaku-lite%2Fdom?label=dom)

@@ -240,9 +255,9 @@ Import only the engine you need for a smaller bundle:

```typescript
// Full (both engines) — 26.0 KB min
// Full (both engines)
import { createEngine } from 'danmaku-lite'
// Canvas only — 18.4 KB min (no DOM code)
// Canvas only
import { createEngine } from 'danmaku-lite/canvas'
// DOM only — 15.4 KB min (no Canvas / OffscreenCanvas code)
// DOM only
import { createEngine } from 'danmaku-lite/dom'

@@ -257,9 +272,9 @@ ```

dist/
index.js 58.0 KB ESM full (unminified + sourcemap)
index.min.js 26.0 KB ESM full (minified + sourcemap)
canvas.js 41.3 KB ESM canvas-only (unminified + sourcemap)
canvas.min.js 18.4 KB ESM canvas-only (minified + sourcemap)
dom.js 34.2 KB ESM dom-only (unminified + sourcemap)
dom.min.js 15.4 KB ESM dom-only (minified + sourcemap)
index.d.ts 6.8 KB TypeScript declarations
index.js ESM full (unminified + sourcemap)
index.min.js ESM full (minified + sourcemap)
canvas.js ESM canvas-only (unminified + sourcemap)
canvas.min.js ESM canvas-only (minified + sourcemap)
dom.js ESM dom-only (unminified + sourcemap)
dom.min.js ESM dom-only (minified + sourcemap)
index.d.ts TypeScript declarations
```

@@ -266,0 +281,0 @@

/** Bridge between the danmaku engine and the host media player. */
interface PlayerAdapter {
/** Current playback position in seconds. Read every frame. */
readonly position: number;
/** Whether playback is currently paused. Read every frame. */
readonly paused: boolean;
/** Total media duration in seconds. Optional (e.g. live streams). */
readonly duration?: number;
}
/** Danmaku display mode constants (matches Bilibili convention). */
declare const enum DanmakuMode {
/** Right-to-left scrolling (standard) */
Scroll = 1,
/** Top-center fixed */
Top = 5,
/** Bottom-center fixed */
Bottom = 6
}
interface DanmakuItem {
/** Unique identifier. Used for deduplication on load(). */
id: number | string;
/** Display text. Plain string — no HTML. */
text: string;
/** Emission time in seconds (media time, not wall time). */
time: number;
/** Display mode. @see DanmakuMode */
mode: DanmakuMode;
/** 24-bit RGB color (e.g. 0xFFFFFF). */
color: number;
/** Font size in CSS pixels for this item. Overrides engine default if set. */
font_size?: number;
}
/**
* Adapter for streaming danmaku data from a remote source.
* The host application provides a fetch implementation that
* calls their backend API or reads from local storage.
*/
interface DataSourceAdapter {
/**
* Fetch danmaku items for a given time range.
*
* @param start - Start time in seconds (inclusive)
* @param end - End time in seconds (exclusive). May be Infinity
* for live streaming where the end is unknown.
* @returns Promise resolving to the danmaku items in this range.
* Items do NOT need to be sorted — the engine sorts them.
* May be empty if no items exist in this range.
*/
fetch(start: number, end: number): Promise<DanmakuItem[]>;
}
type EngineType = 'canvas' | 'dom';
type OverflowStrategy = 'drop' | 'none';
interface DanmakuOptions {
/** The DOM element the engine renders into. Must have non-zero dimensions. */
container: HTMLElement;
/** Adapter bridging the engine to the host media player. */
adapter: PlayerAdapter;
/** Whether rendering is enabled. When false, loop runs but nothing is drawn. Default: true */
enabled?: boolean;
/** Target frames per second for the render loop. Default: 60 */
fps?: number;
/** Fraction of container height used for danmaku (0–1). Default: 0.75 */
area?: number;
/** CSS font-family string. Default: 'sans-serif' */
fontFamily?: string;
/** Base font size in CSS pixels. Individual items can override via font_size. Default: 25 */
fontSize?: number;
/** CSS font-weight value. Default: 'bold' */
fontWeight?: string;
/** Global opacity for all danmaku (0–1). Default: 1.0 */
opacity?: number;
/** Text bitmap padding in CSS pixels. Affects horizontal spacing. Default: 4 */
padding?: number;
/** Text outline stroke width in CSS pixels. Default: 1.25 */
strokeWidth?: number;
/** Stroke color as 0xRRGGBB. Default: 0x000000 (black) */
strokeColor?: number;
/** Minimum position jump (seconds) that triggers seek handling. Default: 0.2 */
seekThreshold?: number;
/** Playback speed multiplier. Affects scroll velocity. Default: 1.0 */
speed?: number;
/** Fixed danmaku (mode 5/6) display duration in seconds. Default: 4 */
duration?: number;
/** Behavior when no free track is available. 'drop' discards silently, 'none' forces emission. Default: 'drop' */
overflow?: OverflowStrategy;
/** Maximum simultaneously visible danmaku. 0 = unlimited. Default: 0 */
maxVisible?: number;
/** Maximum number of cached ImageBitmap objects. Default: 500 */
maxCache?: number;
/** Number of items to pre-cache ahead of playback position. Default: 50 */
preCacheCount?: number;
/** Enable imageSmoothingEnabled on the canvas context. Default: true */
smoothing?: boolean;
/** Add will-change: transform to danmaku elements. Disable to reduce GPU memory. Default: true */
willChange?: boolean;
/** Use text-shadow multi-directional offset to simulate stroke. Disable for plain text. Default: true */
useTextShadow?: boolean;
/** Called when a streaming fetch error occurs. If not set, errors are silently retried. */
onError?: (error: Error) => void;
/**
* Adapter for streaming danmaku data from a backend.
* When provided, the engine manages data fetching automatically.
* When omitted, the consumer must call load() explicitly.
*/
dataSource?: DataSourceAdapter;
/**
* Seconds of danmaku data to pre-buffer ahead of playback position.
* Only used when dataSource is set. Default: 60
*/
preBuffer?: number;
/**
* Seconds of danmaku data to retain behind playback position.
* Data older than (position - leadTime) is evicted from memory.
* Default: 0 (keep all). Set to >0 for memory-constrained long sessions (e.g. live streaming).
*/
leadTime?: number;
}
/** Contract fulfilled by both CanvasEngine and DOMEngine. */
interface DanmakuEngine {
/** Load (replace) the entire danmaku list. Sorted by time internally. */
load(items: readonly DanmakuItem[]): void;
/** Remove all loaded danmaku and clear visible elements. */
clear(): void;
/** Recalculate dimensions after container resize. Consumer must call this. */
resize(): void;
/** Permanently destroy the engine. Frees all resources. Idempotent. */
destroy(): void;
/** Whether destroy() has been called. */
readonly isDestroyed: boolean;
setEnabled(v: boolean): void;
setFps(v: number): void;
setArea(v: number): void;
setOpacity(v: number): void;
setSpeed(v: number): void;
setFontFamily(v: string): void;
setFontSize(v: number): void;
setFontWeight(v: string): void;
setStrokeWidth(v: number): void;
setStrokeColor(v: number): void;
setPadding(v: number): void;
setDuration(v: number): void;
setOverflow(v: OverflowStrategy): void;
setMaxVisible(v: number): void;
setMaxCache(v: number): void;
setPreCacheCount(v: number): void;
setSmoothing(v: boolean): void;
setWillChange(v: boolean): void;
setUseTextShadow(v: boolean): void;
/**
* Immediately display a single danmaku at the current playback position.
* Bypasses the scheduler — the item is rendered regardless of its time field.
* Always shows (skips maxVisible and overflow checks).
* Use for user-sent messages or real-time notifications on send success.
*/
send(item: DanmakuItem): void;
}
export { type DanmakuOptions as D, type EngineType as E, type OverflowStrategy as O, type PlayerAdapter as P, type DanmakuEngine as a, type DanmakuItem as b, DanmakuMode as c, type DataSourceAdapter as d };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display