本文へ移動
cccskills
無料GitHub で公開

cross-platform-desktop

Cross-platform desktop development for macOS and Windows -- platform abstractions, UI convention differences, and multi-platform CI/CD. Activate on: cross-platform app, macOS and Windows, platform differences, DMG installer, MSI installer, NSIS installer, Cmd vs Ctrl, platform abstractions, menu bar differences, native conventions. NOT for: mobile apps, web-only apps, Tauri-specific internals (use rust-tauri-development).

インストール方法を見る

含まれるファイル(1)

  • SKILL.md13.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Cross-Platform Desktop Development

Build desktop applications that ship on macOS AND Windows. This skill covers the platform differences that break your app, the abstraction strategies that save your sanity, and the CI/CD discipline that catches problems before users do.

When to Use / Do NOT Use For

Use for: Desktop apps targeting macOS + Windows, framework evaluation (Tauri vs Electron vs Flutter), platform-convention-aware UI design, multi-platform CI/CD, debugging cross-platform rendering/behavior.

Do NOT use for: Web-only apps | Mobile apps | Single-platform native (SwiftUI/WinUI) | Linux-only desktop

Framework Decision Matrix (2025-2026)

FactorTauri v2ElectronFlutter Desktop
Bundle size2-10 MB80-150 MB15-30 MB
Idle memory30-40 MB150-300 MB60-100 MB
RenderingNative webview (varies per OS)Bundled Chromium (identical)Skia engine (identical)
BackendRustNode.jsDart
Plugin ecosystemGrowing (50+ official)Mature (thousands)Moderate
Security modelDeny-by-defaultOpen by defaultSandboxed
Cross-platform renderingWebKit (macOS) vs Chromium (Windows)Chromium everywhereSkia everywhere
Best forPerformance, security, small bundleWeb teams, pixel-perfect parityCustom UI, animation

Choose Tauri when performance and security matter and you accept rendering differences. Choose Electron when pixel-identical rendering across platforms is non-negotiable. Choose Flutter when you also target mobile and want one widget toolkit everywhere.

Platform Differences That Break Apps

File Paths

ConcernmacOSWindows
Separator/\ (but / works in most APIs)
App data~/Library/Application Support/com.app.id/%APPDATA%\AppName\
Temp dir$TMPDIR%TEMP%
Home dir$HOME (~)%USERPROFILE%
Case sensitivityNo by default (APFS)No (NTFS)
Max path length1024 chars260 chars default, 32767 with opt-in
Reserved namesNoneCON, PRN, AUX, NUL, COM1-9, LPT1-9

Never hardcode paths. Use platform APIs:

// Rust: dirs crate
let config = dirs::config_dir().unwrap();
// macOS: ~/Library/Application Support
// Windows: C:\Users\<user>\AppData\Roaming

let data = dirs::data_dir().unwrap();
let cache = dirs::cache_dir().unwrap();
// Tauri JS API
import { appDataDir, homeDir, tempDir } from "@tauri-apps/api/path";

const dataDir = await appDataDir(); // Platform-correct automatically

Keyboard Shortcuts

ActionmacOSWindows/Linux
CopyCmd+CCtrl+C
PasteCmd+VCtrl+V
UndoCmd+ZCtrl+Z
RedoCmd+Shift+ZCtrl+Y
PreferencesCmd+,Ctrl+, (or Edit > Preferences)
Quit appCmd+QAlt+F4
Close windowCmd+WCtrl+W or Alt+F4
FindCmd+FCtrl+F
SaveCmd+SCtrl+S

Abstraction pattern:

const isMac = navigator.platform.includes("Mac");

function formatShortcut(key: string): string {
  const mod = isMac ? "\u2318" : "Ctrl+";
  return `${mod}${key.toUpperCase()}`;
}

function isModKey(e: KeyboardEvent): boolean {
  return isMac ? e.metaKey : e.ctrlKey;
}

// Usage
document.addEventListener("keydown", (e) => {
  if (isModKey(e) && e.key === "s") {
    e.preventDefault();
    saveDocument();
  }
});

Window Chrome and Menus

ElementmacOSWindows
Menu bar locationTop of screen (global)Top of window
Window controlsTop-left (close/minimize/zoom)Top-right (minimize/maximize/close)
System trayMenu bar area (top-right)Notification area (bottom-right)
Close last windowApp keeps runningApp quits
Quit appCmd+Q or menuClosing last window or Alt+F4
Native dialogsSheet (slides from title bar)Modal (centered on window)
Dark modeNSAppearance / systemprefers-color-scheme + registry
Default fontSF Pro (system)Segoe UI (system)

The close-vs-quit behavior is the most common cross-platform bug. Handle it explicitly:

// Tauri: platform-correct close behavior
app.on_window_event(|window, event| {
    if let tauri::WindowEvent::CloseRequested { api, .. } = event {
        #[cfg(target_os = "macos")]
        {
            // macOS convention: hide, do not quit
            window.hide().unwrap();
            api.prevent_close();
        }
        // Windows: default close-and-quit is correct
    }
});

Rendering Differences (Tauri-Specific)

Tauri uses native webviews per platform. This causes subtle differences:

IssuemacOS (WebKit)Windows (WebView2/Chromium)
Font renderingSub-pixel antialiasingClearType / grayscale
Default system fontSF ProSegoe UI
Emoji renderingApple Color EmojiSegoe UI Emoji
Scrollbar stylingWebKit-specificChromium-specific
CSS container queriesCheck WebKit versionGenerally supported
Date/time inputNative WebKit pickerChromium picker

Electron avoids these entirely by bundling Chromium on all platforms. If rendering parity is critical, this is the strongest argument for Electron.

Mitigation for Tauri:

/* Cross-platform font stack */
body {
  font-family:
    -apple-system,        /* macOS SF Pro */
    BlinkMacSystemFont,   /* macOS Chrome fallback */
    "Segoe UI",           /* Windows */
    Roboto,               /* Android/Linux */
    system-ui,
    sans-serif;
}

/* Normalize scrollbars */
::-webkit-scrollbar {
  width: 8px;
}
::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, 0.3);
  border-radius: 4px;
}

DPI and Display Scaling

FactormacOSWindows
Default scale2x (Retina)1x, 1.25x, 1.5x, 2x (user configurable)
Scaling methodInteger (2x only on most displays)Fractional (125%, 150%)
Common gotchaNone (2x is standard)125% scaling causes blurry rendering

Fix: Use CSS logical units, SVG icons (not bitmaps), and test at 100%, 125%, and 150% scaling on Windows.

Installer Formats

FormatPlatformToolUse Case
DMGmacOScreate-dmg, Tauri bundlerStandard drag-to-Applications
.app bundlemacOScargo tauri buildThe application itself
MSIWindowsWiX (via Tauri)Enterprise, Group Policy
NSIS EXEWindowsNSIS (via Tauri)Consumer apps, custom UI
AppImageLinuxTauri bundlerUniversal portable binary
.debLinuxTauri bundlerDebian/Ubuntu

Tauri config for all formats:

{
  "bundle": {
    "targets": ["dmg", "nsis", "msi", "deb", "appimage"],
    "macOS": {
      "minimumSystemVersion": "10.15",
      "dmg": {
        "appPosition": { "x": 180, "y": 170 },
        "applicationFolderPosition": { "x": 480, "y": 170 }
      }
    },
    "windows": {
      "nsis": {
        "installMode": "both",
        "displayLanguageSelector": true
      },
      "wix": {
        "language": "en-US"
      }
    }
  }
}

CI/CD: GitHub Actions Matrix Build

Use a matrix strategy to build on native runners for each platform. The full pipeline YAML is in rust-app-distribution -- the key pattern:

strategy:
  fail-fast: false
  matrix:
    include:
      - platform: macos-latest     # ARM Mac (M-series)
        target: aarch64-apple-darwin
      - platform: macos-13         # Intel Mac
        target: x86_64-apple-darwin
      - platform: windows-latest
        target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.platform }}

macOS universal binary (ARM + Intel in one): use target universal-apple-darwin with rustup target add aarch64-apple-darwin x86_64-apple-darwin.

Platform-Specific Code Patterns

Rust: cfg(target_os) Guards

#[cfg(target_os = "macos")]
fn platform_init(app: &tauri::App) {
    // macOS-specific: dock icon, activation policy
    app.set_activation_policy(tauri::ActivationPolicy::Regular);
}

#[cfg(target_os = "windows")]
fn platform_init(app: &tauri::App) {
    // Windows-specific: jump list, toast notification setup
}

// Always provide a fallback
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
fn platform_init(_app: &tauri::App) {}

TypeScript: Runtime Platform Detection

import { platform } from "@tauri-apps/plugin-os";

const os = await platform(); // "macos" | "windows" | "linux"

// Conditional UI
function ShortcutHint({ action }: { action: string }) {
  const mod = os === "macos" ? "\u2318" : "Ctrl";
  return <kbd>{mod}+{action}</kbd>;
}

CSS: Platform-Aware Styling

/* Tauri injects data-platform attribute (configure in setup) */
[data-platform="macos"] .titlebar {
  padding-left: 80px; /* Space for traffic lights */
}

[data-platform="windows"] .titlebar {
  padding-right: 140px; /* Space for min/max/close */
}

Testing Across Platforms

Local Development

  • Primary dev machine: Build and test natively
  • Secondary platform: VM (Parallels/VMware for Windows on Mac, or vice versa), or dedicated hardware
  • Quick check: CI runners catch build failures even without local testing

Automated Testing in CI

# Run tests on both platforms in CI
test:
  strategy:
    matrix:
      os: [macos-latest, windows-latest]
  runs-on: ${{ matrix.os }}
  steps:
    - uses: actions/checkout@v4
    - run: cargo test --manifest-path src-tauri/Cargo.toml
    - run: npm ci && npm test

Screenshot Comparison

Use headless browser testing (Playwright) in CI to screenshot the app on each platform and diff the results. Catches rendering regressions across WebKit/WebView2.

Anti-Patterns

1. Hardcoded Paths

Symptom: fs.readFile("/Users/...") or fs.readFile("C:\\Users\\...") Fix: Use dirs crate (Rust) or @tauri-apps/api/path (JS). Never assume separators.

2. Testing on One Platform Only

Symptom: "Works on my Mac" ships broken on Windows. Fix: CI matrix builds on both platforms. Period.

3. Ignoring Close-vs-Quit Semantics

Symptom: macOS users expect app to stay running when closing window. Windows users expect it to quit. Fix: Follow each platform's convention explicitly.

4. Platform-Specific Fonts Without Fallbacks

Symptom: "SF Pro" renders as Times New Roman on Windows. Fix: Full font stack: -apple-system, "Segoe UI", Roboto, sans-serif.

5. Pixel-Based Layouts That Break at Fractional Scaling

Symptom: UI looks fine on macOS Retina, misaligned at 125%/150% on Windows. Fix: Use logical CSS units, SVG icons, test at multiple DPI settings.

6. Assuming WebKit Behavior on Windows

Symptom: CSS or JS works on macOS (WebKit) but breaks on Windows (Chromium). Fix: Test both. Use feature detection. Check compat tables.

7. One Giant Installer for All Platforms

Symptom: Trying to create a universal artifact. Fix: Each platform gets its own format: DMG (macOS), NSIS/MSI (Windows).

8. Not Handling Windows Long Path Limits

Symptom: File operations fail on deeply nested directories. Fix: Check path length, or use \\?\ extended-length prefix on Windows.

Quality Checklist

[ ] App builds and runs on both macOS and Windows
[ ] CI/CD matrix builds both platforms on every push
[ ] Keyboard shortcuts use Cmd on macOS, Ctrl on Windows
[ ] Shortcut hints in UI reflect current platform dynamically
[ ] Close button follows platform convention (hide on macOS, quit on Windows)
[ ] Menu bar is global on macOS, in-window on Windows
[ ] System tray works on both platforms
[ ] File paths resolved via platform APIs (never hardcoded)
[ ] Font stack includes fallbacks for both platforms
[ ] Dark mode detected and applied on both platforms
[ ] Tested at 1x, 1.25x, 1.5x, and 2x display scaling
[ ] Installers generated: DMG for macOS, NSIS or MSI for Windows
[ ] Code signing configured for both platforms (see rust-app-distribution)
[ ] No platform-specific CSS without feature detection
[ ] Window state (size, position) persisted correctly per platform

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Expert in 2000s-era music visualization (Milkdrop, AVS, Geiss) and modern WebGL implementations. Specializes in Butterchurn integration, Web Audio API AnalyserNode FFT data, GLSL shaders for audio-reactive visuals, and psychedelic generative art. Activate on "Milkdrop", "music visualization", "WebGL visualizer", "Butterchurn", "audio reactive", "FFT visualization", "spectrum analyzer". NOT for simple bar charts/waveforms (use basic canvas), video editing, or non-audio visuals.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

Expert legal research agent for finding and scraping expungement data state by state. Knows authoritative sources, URL patterns, Firecrawl configuration, and 2026 legal landscape.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

Expert in 3D computer vision labeling tools, workflows, and AI-assisted annotation for LiDAR, point clouds, and sensor fusion. Covers SAM4D/Point-SAM, human-in-the-loop architectures, and vertical-specific training strategies. Activate on '3D labeling', 'point cloud annotation', 'LiDAR labeling', 'SAM 3D', 'SAM4D', 'sensor fusion annotation', '3D bounding box', 'semantic segmentation point cloud'. NOT for 2D image labeling (use clip-aware-embeddings), general ML training (use ml-engineer), video annotation without 3D (use computer-vision-pipeline), or VLM prompt engineering (use prompt-engineer).

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

Apply crisis decision-making research to agent routing, uncertainty triage, and coordination failure analysis in time-pressured systems. Use when diagnosing handoff failures, analytical paralysis, or expert judgment under incomplete information. NOT for routine coding, simple CRUD design, or static single-agent tasks with complete information.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

Use for insight, reframing, contradiction, impasse, and anomaly-driven problem solving when execution effort no longer helps. NOT for routine optimization, error correction, or well-specified tasks with known solution paths.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

Apply cognitive task analysis to expert work that depends on perceptual cues, branching judgment, and recurring monitoring loops. Use when decomposing expert capability into agent structure, simulation design, or validation interviews. NOT for ordinary step-by-step SOP capture or simple pipelines with no tacit cue layer.

日本語の概要は準備中です。原文の説明を表示しています。

curiositech/port-daddy22026年10月12日 更新

curiositech のスキルをすべて見る

このスキルの問題を報告する