mcpField
A
adding-tauri-splashscreen

adding-tauri-splashscreen

github.com/dchuk開発36152 回インストール40 週間前に更新
リポジトリ

adding-tauri-splashscreen について

Tauri v2 アプリの起動画面を実装するためのスキルです。ウィンドウ設定とフロントエンド・バックエンドの初期化を調整し、準備後にメインウィンドウを表示します。

主な機能

  1. 01起動画面とメインウィンドウの設定
  2. 02フロントエンドとバックエンドの起動調整
  3. 03起動画面を閉じてメイン画面を表示
  4. 04シンプル・進捗バー・ダーク画面のスタイル
  5. 05初期化エラーと表示タイミングへの対応

活用シーン

  1. 01Tauri アプリの初期化中にローディング画面を表示
  2. 02初期化完了までメインウィンドウを非表示
  3. 03起動画面の表示や位置の問題を調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dchuk/claude-code-tauri-skills --skill adding-tauri-splashscreen

インストール後、Claude Code で/adding-tauri-splashscreenを入力して読み込まれたか確認します。

詳細

Tauri スプラッシュ画面の実装

このスキルでは、Tauri v2 アプリケーションでスプラッシュ画面を実装する方法を説明します。スプラッシュ画面は、メインウィンドウの読み込みと初期化中に、アプリケーションの起動時に表示されます。

概要

スプラッシュ画面のパターンは、次の手順で構成されます。

  1. 起動直後にスプラッシュウィンドウを表示する
  2. 準備が整うまでメインウィンドウを非表示にする
  3. 初期化タスクを実行する(フロントエンドとバックエンド)
  4. 完了したらスプラッシュ画面を閉じ、メインウィンドウを表示する

設定

ウィンドウの設定

tauri.conf.json で両方のウィンドウを設定します。

{
  "app": {
    "windows": [
      {
        "label": "main",
        "title": "My Application",
        "width": 1200,
        "height": 800,
        "visible": false
      },
      {
        "label": "splashscreen",
        "title": "Loading",
        "url": "splashscreen.html",
        "width": 400,
        "height": 300,
        "center": true,
        "resizable": false,
        "decorations": false,
        "transparent": true,
        "alwaysOnTop": true
      }
    ]
  }
}

主な設定:

  • メインウィンドウの "visible": false — 準備が整うまで非表示にします
  • "url": "splashscreen.html" — スプラッシュ画面の HTML を指定します
  • "decorations": false — ウィンドウの枠をなくし、すっきりとした見た目にします
  • "transparent": true — 背景を透過します
  • "alwaysOnTop": true — 読み込み中にスプラッシュ画面を常に前面に表示します

スプラッシュ画面の HTML

フロントエンドのソースディレクトリ(例:src/ や public/)に splashscreen.html を作成します。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Loading</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    html, body {
      height: 100%;
      overflow: hidden;
      background: transparent;
    }

    .splash-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 100vh;
      background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
      border-radius: 12px;
      color: white;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    }

    .logo {
      width: 80px;
      height: 80px;
      margin-bottom: 24px;
    }

    .app-name {
      font-size: 24px;
      font-weight: 600;
      margin-bottom: 16px;
    }

    .loading-spinner {
      width: 40px;
      height: 40px;
      border: 3px solid rgba(255, 255, 255, 0.3);
      border-top-color: #4f46e5;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    .loading-text {
      margin-top: 16px;
      font-size: 14px;
      color: rgba(255, 255, 255, 0.7);
    }
  </style>
</head>
<body>
  <div class="splash-container">
    
    <svg class="logo" viewBox="0 0 100 100" fill="none">
      <circle cx="50" cy="50" r="45" stroke="#4f46e5" stroke-width="4"/>
      <path d="M30 50 L45 65 L70 35" stroke="#4f46e5" stroke-width="4" fill="none"/>
    </svg>
    <div class="app-name">My Application</div>
    <div class="loading-spinner"></div>
    <div class="loading-text">Loading...</div>
  </div>
</body>
</html>

フロントエンドの設定

TypeScript/JavaScript の実装

メインのエントリーファイル(例:src/main.ts)で、次のようにします。

import { invoke } from '@tauri-apps/api/core';

// Helper function for delays
function sleep(seconds: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}

// Frontend initialization
async function initializeFrontend(): Promise<void> {
  // Perform frontend setup tasks here:
  // - Load configuration
  // - Initialize state management
  // - Set up routing
  // - Preload critical assets

  // Example: simulate initialization time
  await sleep(1);

  // Notify backend that frontend is ready
  await invoke('set_complete', { task: 'frontend' });
}

// Start initialization when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
  initializeFrontend().catch(console.error);
});
代替方法:ウィンドウイベントを使用する
import { invoke } from '@tauri-apps/api/core';
import { getCurrentWindow } from '@tauri-apps/api/window';

async function initializeFrontend(): Promise<void> {
  // Your initialization logic
  const config = await loadConfig();
  await setupRouter();
  await preloadAssets();

  // Signal completion
  await invoke('set_complete', { task: 'frontend' });
}

// Wait for window to be fully ready
getCurrentWindow().once('tauri://created', () => {
  initializeFrontend();
});

バックエンドの設定

Tokio 依存関係の追加
cargo add tokio --features time
Rust の実装

src-tauri/src/lib.rs で、次のようにします。

use std::sync::Mutex;
use tauri::{AppHandle, Manager, State};

// Track initialization state
struct SetupState {
    frontend_task: bool,
    backend_task: bool,
}

impl Default for SetupState {
    fn default() -> Self {
        Self {
            frontend_task: false,
            backend_task: false,
        }
    }
}

// Command to mark tasks complete
#[tauri::command]
async fn set_complete(
    app: AppHandle,
    state: State<'_, Mutex<SetupState>>,
    task: String,
) -> Result<(), String> {
    let mut state = state.lock().map_err(|e| e.to_string())?;

    match task.as_str() {
        "frontend" => state.frontend_task = true,
        "backend" => state.backend_task = true,
        _ => return Err(format!("Unknown task: {}", task)),
    }

    // Check if all tasks are complete
    if state.frontend_task && state.backend_task {
        // Close splash and show main window
        if let Some(splash) = app.get_webview_window("splashscreen") {
            splash.close().map_err(|e| e.to_string())?;
        }

        if let Some(main) = app.get_webview_window("main") {
            main.show().map_err(|e| e.to_string())?;
            main.set_focus().map_err(|e| e.to_string())?;
        }
    }

    Ok(())
}

// Backend initialization
async fn setup_backend(app: AppHandle) {
    // IMPORTANT: Use tokio::time::sleep, NOT std::thread::sleep
    // std::thread::sleep blocks the entire async runtime

    // Perform backend initialization:
    // - Database connections
    // - Load configuration
    // - Initialize services

    // Example: simulate work
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;

    // Mark backend as complete
    if let Some(state) = app.try_state::<Mutex<SetupState>>() {
        let _ = set_complete(
            app.clone(),
            state,
            "backend".to_string(),
        ).await;
    }
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .manage(Mutex::new(SetupState::default()))
        .invoke_handler(tauri::generate_handler![set_complete])
        .setup(|app| {
            let handle = app.handle().clone();

            // Spawn backend initialization
            tauri::async_runtime::spawn(async move {
                setup_backend(handle).await;
            });

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

シンプルな実装

フロントエンドの準備を待つだけでよい、よりシンプルなケースの場合:

設定
{
  "app": {
    "windows": [
      {
        "label": "main",
        "visible": false
      },
      {
        "label": "splashscreen",
        "url": "splashscreen.html",
        "width": 400,
        "height": 300,
        "decorations": false
      }
    ]
  }
}
フロントエンド
import { invoke } from '@tauri-apps/api/core';

async function init() {
  // Initialize your app
  await setupApp();

  // Close splash, show main
  await invoke('close_splashscreen');
}

document.addEventListener('DOMContentLoaded', init);
バックエンド
use tauri::{AppHandle, Manager};

#[tauri::command]
async fn close_splashscreen(app: AppHandle) -> Result<(), String> {
    if let Some(splash) = app.get_webview_window("splashscreen") {
        splash.close().map_err(|e| e.to_string())?;
    }

    if let Some(main) = app.get_webview_window("main") {
        main.show().map_err(|e| e.to_string())?;
        main.set_focus().map_err(|e| e.to_string())?;
    }

    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![close_splashscreen])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

スタイルのバリエーション

ミニマルなスプラッシュ画面
<style>
  .splash-container {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background: #ffffff;
  }

  .logo {
    width: 120px;
    animation: pulse 2s ease-in-out infinite;
  }

  @keyframes pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.7; transform: scale(0.95); }
  }
</style>
プログレスバー付きスプラッシュ画面
<style>
  .progress-container {
    width: 200px;
    height: 4px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 2px;
    overflow: hidden;
    margin-top: 20px;
  }

  .progress-bar {
    height: 100%;
    background: #4f46e5;
    animation: progress 2s ease-in-out infinite;
  }

  @keyframes progress {
    0% { width: 0%; }
    50% { width: 70%; }
    100% { width: 100%; }
  }
</style>

<div class="progress-container">
  <div class="progress-bar"></div>
</div>
グロー効果付きダークテーマ
<style>
  .splash-container {
    background: #0a0a0a;
    color: #ffffff;
  }

  .logo {
    filter: drop-shadow(0 0 20px rgba(79, 70, 229, 0.5));
  }

  .app-name {
    text-shadow: 0 0 20px rgba(79, 70, 229, 0.5);
  }
</style>

重要な注意事項

  1. 非同期スリープ:非同期 Rust コードでは、必ず tokio::time::sleep を使用し、std::thread::sleep は使用しないでください。後者はランタイム全体をブロックします。

  2. ウィンドウラベル:コード内のウィンドウラベルが tauri.conf.json のものと一致していることを確認してください。

  3. エラー処理:スプラッシュ画面ではエラーを適切に処理してください。初期化に失敗した場合でも、エラー状態を表示したうえでメインウィンドウを表示してください。

  4. 表示時間:ブランドを表示するのに十分な時間スプラッシュ画面を表示しつつ、ユーザーを苛立たせるほど長くならないようにしてください。最低でも1〜3秒を目安にしてください。

  5. 透過ウィンドウ:transparent: true を使用する場合は、html 要素と body 要素に background: transparent を指定してください。

  6. モバイルでの考慮事項:モバイルプラットフォームでは、スプラッシュ画面の動作が異なります。iOS と Android では、プラットフォーム標準のスプラッシュ画面の使用を検討してください。

トラブルシューティング

スプラッシュ画面が表示されない:

  • tauri.conf.json の URL パスが正しいことを確認してください
  • HTML ファイルが正しい場所にあることを確認してください

メインウィンドウが早く表示されすぎる:

  • メインウィンドウに visible: false が設定されていることを確認してください
  • set_complete コマンドが正しく呼び出されていることを確認してください

背景が透過されない:

  • ウィンドウ設定で transparent: true を設定してください
  • CSS で html と body に background: transparent を設定してください
  • プラットフォームによっては、decorations: false が必要な場合があります

ウィンドウ位置の問題:

  • スプラッシュ画面を中央に表示するには、center: true を使用してください
  • または、x と y の座標を明示的に指定してください

コメント