← ソースコード説明書

apps/editor - エディタ SPA

概要

kaedevn のメインエディタ。React 19 + Vite 7 + Zustand 5 で構成される SPA。ブロックベースの GUI でページ・ブロック・キャラクター(2D 立ち絵 / VRM 3D / Live2D / Shape Ch)・アセットを管理し、Kaede Script のタグ記法(KS)を生成してプレビューエンジンに送る。KSC(コード記法)ブロックの埋め込みにも対応。

ディレクトリ構成

apps/editor/
├── src/
│   ├── pages/              # 8 ページコンポーネント
│   ├── components/         # 59 コンポーネント
│   │   ├── blocks/         # 14 ブロックカード + CardShell
│   │   ├── panels/         # 設定・キャラクター・アセットパネル
│   │   ├── sidebar/        # アウトライン・インスペクタ・プレビュー
│   │   ├── timeline/       # タイムラインエディタ
│   │   ├── ui/             # UI プリミティブ(ドロワー、FAB、コンテキストメニュー等)
│   │   └── KSEditor/       # KS スクリプトエディタ
│   ├── store/              # Zustand ストア (useEditorStore.ts)
│   ├── hooks/              # カスタムフック (6 ファイル)
│   ├── config/             # API, blockTheme, frontend URLs
│   ├── utils/              # 変換, ハイライト, マイグレーション
│   ├── types/              # 型定義 (Block, EditorProject 等)
│   ├── index.css           # Tailwind グローバルスタイル
│   └── main.tsx            # エントリポイント
├── test/                   # Vitest ユニットテスト
├── vite.config.ts          # ポート 5176
├── vitest.config.ts
├── playwright.config.ts
└── package.json

主要ファイル

ファイル行数役割
src/store/useEditorStore.ts~1,500Zustand ストア。プロジェクト、ページ、ブロック、キャラクター、アセット、undo/redo、自動保存
src/pages/EditorPage.tsx~800メインエディタページ。レイアウト、状態同期、自動保存(60秒)、beforeunload、ゲストモード
src/components/BlockList.tsx~400ブロック一覧。ドラッグ&ドロップ、コンテキストメニュー、FAB、警告表示
src/components/Header.tsx~260ヘッダー。保存、プレビュー、undo/redo、設定、タイムライン切替
src/utils/ksConverter.ts~400ブロック ↔ KSC AST 双方向変換
src/types/index.ts~330全 14 ブロック型定義、AssetRef、Character、Expression
src/config/api.ts~150API エンドポイント、authFetch、getAssetUrl

依存関係

内部パッケージ

  • @kaedevn/core (型参照のみ)

主要外部ライブラリ

  • react 19 / react-dom / react-router-dom — UI フレームワーク
  • zustand 5 — 状態管理
  • @dnd-kit/core / @dnd-kit/sortable — ドラッグ&ドロップ
  • @monaco-editor/react — コードエディタ
  • react-simple-code-editor / prismjs — 軽量コードエディタ
  • react-hot-toast — トースト通知
  • framer-motion — アニメーション
  • tailwindcss 3.4 — CSS

ページ構成

ページパス役割
EditorPage/projects/editor/:workIdメインエディタ
EditorPage (guest)/projects/editorゲストモード
UserProjectListPage/projectsプロジェクト一覧
LoginPage/loginログイン
UserSelectPage/user-selectユーザー選択
UserSettingsPage/settingsユーザー設定
WorksPage/works作品一覧(準備中)
FavoritesPage/favoritesお気に入り(準備中)
GuidePage/guideガイド(準備中)

Zustand ストア (useEditorStore)

State

{
  project: EditorProject | null     // プロジェクトデータ
  currentPageIndex: number          // 現在のページ
  activeTab: 'editor' | 'character' | 'asset' | 'settings' | 'script'
  timelines: TimelineRoot[]         // タイムラインデータ
  _history: { past: [], future: [] } // undo/redo 履歴 (50エントリ上限)
  _lastSavedAt: number              // 自動保存用タイムスタンプ
  kscTestScript: string | null      // KSC テスト用スクリプト
  kscError: { message, line?, column? } | null
}

主要アクション

カテゴリアクション
プロジェクトsetProject, updateProjectTitle
ページaddPage, removePage, renamePage, setCurrentPage
ブロックaddBlock, updateBlock, moveBlock, removeBlock, duplicateBlock, setBlocks, reorderBlocks
アセットaddAsset, removeAsset, updateAssetSlug
キャラクターsetCharacters, addCharacter, updateCharacter, removeCharacter
表情addExpression, updateExpression, removeExpression
プレビューbuildPreviewScript, buildPageScript, buildSnapshotScript
履歴undo, redo, canUndo, canRedo
保存_markSaved, _isDirty

ブロック型一覧

ブロックファイル役割
startStartBlockCard.tsxストーリー開始マーカー(編集不可)
bgBgBlockCard.tsx背景アセット選択 + トランスフォーム
chChBlockCard.tsxキャラクター・表情・位置
textTextBlockCard.tsxテキスト(話者名 + 本文)
overlayOverlayBlockCard.tsxオーバーレイ画像
choiceChoiceBlockCard.tsx選択肢(複数オプション + 条件)
ifIfBlockCard.tsx条件分岐(then/else ブロックリスト)
jumpJumpBlockCard.tsxページジャンプ
set_varSetVarBlockCard.tsx変数設定 (=, +=, -=)
effectEffectBlockCard.tsxエフェクト(種類・強度・時間)
screen_filterScreenFilterBlockCard.tsxスクリーンフィルター
timelineTimelineBlockCard.tsxタイムラインアニメーション
battleBattleBlockCard.tsxバトル(敵グループ・勝敗ジャンプ)
kscKscBlockCard.tsxKSC スクリプト直接記述

カスタムフック

フック役割
useMediaQueryCSS メディアクエリ監視
useBreakpoint'mobile' / 'tablet' / 'desktop' 判定
useKeyboardAdjustモバイルキーボード高さ追従
useLongPressロングプレス検出(コンテキストメニュー用)
useScrollDirectionスクロール方向検出(ヘッダー表示/非表示)
useReducedMotionprefers-reduced-motion 検出

自動保存 / 離脱警告

  • 自動保存: 60秒間隔で _isDirty() をチェック → PUT API で保存 → _markSaved()
  • 離脱警告: beforeunload イベントで _isDirty() をチェック → 未保存時にブラウザ確認ダイアログ
  • 手動保存: ヘッダーの保存ボタン → 成功時に _markSaved()

レスポンシブ対応

  • モバイル (640px以下): ハンバーガーメニュー、タブナビゲーション、ボトムシート、FAB
  • タブレット: 2カラムレイアウト
  • デスクトップ: 3カラムレイアウト(サイドバー + メインエリア + インスペクタ)
  • タッチターゲット最小 44px

テスト

ユニットテスト (Vitest)

  • test/store.test.ts — ストア CRUD テスト (~80 テスト)
  • test/types.test.ts — 型バリデーション (~30 テスト)
  • test/ksConverter.test.ts — ブロック ↔ KSC 変換 (~50 テスト)
  • test/api-config.test.ts — API エンドポイント検証

E2E テスト (Playwright)

  • test-mobile-ui.spec.ts — モバイル UI (640px)
  • test-mobile-ux-phase3.spec.ts — モバイル 3 カラム
  • test-three-column.spec.ts — デスクトップレイアウト

合計: 189 ユニットテスト + 3 E2E テストファイル

Ad: stickyBottom (728x90)
kaedevn - ノベルゲームを作れるプラットフォーム