Under the hood

Architecture Tutorial

A detailed, step-by-step deep-dive into how Crest works. From hotkey registration in Rust to high-fidelity rendering in React.

Sourced directly from the official Crest codebase tutorial.

Overview

Overview of Crest

Crest is a powerful, unified search engine and productivity tool designed to streamline your digital workflow. It acts as a central hub for accessing applications, files, web searches, calculations, and more, all through a simple and intuitive interface.

This tutorial will guide you through the core components of Crest, from its global hotkey management to its sophisticated plugin system and state management.

Key Features

  • Global Hotkey & Window Management: Instant access to Crest from anywhere in your system.
  • Unified Search Engine: A single search bar to find everything you need.
  • Data Indexers: Efficiently indexing your local data for lightning-fast retrieval.
  • Plugin System: Extend Crest's functionality with custom plugins.
  • Tauri IPC Bridge: Secure communication between the frontend and the Rust backend.
  • Frontend State Management: A responsive and synchronized user interface powered by Zustand.

Explore the chapters on the left to dive deep into each of these areas and understand how Crest is built and how it works.

Chapter 01

Global Hotkey & Window Management

In this chapter, we explore how Crest handles global hotkeys and window management using the Tauri framework. This is the entry point for the user, allowing them to summon Crest instantly with a simple keyboard shortcut.

The Global Hotkey

Crest uses the tauri-plugin-global-shortcut to listen for a specific key combination (e.g., Alt+Space or Cmd+Space). When this shortcut is pressed, the backend receives an event and toggles the visibility of the main window.

Backend Implementation (Rust)

// src-tauri/src/main.rs
// ... imports ...

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_global_shortcut::Builder::new().build())
        .setup(|app| {
            let handle = app.handle();
            // Register the global shortcut
            app.global_shortcut_manager().register("Alt+Space", move || {
                let window = handle.get_window("main").unwrap();
                if window.is_visible().unwrap() {
                    window.hide().unwrap();
                } else {
                    window.show().unwrap();
                    window.set_focus().unwrap();
                }
            }).unwrap();
            Ok(())
        })
        // ...
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Window Management

Crest's main window is configured to be borderless and transparent, providing a modern "palette" feel. We also handle events like "blur" (when the window loses focus) to automatically hide the application.

Blur Event Handling

// src/App.tsx
import { useEffect } from 'react';
import { appWindow } from '@tauri-apps/api/window';

function App() {
  useEffect(() => {
    const unlisten = appWindow.onFocusChanged(({ payload: focused }) => {
      if (!focused) {
        appWindow.hide();
      }
    });
    return () => {
      unlisten.then(f => f());
    };
  }, []);
  // ...
}

By combining global shortcuts with smart window event handling, Crest provides a seamless and "always-available" experience for the user.

Chapter 03

Data Indexers

In our last chapter, we unveiled the magic of Crest's Unified Search Engine, learning how it intelligently processes your queries to find applications, files, and even web results. But a truly smart search engine needs to know what's on your computer! How does Crest get this information? That's where Data Indexers come into play.

Imagine Crest as a super-fast librarian. The Unified Search Engine is how you ask the librarian for a book. But before you can ask, someone needs to actually go out, find all the books, read their titles, authors, and summaries, and neatly organize them on shelves. These dedicated "book-finders" and "organizers" are Crest's Data Indexers.

What is a Data Indexer?

A Data Indexer is a specialized background process that crawls through a specific type of data on your system, extracts the important bits, and stores them in a highly optimized "Index" (like a giant, searchable catalog).

  • App Indexer: Scans system application folders (like /Applications or C:\Program Files) for app names, icons, and locations.
  • File Indexer: Scans your home directory and other folders you specify for file names, paths, and metadata.
  • Clipboard Indexer: Scans your system clipboard for recently copied text, links, or images.

The App Indexer (A Rust Example)

In Crest's backend (written in Rust), the App Indexer is responsible for finding your installed programs.

// src-tauri/src/indexers/app_indexer.rs (Simplified)
use std::fs;
use std::path::Path;

pub struct AppInfo {
    pub name: String,
    pub path: String,
}

pub fn index_apps() -> Vec<AppInfo> {
    let mut apps = Vec::new();
    let app_dir = Path::new("/Applications");

    if let Ok(entries) = fs::read_dir(app_dir) {
        for entry in entries.flatten() {
            let path = entry.path();
            if path.extension().and_then(|s| s.to_str()) == Some("app") {
                let name = path.file_stem().unwrap().to_str().unwrap().to_string();
                apps.push(AppInfo { name, path: path.to_str().unwrap().to_string() });
            }
        }
    }
    apps
}
Chapter 04

Plugin System

In our journey through Crest so far, we've learned how to summon it with a Global Hotkey, how its Unified Search Engine intelligently finds information, and how Data Indexers keep everything up-to-date. But what if you need Crest to do something really specific? That's where the Plugin System shines!

The main problem the Plugin System solves is customization without complexity. Instead of having to change Crest's core code, you can write small, independent programs (plugins) that Crest can run.

A Simple JavaScript Plugin (Conceptual)

Crest allows you to write plugins in simple JavaScript. Here's what a basic "Hello World" plugin might look like:

// hello-plugin.js
module.exports = {
  onSearch: async (query) => {
    if (query.startsWith('hello')) {
      return [{
        id: 'hello-result',
        title: 'Say Hello!',
        subtitle: 'Crest is happy to see you.',
        category: 'Plugin',
        action: { type: 'copy', value: 'Hello from Crest!' }
      }];
    }
    return [];
  },
  onAction: (result) => {
    console.log("Plugin action triggered:", result.title);
  }
};
Chapter 05

Tauri IPC Bridge

The "Tauri IPC Bridge" is exactly this secure communication channel. "IPC" stands for Inter-Process Communication, which is just a fancy way of saying "two separate programs talking to each other." Tauri, the framework Crest is built with, provides an incredibly safe and fast bridge between the frontend and the backend.

The core problem the IPC Bridge solves is secure and efficient coordination.

How to Use the IPC Bridge (A Search Example)

1. Defining a Command in the Backend (Rust)

// src-tauri/src/main.rs (Simplified)
#[tauri::command]
fn search(query: String) -> Vec<SearchResult> {
    println!("Backend received search query: {}", query);
    let results = core_engine::run_search(query);
    results
}

fn main() {
  tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![search])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}

2. Invoking the Command from the Frontend (TypeScript)

// src/components/SearchInput.tsx (Simplified)
import { invoke } from '@tauri-apps/api/core';

const handleSearch = async (query: string) => {
  try {
    const results = await invoke<SearchResult[]>('search', { query: query });
    console.log("Frontend received results:", results);
  } catch (error) {
    console.error("IPC call failed:", error);
  }
};
Chapter 06

Frontend State Management

"Frontend State Management" is the system that organizes all the monitors, data screens, and controls within the control room itself. It ensures that when you type a query, the search box updates, the results list changes, and the preview panel shows details for the correct active item, all in perfect sync.

Zustand State Store

Crest uses Zustand to manage its global state. This store holds the current search results and the active selection.

// src/store/useSearchStore.ts
import { create } from 'zustand';
import { SearchResult } from '../types/ipc';

interface SearchState {
  results: SearchResult[];
  selectedIndex: number;
  setResults: (results: SearchResult[]) => void;
  nextResult: () => void;
  prevResult: () => void;
}

export const useSearchStore = create<SearchState>((set) => ({
  results: [],
  selectedIndex: 0,
  setResults: (results) => set({ results, selectedIndex: 0 }),
  nextResult: () => set((state) => ({ 
    selectedIndex: Math.min(state.selectedIndex + 1, state.results.length - 1) 
  })),
  prevResult: () => set((state) => ({ 
    selectedIndex: Math.max(state.selectedIndex - 1, 0) 
  })),
}));

By centralizing the state in a Zustand store, any component in Crest can easily access and update the search results or the currently selected item, ensuring a consistent user experience.