Back to Home

Building Model Faceoff

Model Faceoff

Building Model Faceoff

Compare AI Models from Different Providers Side-by-Side

The Problem: One Model Doesn't Fit All

As AI models proliferate, choosing the right one for your task has become increasingly difficult. Different models excel at different things:

  1. GPT-4o excels at creative writing and nuanced conversations
  2. Claude is known for careful reasoning and following instructions
  3. Gemini offers strong multimodal capabilities and long context windows
  4. Llama 3 provides excellent performance for open-source enthusiasts
  5. Mistral delivers impressive results with lower latency

When you're building AI-powered applications or just trying to find the best model for your workflow, you need to actually compare outputs side-by-side. Opening multiple browser tabs to different AI playgrounds is tedious. Copy-pasting prompts between them is error-prone. And tracking which model performs best for specific tasks? Nearly impossible.

I needed a tool to compare models simultaneously, with real-time streaming, conversation history, and cost tracking—all in one place.

The Vision: A Desktop Command Center for AI Models

I set out to build Model Faceoff: an Electron desktop app that serves as a single interface for comparing any AI model from any provider. The core principles:

Side-by-Side Comparison

Compare up to 3 models simultaneously with the same prompt. See responses stream in real-time and evaluate quality differences instantly.

OpenRouter Integration

One API key gives you access to 100+ models from OpenAI, Anthropic, Google, Meta, Mistral, and more. No need to manage multiple API keys.

Local-First Architecture

All conversation history and preferences stored locally in SQLite. Your data stays on your machine. No cloud sync, no subscriptions.

Usage Tracking & Cost Estimates

Track token usage, response times, and estimated costs per model. Make informed decisions about price-to-performance tradeoffs.

Model Faceoff in Action

Side-by-Side Model Comparison

Compare responses from multiple AI models simultaneously. Each model streams its response in real-time, with full markdown rendering and syntax highlighting for code blocks.

Model Faceoff comparing multiple AI models side-by-side with streaming responses

Model Selection

Choose from 100+ models across OpenAI, Anthropic, Google, Meta, Mistral, and more—all with a single API key.

Model Faceoff model selection interface showing available AI models

Conversation History

All conversations saved locally with full search. Replay any comparison and see how different models responded.

Model Faceoff conversation history panel

API Logs & Debugging

Full visibility into every API call with request/response details, latency metrics, and token counts for debugging and optimization.

Model Faceoff API logs showing request details and response metrics

Key Features

Streaming Responses

Watch responses appear in real-time as models generate them. No waiting for complete responses—see the thinking unfold token by token.

Markdown Rendering

Full markdown support with syntax highlighting for code blocks. See formatted responses exactly as they're meant to be displayed.

Conversation History

All conversations saved locally with full search capabilities. Replay any conversation, compare how different models responded to the same prompts.

Model Presets

Save your favorite model combinations as presets. Switch instantly between "Creative Writing" (GPT-4o vs Claude) and "Code Review" (Claude vs Gemini) configurations.

API Logs & Debugging

Full visibility into every API call. See request/response details, latency metrics, and token counts for debugging and optimization.

Auto-Updates

Automatic updates via GitHub Releases. The app checks for new versions and offers one-click installation—always stay current with the latest features.

The Tech Stack

Electron + React 19 + TypeScript

Electron provides the desktop runtime, React 19 handles the UI with its latest concurrent features, and TypeScript ensures type safety across the entire codebase. The multi-process architecture (main process, renderer process, preload script) keeps the app secure and performant.

SQLite with better-sqlite3

All data persists locally in SQLite. The synchronous API of better-sqlite3 makes database operations predictable and fast. WAL mode ensures concurrent read access without blocking. Conversations, messages, settings, and API logs all live in a single portable database file.

Vite + Electron Forge

Vite provides lightning-fast hot module replacement during development. Electron Forge handles building, packaging, and publishing for macOS (DMG), Windows (installer), and Linux (deb/rpm). Three separate Vite configs manage main process, renderer process, and preload script builds.

Tailwind CSS + shadcn/ui

Utility-first CSS with Tailwind keeps styling consistent and maintainable. Radix UI primitives from shadcn/ui provide accessible, customizable components for dialogs, tabs, and form elements. The result: a polished, native-feeling desktop experience.

OpenRouter API

OpenRouter provides a unified API for 100+ models from different providers. One API key, one interface, endless possibilities. The app fetches available models dynamically, so new models appear automatically as OpenRouter adds them.

The Architecture: Electron's Multi-Process Model

Electron enforces security through process isolation:

  • Main Process: Node.js environment running main.ts—manages windows, handles system APIs, initializes database, runs auto-updater
  • Renderer Process: Browser environment running React—completely isolated from Node.js APIs for security
  • Preload Script: Secure bridge exposing specific IPC channels via contextBridge

IPC Communication Pattern

Every feature follows a strict IPC contract with typed responses:

// All IPC handlers return IPCResponse<T>
interface IPCResponse<T> {
  success: boolean;
  data?: T;
  error?: { code: string; message: string };
}

// Renderer calls main via window.api
const result = await window.api.conversations.create({
  modelIds: ['gpt-4o', 'claude-3-opus'],
  title: 'My comparison'
});

// Type-safe access to response
if (result.success) {
  console.log(result.data.conversationId);
}

This pattern provides compile-time safety for all cross-process communication. TypeScript catches type mismatches before runtime, and the standardized response format makes error handling predictable.

The Database Design: Simple and Effective

SQLite with WAL mode provides concurrent read access while maintaining data integrity. The schema is intentionally minimal:

Core Tables

  • settings: Key-value store for configuration (API key, preferences, window state)
  • conversations: Parent records with title, model IDs, timestamps
  • messages: Individual messages with role, content, model ID, token counts
  • api_logs: Full request/response logging for debugging

The synchronous API of better-sqlite3 simplifies code significantly—no async/await ceremony for database operations. This makes the codebase more readable and eliminates entire categories of race conditions.

The Streaming Challenge: Real-Time Token Display

Streaming responses from multiple models simultaneously requires careful coordination:

  1. User sends prompt → Main process receives via IPC
  2. Main process initiates parallel fetch calls to OpenRouter for each selected model
  3. As chunks arrive, main process emits events back to renderer via IPC
  4. Renderer updates UI in real-time, accumulating tokens per model
  5. On completion, full response saved to database with token counts

The challenge: Electron's IPC is event-based, not streaming. Solution: chunked events with model identification:

// Main process emits chunks as they arrive
mainWindow.webContents.send('stream-chunk', {
  modelId: 'gpt-4o',
  chunk: 'Here is the ',
  done: false
});

// Renderer accumulates chunks per model
window.api.onStreamChunk((data) => {
  setResponses(prev => ({
    ...prev,
    [data.modelId]: prev[data.modelId] + data.chunk
  }));
});

This architecture handles any number of concurrent streams without blocking the UI.

Cross-Platform Distribution

Model Faceoff runs on macOS, Windows, and Linux with platform-specific installers:

macOS

DMG installer with Apple Silicon and Intel builds. Code-signed and notarized.

Windows

Squirrel installer with auto-updates. Single .exe setup.

Linux

DEB and RPM packages for Debian/Ubuntu and Fedora/RHEL.

Electron Forge's publisher-github integration automatically uploads release artifacts to GitHub Releases. The electron-updater package checks for new versions on startup and offers one-click installation.

The Challenges and Trade-Offs

1. Bundle Size Management

Electron apps ship with Chromium, resulting in 150MB+ base size. Vite's tree-shaking and the auto-unpack-natives plugin help minimize additional bloat. The tradeoff: desktop power for download size.

2. Cross-Process Type Safety

TypeScript doesn't inherently understand IPC boundaries. The solution: shared type definitions imported by both main and renderer, with the preload script serving as the type-safe contract between them.

3. Native Module Compatibility

better-sqlite3 is a native Node.js addon that must be rebuilt for each platform and Electron version. Electron Forge's rebuild plugin handles this automatically, but CI/CD pipelines need separate builds for each target.

4. Rate Limits and Error Handling

OpenRouter passes through rate limits from upstream providers. The app handles 429 responses gracefully with user feedback. Each model stream operates independently—if one fails, others continue.

The Results: One Interface for All Models

Without Model Faceoff

  • Open 3 browser tabs to different AI playgrounds
  • Copy-paste the same prompt to each
  • Wait for responses separately
  • Manually track which model performed better
  • Result: Fragmented, tedious, no history

With Model Faceoff

  • Select 3 models from dropdown
  • Type prompt once, click Send to All
  • Watch responses stream side-by-side
  • All conversations saved and searchable
  • Result: Unified, efficient, full history

Technical Highlights

Electron 38 with latest Chromium
React 19 with concurrent features
TypeScript end-to-end
SQLite with WAL mode
Vite for sub-second hot reload
100+ AI models via OpenRouter
Real-time streaming for all responses
Auto-updates via GitHub Releases
Cross-platform macOS, Windows, Linux
Open source MIT license

Conclusion: The Right Tool for the Right Job

Model Faceoff proves that Electron desktop apps remain a powerful choice for developer tools. The combination of web technologies for rapid UI development with Node.js for system access creates applications that feel native while shipping cross-platform.

The key insight: AI model selection shouldn't require faith. Comparing outputs side-by-side reveals differences that specs and benchmarks can't capture. What reads well in a GPT-4o response might lack the precision Claude brings to the same prompt.

With OpenRouter handling the API complexity, the app stays focused on what matters: making comparison effortless.

Stop guessing which model is best. Download Model Faceoff and see for yourself.

Tech Stack Summary

Frontend: React 19, TypeScript, Tailwind CSS, Radix UI (shadcn/ui), Lucide Icons

Backend: Electron 38, Node.js, better-sqlite3, electron-updater

Build: Vite, Electron Forge, PostCSS

API: OpenRouter (unified access to OpenAI, Anthropic, Google, Meta, Mistral, and more)

Distribution: GitHub Releases with auto-updates for macOS, Windows, Linux

Ready to Compare AI Models Like a Pro?

Download Model Faceoff for free and start comparing models side-by-side. Or if you need custom AI tooling built for your team, let's talk.

Download Free