Raycast: 생산성 UI의 예술

Raycast가 50ms 미만의 응답 시간과 개성을 어떻게 달성했는지: macOS 네이티브 디자인, 키보드 우선, 확장 프로그램 생태계, HUD 패턴. Swift 구현 패턴 포함.

5 분 소요 929 단어
Raycast: 생산성 UI의 예술 screenshot

Raycast: 생산성 UI의 예술

"우리는 최고의 도구란 사용자의 길을 방해하지 않는 것이라 믿습니다." — Raycast 팀

Raycast는 파워 유저들 사이에서 Spotlight를 대체한 macOS 런처입니다. 따뜻함과 개성을 유지하면서도 극한의 효율성을 위해 어떻게 디자인해야 하는지 보여줍니다.


Raycast가 중요한 이유

Raycast는 실용적인 소프트웨어가 차갑게 느껴질 필요가 없다는 것을 증명합니다. 다음을 결합했습니다: - 번개 같은 속도 (50ms 미만으로 실행) - 키보드 우선 인터랙션 - 스토어를 통한 확장성 - 섬세한 디테일을 통한 개성

주요 성과: - 런처가 무엇이 될 수 있는지 재정의 - 개발자 도구도 개성을 가질 수 있음을 증명 - 번성하는 확장 프로그램 생태계 구축 - macOS 네이티브 디자인의 새로운 기준 제시


핵심 요점

  1. 50ms가 속도 임계값 - 사용자는 50ms 이상의 지연을 인지합니다. 이것을 가이드라인이 아닌 엄격한 엔지니어링 제약조건으로 다루세요
  2. 네이티브 플랫폼 통합이 신뢰를 만든다 - Vibrancy, SF Symbols, 시스템 강조 색상, 표준 단축키가 Raycast를 macOS의 일부처럼 느끼게 합니다
  3. 키보드 단축키는 발견 가능해야 한다 - 단축키를 툴팁이나 문서에 숨기지 말고 결과 목록에 인라인으로 표시하세요 (⌘1, ⌘2)
  4. 성능 비용 없는 개성 - 업적 달성 시 색종이 효과, 재치 있는 빈 상태 화면, 영리한 문구가 지연 없이 즐거움을 선사합니다
  5. 확장 프로그램 생태계에는 디자인 언어가 필요하다 - 서드파티 확장 프로그램도 동일한 폼 컴포넌트, 액션 패널, 네비게이션 패턴을 사용하기 때문에 네이티브처럼 느껴집니다

핵심 디자인 원칙

1. 즉각적인 반응

Raycast는 생각의 연장선처럼 느껴집니다. 지연이 없습니다. 기다림이 없습니다.

구현 방법: - 네이티브 Swift 구현 (Electron 아님) - 사전 로드된 확장 프로그램 인덱스 - 공격적인 캐싱 - 최적화된 렌더링 파이프라인

50ms 규칙: 무언가가 50ms 이상 걸리면 사용자는 알아차립니다. Raycast는 이것을 엄격한 제약조건으로 다룹니다.

디자인 시사점: - UI를 즉시 보여주고 데이터는 비동기로 로드 - 무거운 작업에는 스켈레톤 상태 사용 - 절대 메인 스레드를 차단하지 않음 - 네트워크 호출보다 로컬 처리 선호

// Raycast-style instant response pattern
struct SearchView: View {
    @State private var results: [Result] = []
    @State private var isLoading = false

    var body: some View {
        VStack {
            // Show immediately with cached data
            ForEach(cachedResults) { result in
                ResultRow(result)
            }

            if isLoading {
                // Unobtrusive loading indicator
                ProgressView()
                    .scaleEffect(0.5)
            }
        }
        .task(id: query) {
            isLoading = true
            results = await search(query)
            isLoading = false
        }
    }
}

2. 깊은 macOS 통합

Raycast는 macOS에 속한 것처럼 느껴집니다. 플랫폼 규칙을 존중하면서도 경계를 넓힙니다.

네이티브 동작: - Vibrancy와 블러 (NSVisualEffectView) - 시스템 강조 색상 - 전반적인 SF Symbols 사용 - 네이티브 키보드 단축키 - 시스템 다크/라이트 모드 존중

구현:

// macOS vibrancy
struct RaycastWindow: View {
    var body: some View {
        VStack {
            // Content
        }
        .background(.ultraThinMaterial)  // Native blur
        .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
    }
}

// System accent color
Text("Selected")
    .foregroundStyle(.tint)  // Follows system preference

// SF Symbols with semantic colors
Image(systemName: "checkmark.circle.fill")
    .foregroundStyle(.green)

윈도우 디자인:

┌────────────────────────────────────────────────────────────┐
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░░                                                      ░░ │
│ ░░  > Search Raycast...                                 ░░ │
│ ░░                                                      ░░ │
│ ░░  ┌────────────────────────────────────────────────┐  ░░ │
│ ░░  │ [A]  Applications                      Cmd+1   │  ░░ │
│ ░░  │ [F]  File Search                       Cmd+2   │  ░░ │
│ ░░  │ [C]  Clipboard History                 Cmd+3   │  ░░ │
│ ░░  │ [S]  System Commands                   Cmd+4   │  ░░ │
│ ░░  └────────────────────────────────────────────────┘  ░░ │
│ ░░                                                      ░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
└────────────────────────────────────────────────────────────┘
                    ↑ Vibrancy가 윈도우를 통해 데스크톱을 보여줌

3. 시각적 피드백을 동반한 키보드 우수성

모든 액션에는 키보드 단축키가 있습니다. 모든 단축키에는 시각적 확인이 있습니다.

단축키 표시 패턴:

RESULTS LIST:
┌────────────────────────────────────────────────────────────┐
│ Recent Applications                                        │
│                                                            │
│  (*)  Visual Studio Code                         Cmd+1     │
│       ~/Projects/my-app                                    │
│                                                            │
│  ( )  Figma                                      Cmd+2     │
│       ~/Design/project.fig                                 │
│                                                            │
│  ( )  Terminal                                   Cmd+3     │
│                                                            │
│ ───────────────────────────────────────────────────────────│
│  Actions                            Cmd+K  or  ->  to see  │
└────────────────────────────────────────────────────────────┘

액션 패널:

┌────────────────────────────────────────────────────────────┐
│ Actions for "Visual Studio Code"                  esc <-   │
│                                                            │
│  Open                                             Enter    │
│  Open in New Window                           Cmd+Enter    │
│  ──────────────────────────────────────────────────────── │
│  Show in Finder                             Cmd+Shift+F    │
│  Copy Path                                  Cmd+Shift+C    │
│  ──────────────────────────────────────────────────────── │
│  Move to Trash                           Cmd+Backspace     │
└────────────────────────────────────────────────────────────┘

디자인 원칙: - 단축키를 인라인으로 표시 (툴팁이 아닌) - 수정자 키별로 단축키 그룹화 - 예상되는 곳에 표준 macOS 단축키 사용 - 니모닉 패턴 (⌘⇧F = Finder)


4. 디테일에서의 개성

Raycast는 효율적이지만 무미건조하지 않습니다. 작은 즐거움들이 기억에 남게 만듭니다.

예시: - 업적 달성 시 색종이 효과 - 액션에 대한 미묘한 사운드 - 재치 있는 빈 상태 화면 - 파워 유저를 위한 이스터 에그

빈 상태 예시:

┌────────────────────────────────────────────────────────────┐
│                                                            │
│                        [?]                                 │
│                                                            │
│               No results for "asdfgh"                      │
│                                                            │
│          Try searching for something else,                 │
│          or check out the Extension Store                  │
│                                                            │
│              [Browse Extensions]                           │
│                                                            │
└────────────────────────────────────────────────────────────┘

색종이 효과 패턴 (업적 달성 시):

// After completing onboarding, earning badge, etc.
ConfettiView()
    .transition(.opacity)
    .animation(.spring(), value: showConfetti)

개성 가이드라인: - 즐거움이 지연을 유발해서는 안 됨 - 축하는 획득된 것 (무작위가 아님) - 문구에서의 개성 ("No results for…" vs "Error: 0 results") - 사운드는 선택적이고 눈에 띄지 않게


5. 확장 프로그램 생태계 디자인

Raycast의 확장 프로그램 스토어는 아름답게 디자인되어 있습니다.

확장 프로그램 카드:

┌────────────────────────────────────────────────────────────┐
│  ┌──────┐                                                  │
│  │ [+]  │  GitHub                                          │
│  │      │  Search repos, PRs, and issues                   │
│  └──────┘                                                  │
│           ★★★★★  1.2k ratings  •  By Raycast               │
│                                                            │
│           [Install]                                        │
└────────────────────────────────────────────────────────────┘

확장 프로그램 상세 뷰:

┌────────────────────────────────────────────────────────────┐
│                                                            │
│  ← GitHub                                     [Uninstall]  │
│                                                            │
│  ┌──────────────────────────────────────────────────────┐ │
│  │                                                       │ │
│  │           [Screenshot of extension in use]           │ │
│  │                                                       │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Commands                                                  │
│  ├─ Search Repositories                                    │
│  ├─ My Pull Requests                                       │
│  ├─ Search Issues                                          │
│  └─ Create Issue                                           │
│                                                            │
│  Changelog                                                 │
│  ├─ v2.1.0  Added organization filtering                   │
│  └─ v2.0.0  Complete rewrite with new API                  │
│                                                            │
└────────────────────────────────────────────────────────────┘

6. 익스텐션을 위한 폼 디자인

익스텐션은 일관된 폼 시스템을 사용합니다.

폼 패턴:

┌────────────────────────────────────────────────────────────┐
│ Create GitHub Issue                                   esc  │
│                                                            │
│  Repository                                                │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ raycast/extensions                               ▾   │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Title                                                     │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ Bug: Search not working                              │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Description                                               │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ When I search for...                                 │ │
│  │                                                       │ │
│  │                                                       │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│  Labels                                    (optional)      │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ [bug] [needs-triage]                             +   │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                            │
│           [Create Issue ⌘↵]    [Cancel esc]                │
│                                                            │
└────────────────────────────────────────────────────────────┘

폼 컴포넌트 스타일링:

// Raycast-style form in SwiftUI
Form {
    Section("Repository") {
        Picker("", selection: $repo) {
            ForEach(repos) { repo in
                Text(repo.name).tag(repo)
            }
        }
        .labelsHidden()
    }

    Section("Title") {
        TextField("Bug: ...", text: $title)
    }

    Section("Description") {
        TextEditor(text: $description)
            .frame(minHeight: 100)
    }
}
.formStyle(.grouped)

배워야 할 디자인 패턴

검색 우선 패턴

모든 것은 검색에서 시작됩니다.

┌────────────────────────────────────────────────────────────┐
│  > |                                                       │
│    ^ 실행 즉시 커서가 여기에 위치                            │
│                                                            │
│  명령어, 앱, 파일 등을 검색하려면 입력하세요                   │
└────────────────────────────────────────────────────────────┘

구현 방식: - 실행 시 검색창에 자동 포커스 - 하이라이트가 포함된 퍼지 매칭 - 스마트 랭킹 (최근 + 빈도 + 관련성) - 타이핑과 동시에 결과 표시

계층적 내비게이션

복잡함 없이 깊은 기능에 접근합니다.

Level 1: 메인 검색
    ↓ Enter
Level 2: 익스텐션 명령어
    ↓ Enter
Level 3: 액션 결과
    ↓ ⌘K
Level 4: 액션 패널

항상: esc는 한 단계 뒤로 이동

HUD 확인 알림

작업 흐름을 방해하지 않는 빠른 피드백입니다.

액션 수행 후:
┌────────────────────────┐
│  ✓ 클립보드에 복사됨    │
└────────────────────────┘
    ↑ 잠시 나타났다가 사라짐
      닫기 버튼 불필요
// HUD pattern
struct HUDView: View {
    @State private var show = false

    var body: some View {
        if show {
            Text("✓ Copied")
                .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 }
                    }
                }
        }
    }
}

Raycast에서 가져올 것들

런처/검색 UI를 위해

  1. 50ms 아니면 실패 - 속도는 협상 불가
  2. 모든 곳에 키보드 단축키 - 숨기지 말고 발견 가능하게
  3. 하이라이트가 포함된 퍼지 검색 - 왜 매칭되었는지 보여주기
  4. 액션 패널 (⌘K) - 컨텍스트에 맞는 액션 제공
  5. HUD 확인 알림 - 빠르고 논블로킹 피드백

macOS 앱을 위해

  1. 네이티브 바이브런시 - NSVisualEffectView/.material 사용
  2. SF Symbols - 시스템과 일관성 유지
  3. 시스템 색상 - 강조색 설정 존중
  4. 연속 곡선 모서리 - .cornerRadius(style: .continuous)
  5. 표준 단축키 - ⌘C, ⌘V 등을 재발명하지 말 것

구체적인 테크닉

테크닉 적용 방법
즉시 실행 윈도우 미리 준비, 콘텐츠 지연 로딩
퍼지 검색 Fuse.js 또는 유사 라이브러리 사용
단축키 힌트 결과에 ⌘1, ⌘2 등 인라인 표시
액션 패널 ⌘K 또는 →로 보조 액션 제공
HUD 피드백 토스트 스타일, 자동 사라짐
익스텐션 API 명확한 계약, 일관된 UI

컬러 시스템

Raycast는 시스템과 연동되는 시맨틱 컬러를 사용합니다.

// Raycast-inspired semantic colors
extension Color {
    static let rayBackground = Color(nsColor: .windowBackgroundColor)
    static let raySecondary = Color.secondary
    static let rayTertiary = Color(nsColor: .tertiaryLabelColor)

    // Status colors
    static let raySuccess = Color.green
    static let rayWarning = Color.orange
    static let rayError = Color.red

    // Accent follows system
    static let rayAccent = Color.accentColor
}

// Dark mode example
struct ResultRow: View {
    var body: some View {
        HStack {
            Image(systemName: "app.fill")
                .foregroundStyle(.secondary)

            Text("Application Name")
                .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)
    }
}

핵심 인사이트

“모든 밀리초가 중요합니다. 사용자는 50ms와 100ms의 차이를 체감합니다.”

“키보드 단축키는 문서를 암기해서가 아니라 자연스럽게 발견할 수 있어야 합니다.”

“개성은 소프트웨어를 기억에 남게 만듭니다. 효율성은 소프트웨어를 필수불가결하게 만듭니다.”

“확장 기능은 덧붙여진 느낌이 아니라 네이티브처럼 느껴져야 합니다. 동일한 UI 언어, 동일한 인터랙션.”


자주 묻는 질문

Raycast는 어떻게 50ms 이하의 응답 시간을 달성하나요?

Raycast는 네이티브 Swift 구현(Electron이 아님)을 사용하고, 실행 시 확장 기능 인덱스를 미리 로드하며, 검색 결과를 적극적으로 캐싱하고, 렌더링 파이프라인을 최적화합니다. UI는 데이터가 비동기적으로 로드되는 동안 즉시 나타납니다. 50ms 임계값은 목표가 아닌 엄격한 제약 조건으로 취급됩니다.

Raycast가 macOS에 네이티브처럼 보이는 이유는 무엇인가요?

Raycast는 vibrancy/blur 효과를 위해 NSVisualEffectView를 사용하고, 모든 아이콘에 SF Symbols를 사용하며, 사용자 설정을 존중하는 시스템 강조 색상을 사용하고, 표준 macOS 키보드 단축키를 사용합니다. 창은 연속적인 코너 반경을 가지며 시스템 다크/라이트 모드를 자동으로 따릅니다.

Raycast의 키보드 단축키 접근 방식은 무엇인가요?

모든 액션에는 툴팁에 숨겨지지 않고 결과에 인라인으로 표시되는 키보드 단축키(⌘1, ⌘2 등)가 있습니다. 단축키는 니모닉 패턴을 사용합니다(Finder는 ⌘⇧F, Copy Path는 ⌘⇧C). 액션 패널(⌘K)은 각각의 단축키가 있는 보조 액션을 제공합니다.

Raycast는 속도 저하 없이 어떻게 개성을 더하나요?

축하 효과는 무작위가 아닌 성과 달성 후에만 짧게 나타납니다—콘페티는 업적 후에 등장합니다. 빈 상태에는 재치 있는 문구가 있습니다("Error: 0 results" 대신 "No results for…"). 사운드는 선택 사항이며 눈에 띄지 않습니다. 즐거움이 사용자를 차단하거나 지연을 추가하는 일은 절대 없습니다.

Raycast의 확장 기능 시스템은 어떻게 일관성을 유지하나요?

모든 확장 기능은 동일한 UI 컴포넌트(폼, 리스트, 액션 패널)를 사용하고, 동일한 내비게이션 패턴(Enter로 들어가기, Escape로 뒤로 가기)을 따르며, 시스템 스타일링을 상속받습니다. API가 일관성을 강제하므로 서드파티 확장 기능도 내장 기능과 구분이 안 될 정도로 느껴집니다.


리소스

  • 웹사이트: raycast.com
  • 스토어: raycast.com/store - 확장 기능 디자인 연구
  • 문서: 확장 기능 개발 가이드라인
  • 블로그: 성능 관련 엔지니어링 포스트
  • GitHub: github.com/raycast - 오픈 소스 확장 기능