optimize both devicesa

This commit is contained in:
2026-04-24 13:04:00 +07:00
parent 8bf72addb2
commit 942b5c56e2
6 changed files with 590 additions and 591 deletions
+225
View File
@@ -0,0 +1,225 @@
import init, { MatrixEngine } from "./matrix_engine.js";
let engine;
let wasm;
let ctx;
let atlasCanvas, atlasCtx;
let width, height;
let fontSize = 16;
let isMobile = false,
isVpnOn = false,
isDarkMode = true;
const chars =
"0101アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホ마미무메모야유요라릴레로와원>_±÷×=≠≈≡≤≥";
function buildAtlas() {
// Создаем или пересоздаем атлас под текущий fontSize
atlasCanvas = new OffscreenCanvas(chars.length * fontSize, fontSize * 2);
atlasCtx = atlasCanvas.getContext("2d", { alpha: false });
let r, g, b;
if (isVpnOn && isDarkMode) {
r = 139;
g = 61;
b = 255;
} else if (!isVpnOn && isDarkMode) {
r = 0;
g = 229;
b = 242;
} else if (isVpnOn && !isDarkMode) {
r = 109;
g = 40;
b = 217;
} else {
r = 2;
g = 132;
b = 199;
}
atlasCtx.fillStyle = isDarkMode ? "rgb(10, 10, 12)" : "rgb(250, 250, 252)";
atlasCtx.fillRect(0, 0, atlasCanvas.width, atlasCanvas.height);
atlasCtx.font = `bold ${fontSize}px monospace`;
atlasCtx.textBaseline = "top";
atlasCtx.textAlign = "center";
const halfFs = fontSize / 2;
atlasCtx.fillStyle = `rgb(${r}, ${g}, ${b})`;
for (let i = 0; i < chars.length; i++)
atlasCtx.fillText(chars[i], i * fontSize + halfFs, 0);
atlasCtx.fillStyle = "rgb(255, 255, 255)";
for (let i = 0; i < chars.length; i++)
atlasCtx.fillText(chars[i], i * fontSize + halfFs, fontSize);
}
function getGlitchColor(type) {
let r, g, b;
if (isVpnOn && isDarkMode) {
r = 139;
g = 61;
b = 255;
} else if (!isVpnOn && isDarkMode) {
r = 0;
g = 229;
b = 242;
} else if (isVpnOn && !isDarkMode) {
r = 109;
g = 40;
b = 217;
} else {
r = 2;
g = 132;
b = 199;
}
if (type === 0) return isDarkMode ? "rgb(10, 10, 12)" : "rgb(250, 250, 252)";
if (type === 1) return `rgba(${r},${g},${b},0.9)`;
if (type === 2) return `rgba(${255 - r},${255 - g},${255 - b},0.7)`;
if (type === 3) return "rgba(255,255,255,0.95)";
return "rgba(255,20,80,0.95)";
}
self.onmessage = async (e) => {
const { type, payload } = e.data;
if (type === "INIT") {
ctx = payload.canvas.getContext("2d", { alpha: false });
width = payload.width;
height = payload.height;
isMobile = payload.isMobile;
isVpnOn = payload.isVpnOn;
isDarkMode = payload.isDarkMode;
fontSize = payload.fontSize || 16;
wasm = await init("./matrix_engine_bg.wasm");
engine = new MatrixEngine(width, height, fontSize);
engine.set_mobile(isMobile);
buildAtlas();
requestAnimationFrame(render);
}
// ДОБАВЛЯЕМ ПРОВЕРКУ: if (!engine) return; во всех остальных случаях
else if (type === "RESIZE") {
if (!engine) return;
width = payload.width;
height = payload.height;
fontSize = payload.fontSize || 16;
ctx.canvas.width = width;
ctx.canvas.height = height;
engine.set_mobile(payload.isMobile);
engine.resize(width, height);
buildAtlas();
} else if (type === "THEME") {
isVpnOn = payload.isVpnOn;
isDarkMode = payload.isDarkMode;
buildAtlas();
if (ctx) {
ctx.globalAlpha = 1.0;
ctx.fillStyle = isDarkMode ? "rgb(10, 10, 12)" : "rgb(250, 250, 252)";
ctx.fillRect(0, 0, width, height);
}
} else if (type === "MOUSE_MOVE") {
if (engine) engine.update_mouse(payload.x, payload.y);
} else if (type === "DRAW_START") {
if (engine) {
engine.set_drawing(true);
engine.trigger_glitch(payload.x, payload.y);
}
} else if (type === "DRAW_END") {
if (engine) engine.set_drawing(false);
}
};
function render() {
engine.tick();
// 1. Фон
ctx.globalAlpha = 1.0;
ctx.fillStyle = isDarkMode
? "rgba(10, 10, 12, 0.2)"
: "rgba(250, 250, 252, 0.2)";
ctx.fillRect(0, 0, width, height);
// 2. Читаем память Wasm и рисуем Задний план
const bgLen = engine.bg_len();
if (bgLen > 0) {
const bgData = new Float32Array(wasm.memory.buffer, engine.bg_ptr(), bgLen);
const bgF = fontSize * 0.6;
for (let i = 0; i < bgLen; i += 4) {
ctx.globalAlpha = bgData[i + 3];
ctx.drawImage(
atlasCanvas,
bgData[i + 2] * fontSize,
0,
fontSize,
fontSize,
bgData[i],
bgData[i + 1],
bgF,
bgF,
);
}
}
// 3. Читаем память Wasm и рисуем Передний план
const fgLen = engine.fg_len();
const fgData = new Float32Array(wasm.memory.buffer, engine.fg_ptr(), fgLen);
for (let i = 0; i < fgLen; i += 5) {
ctx.globalAlpha = fgData[i + 4];
ctx.drawImage(
atlasCanvas,
fgData[i + 2] * fontSize,
fgData[i + 3] * fontSize,
fontSize,
fontSize,
fgData[i],
fgData[i + 1],
fontSize,
fontSize,
);
}
// 4. Глитчи
const glLen = engine.glitch_len();
if (glLen > 0) {
ctx.globalAlpha = 1.0;
const glData = new Float32Array(
wasm.memory.buffer,
engine.glitch_ptr(),
glLen,
);
for (let i = 0; i < glLen; i += 5) {
ctx.fillStyle = getGlitchColor(glData[i + 4]);
ctx.fillRect(glData[i], glData[i + 1], glData[i + 2], glData[i + 3]);
}
}
// 5. След мыши
const gsLen = engine.glass_len();
if (gsLen > 0) {
const gsData = new Float32Array(
wasm.memory.buffer,
engine.glass_ptr(),
gsLen,
);
for (let i = 0; i < gsLen; i += 4) {
ctx.globalAlpha = gsData[i + 3];
ctx.drawImage(
atlasCanvas,
gsData[i + 2] * fontSize,
0,
fontSize,
fontSize,
gsData[i],
gsData[i + 1],
fontSize,
fontSize,
);
}
}
requestAnimationFrame(render);
}