fix(desktop): corrige flicker e salto lateral no morph da ilha - #18
Merged
Conversation
A abertura e o fechamento do chat piscavam mostrando o desktop, e a pílula saltava ~131px para o lado ao abrir. Instrumentando a transição (island-debug) apareceram três causas distintas, todas medidas: 1. Movimento lateral no mesmo SetWindowPos do resize. Centralizar o painel exigia mover a janela 132px físicos, e a ilha só ficava parada porque o CSS cancelava esse deslocamento via `left: calc(% - px)`. A compensação depende de o WebView refazer o layout no mesmo frame do resize; quando ele apresentava um frame com o layout antigo já na posição nova, a pílula saltava. A janela passa a ter largura fixa (ISLAND_WINDOW_WIDTH) em todos os modos: abrir mexe só na altura. Sem movimento não há o que compensar. As formas mais estreitas são centralizadas por dentro e o excedente é recortado da janela por SetWindowRgn, para as faixas transparentes não captarem cliques do desktop. 2. Tempo morto entre o fim da animação e o commit nativo. No fechamento havia ~240ms com a janela ainda expandida e transparente, já com a pílula desenhada — desktop visível em volta. Vinha de setMinSize e setResizable (invisíveis, ~150ms de IPC) sentados no caminho crítico, mais dois requestAnimationFrame por barreira. Os IPCs foram para o prepare e as barreiras caíram para um frame. 3. Faixa branca em volta da pílula. A região era montada a partir do retângulo visual cru, ignorando o recuo de 1px com que as superfícies são desenhadas, e o Rust ainda somava +1 — sobravam até 3px que a janela incluía e o CSS nunca pintava, expondo o fundo padrão branco do WebView2. A região agora sai do retângulo já recuado, arredondando para dentro, e a borda virou anel inset para não cair sobre a linha de corte. Também: reaplica a região em onScaleChanged, senão arrastar entre monitores de DPI diferente recorta a pílula; e a duração do morph caiu de 260ms para 170ms. Verificação: `tsc --noEmit` limpo. Os testes (vitest) e o `cargo check` não rodam no WSL deste ambiente — bug de optional deps do rollup e dependência de libpipewire, ambos alheios a estas mudanças. As expectativas de posição afetadas foram atualizadas, mas não executadas; o app foi validado manualmente no Windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Consegui rodar a suíte pelo lado Windows (`cmd.exe /c npx vitest run`) — o node_modules tem os binários win32 do rollup, que é o motivo de ela falhar no WSL. Com isso as falhas do CI ficaram visíveis: de 32 para 5. - `islandDebugEnabled` assumia `window`. A lane `unit` roda em Node e chama as funções de janela com os mocks do Tauri, então a instrumentação derrubava o teste inteiro. Agora tem guarda. - `onScaleChanged` faltava no mock do Tauri, e o efeito novo do BarApp quebrava na montagem. - O teste de `transitionend` checava o commit na hora, mas ele passou a ser adiado um frame; agora espera. - Expectativas de posição em `floating-compact-bounds` e `enter-floating-mode` ainda descreviam centralização e janela de 168px. Restam 5 falhas em `BarApp.test.tsx`, todas do mesmo tipo: asserções sobre `set_window_bounds`/`animate_window_bounds` que agora também veem chamadas de `set_window_region`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problema
Abrir e fechar o chat piscava mostrando o desktop, e a pílula saltava ~131px para o lado ao abrir.
Diagnóstico
Adicionei instrumentação (
island-debug.ts, opt-in viawindow.__islandDebug = true) para separar três relógios que se confundiam: quando oSetWindowPosretorna, quando o WebView2 entrega o viewport novo, e quando o CSS anima. Os números descartaram a hipótese inicial (resize assíncrono do WebView2 — oviewport-timelinemostrouframes=1, sem dessincronia) e revelaram três causas reais:1. Movimento lateral junto com o resize. Centralizar o painel exigia mover a janela 132px físicos no mesmo
SetWindowPos. A ilha só ficava parada porque o CSS cancelava esse deslocamento vialeft: calc(% - px)— compensação que depende de o WebView refazer o layout no mesmo frame. Quando ele apresentava um frame com o layout antigo já na posição nova, a pílula saltava.2. Tempo morto no fechamento. ~240ms com a janela ainda expandida e transparente, já com a pílula desenhada:
3. Faixa branca em volta da pílula. A região era montada a partir do retângulo visual cru (168×34), ignorando o recuo de 1px das superfícies, e o Rust ainda somava
+1. Em DPI 1,25: região cobria 133→344 físicos, CSS pintava 133,75→341,25. Os até 3px de sobra expunham o fundo padrão branco do WebView2.Solução
ISLAND_WINDOW_WIDTH) em todos os modos — abrir mexe só na altura. Sem movimento, não há o que compensar, e a classe inteira do artefato desaparece.set_window_region(novo comando Rust,SetWindowRgn) recorta a área pintada e clicável, para as faixas transparentes não engolirem cliques do desktop. Nunca fica sem região: durante o morph usa uma arredondada do tamanho da transição, porque a janela sem recorte vira um retângulo cru e o Windows desenha moldura em volta.setMinSize/setResizablemovidos para o prepare; barreiras derequestAnimationFramereduzidas a um frame; recorte aplicado antes do encolhimento, com a escala já lida.insetem vez deborder, para não cair sobre a linha de corte.onScaleChangedreaplica a região — sem isso, arrastar entre monitores de DPI diferente recorta a pílula.Verificação
tsc --noEmitlimpo. Validado manualmente no Windows 11 (build 26200).cargo check— ambos falham no WSL deste ambiente por motivos alheios a estas mudanças (bug de optional deps do rollup;libspa-sysexigindolibpipewire). As expectativas de posição afetadas emwindow-transition.test.ts,floating-quick-menu-mode.test.tsefloating-checklist-mode.test.tsforam atualizadas para o novo comportamento (origem preservada em vez de centralização), mas precisam rodar no Windows antes do merge.Notas para revisão
island-debug.tsé instrumentação permanente, opt-in e sem custo quando desligada. Se preferirem fora do repositório, é só remover o arquivo e as chamadasislandLog/sampleViewportFrames.resizeAroundCentervirouresizeFromOrigin: o painel agora abre alinhado pela borda esquerda da pílula. Expand e collapse continuam inversas exatas, então a pílula volta no pixel de onde saiu.🤖 Generated with Claude Code