Raycast: A Arte da UI de Produtividade

Como o Raycast alcançou tempos de resposta abaixo de 50ms com personalidade: design nativo para macOS, excelência em teclado, ecossistemas de extensões e padrões HUD. Com padrões de implementação em Swift.

5 min de leitura 1126 palavras
Raycast: A Arte da UI de Produtividade screenshot

Raycast: A Arte da UI de Produtividade

“Acreditamos que as melhores ferramentas saem do seu caminho.” — Equipe Raycast

Raycast é um launcher para macOS que substituiu o Spotlight para usuários avançados. Ele demonstra como projetar para eficiência extrema enquanto mantém calor e personalidade.


Por Que o Raycast Importa

O Raycast prova que software utilitário não precisa parecer frio. Ele combina: - Velocidade impressionante (inicializa em <50ms) - Interação focada no teclado - Extensibilidade através de uma loja - Personalidade através de detalhes encantadores

Conquistas principais: - Redefiniu o que um launcher pode ser - Provou que ferramentas para desenvolvedores podem ter personalidade - Criou um ecossistema próspero de extensões - Estabeleceu novos padrões para design nativo do macOS


Principais Conclusões

  1. 50ms é o limite de velocidade - Usuários percebem qualquer latência acima de 50ms; trate isso como uma restrição de engenharia rígida, não uma diretriz
  2. Integração nativa com a plataforma cria confiança - Vibrância, SF Symbols, cores de destaque do sistema e atalhos padrão fazem o Raycast parecer parte do macOS
  3. Atalhos de teclado devem ser descobríveis - Mostre atalhos inline nos resultados (⌘1, ⌘2), não escondidos em tooltips ou documentação
  4. Personalidade sem custo de performance - Confete em conquistas, estados vazios divertidos e textos criativos criam encantamento sem adicionar latência
  5. Ecossistemas de extensões precisam de linguagem de design - Extensões de terceiros parecem nativas porque usam os mesmos componentes de formulário, painéis de ação e padrões de navegação

Princípios Fundamentais de Design

1. Resposta Instantânea

O Raycast parece uma extensão dos seus pensamentos. Sem latência. Sem espera.

Como eles conseguem isso: - Implementação nativa em Swift (não Electron) - Índice de extensões pré-carregado - Cache agressivo - Pipeline de renderização otimizado

A regra dos 50ms: Se algo leva mais de 50ms, os usuários percebem. O Raycast trata isso como uma restrição rígida.

Implicações de design: - Mostre a UI imediatamente, carregue dados de forma assíncrona - Estados skeleton para operações pesadas - Nunca bloqueie a thread principal - Prefira processamento local em vez de chamadas de rede

// Padrão de resposta instantânea estilo Raycast
struct SearchView: View {
    @State private var results: [Result] = []
    @State private var isLoading = false

    var body: some View {
        VStack {
            // Mostra imediatamente com dados em cache
            ForEach(cachedResults) { result in
                ResultRow(result)
            }

            if isLoading {
                // Indicador de carregamento discreto
                ProgressView()
                    .scaleEffect(0.5)
            }
        }
        .task(id: query) {
            isLoading = true
            results = await search(query)
            isLoading = false
        }
    }
}

2. Integração Profunda com macOS

O Raycast parece pertencer ao macOS. Ele respeita as convenções da plataforma enquanto amplia os limites.

Comportamentos nativos: - Vibrância e blur (NSVisualEffectView) - Cores de destaque do sistema - SF Symbols em toda parte - Atalhos de teclado nativos - Respeita o modo escuro/claro do sistema

Implementação:

// Vibrância do macOS
struct RaycastWindow: View {
    var body: some View {
        VStack {
            // Conteúdo
        }
        .background(.ultraThinMaterial)  // Blur nativo
        .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
    }
}

// Cor de destaque do sistema
Text("Selecionado")
    .foregroundStyle(.tint)  // Segue a preferência do sistema

// SF Symbols com cores semânticas
Image(systemName: "checkmark.circle.fill")
    .foregroundStyle(.green)

Design da janela:

┌────────────────────────────────────────────────────────────┐
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░░                                                      ░░ │
│ ░░  > Pesquisar Raycast...                              ░░ │
│ ░░                                                      ░░ │
│ ░░  ┌────────────────────────────────────────────────┐  ░░ │
│ ░░  │ [A]  Aplicativos                       Cmd+1   │  ░░ │
│ ░░  │ [F]  Busca de Arquivos                 Cmd+2   │  ░░ │
│ ░░  │ [C]  Histórico da Área de Transferência Cmd+3  │  ░░ │
│ ░░  │ [S]  Comandos do Sistema               Cmd+4   │  ░░ │
│ ░░  └────────────────────────────────────────────────┘  ░░ │
│ ░░                                                      ░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
└────────────────────────────────────────────────────────────┘
                    ↑ Vibrância mostra a área de trabalho através da janela

3. Excelência do Teclado com Feedback Visual

Toda ação tem um atalho de teclado. Todo atalho tem confirmação visual.

Padrões de exibição de atalhos:

LISTA DE RESULTADOS:
┌────────────────────────────────────────────────────────────┐
│ Aplicativos Recentes                                       │
│                                                            │
│  (*)  Visual Studio Code                         Cmd+1     │
│       ~/Projects/my-app                                    │
│                                                            │
│  ( )  Figma                                      Cmd+2     │
│       ~/Design/project.fig                                 │
│                                                            │
│  ( )  Terminal                                   Cmd+3     │
│                                                            │
│ ───────────────────────────────────────────────────────────│
│  Ações                              Cmd+K  ou  ->  para ver│
└────────────────────────────────────────────────────────────┘

Painel de ações:

┌────────────────────────────────────────────────────────────┐
│ Ações para "Visual Studio Code"                   esc <-   │
│                                                            │
│  Abrir                                            Enter    │
│  Abrir em Nova Janela                         Cmd+Enter    │
│  ──────────────────────────────────────────────────────── │
│  Mostrar no Finder                          Cmd+Shift+F    │
│  Copiar Caminho                             Cmd+Shift+C    │
│  ──────────────────────────────────────────────────────── │
│  Mover para o Lixo                       Cmd+Backspace     │
└────────────────────────────────────────────────────────────┘

Princípios de design: - Mostre atalhos inline (não em tooltips) - Agrupe atalhos por tecla modificadora - Use atalhos padrão do macOS onde esperado - Padrões mnemônicos (⌘⇧F = Finder)


4. Personalidade nos Detalhes

O Raycast é eficiente mas não estéril. Pequenos encantos o tornam memorável.

Exemplos: - Confete em conquistas - Sons sutis para ações - Estados vazios divertidos - Easter eggs para usuários avançados

Exemplo de estado vazio:

┌────────────────────────────────────────────────────────────┐
│                                                            │
│                        [?]                                 │
│                                                            │
│               Sem resultados para "asdfgh"                 │
│                                                            │
│          Tente pesquisar algo diferente,                   │
│          ou confira a Loja de Extensões                    │
│                                                            │
│              [Explorar Extensões]                          │
│                                                            │
└────────────────────────────────────────────────────────────┘

Padrão de confete (para conquistas):

// Após completar onboarding, ganhar badge, etc.
ConfettiView()
    .transition(.opacity)
    .animation(.spring(), value: showConfetti)

Diretrizes de personalidade: - Encantamento não deve atrasar - Celebrações são conquistadas (não aleatórias) - Personalidade no texto (“Sem resultados para...” vs “Erro: 0 resultados”) - Som é opcional e discreto


5. Design do Ecossistema de Extensões

A loja de extensões do Raycast é lindamente projetada.

Card de extensão:

┌────────────────────────────────────────────────────────────┐
│  ┌──────┐                                                  │
│  │ [+]  │  GitHub                                          │
│  │      │  Pesquise repos, PRs e issues                    │
│  └──────┘                                                  │
│           ★★★★★  1.2k avaliações  •  Por Raycast           │
│                                                            │
│           [Instalar]                                       │
└────────────────────────────────────────────────────────────┘

Visualização de detalhes da extensão:

┌────────────────────────────────────────────────────────────┐
│                                                            │
│  ← GitHub                                    [Desinstalar] │
│                                                            │
│  ┌──────────────────────────────────────────────────────┐ │
│  │                                                       │ │
│  │           [Screenshot da extensão em uso]            │ │
│  │                                                       │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Comandos                                                  │
│  ├─ Pesquisar Repositórios                                 │
│  ├─ Meus Pull Requests                                     │
│  ├─ Pesquisar Issues                                       │
│  └─ Criar Issue                                            │
│                                                            │
│  Changelog                                                 │
│  ├─ v2.1.0  Adicionado filtro por organização              │
│  └─ v2.0.0  Reescrita completa com nova API                │
│                                                            │
└────────────────────────────────────────────────────────────┘

6. Design de Formulários para Extensões

As extensões usam um sistema de formulários consistente.

Padrões de formulário:

┌────────────────────────────────────────────────────────────┐
│ Criar Issue no GitHub                                 esc  │
│                                                            │
│  Repositório                                               │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ raycast/extensions                               ▾   │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Título                                                    │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ Bug: Busca não está funcionando                      │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Descrição                                                 │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ Quando eu pesquiso por...                            │ │
│  │                                                       │ │
│  │                                                       │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Labels                                    (opcional)      │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ [bug] [needs-triage]                             +   │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│           [Criar Issue ⌘↵]    [Cancelar esc]               │
│                                                            │
└────────────────────────────────────────────────────────────┘

Estilização de componentes de formulário:

// Formulário estilo Raycast em SwiftUI
Form {
    Section("Repositório") {
        Picker("", selection: $repo) {
            ForEach(repos) { repo in
                Text(repo.name).tag(repo)
            }
        }
        .labelsHidden()
    }

    Section("Título") {
        TextField("Bug: ...", text: $title)
    }

    Section("Descrição") {
        TextEditor(text: $description)
            .frame(minHeight: 100)
    }
}
.formStyle(.grouped)

Padrões de Design para Aprender

O Padrão Busca-Primeiro

Tudo começa com busca.

┌────────────────────────────────────────────────────────────┐
│  > |                                                       │
│    ^ Cursor aqui imediatamente ao abrir                    │
│                                                            │
│  Digite para pesquisar comandos, apps, arquivos e mais     │
└────────────────────────────────────────────────────────────┘

Implementação: - Auto-foco na busca ao abrir - Correspondência fuzzy com destaques - Classificação inteligente (recente + frequente + relevante) - Resultados aparecem enquanto você digita

Navegação Hierárquica

Funcionalidade profunda sem complexidade.

Nível 1: Busca principal
    ↓ Enter
Nível 2: Comandos da extensão
    ↓ Enter
Nível 3: Resultados da ação
    ↓ ⌘K
Nível 4: Painel de ações

Sempre: esc volta um nível

Confirmações HUD

Feedback rápido sem interrupção.

Após a ação:
┌────────────────────────────────────┐
│  ✓ Copiado para a área de transf.  │
└────────────────────────────────────┘
    ↑ Aparece brevemente, desaparece
      Não requer dismissão
// Padrão HUD
struct HUDView: View {
    @State private var show = false

    var body: some View {
        if show {
            Text("✓ Copiado")
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(.regularMaterial)
                .cornerRadius(8)
                .transition(.opacity.combined(with: .scale))
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
                        withAnimation { show = false }
                    }
                }
        }
    }
}

O Que Copiar do Raycast

Para UI de Launcher/Busca

  1. 50ms ou nada - Velocidade não é negociável
  2. Atalhos de teclado em todo lugar - Descobríveis, não escondidos
  3. Busca fuzzy com destaque - Mostre por que os resultados correspondem
  4. Painéis de ação (⌘K) - Ações sensíveis ao contexto
  5. Confirmações HUD - Feedback rápido e não-bloqueante

Para Apps macOS

  1. Vibrância nativa - Use NSVisualEffectView/.material
  2. SF Symbols - Consistente com o sistema
  3. Cores do sistema - Respeite a preferência de cor de destaque
  4. Cantos contínuos - .cornerRadius(style: .continuous)
  5. Atalhos padrão - Não reinvente ⌘C, ⌘V, etc.

Técnicas Específicas

Técnica Como Aplicar
Inicialização instantânea Pré-aqueça a janela, carregue conteúdo lazy
Busca fuzzy Use Fuse.js ou biblioteca similar
Dicas de atalhos Inline ⌘1, ⌘2, etc. nos resultados
Painel de ações Ações secundárias com ⌘K ou →
Feedback HUD Estilo toast, auto-dismiss
API de extensões Contratos claros, UI consistente

Sistema de Cores

O Raycast usa cores semânticas vinculadas ao sistema.

// Cores semânticas inspiradas no Raycast
extension Color {
    static let rayBackground = Color(nsColor: .windowBackgroundColor)
    static let raySecondary = Color.secondary
    static let rayTertiary = Color(nsColor: .tertiaryLabelColor)

    // Cores de status
    static let raySuccess = Color.green
    static let rayWarning = Color.orange
    static let rayError = Color.red

    // Destaque segue o sistema
    static let rayAccent = Color.accentColor
}

// Exemplo de modo escuro
struct ResultRow: View {
    var body: some View {
        HStack {
            Image(systemName: "app.fill")
                .foregroundStyle(.secondary)

            Text("Nome do Aplicativo")
                .foregroundStyle(.primary)

            Spacer()

            Text("⌘ 1")
                .font(.caption)
                .foregroundStyle(.tertiary)
                .padding(.horizontal, 6)
                .padding(.vertical, 2)
                .background(Color.secondary.opacity(0.2))
                .cornerRadius(4)
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 8)
    }
}

Insights Principais

“Cada milissegundo importa. Os usuários sentem a diferença entre 50ms e 100ms.”

“Atalhos de teclado devem ser descobríveis, não memorizados a partir de documentação.”

“Personalidade torna o software memorável. Eficiência o torna indispensável.”

“Extensões devem parecer nativas, não acopladas. Mesma linguagem de UI, mesmas interações.”


Perguntas Frequentes

Como o Raycast consegue tempos de resposta abaixo de 50ms?

O Raycast usa implementação nativa em Swift (não Electron), pré-carrega o índice de extensões ao iniciar, faz cache agressivo dos resultados de busca e otimiza o pipeline de renderização. A UI aparece imediatamente enquanto os dados carregam de forma assíncrona. O limite de 50ms é tratado como uma restrição rígida, não como uma meta.

Por que o Raycast parece tão nativo do macOS?

O Raycast usa NSVisualEffectView para vibrância/blur, SF Symbols para todos os ícones, cores de destaque do sistema que respeitam as preferências do usuário e atalhos de teclado padrão do macOS. A janela tem cantos com raio contínuo e segue o modo escuro/claro do sistema automaticamente.

Qual é a abordagem do Raycast para atalhos de teclado?

Toda ação tem um atalho de teclado exibido inline nos resultados (⌘1, ⌘2, etc.), não escondidos em tooltips. Os atalhos usam padrões mnemônicos (⌘⇧F para Finder, ⌘⇧C para Copiar Caminho). O painel de ações (⌘K) fornece ações secundárias com seus próprios atalhos.

Como o Raycast adiciona personalidade sem desacelerar?

As celebrações são conquistadas e breves—confete aparece após conquistas, não aleatoriamente. Estados vazios têm texto divertido (“Sem resultados para...” em vez de “Erro: 0 resultados”). Sons são opcionais e discretos. O encantamento nunca bloqueia o usuário ou adiciona latência.

Como o sistema de extensões do Raycast mantém consistência?

Todas as extensões usam os mesmos componentes de UI (formulários, listas, painéis de ação), seguem os mesmos padrões de navegação (Enter para aprofundar, Escape para voltar) e herdam o estilo do sistema. A API impõe consistência para que extensões de terceiros sejam indistinguíveis dos recursos nativos.


Recursos

  • Website: raycast.com
  • Loja: raycast.com/store - Estude o design das extensões
  • Documentação: Diretrizes de desenvolvimento de extensões
  • Blog: Posts de engenharia sobre performance
  • GitHub: github.com/raycast - Extensões open source