fdsa
This commit is contained in:
+39
-13
@@ -41,11 +41,12 @@
|
||||
--badge-tag: #090909;
|
||||
--posts-meta-bg: #000000b8;
|
||||
--x2154: #215483;
|
||||
--bg-canvas-opacity: 1.0;
|
||||
--bg-canvas-blur: 30px;
|
||||
--bg-canvas-color: transparent;
|
||||
--bg-canvas-color-opacity: 0.0;
|
||||
--onara-bg-opacity: 0.7;
|
||||
--bg-canvas-opacity: 0.81;
|
||||
--bg-canvas-blur: 151px;
|
||||
--bg-canvas-zoom: 1.38;
|
||||
--bg-canvas-color: rgba(0, 0, 0, 0.09);
|
||||
--bg-canvas-color-opacity: 0.09;
|
||||
--onara-bg-opacity: 0.4;
|
||||
--onara-backdrop-blur: 5px;
|
||||
--onara-grid-dim-opacity: 0.38;
|
||||
}
|
||||
@@ -10391,11 +10392,11 @@ div.favs div.posts {
|
||||
bottom: 0;
|
||||
width: calc(100vw - var(--sidebar-w, 300px));
|
||||
height: 100%;
|
||||
transform: translate3d(0, 0, 0) scale(var(--bg-canvas-zoom, 1.12));
|
||||
transform: translate3d(0, 0, 0) scale(var(--bg-canvas-zoom, 1.38));
|
||||
transform-origin: center center;
|
||||
z-index: -2;
|
||||
transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1), width 0.3s ease-in-out;
|
||||
opacity: var(--bg-canvas-opacity, 1.0);
|
||||
opacity: var(--bg-canvas-opacity, 0.81);
|
||||
filter: var(--bg-canvas-filter, none);
|
||||
-webkit-filter: var(--bg-canvas-filter, none);
|
||||
background-color: var(--bg-canvas-color, transparent);
|
||||
@@ -20947,7 +20948,7 @@ body.onara-modal-open .admin-bar.open {
|
||||
z-index: 10050 !important;
|
||||
display: none;
|
||||
flex-direction: column !important;
|
||||
background: rgba(0, 0, 0, var(--onara-bg-opacity, 0.7)) !important;
|
||||
background: rgba(0, 0, 0, var(--onara-bg-opacity, 0.4)) !important;
|
||||
backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
||||
-webkit-backdrop-filter: blur(var(--onara-backdrop-blur, 5px)) saturate(130%) !important;
|
||||
overflow-y: auto !important;
|
||||
@@ -21148,11 +21149,36 @@ body.layout-modern #onara-modal .item-layout-container .item-main-content {
|
||||
margin-right: auto !important;
|
||||
}
|
||||
|
||||
#onara-modal .content:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
|
||||
#onara-modal ._204863:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
|
||||
#onara-modal .item_title:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
|
||||
#onara-modal .item-title:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom) {
|
||||
animation: contentSlideIn 0.55s cubic-bezier(0.16, 1, 0.3, 1) both !important;
|
||||
#onara-modal .content.slide-next,
|
||||
#onara-modal .content.slide-prev,
|
||||
#onara-modal ._204863.slide-next,
|
||||
#onara-modal ._204863.slide-prev,
|
||||
#onara-modal .item_title.slide-next,
|
||||
#onara-modal .item_title.slide-prev,
|
||||
#onara-modal .item-title.slide-next,
|
||||
#onara-modal .item-title.slide-prev,
|
||||
#onara-modal .content:not(.slide-out-left):not(.slide-out-right):not(.fade-out-zoom),
|
||||
#onara-modal ._204863:not(.slide-out-left):not(.slide-out-right):not(.fade-out-zoom),
|
||||
#onara-modal .item_title:not(.slide-out-left):not(.slide-out-right):not(.fade-out-zoom),
|
||||
#onara-modal .item-title:not(.slide-out-left):not(.slide-out-right):not(.fade-out-zoom) {
|
||||
animation: contentFadeInZoom 0.32s cubic-bezier(0.16, 1, 0.3, 1) both !important;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
#onara-modal .content.slide-out-left,
|
||||
#onara-modal .content.slide-out-right,
|
||||
#onara-modal ._204863.slide-out-left,
|
||||
#onara-modal ._204863.slide-out-right,
|
||||
#onara-modal .item_title.slide-out-left,
|
||||
#onara-modal .item_title.slide-out-right,
|
||||
#onara-modal .item-title.slide-out-left,
|
||||
#onara-modal .item-title.slide-out-right,
|
||||
#onara-modal .content.fade-out-zoom,
|
||||
#onara-modal ._204863.fade-out-zoom,
|
||||
#onara-modal .item_title.fade-out-zoom,
|
||||
#onara-modal .item-title.fade-out-zoom {
|
||||
animation: contentFadeOutZoom 0.18s cubic-bezier(0.3, 0, 0.8, 1) forwards !important;
|
||||
pointer-events: none;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
|
||||
+518
-116
@@ -1682,7 +1682,11 @@ window.cancelAnimFrame = (function () {
|
||||
modal._closeTimeout = null;
|
||||
}
|
||||
modal._isClosing = false;
|
||||
const wasAlreadyOpen = document.body.classList.contains('onara-modal-open');
|
||||
document.body.classList.add('onara-modal-open');
|
||||
if (typeof window.applyBackgroundOpacitySettings === 'function') {
|
||||
window.applyBackgroundOpacitySettings(null, true);
|
||||
}
|
||||
if (document.querySelector('.index-container') && window.scrollY !== 0) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
@@ -1698,9 +1702,9 @@ window.cancelAnimFrame = (function () {
|
||||
canvas.classList.remove('fader-out', 'fast-fade');
|
||||
canvas.classList.add('fader-in');
|
||||
canvas.style.transition = 'none';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 0.95)';
|
||||
}
|
||||
if (typeof window.paintImmediateBgThumb === 'function') {
|
||||
if (!wasAlreadyOpen && typeof window.paintImmediateBgThumb === 'function') {
|
||||
window.paintImmediateBgThumb();
|
||||
}
|
||||
|
||||
@@ -1978,6 +1982,9 @@ window.cancelAnimFrame = (function () {
|
||||
modal.classList.remove('onara-fade-in');
|
||||
modal.classList.add('onara-fade-out');
|
||||
document.body.classList.remove('onara-modal-open');
|
||||
if (typeof window.applyBackgroundOpacitySettings === 'function') {
|
||||
window.applyBackgroundOpacitySettings(null, false);
|
||||
}
|
||||
|
||||
// Destroy background instance when Onara modal closes so it doesn't linger on the index grid
|
||||
if (window.destroyBackgroundInstance) {
|
||||
@@ -4028,6 +4035,199 @@ window.cancelAnimFrame = (function () {
|
||||
}
|
||||
};
|
||||
|
||||
let mediaAmbientSampleCanvas = null;
|
||||
let mediaAmbientSampleCtx = null;
|
||||
|
||||
const sampleMediaSpatialColors = (source) => {
|
||||
if (!source) return null;
|
||||
const w = source.videoWidth || source.naturalWidth || source.width || 0;
|
||||
const h = source.videoHeight || source.naturalHeight || source.height || 0;
|
||||
if (w <= 0 || h <= 0) return null;
|
||||
|
||||
if (!mediaAmbientSampleCanvas) {
|
||||
mediaAmbientSampleCanvas = document.createElement('canvas');
|
||||
mediaAmbientSampleCanvas.width = 4;
|
||||
mediaAmbientSampleCanvas.height = 4;
|
||||
mediaAmbientSampleCtx = mediaAmbientSampleCanvas.getContext('2d', { willReadFrequently: true });
|
||||
}
|
||||
if (!mediaAmbientSampleCtx) return null;
|
||||
|
||||
try {
|
||||
mediaAmbientSampleCtx.clearRect(0, 0, 4, 4);
|
||||
mediaAmbientSampleCtx.drawImage(source, 0, 0, 4, 4);
|
||||
const data = mediaAmbientSampleCtx.getImageData(0, 0, 4, 4).data;
|
||||
|
||||
// Sample top half (rows 0, 1) and bottom half (rows 2, 3)
|
||||
let rTop = 0, gTop = 0, bTop = 0, countTop = 0;
|
||||
let rBot = 0, gBot = 0, bBot = 0, countBot = 0;
|
||||
|
||||
for (let y = 0; y < 4; y++) {
|
||||
for (let x = 0; x < 4; x++) {
|
||||
const idx = (y * 4 + x) * 4;
|
||||
const a = data[idx + 3];
|
||||
if (a > 20) {
|
||||
if (y < 2) {
|
||||
rTop += data[idx];
|
||||
gTop += data[idx + 1];
|
||||
bTop += data[idx + 2];
|
||||
countTop++;
|
||||
} else {
|
||||
rBot += data[idx];
|
||||
gBot += data[idx + 1];
|
||||
bBot += data[idx + 2];
|
||||
countBot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const top = countTop > 0
|
||||
? [Math.round(rTop / countTop), Math.round(gTop / countTop), Math.round(bTop / countTop)]
|
||||
: [25, 25, 35];
|
||||
const bot = countBot > 0
|
||||
? [Math.round(rBot / countBot), Math.round(gBot / countBot), Math.round(bBot / countBot)]
|
||||
: [25, 25, 35];
|
||||
|
||||
return { top, bottom: bot };
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const boostColorSaturation = (rgb, boost = 1.35) => {
|
||||
if (!rgb || !Array.isArray(rgb) || rgb.length < 3) return [30, 30, 40];
|
||||
const [r, g, b] = rgb;
|
||||
const lum = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
return [
|
||||
Math.min(255, Math.max(0, Math.round(lum + (r - lum) * boost))),
|
||||
Math.min(255, Math.max(0, Math.round(lum + (g - lum) * boost))),
|
||||
Math.min(255, Math.max(0, Math.round(lum + (b - lum) * boost)))
|
||||
];
|
||||
};
|
||||
|
||||
const mediaAmbientState = {
|
||||
top: [25, 25, 35],
|
||||
targetTop: [25, 25, 35],
|
||||
bottom: [25, 25, 35],
|
||||
targetBottom: [25, 25, 35],
|
||||
hasSampled: false
|
||||
};
|
||||
|
||||
const setAmbientTargetColors = (colors) => {
|
||||
if (!colors) return;
|
||||
if (colors.top) mediaAmbientState.targetTop = [...colors.top];
|
||||
if (colors.bottom) mediaAmbientState.targetBottom = [...colors.bottom];
|
||||
};
|
||||
|
||||
const updateAmbientLerp = (smoothingFactor) => {
|
||||
const cfg = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning() : null) || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const factor = smoothingFactor !== undefined
|
||||
? smoothingFactor
|
||||
: (cfg.bgAmbientSmoothness !== undefined ? Number(cfg.bgAmbientSmoothness) : 0.05);
|
||||
const s = mediaAmbientState;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
s.top[i] += (s.targetTop[i] - s.top[i]) * factor;
|
||||
s.bottom[i] += (s.targetBottom[i] - s.bottom[i]) * factor;
|
||||
}
|
||||
return {
|
||||
top: s.top.map(v => Math.min(255, Math.max(0, Math.round(v)))),
|
||||
bottom: s.bottom.map(v => Math.min(255, Math.max(0, Math.round(v))))
|
||||
};
|
||||
};
|
||||
|
||||
const renderAmbientLightingWash = (ctx, targetW, targetH, colors, alpha = 1.0) => {
|
||||
if (!ctx || !colors) return;
|
||||
const cfg = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning() : null) || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const satBoost = cfg.bgAmbientSaturation !== undefined ? Number(cfg.bgAmbientSaturation) : 1.35;
|
||||
const intensity = cfg.bgAmbientIntensity !== undefined ? Number(cfg.bgAmbientIntensity) : 1.0;
|
||||
const spread = cfg.bgAmbientSpread !== undefined ? Number(cfg.bgAmbientSpread) : 0.85;
|
||||
|
||||
const rawTop = colors.top || colors;
|
||||
const rawBot = colors.bottom || colors.top || colors;
|
||||
const top = boostColorSaturation(rawTop, satBoost);
|
||||
const bot = boostColorSaturation(rawBot, satBoost);
|
||||
|
||||
ctx.save();
|
||||
if (alpha < 1.0) ctx.globalAlpha = alpha;
|
||||
|
||||
const cx = targetW / 2;
|
||||
const cyTop = targetH * 0.28;
|
||||
const cyBot = targetH * 0.72;
|
||||
const maxR = Math.max(targetW, targetH) * spread;
|
||||
|
||||
// 1. Dark background base
|
||||
ctx.fillStyle = '#06060c';
|
||||
ctx.fillRect(0, 0, targetW, targetH);
|
||||
|
||||
const a0 = Math.min(1.0, Math.max(0.0, 0.90 * intensity)).toFixed(3);
|
||||
const a1 = Math.min(1.0, Math.max(0.0, 0.55 * intensity)).toFixed(3);
|
||||
const a2 = Math.min(1.0, Math.max(0.0, 0.18 * intensity)).toFixed(3);
|
||||
|
||||
// 2. Top ambient lobe
|
||||
const [rt, gt, bt] = top;
|
||||
const gradTop = ctx.createRadialGradient(cx, cyTop, 0, cx, cyTop, maxR);
|
||||
gradTop.addColorStop(0, `rgba(${rt}, ${gt}, ${bt}, ${a0})`);
|
||||
gradTop.addColorStop(0.35, `rgba(${Math.round(rt * 0.75)}, ${Math.round(gt * 0.75)}, ${Math.round(bt * 0.75)}, ${a1})`);
|
||||
gradTop.addColorStop(0.70, `rgba(${Math.round(rt * 0.35)}, ${Math.round(gt * 0.35)}, ${Math.round(bt * 0.35)}, ${a2})`);
|
||||
gradTop.addColorStop(1.0, 'rgba(6, 6, 12, 0.0)');
|
||||
|
||||
ctx.fillStyle = gradTop;
|
||||
ctx.fillRect(0, 0, targetW, targetH);
|
||||
|
||||
// 3. Bottom ambient lobe
|
||||
const [rb, gb, bb] = bot;
|
||||
const gradBot = ctx.createRadialGradient(cx, cyBot, 0, cx, cyBot, maxR);
|
||||
gradBot.addColorStop(0, `rgba(${rb}, ${gb}, ${bb}, ${a0})`);
|
||||
gradBot.addColorStop(0.35, `rgba(${Math.round(rb * 0.75)}, ${Math.round(gb * 0.75)}, ${Math.round(bb * 0.75)}, ${a1})`);
|
||||
gradBot.addColorStop(0.70, `rgba(${Math.round(rb * 0.35)}, ${Math.round(gb * 0.35)}, ${Math.round(bb * 0.35)}, ${a2})`);
|
||||
gradBot.addColorStop(1.0, 'rgba(6, 6, 12, 0.0)');
|
||||
|
||||
ctx.fillStyle = gradBot;
|
||||
ctx.fillRect(0, 0, targetW, targetH);
|
||||
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
let ambientTransitionRaf = null;
|
||||
const transitionAmbientToColors = (colors, onComplete) => {
|
||||
setAmbientTargetColors(colors);
|
||||
if (ambientTransitionRaf) window.cancelAnimFrame(ambientTransitionRaf);
|
||||
const canvas = document.getElementById('bg');
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
let frames = 0;
|
||||
const maxFrames = 30; // ~500ms smooth cinematic color melt
|
||||
|
||||
const step = () => {
|
||||
const current = updateAmbientLerp(0.10);
|
||||
const w = canvas.width;
|
||||
const h = canvas.height;
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
renderAmbientLightingWash(ctx, w, h, current, 1.0);
|
||||
if (typeof window.applyBgColorOverlay === 'function') {
|
||||
window.applyBgColorOverlay(ctx, w, h);
|
||||
}
|
||||
|
||||
frames++;
|
||||
const distTop = Math.abs(mediaAmbientState.top[0] - mediaAmbientState.targetTop[0]) +
|
||||
Math.abs(mediaAmbientState.top[1] - mediaAmbientState.targetTop[1]) +
|
||||
Math.abs(mediaAmbientState.top[2] - mediaAmbientState.targetTop[2]);
|
||||
const distBot = Math.abs(mediaAmbientState.bottom[0] - mediaAmbientState.targetBottom[0]) +
|
||||
Math.abs(mediaAmbientState.bottom[1] - mediaAmbientState.targetBottom[1]) +
|
||||
Math.abs(mediaAmbientState.bottom[2] - mediaAmbientState.targetBottom[2]);
|
||||
|
||||
if (frames < maxFrames && (distTop > 2 || distBot > 2)) {
|
||||
ambientTransitionRaf = window.requestAnimFrame(step);
|
||||
} else {
|
||||
ambientTransitionRaf = null;
|
||||
if (onComplete) onComplete();
|
||||
}
|
||||
};
|
||||
ambientTransitionRaf = window.requestAnimFrame(step);
|
||||
};
|
||||
|
||||
// Paint background canvas immediately from thumbnail without network or animation delay
|
||||
window.paintImmediateBgThumb = (thumbOrElem) => {
|
||||
if (typeof background !== 'undefined' && !background) return;
|
||||
@@ -4058,18 +4258,18 @@ window.cancelAnimFrame = (function () {
|
||||
canvas.classList.remove('fader-out', 'fast-fade');
|
||||
canvas.classList.add('fader-in');
|
||||
canvas.style.transition = 'none';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
|
||||
canvas.style.opacity = document.body.classList.contains('onara-modal-open') ? 'var(--bg-canvas-opacity, 0.95)' : 'var(--bg-canvas-opacity, 0.81)';
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const cfg = (typeof window.audioVisualizerTuning !== 'undefined' && window.audioVisualizerTuning) || (typeof DEFAULT_AUDIO_TUNING !== 'undefined' ? DEFAULT_AUDIO_TUNING : {});
|
||||
const cfg = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning(true) : null) || (typeof window.audioVisualizerTuning !== 'undefined' && window.audioVisualizerTuning) || (typeof DEFAULT_AUDIO_TUNING !== 'undefined' ? DEFAULT_AUDIO_TUNING : {});
|
||||
const method = cfg.bgBlurMethod !== undefined ? Number(cfg.bgBlurMethod) : 0;
|
||||
const bSetting = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 30;
|
||||
const bPx = method === 1 ? 0 : Math.round(bSetting * SCALE);
|
||||
const bVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.45;
|
||||
const sat = cfg.bgCanvasSaturate !== undefined ? Number(cfg.bgCanvasSaturate) : 1.8;
|
||||
const con = cfg.bgCanvasContrast !== undefined ? Number(cfg.bgCanvasContrast) : 1.1;
|
||||
const bSetting = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 31;
|
||||
const bPx = (method === 1 || method === 2) ? 0 : Math.round(bSetting * SCALE);
|
||||
const bVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.6;
|
||||
const sat = cfg.bgCanvasSaturate !== undefined ? Number(cfg.bgCanvasSaturate) : 1.85;
|
||||
const con = cfg.bgCanvasContrast !== undefined ? Number(cfg.bgCanvasContrast) : 1.15;
|
||||
const parts = [];
|
||||
if (bPx > 0) parts.push(`blur(${bPx}px)`);
|
||||
if (bVal !== 1) parts.push(`brightness(${bVal})`);
|
||||
@@ -4077,13 +4277,22 @@ window.cancelAnimFrame = (function () {
|
||||
if (con !== 1) parts.push(`contrast(${con})`);
|
||||
const filterStr = parts.length > 0 ? parts.join(' ') : 'none';
|
||||
|
||||
const useAmbient = Number(cfg.bgAmbientLighting) === 1;
|
||||
if (useAmbient) {
|
||||
ctx.clearRect(0, 0, cw, ch);
|
||||
const sampled = sampleMediaSpatialColors(img) || { top: [30, 30, 45], bottom: [30, 30, 45] };
|
||||
setAmbientTargetColors(sampled);
|
||||
mediaAmbientState.top = [...mediaAmbientState.targetTop];
|
||||
mediaAmbientState.bottom = [...mediaAmbientState.targetBottom];
|
||||
renderAmbientLightingWash(ctx, cw, ch, sampled, 1.0);
|
||||
} else {
|
||||
ctx.clearRect(0, 0, cw, ch);
|
||||
ctx.save();
|
||||
ctx.filter = filterStr;
|
||||
|
||||
let sw = img.naturalWidth || img.width;
|
||||
let sh = img.naturalHeight || img.height;
|
||||
if (sw > 0 && sh > 0) {
|
||||
if (sw > 0 && sw > 0) {
|
||||
const scale = Math.max(cw / sw, ch / sh);
|
||||
const dw = sw * scale;
|
||||
const dh = sh * scale;
|
||||
@@ -4094,6 +4303,7 @@ window.cancelAnimFrame = (function () {
|
||||
ctx.drawImage(img, 0, 0, cw, ch);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Color overlay tint if configured
|
||||
const colOp = cfg.bgCanvasColorOpacity !== undefined ? Math.min(1, Math.max(0, Number(cfg.bgCanvasColorOpacity))) : 0;
|
||||
@@ -4216,20 +4426,22 @@ window.cancelAnimFrame = (function () {
|
||||
}
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
const cfgCurrent = window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const blurSetting = cfgCurrent.bgCanvasBlur !== undefined ? Number(cfgCurrent.bgCanvasBlur) : 30;
|
||||
const blurPx = Math.round(blurSetting * SCALE);
|
||||
const brightnessVal = cfgCurrent.bgCanvasBrightness !== undefined ? Number(cfgCurrent.bgCanvasBrightness) : 0.45;
|
||||
const cfgCurrent = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning() : null) || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const blurSetting = cfgCurrent.bgCanvasBlur !== undefined ? Number(cfgCurrent.bgCanvasBlur) : 31;
|
||||
const methodSetting = cfgCurrent.bgBlurMethod !== undefined ? Number(cfgCurrent.bgBlurMethod) : 0;
|
||||
const blurPx = (methodSetting === 1 || methodSetting === 2) ? 0 : Math.round(blurSetting * SCALE);
|
||||
const brightnessVal = cfgCurrent.bgCanvasBrightness !== undefined ? Number(cfgCurrent.bgCanvasBrightness) : 0.6;
|
||||
|
||||
const getCanvasFilter = () => {
|
||||
const cfg = window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const cfg = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning() : null) || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const method = cfg.bgBlurMethod !== undefined ? Number(cfg.bgBlurMethod) : 0;
|
||||
const bSetting = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 30;
|
||||
const bSetting = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 31;
|
||||
// Method 1 = GPU CSS filter only (no canvas blur, handled by CSS --bg-canvas-filter)
|
||||
const bPx = method === 1 ? 0 : Math.round(bSetting * SCALE);
|
||||
const bVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.45;
|
||||
const sat = cfg.bgCanvasSaturate !== undefined ? Number(cfg.bgCanvasSaturate) : 1.8;
|
||||
const con = cfg.bgCanvasContrast !== undefined ? Number(cfg.bgCanvasContrast) : 1.1;
|
||||
// Method 2 = Hybrid (CSS blur + canvas sat/contrast)
|
||||
const bPx = (method === 1 || method === 2) ? 0 : Math.round(bSetting * SCALE);
|
||||
const bVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.6;
|
||||
const sat = cfg.bgCanvasSaturate !== undefined ? Number(cfg.bgCanvasSaturate) : 1.85;
|
||||
const con = cfg.bgCanvasContrast !== undefined ? Number(cfg.bgCanvasContrast) : 1.15;
|
||||
const parts = [];
|
||||
if (bPx > 0) parts.push(`blur(${bPx}px)`);
|
||||
if (bVal !== 1) parts.push(`brightness(${bVal})`);
|
||||
@@ -4270,7 +4482,7 @@ window.cancelAnimFrame = (function () {
|
||||
};
|
||||
|
||||
const applyBgColorOverlay = (ctx, w, h) => {
|
||||
const cfg = window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const cfg = (typeof window.getEffectiveBackgroundTuning === 'function' ? window.getEffectiveBackgroundTuning() : null) || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const colOp = cfg.bgCanvasColorOpacity !== undefined ? Math.min(1, Math.max(0, Number(cfg.bgCanvasColorOpacity))) : 0;
|
||||
if (colOp > 0.001) {
|
||||
const col = cfg.bgCanvasColor || '#000000';
|
||||
@@ -4287,8 +4499,15 @@ window.cancelAnimFrame = (function () {
|
||||
syncCanvasDimensions();
|
||||
const targetW = canvas.width;
|
||||
const targetH = canvas.height;
|
||||
const isOnara = document.body.classList.contains('onara-modal-open') || (typeof isOnaraActive === 'function' && isOnaraActive());
|
||||
if (!prevSnapshot || isOnara) {
|
||||
const useAmbient = Number(cfgCurrent.bgAmbientLighting) === 1;
|
||||
|
||||
if (useAmbient) {
|
||||
const sampled = sampleMediaSpatialColors(sourceImg) || { top: [30, 30, 45], bottom: [30, 30, 45] };
|
||||
transitionAmbientToColors(sampled, onComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!prevSnapshot) {
|
||||
context.clearRect(0, 0, targetW, targetH);
|
||||
context.save();
|
||||
context.filter = getCanvasFilter();
|
||||
@@ -4312,15 +4531,12 @@ window.cancelAnimFrame = (function () {
|
||||
const h = canvas.height;
|
||||
context.clearRect(0, 0, w, h);
|
||||
|
||||
// 1. Fade out previous background
|
||||
if (ease < 1.0 && prevSnapshot) {
|
||||
context.save();
|
||||
context.globalAlpha = 1.0 - ease;
|
||||
// 1. Base: keep previous background at full opacity underneath (prevents transparent dip)
|
||||
if (prevSnapshot) {
|
||||
context.drawImage(prevSnapshot, 0, 0, w, h);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
// 2. Fade in new background with blur and brightness
|
||||
// 2. Fade in new background smoothly over previous
|
||||
context.save();
|
||||
context.globalAlpha = ease;
|
||||
context.filter = getCanvasFilter();
|
||||
@@ -4352,35 +4568,36 @@ window.cancelAnimFrame = (function () {
|
||||
if (itemId) {
|
||||
if (document.body.classList.contains('onara-modal-open')) {
|
||||
const onaraThumbImg = document.querySelector('.posts > a.thumb.onara-active img, .posts > a.thumb:focus img');
|
||||
if (onaraThumbImg && onaraThumbImg.complete && onaraThumbImg.naturalWidth > 0) {
|
||||
crossfadeToSource(onaraThumbImg, () => {
|
||||
if (isDrawable && elem.complete && elem.naturalWidth > 0) {
|
||||
crossfadeToSource(elem);
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (onaraThumbImg && onaraThumbImg.complete && onaraThumbImg.naturalWidth > 0) {
|
||||
crossfadeToSource(onaraThumbImg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const thumb = new Image();
|
||||
thumb.onload = () => {
|
||||
crossfadeToSource(thumb, () => {
|
||||
if (isDrawable) {
|
||||
if (elem.complete && elem.naturalWidth > 0) {
|
||||
crossfadeToSource(elem);
|
||||
} else {
|
||||
elem.onload = () => crossfadeToSource(elem);
|
||||
}
|
||||
}
|
||||
});
|
||||
let resolved = false;
|
||||
const onLoaded = (src) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
crossfadeToSource(src);
|
||||
};
|
||||
thumb.onerror = () => {
|
||||
|
||||
if (isDrawable) {
|
||||
if (elem.complete && elem.naturalWidth > 0) {
|
||||
crossfadeToSource(elem);
|
||||
} else {
|
||||
elem.onload = () => crossfadeToSource(elem);
|
||||
onLoaded(elem);
|
||||
return;
|
||||
}
|
||||
elem.onload = () => onLoaded(elem);
|
||||
}
|
||||
|
||||
const thumb = new Image();
|
||||
thumb.onload = () => onLoaded(thumb);
|
||||
thumb.onerror = () => {
|
||||
if (isDrawable && elem.complete && elem.naturalWidth > 0) {
|
||||
onLoaded(elem);
|
||||
}
|
||||
};
|
||||
let newSrc = `/t/${itemId}.webp`;
|
||||
@@ -4407,19 +4624,46 @@ window.cancelAnimFrame = (function () {
|
||||
const curCw = canvas.width;
|
||||
const curCh = canvas.height;
|
||||
context.clearRect(0, 0, curCw, curCh);
|
||||
const isOnara = document.body.classList.contains('onara-modal-open') || (typeof isOnaraActive === 'function' && isOnaraActive());
|
||||
if (prevSnapshot && !isOnara) {
|
||||
|
||||
const useAmbient = Number(cfgCurrent.bgAmbientLighting) === 1;
|
||||
if (useAmbient) {
|
||||
if (!elem._ambientFrameCount) elem._ambientFrameCount = 0;
|
||||
elem._ambientFrameCount++;
|
||||
if (elem._ambientFrameCount % 3 === 0 || !mediaAmbientState.hasSampled) {
|
||||
const sampled = sampleMediaSpatialColors(elem);
|
||||
if (sampled) {
|
||||
setAmbientTargetColors(sampled);
|
||||
mediaAmbientState.hasSampled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth exponential lerp on every single RAF frame (0.05 per frame = buttery smooth)
|
||||
const current = updateAmbientLerp(0.05);
|
||||
|
||||
if (prevSnapshot) {
|
||||
const elapsed = performance.now() - videoFadeStartTime;
|
||||
const progress = Math.min(1.0, elapsed / 350);
|
||||
const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
|
||||
|
||||
if (ease < 1.0) {
|
||||
context.save();
|
||||
context.globalAlpha = 1.0 - ease;
|
||||
context.drawImage(prevSnapshot, 0, 0, curCw, curCh);
|
||||
context.restore();
|
||||
}
|
||||
renderAmbientLightingWash(context, curCw, curCh, current, ease);
|
||||
|
||||
if (progress >= 1.0) {
|
||||
prevSnapshot = null;
|
||||
}
|
||||
} else {
|
||||
renderAmbientLightingWash(context, curCw, curCh, current, 1.0);
|
||||
}
|
||||
} else {
|
||||
if (prevSnapshot) {
|
||||
const elapsed = performance.now() - videoFadeStartTime;
|
||||
const progress = Math.min(1.0, elapsed / 350);
|
||||
const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
|
||||
|
||||
// Base: previous frame drawn underneath at full opacity
|
||||
context.drawImage(prevSnapshot, 0, 0, curCw, curCh);
|
||||
|
||||
// Video dissolves smoothly on top
|
||||
context.save();
|
||||
context.globalAlpha = ease;
|
||||
context.filter = getCanvasFilter();
|
||||
@@ -4432,7 +4676,7 @@ window.cancelAnimFrame = (function () {
|
||||
prevSnapshot = null;
|
||||
}
|
||||
} else {
|
||||
// Video already loaded or resumed from pause (or instant in Onara): render directly at 100% opacity without fading from black
|
||||
// Video already loaded or resumed from pause: render directly at 100% opacity without fading from black
|
||||
context.save();
|
||||
context.filter = getCanvasFilter();
|
||||
try {
|
||||
@@ -4440,6 +4684,7 @@ window.cancelAnimFrame = (function () {
|
||||
} catch (e) {}
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
// Color overlay tint if configured
|
||||
applyBgColorOverlay(context, curCw, curCh);
|
||||
@@ -4458,8 +4703,19 @@ window.cancelAnimFrame = (function () {
|
||||
if (prevSnapshot) videoFadeStartTime = performance.now();
|
||||
|
||||
if (elem.tagName === 'VIDEO') {
|
||||
// For album videos (reused element), remove old listeners first
|
||||
if (background) {
|
||||
if (!elem.paused) {
|
||||
if (bgRafId) window.cancelAnimFrame(bgRafId);
|
||||
animationLoop();
|
||||
}
|
||||
// For album videos that haven't started yet, or Onara videos pending play, drawOnce with the thumbnail
|
||||
else if (isAlbumVideo || document.body.classList.contains('onara-modal-open')) {
|
||||
drawOnce();
|
||||
}
|
||||
}
|
||||
|
||||
const startVideoLoop = () => {
|
||||
if (crossfadeRafId) window.cancelAnimFrame(crossfadeRafId);
|
||||
if (bgRafId) window.cancelAnimFrame(bgRafId);
|
||||
// Only reset fade start time if a previous snapshot is actively waiting to be crossfaded
|
||||
if (prevSnapshot) videoFadeStartTime = performance.now();
|
||||
@@ -4721,23 +4977,81 @@ window.cancelAnimFrame = (function () {
|
||||
enableBlink: 0,
|
||||
blinkInterval: 12,
|
||||
beatHueSpeed: 0.1,
|
||||
onaraBgOpacity: 0.7,
|
||||
onaraBgOpacity: 0.4,
|
||||
onaraBackdropBlur: 5,
|
||||
bgCanvasColor: '#000000',
|
||||
bgCanvasColorOpacity: 0,
|
||||
bgCanvasOpacity: 1,
|
||||
bgCanvasColor: "#000000",
|
||||
bgCanvasColorOpacity: 0.09,
|
||||
bgCanvasOpacity: 0.81,
|
||||
bgBlurMethod: 0,
|
||||
bgCanvasBlur: 30,
|
||||
bgCanvasBrightness: 0.45,
|
||||
bgCanvasSaturate: 1.8,
|
||||
bgCanvasContrast: 1.1,
|
||||
bgCanvasZoom: 1.12,
|
||||
bgCanvasScale: 3,
|
||||
bgCanvasBlur: 151,
|
||||
bgCanvasBrightness: 0.6,
|
||||
bgCanvasSaturate: 1.9,
|
||||
bgCanvasContrast: 1.15,
|
||||
bgCanvasZoom: 1.38,
|
||||
bgCanvasScale: 2.15,
|
||||
onaraGridDim: 0.38,
|
||||
feedAudioToBg: 0
|
||||
feedAudioToBg: 1,
|
||||
bgAmbientLighting: 1,
|
||||
bgAmbientIntensity: 1.9,
|
||||
bgAmbientSpread: 0.5,
|
||||
bgAmbientSaturation: 1.5,
|
||||
bgAmbientSmoothness: 0.06
|
||||
};
|
||||
|
||||
const TUNING_CONFIG_VERSION = '2026-09-16_tuner_v7';
|
||||
const TUNING_CONFIG_VERSION = '2026-09-16_tuner_v12';
|
||||
|
||||
const DEFAULT_ONARA_TUNING = {
|
||||
bgCanvasColor: "#000000",
|
||||
bgCanvasColorOpacity: 0.8,
|
||||
bgCanvasOpacity: 0.95,
|
||||
bgBlurMethod: 2,
|
||||
bgCanvasBlur: 31,
|
||||
bgCanvasBrightness: 0.6,
|
||||
bgCanvasSaturate: 1.85,
|
||||
bgCanvasContrast: 1.15,
|
||||
bgCanvasZoom: 1.38,
|
||||
bgCanvasScale: 2.15,
|
||||
feedAudioToBg: 1,
|
||||
onaraBgOpacity: 0,
|
||||
onaraBackdropBlur: 10,
|
||||
onaraGridDim: 0,
|
||||
bgAmbientLighting: 0,
|
||||
bgAmbientIntensity: 1.0,
|
||||
bgAmbientSpread: 0.85,
|
||||
bgAmbientSaturation: 1.35,
|
||||
bgAmbientSmoothness: 0.05
|
||||
};
|
||||
|
||||
const ONARA_TUNING_CONFIG_VERSION = '2026-09-16_onara_v3';
|
||||
let savedOnaraTuning = null;
|
||||
try {
|
||||
const appliedOnaraVer = localStorage.getItem('f0ck_onara_tuning_ver');
|
||||
if (appliedOnaraVer !== ONARA_TUNING_CONFIG_VERSION) {
|
||||
localStorage.setItem('f0ck_onara_tuning', JSON.stringify(DEFAULT_ONARA_TUNING));
|
||||
localStorage.setItem('f0ck_onara_tuning_ver', ONARA_TUNING_CONFIG_VERSION);
|
||||
savedOnaraTuning = Object.assign({}, DEFAULT_ONARA_TUNING);
|
||||
} else {
|
||||
const raw = localStorage.getItem('f0ck_onara_tuning');
|
||||
if (raw) savedOnaraTuning = JSON.parse(raw);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
window.DEFAULT_ONARA_TUNING = DEFAULT_ONARA_TUNING;
|
||||
window.onaraTuning = Object.assign({}, DEFAULT_ONARA_TUNING, savedOnaraTuning || {});
|
||||
|
||||
const isCurrentlyInOnara = () => {
|
||||
return document.body.classList.contains('onara-modal-open') ||
|
||||
(typeof isOnaraActive === 'function' && isOnaraActive() && !!document.getElementById('onara-item-mount'));
|
||||
};
|
||||
|
||||
const getEffectiveBackgroundTuning = (forceMode) => {
|
||||
const useOnara = forceMode !== undefined ? (forceMode === 'onara' || forceMode === true) : isCurrentlyInOnara();
|
||||
if (useOnara) {
|
||||
return Object.assign({}, window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING, window.onaraTuning || DEFAULT_ONARA_TUNING);
|
||||
}
|
||||
return window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
};
|
||||
window.getEffectiveBackgroundTuning = getEffectiveBackgroundTuning;
|
||||
|
||||
const getCustomDefaultTuning = () => {
|
||||
try {
|
||||
@@ -4777,17 +5091,18 @@ window.cancelAnimFrame = (function () {
|
||||
|
||||
window.audioVisualizerTuning = Object.assign({}, getEffectiveDefaultTuning(), savedTuning || {});
|
||||
|
||||
const applyBackgroundOpacitySettings = (cfg) => {
|
||||
const c = cfg || window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
|
||||
const onaraOp = c.onaraBgOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.onaraBgOpacity))) : 0.70;
|
||||
const bgOp = c.bgCanvasOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.bgCanvasOpacity))) : 1.00;
|
||||
const gridThumbOp = c.onaraGridDim !== undefined ? Math.min(1, Math.max(0, Number(c.onaraGridDim))) : 0.38;
|
||||
const onaraBlur = c.onaraBackdropBlur !== undefined ? Math.max(0, Number(c.onaraBackdropBlur)) : 5;
|
||||
const bgBlur = c.bgCanvasBlur !== undefined ? Math.max(0, Number(c.bgCanvasBlur)) : 30;
|
||||
const method = c.bgBlurMethod !== undefined ? Number(c.bgBlurMethod) : 0;
|
||||
const zoom = c.bgCanvasZoom !== undefined ? Math.max(1.0, Number(c.bgCanvasZoom)) : 1.12;
|
||||
const applyBackgroundOpacitySettings = (cfg, forceMode) => {
|
||||
const inOnara = forceMode !== undefined ? (forceMode === 'onara' || forceMode === true) : isCurrentlyInOnara();
|
||||
const c = cfg || getEffectiveBackgroundTuning(forceMode);
|
||||
const onaraOp = c.onaraBgOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.onaraBgOpacity))) : (inOnara ? 0.0 : 0.40);
|
||||
const bgOp = c.bgCanvasOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.bgCanvasOpacity))) : (inOnara ? 0.95 : 0.81);
|
||||
const gridThumbOp = c.onaraGridDim !== undefined ? Math.min(1, Math.max(0, Number(c.onaraGridDim))) : (inOnara ? 0.0 : 0.38);
|
||||
const onaraBlur = c.onaraBackdropBlur !== undefined ? Math.max(0, Number(c.onaraBackdropBlur)) : (inOnara ? 10 : 5);
|
||||
const bgBlur = c.bgCanvasBlur !== undefined ? Math.max(0, Number(c.bgCanvasBlur)) : (inOnara ? 31 : 151);
|
||||
const method = c.bgBlurMethod !== undefined ? Number(c.bgBlurMethod) : (inOnara ? 2 : 0);
|
||||
const zoom = c.bgCanvasZoom !== undefined ? Math.max(1.0, Number(c.bgCanvasZoom)) : 1.38;
|
||||
const bgColor = c.bgCanvasColor || '#000000';
|
||||
const bgColOp = c.bgCanvasColorOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.bgCanvasColorOpacity))) : 0.0;
|
||||
const bgColOp = c.bgCanvasColorOpacity !== undefined ? Math.min(1, Math.max(0, Number(c.bgCanvasColorOpacity))) : (inOnara ? 0.8 : 0.09);
|
||||
const computedBgCol = bgColOp <= 0.001 ? 'transparent' : (bgColOp >= 0.999 ? bgColor : `color-mix(in srgb, ${bgColor} ${Math.round(bgColOp * 100)}%, transparent)`);
|
||||
|
||||
document.documentElement.style.setProperty('--onara-bg-opacity', onaraOp.toFixed(3));
|
||||
@@ -4799,8 +5114,12 @@ window.cancelAnimFrame = (function () {
|
||||
document.documentElement.style.setProperty('--bg-canvas-color', computedBgCol);
|
||||
document.documentElement.style.setProperty('--bg-canvas-color-opacity', bgColOp.toFixed(3));
|
||||
|
||||
// Method 1 = GPU CSS filter (the classic look); Method 2 = Hybrid (CSS blur + canvas sat/contrast)
|
||||
if (method === 1 || method === 2) {
|
||||
// Ambient lighting mode: when enabled, soft GPU diffusion blur makes it look identical to YouTube's ambient mode
|
||||
const useAmbient = Number(c.bgAmbientLighting) === 1;
|
||||
if (useAmbient) {
|
||||
const ambientBlur = Math.max(30, Math.min(100, Number(c.bgCanvasBlur) || 48));
|
||||
document.documentElement.style.setProperty('--bg-canvas-filter', `blur(${ambientBlur}px)`);
|
||||
} else if (method === 1 || method === 2) {
|
||||
document.documentElement.style.setProperty('--bg-canvas-filter', `blur(${bgBlur}px)`);
|
||||
} else {
|
||||
document.documentElement.style.setProperty('--bg-canvas-filter', 'none');
|
||||
@@ -4816,7 +5135,7 @@ window.cancelAnimFrame = (function () {
|
||||
}
|
||||
};
|
||||
window.applyBackgroundOpacitySettings = applyBackgroundOpacitySettings;
|
||||
applyBackgroundOpacitySettings(window.audioVisualizerTuning);
|
||||
applyBackgroundOpacitySettings(null);
|
||||
|
||||
// Eye Cursor Follower & 3D Tracking
|
||||
const mousePos = { x: null, y: null, active: false };
|
||||
@@ -5095,6 +5414,11 @@ window.cancelAnimFrame = (function () {
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgCanvasColor', label: 'Background Color', type: 'color' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgCanvasColorOpacity', label: 'Background Color Opacity', min: 0.00, max: 1.00, step: 0.01, unit: '' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgCanvasOpacity', label: 'Background Canvas Opacity', min: 0.00, max: 1.00, step: 0.01, unit: '' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgAmbientLighting', label: 'Ambient Lighting (1=YouTube Glow, 0=Filter)', min: 0, max: 1, step: 1, unit: '' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgAmbientIntensity', label: 'Ambient Glow Brightness', min: 0.10, max: 2.50, step: 0.05, unit: 'x' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgAmbientSpread', label: 'Ambient Glow Spread / Size', min: 0.30, max: 2.00, step: 0.05, unit: 'x' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgAmbientSaturation', label: 'Ambient Glow Saturation', min: 0.50, max: 3.50, step: 0.05, unit: 'x' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgAmbientSmoothness', label: 'Ambient Video Transition Speed', min: 0.01, max: 0.25, step: 0.01, unit: '' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgBlurMethod', label: 'Blur Engine (0=Canvas 2D, 1=GPU CSS, 2=Hybrid)', min: 0, max: 2, step: 1, unit: '' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgCanvasBlur', label: 'Blur Radius', min: 0, max: 300, step: 1, unit: 'px' },
|
||||
{ section: 'Video & Ambient Background Canvas', key: 'bgCanvasBrightness', label: 'Brightness', min: 0.10, max: 3.00, step: 0.05, unit: 'x' },
|
||||
@@ -5367,13 +5691,17 @@ window.cancelAnimFrame = (function () {
|
||||
<div class="f0ck-tuner-body">
|
||||
<div class="f0ck-tuner-presets-bar">
|
||||
<div style="font-size: 11px; opacity: 0.85; font-weight: 700; display: flex; align-items: center; gap: 6px;">
|
||||
<i class="fa-solid fa-film"></i> Video & Onara Background Settings
|
||||
<i class="fa-solid fa-film"></i> Background Settings
|
||||
</div>
|
||||
<div class="f0ck-tuner-presets-actions">
|
||||
<button type="button" id="bg-tuner-copy" class="f0ck-tuner-btn-save-preset" title="Copy background settings as JSON"><i class="fa-solid fa-copy"></i> Copy Settings</button>
|
||||
<button type="button" id="bg-tuner-reset" class="f0ck-tuner-btn-factory-reset" title="Reset background settings to defaults"><i class="fa-solid fa-rotate-left"></i> Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f0ck-tuner-mode-bar" style="display: flex; gap: 6px; padding: 6px 12px; background: rgba(255,255,255,0.04); border-bottom: 1px solid rgba(255,255,255,0.08);">
|
||||
<button type="button" id="bg-mode-btn-standard" class="f0ck-tuner-subtab-btn active" style="flex: 1; padding: 6px 10px; font-size: 11px; text-align: center;">Standard View</button>
|
||||
<button type="button" id="bg-mode-btn-onara" class="f0ck-tuner-subtab-btn" style="flex: 1; padding: 6px 10px; font-size: 11px; text-align: center;"><i class="fa-solid fa-expand"></i> Onara Mode Only</button>
|
||||
</div>
|
||||
${bgRowsHtml}
|
||||
</div>
|
||||
</div>
|
||||
@@ -5407,7 +5735,7 @@ window.cancelAnimFrame = (function () {
|
||||
// ── Audio Presets & Events ──────────────────────────────────────────────
|
||||
const BUILTIN_PRESETS = {
|
||||
'Default': getEffectiveDefaultTuning(),
|
||||
'Onara': Object.assign({}, DEFAULT_AUDIO_TUNING),
|
||||
'Onara': Object.assign({}, DEFAULT_AUDIO_TUNING, DEFAULT_ONARA_TUNING),
|
||||
'Reactor': {
|
||||
useCustomColor: 0,
|
||||
visualizerColor: "#241f31",
|
||||
@@ -5995,68 +6323,125 @@ window.cancelAnimFrame = (function () {
|
||||
});
|
||||
});
|
||||
|
||||
// ── Background Sliders Event Listeners ─────────────────────────────────
|
||||
// ── Background Sliders Event Listeners (Standard vs Onara mode) ────────
|
||||
let activeBgTunerMode = isCurrentlyInOnara() ? 'onara' : 'standard';
|
||||
|
||||
const syncBgSlidersDisplay = () => {
|
||||
const isO = activeBgTunerMode === 'onara';
|
||||
const sourceObj = isO ? (window.onaraTuning || DEFAULT_ONARA_TUNING) : (window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING);
|
||||
const defaultObj = isO ? DEFAULT_ONARA_TUNING : DEFAULT_AUDIO_TUNING;
|
||||
|
||||
const stdBtn = panel.querySelector('#bg-mode-btn-standard');
|
||||
const onaraBtn = panel.querySelector('#bg-mode-btn-onara');
|
||||
if (stdBtn) stdBtn.classList.toggle('active', !isO);
|
||||
if (onaraBtn) onaraBtn.classList.toggle('active', isO);
|
||||
|
||||
backgroundSliders.forEach(s => {
|
||||
const input = panel.querySelector(`#input-bg-${s.key}`);
|
||||
const valEl = panel.querySelector(`#val-bg-${s.key}`);
|
||||
if (!input || !valEl) return;
|
||||
const val = sourceObj[s.key] !== undefined ? sourceObj[s.key] : defaultObj[s.key];
|
||||
input.value = val;
|
||||
if (s.type === 'color') {
|
||||
valEl.textContent = val;
|
||||
} else {
|
||||
const num = Number(val);
|
||||
const displayVal = Number.isInteger(num) ? num : parseFloat(num.toFixed(3));
|
||||
valEl.textContent = `${displayVal}${s.unit || ''}`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
panel.querySelector('#bg-mode-btn-standard')?.addEventListener('click', () => {
|
||||
activeBgTunerMode = 'standard';
|
||||
syncBgSlidersDisplay();
|
||||
applyBackgroundOpacitySettings(window.audioVisualizerTuning, false);
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage('Tuning Standard Background', 1500, 'info');
|
||||
}
|
||||
});
|
||||
|
||||
panel.querySelector('#bg-mode-btn-onara')?.addEventListener('click', () => {
|
||||
activeBgTunerMode = 'onara';
|
||||
syncBgSlidersDisplay();
|
||||
applyBackgroundOpacitySettings(window.onaraTuning, true);
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage('Tuning Onara Mode Background', 1500, 'info');
|
||||
}
|
||||
});
|
||||
|
||||
backgroundSliders.forEach(s => {
|
||||
const input = panel.querySelector(`#input-bg-${s.key}`);
|
||||
const valEl = panel.querySelector(`#val-bg-${s.key}`);
|
||||
if (!input || !valEl) return;
|
||||
input.addEventListener('input', () => {
|
||||
const isO = activeBgTunerMode === 'onara';
|
||||
const targetObj = isO ? window.onaraTuning : window.audioVisualizerTuning;
|
||||
const storageKey = isO ? 'f0ck_onara_tuning' : 'f0ck_audio_tuning';
|
||||
|
||||
if (s.type === 'color') {
|
||||
window.audioVisualizerTuning[s.key] = input.value;
|
||||
targetObj[s.key] = input.value;
|
||||
valEl.textContent = input.value;
|
||||
} else {
|
||||
const parsed = parseFloat(input.value);
|
||||
window.audioVisualizerTuning[s.key] = parsed;
|
||||
targetObj[s.key] = parsed;
|
||||
const displayVal = Number.isInteger(parsed) ? parsed : parseFloat(parsed.toFixed(3));
|
||||
valEl.textContent = `${displayVal}${s.unit || ''}`;
|
||||
}
|
||||
|
||||
applyBackgroundOpacitySettings(window.audioVisualizerTuning);
|
||||
applyBackgroundOpacitySettings(targetObj, isO);
|
||||
|
||||
try {
|
||||
localStorage.setItem('f0ck_audio_tuning', JSON.stringify(window.audioVisualizerTuning));
|
||||
localStorage.setItem(storageKey, JSON.stringify(targetObj));
|
||||
} catch (e) {}
|
||||
});
|
||||
});
|
||||
|
||||
panel.querySelector('#bg-tuner-reset')?.addEventListener('click', () => {
|
||||
const isO = activeBgTunerMode === 'onara';
|
||||
if (isO) {
|
||||
window.onaraTuning = Object.assign({}, DEFAULT_ONARA_TUNING);
|
||||
try {
|
||||
localStorage.setItem('f0ck_onara_tuning', JSON.stringify(window.onaraTuning));
|
||||
} catch (e) {}
|
||||
syncBgSlidersDisplay();
|
||||
applyBackgroundOpacitySettings(window.onaraTuning, true);
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage('Onara background settings reset to defaults', 2000, 'info');
|
||||
}
|
||||
} else {
|
||||
const defaults = DEFAULT_AUDIO_TUNING;
|
||||
backgroundSliders.forEach(s => {
|
||||
window.audioVisualizerTuning[s.key] = defaults[s.key];
|
||||
const input = panel.querySelector(`#input-bg-${s.key}`);
|
||||
const valEl = panel.querySelector(`#val-bg-${s.key}`);
|
||||
if (input) input.value = defaults[s.key];
|
||||
if (valEl) {
|
||||
if (s.type === 'color') {
|
||||
valEl.textContent = defaults[s.key];
|
||||
} else {
|
||||
const num = Number(defaults[s.key]);
|
||||
const displayVal = Number.isInteger(num) ? num : parseFloat(num.toFixed(3));
|
||||
valEl.textContent = `${displayVal}${s.unit || ''}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
applyBackgroundOpacitySettings(window.audioVisualizerTuning);
|
||||
syncBgSlidersDisplay();
|
||||
applyBackgroundOpacitySettings(window.audioVisualizerTuning, false);
|
||||
try {
|
||||
localStorage.setItem('f0ck_audio_tuning', JSON.stringify(window.audioVisualizerTuning));
|
||||
} catch (e) {}
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage('Background settings reset to default', 2000, 'info');
|
||||
window.flashMessage('Standard background settings reset to default', 2000, 'info');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
panel.querySelector('#bg-tuner-copy')?.addEventListener('click', () => {
|
||||
const isO = activeBgTunerMode === 'onara';
|
||||
const targetObj = isO ? window.onaraTuning : window.audioVisualizerTuning;
|
||||
const bgCfg = {};
|
||||
backgroundSliders.forEach(s => {
|
||||
bgCfg[s.key] = window.audioVisualizerTuning[s.key];
|
||||
bgCfg[s.key] = targetObj[s.key];
|
||||
});
|
||||
navigator.clipboard.writeText(JSON.stringify(bgCfg, null, 2)).then(() => {
|
||||
if (typeof window.flashMessage === 'function') {
|
||||
window.flashMessage('Background settings copied to clipboard!', 2500, 'success');
|
||||
window.flashMessage(`${isO ? 'Onara' : 'Standard'} background settings copied to clipboard!`, 2500, 'success');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize initial slider state in tuner
|
||||
syncBgSlidersDisplay();
|
||||
|
||||
panel.querySelector('#f0ck-tuner-copy')?.addEventListener('click', () => {
|
||||
const copyBtn = panel.querySelector('#f0ck-tuner-copy');
|
||||
const text = JSON.stringify(window.audioVisualizerTuning, null, 2);
|
||||
@@ -7032,7 +7417,7 @@ window.cancelAnimFrame = (function () {
|
||||
const bOpacity = Math.min(1, Math.max(0, cfg.barOpacity !== undefined ? Number(cfg.barOpacity) : 0.85));
|
||||
const bGlow = Math.max(0, cfg.barGlow !== undefined ? cfg.barGlow : 8);
|
||||
|
||||
const feedToBg = Number(cfg.feedAudioToBg !== undefined ? cfg.feedAudioToBg : 0) === 1;
|
||||
const feedToBg = Number(cfg.feedAudioToBg !== undefined ? cfg.feedAudioToBg : 1) === 1;
|
||||
const showBarsOnPlayer = cfg.enableBars !== undefined ? Number(cfg.enableBars) === 1 : true;
|
||||
const showBars = showBarsOnPlayer || feedToBg;
|
||||
canvas.style.opacity = showBarsOnPlayer ? '1' : '0';
|
||||
@@ -8686,7 +9071,7 @@ window.cancelAnimFrame = (function () {
|
||||
// Draw inner eye canvas centered behind the item content (respecting sidebar width)
|
||||
const srcW = innerEyeCanvas.width;
|
||||
const srcH = innerEyeCanvas.height;
|
||||
const bgScale = cfg.bgCanvasScale !== undefined ? Number(cfg.bgCanvasScale) : 3;
|
||||
const bgScale = cfg.bgCanvasScale !== undefined ? Number(cfg.bgCanvasScale) : 2.15;
|
||||
|
||||
// #bg canvas is already positioned to the free space respecting the sidebar
|
||||
const contentW = bw;
|
||||
@@ -8698,8 +9083,8 @@ window.cancelAnimFrame = (function () {
|
||||
const dy = (bh - dh) / 2;
|
||||
|
||||
// Apply blur & brightness via CSS filter (smooth at display resolution)
|
||||
const blurPx = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 30;
|
||||
const brightVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.45;
|
||||
const blurPx = cfg.bgCanvasBlur !== undefined ? Number(cfg.bgCanvasBlur) : 31;
|
||||
const brightVal = cfg.bgCanvasBrightness !== undefined ? Number(cfg.bgCanvasBrightness) : 0.6;
|
||||
const filterParts = [];
|
||||
if (blurPx > 0) filterParts.push(`blur(${blurPx}px)`);
|
||||
if (brightVal !== 1) filterParts.push(`brightness(${brightVal})`);
|
||||
@@ -10384,7 +10769,7 @@ window.cancelAnimFrame = (function () {
|
||||
canvas.classList.remove('fader-out', 'fast-fade');
|
||||
canvas.classList.add('fader-in');
|
||||
canvas.style.transition = 'none';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 0.95)';
|
||||
} else {
|
||||
canvas.classList.add('fast-fade');
|
||||
canvas.classList.remove('fader-in');
|
||||
@@ -10655,9 +11040,13 @@ window.cancelAnimFrame = (function () {
|
||||
const _newEls = _container.querySelectorAll('.content, ._204863, .item_title');
|
||||
_newEls.forEach(el => {
|
||||
el.classList.remove('slide-next', 'slide-prev', 'slide-out-left', 'slide-out-right', 'fade-out-zoom', 'fade-in-zoom');
|
||||
if (useOnara) {
|
||||
el.classList.add('fade-in-zoom');
|
||||
} else {
|
||||
el.classList.add(options.direction === 'next' ? 'slide-next' : 'slide-prev');
|
||||
}
|
||||
});
|
||||
} else if (options.transition === 'fade-zoom') {
|
||||
} else if (options.transition === 'fade-zoom' || useOnara) {
|
||||
const _newEls = _container.querySelectorAll('.content, ._204863, .item_title');
|
||||
_newEls.forEach(el => {
|
||||
el.classList.remove('slide-next', 'slide-prev', 'slide-out-left', 'slide-out-right', 'fade-out-zoom', 'fade-in-zoom');
|
||||
@@ -10701,7 +11090,7 @@ window.cancelAnimFrame = (function () {
|
||||
_canvas.classList.add('fader-in');
|
||||
if (useOnara) {
|
||||
_canvas.style.transition = 'none';
|
||||
_canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
|
||||
_canvas.style.opacity = 'var(--bg-canvas-opacity, 0.95)';
|
||||
}
|
||||
}
|
||||
if (window.initBackground) window.initBackground();
|
||||
@@ -10903,9 +11292,13 @@ window.cancelAnimFrame = (function () {
|
||||
const newEls = container.querySelectorAll('.content, ._204863, .item_title');
|
||||
newEls.forEach(el => {
|
||||
el.classList.remove('slide-next', 'slide-prev', 'slide-out-left', 'slide-out-right', 'fade-out-zoom', 'fade-in-zoom');
|
||||
if (useOnara) {
|
||||
el.classList.add('fade-in-zoom');
|
||||
} else {
|
||||
el.classList.add(options.direction === 'next' ? 'slide-next' : 'slide-prev');
|
||||
}
|
||||
});
|
||||
} else if (options.transition === 'fade-zoom') {
|
||||
} else if (options.transition === 'fade-zoom' || useOnara) {
|
||||
const newEls = container.querySelectorAll('.content, ._204863, .item_title');
|
||||
newEls.forEach(el => {
|
||||
el.classList.remove('slide-next', 'slide-prev', 'slide-out-left', 'slide-out-right', 'fade-out-zoom', 'fade-in-zoom');
|
||||
@@ -10975,7 +11368,7 @@ window.cancelAnimFrame = (function () {
|
||||
canvas.classList.add('fader-in');
|
||||
if (useOnara) {
|
||||
canvas.style.transition = 'none';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
|
||||
canvas.style.opacity = 'var(--bg-canvas-opacity, 0.95)';
|
||||
}
|
||||
}
|
||||
if (window.initBackground) window.initBackground();
|
||||
@@ -11121,13 +11514,14 @@ window.cancelAnimFrame = (function () {
|
||||
if (thumbnail && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
|
||||
e.preventDefault();
|
||||
if (isOnaraActive()) {
|
||||
const wasOpen = document.body.classList.contains('onara-modal-open');
|
||||
document.querySelectorAll('.onara-active').forEach(el => el.classList.remove('onara-active'));
|
||||
thumbnail.classList.add('onara-active');
|
||||
if (document.activeElement && document.activeElement !== thumbnail && typeof document.activeElement.blur === 'function') {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
openOnaraModal();
|
||||
if (typeof window.paintImmediateBgThumb === 'function') {
|
||||
if (!wasOpen && typeof window.paintImmediateBgThumb === 'function') {
|
||||
window.paintImmediateBgThumb(thumbnail);
|
||||
}
|
||||
}
|
||||
@@ -11299,18 +11693,26 @@ window.cancelAnimFrame = (function () {
|
||||
const isPrev = link.id === 'prev' || link.classList.contains('nav-prev');
|
||||
const direction = isNext ? 'next' : (isPrev ? 'prev' : null);
|
||||
|
||||
const isModalOpen = document.body.classList.contains('onara-modal-open');
|
||||
const isGridPage = !!document.querySelector('.index-layout-wrapper, .index-container, .posts');
|
||||
const useOnara = isOnaraActive() && (isGridPage || isModalOpen);
|
||||
|
||||
if (direction) {
|
||||
const outEls = document.querySelectorAll('.content, ._204863, .item_title');
|
||||
outEls.forEach(el => {
|
||||
el.classList.remove('slide-out-left', 'slide-out-right', 'slide-next', 'slide-prev');
|
||||
el.classList.remove('slide-out-left', 'slide-out-right', 'slide-next', 'slide-prev', 'fade-out-zoom', 'fade-in-zoom');
|
||||
if (useOnara) {
|
||||
el.classList.add('fade-out-zoom');
|
||||
} else {
|
||||
el.classList.add(direction === 'next' ? 'slide-out-left' : 'slide-out-right');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (link.href.match(/\/p\/\d+/) || link.href.match(/[?&]page=\d+/)) {
|
||||
loadPageAjax(link.href);
|
||||
} else {
|
||||
loadItemAjax(link.href, true, { direction });
|
||||
loadItemAjax(link.href, true, { direction, transition: useOnara ? 'fade-zoom' : null });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user