kinetic-slider
Version:
A WebGL-powered kinetic slider component using PIXI.js
955 lines (952 loc) • 29.9 kB
JavaScript
import { ShaderResourceManager } from './ShaderResourceManager.js';
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
class ResourceManager {
/**
* Creates a new ResourceManager instance
*
* @param componentId - Unique identifier for this component instance
* @param options - Configuration options
*/
constructor(componentId, options = {}) {
// Resource collections
__publicField(this, "textures", /* @__PURE__ */ new Map());
__publicField(this, "filters", /* @__PURE__ */ new Set());
__publicField(this, "displayObjects", /* @__PURE__ */ new Set());
__publicField(this, "pixiApps", /* @__PURE__ */ new Set());
__publicField(this, "animations", /* @__PURE__ */ new Set());
// Event listener tracking with improved nesting
__publicField(this, "listeners", /* @__PURE__ */ new Map());
// Timer tracking
__publicField(this, "timeouts", /* @__PURE__ */ new Set());
__publicField(this, "intervals", /* @__PURE__ */ new Set());
// Manager state
__publicField(this, "disposed", false);
__publicField(this, "unmounting", false);
__publicField(this, "componentId");
__publicField(this, "options");
// Performance metrics (optional)
__publicField(this, "metrics", null);
__publicField(this, "autoCleanupTimer", null);
// Shader resource manager
__publicField(this, "shaderManager", null);
this.componentId = componentId;
this.options = {
logLevel: options.logLevel || "warn",
enableMetrics: options.enableMetrics || false,
autoCleanupInterval: options.autoCleanupInterval || null,
enableShaderPooling: options.enableShaderPooling !== false
// Enable by default
};
if (this.options.enableMetrics) {
this.metrics = {
operations: {},
batchStats: {
textures: this.createEmptyBatchStats(),
filters: this.createEmptyBatchStats(),
displayObjects: this.createEmptyBatchStats(),
animations: this.createEmptyBatchStats()
}
};
}
if (this.options.enableShaderPooling) {
this.shaderManager = ShaderResourceManager.getInstance({
debug: this.options.logLevel === "debug",
enableMetrics: this.options.enableMetrics
});
this.log("info", "Shader pooling enabled");
}
this.log("info", `ResourceManager initialized`);
this.setupAutoCleanup();
}
/**
* Creates an empty batch statistics object
*/
createEmptyBatchStats() {
return {
totalBatches: 0,
totalItems: 0,
averageBatchSize: 0,
largestBatch: 0
};
}
/**
* Set up automatic cleanup interval
*/
setupAutoCleanup() {
if (this.options.autoCleanupInterval) {
this.autoCleanupTimer = setInterval(() => {
this.performAutoCleanup();
}, this.options.autoCleanupInterval);
}
}
/**
* Perform automatic cleanup of unused resources
*/
performAutoCleanup() {
if (this.disposed || this.unmounting) return;
this.log("debug", "Performing automatic resource cleanup...");
let texturesReleased = 0;
this.textures.forEach((entry, url) => {
if (entry.refCount <= 0) {
this.releaseTexture(url);
texturesReleased++;
}
});
let animationsReleased = 0;
this.animations.forEach((animation) => {
if (animation.isActive() === false) {
animation.kill();
this.animations.delete(animation);
animationsReleased++;
}
});
this.log("debug", `Auto cleanup complete: ${texturesReleased} textures and ${animationsReleased} animations released`);
}
/**
* Log a message with the appropriate level
*
* @param level - Log level
* @param message - Log message
* @param data - Optional data to log
*/
log(level, message, data) {
const logLevels = {
"error": 0,
"warn": 1,
"info": 2,
"debug": 3
};
if (logLevels[level] <= logLevels[this.options.logLevel || "warn"]) {
const logMessage = `[ResourceManager:${this.componentId}] ${message}`;
switch (level) {
case "error":
console.error(logMessage, data);
break;
case "warn":
console.warn(logMessage, data);
break;
case "info":
console.info(logMessage, data);
break;
case "debug":
console.debug(logMessage, data);
break;
}
}
}
/**
* Records performance metric for an operation
*
* @param name - Operation name
* @param startTime - Start time of the operation
*/
recordMetric(name, startTime) {
if (!this.metrics) return;
const endTime = performance.now();
const duration = endTime - startTime;
if (!this.metrics.operations[name]) {
this.metrics.operations[name] = {
count: 0,
totalTime: 0,
averageTime: 0
};
}
const op = this.metrics.operations[name];
op.count++;
op.totalTime += duration;
op.averageTime = op.totalTime / op.count;
}
/**
* Update batch statistics
*
* @param type - Resource type
* @param batchSize - Size of the batch
*/
updateBatchStats(type, batchSize) {
if (!this.metrics) return;
const stats = this.metrics.batchStats[type];
stats.totalBatches++;
stats.totalItems += batchSize;
stats.averageBatchSize = stats.totalItems / stats.totalBatches;
stats.largestBatch = Math.max(stats.largestBatch, batchSize);
}
/**
* Mark component as unmounting to prevent new resource allocations
*/
markUnmounting() {
this.unmounting = true;
this.log("info", "Component marked as unmounting");
}
/**
* Check if the resource manager is active and can allocate resources
*/
isActive() {
return !this.unmounting && !this.disposed;
}
// ===== FILTER CONTROL METHODS =====
/**
* Safely disable a filter to ensure it has no visible effect
*
* @param filter - Filter to disable
*/
disableFilter(filter) {
try {
if ("enabled" in filter && typeof filter.enabled === "boolean") {
filter.enabled = false;
}
if ("alpha" in filter && typeof filter.alpha === "number") {
filter.alpha = 0;
}
if ("strength" in filter && typeof filter.strength === "number") {
filter.strength = 0;
}
if ("scale" in filter) {
const scale = filter.scale;
if (scale && typeof scale.x === "number" && typeof scale.y === "number") {
scale.x = 0;
scale.y = 0;
} else if (typeof scale === "number") {
filter.scale = 0;
}
}
if ("blur" in filter && typeof filter.blur === "number") {
filter.blur = 0;
}
} catch (error) {
this.log("debug", "Error disabling filter", error);
}
}
/**
* Disable all filters on a display object
*
* @param displayObject - The display object whose filters should be disabled
*/
disableFiltersOnObject(displayObject) {
if (!displayObject.filters) return;
try {
if (Array.isArray(displayObject.filters)) {
displayObject.filters.forEach((filter) => {
if (filter) this.disableFilter(filter);
});
} else if (displayObject.filters) {
this.disableFilter(displayObject.filters);
}
this.log("debug", "Disabled filters on display object");
} catch (error) {
this.log("warn", "Error disabling filters on object", error);
}
}
/**
* Initialize a filter in a disabled state
* This ensures the filter has no effect when first created
*
* @param filter - Filter to initialize
* @returns The initialized filter
*/
initializeFilterDisabled(filter) {
this.disableFilter(filter);
return filter;
}
/**
* Batch initialize and disable filters
*
* @param filters - Array of filters to initialize disabled
* @returns The array of initialized filters
*/
initializeFilterBatchDisabled(filters) {
filters.forEach((filter) => this.disableFilter(filter));
return filters;
}
/**
* Track a filter
*
* @param filter - Filter to track
* @returns The filter for chaining
*/
trackFilter(filter) {
if (!this.isActive()) return filter;
const startTime = this.metrics ? performance.now() : 0;
this.filters.add(filter);
if (this.shaderManager) {
this.log("debug", `Filter registered with shader manager`);
}
if (this.metrics) {
this.recordMetric("trackFilter", startTime);
this.updateBatchStats("filters", 1);
}
return filter;
}
/**
* Dispose of a single filter
*/
disposeFilter(filter) {
const startTime = this.metrics ? performance.now() : 0;
try {
this.disableFilter(filter);
if (this.shaderManager) {
this.shaderManager.releaseShader(filter);
}
filter.destroy();
} catch (error) {
this.log("debug", `Using fallback disposal for filter`, error);
this.disableFilter(filter);
}
this.filters.delete(filter);
if (this.metrics) {
this.recordMetric("disposeFilter", startTime);
}
}
/**
* Get shader manager instance
*
* @returns The shader manager instance or null if not enabled
*/
getShaderManager() {
return this.shaderManager;
}
// ===== BATCH TRACKING METHODS =====
/**
* Track multiple textures at once
*
* @param textures - Map of URL to texture
* @returns The same map for chaining
*/
trackTextureBatch(textures) {
if (!this.isActive()) return textures;
const startTime = this.metrics ? performance.now() : 0;
textures.forEach((texture, url) => {
const entry = this.textures.get(url);
if (entry) {
entry.refCount++;
entry.lastUsed = Date.now();
} else {
this.textures.set(url, {
resource: texture,
refCount: 1,
lastUsed: Date.now()
});
}
});
if (this.metrics) {
this.recordMetric("trackTextureBatch", startTime);
this.updateBatchStats("textures", textures.size);
}
this.log("debug", `Tracked ${textures.size} textures in batch`);
return textures;
}
/**
* Track multiple filters at once
*
* @param filters - Array of filters to track
* @returns The same array for chaining
*/
trackFilterBatch(filters) {
if (!this.isActive()) return filters;
const startTime = this.metrics ? performance.now() : 0;
filters.forEach((filter) => this.filters.add(filter));
if (this.metrics) {
this.recordMetric("trackFilterBatch", startTime);
this.updateBatchStats("filters", filters.length);
}
this.log("debug", `Tracked ${filters.length} filters in batch`);
return filters;
}
/**
* Track multiple display objects at once
*
* @param objects - Array of display objects to track
* @returns The same array for chaining
*/
trackDisplayObjectBatch(objects) {
if (!this.isActive()) return objects;
const startTime = this.metrics ? performance.now() : 0;
objects.forEach((object) => this.displayObjects.add(object));
if (this.metrics) {
this.recordMetric("trackDisplayObjectBatch", startTime);
this.updateBatchStats("displayObjects", objects.length);
}
this.log("debug", `Tracked ${objects.length} display objects in batch`);
return objects;
}
/**
* Track multiple animations at once
*
* @param animations - Array of animations to track
* @returns The same array for chaining
*/
trackAnimationBatch(animations) {
if (!this.isActive()) return animations;
const startTime = this.metrics ? performance.now() : 0;
animations.forEach((animation) => this.animations.add(animation));
if (this.metrics) {
this.recordMetric("trackAnimationBatch", startTime);
this.updateBatchStats("animations", animations.length);
}
this.log("debug", `Tracked ${animations.length} animations in batch`);
return animations;
}
/**
* Track event listeners in batch
*
* @param element - DOM element
* @param listeners - Map of event types to callbacks
*/
addEventListenerBatch(element, listeners) {
if (!this.isActive()) return;
const startTime = this.metrics ? performance.now() : 0;
let count = 0;
if (!this.listeners.has(element)) {
this.listeners.set(element, /* @__PURE__ */ new Map());
}
const elementListeners = this.listeners.get(element);
listeners.forEach((callbacks, eventType) => {
if (!elementListeners.has(eventType)) {
elementListeners.set(eventType, /* @__PURE__ */ new Set());
}
const callbackSet = elementListeners.get(eventType);
callbacks.forEach((callback) => {
callbackSet.add(callback);
element.addEventListener(eventType, callback);
count++;
});
});
if (this.metrics) {
this.recordMetric("addEventListenerBatch", startTime);
}
this.log("debug", `Added ${count} event listeners in batch`);
}
// ===== INDIVIDUAL TRACKING METHODS =====
/**
* Track a GSAP animation
*
* @param animation - Animation to track
* @returns The animation for chaining
*/
trackAnimation(animation) {
if (!this.isActive()) {
animation.kill();
return animation;
}
const startTime = this.metrics ? performance.now() : 0;
this.animations.add(animation);
if (this.metrics) {
this.recordMetric("trackAnimation", startTime);
this.updateBatchStats("animations", 1);
}
return animation;
}
/**
* Track a texture
*
* @param url - Texture URL
* @param texture - Texture to track
* @returns The texture for chaining
*/
trackTexture(url, texture) {
if (!this.isActive()) return texture;
const startTime = this.metrics ? performance.now() : 0;
const entry = this.textures.get(url);
if (entry) {
entry.refCount++;
entry.lastUsed = Date.now();
} else {
this.textures.set(url, {
resource: texture,
refCount: 1,
lastUsed: Date.now()
});
}
if (this.metrics) {
this.recordMetric("trackTexture", startTime);
this.updateBatchStats("textures", 1);
}
return texture;
}
/**
* Release a texture, destroying it when no longer referenced
*/
releaseTexture(url) {
const entry = this.textures.get(url);
if (!entry) return;
const startTime = this.metrics ? performance.now() : 0;
entry.refCount--;
if (entry.refCount <= 0) {
try {
entry.resource.destroy(true);
this.textures.delete(url);
this.log("debug", `Destroyed texture: ${url}`);
} catch (error) {
this.log("warn", `Failed to destroy texture: ${url}`, error);
}
}
if (this.metrics) {
this.recordMetric("releaseTexture", startTime);
}
}
/**
* Track a PIXI Application
*
* @param app - Application to track
* @returns The application for chaining
*/
trackPixiApp(app) {
if (!this.isActive()) {
this.disposePixiApp(app);
return app;
}
const startTime = this.metrics ? performance.now() : 0;
this.pixiApps.add(app);
if (this.metrics) {
this.recordMetric("trackPixiApp", startTime);
}
this.log("info", "Tracking PIXI application");
return app;
}
/**
* Dispose of a PIXI Application
*/
disposePixiApp(app) {
const startTime = this.metrics ? performance.now() : 0;
try {
app.stop();
if (app.canvas instanceof HTMLCanvasElement) {
app.canvas.remove();
}
app.destroy(true, { children: true });
this.log("info", "PIXI application destroyed");
} catch (error) {
this.log("warn", "Error disposing PIXI application", error);
}
this.pixiApps.delete(app);
if (this.metrics) {
this.recordMetric("disposePixiApp", startTime);
}
}
/**
* Track a display object
*
* @param displayObject - Display object to track
* @returns The display object for chaining
*/
trackDisplayObject(displayObject) {
if (!this.isActive()) return displayObject;
const startTime = this.metrics ? performance.now() : 0;
this.displayObjects.add(displayObject);
if (this.metrics) {
this.recordMetric("trackDisplayObject", startTime);
this.updateBatchStats("displayObjects", 1);
}
return displayObject;
}
/**
* Dispose of a display object
*/
disposeDisplayObject(displayObject) {
const startTime = this.metrics ? performance.now() : 0;
try {
if (displayObject.parent) {
displayObject.parent.removeChild(displayObject);
}
this.disableFiltersOnObject(displayObject);
if (displayObject.filters) {
if (Array.isArray(displayObject.filters)) {
displayObject.filters.forEach((filter) => {
this.disposeFilter(filter);
});
} else {
this.disposeFilter(displayObject.filters);
}
displayObject.filters = [];
}
displayObject.destroy({
children: true,
texture: false
});
} catch (error) {
this.log("warn", "Error disposing display object", error);
}
this.displayObjects.delete(displayObject);
if (this.metrics) {
this.recordMetric("disposeDisplayObject", startTime);
}
}
/**
* Add an event listener with tracking
*/
addEventListener(element, eventType, callback) {
if (!this.isActive()) return;
const startTime = this.metrics ? performance.now() : 0;
if (!this.listeners.has(element)) {
this.listeners.set(element, /* @__PURE__ */ new Map());
}
const elementListeners = this.listeners.get(element);
if (!elementListeners.has(eventType)) {
elementListeners.set(eventType, /* @__PURE__ */ new Set());
}
const callbacks = elementListeners.get(eventType);
callbacks.add(callback);
element.addEventListener(eventType, callback);
if (this.metrics) {
this.recordMetric("addEventListener", startTime);
}
}
/**
* Remove all event listeners
*/
removeAllEventListeners() {
const startTime = this.metrics ? performance.now() : 0;
let count = 0;
this.listeners.forEach((eventMap, element) => {
eventMap.forEach((callbacks, eventType) => {
callbacks.forEach((callback) => {
element.removeEventListener(eventType, callback);
count++;
});
});
});
this.listeners.clear();
if (this.metrics) {
this.recordMetric("removeAllEventListeners", startTime);
}
this.log("debug", `Removed ${count} event listeners`);
}
/**
* Create a setTimeout with tracking
*/
setTimeout(callback, delay) {
if (!this.isActive()) return setTimeout(() => {
}, 0);
const startTime = this.metrics ? performance.now() : 0;
const timeout = setTimeout(() => {
this.timeouts.delete(timeout);
callback();
}, delay);
this.timeouts.add(timeout);
if (this.metrics) {
this.recordMetric("setTimeout", startTime);
}
return timeout;
}
/**
* Create a setInterval with tracking
*/
setInterval(callback, delay) {
if (!this.isActive()) return setInterval(() => {
}, 0);
const startTime = this.metrics ? performance.now() : 0;
const interval = setInterval(callback, delay);
this.intervals.add(interval);
if (this.metrics) {
this.recordMetric("setInterval", startTime);
}
return interval;
}
/**
* Clear a tracked timeout
*/
clearTimeout(id) {
const startTime = this.metrics ? performance.now() : 0;
globalThis.clearTimeout(id);
this.timeouts.delete(id);
if (this.metrics) {
this.recordMetric("clearTimeout", startTime);
}
}
/**
* Clear a tracked interval
*/
clearInterval(id) {
const startTime = this.metrics ? performance.now() : 0;
globalThis.clearInterval(id);
this.intervals.delete(id);
if (this.metrics) {
this.recordMetric("clearInterval", startTime);
}
}
/**
* Clear all tracked timeouts
*/
clearAllTimeouts() {
const startTime = this.metrics ? performance.now() : 0;
let count = 0;
this.timeouts.forEach((id) => {
globalThis.clearTimeout(id);
count++;
});
this.timeouts.clear();
if (this.metrics) {
this.recordMetric("clearAllTimeouts", startTime);
}
this.log("debug", `Cleared ${count} timeouts`);
}
/**
* Clear all tracked intervals
*/
clearAllIntervals() {
const startTime = this.metrics ? performance.now() : 0;
let count = 0;
this.intervals.forEach((id) => {
globalThis.clearInterval(id);
count++;
});
this.intervals.clear();
if (this.metrics) {
this.recordMetric("clearAllIntervals", startTime);
}
this.log("debug", `Cleared ${count} intervals`);
}
/**
* Get current resource statistics
*
* @returns An object containing counts of various tracked resources
*/
getStats() {
const result = {
textures: this.textures.size,
filters: this.filters.size,
displayObjects: this.displayObjects.size,
animations: this.animations.size,
eventTargets: this.listeners.size,
timeouts: this.timeouts.size,
intervals: this.intervals.size,
pixiApps: this.pixiApps.size,
shaderPoolingEnabled: !!this.shaderManager
};
if (this.metrics) {
result.metrics = this.metrics;
}
if (this.shaderManager) {
result.shaderManager = this.shaderManager.getStats();
}
return result;
}
/**
* Clear all tracked resources
*/
dispose() {
if (this.disposed) return;
const startTime = this.metrics ? performance.now() : 0;
this.log("info", "Disposing all resources...");
this.disposed = true;
this.markUnmounting();
if (this.autoCleanupTimer) {
clearInterval(this.autoCleanupTimer);
this.autoCleanupTimer = null;
}
this.animations.forEach((animation) => animation.kill());
this.animations.clear();
this.removeAllEventListeners();
this.pixiApps.forEach((app) => this.disposePixiApp(app));
this.pixiApps.clear();
this.displayObjects.forEach((obj) => this.disableFiltersOnObject(obj));
this.displayObjects.forEach((obj) => this.disposeDisplayObject(obj));
this.displayObjects.clear();
this.filters.forEach((filter) => this.disposeFilter(filter));
this.filters.clear();
this.textures.forEach((entry, url) => {
try {
entry.resource.destroy(true);
} catch (error) {
this.log("warn", `Error disposing texture: ${url}`, error);
}
});
this.textures.clear();
this.clearAllTimeouts();
this.clearAllIntervals();
if (this.shaderManager) {
this.filters.forEach((filter) => {
this.shaderManager?.releaseShader(filter);
});
this.shaderManager = null;
}
if (this.metrics) {
this.recordMetric("dispose", startTime);
this.log("info", "Performance metrics summary:", this.metrics);
}
this.log("info", "All resources disposed");
}
/**
* Clears any pending updates in the queue
*/
clearPendingUpdates() {
this.timeouts.forEach(clearTimeout);
this.timeouts.clear();
this.intervals.forEach(clearInterval);
this.intervals.clear();
}
/**
* Monitor filter performance and adjust quality if necessary
* Part of the shader optimization implementation
*
* @param filter - Filter to monitor
* @param performanceThreshold - Performance threshold in ms
* @param qualityReduceFactor - How much to reduce quality (0-1)
* @returns Whether the filter was optimized
*/
monitorFilterPerformance(filter, performanceThreshold = 16, qualityReduceFactor = 0.5) {
if (!filter || !this.isActive()) return false;
try {
const startTime = performance.now();
if (filter.enabled) {
if ("apply" in filter && typeof filter.apply === "function") {
this.log("debug", "Monitoring filter performance");
}
}
const endTime = performance.now();
const renderTime = endTime - startTime;
if (renderTime > performanceThreshold) {
this.optimizeFilterQuality(filter, qualityReduceFactor);
this.log("info", `Filter performance optimized: ${renderTime.toFixed(2)}ms -> threshold: ${performanceThreshold}ms`);
return true;
}
return false;
} catch (error) {
this.log("warn", "Error monitoring filter performance", error);
return false;
}
}
/**
* Optimize a filter's quality settings to improve performance
*
* @param filter - Filter to optimize
* @param factor - Factor to reduce quality by (0-1)
* @returns Whether optimization was applied
*/
optimizeFilterQuality(filter, factor = 0.5) {
if (!filter || !this.isActive()) return false;
try {
let optimized = false;
if ("quality" in filter && typeof filter.quality === "number") {
const newQuality = Math.max(1, Math.floor(filter.quality * factor));
if (newQuality < filter.quality) {
filter.quality = newQuality;
optimized = true;
this.log("debug", `Reduced filter quality to ${newQuality}`);
}
}
if ("resolution" in filter && typeof filter.resolution === "number") {
const newResolution = Math.max(0.1, filter.resolution * factor);
if (newResolution < filter.resolution) {
filter.resolution = newResolution;
optimized = true;
this.log("debug", `Reduced filter resolution to ${newResolution.toFixed(2)}`);
}
}
const specificParams = [
"kernelSize",
"blur",
"steps",
"passes",
"iterations",
"sampleSize",
"pixelSize",
"blurX",
"blurY"
];
for (const param of specificParams) {
if (param in filter && typeof filter[param] === "number") {
const currentValue = filter[param];
const newValue = Math.max(1, Math.floor(currentValue * factor));
if (newValue < currentValue) {
filter[param] = newValue;
optimized = true;
this.log("debug", `Reduced filter ${param} to ${newValue}`);
}
}
}
return optimized;
} catch (error) {
this.log("warn", "Error optimizing filter quality", error);
return false;
}
}
/**
* Run diagnostics on all active filters
* Provides insights into filter performance
*
* @returns Diagnostic information about filters
*/
runFilterDiagnostics() {
const results = {
totalFilters: this.filters.size,
filtersByType: {},
potentialOptimizations: 0
};
try {
this.filters.forEach((filter) => {
const filterType = filter.constructor.name;
if (!results.filtersByType[filterType]) {
results.filtersByType[filterType] = 0;
}
results.filtersByType[filterType]++;
let canOptimize = false;
if ("quality" in filter && typeof filter.quality === "number" && filter.quality > 1) {
canOptimize = true;
}
if ("resolution" in filter && typeof filter.resolution === "number" && filter.resolution > 0.5) {
canOptimize = true;
}
if (canOptimize) {
results.potentialOptimizations++;
}
});
if (this.shaderManager) {
results.shaderPoolStats = this.shaderManager.getStats();
}
return results;
} catch (error) {
this.log("warn", "Error running filter diagnostics", error);
return { error: "Failed to run diagnostics", totalFilters: this.filters.size };
}
}
/**
* Automatically optimize all filters based on FPS
* This method should be called periodically during animation
*
* @param currentFPS - Current FPS of the application
* @param targetFPS - Target FPS to maintain
* @param optimizationStep - How aggressive to optimize (0-1)
* @returns Number of filters optimized
*/
autoOptimizeFilters(currentFPS, targetFPS = 55, optimizationStep = 0.8) {
if (!this.isActive() || this.filters.size === 0) return 0;
if (currentFPS >= targetFPS) return 0;
try {
let optimizedCount = 0;
const fpsDifference = targetFPS - currentFPS;
const optimizationFactor = Math.min(0.9, Math.max(
0.5,
optimizationStep * (1 - currentFPS / targetFPS)
));
this.log("info", `Auto-optimizing filters: FPS ${currentFPS.toFixed(1)}/${targetFPS}, factor: ${optimizationFactor.toFixed(2)}`);
const filterEntries = Array.from(this.filters.entries()).map(([id, filter]) => {
let estimatedCost = 1;
if ("quality" in filter && typeof filter.quality === "number") {
estimatedCost *= filter.quality;
}
if ("resolution" in filter && typeof filter.resolution === "number") {
estimatedCost *= filter.resolution;
}
return { id, filter, cost: estimatedCost };
}).sort((a, b) => b.cost - a.cost);
for (const { filter } of filterEntries) {
if (optimizedCount >= 3) break;
const wasOptimized = this.optimizeFilterQuality(filter, optimizationFactor);
if (wasOptimized) {
optimizedCount++;
}
}
if (optimizedCount > 0) {
this.log("info", `Optimized ${optimizedCount} filters to improve performance`);
}
return optimizedCount;
} catch (error) {
this.log("warn", "Error auto-optimizing filters", error);
return 0;
}
}
}
export { ResourceManager as default };
//# sourceMappingURL=ResourceManager.js.map