1 pontos por GN⁺ 1 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • A suposição de que apps de terminal são inerentemente acessíveis por serem baseados em texto não se sustenta nos TUIs modernos, e frameworks como Ink, Bubble Tea e tcell podem criar um ambiente ainda mais hostil para usuários de leitores de tela
  • O CLI acumula saída em ordem cronológica como um fluxo linear de stdin/stdout, mas o TUI trata o terminal como uma grade 2D de células de caracteres, o que dificulta para leitores de tela acompanhar o fluxo
  • O gemini-cli faz o Ink redesenhar a árvore de componentes React para ajustá-la à grade do terminal, movendo o cursor entre spinner, timer e histórico da conversa, o que pode provocar leitura repetida, travamentos e atraso de entrada no Speakup e no NVDA
  • Ferramentas antigas como nano, vim, menuconfig e Irssi reduzem o ruído de atualizações de coordenadas e minimizam a interferência com a linha de entrada usando ocultação do cursor, foco em coluna única e áreas de rolagem do VT100
  • Para criar ferramentas de terminal acessíveis, é preciso evitar frameworks de UI declarativa que tratam o terminal como um canvas e evitar redesenhos agressivos, garantindo um comportamento mais próximo de fluxos de CLI simples e lineares

O equívoco de que “por ser texto, é acessível”

  • A suposição de que aplicações executadas no terminal são inerentemente acessíveis não corresponde ao uso real
  • A expectativa de que leitores de tela consigam interpretar facilmente texto ASCII bruto por não haver gráficos, DOM complexo ou canvas WebGL se rompe nos TUIs modernos
  • Frameworks de UI para terminal como Ink (JS/React), Bubble Tea (Go) e tcell tentam melhorar a experiência do desenvolvedor (DX), mas podem criar um ambiente mais hostil para usuários com deficiência visual
  • Em muitos casos, TUIs modernos são piores em acessibilidade do que interfaces gráficas mal implementadas

Diferença estrutural entre CLI e TUI

  • CLI: fluxo linear

    • CLI funciona com base em stdin/stdout; você digita um comando, o resultado é adicionado abaixo e o cursor desce
    • Como a saída é linear e se acumula em ordem cronológica, ela se adapta bem a leitores de tela em nível de kernel como o Speakup
  • TUI: grade 2D

    • TUI trata a janela do terminal não como um fluxo de texto, mas como uma grade 2D em que cada célula de caractere é usada como se fosse um pixel
    • Ao abandonar o fluxo temporal e priorizar o layout espacial, cria-se uma estrutura difícil de acompanhar para leitores de tela

O problema exposto no gemini-cli

  • O gemini-cli é uma ferramenta escrita em Node.js com o framework Ink e, por fora, parece apenas uma interface de chat simples
  • Internamente, o Ink tenta ajustar a árvore de componentes React à grade do terminal
  • Ao usar com Speakup (Linux) ou NVDA (Windows), o aplicativo não apenas falha: ele despeja continuamente conteúdo para o leitor de tela ler
  • Uma tela que se comporta como um canvas reativo

    • Como o framework trata a tela como um canvas reativo, toda atualização provoca um redesenho
    • Quando a IA está “pensando”, para atualizar um timer ou spinner, ele move o cursor de hardware até a posição do timer, escreve o novo tempo e depois volta ao ponto original
    • Para usuários videntes, isso passa instantaneamente, mas para usuários de leitores de tela soa como “Responding... Time elapsed 1s... Responding... Time elapsed 2s...” repetidamente
    • À medida que o cursor se desloca momentaneamente entre o indicador de status, o spinner e o histórico da conversa, o Speakup tenta ler o que estiver sob o cursor naquele instante
    • Como resultado, atualizações do timer e trechos da conversa se misturam, tornando difícil focar no que está sendo digitado de fato
  • Instabilidade com NVDA e colagem

    • No Windows, ao abrir um terminal com NVDA, conectar por SSH a uma máquina Linux e entrar em uma sessão screen, colar texto pode fazer o NVDA travar imediatamente ou deixar o sistema altamente instável
    • Sempre que um caractere é digitado ou um texto é colado, o estado da aplicação muda, e o framework decide que precisa renderizar a interface novamente
    • Se o histórico da conversa faz parte do estado, ele pode tentar redesenhar ou recalcular instantaneamente o layout de milhares de linhas de texto
    • Quanto mais mensagens houver na conversa, mais frequentemente esse problema ocorre
    • Nem a combinação Insert+5, usada para evitar anúncios de conteúdo dinâmico, consegue evitar isso
  • O loop de atraso de entrada

    • Quando frameworks como Ink rodam em ambientes de thread única como o Node.js, a degradação de desempenho cresce conforme o histórico aumenta
    • Ao colar grandes blocos de texto, é preciso calcular diferenças para milhares de linhas
    • O sistema fica ocupado calculando como redesenhar a tela, e o processamento da entrada atrasa
    • Mesmo ao pressionar uma única tecla, pode ser preciso esperar até 10 segundos para o caractere reaparecer na tela

Por que ferramentas antigas funcionam

  • Ferramentas como nano, vim e menuconfig não são usadas por serem sempre perfeitas em acessibilidade
  • O ponto central é que elas conseguem ocultar totalmente o cursor ou reduzir o ruído gerado pelo rastreamento da posição do cursor
  • nano e vim: ocultação do cursor

    • Se o nano for executado com opções que exibem a posição do cursor, como --constantshow, ou se o vim for usado sem determinadas configurações, a usabilidade pode se deteriorar
    • Quando o cursor fica visível e o rastreamento está ativo, o Speakup prioriza atualizações da posição do cursor em vez do eco de caracteres
    • Quando o usuário digita “a”, em vez de ouvir “a”, ele ouve “Column 2”; ao digitar “b”, ouve “Column 3”
    • Essas ferramentas antigas podem ser configuradas para suprimir atualizações do cursor visual ou da barra de status, fazendo o leitor de tela depender do fluxo de entrada de caracteres em vez de atualizações de coordenadas
    • Frameworks modernos normalmente não oferecem modo “no-cursor” ou “headless” e partem do princípio de que o cursor visual é obrigatório
  • menuconfig: foco em coluna única

    • O menuconfig do kernel Linux funciona porque mantém um foco estrito em uma única coluna
    • Mesmo com bordas e títulos, a área ativa é uma lista vertical, e o cursor permanece preso a essa lista
    • O cursor não sai para o canto inferior direito para atualizar um relógio e depois vai ao canto superior esquerdo para atualizar um título
    • A complexidade espacial se mantém baixa, então o leitor de tela não perde a referência
  • Irssi: uso de áreas de rolagem

    • O Irssi não é acessível por sorte; é uma ferramenta de chat que há mais de 20 anos usa áreas de rolagem do VT100 por meio de um mecanismo de renderização próprio
    • Quando chega uma nova mensagem, ele instrui o driver do terminal a “definir da linha 1 à linha 23 como área de rolagem”
    • Em seguida, envia o comando de “rolar para cima”, o terminal move o conteúdo para cima e desenha o novo texto na parte inferior dessa área
    • Esse método minimiza a interferência com a linha de entrada
    • Em vez de reescrever manualmente todos os caracteres da tela, ele depende de recursos de hardware do terminal
    • Frameworks modernos ignoram esses recursos de hardware e preferem calcular diferenças de estado da tela para reescrever caracteres, o que custa mais computacionalmente e é hostil à acessibilidade

O problema no tratamento dos issues do gemini-cli

  • O Google e os mantenedores do gemini-cli parecem se importar com acessibilidade, mas regressões importantes de acessibilidade estão sendo deixadas de lado no repositório
  • Regressões de acessibilidade como a Issue #3435 e a Issue #11305 não têm discussão, roadmap nem correção
  • A Issue #1553 foi aberta para rastrear esse tipo de falha de acessibilidade, mas não foi resolvida e acabou fechada automaticamente por um bot
  • O bot encerra o issue com uma mensagem genérica dizendo que ele foi fechado por inatividade prolongada e para gerenciamento de backlog
  • Fechar relatos de acessibilidade porque os mantenedores não tocaram neles por meses não é organização; é como esconder evidências
  • Isso passa o sinal de que, se um bug for ignorado tempo suficiente, ele deixa de existir, enquanto o software continua inutilizável para usuários com deficiência visual
  • A métrica de “Closed Issues” do projeto pode melhorar, mas os problemas de acessibilidade seguem sem solução

Conclusão para criar ferramentas de terminal acessíveis

  • Se acessibilidade realmente importa em aplicações para terminal, é preciso parar de usar frameworks de UI declarativa que tratam o terminal como um canvas
  • As stacks de TUI “modernas” foram otimizadas para facilitar ao desenvolvedor escrever código como se estivesse usando React, sacrificando a capacidade da máquina de renderizar texto com eficiência
  • Se a aplicação não garante que o usuário possa ocultar o cursor, ou depende de redesenhos agressivos para mostrar spinners e timers, ela se torna uma ferramenta inacessível
  • Para usuários com deficiência visual, um fluxo de CLI simples e linear é muito melhor do que um TUI “inteligente” que atrasa, despeja leitura contínua e espalha o cursor pela tela inteira

1 comentários

 
GN⁺ 1 시간 전
Comentários no Lobste.rs
  • Este texto, como muitos outros posts de blog, tem um forte cheiro de texto escrito com ajuda de IA
    LLMs adoram títulos desse tipo: “The Architectural Flaw”, “The Lag Loop”, “Why The ‘Old Guard’ Works”, “The Lost Art of Scrolling Regions”, “The ‘Stale Bot’ excuse: A Case Study in Neglect”

    • Já pelo título parece um texto industrial de IA. O tema em si é novo, então talvez denunciar como spam tenha sido exagero, mas 1) eu simplesmente não aguento mais o mesmo estilo repetido em todo lugar e 2) isso me faz duvidar até da precisão do conteúdo
      Poderia ter sido um excelente post de blog, mas se parece que o autor jogou um esboço no ChatGPT e parou por aí, isso é ruim tanto para o leitor quanto para o autor
    • Uma das características de escrita com LLM que eu mais detesto é usar algo como “The <conceito nada consolidado>” de um jeito que faz parecer um conceito formal
      Chamar um problema muito específico e pontual de problema “clássico” é a mesma coisa
  • Isso é realmente deprimente. Em resumo, existem TUIs acessíveis como o Irssi, mas os frameworks modernos de TUI ignoram esses precedentes e dependem de diff de grade e movimentação do cursor
    Leitores de tela leem o conteúdo da posição para a qual o cursor se move, então o resultado vira uma bagunça ou gera uma quantidade absurda de spam de leitura

  • Fico em dúvida se a explicação técnica aqui está totalmente correta
    Em especial, o Ink por muito tempo não suportou renderização incremental nenhuma, e a maioria dos apps que usam Ink ainda não a ativa. E mesmo essa renderização incremental é baseada em linhas, então ela não move o cursor até a posição real do timer
    O Gemini CLI exige uso de buffer alternativo para ativar a renderização incremental, e isso é desativado quando o modo interno compatível com leitor de tela está ligado. A documentação da opção relacionada está aqui
    Além disso, rich/textual em Python muitas vezes é bem mais rápido que Ink, mesmo rodando sobre uma linguagem mais lenta e em geral de thread única. Fazer diff de milhares de linhas não é necessariamente tão lento assim, e certamente não a ponto de levar 10 segundos
    Não duvido que a experiência de usuário esteja frustrante e quebrada, mas a causa exata apresentada parece possivelmente ser uma alucinação de LLM ou baseada em informação incompleta. A renderização incremental do Ink, mesmo quando ativada, não funciona como foi descrito
    Na prática, é bem provável que o redesenho da tela inteira confunda leitores de tela, e que o redesenho baseado em linhas seja ruim por fazer reler fragmentos arbitrários e quebrados de texto sem relação com a mudança

  • Culpar só a TUI não é justo
    O problema real é que o suporte a acessibilidade de quase toda a pilha é péssimo
    Primeiro, a maioria dos emuladores de terminal com renderização por GPU não usa nem um pouco as APIs de acessibilidade fornecidas pelo sistema. Quando o texto é renderizado pela GPU, ferramentas de acessibilidade não conseguem “ler”; ele parece só uma imagem. Kitty, Alacritty e WezTerm entram nisso. Meu terminal, Ghostty, pode ser lido pela API de acessibilidade no macOS, e iTerm2 e Terminal.app também
    Segundo, não existe nenhuma sequência de terminal nem movimento padronizado para uma TUI transmitir informação de acessibilidade ao emulador de terminal. Precisaríamos de algo equivalente a anotações ao estilo ARIA para células do terminal, intervalos de execução e regiões, mas não há nenhuma iniciativa disso. Mesmo que a TUI lide bem com o cursor, ainda vai dar problema em muitos casos de uso
    Por exemplo, no Ghostty temos trabalhado para integrar OSC133 com a API de acessibilidade, expondo cada prompt do shell, entrada e comando como elementos estruturalmente significativos, e não apenas caixas de texto simples. Isso mostra que especificação de terminal, TUI e emulador de terminal precisam se encaixar juntos
    A pilha inteira está apodrecida, e quase ninguém quer consertar isso de verdade. Eu também só faço o melhor que posso com tempo limitado, mas este é um tema enorme que ainda exige política de ecossistema, então é difícil de enfrentar
    Como bônus, a realidade ao mesmo tempo interessante e terrível é que a IA está ajudando a melhorar a acessibilidade aqui. Muitas ferramentas de IA usam ou abusam das APIs de acessibilidade para ler listas de janelas e realizar entrada. Então mais aplicativos começaram a levar integração de acessibilidade muito mais a sério por causa dos casos de uso de IA

    • O terminal realmente está virando um mini navegador
  • Fico irritado todos os dias porque o Claude Code e o gemini-cli não são baseados em readline
    Eles colocaram algumas teclas parecidas, mas falta a longa cauda dos atalhos readline já familiares
    A Anthropic poderia admitir que decidir “fazer como desenvolvimento web” foi um erro e recomeçar com readline
    A ideia de que a experiência familiar de desenvolvimento para quem cria essas ferramentas é mais importante do que a experiência familiar de uso para quem as usa está errada

    • Pelo que entendo, uma grande parte desse problema é que o Ink basicamente se contenta em ser um backend de renderização e não oferece widgets de entrada
      Na prática também quase não existem soluções de terceiros famosas e bem mantidas. Se você precisa de uma caixa de entrada flexível, acaba tendo de construir do zero
      Em contraste com o excelente widget Input do Textual ou com outra biblioteca do ecossistema JS, o OpenTUI
    • readline não é sob licença GNU? Alguém finalmente fez uma versão que não é GPL?
      Eu não gosto de LLMs, então pessoalmente considero a UI ruim uma vantagem, mas pode haver um motivo para não usarem readline
  • Editores de terminal como kakoune e helix provavelmente teriam dificuldade para passar em critérios de acessibilidade, a menos que usem o truque de “esconder o cursor”
    Ainda assim, provavelmente não seriam tão acessíveis quanto o VS Code
    Fora o VS Code, que IDE-lite ou IDE multiplataforma acessível existe? Não gosto da postura cada vez mais hostil do VS Code. Talvez os IDEs da JetBrains

    • Existe o emacspeak, que fornece uma interface muito acessível para o Emacs
      O lado ruim é que, embora o Emacs em si seja multiplataforma, o emacspeak pode ter uma dependência fraca de Linux por causa de TTS. Ou talvez não. Nunca tentei no Windows
    • Primeiro é preciso perguntar acessibilidade para quem. Se for para pessoas surdas, você precisa oferecer texto no idioma local e língua de sinais local. Nos EUA, normalmente é ASL
      Se for acessibilidade para pessoas cegas, você precisa de emacspeak ou das ferramentas de acessibilidade para deficiência visual da própria plataforma
      Acessibilidade é um espectro, não uma caixa de seleção
  • O Links tem um modo de terminal braille separado, que troca elementos de GUI falsos por um menu de tela cheia mais simples e também muda a navegação por setas para ser linha a linha
    Outro caso interessante é o edbrowse. É um navegador em modo texto criado por Karl Dahlke, que é cego, e ao contrário de navegadores web em modo texto mais populares, ele não usa TUI, e sim uma interface de linha de comando no estilo do ed

  • Se for o framework Ink, isso provavelmente explica por que a CLI usa 100% da CPU, trava para sempre e continua redesenhando um histórico longo de chat. Uma pena