English · 中文
A Chinese-ink-flavoured take on QL-Win/QuickLook. Every upstream preview capability is preserved. On top of that, the main-window chrome is rewritten as a four-plate XAML layout with a dual-theme engine, and the buttons plate gains an AI-analyze entry point that routes the current preview file through the OpenRouter chat/completions API and persists the response as Markdown. GPL-3.0 inherited.
| Area | Upstream QuickLook | This fork (Ink) |
|---|---|---|
| Main-window chrome | Fluent captioned window | Four-plate Ink layout with 3 px transparent seams and asymmetric corner cuts |
| Theme | Follows system | Explicit Ink / Paper toggle with charcoal or paper noise texture |
| In-app AI analysis | Not offered | Light-bulb key on the buttons plate → OpenRouter multi-model (Gemini / Claude / DeepSeek / GLM) |
| File-type coverage | Full IViewer plugin catalogue |
Same — every plugin is preserved |
| Plugin system | IViewer |
IViewer, unchanged |
| License | GPL-3.0 | GPL-3.0 (inherited) |
The main viewer window is rewritten as a four-plate composition — a name plate carrying the file name, a buttons plate carrying every action key, a content plate hosting the actual preview, and a status plate displaying file metadata. Plates are separated by 3 px transparent seams so the desktop or the window behind is visible straight through them, which makes the window read as a floating composition rather than a solid block.
Corners are cut asymmetrically with a Path clip: the title plate cuts TR14 (top-right only), the buttons plate cuts BL14 (bottom-left only). The two cuts diagonally balance each other and give the window an editorial character without touching the other two corners.
Two ResourceDictionary themes ship — Ink (dark, charcoal grain) and Paper (light, warm paper grain). Switching is instant via SwitchTheme() and propagates into WebView2-backed viewers (Markdown, HTML) through PreferredColorScheme, so the content plate re-styles atomically with the chrome.
Each plate surface is a 96×96 tiled ImageBrush seeded from a fixed Random(seed), so the grain reproduces byte-for-byte across runs. The brush is exposed via ViewerWindow.GetPlateNoiseBrush(isDark) so the AI dialogs re-use the same instance and stay visually consistent with the main window.
Interaction: hover produces a Storyboard-driven lift on the key you point at, mouse movement inside the window drives a four-quadrant TranslateTransform parallax on the plates, and the window entrance plays a staggered DoubleAnimation bite-in — plates settle from a small offset instead of appearing pinned.
Source lives in QuickLook/ViewerWindow.* (split across Actions.cs, HwndHostBridge.cs, PlateAnimations.cs, Properties.cs) and the theme dictionaries in QuickLook.Common/Styles/MainWindowStyles(.Dark).xaml.
A light-bulb key (Segoe Fluent glyph E82D) is added to the buttons plate, positioned between buttonShare and the divider. Clicking it wires through OnAIAnalyzeClick and runs the following pipeline:
- Prompt capture —
AIAnalyzePromptDialogopens as a modal reskinned to match the shell (three plates, vacuum seams, single-corner cuts, subtitle showing the current model). The user can leave the prompt empty for an auto-analysis, or type a specific instruction and submit with Ctrl+Enter. - Dispatch —
CallOpenRouterAsync()classifies the file by MIME and composes the request body. Text files are sent ascontent:stringwith head/tail sampling for anything over 60 KB (40 KB head + 15 KB tail + gap marker). Images are sent asimage_urlwith a data URI. PDFs are sent asfile+file_data. Everything above 20 MB raw (≈ 27 MB base64) is rejected up front with a specific error rather than a silent OpenRouter 400. - Response —
usage:{include:true}asks OpenRouter to return exact token counts and USD cost. Whenusage.costis missing (older routes, some proxies), anAiPricingtable provides a fallback estimate keyed on the model id. - Result window —
AIAnalyzeResultWindowopens as a non-modal window in the same visual system as the prompt dialog. It shows the model output, a footer line withmodel · input+output tokens · $cost, a Copy button, and a Save button that writes the response as Markdown toAIAnalyzeSaveRoot.
Model and API key are stored in QuickLook.config (never in source). Both are edited through the tray icon's right-click menu — see Usage below.
Source: QuickLook/AIAnalyze*.cs plus the tray-menu wiring in QuickLook/TrayIconManager.cs.
The IViewer plugin system, every format viewer, the named-pipe IPC, and the tray core are untouched. Everything that works in upstream QuickLook works here.
Two options:
Prebuilt MSI — download from the Releases page. None available at the time of the 0.1.0 tag; the first binary release will land once a GitHub Actions build pipeline is set up.
From source — see Build from source below. All you need is Windows and the .NET 10 SDK.
Select any file in Explorer and press Space — exactly the upstream QuickLook behaviour. The Ink chrome renders around whatever viewer plugin handles the file type.
Three ways:
- The lightbulb-shaped key on the right of the buttons plate — rotates between Paper and Ink instantly.
- Tray icon → right-click → Theme — three-state selector: Light / Dark / Follow System.
QuickLook.config→ThemeOverride— persist a choice manually. Values:Light,Dark, or omit to follow the plugin or OS.
The three sources stay in sync — flipping the key writes the same setting the tray menu reads.
First-time setup:
- Tray icon → right-click → OpenRouter API Key... — enter your key. It goes into
QuickLook.configunderOpenRouterApiKey, never into source or logs. - Tray icon → right-click → AI Analyze — the section lists seven curated models with
$in / $outpricing per million tokens. Click one to select; the choice persists.
Per analysis:
- Preview a file with Space.
- Click the 💡 light-bulb key on the buttons plate.
- In the prompt dialog: leave the field empty for an auto-template (built from the file type — code, CSV, Markdown, image, PDF, etc.) or type a specific instruction. Ctrl+Enter submits.
- The result window shows the response, model, token counts, and cost. Copy puts the raw text on the clipboard. Save persists a Markdown file.
By default, saved analyses land in %USERPROFILE%\Documents\QuickLook AI Analyses\. Override by adding one line to %APPDATA%\QuickLook\QuickLook.config:
<AIAnalyzeSaveRoot>D:\my\notes</AIAnalyzeSaveRoot>The value is read every time you press Save, so changes take effect without restarting.
Seven models are wired into the tray menu with fixed pricing labels:
| Model id | Short name | Modality | $ per 1M tokens (in / out) |
|---|---|---|---|
google/gemini-3.5-flash |
Gemini 3.5 Flash | Multimodal | $1.50 / $9.00 |
google/gemini-3.1-flash-lite |
Gemini 3.1 Flash Lite | Multimodal | $0.25 / $1.50 |
google/gemini-2.5-pro |
Gemini 2.5 Pro | Multimodal | $1.25 / $10.00 |
deepseek/deepseek-chat-v3.1 |
DeepSeek Chat v3.1 | Text-only | $0.21 / $0.79 |
openai/gpt-5-mini |
GPT-5 Mini | Multimodal | $0.25 / $2.00 |
anthropic/claude-sonnet-5 |
Claude Sonnet 5 | Multimodal | $2.00 / $10.00 |
z-ai/glm-5.2 |
GLM 5.2 | Text-only | $0.42 / $1.32 |
Custom models — any OpenRouter model id can be used. Set OpenRouterModel directly in QuickLook.config:
<OpenRouterModel>your/model-id-here</OpenRouterModel>The tray menu will not display a check mark for unlisted models, but the pipeline dispatches them fine. Pricing shown in the result window falls back to $0 for unlisted models since there is no local table entry — token counts are still exact from OpenRouter.
Sending an image or PDF to a text-only model returns whatever OpenRouter's fallback behaviour is (usually an error). Stick to multimodal models for non-text.
Fork-specific settings live in %APPDATA%\QuickLook\QuickLook.config:
| Setting | Default | Description |
|---|---|---|
ThemeOverride |
Dark |
Light / Dark / omit to follow plugin or OS. |
OpenRouterApiKey |
(empty) | Set through tray icon → OpenRouter API Key... Never edit by hand unless you have to. |
OpenRouterModel |
google/gemini-3.5-flash |
Any OpenRouter model id. |
AIAnalyzeSaveRoot |
%USERPROFILE%\Documents\QuickLook AI Analyses |
Where the Save button writes Markdown files. |
Upstream QuickLook settings (AutoStartup, CloseOnLostFocus, Topmost, ShowInTaskbar, plugin toggles, …) remain valid and untouched.
Prerequisites:
- Windows 10 22H2 or Windows 11
- .NET 10 SDK — this fork currently pins to
10.0.301 - Visual Studio 2022 (17.x) optional; command-line
dotnet buildis enough
Build the main app (Release, x64):
dotnet build QuickLook.slnx -c Release -p:Platform=x64Output lands under QuickLook\bin\x64\Release\net10.0-windows10.0.19041.0\. Copy or run the binary from there; no installer step needed for a from-source build.
More details in CONTRIBUTING.md.
Product direction, visual decisions and acceptance testing: @lucaszhouc. Most of the fork's implementation code was written by Anthropic Claude models under the maintainer's direction — see AUTHORS.md for the module-level breakdown.
Upstream QuickLook remains © the QuickLook contributors under GPL-3.0. See LICENSE.
Honestly, GitHub notifications tend to slip past me — the fastest way to reach me is email: lucaszhouc@gmail.com. Bug reports, PR ideas you want to sanity-check before writing them, questions before you fork the code, or just curiosity about a design decision — all welcome.
This project is a fork of QL-Win/QuickLook. See the upstream repository for the original project, its documentation, and the full contributor list. GPL-3.0 is preserved on every source file that carries an upstream copyright header.
