Guia Web
Porta 5555, escala viewport e device preview no navegador.
Porta fixa e sessão
O login guarda sessão por origin (inclui porta), seja Supabase Auth ou Firebase Auth. kasy run --web usa 5555 para a sessão persistir entre execuções.
Escala viewport (0.93)
Flutter Web renderiza ~10% maior que o equivalente nativo. O kit aplica escala 0.93 na web para ficar alinhado ao design mobile.
Knobs em lib/core/web_viewport_scale.dart:
const bool kWebViewportScaleEnabled = true;
const double kWebViewportScale = 0.93;Nativo nunca escala (kIsWeb). Device preview desliga escala para simular tamanho real do celular.
Quanto mais perto de 1.0, maior fica tudo:
| Valor | Efeito |
|---|---|
1.00 | Tamanho cheio do Flutter Web (o original, sem escala) |
0.95 | Encolhe 5% (correção suave) |
0.93 | Encolhe ~7%, padrão do kit |
0.90 | Encolhe 10% (idêntico ao nativo, costuma ficar pequeno demais no monitor) |
A escala vale em todos os breakpoints da web, então não existe salto de tamanho ao cruzar um breakpoint. Ela também não substitui o design responsivo: desligue o knob e o app continua com breakpoints, tipografia responsiva e layouts adaptativos funcionando, só ~7% maior.
No desktop existe uma compensação a mais: se a tela do Mac/Windows estiver com escala de sistema alta, o app comprime além do 0.93 para não cortar o layout. A conta usa a largura da tela, não a da janela, então estreitar a janela do navegador só refluí o layout, não encolhe. O limite de desktop é a constante kWebViewportScaleDesktopBreakpoint (1024px) no mesmo arquivo.
Device preview (debug)
control/ctrl + shift + d liga o frame de iPhone/iPad no navegador (debug). No Mac use control (⌃), não command (⌘). Inspector: control/ctrl + shift + i. Também listados em Admin → Visão geral → Preview.
Na primeira vez (projeto novo ou storage limpo), o fundo do preview e o tema do app dentro da moldura seguem o modo do sistema (claro/escuro do macOS/Windows). O botão sol/lua no canto inferior direito muda só o canvas atrás do device; o ícone sol/lua na barra do preview muda o tema do app. As duas escolhas são salvas no localStorage e voltam iguais no próximo kasy run --web.
Fundo da página no reload
| Preview | Quem manda no fundo ao dar R (hot restart) ou recarregar a página |
|---|---|
| Ligado | O tema do próprio preview (o sol/lua do canvas). Mesmo trocando o tema do app dentro da moldura, o fundo segue o preview, então trabalhar no escuro não pisca branco no reload |
| Desligado | O tema global do app (claro, escuro ou sistema) |
Em release isso não existe, porque o preview só roda em debug na web: o fundo sempre segue o tema do app. Por baixo, o preview grava a decisão já resolvida na chave kasy.web_preview_chrome (dark, light ou off), e o script de boot do web/index.html lê só essa chave no arranque.
Não confunda com o DevInspector. Device Preview troca o tamanho de tela simulado. DevInspector (segurar um widget) identifica esse widget e copia o contexto pra IA. São duas ferramentas de debug diferentes.
Onboarding e autenticação
O preview não muda só o tamanho da moldura. Ele também define qual fluxo de auth você está testando no kasy run --web:
| Modo | Primeiro acesso | Guest / "Continuar sem conta" | Depois de sair |
|---|---|---|---|
| Preview iOS, Android ou iPad | Onboarding (igual nativo) | Sim, na tela Entrar (não em Cadastro) | /signin |
| Preview Desktop ou preview desligado | Vai direto pro Entrar | Não | /signin |
| Web real (celular, tablet ou desktop no browser, produção) | Vai direto pro Entrar | Não | /signin |
Layout ≠ fluxo. Abrir o app no Safari do iPhone ou no Chrome do tablet usa os breakpoints mobile/tablet (UI responsiva), mas o comportamento de conta continua sendo o da web: login obrigatório, sem onboarding, sem guest anônimo. Isso é intencional no preset SaaS do kit: trial, assinatura (RevenueCat/Stripe) e suporte precisam de um usuário identificável.
Use o preview em iOS / Android / iPad quando quiser validar onboarding, paywall, conta anônima e skip sem abrir simulador. Na web publicada (mobile incluído), o padrão é pedir conta antes de usar o app.
Navegação dentro do app: em Configurações → Cadastrar (ou Entrar), o preview mobile/tablet mostra a seta voltar igual ao nativo quando a rota foi aberta com push. No preview Desktop ou na web sem frame, essa seta some (entrada direta em /signin ou /signup).
Supabase: depois do loader ("criando sua conta"), confira em Authentication → Users. Se o dropdown da busca estiver em Email address, usuários anônimos somem da lista (não têm e-mail). Use Unified search ou busque pelo User ID de public.users. Detalhes em Troubleshooting.
Trocar a aba do toolbar (ex.: iPhone → Desktop) atualiza o redirect do app na hora. Se você estava no onboarding e mudou pra Desktop, o fluxo volta pro modo web.
Rota /onboarding
O GoRouter controla quem pode ficar em /onboarding:
| Situação | Para onde vai |
|---|---|
| Primeira instalação (nativo ou preview iOS / Android / iPad), sem sessão | Fluxo real de onboarding |
Já logado, guest com ID e onboarded, ou flag onboarding_completed | Home (não abre onboarding de novo) |
Digitar /onboarding com sessão estabelecida | Home |
Web SaaS (preview Desktop, preview desligado, ou web publicada) em /onboarding | Entrar (sem sessão) ou Home (com sessão) |
Admin → Testar onboarding, ou /onboarding?preview=true em build debug | Walkthrough sem efeitos (sem conta, sem perfil, sem permissões reais) |
/onboarding?preview=true em release sem ser admin | Home |
Não cria conta duplicada: se já existe ID no backend (login ou guest anônimo), o loader pula a criação de anônimo. Só a primeira instalação sem ID cria guest no fim do fluxo.
Ver o onboarding de novo no dev
Na aba normal do navegador (incluindo o browser do Cursor), o kit lembra coisas entre reloads:
| O que | Onde | Efeito |
|---|---|---|
onboarding_completed | localStorage (SharedPreferences) | Depois de concluir ou pular, o redirect não manda mais pro onboarding |
dev.last_route | localStorage | No debug, hot restart (R) volta pra última rota (ex.: /, /settings) em vez da primeira tela |
Por isso a aba anônima parece "funcionar": storage vazio = primeiro acesso de novo. O kasy clear-web e o kasy reset --web abrem a URL ?kasy_clear_storage=1 no seu navegador padrão (macOS, Windows e Linux). Essa URL zera localStorage, sessionStorage e IndexedDB (sessão do Firebase Auth na web fica no IndexedDB).
Opções sem anônimo:
- Admin → Testar onboarding (
/onboarding?preview=true): percorre todas as telas sem criar guest, sem gravar perfil e sem prompts reais. Volta pro Admin no fim. Em release, só admin (ou debug). Bom pra layout e copy. - Primeiro acesso real de novo:
kasy clear-web(comkasy run --webativo),kasy run --web --open-browser --fresh, aba anônima/privada, ou limpar site data dolocalhost:5555no DevTools → Application. No MCP:run_appcomfreshStorage=trueouclear_web_storage. Com device preview em aba iOS/Android/iPad, cai no onboarding. - URL direta:
/onboarding?preview=truesó em debug ou como admin. O fluxo real (/onboardingsem query) só na primeira instalação; sessão estabelecida vai pra Home.
Recarregar só a aba do browser (F5) não recompila o Dart. Depois de mudar código, use hot reload ou hot restart (veja abaixo).
Hot reload e hot restart (r / R)
No kasy run --web, você atualiza o build de duas formas:
| Onde | Como |
|---|---|
| Toolbar do device preview | Botões r e R na barra do preview (preferido se você já está no navegador) |
Terminal do kasy run --web | Digite r ou R |
| Mudança | Use |
|---|---|
| Layout, cor, padding, texto, ícone, estilo | r (hot reload, rápido, mantém estado) |
Provider, initState, rota, main(), wiring que rebuild não pega | R (hot restart) |
r falhou ou Flutter pediu restart | R |
Não use R só por mudança visual: é mais lento e zera formulários, navegação e sessão guest.
Quem manda r / R
| Situação | Reload |
|---|---|
kasy run não está rodando | flutter analyze limpo. A IA não inicia o app sozinha. |
kasy run rodando (você ou a IA terminou um edit em Dart) | r (UI/estilo) ou R (lógica/bug). Ver Orientação para IA. |
| IA vai navegar ou testar no browser | Checklist em docs/agent-browser-qa.md (link na orientação para IA). |
Dev humano: toolbar ou terminal quando quiser. IA: regras completas em Orientação para IA (documentação do site, não a landing page).
Navegação por IA (Browser QA)
Flutter Web pinta a tela inteira em canvas, sem tratamento especial, um agente de IA no navegador (Cursor, Claude, Playwright) não enxerga botão nem campo de texto como enxergaria numa página React comum, só pixels.
O kit resolve isso ligando a árvore de semantics do Flutter em toda build de debug/profile (nunca em produção) e instalando uma ponte JS (window.__kasyBrowserQa) que permite ao agente clicar e digitar sem depender do hit-test do DOM:
if (!kReleaseMode) {
SemanticsBinding.instance.ensureSemantics();
installBrowserQaBridge();
}Com isso ligado, um agente de IA consegue ler a página como uma árvore de acessibilidade normal (nome de cada botão, campo, switch) e chamar:
window.__kasyBrowserQa.click(label)pra tocar um controle pelo nome (não depende debrowser_clickno DOM)window.__kasyBrowserQa.setTextIn(label, valor)pra digitar num campo pelo nomewindow.__kasyBrowserQa.exists(label)/go(path)pra assert e navegação
A ponte também neutraliza overlays flt-semantics de tela cheia no DOM, então browser_click por ref continua como fallback. Não invente pointer-events à mão.
Roteiro do agente (reload r/R, terminal, snapshot, click / setTextIn): Orientação para IA e docs/agent-browser-qa.md no projeto. MCP: browser_qa_guide. Requer kasy-cli ≥ 1.87.1 (e kasy update core em projetos já gerados; a 1.87.0 anunciava a ponte mas o update core não a entregava).
Se você usa um agente de IA com o MCP do Kasy conectado, chame browser_qa_guide depois de implementar ou mudar uma tela (ver MCP).
Isso não muda nada pro usuário final: é só uma camada de debug, curta e apagada em builds de release.
Login social em iframe ou navegador embutido (Cursor, LP)
Abrir o app web em iframe (preview na landing) ou no Simple Browser do Cursor/VS Code não é igual a uma aba normal do Chrome.
O kit trata esses hosts como embedded OAuth host. No Cursor / VS Code Simple Browser, o login social usa redirect na mesma aba (não popup), porque popups abrem como aba nova e o OAuth não volta.
| Backend | Comportamento |
|---|---|
| Firebase | Popup no desktop normal; redirect em mobile web e no navegador embutido da IDE |
| Supabase | signInWithOAuth com LaunchMode.externalApplication no iframe; redirect na mesma aba fora de iframe |
Domínios OAuth (Firebase): o kasy new registra no Google Cloud os redirect URIs firebaseapp.com e web.app, e ajusta authDomain para SEU_PROJETO.web.app. Projeto já existente: kasy oauth-web. Apple e Facebook não têm API pública para isso: no Apple Developer (Services ID) e no Meta você precisa cadastrar os dois handlers manualmente. O kasy apple-web e o kasy facebook imprimem a lista completa.
Se o popup abre mas a aba original também redireciona, atualize o kit (kasy update core) e confirme kasy-cli ≥ 1.71.3.
Google Cloud
Adicione http://localhost:5555 e seu domínio de produção como origins autorizados em Google Cloud Console → Credenciais → seu OAuth Client.
Atualizado em 03/11/2026

