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.
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
- 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
- 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
- Atalhos de teclado devem ser descobríveis - Mostre atalhos inline nos resultados (⌘1, ⌘2), não escondidos em tooltips ou documentação
- Personalidade sem custo de performance - Confete em conquistas, estados vazios divertidos e textos criativos criam encantamento sem adicionar latência
- 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
- 50ms ou nada - Velocidade não é negociável
- Atalhos de teclado em todo lugar - Descobríveis, não escondidos
- Busca fuzzy com destaque - Mostre por que os resultados correspondem
- Painéis de ação (⌘K) - Ações sensíveis ao contexto
- Confirmações HUD - Feedback rápido e não-bloqueante
Para Apps macOS
- Vibrância nativa - Use NSVisualEffectView/.material
- SF Symbols - Consistente com o sistema
- Cores do sistema - Respeite a preferência de cor de destaque
- Cantos contínuos - .cornerRadius(style: .continuous)
- 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