perf(immersive): improve background quality while maintaining low CPU
- Increase canvas size from 8x8 to 64x64 to reduce visible pixelation - Add small CSS blur(40px) to smooth the result - Key: blur(40px) on 64x64 is much cheaper than blur(120px) on full image - Adjusted brightness slightly darker (0.55x) for better text contrast
This commit is contained in:
1 parent
f012ba33f4
commit
282fffc6a4
1 file changed
+29
-29
@@ -9,9 +9,9 @@
|
|||||||
let isLoading = $state(true);
|
let isLoading = $state(true);
|
||||||
let currentArtwork = $state('');
|
let currentArtwork = $state('');
|
||||||
|
|
||||||
// Generate a tiny blurred version using Canvas (GPU-free approach)
|
// Generate a small blurred version using Canvas
|
||||||
// Instead of CSS blur(120px) which kills WebKit performance,
|
// Key insight: blur(30px) on a 64x64 image is MUCH cheaper than blur(120px) on full image
|
||||||
// we resize the image to 8x8 pixels and scale it up - natural blur effect
|
// The small source + small blur = smooth result with minimal CPU
|
||||||
async function generateBlurredBackground(imageUrl: string): Promise<void> {
|
async function generateBlurredBackground(imageUrl: string): Promise<void> {
|
||||||
if (!canvasRef || !imageUrl) return;
|
if (!canvasRef || !imageUrl) return;
|
||||||
|
|
||||||
@@ -22,35 +22,34 @@
|
|||||||
img.crossOrigin = 'anonymous';
|
img.crossOrigin = 'anonymous';
|
||||||
|
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
// Draw to tiny size (8x8) - this creates natural blur when scaled
|
// Use 64x64 - large enough to avoid blocky pixels, small enough to be efficient
|
||||||
const tinySize = 8;
|
const size = 64;
|
||||||
canvasRef!.width = tinySize;
|
canvasRef!.width = size;
|
||||||
canvasRef!.height = tinySize;
|
canvasRef!.height = size;
|
||||||
|
|
||||||
// Draw image scaled down to 8x8
|
// Draw image scaled down
|
||||||
ctx.drawImage(img, 0, 0, tinySize, tinySize);
|
ctx.drawImage(img, 0, 0, size, size);
|
||||||
|
|
||||||
// Slightly boost saturation by adjusting colors
|
// Apply color adjustments
|
||||||
const imageData = ctx.getImageData(0, 0, tinySize, tinySize);
|
const imageData = ctx.getImageData(0, 0, size, size);
|
||||||
const data = imageData.data;
|
const data = imageData.data;
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
// Simple saturation boost
|
|
||||||
const r = data[i];
|
const r = data[i];
|
||||||
const g = data[i + 1];
|
const g = data[i + 1];
|
||||||
const b = data[i + 2];
|
const b = data[i + 2];
|
||||||
const avg = (r + g + b) / 3;
|
const avg = (r + g + b) / 3;
|
||||||
|
|
||||||
// Saturation factor (1.3x)
|
// Saturation boost (1.3x)
|
||||||
const satFactor = 1.3;
|
const satFactor = 1.3;
|
||||||
data[i] = Math.min(255, avg + (r - avg) * satFactor);
|
let newR = avg + (r - avg) * satFactor;
|
||||||
data[i + 1] = Math.min(255, avg + (g - avg) * satFactor);
|
let newG = avg + (g - avg) * satFactor;
|
||||||
data[i + 2] = Math.min(255, avg + (b - avg) * satFactor);
|
let newB = avg + (b - avg) * satFactor;
|
||||||
|
|
||||||
// Brightness reduction (0.6x)
|
// Brightness reduction (0.55x) - slightly darker for better text contrast
|
||||||
data[i] = data[i] * 0.6;
|
data[i] = Math.min(255, Math.max(0, newR * 0.55));
|
||||||
data[i + 1] = data[i + 1] * 0.6;
|
data[i + 1] = Math.min(255, Math.max(0, newG * 0.55));
|
||||||
data[i + 2] = data[i + 2] * 0.6;
|
data[i + 2] = Math.min(255, Math.max(0, newB * 0.55));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.putImageData(imageData, 0, 0);
|
ctx.putImageData(imageData, 0, 0);
|
||||||
@@ -96,16 +95,17 @@
|
|||||||
|
|
||||||
.background-canvas {
|
.background-canvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* Extend beyond viewport for seamless edges */
|
/* Extend beyond viewport to hide blur edges */
|
||||||
inset: -50px;
|
inset: -80px;
|
||||||
width: calc(100% + 100px);
|
width: calc(100% + 160px);
|
||||||
height: calc(100% + 100px);
|
height: calc(100% + 160px);
|
||||||
/* Scale up tiny canvas - creates natural blur effect */
|
/* Smooth interpolation when scaling up */
|
||||||
/* Using image-rendering: auto for smooth interpolation */
|
|
||||||
image-rendering: auto;
|
image-rendering: auto;
|
||||||
/* GPU layer for smooth transitions */
|
/* Small blur to smooth out the 64x64 canvas - MUCH cheaper than 120px on full image */
|
||||||
transform: scale(1.1) translateZ(0);
|
filter: blur(40px);
|
||||||
will-change: opacity;
|
/* GPU layer for performance */
|
||||||
|
transform: scale(1.15) translateZ(0);
|
||||||
|
will-change: opacity, filter;
|
||||||
transition: opacity 500ms ease-out;
|
transition: opacity 500ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user