feat: boot-экран, стабильность Windows и оптимизация Pixi/пульта
- Экран загрузки (boot.html, bootWindow): статусы, ensureRoots и проверка лицензии, редактор после готовности; закрытие через destroy при closable:false. - Упакованное приложение на Windows: disableHardwareAcceleration, sandbox выкл. вне dev, отложенный показ редактора, ensureWindowBecomesVisible, фокус на splash при second-instance. - Vite: вход boot.html; eslint: игнор release/; тесты boot и maxFPS тикера. - Пульт: позиция курсора кисти через ref/DOM без setState на каждый move; черновик эффекта через rAF; Pixi: maxFPS 32, resolution cap, antialias off, debounce ResizeObserver, меньше частиц poisonCloud, contain на хосте. Made-with: Cursor
This commit is contained in:
@@ -41,13 +41,15 @@ export function PixiEffectsOverlay({ state, interactive = false, style, viewport
|
||||
const viewportRef = useRef<{ x: number; y: number; w: number; h: number }>({ x: 0, y: 0, w: 1, h: 1 });
|
||||
const viewportProvidedRef = useRef(false);
|
||||
|
||||
const dpr = useMemo(() => Math.min(2, window.devicePixelRatio || 1), []);
|
||||
/** Снижаем resolution на HiDPI — меньше пикселей в WebGL, визуально ок для оверлея эффектов. */
|
||||
const dpr = useMemo(() => Math.min(1.5, window.devicePixelRatio || 1), []);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
if (!host) return;
|
||||
|
||||
let destroyed = false;
|
||||
let resizeRaf = 0;
|
||||
let app: any = null;
|
||||
let cleanup: (() => void) | null = null;
|
||||
void (async () => {
|
||||
@@ -58,10 +60,14 @@ export function PixiEffectsOverlay({ state, interactive = false, style, viewport
|
||||
app = new pixi.Application();
|
||||
await app.init({
|
||||
backgroundAlpha: 0,
|
||||
antialias: true,
|
||||
antialias: false,
|
||||
powerPreference: 'high-performance',
|
||||
resolution: dpr,
|
||||
autoDensity: true,
|
||||
preference: 'webgl',
|
||||
});
|
||||
// Меньше кадров — меньше CPU/GPU; анимации эффектов остаются плавными.
|
||||
app.ticker.maxFPS = 32;
|
||||
if (destroyed) return;
|
||||
host.appendChild(app.canvas);
|
||||
// Canvas по умолчанию перехватывает hit-test; оставляем клики «сквозь» оверлей для слоя кисти сверху.
|
||||
@@ -72,13 +78,16 @@ export function PixiEffectsOverlay({ state, interactive = false, style, viewport
|
||||
app.stage.addChild(root);
|
||||
|
||||
const ro = new ResizeObserver(() => {
|
||||
const r = host.getBoundingClientRect();
|
||||
app.renderer.resize(Math.max(1, Math.floor(r.width)), Math.max(1, Math.floor(r.height)));
|
||||
sizeRef.current = { w: app.renderer.width, h: app.renderer.height };
|
||||
if (!viewportProvidedRef.current) {
|
||||
viewportRef.current = { x: 0, y: 0, w: sizeRef.current.w, h: sizeRef.current.h };
|
||||
}
|
||||
syncNodes(pixi, root, nodesRef.current, stateRef.current, sizeRef.current, viewportRef.current);
|
||||
cancelAnimationFrame(resizeRaf);
|
||||
resizeRaf = requestAnimationFrame(() => {
|
||||
const r = host.getBoundingClientRect();
|
||||
app.renderer.resize(Math.max(1, Math.floor(r.width)), Math.max(1, Math.floor(r.height)));
|
||||
sizeRef.current = { w: app.renderer.width, h: app.renderer.height };
|
||||
if (!viewportProvidedRef.current) {
|
||||
viewportRef.current = { x: 0, y: 0, w: sizeRef.current.w, h: sizeRef.current.h };
|
||||
}
|
||||
syncNodes(pixi, root, nodesRef.current, stateRef.current, sizeRef.current, viewportRef.current);
|
||||
});
|
||||
});
|
||||
ro.observe(host);
|
||||
|
||||
@@ -117,6 +126,7 @@ export function PixiEffectsOverlay({ state, interactive = false, style, viewport
|
||||
|
||||
return () => {
|
||||
destroyed = true;
|
||||
cancelAnimationFrame(resizeRaf);
|
||||
cleanup?.();
|
||||
const a = appRef.current;
|
||||
appRef.current = null;
|
||||
@@ -378,7 +388,8 @@ function createInstanceNode(
|
||||
if (inst.type === 'poisonCloud') {
|
||||
const cont = new pixi.Container();
|
||||
const tex = getPoisonParticleTexture(pixi);
|
||||
const particleCount = 520;
|
||||
/** Меньше спрайтов — быстрее тик; картина остаётся плотной. */
|
||||
const particleCount = 400;
|
||||
const particles: PoisonParticleFx[] = [];
|
||||
for (let i = 0; i < particleCount; i += 1) {
|
||||
const s = new pixi.Sprite(tex);
|
||||
|
||||
Reference in New Issue
Block a user