From 57c4cf0cd52118e000963fcab5e7a00f26bc358b Mon Sep 17 00:00:00 2001 From: ienaga Date: Sun, 22 Feb 2026 01:35:20 +0900 Subject: [PATCH 1/3] =?UTF-8?q?codex=E3=81=AE=E3=83=89=E3=82=AD=E3=83=A5?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0522673..b37bdfe 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Create `.vscode/mcp.json` at the project root: "servers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -97,7 +97,7 @@ Edit the configuration file: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -116,7 +116,7 @@ Create `.mcp.json` at the project root: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -126,7 +126,7 @@ Create `.mcp.json` at the project root: Or add directly via CLI: ```bash -claude mcp add next2d -- npx next2d-development-mcp +claude mcp add next2d -- npx -y next2d-development-mcp ``` ### OpenAI Codex (ChatGPT CLI) @@ -139,12 +139,16 @@ Create `.codex/mcp.json` at the project root: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } ``` +> `npm` キャッシュ権限エラー (`EPERM`, `~/.npm/_npx`) が出る場合はキャッシュ先を明示してください。 +> If npm cache permission errors occur, set a writable cache path: +> `"args": ["-y", "--cache", "/tmp/next2d-mcp-npm-cache", "next2d-development-mcp"]` + ### Gemini CLI プロジェクトルートに `.gemini/settings.json` を作成します。 @@ -155,7 +159,7 @@ Create `.gemini/settings.json` at the project root: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -176,7 +180,7 @@ Add the MCP server from Cline settings: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -195,7 +199,7 @@ Add to Cursor settings: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -213,7 +217,7 @@ Add to Windsurf MCP configuration: "mcpServers": { "next2d": { "command": "npx", - "args": ["next2d-development-mcp"] + "args": ["-y", "next2d-development-mcp"] } } } @@ -227,7 +231,7 @@ MCP uses the standard **stdio** transport protocol. Configure the following comm ``` command: npx -args: next2d-development-mcp +args: -y next2d-development-mcp ``` --- From 50fabdbea3e018ef367768b4a54a93c85fbbe739 Mon Sep 17 00:00:00 2001 From: ienaga Date: Mon, 23 Feb 2026 13:04:16 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=83=AC?= =?UTF-8?q?=E3=83=B3=E3=82=B9=E7=AE=A1=E7=90=86=E3=82=92git=20submodule?= =?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/skills/SKILL.md | 134 - .github/skills/references/develop-specs.md | 1576 --------- .github/skills/references/framework-specs.md | 1687 --------- .github/skills/references/player-specs.md | 3292 ------------------ .github/workflows/publish.yml | 5 +- .gitignore | 1 + .gitmodules | 3 + next2d-development-assistant | 1 + package.json | 4 +- src/resources/index.ts | 44 +- 10 files changed, 53 insertions(+), 6694 deletions(-) delete mode 100644 .github/skills/SKILL.md delete mode 100644 .github/skills/references/develop-specs.md delete mode 100644 .github/skills/references/framework-specs.md delete mode 100644 .github/skills/references/player-specs.md create mode 100644 .gitmodules create mode 160000 next2d-development-assistant diff --git a/.github/skills/SKILL.md b/.github/skills/SKILL.md deleted file mode 100644 index 43bf1d2..0000000 --- a/.github/skills/SKILL.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -name: next2d-development-assistant -description: > - Next2D Player および Next2D Framework を用いたアプリケーション開発を支援するスキル。 - TypeScript ベースの MVVM + Clean Architecture + Atomic Design パターンに従ったコード生成、 - WebGL/WebGPU 2D レンダリングエンジン API の活用、デバッグ支援、パフォーマンス最適化を提供する。 - - Use when: - (1) Next2D Player の DisplayObject API (MovieClip, Sprite, Shape, TextField, Video, Sound, Tween, Filters) を使ったコードを書く - (2) Next2D Framework の MVVM パターン (View/ViewModel, UseCase, Repository) に従った画面実装 - (3) routing.json, config.json, stage.json の設定 - (4) Atomic Design (Atom/Molecule/Organism/Page) による UI コンポーネント設計 - (5) Animation Tool (.n2d) アセットとの連携 - (6) マルチプラットフォームビルド (Web/Steam/iOS/Android) - (7) Next2D プロジェクトの新規作成やセットアップ - - Trigger keywords: Next2D, next2d, @next2d/player, @next2d/framework, @next2d/display, - @next2d/events, @next2d/text, @next2d/media, @next2d/ui, MovieClipContent, - gotoView, routing.json, stage.json, create-next2d-app ---- - -# Next2D Development Assistant - -## Overview - -Next2D は WebGL/WebGPU ベースの 2D レンダリングエンジン (Player) と MVVM フレームワーク (Framework) で構成される。 -Flash Player ライクな DisplayList アーキテクチャを Web/デスクトップ/モバイルで実現する。 - -## Architecture - -``` -View Layer (view/, ui/) - └─ depends on ─→ Interface Layer (interface/) - ↑ -Application Layer (model/application/) - ├─ depends on ─→ Interface Layer - ├─ depends on ─→ Domain Layer (model/domain/) - └─ calls ──────→ Infrastructure Layer (model/infrastructure/) -``` - -**Design Patterns:** MVVM + Clean Architecture + Atomic Design -**Language:** TypeScript (any 禁止, Interface は I プレフィックス) -**Build Tool:** Vite / **Testing:** Vitest / **Package Manager:** npm - -## Quick Start - -```bash -npx create-next2d-app my-app -cd my-app -npm install -npm start # http://localhost:5173 -npm run generate # routing.json から View/ViewModel を自動生成 -``` - -## Core Workflow - -### 1. 新しい画面を追加する - -1. `src/config/routing.json` にルートを追加 -2. `npm run generate` で View/ViewModel の雛形を自動生成 -3. ViewModel に UseCase を追加 -4. View に UI コンポーネント (Atomic Design) を配置 -5. イベントは必ず ViewModel に委譲 - -### 2. API データを取得する画面 - -1. `interface/` にレスポンス型を定義 (`I` プレフィックス) -2. `model/infrastructure/repository/` に Repository を作成 (try-catch 必須, config からエンドポイント取得) -3. `model/application/{screen}/usecase/` に UseCase を作成 (`execute` メソッド統一) -4. `routing.json` の `requests` で自動取得、または ViewModel から UseCase 経由で取得 - -### 3. Animation Tool アセットを使う - -1. Animation Tool でシンボルを作成 → `.n2d` ファイルを `file/` に配置 -2. `ui/content/` に MovieClipContent 継承クラスを作成 (`namespace` でシンボル名を指定) -3. `routing.json` で `type: "content"` として読み込み - -## View/ViewModel Lifecycle - -``` -ViewModel 生成 → ViewModel.initialize() → View 生成 (VM注入) → View.initialize() → View.onEnter() → (操作) → View.onExit() -``` - -**重要:** ViewModel の `initialize()` は View の `initialize()` より前に呼ばれる。View 初期化時にはデータ準備済み。 - -## Key Rules - -- **View:** 表示構造のみ。ビジネスロジック禁止。イベントは ViewModel に委譲 -- **ViewModel:** UseCase を保持。インターフェースに依存 (具象クラス禁止) -- **UseCase:** 1 アクション = 1 UseCase。エントリーポイントは `execute`。単一責任 -- **Repository:** try-catch 必須。エンドポイントは `config` から取得。`any` 禁止 -- **UI Component:** 単一責任。データは ViewModel から引数で受け取る -- **Interface:** `I` プレフィックス。必要最小限のプロパティのみ - -## Build Commands - -| Command | Platform | Output | -|---------|----------|--------| -| `npm run build:web -- --env prd` | Web | `dist/web/prd/` | -| `npm run build:steam:windows -- --env prd` | Windows | `dist/steam/windows/` | -| `npm run build:steam:macos -- --env prd` | macOS | `dist/steam/macos/` | -| `npm run build:ios -- --env prd` | iOS | Xcode project | -| `npm run build:android -- --env prd` | Android | Android Studio project | - -Environment options: `--env local|dev|stg|prd` - -## References - -Detailed specifications are available in the `references/` directory. Read the relevant file based on the user's needs: - -- **[player-specs.md](references/player-specs.md)** - Next2D Player API reference (DisplayObject, MovieClip, Sprite, Shape, TextField, Video, Sound, Tween, Events, Filters). Read when implementing rendering, animation, graphics, or interaction logic. -- **[framework-specs.md](references/framework-specs.md)** - Next2D Framework reference (MVVM architecture, routing, config, View/ViewModel lifecycle, Animation Tool integration). Read when working on application architecture, screen transitions, or configuration. -- **[develop-specs.md](references/develop-specs.md)** - Development template specs (project structure, CLI commands, interfaces, Model layer, UI layer with Atomic Design, View/ViewModel patterns). Read when creating new components, setting up projects, or following coding patterns. - -### When to read which reference - -| Task | Reference | -|------|-----------| -| DisplayObject のプロパティ/メソッドを確認 | player-specs.md | -| MovieClip/Sprite/Shape/TextField の使い方 | player-specs.md | -| フィルター (Blur, DropShadow, Glow 等) の適用 | player-specs.md | -| Tween アニメーションの実装 | player-specs.md | -| Sound/Video の再生 | player-specs.md | -| イベントシステム (addEventListener 等) | player-specs.md | -| routing.json / config.json の設定 | framework-specs.md | -| View/ViewModel のライフサイクル | framework-specs.md | -| 画面遷移 (gotoView) の実装 | framework-specs.md | -| Animation Tool 連携 | framework-specs.md | -| プロジェクト構造・ディレクトリ設計 | develop-specs.md | -| UseCase / Repository の作成 | develop-specs.md | -| Atomic Design コンポーネントの作成 | develop-specs.md | -| ボタン連続押下防止パターン | develop-specs.md | -| Interface の定義パターン | develop-specs.md | -| テストの書き方 (Vitest) | develop-specs.md | diff --git a/.github/skills/references/develop-specs.md b/.github/skills/references/develop-specs.md deleted file mode 100644 index 24b4888..0000000 --- a/.github/skills/references/develop-specs.md +++ /dev/null @@ -1,1576 +0,0 @@ -# Next2D Framework TypeScript Template - Development Specs - -## Table of Contents - -1. [Overview](#next2d-framework-typescript-template---overview) -2. [CLI Commands Reference](#cli-commands-reference) -3. [Configuration Files](#configuration-files) -4. [Interface Definitions](#interface-definitions) -5. [Model Layer (Application / Domain / Infrastructure)](#model-layer-application--domain--infrastructure) -6. [UI Layer (Components / Animation / Content)](#ui-layer-components--animation--content) -7. [View / ViewModel (MVVM Pattern)](#view--viewmodel-mvvm-pattern) - ---- - -# Next2D Framework TypeScript Template - Overview - -## Project Summary - -Next2D Frameworkを使用したTypeScriptプロジェクトテンプレート。MVVM + Clean Architecture + Atomic Designを採用。 - -- **レンダリングエンジン**: Next2D Player -- **フレームワーク**: Next2D Framework -- **言語**: TypeScript -- **ビルドツール**: Vite -- **テスト**: Vitest -- **パッケージマネージャ**: npm - -## Requirements - -- Node.js 22.x以上 -- npm 10.x以上 -- iOS: Xcode 14以上 (iOS/Androidビルド時のみ) -- Android: Android Studio, JDK 21以上 (iOS/Androidビルド時のみ) - -## Architecture - -**MVVM + Clean Architecture + Atomic Design** の5層構成: - -``` -View Layer (view/, ui/) - └─ depends on ─→ Interface Layer (interface/) - ↑ -Application Layer (model/application/) - ├─ depends on ─→ Interface Layer - ├─ depends on ─→ Domain Layer (model/domain/) - └─ calls ──────→ Infrastructure Layer (model/infrastructure/) -``` - -### Layer Dependencies (依存関係の方向) - -- **View層** → Interface経由でApplication層を使用 -- **Application層** → Interface経由でDomain層・Infrastructure層を使用 -- **Domain層** → 何にも依存しない(最も安定、純粋なビジネスロジック) -- **Infrastructure層** → Interface層を実装 - -### Key Design Patterns - -1. **MVVM**: View(表示) / ViewModel(橋渡し) / Model(ビジネスロジック+データアクセス) -2. **UseCase Pattern**: ユーザーアクションごとに専用のUseCaseクラスを作成 -3. **Dependency Inversion**: 具象クラスではなくインターフェースに依存 -4. **Repository Pattern**: データアクセスを抽象化 -5. **Atomic Design**: Atom → Molecule → Organism → Template → Page - -## Directory Structure - -``` -src/ -├── config/ # 設定ファイル (stage.json, config.json, routing.json) -├── interface/ # TypeScriptインターフェース定義 -├── model/ -│ ├── application/ # UseCase (ビジネスロジック実装) -│ │ └── {screen}/usecase/ -│ ├── domain/ # コアビジネスロジック -│ │ └── {feature}/service/ -│ └── infrastructure/ # Repository (データアクセス) -│ └── repository/ -├── ui/ -│ ├── animation/ # アニメーション定義 -│ │ └── {screen}/ -│ ├── component/ -│ │ ├── atom/ # 最小コンポーネント (Button, Text等) -│ │ ├── molecule/ # 複合コンポーネント -│ │ ├── organism/ # 複数Moleculeの組み合わせ (拡張用) -│ │ ├── page/ # ページコンポーネント -│ │ │ └── {screen}/ -│ │ └── template/ # ページテンプレート (拡張用) -│ └── content/ # Animation Tool生成コンテンツ -├── view/ # View & ViewModel -│ └── {screen}/ -│ ├── {Screen}View.ts -│ └── {Screen}ViewModel.ts -└── assets/ # 静的ファイル (画像, JSON) - -@types/ # グローバル型定義 (.d.ts) -electron/ # Electron設定 (デスクトップビルド用) -file/ # Animation Tool n2dファイル -mock/ # 開発用モックデータ (API, Content, 画像) -``` - -## Best Practices (全体共通) - -1. **インターフェース優先**: 常に具象クラスではなくインターフェースに依存 -2. **単一責任の原則**: 各クラスは1つの責務のみを持つ -3. **型安全性**: `any`型を避け、明示的な型定義を使用 -4. **テスタブル**: 各層を独立してテスト可能にする -5. **JSDoc**: 処理内容を日英両方で明記 -6. **executeメソッド**: UseCaseのエントリーポイントを統一 -7. **エラーハンドリング**: Infrastructure層で適切に処理 - ---- - -# CLI Commands Reference - -## Setup - -```bash -npm install # 依存パッケージのインストール -``` - -## Development - -```bash -npm start # 開発サーバー起動 (http://localhost:5173) -npm run generate # routing.jsonからView/ViewModelクラスを自動生成 -``` - -## Testing - -```bash -npm test # 全テスト実行 (Vitest) -npm test -- --watch # ウォッチモード -npm test -- --coverage # カバレッジレポート -``` - -## Build - -| Command | Platform | Output | -|---------|----------|--------| -| `npm run build:web -- --env prd` | Web (HTML) | `dist/web/prd/` | -| `npm run build:steam:windows -- --env prd` | Windows (Steam) | `dist/steam/windows/` | -| `npm run build:steam:macos -- --env prd` | macOS (Steam) | `dist/steam/macos/` | -| `npm run build:steam:linux -- --env prd` | Linux (Steam) | `dist/steam/linux/` | -| `npm run build:ios -- --env prd` | iOS | Xcode project | -| `npm run build:android -- --env prd` | Android | Android Studio project | - -## Platform Emulators - -```bash -npm run preview:windows -- --env prd # Windows -npm run preview:macos -- --env prd # macOS -npm run preview:linux -- --env prd # Linux -npm run preview:ios -- --env prd # iOS -npm run preview:android -- --env prd # Android -``` - -`--env` オプション: `local`, `dev`, `stg`, `prd` - -## Environment Configuration - -環境ごとの設定は`src/config/config.json`で管理。`--env`で指定した環境名の設定値と`all`の設定値がマージされる。 - ---- - -# Configuration Files - -設定ファイルは `src/config/` ディレクトリに配置。 - -## stage.json - -表示領域(Stage)の設定。 - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `width` | number | 240 | 表示領域の幅 | -| `height` | number | 240 | 表示領域の高さ | -| `fps` | number | 60 | 描画回数/秒 (1-60) | -| `options` | object | null | オプション設定 | - -### Stage Options - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `options.fullScreen` | boolean | false | 画面全体に描画 | -| `options.tagId` | string | null | 描画先のエレメントID | -| `options.bgColor` | string | "transparent" | 背景色 (16進数) | - -### Example - -```json -{ - "width": 240, - "height": 240, - "fps": 60, - "options": { - "fullScreen": true - } -} -``` - ---- - -## config.json - -環境別の設定ファイル。`local`, `dev`, `stg`, `prd`, `all` に分離。 - -### Structure - -```json -{ - "local": { "api": { "endPoint": "/" }, "content": { "endPoint": "/" } }, - "dev": { "api": { "endPoint": "/" }, "content": { "endPoint": "/" } }, - "stg": { "api": { "endPoint": "/" }, "content": { "endPoint": "/" } }, - "prd": { "api": { "endPoint": "https://..." }, "content": { "endPoint": "https://..." } }, - "all": { /* 全環境共通 */ } -} -``` - -### `all` Properties (全環境共通) - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `defaultTop` | string | "top" | ページトップのView名 | -| `spa` | boolean | true | SPA (URLでシーン制御) | -| `loading.callback` | string | "Loading" | ローディング画面のコールバッククラス。start/end関数が呼ばれる | -| `gotoView.callback` | string/array | ["callback.Background"] | 画面遷移完了後のコールバッククラス。execute関数がasync/awaitで呼ばれる | - -### `platform` Property - -ビルド時の`--platform`値がセットされる。値: `macos`, `windows`, `linux`, `ios`, `android`, `web` - -### Config Access in Code - -```typescript -import { config } from "@/config/Config"; - -const endpoint = config.api.endPoint; -const stageWidth = config.stage.width; -``` - ---- - -## routing.json - -ルーティング設定。トッププロパティは英数字・スラッシュ。スラッシュをキーにCamelCaseでViewクラスにアクセス。 - -### Routing Example - -```json -{ - "quest/list": { - "requests": [] - } -} -``` - -→ `https://example.com/quest/list` でアクセス可能。`QuestListView`クラスがセットされる。 - -### Cluster Pattern (共通リクエストの再利用) - -`@`プレフィックスで共通リクエスト群を定義し、他のルートから参照: - -```json -{ - "@sample": { - "requests": [ - { - "type": "content", - "path": "{{ content.endPoint }}content/sample.json", - "name": "MainContent", - "cache": true - } - ] - }, - "top": { - "requests": [ - { "type": "cluster", "path": "@sample" }, - { "type": "json", "path": "{{ api.endPoint }}api/top.json", "name": "TopText" } - ] - } -} -``` - -### Second Level Properties - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `private` | boolean | false | true時、URLアクセスするとTopViewが読み込まれる | -| `requests` | array | null | Viewバインド前に実行するリクエスト群 | - -### Request Properties - -| Property | Type | Default | Description | -|----------|------|---------|-------------| -| `type` | string | "content" | `json`, `content`, `custom`, `cluster` | -| `path` | string | "" | `{{***}}`でconfig変数を参照可能。`@`プレフィックスでcluster参照 | -| `name` | string | "" | responseのキー名。`app.getResponse().get("key")` | -| `cache` | boolean | false | キャッシュ有効。`app.getCache().get("key")` | -| `callback` | string/array | null | リクエスト完了後のコールバッククラス。execute関数が呼ばれる | -| `class` | string | "" | custom type時のリクエスト実行クラス | -| `access` | string | "public" | custom type時の関数アクセス (`public`/`static`) | -| `method` | string | "" | custom type時の関数名 | - -### Request Types - -- **`json`**: URLからJSONを取得 -- **`content`**: Animation Toolコンテンツを取得 -- **`custom`**: 指定クラスのメソッドを実行 -- **`cluster`**: `@`プレフィックスの共通リクエスト群を参照 - -### Data Access - -```typescript -// responseデータ (画面遷移で初期化される) -const data = app.getResponse().get("HomeText"); - -// cacheデータ (画面遷移しても保持される) -const cached = app.getCache().get("MainContent"); -``` - ---- - -## Static Files - -### mock/ Directory - -ローカル開発用モックデータ。`http://localhost:5173/***`でアクセス可能。`routing.json`のパスと重複しないよう注意。 - -``` -mock/ -├── api/ # APIモック (JSON) -├── content/ # Animation Toolコンテンツモック -└── img/ # 画像モック -``` - -### file/ Directory - -Animation Toolで作成した`.n2d`ファイルを格納。バージョン管理可能。 - -### assets/ Directory - -ビルド時にバンドルに含める静的アセット。 - -```typescript -// 画像インポート -import logoImage from "@/assets/logo.png?inline"; - -// JSONインポート -import animation from "@/assets/animation.json"; -``` - -| 項目 | assets | mock | -|------|--------|------| -| 用途 | バンドルに含める | 開発サーバーで配信 | -| アクセス | importで取得 | URL経由でfetch | -| ビルド | バンドルに含まれる | 含まれない | - ---- - -## @types/ Directory - -グローバルな型定義ファイル (.d.ts)。`Window`インターフェースの拡張等。アプリケーション固有のインターフェースは`src/interface/`に配置。 - ---- - -# Interface Definitions - -TypeScriptインターフェース定義。Clean Architecture原則に従い、各層の依存関係を抽象化。 - -## Rules - -- 命名規則: `I` プレフィックスを使用 (例: `IDraggable`, `ITextField`) -- 必要最小限のプロパティのみ定義 -- `any`型を禁止、常に明示的な型を使用 -- JSDocコメントを追加 - -## Interface Categories - -### 1. UI関連 (コンポーネントの振る舞い) - -```typescript -// IDraggable.ts - ドラッグ可能なオブジェクト -export interface IDraggable { - startDrag(): void; - stopDrag(): void; -} -// 使用: HomeBtnMolecule, HomeContent - -// ITextField.ts - テキストフィールドの基本プロパティ -export interface ITextField { - width: number; - x: number; -} -// 使用: TextAtom, CenterTextFieldUseCase - -// ITextFieldProps.ts - テキストフィールドの詳細プロパティ設定 -// 使用: TextAtomのコンストラクタ - -// ITextFieldType.ts - テキストフィールドタイプ -// ITextFieldAutoSize.ts - テキストフィールドオートサイズ -// ITextFormatAlign.ts - テキストフォーマットアライン -// ITextFormatObject.ts - テキストフォーマットスタイル設定 -``` - -### 2. データ転送オブジェクト (DTO) - -```typescript -// IHomeTextResponse.ts - APIレスポンス型 -export interface IHomeTextResponse { - word: string; -} -// 使用: HomeTextRepository.get()の戻り値型 -``` - -### 3. 画面遷移関連 - -```typescript -// IViewName.ts - 利用可能な画面名 (Union型) -export type ViewName = "top" | "home"; -// 使用: NavigateToViewUseCase -// 新画面追加時はこの型にも追加が必要 -``` - -### 4. 設定関連 - -- `IConfig.ts` - アプリケーション全体設定 -- `IStage.ts` - ステージ設定 (`stage.json`の型) -- `IRouting.ts` - ルーティング設定 -- `IGotoView.ts` - 画面遷移オプション -- `IRequest.ts` / `IRequestType.ts` - HTTPリクエスト設定 -- `IOptions.ts` - オプション設定 - -## Interface Template - -```typescript -/** - * @description [インターフェースの説明] - * [Interface description] - * - * @interface - */ -export interface IYourInterface -{ - /** - * @description [プロパティの説明] - * [Property description] - * - * @type {type} - */ - propertyName: type; - - /** - * @description [メソッドの説明] - * [Method description] - * - * @param {ParamType} paramName - * @return {ReturnType} - * @method - */ - methodName(paramName: ParamType): ReturnType; -} -``` - -## Best Practices - -```typescript -// OK: 必要最小限 -export interface ITextField { - width: number; - x: number; -} - -// NG: 不要なプロパティ -export interface ITextField { - width: number; - height: number; // 使用しない - x: number; - y: number; // 使用しない -} - -// OK: 型の再利用 -export interface IPosition { x: number; y: number; } -export interface ITextField extends IPosition { width: number; } - -// OK: 明示的型 -export interface IHomeTextResponse { word: string; } - -// NG: any型 -export interface IHomeTextResponse { word: any; } -``` - -## Adding New Interface Steps - -1. 目的を明確にする(どの層の依存を抽象化するか) -2. `I`プレフィックスの命名規則に従う -3. 必要最小限のプロパティ/メソッドのみ定義 -4. JSDocコメントを追加 -5. 使用箇所を明記 - ---- - -# Model Layer (Application / Domain / Infrastructure) - -Model層はビジネスロジックとデータアクセスを担当。Clean Architectureに基づき3層で構成。 - -## Directory Structure - -``` -model/ -├── application/ # UseCase (ビジネスロジック) -│ └── {screen}/ -│ └── usecase/ -│ └── {Action}UseCase.ts -├── domain/ # コアビジネスロジック -│ └── {feature}/ -│ ├── {Feature}.ts -│ └── service/ -│ └── {Feature}{Action}Service.ts -└── infrastructure/ # Repository (データアクセス) - └── repository/ - └── {Resource}Repository.ts -``` - -## Layer Dependencies - -``` -Application → Domain (uses) -Application → Infrastructure (calls) -Domain → 依存なし (最も安定) -``` - ---- - -## Application Layer (UseCase) - -### Rules - -- 1つのユーザーアクションに対して1つのUseCaseクラスを作成 -- エントリーポイントは `execute` メソッドに統一 -- インターフェースに依存し、具象クラスに依存しない -- 画面ごとにディレクトリを作成: `application/{screen}/usecase/` - -### UseCase Template - -```typescript -import type { IYourInterface } from "@/interface/IYourInterface"; - -/** - * @description [UseCaseの説明] - * [UseCase description] - * - * @class - */ -export class YourUseCase -{ - /** - * @description [処理の説明] - * [Process description] - * - * @param {IYourInterface} param - * @return {void} - * @method - * @public - */ - execute (param: IYourInterface): void - { - // ビジネスロジックを実装 - } -} -``` - -### UseCase with Repository - -```typescript -import { YourRepository } from "@/model/infrastructure/repository/YourRepository"; -import type { IYourResponse } from "@/interface/IYourResponse"; - -export class FetchDataUseCase -{ - async execute (): Promise - { - try { - const data = await YourRepository.get(); - // ビジネスロジック: データの加工・検証 - return data; - } catch (error) { - console.error('Failed to fetch data:', error); - throw error; - } - } -} -``` - -### UseCase Composition (複数UseCaseの組み合わせ) - -```typescript -export class InitializeScreenUseCase -{ - private readonly fetchUseCase: FetchDataUseCase; - private readonly centerUseCase: CenterTextFieldUseCase; - - constructor () - { - this.fetchUseCase = new FetchDataUseCase(); - this.centerUseCase = new CenterTextFieldUseCase(); - } - - async execute (textField: ITextField): Promise - { - const data = await this.fetchUseCase.execute(); - this.centerUseCase.execute(textField, stageWidth); - } -} -``` - -### UseCase Anti-Patterns - -```typescript -// NG: 複数の責務 -export class DragUseCase { - start(target: IDraggable): void { ... } - stop(target: IDraggable): void { ... } - validate(target: IDraggable): boolean { ... } -} - -// OK: 単一の責務 -export class StartDragUseCase { - execute(target: IDraggable): void { target.startDrag(); } -} -export class StopDragUseCase { - execute(target: IDraggable): void { target.stopDrag(); } -} - -// NG: 具象クラスに依存 -execute(target: HomeBtnMolecule): void { ... } - -// OK: インターフェースに依存 -execute(target: IDraggable): void { ... } -``` - -### UseCase Test Template - -```typescript -import { StartDragUseCase } from "./StartDragUseCase"; -import type { IDraggable } from "@/interface/IDraggable"; - -describe('StartDragUseCase', () => { - test('should call startDrag on target', () => { - const mockDraggable: IDraggable = { - startDrag: vi.fn(), - stopDrag: vi.fn() - }; - - const useCase = new StartDragUseCase(); - useCase.execute(mockDraggable); - - expect(mockDraggable.startDrag).toHaveBeenCalled(); - }); -}); -``` - ---- - -## Domain Layer - -### Rules - -- アプリケーションのコアビジネスルールを実装 -- 可能な限りフレームワーク非依存(※Next2D描画機能の使用は許容) -- 純粋関数を心がけ、副作用を最小化 -- 可能な限り不変オブジェクトを使用 - -### Domain Service (Functional Style) - -```typescript -/** - * @description [サービスの説明] - * [Service description] - * - * @param {ParamType} param - * @return {ReturnType} - */ -export const execute = (param: ParamType): ReturnType => -{ - // ビジネスルールの実装 - return result; -}; -``` - -### Domain Class (Class-based Style) - -```typescript -import { Shape, stage } from "@next2d/display"; -import { Event } from "@next2d/events"; - -/** - * @description [ドメインクラスの説明] - * [Domain class description] - * - * @class - */ -export class YourDomainClass -{ - public readonly shape: Shape; - - constructor () - { - this.shape = new Shape(); - } - - execute (): void - { - // コアビジネスロジック - } -} -``` - -### Domain Callback Pattern - -`config.json`の`gotoView.callback`で設定されたクラスは、画面遷移完了後に`execute()`が呼び出される。 - -```typescript -// config.json: "gotoView": { "callback": ["domain.callback.Background"] } -// → model/domain/callback/Background.ts の execute() が呼ばれる - -export class Background -{ - execute (): void - { - const context = app.getContext(); - const view = context.view; - if (!view) return; - view.addChildAt(this.shape, 0); - } -} -``` - -### Domain Directory Extensions (将来の拡張) - -``` -domain/ -├── callback/ # コールバック処理 -├── service/ # ドメインサービス -├── entity/ # エンティティ (ID持ち) -└── value-object/ # 値オブジェクト -``` - ---- - -## Infrastructure Layer (Repository) - -### Rules - -- 外部システムとの連携(API、DB等)を担当 -- `any`型を避け、明示的な型定義を使用 -- すべての外部アクセスでtry-catchを実装 -- エンドポイントは`config`から取得(ハードコーディング禁止) -- シンプルな場合は静的メソッド、状態を持つ場合はインスタンスメソッド - -### Repository Template - -```typescript -import type { IYourResponse } from "@/interface/IYourResponse"; -import { config } from "@/config/Config"; - -/** - * @description [Repositoryの説明] - * [Repository description] - * - * @class - */ -export class YourRepository -{ - /** - * @description [処理の説明] - * [Process description] - * - * @param {string} id - * @return {Promise} - * @static - * @throws {Error} [エラーの説明] - */ - static async get (id: string): Promise - { - try { - const response = await fetch( - `${config.api.endPoint}api/your-endpoint/${id}` - ); - - if (!response.ok) { - throw new Error( - `HTTP error! status: ${response.status}` - ); - } - - return await response.json() as IYourResponse; - - } catch (error) { - console.error('Failed to fetch data:', error); - throw error; - } - } -} -``` - -### Repository with Cache - -```typescript -export class CachedRepository -{ - private static cache: Map = new Map(); - private static readonly CACHE_TTL = 60000; - - static async get (id: string): Promise - { - const cached = this.cache.get(id); - const now = Date.now(); - - if (cached && (now - cached.timestamp) < this.CACHE_TTL) { - return cached.data; - } - - const response = await fetch(`${config.api.endPoint}api/${id}`); - const data = await response.json(); - this.cache.set(id, { data, timestamp: now }); - - return data; - } -} -``` - -### Repository Anti-Patterns - -```typescript -// NG: any型 -static async get(): Promise { ... } - -// OK: 明示的型定義 -static async get(): Promise { ... } - -// NG: エラーハンドリングなし -static async get(): Promise { - const response = await fetch(...); - return await response.json(); -} - -// NG: ハードコーディング -const response = await fetch('https://example.com/api/data.json'); - -// OK: configから取得 -const response = await fetch(`${config.api.endPoint}api/data.json`); -``` - -### routing.json Custom Request Pattern - -`routing.json`でRepositoryを直接呼び出すことも可能: - -```json -{ - "home": { - "requests": [ - { - "type": "custom", - "class": "infrastructure.repository.HomeTextRepository", - "access": "static", - "method": "get", - "name": "HomeText", - "cache": true - } - ] - } -} -``` - -取得したデータは `app.getResponse().get("HomeText")` でアクセス可能。 - ---- - -# UI Layer (Components / Animation / Content) - -## Directory Structure - -``` -ui/ -├── animation/ # アニメーション定義 -│ └── {screen}/ -│ └── {Component}{Action}Animation.ts -├── component/ -│ ├── atom/ # 最小単位 (Button, Text等) -│ ├── molecule/ # Atomの組み合わせ -│ ├── organism/ # 複数Moleculeの組み合わせ (拡張用) -│ ├── page/ # ページコンポーネント -│ │ └── {screen}/ -│ └── template/ # ページテンプレート (拡張用) -└── content/ # Animation Tool生成コンテンツ -``` - -## Rules (共通) - -- 各コンポーネントは単一の責務のみ -- ビジネスロジックやデータアクセスに直接依存しない -- データはViewModelから引数で受け取る -- インターフェースを実装して抽象化する - ---- - -## DisplayObject 配置の基本方針(中心基準点パターン) - -Next2D の座標系は画面左上 (0, 0) が基準点。Shape や Sprite をそのまま配置すると、スケールや回転アニメーション時に座標がずれる。 -**基本方針として、子要素を親 Sprite に中心配置する。** - -### パターン: Shape を Sprite に中心配置 - -```typescript -const sprite = new Sprite(); -const shape = new Shape(); - -// 画像の場合、Retina対応でスケールを設定 -shape.scaleX = shape.scaleY = 0.5; - -// スケール設定後に中心配置 -shape.x = -shape.width / 2; -shape.y = -shape.height / 2; - -sprite.addChild(shape); -``` - -### パターン: Sprite を Sprite に中心配置 - -```typescript -const parent = new Sprite(); -const child = new Sprite(); - -// 子要素のサイズ確定後に中心配置 -child.x = -child.width / 2; -child.y = -child.height / 2; - -parent.addChild(child); -``` - -### なぜ中心配置が必要か - -- スケール・回転は DisplayObject の (0, 0) を基点に実行される -- 中心配置しないと、回転・拡縮時に意図しない位置ずれが発生する -- 中心配置により、親 Sprite の (x, y) がそのまま表示上の中心座標になる - -**注意:** すべてのケースで必須ではないが、アニメーション対象の要素には基本的にこのパターンを適用する。 - ---- - -## Atomic Design Hierarchy - -### Atom (原子) - 最小単位 - -最も基本的なUI要素。これ以上分割できない。 - -```typescript -// ButtonAtom: ボタンの基本機能 (enable/disable による連続押下防止機能付き) -import { Sprite } from "@next2d/display"; - -export class ButtonAtom extends Sprite -{ - constructor () - { - super(); - this.buttonMode = true; - } - - /** - * @description ボタンを有効化する - * Enable button - * - * @return {void} - * @method - * @public - */ - enable (): void - { - this.mouseEnabled = true; - this.mouseChildren = true; - } - - /** - * @description ボタンを無効化する - * Disable button - * - * @return {void} - * @method - * @public - */ - disable (): void - { - this.mouseEnabled = false; - this.mouseChildren = false; - } -} -``` - -```typescript -// TextAtom: テキスト表示の基本機能 -import { TextField } from "@next2d/text"; -import type { ITextField } from "@/interface/ITextField"; -import type { ITextFormatObject } from "@/interface/ITextFormatObject"; - -export class TextAtom extends TextField implements ITextField -{ - constructor ( - text: string = "", - props: any | null = null, - format_object: ITextFormatObject | null = null - ) { - super(); - // プロパティ設定、フォーマット設定 - } -} -``` - -### ボタン連続押下防止パターン - -ボタン押下後に処理が完了するまで連続押下を防止したい場合に使えるパターン。`ButtonAtom` の `disable()` / `enable()` を利用して `mouseEnabled` と `mouseChildren` を制御する。 - -連続押下を防止するかどうかはユースケースに応じて判断する。画面遷移やAPI通信など多重実行を避けたい処理では有効。 - -#### View でのイベント登録パターン - -```typescript -// View: ボタン押下時にViewModelのハンドラを呼び出す -async initialize (): Promise -{ - const btn = new YourBtnMolecule(); - btn.addEventListener(PointerEvent.POINTER_DOWN, (event) => { - this.vm.handleButtonTap(event); - }); - this.addChild(btn); -} -``` - -#### ViewModel での連続押下防止パターン - -```typescript -// ViewModel: disable → 処理 → enable で連続押下を防止 -handleButtonTap (event: PointerEvent): void -{ - // ボタンを即座に無効化して連続押下を防止 - const button = event.currentTarget as unknown as ButtonAtom; - button.disable(); - - // 処理実行 (画面遷移、API呼び出し、アニメーション等) - this.someUseCase.execute(); - - // 処理完了後にボタンを再有効化 (画面遷移の場合は不要) - button.enable(); -} -``` - -#### 非同期処理での連続押下防止パターン - -```typescript -// ViewModel: 非同期処理の完了を待ってから再有効化 -async handleButtonTap (event: PointerEvent): Promise -{ - const button = event.currentTarget as unknown as ButtonAtom; - button.disable(); - - try { - await this.fetchDataUseCase.execute(); - } finally { - // エラー時も必ず再有効化 - button.enable(); - } -} -``` - -#### アニメーション完了後に再有効化するパターン - -```typescript -// ViewModel: アニメーション完了コールバックで再有効化 -handleButtonTap (event: PointerEvent): void -{ - const button = event.currentTarget as unknown as ButtonAtom; - button.disable(); - - new SomeAnimation(button, () => { - // アニメーション完了後に再有効化 - button.enable(); - }).start(); -} -``` - -#### 連続押下を許可するケース - -以下のケースでは `disable()` / `enable()` を使わず、連続押下を許可する: - -- **インクリメント/デクリメントボタン**: 数量の増減など、連打を前提とした操作 -- **連射系ゲーム操作**: 連続タップがゲームメカニクスの一部である場合 -- **トグルボタン**: ON/OFF を素早く切り替える必要がある場合 - -### Molecule (分子) - Atomの組み合わせ - -複数のAtomを組み合わせた、特定の用途向けコンポーネント。 - -```typescript -import { ButtonAtom } from "../atom/ButtonAtom"; -import { HomeContent } from "@/ui/content/HomeContent"; -import type { IDraggable } from "@/interface/IDraggable"; - -export class HomeBtnMolecule extends ButtonAtom implements IDraggable -{ - private readonly homeContent: HomeContent; - - constructor () - { - super(); - this.homeContent = new HomeContent(); - this.addChild(this.homeContent); - } - - // IDraggableメソッド(startDrag/stopDrag)はMovieClipContentの親クラスから継承 -} -``` - -```typescript -import { ButtonAtom } from "../atom/ButtonAtom"; -import { TextAtom } from "../atom/TextAtom"; - -export class TopBtnMolecule extends ButtonAtom -{ - constructor (text: string) // ViewModelからテキストを受け取る - { - super(); - const textField = new TextAtom(text, { autoSize: "center" }); - this.addChild(textField); - } - - playEntrance (callback: () => void): void - { - // アニメーション再生 - } -} -``` - -### Organism (有機体) - 拡張用 - -複数のMoleculeを組み合わせた大きな機能単位。必要に応じて実装。 - -### Page (ページ) - -画面全体を構成するコンポーネント。ViewからPageを配置し、PageがMolecule/Atomを組み合わせて画面構築。 - -### Template (テンプレート) - 拡張用 - -ページのレイアウト構造を定義。必要に応じて実装。 - -## Component Creation Templates - -### New Atom - -```typescript -import { Sprite } from "@next2d/display"; - -export class YourAtom extends Sprite -{ - constructor (props: any = null) - { - super(); - if (props) { - Object.assign(this, props); - } - } -} -``` - -### New Molecule - -```typescript -import { ButtonAtom } from "../atom/ButtonAtom"; -import { TextAtom } from "../atom/TextAtom"; - -export class YourMolecule extends ButtonAtom -{ - constructor () - { - super(); - const text = new TextAtom("Click me"); - this.addChild(text); - } -} -``` - -## Anti-Patterns - -```typescript -// NG: コンポーネント内でデータ取得 -export class BadAtom extends TextField { - async fetchDataFromAPI() { ... } // NG: データ取得は別層の責務 -} - -// NG: 直接APIアクセス -constructor() { - const data = await Repository.get(); // NG -} - -// OK: ViewModelからデータを受け取る -constructor(text: string) { - this.textField = new TextAtom(text); // OK -} -``` - ---- - -## Animation - -アニメーションロジックをコンポーネントから分離し、再利用性と保守性を向上。 - -### Naming Convention - -`{Component}{Action}Animation.ts` (例: `TopBtnShowAnimation.ts`) - -### Animation Types - -- **Show Animation**: 画面表示時のアニメーション -- **Exit Animation**: 画面遷移時のアニメーション -- **Interaction Animation**: ユーザー操作に対するアニメーション - -### Animation Class Template - -```typescript -import type { Sprite } from "@next2d/display"; -import { Tween, Easing, type Job } from "@next2d/ui"; -import { Event } from "@next2d/events"; - -/** - * @description [アニメーションの説明] - * [Animation description] - * - * @class - * @public - */ -export class YourAnimation -{ - private readonly _job: Job; - - /** - * @param {Sprite} sprite - アニメーション対象 - * @param {() => void} callback - 完了時コールバック - * @constructor - * @public - */ - constructor ( - sprite: Sprite, - callback?: () => void - ) { - // 初期状態設定 - sprite.alpha = 0; - - // Tween設定: (対象, 開始値, 終了値, 秒数, 遅延秒数, イージング) - this._job = Tween.add(sprite, - { "alpha": 0 }, - { "alpha": 1 }, - 0.5, 1, Easing.outQuad - ); - - if (callback) { - this._job.addEventListener(Event.COMPLETE, callback); - } - } - - /** - * @description アニメーション開始 - * Start animation - * - * @method - * @public - */ - start (): void - { - this._job.start(); - } -} -``` - -### Component-Animation Coordination - -```typescript -// component/molecule/TopBtnMolecule.ts -import { TopBtnShowAnimation } from "@/ui/animation/top/TopBtnShowAnimation"; - -export class TopBtnMolecule extends ButtonAtom { - playShow(callback: () => void): void { - new TopBtnShowAnimation(this, callback).start(); - } -} -``` - ---- - -## Content (Animation Tool) - -Animation Toolで作成されたコンテンツをTypeScriptクラスとしてラップ。 - -### Content Template - -```typescript -import { MovieClipContent } from "@next2d/framework"; - -/** - * @description [コンテンツの説明] - * [Content description] - * - * @class - * @extends {MovieClipContent} - */ -export class YourContent extends MovieClipContent -{ - /** - * @description Animation Toolのシンボル名を返す - * Returns the Animation Tool symbol name - * - * @return {string} - * @readonly - */ - get namespace (): string - { - return "YourSymbolName"; // Animation Toolで設定した名前と一致させる - } -} -``` - -### Content with Interface - -```typescript -import { MovieClipContent } from "@next2d/framework"; -import type { IDraggable } from "@/interface/IDraggable"; - -export class HomeContent extends MovieClipContent implements IDraggable -{ - get namespace (): string - { - return "HomeContent"; - } - - // IDraggableメソッド(startDrag/stopDrag)は - // MovieClipContentの親クラス(MovieClip)から継承 -} -``` - -### Content Creation Steps - -1. Animation Toolでシンボルを作成 -2. `.n2d`ファイルを`file/`ディレクトリに配置 -3. Contentクラスを作成 (`namespace`はシンボル名と一致させる) -4. Molecule等のコンポーネントで使用 - -### Content Rules - -- クラス名とシンボル名を一致させる -- アニメーションの制御のみを担当 -- 必要な機能はインターフェースで定義 - ---- - -# View / ViewModel (MVVM Pattern) - -## Rules - -- 1画面にView + ViewModelをワンセット作成 -- ディレクトリ名はキャメルケースの最初のブロック (例: `questList` → `view/quest/`) -- Viewは表示構造のみ担当、ビジネスロジックはViewModelに委譲 -- イベントは必ずViewModelに委譲(View内で完結させない) -- ViewModelはインターフェースに依存し、具象クラスに依存しない - -## Lifecycle (実行順序) - -``` -1. ViewModel インスタンス生成 -2. ViewModel.initialize() ← ViewModelが先 -3. View インスタンス生成 (ViewModelを注入) -4. View.initialize() ← UIコンポーネントの構築 -5. View.onEnter() ← 画面表示時の処理 - (ユーザー操作) -6. View.onExit() ← 画面非表示時の処理 -``` - -### View Lifecycle Methods - -| Method | Timing | Purpose | Do | Don't | -|--------|--------|---------|-----|-------| -| `initialize()` | View生成直後、表示前 | UIコンポーネントの生成・配置・イベントリスナー登録 | addChild, addEventListener | API呼び出し、重い処理 | -| `onEnter()` | initialize完了後、画面表示直前 | 入場アニメーション、データ取得、タイマー開始 | アニメーション再生、fetchInitialData | UIコンポーネント生成 | -| `onExit()` | 別画面遷移前 | アニメーション停止、タイマークリア、リソース解放 | clearInterval, 状態リセット | 新リソース作成 | - -### ViewModel Lifecycle Methods - -| Method | Timing | Purpose | View参照 | -|--------|--------|---------|---------| -| `constructor()` | インスタンス生成時 | UseCaseの生成 | 不可 | -| `initialize()` | Viewの`initialize()`より前 | 初期データ取得、状態初期化 | 不可 | -| イベントハンドラ | ユーザー操作時 | ビジネスロジック実行 | 可能 | - -## View Class Template - -```typescript -import type { {Screen}ViewModel } from "./{Screen}ViewModel"; -import { View } from "@next2d/framework"; - -/** - * @class - * @extends {View} - */ -export class {Screen}View extends View -{ - /** - * @param {{Screen}ViewModel} vm - * @constructor - * @public - */ - constructor ( - private readonly vm: {Screen}ViewModel - ) { - super(); - } - - /** - * @description 画面の初期化 - UIコンポーネントの構築 - * Initialize - Build UI components - * - * @return {Promise} - * @method - * @override - * @public - */ - async initialize (): Promise - { - // UIコンポーネントの作成と配置 - // イベントリスナーの登録 (ViewModelのメソッドに接続) - } - - /** - * @description 画面表示時の処理 - * On screen shown - * - * @return {Promise} - * @method - * @override - * @public - */ - async onEnter (): Promise - { - // 入場アニメーション、データ取得 - } - - /** - * @description 画面非表示時の処理 - * On screen hidden - * - * @return {Promise} - * @method - * @override - * @public - */ - async onExit (): Promise - { - // タイマークリア、リソース解放 - } -} -``` - -## ViewModel Class Template - -```typescript -import { ViewModel } from "@next2d/framework"; -import { YourUseCase } from "@/model/application/{screen}/usecase/YourUseCase"; - -/** - * @class - * @extends {ViewModel} - */ -export class {Screen}ViewModel extends ViewModel -{ - private readonly yourUseCase: YourUseCase; - - constructor () - { - super(); - this.yourUseCase = new YourUseCase(); - } - - /** - * @description ViewModelの初期化 (Viewのinitialize()より前に呼ばれる) - * Initialize ViewModel (called before View's initialize()) - * - * @return {Promise} - * @method - * @override - * @public - */ - async initialize (): Promise - { - // 初期データ取得、状態初期化 - // ※ この時点ではViewは未生成のためUI操作不可 - } - - /** - * @description イベントハンドラ - * Event handler - * - * @param {PointerEvent} event - * @return {void} - * @method - * @public - */ - yourEventHandler (event: PointerEvent): void - { - // インターフェースを通じてターゲットを取得 - const target = event.currentTarget as unknown as IYourInterface; - this.yourUseCase.execute(target); - } -} -``` - -## View-ViewModel Coordination Pattern - -ViewModelの`initialize()`で事前取得したデータをViewで使用するパターン: - -```typescript -// ViewModel: 事前にデータ取得 -async initialize(): Promise { - const data = await HomeTextRepository.get(); - this.homeText = data.word; -} - -getHomeText(): string { - return this.homeText; -} - -// View: ViewModelから取得済みデータを使用 -async initialize(): Promise { - // vm.initialize()は既に完了している - const text = this.vm.getHomeText(); - const textField = new TextAtom(text); - this.addChild(textField); -} -``` - -## Code Generation - -```bash -npm run generate -``` - -`routing.json`のトッププロパティ値を分解し、`view`ディレクトリ直下に対象ディレクトリがなければ作成。View/ViewModelが存在しない場合のみ新規クラスを生成。 - -## Anti-Patterns - -```typescript -// NG: Viewでビジネスロジック -class BadView extends View { - async initialize() { - btn.addEventListener(PointerEvent.POINTER_DOWN, async () => { - const data = await Repository.get(); // NG - this.processData(data); // NG - }); - } -} - -// NG: ViewModelで具象クラスに依存 -homeContentPointerDownEvent(event: PointerEvent): void { - const target = event.currentTarget as HomeBtnMolecule; // NG - target.startDrag(); -} - -// OK: ViewModelでインターフェースに依存 -homeContentPointerDownEvent(event: PointerEvent): void { - const target = event.currentTarget as unknown as IDraggable; // OK - this.startDragUseCase.execute(target); -} -``` diff --git a/.github/skills/references/framework-specs.md b/.github/skills/references/framework-specs.md deleted file mode 100644 index 2129835..0000000 --- a/.github/skills/references/framework-specs.md +++ /dev/null @@ -1,1687 +0,0 @@ -# Next2D Framework Specs - Combined Reference - -## Table of Contents - -1. [Index - フレームワーク概要](#index---フレームワーク概要) -2. [AnimationTool連携](#animationtool連携) -3. [設定ファイル](#設定ファイル) -4. [ルーティング](#ルーティング) -5. [View と ViewModel](#view-と-viewmodel) - ---- - -# Index - フレームワーク概要 - -Next2D Framework is an MVVM framework for application development using the Next2D Player. It provides routing, View/ViewModel management, configuration management, and other features for single-page applications (SPAs). - -## Key Features - -- **MVVM Pattern**: Separation of concerns through Model-View-ViewModel architecture -- **Clean Architecture**: Dependency inversion and loosely coupled design -- **Single Page Application**: Scene management based on URLs -- **Animation Tool Integration**: Integration with assets created in Animation Tool -- **TypeScript Support**: Type-safe development capability -- **Atomic Design**: Component design promoting reusability - -## Architecture Overview - -This project combines clean architecture with the MVVM pattern. - -```mermaid -graph TB - subgraph ViewLayer["View Layer"] - View["View"] - ViewModel["ViewModel"] - UI["UI Components"] - end - - subgraph InterfaceLayer["Interface Layer"] - IDraggable["IDraggable"] - ITextField["ITextField"] - IResponse["IResponse"] - end - - subgraph ApplicationLayer["Application Layer"] - UseCase["UseCase"] - end - - subgraph DomainLayer["Domain Layer"] - DomainLogic["Domain Logic"] - DomainService["Service"] - end - - subgraph InfraLayer["Infrastructure Layer"] - Repository["Repository"] - ExternalAPI["External API"] - end - - ViewLayer -.->|interface経由| InterfaceLayer - ViewLayer -.->|calls| ApplicationLayer - ApplicationLayer -.->|interface経由| InterfaceLayer - ApplicationLayer -.->|uses| DomainLayer - ApplicationLayer -.->|calls| InfraLayer - InfraLayer -.->|accesses| ExternalAPI -``` - -### Layer Responsibilities - -| Layer | Path | Role | -|----------|------|------| -| **View** | `view/*`, `ui/*` | Screen structure and display | -| **ViewModel** | `view/*` | Bridging View and Model, event handling | -| **Interface** | `interface/*` | Abstraction layer, type definitions | -| **Application** | `model/application/*/usecase/*` | Business logic implementation (UseCase) | -| **Domain** | `model/domain/*` | Core business rules | -| **Infrastructure** | `model/infrastructure/repository/*` | Data access, external API integration | - -### Dependency Direction - -Following clean architecture principles, dependencies always point inward toward the Domain layer. - -- **View Layer**: Uses Application layer through interfaces -- **Application Layer**: Uses Domain and Infrastructure layers through interfaces -- **Domain Layer**: Depends on nothing (pure business logic) -- **Infrastructure Layer**: Implements Domain layer interfaces - -## Directory Structure - -``` -my-app/ -├── src/ -│ ├── config/ # Configuration files -│ │ ├── stage.json # Stage configuration -│ │ ├── config.json # Environment configuration -│ │ ├── routing.json # Routing configuration -│ │ └── Config.ts # Type definitions and exports -│ │ -│ ├── interface/ # Interface definitions -│ │ ├── IDraggable.ts # Draggable objects -│ │ ├── ITextField.ts # Text field interface -│ │ ├── IHomeTextResponse.ts # API response type -│ │ └── IViewName.ts # Screen name type definition -│ │ -│ ├── view/ # View & ViewModel -│ │ ├── top/ -│ │ │ ├── TopView.ts # Screen structure definition -│ │ │ └── TopViewModel.ts # Business logic bridge -│ │ └── home/ -│ │ ├── HomeView.ts -│ │ └── HomeViewModel.ts -│ │ -│ ├── model/ -│ │ ├── application/ # Application layer -│ │ │ ├── top/ -│ │ │ │ └── usecase/ -│ │ │ │ └── NavigateToViewUseCase.ts -│ │ │ └── home/ -│ │ │ └── usecase/ -│ │ │ ├── StartDragUseCase.ts -│ │ │ ├── StopDragUseCase.ts -│ │ │ └── CenterTextFieldUseCase.ts -│ │ │ -│ │ ├── domain/ # Domain layer -│ │ │ └── callback/ -│ │ │ ├── Background.ts -│ │ │ └── Background/ -│ │ │ └── service/ -│ │ │ ├── BackgroundDrawService.ts -│ │ │ └── BackgroundChangeScaleService.ts -│ │ │ -│ │ └── infrastructure/ # Infrastructure layer -│ │ └── repository/ -│ │ └── HomeTextRepository.ts -│ │ -│ ├── ui/ # UI components -│ │ ├── animation/ # Animation definitions -│ │ │ └── top/ -│ │ │ └── TopBtnShowAnimation.ts -│ │ │ -│ │ ├── component/ # Atomic design -│ │ │ ├── atom/ # Minimal unit components -│ │ │ │ ├── ButtonAtom.ts -│ │ │ │ └── TextAtom.ts -│ │ │ ├── molecule/ # Combined atoms -│ │ │ │ ├── HomeBtnMolecule.ts -│ │ │ │ └── TopBtnMolecule.ts -│ │ │ ├── organism/ # Multiple molecules combined -│ │ │ ├── template/ # Page templates -│ │ │ └── page/ # Page components -│ │ │ ├── top/ -│ │ │ │ └── TopPage.ts -│ │ │ └── home/ -│ │ │ └── HomePage.ts -│ │ │ -│ │ └── content/ # Animation Tool generated content -│ │ ├── TopContent.ts -│ │ └── HomeContent.ts -│ │ -│ ├── assets/ # Static assets -│ │ -│ ├── Packages.ts # Package exports -│ └── index.ts # Entry point -│ -├── file/ # Animation Tool output files -│ └── sample.n2d -│ -├── mock/ # Mock data -│ ├── api/ # API mocks -│ ├── content/ # Content mocks -│ └── img/ # Image mocks -│ -└── package.json -``` - -## Framework Flowchart - -Detailed flow of screen transitions via the gotoView function. - -```mermaid -graph TD - User([User]) -->|Request| GotoView[gotoView Path] - - GotoView --> LoadingCheck{use loading?
Default: true} - - LoadingCheck -->|YES| ScreenOverlay[Screen Overlay] - LoadingCheck -->|NO| RemoveResponse - ScreenOverlay --> LoadingStart[Start Loading] - LoadingStart --> RemoveResponse - - RemoveResponse[Remove Previous Response Data] --> ParseQuery[Parse Query String] - ParseQuery --> UpdateHistory{SPA mode?} - - UpdateHistory -->|YES| PushState[Push History State] - UpdateHistory -->|NO| RequestType - PushState --> RequestType - - RequestType[Request Type] - - RequestType --> JSON[JSON: Get external JSON data] - RequestType --> CONTENT[CONTENT: Get Animation Tool JSON] - RequestType --> CUSTOM[CUSTOM: Request to external API] - - JSON --> CacheCheck{use cache?
Default: false} - CONTENT --> CacheCheck - CUSTOM --> CacheCheck - - CacheCheck -->|YES| CacheData[(Cache)] - CacheCheck -->|NO| GlobalData{{Global Network}} - - CacheData --> Cached{Cached?} - - Cached -->|NO| GlobalData - Cached -->|YES| RegisterResponse - GlobalData --> RegisterResponse - - RegisterResponse[Register Response Data] --> RequestCallback{request callback?} - - RequestCallback -->|YES| ExecRequestCallback[Execute Request Callback] - RequestCallback -->|NO| UnbindView - ExecRequestCallback --> UnbindView - - UnbindView[Previous View: onExit & Unbind] --> BindView[New View/ViewModel: Bind] - BindView --> ViewModelInit[ViewModel: initialize] - - ViewModelInit --> ViewInit[View: initialize] - ViewInit --> AddToStage[Add View to Stage] - AddToStage --> GotoViewCallback{gotoView callback?} - - GotoViewCallback -->|YES| ExecGotoViewCallback[Execute gotoView Callback] - GotoViewCallback -->|NO| LoadingEndCheck - ExecGotoViewCallback --> LoadingEndCheck - - LoadingEndCheck{use loading?
Default: true} - - LoadingEndCheck -->|YES| LoadingEnd[End Loading] - LoadingEndCheck -->|NO| OnEnter - LoadingEnd --> DisposeOverlay[Dispose Screen Overlay] - DisposeOverlay --> OnEnter - - OnEnter[View: onEnter] --> StartDrawing - - StartDrawing[Start Drawing] -->|Response| User - - style User fill:#d5e8d4,stroke:#82b366 - style StartDrawing fill:#dae8fc,stroke:#6c8ebf - style CacheData fill:#fff2cc,stroke:#d6b656 - style GlobalData fill:#f5f5f5,stroke:#666666 -``` - -### Main Flow Steps - -| Step | Description | -|----------|------| -| **gotoView** | Entry point for screen transitions | -| **Loading** | Display/hide loading screen control | -| **Request Type** | Three types of requests: JSON, CONTENT, CUSTOM | -| **Cache** | Response data caching control | -| **View/ViewModel Bind** | New View/ViewModel binding process | -| **onEnter** | Callback after screen display completion | - -## Major Design Patterns - -### 1. MVVM (Model-View-ViewModel) - -- **View**: Handles screen structure and display without business logic -- **ViewModel**: Bridges View and Model, holds UseCases and processes events -- **Model**: Manages business logic and data access - -### 2. UseCase Pattern - -Create dedicated UseCase classes for each user action: - -```typescript -export class StartDragUseCase -{ - execute(target: IDraggable): void - { - target.startDrag(); - } -} -``` - -### 3. Dependency Inversion - -Depend on interfaces rather than concrete classes: - -```typescript -// Good example: depends on interface -import type { IDraggable } from "@/interface/IDraggable"; - -function startDrag(target: IDraggable): void -{ - target.startDrag(); -} -``` - -### 4. Repository Pattern - -Abstracts data access with error handling: - -```typescript -export class HomeTextRepository -{ - static async get(): Promise - { - try { - const response = await fetch(`${config.api.endPoint}api/home.json`); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return await response.json(); - } catch (error) { - console.error("Failed to fetch:", error); - throw error; - } - } -} -``` - -## Quick Start - -### Project Creation - -```bash -npx create-next2d-app my-app -cd my-app -npm install -npm start -``` - -### Auto-generate View/ViewModel - -```bash -npm run generate -``` - -This command parses the top properties in `routing.json` and generates corresponding View and ViewModel classes. - -## Best Practices - -1. **Interface First**: Always depend on interfaces rather than concrete types -2. **Single Responsibility Principle**: Each class should have only one responsibility -3. **Dependency Injection**: Inject dependencies through constructors -4. **Error Handling**: Handle errors appropriately in Repository layer -5. **Type Safety**: Use explicit type definitions, avoid `any` type - -## Related Documentation - -### Basics -- View/ViewModel - Screen display and data binding -- Routing - URL-based screen transitions -- Configuration Files - Environment and stage configuration -- Animation Tool Integration - Leveraging Animation Tool assets - -### Next2D Player Integration -- Next2D Player - Rendering engine -- MovieClip - Timeline animation -- Event System - User interaction - ---- - -# AnimationTool連携 - -Next2D FrameworkはAnimationToolで作成したアセットとシームレスに連携できます。 - -## 概要 - -AnimationToolは、Next2D Player用のアニメーションやUIコンポーネントを作成するためのツールです。出力されたJSONファイルをフレームワークで読み込み、MovieClipとして利用できます。 - -## ディレクトリ構成 - -``` -src/ -├── ui/ -│ ├── content/ # Animation Tool生成コンテンツ -│ │ ├── TopContent.ts -│ │ └── HomeContent.ts -│ │ -│ ├── component/ # Atomic Designコンポーネント -│ │ ├── atom/ # 最小単位のコンポーネント -│ │ │ ├── ButtonAtom.ts -│ │ │ └── TextAtom.ts -│ │ ├── molecule/ # Atomを組み合わせたコンポーネント -│ │ │ ├── TopBtnMolecule.ts -│ │ │ └── HomeBtnMolecule.ts -│ │ ├── organism/ # 複数Moleculeの組み合わせ -│ │ ├── template/ # ページテンプレート -│ │ └── page/ # ページコンポーネント -│ │ ├── top/ -│ │ │ └── TopPage.ts -│ │ └── home/ -│ │ └── HomePage.ts -│ │ -│ └── animation/ # コードアニメーション定義 -│ └── top/ -│ └── TopBtnShowAnimation.ts -│ -└── file/ # Animation Tool出力ファイル - └── sample.n2d -``` - -## MovieClipContent - -Animation Toolで作成したコンテンツをラップするクラスです。 - -### 基本構造 - -```typescript -import { MovieClipContent } from "@next2d/framework"; - -/** - * @see file/sample.n2d - */ -export class TopContent extends MovieClipContent -{ - /** - * Animation Tool上で設定したシンボル名を返す - */ - get namespace(): string - { - return "TopContent"; - } -} -``` - -### namespaceの役割 - -`namespace`プロパティは、Animation Toolで作成したシンボルの名前と一致させます。この名前を使って、読み込まれたJSONデータから対応するMovieClipが生成されます。 - -## コンテンツの読み込み - -### routing.jsonでの設定 - -Animation ToolのJSONファイルは`routing.json`の`requests`で読み込みます。 - -```json -{ - "@sample": { - "requests": [ - { - "type": "content", - "path": "{{ content.endPoint }}content/sample.json", - "name": "MainContent", - "cache": true - } - ] - }, - "top": { - "requests": [ - { - "type": "cluster", - "path": "@sample" - } - ] - } -} -``` - -#### request設定 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `type` | string | `"content"` を指定 | -| `path` | string | JSONファイルへのパス | -| `name` | string | レスポンスに登録されるキー名 | -| `cache` | boolean | キャッシュするかどうか | - -#### cluster機能 - -`@`で始まるキーはクラスターとして定義され、複数のルートで共有できます。`type: "cluster"`で参照します。 - -```json -{ - "@common": { - "requests": [ - { - "type": "content", - "path": "{{ content.endPoint }}common.json", - "name": "CommonContent", - "cache": true - } - ] - }, - "top": { - "requests": [ - { "type": "cluster", "path": "@common" } - ] - }, - "home": { - "requests": [ - { "type": "cluster", "path": "@common" } - ] - } -} -``` - -## 関連項目 - -- View/ViewModel -- ルーティング -- 設定ファイル - ---- - -# 設定ファイル - -Next2D Frameworkの設定は3つのJSONファイルで管理します。 - -## ファイル構成 - -``` -src/config/ -├── stage.json # 表示領域の設定 -├── config.json # 環境設定 -└── routing.json # ルーティング設定 -``` - -## stage.json - -表示領域(Stage)の設定を行うJSONファイルです。 - -```json -{ - "width": 1920, - "height": 1080, - "fps": 60, - "options": { - "fullScreen": true, - "tagId": null, - "bgColor": "transparent" - } -} -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `width` | number | 240 | 表示領域の幅 | -| `height` | number | 240 | 表示領域の高さ | -| `fps` | number | 60 | 1秒間に何回描画するか(1〜60) | -| `options` | object | null | オプション設定 | - -### options設定 - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `fullScreen` | boolean | false | Stageで設定した幅と高さを超えて画面全体に描画 | -| `tagId` | string | null | IDを指定すると、指定したIDのエレメント内で描画を行う | -| `bgColor` | string | "transparent" | 背景色を16進数で指定。デフォルトは無色透明 | - -## config.json - -環境ごとの設定を管理するファイルです。`local`、`dev`、`stg`、`prd`、`all`と区切られており、`all`以外は任意の環境名です。 - -```json -{ - "local": { - "api": { - "endPoint": "http://localhost:3000/" - }, - "content": { - "endPoint": "http://localhost:5500/" - } - }, - "dev": { - "api": { - "endPoint": "https://dev-api.example.com/" - } - }, - "prd": { - "api": { - "endPoint": "https://api.example.com/" - } - }, - "all": { - "spa": true, - "defaultTop": "top", - "loading": { - "callback": "Loading" - }, - "gotoView": { - "callback": ["callback.Background"] - } - } -} -``` - -### all設定 - -`all`はどの環境でも書き出される共通変数です。 - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `spa` | boolean | true | Single Page ApplicationとしてURLでシーンを制御 | -| `defaultTop` | string | "top" | ページトップのView。設定がない場合はTopViewクラスが起動 | -| `loading.callback` | string | Loading | ローディング画面のクラス名。start関数とend関数を呼び出す | -| `gotoView.callback` | string \| array | ["callback.Background"] | gotoView完了後のコールバッククラス | - -### platform設定 - -ビルド時の`--platform`で指定した値がセットされます。 - -対応値: `macos`, `windows`, `linux`, `ios`, `android`, `web` - -```typescript -import { config } from "@/config/Config"; - -if (config.platform === "ios") { - // iOS固有の処理 -} -``` - -## routing.json - -ルーティングの設定ファイルです。詳細は[ルーティング](#ルーティング)を参照してください。 - -```json -{ - "top": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/top.json", - "name": "TopText" - } - ] - }, - "home": { - "requests": [] - } -} -``` - -## 設定値の取得 - -コード内で設定値を取得するには`config`オブジェクトを使用します。 - -### Config.tsの例 - -```typescript -import stageJson from "./stage.json"; -import configJson from "./config.json"; - -interface IStageConfig { - width: number; - height: number; - fps: number; - options: { - fullScreen: boolean; - tagId: string | null; - bgColor: string; - }; -} - -interface IConfig { - stage: IStageConfig; - api: { - endPoint: string; - }; - content: { - endPoint: string; - }; - spa: boolean; - defaultTop: string; - platform: string; -} - -export const config: IConfig = { - stage: stageJson, - ...configJson -}; -``` - -### 使用例 - -```typescript -import { config } from "@/config/Config"; - -// ステージ設定 -const stageWidth = config.stage.width; -const stageHeight = config.stage.height; - -// API設定 -const apiEndPoint = config.api.endPoint; - -// SPA設定 -const isSpa = config.spa; -``` - -## ローディング画面 - -`loading.callback`で設定したクラスの`start`関数と`end`関数が呼び出されます。 - -```typescript -export class Loading -{ - private shape: Shape; - - constructor() - { - this.shape = new Shape(); - // ローディング表示の初期化 - } - - start(): void - { - // ローディング開始時の処理 - stage.addChild(this.shape); - } - - end(): void - { - // ローディング終了時の処理 - this.shape.remove(); - } -} -``` - -## gotoViewコールバック - -`gotoView.callback`で設定したクラスの`execute`関数が呼び出されます。複数のクラスを配列で設定でき、async/awaitで順次実行されます。 - -```typescript -import { app } from "@next2d/framework"; -import { Shape, stage } from "@next2d/display"; - -export class Background -{ - public readonly shape: Shape; - - constructor() - { - this.shape = new Shape(); - } - - execute(): void - { - const context = app.getContext(); - const view = context.view; - if (!view) return; - - // 背景を最背面に配置 - view.addChildAt(this.shape, 0); - } -} -``` - -## ビルドコマンド - -環境を指定してビルド: - -```bash -# ローカル環境 -npm run build -- --env=local - -# 開発環境 -npm run build -- --env=dev - -# 本番環境 -npm run build -- --env=prd -``` - -プラットフォームを指定: - -```bash -npm run build -- --platform=web -npm run build -- --platform=ios -npm run build -- --platform=android -``` - -## 設定例 - -### 完全な設定ファイルの例 - -#### stage.json - -```json -{ - "width": 1920, - "height": 1080, - "fps": 60, - "options": { - "fullScreen": true, - "tagId": null, - "bgColor": "#1461A0" - } -} -``` - -#### config.json - -```json -{ - "local": { - "api": { - "endPoint": "http://localhost:3000/" - }, - "content": { - "endPoint": "http://localhost:5500/mock/content/" - } - }, - "dev": { - "api": { - "endPoint": "https://dev-api.example.com/" - }, - "content": { - "endPoint": "https://dev-cdn.example.com/content/" - } - }, - "prd": { - "api": { - "endPoint": "https://api.example.com/" - }, - "content": { - "endPoint": "https://cdn.example.com/content/" - } - }, - "all": { - "spa": true, - "defaultTop": "top", - "loading": { - "callback": "Loading" - }, - "gotoView": { - "callback": ["callback.Background"] - } - } -} -``` - -## 関連項目 - -- [ルーティング](#ルーティング) -- [View/ViewModel](#view-と-viewmodel) - ---- - -# ルーティング - -Next2D FrameworkはシングルページアプリケーションとしてURLでシーンを制御できます。ルーティングは`routing.json`で設定します。 - -## 基本設定 - -ルーティングのトッププロパティは英数字とスラッシュが使用できます。スラッシュをキーにCamelCaseでViewクラスにアクセスします。 - -```json -{ - "top": { - "requests": [] - }, - "home": { - "requests": [] - }, - "quest/list": { - "requests": [] - } -} -``` - -上記の場合: -- `top` → `TopView`クラス -- `home` → `HomeView`クラス -- `quest/list` → `QuestListView`クラス - -## ルート定義 - -### 基本的なルート - -```json -{ - "top": { - "requests": [] - } -} -``` - -アクセス: `https://example.com/` または `https://example.com/top` - -### セカンドレベルプロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `private` | boolean | false | URLでの直接アクセスを制御。trueの場合、URLでアクセスするとTopViewが読み込まれる | -| `requests` | array | null | Viewがbindされる前にリクエストを送信 | - -### プライベートルート - -URLでの直接アクセスを禁止したい場合: - -```json -{ - "quest/detail": { - "private": true, - "requests": [] - } -} -``` - -`private: true`の場合、URLで直接アクセスすると`TopView`にリダイレクトされます。プログラムからの`app.gotoView()`でのみアクセス可能です。 - -## requestsの設定 - -Viewがbindされる前にデータを取得できます。取得したデータは`app.getResponse()`で取得できます。 - -### requests配列の設定項目 - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `type` | string | content | `json`、`content`、`custom`の固定値 | -| `path` | string | empty | リクエスト先のパス | -| `name` | string | empty | `response`にセットするキー名 | -| `cache` | boolean | false | データをキャッシュするか | -| `callback` | string \| array | null | リクエスト完了後のコールバッククラス | -| `class` | string | empty | リクエストを実行するクラス(typeがcustomの場合のみ) | -| `access` | string | public | 関数へのアクセス修飾子(`public`または`static`) | -| `method` | string | empty | 実行する関数名(typeがcustomの場合のみ) | - -### typeの種類 - -#### json - -外部JSONデータを取得: - -```json -{ - "home": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/home.json", - "name": "HomeData" - } - ] - } -} -``` - -#### content - -Animation ToolのJSONを取得: - -```json -{ - "top": { - "requests": [ - { - "type": "content", - "path": "{{content.endPoint}}top.json", - "name": "TopContent" - } - ] - } -} -``` - -#### custom - -カスタムクラスでリクエストを実行: - -```json -{ - "user/profile": { - "requests": [ - { - "type": "custom", - "class": "repository.UserRepository", - "access": "static", - "method": "getProfile", - "name": "UserProfile" - } - ] - } -} -``` - -### 変数の展開 - -`{{***}}`で囲むと`config.json`の変数を取得できます: - -```json -{ - "path": "{{api.endPoint}}path/to/api" -} -``` - -### キャッシュの利用 - -`cache: true`を設定すると、データがキャッシュされます。キャッシュしたデータは画面遷移しても初期化されません。 - -```json -{ - "top": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/master.json", - "name": "MasterData", - "cache": true - } - ] - } -} -``` - -キャッシュデータの取得: - -```typescript -import { app } from "@next2d/framework"; - -const cache = app.getCache(); -if (cache.has("MasterData")) { - const masterData = cache.get("MasterData"); -} -``` - -### コールバック - -リクエスト完了後にコールバックを実行: - -```json -{ - "home": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/home.json", - "name": "HomeData", - "callback": "callback.HomeDataCallback" - } - ] - } -} -``` - -コールバッククラス: - -```typescript -export class HomeDataCallback -{ - constructor(data: any) - { - // 取得したデータが渡される - } - - execute(): void - { - // コールバック処理 - } -} -``` - -## 画面遷移 - -### app.gotoView() - -`app.gotoView()`で画面遷移を行います: - -```typescript -import { app } from "@next2d/framework"; - -// 基本的な遷移 -await app.gotoView("home"); - -// パスで遷移 -await app.gotoView("quest/list"); - -// クエリパラメータ付き -await app.gotoView("quest/detail?id=123"); -``` - -### UseCaseでの画面遷移 - -画面遷移はUseCaseで行うことを推奨します: - -```typescript -import { app } from "@next2d/framework"; - -export class NavigateToViewUseCase -{ - async execute(viewName: string): Promise - { - await app.gotoView(viewName); - } -} -``` - -ViewModelでの使用: - -```typescript -export class TopViewModel extends ViewModel -{ - private readonly navigateToViewUseCase: NavigateToViewUseCase; - - constructor() - { - super(); - this.navigateToViewUseCase = new NavigateToViewUseCase(); - } - - async onClickStartButton(): Promise - { - await this.navigateToViewUseCase.execute("home"); - } -} -``` - -## レスポンスデータの取得 - -`requests`で取得したデータは`app.getResponse()`で取得できます: - -```typescript -import { app } from "@next2d/framework"; - -async initialize(): Promise -{ - const response = app.getResponse(); - - if (response.has("TopText")) { - const topText = response.get("TopText") as { word: string }; - this.text = topText.word; - } -} -``` - -**注意:** `response`データは画面遷移すると初期化されます。画面を跨いで保持したいデータは`cache: true`を設定してください。 - -## SPAモード - -`config.json`の`all.spa`で設定します: - -```json -{ - "all": { - "spa": true - } -} -``` - -- `true`: URLでシーンを制御(History API使用) -- `false`: URLによるシーン制御を無効化 - -## デフォルトのトップページ - -`config.json`で設定: - -```json -{ - "all": { - "defaultTop": "top" - } -} -``` - -設定がない場合は`TopView`クラスが起動します。 - -## View/ViewModelの自動生成 - -`routing.json`の設定から自動生成できます: - -```bash -npm run generate -``` - -このコマンドは`routing.json`のトッププロパティを解析し、対応するViewとViewModelクラスを生成します。 - -## 設定例 - -### 完全な routing.json の例 - -```json -{ - "top": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/top.json", - "name": "TopText" - } - ] - }, - "home": { - "requests": [ - { - "type": "json", - "path": "{{api.endPoint}}api/home.json", - "name": "HomeData" - }, - { - "type": "content", - "path": "{{content.endPoint}}home.json", - "name": "HomeContent", - "cache": true - } - ] - }, - "quest/list": { - "requests": [ - { - "type": "custom", - "class": "repository.QuestRepository", - "access": "static", - "method": "getList", - "name": "QuestList" - } - ] - }, - "quest/detail": { - "private": true, - "requests": [ - { - "type": "custom", - "class": "repository.QuestRepository", - "access": "static", - "method": "getDetail", - "name": "QuestDetail" - } - ] - } -} -``` - -## 関連項目 - -- [View/ViewModel](#view-と-viewmodel) -- [設定ファイル](#設定ファイル) - ---- - -# View と ViewModel - -Next2D FrameworkはMVVM(Model-View-ViewModel)パターンを採用しています。1画面にViewとViewModelをワンセット作成するのが基本スタイルです。 - -## アーキテクチャ - -```mermaid -graph TB - subgraph ViewLayer["View Layer"] - ViewRole["画面の構造と表示を担当"] - ViewRule["ビジネスロジックは持たない"] - end - - subgraph ViewModelLayer["ViewModel Layer"] - VMRole1["ViewとModelの橋渡し"] - VMRole2["UseCaseを保持"] - VMRole3["イベントハンドリング"] - end - - subgraph ModelLayer["Model Layer"] - ModelRole1["ビジネスロジック(UseCase)"] - ModelRole2["データアクセス(Repository)"] - end - - ViewLayer <-->|双方向| ViewModelLayer - ViewModelLayer <--> ModelLayer -``` - -## ディレクトリ構造 - -``` -src/ -└── view/ - ├── top/ - │ ├── TopView.ts - │ └── TopViewModel.ts - └── home/ - ├── HomeView.ts - └── HomeViewModel.ts -``` - -## View - -Viewはメインコンテキストにアタッチされるコンテナです。Viewは表示構造のみを担当し、ビジネスロジックはViewModelに委譲します。 - -### Viewの責務 - -- **画面の構造定義** - UIコンポーネントの配置と座標設定 -- **イベントリスナーの登録** - ViewModelのメソッドと接続 -- **ライフサイクル管理** - `initialize`, `onEnter`, `onExit` - -### 基本構造 - -```typescript -import type { TopViewModel } from "./TopViewModel"; -import { View } from "@next2d/framework"; -import { TopPage } from "@/ui/component/page/top/TopPage"; - -export class TopView extends View -{ - private readonly _topPage: TopPage; - - constructor(vm: TopViewModel) - { - super(vm); - this._topPage = new TopPage(); - this.addChild(this._topPage); - } - - async initialize(): Promise - { - this._topPage.initialize(this.vm); - } - - async onEnter(): Promise - { - await this._topPage.onEnter(); - } - - async onExit(): Promise - { - return void 0; - } -} -``` - -### ライフサイクル - -```mermaid -sequenceDiagram - participant Framework as Framework - participant VM as ViewModel - participant View as View - participant UI as UI Components - - Note over Framework,UI: 画面遷移開始 - - Framework->>VM: new ViewModel() - Framework->>VM: initialize() - Note over VM: ViewModelが先に初期化される - - Framework->>View: new View(vm) - Framework->>View: initialize() - View->>UI: コンポーネント作成 - View->>VM: イベントリスナー登録 - - Framework->>View: onEnter() - View->>UI: アニメーション開始 - - Note over Framework,UI: ユーザーが画面を操作 - - Framework->>View: onExit() - View->>UI: クリーンアップ -``` - -#### initialize() - 初期化 - -**呼び出しタイミング:** -- Viewのインスタンスが生成された直後 -- 画面遷移時に1回だけ呼び出される -- ViewModelの`initialize()`より**後**に実行される - -**主な用途:** -- UIコンポーネントの生成と配置 -- イベントリスナーの登録 -- 子要素の追加(`addChild`) - -```typescript -async initialize(): Promise -{ - const { HomeBtnMolecule } = await import("@/ui/component/molecule/HomeBtnMolecule"); - const { PointerEvent } = next2d.events; - - const homeContent = new HomeBtnMolecule(); - homeContent.x = 120; - homeContent.y = 120; - - // イベントをViewModelに委譲 - homeContent.addEventListener( - PointerEvent.POINTER_DOWN, - this.vm.homeContentPointerDownEvent - ); - - this.addChild(homeContent); -} -``` - -#### onEnter() - 画面表示時 - -**呼び出しタイミング:** -- `initialize()`の実行完了後 -- 画面が表示される直前 - -**主な用途:** -- 入場アニメーションの開始 -- タイマーやインターバルの開始 -- フォーカス設定 - -```typescript -async onEnter(): Promise -{ - const topBtn = this.getChildByName("topBtn") as TopBtnMolecule; - topBtn.playEntrance(() => { - console.log("アニメーション完了"); - }); -} -``` - -#### onExit() - 画面非表示時 - -**呼び出しタイミング:** -- 別の画面に遷移する直前 -- Viewが破棄される前 - -**主な用途:** -- アニメーションの停止 -- タイマーやインターバルのクリア -- リソースの解放 - -```typescript -async onExit(): Promise -{ - if (this.autoSlideTimer) { - clearInterval(this.autoSlideTimer); - this.autoSlideTimer = null; - } -} -``` - -## ViewModel - -ViewModelはViewとModelの橋渡しを行います。UseCaseを保持し、Viewからのイベントを処理してビジネスロジックを実行します。 - -### ViewModelの責務 - -- **イベント処理** - Viewからのイベントを受け取る -- **UseCaseの実行** - ビジネスロジックを呼び出す -- **依存性の管理** - UseCaseのインスタンスを保持 -- **状態管理** - 画面固有の状態を管理 - -### 基本構造 - -```typescript -import { ViewModel, app } from "@next2d/framework"; -import { NavigateToViewUseCase } from "@/model/application/top/usecase/NavigateToViewUseCase"; - -export class TopViewModel extends ViewModel -{ - private readonly navigateToViewUseCase: NavigateToViewUseCase; - private topText: string = ""; - - constructor() - { - super(); - this.navigateToViewUseCase = new NavigateToViewUseCase(); - } - - async initialize(): Promise - { - // routing.jsonのrequestsで取得したデータを受け取る - const response = app.getResponse(); - this.topText = response.has("TopText") - ? (response.get("TopText") as { word: string }).word - : ""; - } - - getTopText(): string - { - return this.topText; - } - - async onClickStartButton(): Promise - { - await this.navigateToViewUseCase.execute("home"); - } -} -``` - -### ViewModelの初期化タイミング - -**重要: ViewModelの`initialize()`はViewの`initialize()`より前に呼び出されます。** - -``` -1. ViewModel のインスタンス生成 - ↓ -2. ViewModel.initialize() ← ViewModelが先 - ↓ -3. View のインスタンス生成(ViewModelを注入) - ↓ -4. View.initialize() - ↓ -5. View.onEnter() -``` - -これにより、Viewの初期化時にはViewModelのデータが既に準備されています。 - -```typescript -// HomeViewModel.ts -export class HomeViewModel extends ViewModel -{ - private homeText: string = ""; - - async initialize(): Promise - { - // ViewModelのinitializeで事前にデータ取得 - const data = await HomeTextRepository.get(); - this.homeText = data.word; - } - - getHomeText(): string - { - return this.homeText; - } -} - -// HomeView.ts -export class HomeView extends View -{ - constructor(private readonly vm: HomeViewModel) - { - super(); - } - - async initialize(): Promise - { - // この時点でvm.initialize()は既に完了している - const text = this.vm.getHomeText(); - - // 取得済みのデータを使ってUIを構築 - const textField = new TextAtom(text); - this.addChild(textField); - } -} -``` - -## 画面遷移 - -画面遷移には`app.gotoView()`を使用します。 - -```typescript -import { app } from "@next2d/framework"; - -// 指定のViewに遷移 -await app.gotoView("home"); - -// パラメータ付きで遷移 -await app.gotoView("user/detail?id=123"); -``` - -### UseCaseでの画面遷移 - -```typescript -import { app } from "@next2d/framework"; - -export class NavigateToViewUseCase -{ - async execute(viewName: string): Promise - { - await app.gotoView(viewName); - } -} -``` - -## レスポンスデータの取得 - -`routing.json`で設定した`requests`のデータは`app.getResponse()`で取得できます。 - -```typescript -import { app } from "@next2d/framework"; - -async initialize(): Promise -{ - const response = app.getResponse(); - - if (response.has("UserData")) { - const userData = response.get("UserData"); - this.userName = userData.name; - } -} -``` - -## キャッシュデータの取得 - -`cache: true`を設定したデータは`app.getCache()`で取得できます。 - -```typescript -import { app } from "@next2d/framework"; - -const cache = app.getCache(); -if (cache.has("MasterData")) { - const masterData = cache.get("MasterData"); -} -``` - -## 設計原則 - -### 1. 関心の分離 - -```typescript -// 良い例: Viewは表示のみ、ViewModelはロジック -class HomeView extends View -{ - async initialize(): Promise - { - const btn = new HomeBtnMolecule(); - btn.addEventListener(PointerEvent.POINTER_DOWN, this.vm.onClick); - } -} - -class HomeViewModel extends ViewModel -{ - onClick(event: PointerEvent): void - { - this.someUseCase.execute(); - } -} -``` - -### 2. 依存性の逆転 - -ViewModelはインターフェースに依存し、具象クラスに依存しません。 - -```typescript -// 良い例: インターフェースに依存 -homeContentPointerDownEvent(event: PointerEvent): void -{ - const target = event.currentTarget as unknown as IDraggable; - this.startDragUseCase.execute(target); -} -``` - -### 3. イベントは必ずViewModelに委譲 - -View内でイベント処理を完結させず、必ずViewModelに委譲します。 - -## View/ViewModel作成のテンプレート - -### View - -```typescript -import type { YourViewModel } from "./YourViewModel"; -import { View } from "@next2d/framework"; - -export class YourView extends View -{ - constructor(vm: YourViewModel) - { - super(vm); - } - - async initialize(): Promise - { - // UIコンポーネントの作成と配置 - } - - async onEnter(): Promise - { - // 画面表示時の処理 - } - - async onExit(): Promise - { - // 画面非表示時の処理 - } -} -``` - -### ViewModel - -```typescript -import { ViewModel } from "@next2d/framework"; -import { YourUseCase } from "@/model/application/your/usecase/YourUseCase"; - -export class YourViewModel extends ViewModel -{ - private readonly yourUseCase: YourUseCase; - - constructor() - { - super(); - this.yourUseCase = new YourUseCase(); - } - - async initialize(): Promise - { - return void 0; - } - - yourEventHandler(event: Event): void - { - this.yourUseCase.execute(); - } -} -``` - -## 関連項目 - -- [ルーティング](#ルーティング) -- [設定ファイル](#設定ファイル) diff --git a/.github/skills/references/player-specs.md b/.github/skills/references/player-specs.md deleted file mode 100644 index cced772..0000000 --- a/.github/skills/references/player-specs.md +++ /dev/null @@ -1,3292 +0,0 @@ -# Next2D Player - API Reference - -## Table of Contents - -1. [Overview](#next2d-player) -2. [DisplayObject](#displayobject) -3. [Events](#イベントシステム) -4. [MovieClip](#movieclip) -5. [Shape](#shape) -6. [Sound](#サウンド) -7. [Sprite](#sprite) -8. [TextField](#textfield) -9. [Tween](#tweenアニメーション) -10. [Video](#video) -11. [Filters](#フィルター) - ---- - -# Next2D Player - -Next2D Playerは、WebGL/WebGPUを用いた高速2Dレンダリングエンジンです。Flash Playerのような機能をWeb上で実現し、ベクター描画、Tweenアニメーション、テキスト、音声、動画など、さまざまな要素をサポートしています。 - -## 主な特徴 - -- **高速レンダリング**: WebGL/WebGPUを活用した高速2D描画 -- **マルチプラットフォーム**: デスクトップからモバイルまで対応 -- **Flash互換API**: swf2jsから派生した馴染みやすいAPI設計 -- **豊富なフィルター**: Blur、DropShadow、Glow、Bevelなど多数のフィルターをサポート - -## レンダリングパイプライン - -Next2D Playerの高速レンダリングを実現するパイプラインの全体像です。 - -```mermaid -flowchart TB - %% Main Drawing Flow Chart - subgraph MainFlow["描画フローチャート - メインレンダリングパイプライン"] - direction TB - - subgraph Inputs["表示オブジェクト"] - Shape["Shape
(Bitmap/Vector)"] - TextField["TextField
(canvas2d)"] - Video["Video Element"] - end - - Shape --> MaskCheck - TextField --> MaskCheck - Video --> MaskCheck - - MaskCheck{"マスク
レンダリング?"} - - MaskCheck -->|YES| DirectRender["直接レンダリング"] - DirectRender -->|drawArrays| FinalRender - - MaskCheck -->|NO| CacheCheck1{"キャッシュ
あり?"} - - CacheCheck1 -->|NO| TextureAtlas["テクスチャアトラス
(二分木パッキング)"] - TextureAtlas --> Coordinates - - CacheCheck1 -->|YES| Coordinates["座標データベース
(x, y, w, h)"] - - Coordinates --> FilterBlendCheck{"フィルター or
ブレンド?"} - - FilterBlendCheck -->|NO| MainArrays - FilterBlendCheck -->|YES| NeedCache{"キャッシュ
あり?"} - - NeedCache -->|NO| CacheRender["キャッシュにレンダリング"] - CacheRender --> TextureCache - NeedCache -->|YES| TextureCache["テクスチャキャッシュ"] - - TextureCache -->|drawArrays| FinalRender - - MainArrays["インスタンス配列
━━━━━━━━━━━━━━━
matrix
colorTransform
Coordinates
━━━━━━━━━━━━━━━
バッチレンダリング"] - - MainArrays -->|drawArraysInstanced
複数オブジェクトを1回で描画| FinalRender["最終レンダリング"] - - FinalRender -->|60fps| MainFramebuffer["メインフレームバッファ
(ディスプレイ)"] - end - - %% Branch Flow for Filter/Blend/Mask - subgraph BranchFlow["フィルター/ブレンド/マスク - 分岐処理"] - direction TB - - subgraph FilterInputs["表示オブジェクト"] - Shape2["Shape
(Bitmap/Vector)"] - TextField2["TextField
(canvas2d)"] - Video2["Video Element"] - end - - Shape2 --> CacheCheck2 - TextField2 --> CacheCheck2 - Video2 --> CacheCheck2 - - CacheCheck2{"キャッシュ
あり?"} - - CacheCheck2 -->|NO| EffectRender["エフェクトレンダリング"] - CacheCheck2 -->|YES| BranchArrays - EffectRender --> BranchArrays - - BranchArrays["インスタンス配列
━━━━━━━━━━━━━━━
matrix
colorTransform
Coordinates
━━━━━━━━━━━━━━━
バッチレンダリング"] - - BranchArrays -->|drawArraysInstanced
複数オブジェクトを1回で描画| BranchRender["エフェクト結果"] - - BranchRender -->|filter/blend| TextureCache - end - - %% Connections between flows - FilterBlendCheck -.->|"分岐フローを
トリガー"| BranchFlow - BranchArrays -.->|"レンダリング情報
(座標)"| MainArrays -``` - -### パイプラインの特徴 - -- **バッチレンダリング**: 複数のオブジェクトを1回のGPUコールで描画 -- **テクスチャキャッシュ**: フィルターやブレンド効果を効率的に処理 -- **二分木パッキング**: テクスチャアトラスで最適なメモリ使用 -- **60fps描画**: 高フレームレートでのスムーズなアニメーション - -## DisplayListアーキテクチャ - -Next2D Playerは、Flash Playerと同様のDisplayListアーキテクチャを採用しています。 - -### 主要クラス階層 - -``` -DisplayObject (基底クラス) -├── InteractiveObject -│ ├── DisplayObjectContainer -│ │ ├── Sprite -│ │ ├── MovieClip -│ │ └── Stage -│ └── TextField -├── Shape -├── Video -└── Bitmap -``` - -### DisplayObjectContainer - -子オブジェクトを持つことができるコンテナクラス: - -- `addChild(child)`: 子要素を最前面に追加 -- `addChildAt(child, index)`: 指定インデックスに子要素を追加 -- `removeChild(child)`: 子要素を削除 -- `getChildAt(index)`: インデックスから子要素を取得 -- `getChildByName(name)`: 名前から子要素を取得 - -### MovieClip - -タイムラインアニメーションを持つDisplayObject: - -- `play()`: タイムラインを再生 -- `stop()`: タイムラインを停止 -- `gotoAndPlay(frame)`: 指定フレームに移動して再生 -- `gotoAndStop(frame)`: 指定フレームに移動して停止 -- `currentFrame`: 現在のフレーム番号 -- `totalFrames`: 総フレーム数 - -## 基本的な使い方 - -```typescript -const { MovieClip } = next2d.display; -const { DropShadowFilter } = next2d.filters; - -// ルートMovieClipを作成 -const root = await next2d.createRootMovieClip(800, 600, 60, { - tagId: "container", - bgColor: "#ffffff" -}); - -// MovieClipの作成 -const mc = new MovieClip(); -root.addChild(mc); - -// 位置とサイズの設定 -mc.x = 100; -mc.y = 100; -mc.scaleX = 2; -mc.scaleY = 2; -mc.rotation = 45; - -// フィルターの適用 -mc.filters = [ - new DropShadowFilter(4, 45, 0x000000, 0.5) -]; -``` - -## JSONデータの読み込み - -Open Animation Toolで作成したJSONファイルを読み込んで描画: - -```typescript -const { Loader } = next2d.display; -const { URLRequest } = next2d.net; - -const loader = new Loader(); -await loader.load(new URLRequest("animation.json")); - -// 読み込み完了後、直接contentにアクセス -const mc = loader.content; -stage.addChild(mc); -``` - -## 関連ドキュメント - -### 表示オブジェクト -- [DisplayObject](/ja/reference/player/display-object) - 全ての表示オブジェクトの基底クラス -- [MovieClip](/ja/reference/player/movie-clip) - タイムラインアニメーション -- [Sprite](/ja/reference/player/sprite) - グラフィックス描画とインタラクション -- [Shape](/ja/reference/player/shape) - 軽量なベクター描画 -- [TextField](/ja/reference/player/text-field) - テキスト表示と入力 -- [Video](/ja/reference/player/video) - 動画再生 - -### システム -- [イベントシステム](/ja/reference/player/events) - マウス、キーボード、タッチイベント -- [フィルター](/ja/reference/player/filters) - Blur、DropShadow、Glowなど -- [サウンド](/ja/reference/player/sound) - 音声再生とサウンドエフェクト -- [Tweenアニメーション](/ja/reference/player/tween) - プログラムによるアニメーション - - ---- - -# DisplayObject - -DisplayObjectは、Next2D Playerにおける全ての表示オブジェクトの基底クラスです。 - -## プロパティ (Properties) - -### 読み取り専用プロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `instanceId` | number | DisplayObjectのユニークなインスタンスID | -| `isSprite` | boolean | Spriteの機能を所持しているかを返却 | -| `isInteractive` | boolean | InteractiveObjectの機能を所持しているかを返却 | -| `isContainerEnabled` | boolean | コンテナの機能を所持しているかを返却 | -| `isTimelineEnabled` | boolean | MovieClipの機能を所持しているかを返却 | -| `isShape` | boolean | Shapeの機能を所持しているかを返却 | -| `isVideo` | boolean | Videoの機能を所持しているかを返却 | -| `isText` | boolean | Textの機能を所持しているかを返却 | -| `concatenatedMatrix` | Matrix | ルートレベルまでの結合された変換行列 | -| `dropTarget` | DisplayObject \| null | スプライトのドラッグ先またはドロップされた先の表示オブジェクト | -| `loaderInfo` | LoaderInfo \| null | この表示オブジェクトが属するファイルの読み込み情報 | -| `mouseX` | number | 対象のDisplayObjectの基準点からのマウスのX座標(ピクセル) | -| `mouseY` | number | 対象のDisplayObjectの基準点からのマウスのY座標(ピクセル) | -| `root` | MovieClip \| Sprite \| null | DisplayObjectのルートであるDisplayObjectContainer | - -### 読み書きプロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `name` | string | 名前。getChildByName()で使用される(デフォルト: "") | -| `startFrame` | number | 開始フレーム(デフォルト: 1) | -| `endFrame` | number | 終了フレーム(デフォルト: 0) | -| `isMask` | boolean | マスクとしてDisplayObjectにセットされているかを示す(デフォルト: false) | -| `parent` | Sprite \| MovieClip \| null | このDisplayObjectの親のDisplayObjectContainer | -| `alpha` | number | アルファ透明度値(0.0~1.0、デフォルト: 1.0) | -| `blendMode` | string | 使用するブレンドモード(デフォルト: BlendMode.NORMAL) | -| `filters` | Array \| null | 表示オブジェクトに関連付けられている各フィルターオブジェクトの配列 | -| `height` | number | 表示オブジェクトの高さ(ピクセル単位) | -| `width` | number | 表示オブジェクトの幅(ピクセル単位) | -| `colorTransform` | ColorTransform | 表示オブジェクトのColorTransform | -| `matrix` | Matrix | 表示オブジェクトのMatrix | -| `rotation` | number | DisplayObjectインスタンスの回転角度(度単位) | -| `scale9Grid` | Rectangle \| null | 現在有効な拡大/縮小グリッド | -| `scaleX` | number | 基準点から適用されるオブジェクトの水平スケール値 | -| `scaleY` | number | 基準点から適用されるオブジェクトの垂直スケール値 | -| `visible` | boolean | 表示オブジェクトが可視かどうか(デフォルト: true) | -| `x` | number | 親DisplayObjectContainerのローカル座標を基準にしたX座標 | -| `y` | number | 親DisplayObjectContainerのローカル座標を基準にしたY座標 | - -## メソッド (Methods) - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `getBounds(targetDisplayObject)` | Rectangle | 指定したDisplayObjectの座標系を基準にして、表示オブジェクトの領域を定義する矩形を返す | -| `globalToLocal(point)` | Point | pointオブジェクトをステージ(グローバル)座標から表示オブジェクトの(ローカル)座標に変換 | -| `localToGlobal(point)` | Point | pointオブジェクトを表示オブジェクトの(ローカル)座標からステージ(グローバル)座標に変換 | -| `hitTestObject(targetDisplayObject)` | boolean | DisplayObjectの描画範囲を評価して、重複または交差するかどうかを調べる | -| `hitTestPoint(x, y, shapeFlag)` | boolean | 表示オブジェクトを評価して、x および y パラメーターで指定されたポイントと重複または交差するかどうかを調べる | -| `getLocalVariable(key)` | any | クラスのローカル変数空間から値を取得 | -| `setLocalVariable(key, value)` | void | クラスのローカル変数空間へ値を保存 | -| `hasLocalVariable(key)` | boolean | クラスのローカル変数空間に値があるかどうかを判断 | -| `deleteLocalVariable(key)` | void | クラスのローカル変数空間の値を削除 | -| `getGlobalVariable(key)` | any | グローバル変数空間から値を取得 | -| `setGlobalVariable(key, value)` | void | グローバル変数空間へ値を保存 | -| `hasGlobalVariable(key)` | boolean | グローバル変数空間に値があるかどうかを判断 | -| `deleteGlobalVariable(key)` | void | グローバル変数空間の値を削除 | -| `clearGlobalVariable()` | void | グローバル変数空間の値を全てクリア | -| `remove()` | void | 親子関係を解除 | - -## ブレンドモード - -| 定数 | 説明 | -|------|------| -| `BlendMode.NORMAL` | 通常表示 | -| `BlendMode.ADD` | 加算 | -| `BlendMode.MULTIPLY` | 乗算 | -| `BlendMode.SCREEN` | スクリーン | -| `BlendMode.DARKEN` | 暗くする | -| `BlendMode.LIGHTEN` | 明るくする | -| `BlendMode.DIFFERENCE` | 差分 | -| `BlendMode.OVERLAY` | オーバーレイ | -| `BlendMode.HARDLIGHT` | ハードライト | -| `BlendMode.INVERT` | 反転 | -| `BlendMode.ALPHA` | アルファ | -| `BlendMode.ERASE` | 消去 | - -## 使用例 - -```typescript -const { Sprite } = next2d.display; -const { BlurFilter } = next2d.filters; - -const sprite = new Sprite(); - -// 位置とサイズ -sprite.x = 100; -sprite.y = 200; -sprite.scaleX = 1.5; -sprite.scaleY = 1.5; -sprite.rotation = 30; - -// 表示制御 -sprite.alpha = 0.8; -sprite.visible = true; -sprite.blendMode = "add"; - -// フィルター -sprite.filters = [ - new BlurFilter(4, 4) -]; - -// ステージに追加 -stage.addChild(sprite); -``` - -### 座標変換の例 - -```typescript -const { Point } = next2d.geom; - -// グローバル座標をローカル座標に変換 -const globalPoint = new Point(100, 100); -const localPoint = displayObject.globalToLocal(globalPoint); - -// ローカル座標をグローバル座標に変換 -const localPos = new Point(0, 0); -const globalPos = displayObject.localToGlobal(localPos); -``` - -### 衝突判定の例 - -```typescript -// バウンディングボックスで判定 -const hit1 = displayObject.hitTestPoint(100, 100, false); - -// 実際の形状で判定 -const hit2 = displayObject.hitTestPoint(100, 100, true); - -// 他のDisplayObjectとの衝突判定 -if (obj1.hitTestObject(obj2)) { - console.log("衝突しました"); -} -``` - -### 変数操作の例 - -```typescript -// ローカル変数の操作 -displayObject.setLocalVariable("score", 100); -const score = displayObject.getLocalVariable("score"); -if (displayObject.hasLocalVariable("score")) { - displayObject.deleteLocalVariable("score"); -} - -// グローバル変数の操作 -displayObject.setGlobalVariable("gameState", "playing"); -const state = displayObject.getGlobalVariable("gameState"); -displayObject.clearGlobalVariable(); // 全てクリア -``` - -## 関連項目 - -- [MovieClip](/ja/reference/player/movie-clip) -- [Sprite](/ja/reference/player/sprite) - - ---- - -# イベントシステム - -Next2D Playerは、W3C DOMイベントモデルと同様の3フェーズイベントフロー機構を採用しています。 - -## EventDispatcher - -すべてのイベント発行可能なオブジェクトの基底クラスです。 - -### addEventListener(type, listener, useCapture, priority) - -イベントリスナーを登録します。 - -```typescript -const { PointerEvent } = next2d.events; - -displayObject.addEventListener(PointerEvent.POINTER_DOWN, (event) => { - console.log("ポインターが押されました"); -}); - -// キャプチャフェーズで受け取る -displayObject.addEventListener(PointerEvent.POINTER_DOWN, handler, true); - -// 優先度を指定 -displayObject.addEventListener(PointerEvent.POINTER_DOWN, handler, false, 10); -``` - -### removeEventListener(type, listener, useCapture) - -イベントリスナーを削除します。 - -```typescript -displayObject.removeEventListener(PointerEvent.POINTER_DOWN, handler); -``` - -### removeAllEventListener(type, useCapture) - -特定タイプのすべてのイベントリスナーを削除します。 - -```typescript -displayObject.removeAllEventListener(PointerEvent.POINTER_DOWN); -``` - -### hasEventListener(type) - -指定タイプのリスナーが登録されているか確認します。 - -```typescript -if (displayObject.hasEventListener(PointerEvent.POINTER_DOWN)) { - console.log("ポインターダウンリスナーが登録されています"); -} -``` - -### willTrigger(type) - -このオブジェクトまたは祖先がイベントタイプのリスナーを持つか確認します。 - -```typescript -if (displayObject.willTrigger(PointerEvent.POINTER_DOWN)) { - console.log("このオブジェクトまたは祖先にリスナーがあります"); -} -``` - -### dispatchEvent(event) - -イベントを発行します。 - -```typescript -const { Event } = next2d.events; - -const event = new Event("customEvent"); -displayObject.dispatchEvent(event); -``` - -## Event クラス - -### プロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `type` | String | イベントタイプ | -| `target` | Object | イベント発行元 | -| `currentTarget` | Object | 現在のリスナー登録先 | -| `eventPhase` | Number | イベントフェーズ | -| `bubbles` | Boolean | バブリングするか | - -### メソッド - -| メソッド | 説明 | -|----------|------| -| `stopPropagation()` | 伝播を停止 | -| `stopImmediatePropagation()` | 伝播を即座に停止 | - -## 標準イベントタイプ - -### 表示リスト関連 - -| イベント | 説明 | -|----------|------| -| `added` | DisplayObjectContainerに追加された | -| `addedToStage` | Stageに追加された | -| `removed` | DisplayObjectContainerから削除された | -| `removedFromStage` | Stageから削除された | - -```typescript -sprite.addEventListener("addedToStage", (event) => { - console.log("ステージに追加されました"); -}); -``` - -### タイムライン関連 - -| イベント | 説明 | -|----------|------| -| `enterFrame` | 各フレームで発生 | -| `frameConstructed` | フレーム構築完了 | -| `exitFrame` | フレーム離脱時 | - -```typescript -movieClip.addEventListener("enterFrame", (event) => { - // 毎フレーム実行される処理 - updatePosition(); -}); -``` - -### ロード関連 - -| イベント | 説明 | -|----------|------| -| `complete` | ロード完了 | -| `progress` | ロード進捗 | -| `ioError` | IOエラー | -| `httpStatus` | HTTPステータス受信 | - -```typescript -const { Loader } = next2d.display; -const { URLRequest } = next2d.net; - -const loader = new Loader(); - -// async/awaitを使用した読み込み -await loader.load(new URLRequest("animation.json")); -const content = loader.content; -stage.addChild(content); - -// プログレスイベントを使用する場合 -loader.contentLoaderInfo.addEventListener("progress", (event) => { - const percent = (event.bytesLoaded / event.bytesTotal) * 100; - console.log(`${percent}% ロード完了`); -}); -``` - -## ポインターイベント - -PointerEventはマウス、ペン、タッチなどのポインターデバイスの操作を統一的に処理します。 - -| イベント | 定数 | 説明 | -|----------|------|------| -| `pointerDown` | `PointerEvent.POINTER_DOWN` | ボタンの押下開始 | -| `pointerUp` | `PointerEvent.POINTER_UP` | ボタンの解放 | -| `pointerMove` | `PointerEvent.POINTER_MOVE` | ポインター座標の変化 | -| `pointerOver` | `PointerEvent.POINTER_OVER` | ポインターがヒットテスト境界に入った | -| `pointerOut` | `PointerEvent.POINTER_OUT` | ポインターがヒットテスト境界を出た | -| `pointerLeave` | `PointerEvent.POINTER_LEAVE` | ポインターが要素領域を離れた | -| `pointerCancel` | `PointerEvent.POINTER_CANCEL` | ポインター操作がキャンセルされた | -| `doubleClick` | `PointerEvent.DOUBLE_CLICK` | ダブルクリック/タップが発生 | - -```typescript -const { PointerEvent } = next2d.events; - -sprite.addEventListener(PointerEvent.POINTER_DOWN, (event) => { - console.log("ポインターダウン:", event.localX, event.localY); -}); - -sprite.addEventListener(PointerEvent.POINTER_MOVE, (event) => { - console.log("ポインター移動:", event.stageX, event.stageY); -}); - -sprite.addEventListener(PointerEvent.DOUBLE_CLICK, (event) => { - console.log("ダブルクリック"); -}); -``` - -## キーボードイベント - -| イベント | 定数 | 説明 | -|----------|------|------| -| `keyDown` | `KeyboardEvent.KEY_DOWN` | キー押下 | -| `keyUp` | `KeyboardEvent.KEY_UP` | キー解放 | - -```typescript -const { KeyboardEvent } = next2d.events; - -stage.addEventListener(KeyboardEvent.KEY_DOWN, (event) => { - console.log("キーコード:", event.keyCode); - - switch (event.keyCode) { - case 37: // 左矢印 - player.x -= 10; - break; - case 39: // 右矢印 - player.x += 10; - break; - } -}); -``` - -## フォーカスイベント - -| イベント | 定数 | 説明 | -|----------|------|------| -| `focusIn` | `FocusEvent.FOCUS_IN` | フォーカスを受け取った | -| `focusOut` | `FocusEvent.FOCUS_OUT` | フォーカスを失った | - -```typescript -const { FocusEvent } = next2d.events; - -textField.addEventListener(FocusEvent.FOCUS_IN, (event) => { - console.log("フォーカスを受け取りました"); -}); -``` - -## ホイールイベント - -| イベント | 定数 | 説明 | -|----------|------|------| -| `wheel` | `WheelEvent.WHEEL` | マウスホイールが回転した | - -```typescript -const { WheelEvent } = next2d.events; - -stage.addEventListener(WheelEvent.WHEEL, (event) => { - console.log("ホイール回転"); -}); -``` - -## ビデオイベント - -| イベント | 定数 | 説明 | -|----------|------|------| -| `play` | `VideoEvent.PLAY` | 再生がリクエストされた | -| `playing` | `VideoEvent.PLAYING` | 再生が開始された | -| `pause` | `VideoEvent.PAUSE` | 一時停止された | -| `seek` | `VideoEvent.SEEK` | シーク操作 | - -## ジョブイベント - -Tweenアニメーション用のイベントです。 - -| イベント | 定数 | 説明 | -|----------|------|------| -| `update` | `JobEvent.UPDATE` | プロパティが更新された | -| `stop` | `JobEvent.STOP` | ジョブが停止した | - -## カスタムイベント - -```typescript -const { Event } = next2d.events; - -// カスタムイベントの定義 -const customEvent = new Event("gameOver", true, true); - -// イベントの発行 -gameManager.dispatchEvent(customEvent); - -// イベントのリッスン -gameManager.addEventListener("gameOver", (event) => { - showGameOverScreen(); -}); -``` - -## イベントの伝播 - -イベントは3つのフェーズで伝播します: - -1. **キャプチャフェーズ**: rootからtargetへ(eventPhase = 1) -2. **ターゲットフェーズ**: targetで処理(eventPhase = 2) -3. **バブリングフェーズ**: targetからrootへ(eventPhase = 3) - -```typescript -const { PointerEvent } = next2d.events; - -// キャプチャフェーズで処理 -parent.addEventListener(PointerEvent.POINTER_DOWN, handler, true); - -// バブリングフェーズで処理(デフォルト) -child.addEventListener(PointerEvent.POINTER_DOWN, handler, false); -``` - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [MovieClip](/ja/reference/player/movie-clip) - - ---- - -# MovieClip - -MovieClipは、タイムラインアニメーションを持つDisplayObjectContainerです。Open Animation Toolで作成したアニメーションはMovieClipとして再生されます。 - -## 継承関係 - -```mermaid -classDiagram - DisplayObject <|-- InteractiveObject - InteractiveObject <|-- DisplayObjectContainer - DisplayObjectContainer <|-- Sprite - Sprite <|-- MovieClip - - class DisplayObject { - +x: Number - +y: Number - +visible: Boolean - } - class MovieClip { - +currentFrame: Number - +totalFrames: Number - +play() - +stop() - +gotoAndPlay() - } -``` - -## プロパティ - -### MovieClip固有のプロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `currentFrame` | `number` | MovieClipのタイムライン内の再生ヘッドが置かれているフレームの番号(1から開始、読み取り専用) | -| `totalFrames` | `number` | MovieClipインスタンス内のフレーム総数(読み取り専用) | -| `currentFrameLabel` | `FrameLabel \| null` | MovieClipインスタンスのタイムライン内の現在のフレームにあるラベル(読み取り専用) | -| `currentLabels` | `FrameLabel[] \| null` | 現在のシーンのFrameLabelオブジェクトの配列を返す(読み取り専用) | -| `isPlaying` | `boolean` | ムービークリップが現在再生されているかどうかを示すブール値(読み取り専用) | -| `isTimelineEnabled` | `boolean` | MovieClipの機能を所持しているかを返却(読み取り専用) | - -### DisplayObjectContainerから継承したプロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `numChildren` | `number` | このオブジェクトの子の数を返す(読み取り専用) | -| `mouseChildren` | `boolean` | オブジェクトの子がマウスまたはユーザー入力デバイスに対応しているかどうかを判断する | -| `mask` | `DisplayObject \| null` | 呼び出し元の表示オブジェクトをマスクする指定されたマスクオブジェクト | -| `isContainerEnabled` | `boolean` | コンテナの機能を所持しているかを返却(読み取り専用) | - -## メソッド - -### MovieClip固有のメソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `play()` | `void` | ムービークリップのタイムライン内で再生ヘッドを移動する | -| `stop()` | `void` | ムービークリップ内の再生ヘッドを停止する | -| `gotoAndPlay(frame: string \| number)` | `void` | 指定されたフレームで再生を開始する | -| `gotoAndStop(frame: string \| number)` | `void` | 指定されたフレームに再生ヘッドを送り、そこで停止させる | -| `nextFrame()` | `void` | 次のフレームに再生ヘッドを送り、停止する | -| `prevFrame()` | `void` | 直前のフレームに再生ヘッドを戻し、停止する | -| `addFrameLabel(frame_label: FrameLabel)` | `void` | タイムラインに対して動的にLabelを追加する | - -### DisplayObjectContainerから継承したメソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `addChild(display_object: DisplayObject)` | `DisplayObject` | このDisplayObjectContainerインスタンスに子DisplayObjectインスタンスを追加する | -| `addChildAt(display_object: DisplayObject, index: number)` | `DisplayObject` | 指定したインデックス位置に子DisplayObjectインスタンスを追加する | -| `removeChild(display_object: DisplayObject)` | `void` | 子リストから指定のDisplayObjectインスタンスを削除する | -| `removeChildAt(index: number)` | `void` | 子リストの指定されたインデックス位置から子DisplayObjectを削除する | -| `removeChildren(...indexes: number[])` | `void` | 配列で指定されたインデックスの子をコンテナから削除する | -| `getChildAt(index: number)` | `DisplayObject \| null` | 指定のインデックス位置にある子表示オブジェクトインスタンスを返す | -| `getChildByName(name: string)` | `DisplayObject \| null` | 指定された名前に一致する子表示オブジェクトを返す | -| `getChildIndex(display_object: DisplayObject)` | `number` | 子DisplayObjectインスタンスのインデックス位置を返す | -| `contains(display_object: DisplayObject)` | `boolean` | 指定されたDisplayObjectがインスタンスの子孫か、インスタンス自体かを指定する | -| `setChildIndex(display_object: DisplayObject, index: number)` | `void` | 表示オブジェクトコンテナの既存の子の位置を変更する | -| `swapChildren(display_object1: DisplayObject, display_object2: DisplayObject)` | `void` | 指定された2つの子オブジェクトのz順序(重ね順)を入れ替える | -| `swapChildrenAt(index1: number, index2: number)` | `void` | 指定されたインデックス位置に該当する2つの子オブジェクトのz順序を入れ替える | - -## イベント - -### enterFrame - -各フレームで発生するイベント: - -```typescript -movieClip.addEventListener("enterFrame", (event) => { - console.log("フレーム:", movieClip.currentFrame); -}); -``` - -### frameConstructed - -フレームの構築が完了したときに発生: - -```typescript -movieClip.addEventListener("frameConstructed", (event) => { - // フレームスクリプトの実行前 -}); -``` - -### exitFrame - -フレームを離れるときに発生: - -```typescript -movieClip.addEventListener("exitFrame", (event) => { - // 次のフレームへ移動する前 -}); -``` - -## 使用例 - -### 基本的なアニメーション制御 - -```typescript -const { Loader, Sprite } = next2d.display; -const { PointerEvent } = next2d.events; -const { URLRequest } = next2d.net; - -// JSONからMovieClipを読み込み -const loader = new Loader(); -await loader.load(new URLRequest("animation.json")); - -const mc = loader.content; -stage.addChild(mc); - -// 最初は停止 -mc.stop(); - -// ボタンクリックで再生 -button.addEventListener(PointerEvent.POINTER_DOWN, () => { - if (mc.isPlaying) { - mc.stop(); - } else { - mc.play(); - } -}); -``` - -### フレームラベルを使った制御 - -```typescript -// ラベル位置に移動 -mc.gotoAndStop("idle"); - -// 状態変更 -function changeState(state) { - switch (state) { - case "idle": - mc.gotoAndPlay("idle"); - break; - case "walk": - mc.gotoAndPlay("walk_start"); - break; - case "attack": - mc.gotoAndPlay("attack"); - break; - } -} -``` - -### ネストしたMovieClipの制御 - -```typescript -// 子MovieClipへのアクセス -const childMc = mc.getChildByName("character"); -childMc.gotoAndPlay("run"); - -// 孫MovieClipへのアクセス -const grandChild = mc.character.arm; -grandChild.play(); -``` - -### 子オブジェクトの操作 - -```typescript -// 子オブジェクトを追加 -const sprite = new Sprite(); -mc.addChild(sprite); - -// 特定のインデックスに追加 -mc.addChildAt(sprite, 0); - -// 子オブジェクトを削除 -mc.removeChild(sprite); - -// インデックスで削除 -mc.removeChildAt(0); - -// 複数の子を削除 -mc.removeChildren(0, 1, 2); - -// 子オブジェクトの取得 -const child = mc.getChildAt(0); -const namedChild = mc.getChildByName("myChild"); - -// 子のインデックスを取得 -const index = mc.getChildIndex(sprite); - -// 子のインデックスを変更 -mc.setChildIndex(sprite, 2); - -// 子の順序を入れ替え -mc.swapChildren(sprite1, sprite2); -mc.swapChildrenAt(0, 1); -``` - -### フレームラベルの動的追加 - -```typescript -const { FrameLabel } = next2d.display; - -// 新しいラベルを作成して追加 -const label = new FrameLabel("myLabel", 10); -mc.addFrameLabel(label); - -// ラベルを使って移動 -mc.gotoAndPlay("myLabel"); -``` - -### フレームレートの変更 - -```typescript -// ステージ全体のフレームレートを変更 -stage.frameRate = 30; -``` - -## FrameLabel - -フレームラベルの情報を持つクラス: - -```typescript -// 現在のシーンのすべてのラベルを取得 -const labels = mc.currentLabels; -labels.forEach((label) => { - console.log(`${label.name}: フレーム ${label.frame}`); -}); -``` - -## 関連項目 - -- [Sprite](/ja/reference/player/sprite) -- [イベントシステム](/ja/reference/player/events) - - ---- - -# Shape - -Shapeは、ベクターグラフィックスの描画専用クラスです。Spriteと異なり子オブジェクトを持てませんが、軽量でパフォーマンスに優れています。 - -## 継承関係 - -```mermaid -classDiagram - DisplayObject <|-- Shape - - class Shape { - +graphics: Graphics - } -``` - -## プロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `graphics` | Graphics | この Shape オブジェクトに描画されるベクターの描画コマンドを保持する Graphics オブジェクト(読み取り専用) | -| `isShape` | boolean | Shapeの機能を所持しているかを返却(読み取り専用) | -| `cacheKey` | number | ビルドされたキャッシュキー | -| `cacheParams` | number[] | キャッシュのビルドに利用されるパラメータ(読み取り専用) | -| `isBitmap` | boolean | ビットマップ描画の判定フラグ | -| `src` | string | 指定されたパスから画像を読み込み、Graphicsを生成する | -| `bitmapData` | BitmapData | ビットマップデータを返却(読み取り専用) | -| `namespace` | string | 指定されたオブジェクトの空間名を返却(読み取り専用) | - -## メソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `load(url: string)` | Promise\ | 指定されたURLから画像を非同期で読み込み、Graphicsを生成する | -| `clearBitmapBuffer()` | void | ビットマップデータを解放する | -| `setBitmapBuffer(width: number, height: number, buffer: Uint8Array)` | void | RGBAの画像データを設定する | - -## SpriteとShapeの違い - -| 特徴 | Shape | Sprite | -|------|-------|--------| -| 子オブジェクト | 持てない | 持てる | -| インタラクション | なし | クリック等可能 | -| パフォーマンス | 軽量 | やや重い | -| 用途 | 静的な背景、装飾 | ボタン、コンテナ | - -## 使用例 - -### 基本的な描画 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); - -// 塗りつぶし矩形 -shape.graphics.beginFill(0x3498db); -shape.graphics.drawRect(0, 0, 150, 100); -shape.graphics.endFill(); - -stage.addChild(shape); -``` - -### 複合図形の描画 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -const g = shape.graphics; - -// 背景 -g.beginFill(0xecf0f1); -g.drawRoundRect(0, 0, 200, 150, 10, 10); -g.endFill(); - -// 枠線 -g.lineStyle(2, 0x2c3e50); -g.drawRoundRect(0, 0, 200, 150, 10, 10); - -// 内側の装飾 -g.beginFill(0xe74c3c); -g.drawCircle(100, 75, 30); -g.endFill(); - -stage.addChild(shape); -``` - -### パスの描画 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -const g = shape.graphics; - -g.beginFill(0x9b59b6); - -// 星形を描画 -g.moveTo(50, 0); -g.lineTo(61, 35); -g.lineTo(98, 35); -g.lineTo(68, 57); -g.lineTo(79, 91); -g.lineTo(50, 70); -g.lineTo(21, 91); -g.lineTo(32, 57); -g.lineTo(2, 35); -g.lineTo(39, 35); -g.lineTo(50, 0); - -g.endFill(); - -stage.addChild(shape); -``` - -### ベジェ曲線 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -const g = shape.graphics; - -g.lineStyle(3, 0x1abc9c); - -// 二次ベジェ曲線 -g.moveTo(0, 100); -g.curveTo(50, 0, 100, 100); // 制御点, 終点 - -g.curveTo(150, 200, 200, 100); - -stage.addChild(shape); -``` - -### グラデーション背景 - -```typescript -const { Shape } = next2d.display; -const { Matrix } = next2d.geom; - -const shape = new Shape(); -const g = shape.graphics; - -// グラデーション用マトリックス -const matrix = new Matrix(); -matrix.createGradientBox( - stage.stageWidth, - stage.stageHeight, - Math.PI / 2, // 90度(縦方向) - 0, 0 -); - -// 放射状グラデーション -g.beginGradientFill( - "radial", - [0x667eea, 0x764ba2], - [1, 1], - [0, 255], - matrix -); -g.drawRect(0, 0, stage.stageWidth, stage.stageHeight); -g.endFill(); - -// 最背面に配置 -stage.addChildAt(shape, 0); -``` - -### 動的な再描画 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -stage.addChild(shape); - -let angle = 0; - -// フレームごとに再描画 -stage.addEventListener("enterFrame", () => { - const g = shape.graphics; - - // 前の描画をクリア - g.clear(); - - // 新しい位置に描画 - const x = 200 + Math.cos(angle) * 100; - const y = 150 + Math.sin(angle) * 100; - - g.beginFill(0xe74c3c); - g.drawCircle(x, y, 20); - g.endFill(); - - angle += 0.05; -}); -``` - -### 複数のShapeで構成 - -```typescript -const { Shape } = next2d.display; - -// 背景レイヤー -const bgShape = new Shape(); -bgShape.graphics.beginFill(0x2c3e50); -bgShape.graphics.drawRect(0, 0, 400, 300); -bgShape.graphics.endFill(); - -// 装飾レイヤー -const decorShape = new Shape(); -decorShape.graphics.beginFill(0x3498db, 0.5); -decorShape.graphics.drawCircle(100, 100, 80); -decorShape.graphics.drawCircle(300, 200, 60); -decorShape.graphics.endFill(); - -// 前面レイヤー -const frontShape = new Shape(); -frontShape.graphics.lineStyle(2, 0xecf0f1); -frontShape.graphics.drawRect(50, 50, 300, 200); - -stage.addChild(bgShape); -stage.addChild(decorShape); -stage.addChild(frontShape); -``` - -## パフォーマンスのヒント - -1. **静的な描画にはShapeを使用**: インタラクションが不要な背景や装飾にはShapeが最適 -2. **描画の最小化**: 頻繁に変更されない場合は一度だけ描画 -3. **clear()の使用**: 動的な再描画時は必ずclear()を呼ぶ -4. **複雑な図形はキャッシュ**: cacheAsBitmapプロパティで描画をキャッシュ - -```typescript -// 複雑な図形をビットマップとしてキャッシュ -shape.cacheAsBitmap = true; -``` - -## Graphics クラス - -Graphicsクラスは、ベクターグラフィックスを描画するための描画APIを提供します。Shape.graphicsプロパティを通じてアクセスします。 - -### 塗りつぶしメソッド - -| メソッド | 説明 | -|---------|------| -| `beginFill(color: number, alpha?: number)` | 単色の塗りつぶしを開始。alphaのデフォルトは1 | -| `beginGradientFill(type, colors, alphas, ratios, matrix?, spreadMethod?, interpolationMethod?, focalPointRatio?)` | グラデーション塗りつぶしを開始 | -| `beginBitmapFill(bitmapData, matrix?, repeat?, smooth?)` | ビットマップ塗りつぶしを開始 | -| `endFill()` | 塗りつぶしを終了 | - -#### beginGradientFill パラメータ - -| パラメータ | 型 | 説明 | -|-----------|------|------| -| `type` | string | "linear" または "radial" | -| `colors` | number[] | 色の配列(16進数) | -| `alphas` | number[] | 各色の透明度(0-1) | -| `ratios` | number[] | 各色の位置(0-255) | -| `matrix` | Matrix | グラデーションの変形マトリックス | -| `spreadMethod` | string | "pad", "reflect", "repeat"(デフォルト: "pad") | -| `interpolationMethod` | string | "rgb" または "linearRGB"(デフォルト: "rgb") | -| `focalPointRatio` | number | 放射状グラデーションの焦点位置(-1 to 1) | - -### 線スタイルメソッド - -| メソッド | 説明 | -|---------|------| -| `lineStyle(thickness?, color?, alpha?, pixelHinting?, scaleMode?, caps?, joints?, miterLimit?)` | 線のスタイルを設定 | -| `lineGradientStyle(type, colors, alphas, ratios, matrix?, spreadMethod?, interpolationMethod?, focalPointRatio?)` | グラデーション線スタイルを設定 | -| `lineBitmapStyle(bitmapData, matrix?, repeat?, smooth?)` | ビットマップ線スタイルを設定 | -| `endLine()` | 線スタイルを終了 | - -#### lineStyle パラメータ - -| パラメータ | 型 | デフォルト | 説明 | -|-----------|------|---------|------| -| `thickness` | number | 0 | 線の太さ(ピクセル) | -| `color` | number | 0 | 線の色(16進数) | -| `alpha` | number | 1 | 透明度(0-1) | -| `pixelHinting` | boolean | false | ピクセルスナップ | -| `scaleMode` | string | "normal" | "normal", "none", "vertical", "horizontal" | -| `caps` | string | null | "none", "round", "square" | -| `joints` | string | null | "bevel", "miter", "round" | -| `miterLimit` | number | 3 | マイター結合の限界値 | - -### パスメソッド - -| メソッド | 説明 | -|---------|------| -| `moveTo(x: number, y: number)` | 描画位置を移動 | -| `lineTo(x: number, y: number)` | 現在位置から指定座標まで直線を描画 | -| `curveTo(controlX, controlY, anchorX, anchorY)` | 二次ベジェ曲線を描画 | -| `cubicCurveTo(controlX1, controlY1, controlX2, controlY2, anchorX, anchorY)` | 三次ベジェ曲線を描画 | - -### 図形メソッド - -| メソッド | 説明 | -|---------|------| -| `drawRect(x, y, width, height)` | 矩形を描画 | -| `drawRoundRect(x, y, width, height, ellipseWidth, ellipseHeight?)` | 角丸矩形を描画 | -| `drawCircle(x, y, radius)` | 円を描画 | -| `drawEllipse(x, y, width, height)` | 楕円を描画 | - -### ユーティリティメソッド - -| メソッド | 説明 | -|---------|------| -| `clear()` | すべての描画コマンドをクリア | -| `clone()` | Graphicsオブジェクトを複製 | -| `copyFrom(source: Graphics)` | 別のGraphicsから描画コマンドをコピー | - -### 詳細な使用例 - -#### 線形グラデーション - -```typescript -const { Shape } = next2d.display; -const { Matrix } = next2d.geom; - -const shape = new Shape(); -const g = shape.graphics; - -const matrix = new Matrix(); -matrix.createGradientBox(200, 100, 0, 0, 0); // 幅, 高さ, 回転, x, y - -g.beginGradientFill( - "linear", // タイプ - [0xff0000, 0x00ff00, 0x0000ff], // 色 - [1, 1, 1], // 透明度 - [0, 127, 255], // 比率 - matrix -); -g.drawRect(0, 0, 200, 100); -g.endFill(); - -stage.addChild(shape); -``` - -#### 三次ベジェ曲線 - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -const g = shape.graphics; - -g.lineStyle(2, 0x3498db); - -// 滑らかなS字曲線 -g.moveTo(0, 100); -g.cubicCurveTo( - 50, 0, // 制御点1 - 150, 200, // 制御点2 - 200, 100 // 終点 -); - -stage.addChild(shape); -``` - -#### ビットマップ塗りつぶし - -```typescript -const { Shape } = next2d.display; - -// Shapeのload()メソッドで画像を読み込み -const textureShape = new Shape(); -await textureShape.load("texture.png"); - -// 読み込んだbitmapDataを使ってビットマップ塗りつぶし -const shape = new Shape(); -const g = shape.graphics; - -g.beginBitmapFill(textureShape.bitmapData, null, true, true); -g.drawRect(0, 0, 400, 300); -g.endFill(); - -stage.addChild(shape); -``` - -#### グラデーション線 - -```typescript -const { Shape } = next2d.display; -const { Matrix } = next2d.geom; - -const shape = new Shape(); -const g = shape.graphics; - -const matrix = new Matrix(); -matrix.createGradientBox(200, 200, 0, 0, 0); - -g.lineGradientStyle( - "linear", - [0xff0000, 0x0000ff], - [1, 1], - [0, 255], - matrix -); -g.lineStyle(5); - -g.moveTo(10, 10); -g.lineTo(190, 10); -g.lineTo(190, 190); -g.lineTo(10, 190); -g.lineTo(10, 10); - -stage.addChild(shape); -``` - -#### 複雑な図形の組み合わせ - -```typescript -const { Shape } = next2d.display; - -const shape = new Shape(); -const g = shape.graphics; - -// 外側の矩形(塗りつぶし) -g.beginFill(0x2c3e50); -g.drawRoundRect(0, 0, 200, 150, 15, 15); -g.endFill(); - -// 内側の円(別の色で塗りつぶし) -g.beginFill(0xe74c3c); -g.drawCircle(100, 75, 40); -g.endFill(); - -// 装飾線 -g.lineStyle(2, 0xecf0f1); -g.moveTo(20, 20); -g.lineTo(180, 20); -g.moveTo(20, 130); -g.lineTo(180, 130); - -stage.addChild(shape); -``` - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [Sprite](/ja/reference/player/sprite) -- [フィルター](/ja/reference/player/filters) - - ---- - -# サウンド - -Next2D Playerは、ゲームやアプリケーションで必要な音声機能を提供します。BGM、効果音、ボイスなど様々な用途に対応しています。 - -## クラス構成 - -```mermaid -classDiagram - EventDispatcher <|-- Sound - class Sound { - +audioBuffer: AudioBuffer - +volume: Number - +loopCount: Number - +load(request): Promise - +play(startTime): void - +stop(): void - +clone(): Sound - } - class SoundMixer { - +volume: Number - +stopAll(): void - } -``` - -## Sound - -音声ファイルを読み込み再生するクラスです。EventDispatcherを継承しています。 - -### プロパティ - -| プロパティ | 型 | デフォルト | 読み取り専用 | 説明 | -|-----------|------|----------|:------------:|------| -| `audioBuffer` | AudioBuffer \| null | null | - | オーディオバッファ。load()で読み込んだ音声データが格納されます | -| `loopCount` | number | 0 | - | ループ回数の設定。0でループなし、9999で実質無限ループ | -| `volume` | number | 1 | - | ボリューム。範囲は0(無音)〜1(フルボリューム)。SoundMixer.volumeの値を超えることはできません | -| `canLoop` | boolean | - | ○ | サウンドがループするかどうかを示します | - -### メソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `clone()` | Sound | Soundクラスを複製します。volume、loopCount、audioBufferがコピーされます | -| `load(request: URLRequest)` | Promise\ | 指定したURLから外部MP3ファイルのロードを開始します | -| `play(startTime: number = 0)` | void | サウンドを再生します。startTimeは再生開始時間(秒単位)です。既に再生中の場合は何もしません | -| `stop()` | void | チャンネルで再生しているサウンドを停止します | - -## 使用例 - -### 基本的な音声再生 - -```typescript -const { Sound } = next2d.media; -const { URLRequest } = next2d.net; - -// Soundオブジェクトを作成 -const sound = new Sound(); - -// 音声ファイルを非同期で読み込み -const request = new URLRequest("bgm.mp3"); -await sound.load(request); - -// 再生開始 -sound.play(); -``` - -### 効果音の再生 - -```typescript -const { Sound } = next2d.media; -const { URLRequest } = next2d.net; - -// 効果音をプリロード -const seJump = new Sound(); -const seHit = new Sound(); -const seCoin = new Sound(); - -// 読み込み -await seJump.load(new URLRequest("se/jump.mp3")); -await seHit.load(new URLRequest("se/hit.mp3")); -await seCoin.load(new URLRequest("se/coin.mp3")); - -// 再生関数 -function playSE(sound) { - // 複製して再生(同時に複数回鳴らす場合) - const clone = sound.clone(); - clone.play(); -} - -// ゲーム中で使用 -player.addEventListener("jump", () => { - playSE(seJump); -}); -``` - -### BGMのループ再生 - -```typescript -const { Sound } = next2d.media; -const { URLRequest } = next2d.net; - -const bgm = new Sound(); - -// 読み込み -await bgm.load(new URLRequest("bgm/stage1.mp3")); - -// 音量を設定 -bgm.volume = 0.7; // 70% - -// ループ回数を設定(9999で実質無限ループ) -bgm.loopCount = 9999; - -// 再生 -bgm.play(); - -// BGM停止 -function stopBGM() { - bgm.stop(); -} -``` - -### 音量コントロール - -```typescript -const { Sound } = next2d.media; -const { URLRequest } = next2d.net; - -const bgm = new Sound(); -await bgm.load(new URLRequest("bgm.mp3")); - -// 音量を設定 -bgm.volume = 1.0; -bgm.play(); - -// 音量を変更 -function setVolume(volume) { - bgm.volume = Math.max(0, Math.min(1, volume)); -} - -// フェードアウト -async function fadeOut(duration = 1000) { - const startVolume = bgm.volume; - const startTime = Date.now(); - - return new Promise((resolve) => { - const fade = () => { - const elapsed = Date.now() - startTime; - const progress = Math.min(1, elapsed / duration); - - bgm.volume = startVolume * (1 - progress); - - if (progress >= 1) { - bgm.stop(); - resolve(); - } else { - requestAnimationFrame(fade); - } - }; - fade(); - }); -} -``` - -### サウンドマネージャー - -```typescript -const { Sound, SoundMixer } = next2d.media; -const { URLRequest } = next2d.net; - -class SoundManager { - constructor() { - this._sounds = new Map(); - this._bgm = null; - this._bgmVolume = 0.7; - this._seVolume = 1.0; - this._isMuted = false; - } - - // サウンドをプリロード - async preload(id, url) { - const sound = new Sound(); - await sound.load(new URLRequest(url)); - this._sounds.set(id, sound); - } - - // BGM再生 - playBGM(id, loops = 9999) { - this.stopBGM(); - - const sound = this._sounds.get(id); - if (sound) { - this._bgm = sound.clone(); - this._bgm.volume = this._isMuted ? 0 : this._bgmVolume; - this._bgm.loopCount = loops; - this._bgm.play(); - } - } - - // BGM停止 - stopBGM() { - if (this._bgm) { - this._bgm.stop(); - this._bgm = null; - } - } - - // SE再生 - playSE(id) { - const sound = this._sounds.get(id); - if (sound) { - const clone = sound.clone(); - clone.volume = this._isMuted ? 0 : this._seVolume; - clone.play(); - } - } - - // ミュート切り替え - toggleMute() { - this._isMuted = !this._isMuted; - if (this._bgm) { - this._bgm.volume = this._isMuted ? 0 : this._bgmVolume; - } - return this._isMuted; - } - - // BGM音量設定 - setBGMVolume(volume) { - this._bgmVolume = Math.max(0, Math.min(1, volume)); - if (this._bgm && !this._isMuted) { - this._bgm.volume = this._bgmVolume; - } - } - - // SE音量設定 - setSEVolume(volume) { - this._seVolume = Math.max(0, Math.min(1, volume)); - } -} - -// 使用例 -const soundManager = new SoundManager(); - -// 起動時にプリロード -async function initSounds() { - await soundManager.preload("bgm_title", "bgm/title.mp3"); - await soundManager.preload("bgm_stage1", "bgm/stage1.mp3"); - await soundManager.preload("se_jump", "se/jump.mp3"); - await soundManager.preload("se_coin", "se/coin.mp3"); - await soundManager.preload("se_damage", "se/damage.mp3"); -} - -// ゲーム中 -soundManager.playBGM("bgm_stage1"); -soundManager.playSE("se_jump"); -``` - -## SoundMixer - -全体のサウンドを制御するクラスです。 - -```typescript -const { SoundMixer } = next2d.media; - -// 全ての音声を停止 -SoundMixer.stopAll(); - -// 全体の音量を変更 -SoundMixer.volume = 0.5; // 50% -``` - -## サポートフォーマット - -| フォーマット | 拡張子 | 対応状況 | -|--------------|--------|----------| -| MP3 | .mp3 | 推奨 | -| AAC | .m4a, .aac | 対応 | -| Ogg Vorbis | .ogg | ブラウザ依存 | -| WAV | .wav | 対応(ファイルサイズ大) | - -## ベストプラクティス - -1. **プリロード**: ゲーム開始前に全ての音声をプリロード -2. **フォーマット**: MP3を推奨(互換性と圧縮率のバランス) -3. **効果音**: 短い音声はWAVでも可(レイテンシが低い) -4. **音量管理**: BGMとSEの音量を別々に管理 -5. **モバイル対応**: ユーザーインタラクション後に再生開始 -6. **clone使用**: 同じ音を同時に複数回再生する場合はclone()を使用 - -## 関連項目 - -- [イベントシステム](/ja/reference/player/events) - - ---- - -# Sprite - -SpriteはDisplayObjectContainerです。MovieClipの基底クラスであり、タイムラインを持たない動的なオブジェクト管理に使用します。 - -## 継承関係 - -```mermaid -classDiagram - DisplayObject <|-- InteractiveObject - InteractiveObject <|-- DisplayObjectContainer - DisplayObjectContainer <|-- Sprite - Sprite <|-- MovieClip - - class Sprite { - +buttonMode: Boolean - +useHandCursor: Boolean - } -``` - -## プロパティ - -### Sprite固有のプロパティ - -| プロパティ | 型 | 読取専用 | デフォルト | 説明 | -|-----------|------|:--------:|------------|------| -| `isSprite` | boolean | Yes | true | Spriteの機能を所持しているかを返却 | -| `buttonMode` | boolean | No | false | このスプライトのボタンモードを指定します | -| `useHandCursor` | boolean | No | true | buttonModeがtrueの場合にハンドカーソルを表示するかどうか | -| `hitArea` | Sprite \| null | No | null | スプライトのヒット領域となる別のスプライトを指定します | -| `soundTransform` | SoundTransform \| null | No | null | このスプライト内のサウンドを制御します | - -### DisplayObjectContainerから継承されるプロパティ - -| プロパティ | 型 | 読取専用 | デフォルト | 説明 | -|-----------|------|:--------:|------------|------| -| `isContainerEnabled` | boolean | Yes | true | コンテナの機能を所持しているかを返却 | -| `mouseChildren` | boolean | No | true | オブジェクトの子がマウスまたはユーザー入力デバイスに対応しているかどうか | -| `numChildren` | number | Yes | - | このオブジェクトの子の数を返します | -| `mask` | DisplayObject \| null | No | null | 表示オブジェクトをマスクします | - -### InteractiveObjectから継承されるプロパティ - -| プロパティ | 型 | 読取専用 | デフォルト | 説明 | -|-----------|------|:--------:|------------|------| -| `isInteractive` | boolean | Yes | true | InteractiveObjectの機能を所持しているかを返却 | -| `mouseEnabled` | boolean | No | true | このオブジェクトでマウスまたはその他のユーザー入力メッセージを受け取るかどうか | - -### DisplayObjectから継承されるプロパティ - -| プロパティ | 型 | 読取専用 | デフォルト | 説明 | -|-----------|------|:--------:|------------|------| -| `instanceId` | number | Yes | - | DisplayObjectのユニークなインスタンスID | -| `name` | string | No | "" | 名前を返却します。getChildByName()で使用されます | -| `parent` | Sprite \| MovieClip \| null | No | null | このDisplayObjectの親のDisplayObjectContainerを返却 | -| `x` | number | No | 0 | 親DisplayObjectContainerのローカル座標を基準にしたx座標 | -| `y` | number | No | 0 | 親DisplayObjectContainerのローカル座標を基準にしたy座標 | -| `width` | number | No | - | 表示オブジェクトの幅(ピクセル単位) | -| `height` | number | No | - | 表示オブジェクトの高さ(ピクセル単位) | -| `scaleX` | number | No | 1 | 基準点から適用されるオブジェクトの水平スケール値 | -| `scaleY` | number | No | 1 | 基準点から適用されるオブジェクトの垂直スケール値 | -| `rotation` | number | No | 0 | DisplayObjectインスタンスの元の位置からの回転角(度単位) | -| `alpha` | number | No | 1 | 指定されたオブジェクトのアルファ透明度値(0.0〜1.0) | -| `visible` | boolean | No | true | 表示オブジェクトが可視かどうか | -| `blendMode` | string | No | "normal" | 使用するブレンドモードを指定するBlendModeクラスの値 | -| `filters` | array \| null | No | null | 表示オブジェクトに関連付けられた各フィルターオブジェクトの配列 | -| `matrix` | Matrix | No | - | 表示オブジェクトのMatrixを返します | -| `colorTransform` | ColorTransform | No | - | 表示オブジェクトのColorTransformを返します | -| `concatenatedMatrix` | Matrix | Yes | - | この表示オブジェクトとすべての親オブジェクトの結合されたMatrix | -| `scale9Grid` | Rectangle \| null | No | null | 現在有効な拡大/縮小グリッド | -| `loaderInfo` | LoaderInfo \| null | Yes | null | この表示オブジェクトが属するファイルの読み込み情報 | -| `root` | MovieClip \| Sprite \| null | Yes | null | DisplayObjectのルートであるDisplayObjectContainer | -| `mouseX` | number | Yes | - | 対象のDisplayObjectの基準点からのx軸の位置(ピクセル) | -| `mouseY` | number | Yes | - | 対象のDisplayObjectの基準点からのy軸の位置(ピクセル) | -| `dropTarget` | Sprite \| null | Yes | null | スプライトのドラッグ先またはドロップされた先の表示オブジェクト | -| `isMask` | boolean | No | false | マスクとしてDisplayObjectにセットされているかを示します | - -## メソッド - -### Sprite固有のメソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `startDrag(lockCenter?: boolean, bounds?: Rectangle)` | void | 指定されたスプライトをユーザーがドラッグできるようにします | -| `stopDrag()` | void | startDrag()メソッドを終了します | - -### DisplayObjectContainerから継承されるメソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `addChild(child: DisplayObject)` | DisplayObject | 子DisplayObjectインスタンスを追加します | -| `addChildAt(child: DisplayObject, index: number)` | DisplayObject | 指定のインデックス位置に子DisplayObjectインスタンスを追加します | -| `removeChild(child: DisplayObject)` | void | 指定のchild DisplayObjectインスタンスを削除します | -| `removeChildAt(index: number)` | void | 指定のインデックス位置から子DisplayObjectを削除します | -| `removeChildren(...indexes: number[])` | void | 配列で指定されたインデックスの子をコンテナから削除します | -| `getChildAt(index: number)` | DisplayObject \| null | 指定のインデックス位置にある子表示オブジェクトインスタンスを返します | -| `getChildByName(name: string)` | DisplayObject \| null | 指定された名前に一致する子表示オブジェクトを返します | -| `getChildIndex(child: DisplayObject)` | number | 子DisplayObjectインスタンスのインデックス位置を返します | -| `setChildIndex(child: DisplayObject, index: number)` | void | 表示オブジェクトコンテナの既存の子の位置を変更します | -| `contains(child: DisplayObject)` | boolean | 指定されたDisplayObjectがインスタンスの子孫であるかどうか | -| `swapChildren(child1: DisplayObject, child2: DisplayObject)` | void | 指定された2つの子オブジェクトのz順序を入れ替えます | -| `swapChildrenAt(index1: number, index2: number)` | void | 指定されたインデックス位置の2つの子オブジェクトのz順序を入れ替えます | - -### DisplayObjectから継承されるメソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `getBounds(targetDisplayObject?: DisplayObject)` | Rectangle | 指定したDisplayObjectの座標系を基準にして、表示オブジェクトの領域を定義する矩形を返します | -| `globalToLocal(point: Point)` | Point | pointオブジェクトをステージ(グローバル)座標から表示オブジェクトの(ローカル)座標に変換します | -| `localToGlobal(point: Point)` | Point | pointオブジェクトを表示オブジェクトの(ローカル)座標からステージ(グローバル)座標に変換します | -| `hitTestObject(target: DisplayObject)` | boolean | DisplayObjectの描画範囲を評価して、重複または交差するかどうかを調べます | -| `hitTestPoint(x: number, y: number, shapeFlag?: boolean)` | boolean | 表示オブジェクトを評価して、x、yパラメーターで指定されたポイントと重複または交差するかどうかを調べます | -| `remove()` | void | 親子関係を解除します | -| `getLocalVariable(key: any)` | any | クラスのローカル変数空間から値を取得 | -| `setLocalVariable(key: any, value: any)` | void | クラスのローカル変数空間へ値を保存 | -| `hasLocalVariable(key: any)` | boolean | クラスのローカル変数空間に値があるかどうかを判断します | -| `deleteLocalVariable(key: any)` | void | クラスのローカル変数空間の値を削除 | -| `getGlobalVariable(key: any)` | any | グローバル変数空間から値を取得 | -| `setGlobalVariable(key: any, value: any)` | void | グローバル変数空間へ値を保存 | -| `hasGlobalVariable(key: any)` | boolean | グローバル変数空間に値があるかどうかを判断します | -| `deleteGlobalVariable(key: any)` | void | グローバル変数空間の値を削除 | -| `clearGlobalVariable()` | void | グローバル変数空間に値を全てクリアします | - -## 使用例 - -### ボタンとして使用 - -```typescript -const { Sprite, Shape } = next2d.display; -const { PointerEvent } = next2d.events; - -const button = new Sprite(); - -// ボタンモードを有効化 -button.buttonMode = true; -button.useHandCursor = true; - -// 背景用のShapeを作成 -const bg = new Shape(); -bg.graphics.beginFill(0x3498db); -bg.graphics.drawRoundRect(0, 0, 120, 40, 8, 8); -bg.graphics.endFill(); -button.addChild(bg); - -// クリックイベント -button.addEventListener(PointerEvent.POINTER_DOWN, () => { - console.log("ボタンがクリックされました"); -}); - -stage.addChild(button); -``` - -### マスクとして使用 - -```typescript -const { Sprite, Shape } = next2d.display; - -const container = new Sprite(); - -// コンテンツ用のShape -const content = new Shape(); -content.graphics.beginFill(0xFF0000); -content.graphics.drawRect(0, 0, 200, 200); -content.graphics.endFill(); -container.addChild(content); - -// マスク用のShape -const maskShape = new Shape(); -maskShape.graphics.beginFill(0xFFFFFF); -maskShape.graphics.drawCircle(100, 100, 50); -maskShape.graphics.endFill(); - -// マスクを適用 -container.mask = maskShape; - -stage.addChild(container); -stage.addChild(maskShape); -``` - -### ドラッグ&ドロップ - -```typescript -const { Sprite, Shape } = next2d.display; -const { PointerEvent } = next2d.events; -const { Rectangle } = next2d.geom; - -const draggable = new Sprite(); - -// 背景用のShapeを作成 -const bg = new Shape(); -bg.graphics.beginFill(0x3498db); -bg.graphics.drawRect(0, 0, 100, 100); -bg.graphics.endFill(); -draggable.addChild(bg); - -// ドラッグ開始 -draggable.addEventListener(PointerEvent.POINTER_DOWN, () => { - // ドラッグを開始(中心をロック、境界を指定) - draggable.startDrag(true, new Rectangle(0, 0, 400, 300)); -}); - -// ドラッグ終了 -draggable.addEventListener(PointerEvent.POINTER_UP, () => { - draggable.stopDrag(); -}); - -stage.addChild(draggable); -``` - -### 子オブジェクトの管理 - -```typescript -const { Sprite, Shape } = next2d.display; - -const container = new Sprite(); - -// 複数のShapeを子として追加 -for (let i = 0; i < 5; i++) { - const shape = new Shape(); - shape.graphics.beginFill(0xFF0000 + i * 0x003300); - shape.graphics.drawCircle(0, 0, 20); - shape.graphics.endFill(); - shape.x = i * 50; - shape.name = "circle" + i; - container.addChild(shape); -} - -// 名前で子オブジェクトを取得 -const circle2 = container.getChildByName("circle2"); - -// 子の数を取得 -console.log(container.numChildren); // 5 - -stage.addChild(container); -``` - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [MovieClip](/ja/reference/player/movie-clip) -- [Shape](/ja/reference/player/shape) - - ---- - -# TextField - -TextFieldは、テキストの表示と編集を行うDisplayObjectです。ラベル表示から入力フォームまで、テキスト関連の機能を提供します。 - -## 継承関係 - -```mermaid -classDiagram - DisplayObject <|-- InteractiveObject - InteractiveObject <|-- TextField - - class TextField { - +text: String - +textColor: Number - +type: String - +setTextFormat() - } -``` - -## プロパティ - -### テキスト関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `text` | string | テキストフィールド内の現在のテキストであるストリング | -| `htmlText` | string | テキストフィールドの内容をHTMLで表した文字列 | -| `length` | number | テキストフィールド内の文字数(読み取り専用) | -| `maxChars` | number | ユーザーが入力できる最大文字数(0で無制限) | -| `restrict` | string | ユーザーがテキストフィールドに入力できる文字のセットを指定 | -| `defaultTextFormat` | TextFormat | テキストに適用するデフォルトのフォーマット | -| `stopIndex` | number | テキストの任意の表示終了位置の設定(デフォルト: -1) | - -### 表示関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `width` | number | 表示オブジェクトの幅(ピクセル単位) | -| `height` | number | 表示オブジェクトの高さ(ピクセル単位) | -| `textWidth` | number | テキストの幅(ピクセル単位、読み取り専用) | -| `textHeight` | number | テキストの高さ(ピクセル単位、読み取り専用) | -| `autoSize` | string | テキストフィールドの自動的な拡大/縮小および整列を制御("none", "left", "center", "right") | -| `autoFontSize` | boolean | テキストサイズの自動的な拡大/縮小および整列を制御(デフォルト: false) | -| `wordWrap` | boolean | テキストフィールドのテキストを折り返すかどうか(デフォルト: false) | -| `multiline` | boolean | 複数行テキストフィールドであるかどうか(デフォルト: false) | -| `numLines` | number | テキストの行数(読み取り専用) | - -### 境界線・背景関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `background` | boolean | テキストフィールドに背景の塗りつぶしがあるかどうか(デフォルト: false) | -| `backgroundColor` | number | テキストフィールドの背景の色(デフォルト: 0xffffff) | -| `border` | boolean | テキストフィールドに境界線があるかどうか(デフォルト: false) | -| `borderColor` | number | テキストフィールドの境界線の色(デフォルト: 0x000000) | - -### 輪郭関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `thickness` | number | 輪郭のテキスト幅。0(デフォルト値)で無効 | -| `thicknessColor` | number | 輪郭のテキストの色(16進数形式、デフォルト: 0) | - -### 入力関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `type` | string | テキストフィールドのタイプ("static", "dynamic", "input")(デフォルト: "static") | -| `focus` | boolean | テキストフィールドがフォーカスを持つかどうか(デフォルト: false) | -| `focusVisible` | boolean | テキストフィールドの点滅線の表示・非表示を制御(デフォルト: false) | -| `focusIndex` | number | テキストフィールドのフォーカス位置のインデックス(デフォルト: -1) | -| `selectIndex` | number | テキストフィールドの選択位置のインデックス(デフォルト: -1) | -| `compositionStartIndex` | number | テキストフィールドのコンポジション開始インデックス(デフォルト: -1) | -| `compositionEndIndex` | number | テキストフィールドのコンポジション終了インデックス(デフォルト: -1) | - -### スクロール関連 - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `scrollX` | number | x軸のスクロール位置(デフォルト: 0) | -| `scrollY` | number | y軸のスクロール位置(デフォルト: 0) | -| `scrollEnabled` | boolean | スクロール機能のON/OFFの制御(デフォルト: true) | -| `xScrollShape` | Shape | xスクロールバーの表示用のShapeオブジェクト(読み取り専用) | -| `yScrollShape` | Shape | yスクロールバーの表示用のShapeオブジェクト(読み取り専用) | - -## メソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `appendText(newText: string)` | void | 指定されたストリングをテキストフィールドのテキストの最後に付加します | -| `insertText(newText: string)` | void | テキストフィールドのフォーカス位置にテキストを追加します | -| `deleteText()` | void | テキストフィールドの選択範囲を削除します | -| `getLineText(lineIndex: number)` | string | 指定された行のテキストを返します | -| `replaceText(newText: string, beginIndex: number, endIndex: number)` | void | 指定された文字範囲を新しいテキストの内容に置き換えます | -| `selectAll()` | void | テキストフィールドのすべてのテキストを選択します | -| `copy()` | void | テキストフィールドの選択範囲をコピーします | -| `paste()` | void | コピーしたテキストを選択範囲に貼り付けます | -| `setFocusIndex(stageX: number, stageY: number, selected?: boolean)` | void | テキストフィールドのフォーカス位置を設定します | -| `keyDown(event: KeyboardEvent)` | void | キーダウンイベントを処理します | - -## TextFormat - -テキストのスタイルを設定するクラスです。 - -### プロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `font` | String | フォント名 | -| `size` | Number | フォントサイズ | -| `color` | Number | テキスト色 | -| `bold` | Boolean | 太字 | -| `italic` | Boolean | 斜体 | -| `align` | String | 配置("left", "center", "right") | -| `leading` | Number | 行間(ピクセル) | -| `letterSpacing` | Number | 文字間隔(ピクセル) | - -## 使用例 - -### 基本的なテキスト表示 - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.text = "Hello, Next2D!"; -textField.x = 100; -textField.y = 100; - -stage.addChild(textField); -``` - -### TextFormatの適用 - -```typescript -const { TextField, TextFormat } = next2d.text; - -const textField = new TextField(); -textField.text = "スタイル付きテキスト"; - -// TextFormatを作成 -const format = new TextFormat(); -format.font = "Arial"; -format.size = 24; -format.color = 0x3498db; -format.bold = true; - -// フォーマットを適用 -textField.setTextFormat(format); - -// デフォルトフォーマットとして設定 -textField.defaultTextFormat = format; - -stage.addChild(textField); -``` - -### 自動サイズ調整 - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.autoSize = "left"; // テキストに合わせて自動拡張 -textField.text = "このテキストに合わせてサイズが調整されます"; - -stage.addChild(textField); -``` - -### 複数行テキスト - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.width = 200; -textField.multiline = true; -textField.wordWrap = true; -textField.text = "これは複数行のテキストです。自動的に折り返されます。"; - -stage.addChild(textField); -``` - -### 入力フィールド - -```typescript -const { TextField } = next2d.text; - -const inputField = new TextField(); -inputField.type = "input"; -inputField.width = 200; -inputField.height = 30; -inputField.border = true; -inputField.borderColor = 0xcccccc; -inputField.background = true; -inputField.backgroundColor = 0xffffff; - -// プレースホルダーの代わり -inputField.text = ""; - -// 入力制限(数字のみ) -inputField.restrict = "0-9"; - -// 入力イベント -inputField.addEventListener("change", (event) => { - console.log("入力値:", inputField.text); -}); - -stage.addChild(inputField); -``` - -### パスワードフィールド - -```typescript -const { TextField } = next2d.text; - -const passwordField = new TextField(); -passwordField.type = "input"; -passwordField.displayAsPassword = true; -passwordField.width = 200; -passwordField.height = 30; -passwordField.border = true; -passwordField.borderColor = 0xcccccc; - -stage.addChild(passwordField); -``` - -### HTMLテキスト - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.width = 300; -textField.multiline = true; -textField.htmlText = ` - - 太字テキスト
- 斜体テキスト
- 赤いテキスト -
-`; - -stage.addChild(textField); -``` - -### スクロール可能なテキスト - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.width = 200; -textField.height = 100; -textField.multiline = true; -textField.wordWrap = true; -textField.border = true; -textField.text = "長いテキスト...\n".repeat(20); - -// スクロール操作 -function scrollUp() { - if (textField.scrollY > 0) { - textField.scrollY -= 10; - } -} - -function scrollDown() { - textField.scrollY += 10; -} - -stage.addChild(textField); -``` - -### 動的なテキスト更新 - -```typescript -const { TextField, TextFormat } = next2d.text; - -const scoreField = new TextField(); -scoreField.autoSize = "left"; - -const format = new TextFormat(); -format.font = "Arial"; -format.size = 32; -format.color = 0xffffff; -scoreField.defaultTextFormat = format; - -let score = 0; - -function updateScore(points) { - score += points; - scoreField.text = `Score: ${score}`; -} - -updateScore(0); -stage.addChild(scoreField); -``` - -### テキストの輪郭効果 - -```typescript -const { TextField, TextFormat } = next2d.text; - -const textField = new TextField(); -textField.autoSize = "left"; - -const format = new TextFormat(); -format.font = "Arial"; -format.size = 48; -format.color = 0xffffff; -textField.defaultTextFormat = format; - -textField.text = "輪郭付きテキスト"; -textField.thickness = 2; -textField.thicknessColor = 0x000000; - -stage.addChild(textField); -``` - -### テキストの一部置換 - -```typescript -const { TextField } = next2d.text; - -const textField = new TextField(); -textField.autoSize = "left"; -textField.text = "Hello World!"; - -// "World"を"Next2D"に置き換え -textField.replaceText("Next2D", 6, 11); -// 結果: "Hello Next2D!" - -stage.addChild(textField); -``` - -## イベント - -| イベント | 説明 | -|----------|------| -| `change` | テキストが変更されたとき | -| `focus` | フォーカスを得たとき | -| `blur` | フォーカスを失ったとき | -| `keyDown` | キーが押されたとき | -| `keyUp` | キーが離されたとき | - -```typescript -const { TextField } = next2d.text; - -const inputField = new TextField(); -inputField.type = "input"; - -// Enterキーでフォーム送信 -inputField.addEventListener("keyDown", (event) => { - if (event.keyCode === 13) { // Enter - submitForm(inputField.text); - } -}); - -stage.addChild(inputField); -``` - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [イベントシステム](/ja/reference/player/events) - - ---- - -# Tweenアニメーション - -Next2D Playerでは、`@next2d/ui`パッケージのTweenシステムを使用して、プログラムによるアニメーションを実装できます。位置、サイズ、透明度などのプロパティを滑らかに変化させることができます。 - -## Tweenの基本概念 - -```mermaid -flowchart LR - Start["開始値"] -->|イージング関数| Progress["進行度 0→1"] - Progress --> End["終了値"] - - subgraph Easing["イージング"] - Linear["linear"] - InQuad["inQuad"] - OutQuad["outQuad"] - InOutQuad["inOutQuad"] - end -``` - -## Tween.add() - -`Tween.add()`メソッドでアニメーション用の`Job`インスタンスを作成します。 - -```typescript -const { Tween, Easing } = next2d.ui; - -const job = Tween.add( - target, // アニメーション対象オブジェクト - from, // 開始プロパティ値 - to, // 終了プロパティ値 - delay, // 遅延時間(秒、デフォルト: 0) - duration, // アニメーション時間(秒、デフォルト: 1) - ease // イージング関数(デフォルト: linear) -); - -// アニメーションを開始 -job.start(); -``` - -### パラメータ - -| パラメータ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `target` | any | - | アニメーション対象オブジェクト | -| `from` | object | - | 開始プロパティ値 | -| `to` | object | - | 終了プロパティ値 | -| `delay` | number | 0 | アニメーション開始前の遅延(秒) | -| `duration` | number | 1 | アニメーション継続時間(秒) | -| `ease` | Function \| null | null | イージング関数(デフォルトはlinear) | - -### 戻り値 - -`Job` - アニメーションジョブインスタンス - -## Job クラス - -Jobクラスは個別のアニメーションジョブを管理します。EventDispatcherを継承しています。 - -### メソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `start()` | void | アニメーションを開始します | -| `stop()` | void | アニメーションを停止します | -| `chain(nextJob: Job \| null)` | Job \| null | このジョブの完了後に別のジョブを連結します | - -### プロパティ - -| プロパティ | 型 | 説明 | -|-----------|------|------| -| `target` | any | 対象オブジェクト | -| `from` | object | 開始値 | -| `to` | object | 終了値 | -| `delay` | number | 遅延時間 | -| `duration` | number | 継続時間 | -| `ease` | Function | イージング関数 | -| `currentTime` | number | 現在のアニメーション時間 | -| `nextJob` | Job \| null | 次の連結ジョブ | - -### イベント - -| イベント | 説明 | -|----------|------| -| `enterFrame` | 各アニメーションフレームで発行 | -| `complete` | アニメーション完了時に発行 | - -## イージング関数 - -`Easing`クラスは、11種類のイージングタイプでIn、Out、InOutのバリエーションを含む32種類のイージング関数を提供します。 - -### Linear / リニア -- `Easing.linear` - 一定速度 - -### Quadratic (Quad) / 二次関数 -- `Easing.inQuad` - ゼロ速度から加速 -- `Easing.outQuad` - ゼロ速度まで減速 -- `Easing.inOutQuad` - 中間まで加速、その後減速 - -### Cubic / 三次関数 -- `Easing.inCubic` / `Easing.outCubic` / `Easing.inOutCubic` - -### Quartic (Quart) / 四次関数 -- `Easing.inQuart` / `Easing.outQuart` / `Easing.inOutQuart` - -### Quintic (Quint) / 五次関数 -- `Easing.inQuint` / `Easing.outQuint` / `Easing.inOutQuint` - -### Sinusoidal (Sine) / 正弦波 -- `Easing.inSine` / `Easing.outSine` / `Easing.inOutSine` - -### Exponential (Expo) / 指数関数 -- `Easing.inExpo` / `Easing.outExpo` / `Easing.inOutExpo` - -### Circular (Circ) / 円形 -- `Easing.inCirc` / `Easing.outCirc` / `Easing.inOutCirc` - -### Elastic / 弾性 -- `Easing.inElastic` / `Easing.outElastic` / `Easing.inOutElastic` - -### Back / バック -- `Easing.inBack` / `Easing.outBack` / `Easing.inOutBack` - -### Bounce / バウンス -- `Easing.inBounce` / `Easing.outBounce` / `Easing.inOutBounce` - -### イージング関数のパラメータ - -すべてのイージング関数は4つのパラメータを受け取ります: - -```typescript -ease(t: number, b: number, c: number, d: number): number -``` - -- `t` - 現在の時間 (0 to d) -- `b` - 開始値 -- `c` - 変化量 (終了値 - 開始値) -- `d` - 継続時間 - -## 使用例 - -### 基本的な移動アニメーション - -```typescript -const { Tween, Easing } = next2d.ui; - -const sprite = new Sprite(); -stage.addChild(sprite); - -// xを0から400に1秒かけて移動 -const job = Tween.add( - sprite, - { x: 0, y: 100 }, - { x: 400, y: 100 }, - 0, - 1, - Easing.outQuad -); - -job.start(); -``` - -### 複数プロパティの同時アニメーション - -```typescript -const { Tween, Easing } = next2d.ui; - -// 移動 + 拡大 + フェードイン -const job = Tween.add( - sprite, - { x: 0, y: 0, scaleX: 1, scaleY: 1, alpha: 0 }, - { x: 200, y: 150, scaleX: 2, scaleY: 2, alpha: 1 }, - 0, - 0.5, - Easing.outCubic -); - -job.start(); -``` - -### アニメーションの連結 (chain) - -```typescript -const { Tween, Easing } = next2d.ui; - -// 最初のアニメーション -const job1 = Tween.add( - sprite, - { x: 0 }, - { x: 100 }, - 0, 1, - Easing.outQuad -); - -// 2つ目のアニメーション -const job2 = Tween.add( - sprite, - { x: 100 }, - { x: 200 }, - 0, 1, - Easing.inQuad -); - -// 連結して実行 -job1.chain(job2); -job1.start(); -``` - -### 遅延付きアニメーション - -```typescript -const { Tween, Easing } = next2d.ui; - -// 0.5秒遅延後に1秒かけてフェードアウト -const job = Tween.add( - sprite, - { alpha: 1 }, - { alpha: 0 }, - 0.5, - 1, - Easing.inQuad -); - -job.start(); -``` - -### イベントの活用 - -```typescript -const { Tween, Easing } = next2d.ui; - -const job = Tween.add( - sprite, - { x: 0 }, - { x: 300 }, - 0, 2, - Easing.inOutQuad -); - -// フレームごとの処理 -job.addEventListener("enterFrame", (event) => { - console.log("進行中:", job.currentTime); -}); - -// 完了時の処理 -job.addEventListener("complete", (event) => { - console.log("アニメーション完了!"); -}); - -job.start(); -``` - -### ゲームでの活用例 - -#### キャラクタージャンプ - -```typescript -const { Tween, Easing } = next2d.ui; - -function jump(character) { - const startY = character.y; - const jumpHeight = 100; - - // 上昇 - const upJob = Tween.add( - character, - { y: startY }, - { y: startY - jumpHeight }, - 0, 0.3, - Easing.outQuad - ); - - // 下降 - const downJob = Tween.add( - character, - { y: startY - jumpHeight }, - { y: startY }, - 0, 0.3, - Easing.inQuad - ); - - // 上昇 → 下降を連結 - upJob.chain(downJob); - upJob.start(); -} -``` - -#### UI表示アニメーション - -```typescript -const { Tween, Easing } = next2d.ui; - -function showPopup(popup) { - popup.scaleX = 0; - popup.scaleY = 0; - popup.alpha = 0; - - const job = Tween.add( - popup, - { scaleX: 0, scaleY: 0, alpha: 0 }, - { scaleX: 1, scaleY: 1, alpha: 1 }, - 0, 0.4, - Easing.outBack - ); - - job.start(); -} - -function hidePopup(popup) { - const job = Tween.add( - popup, - { scaleX: 1, scaleY: 1, alpha: 1 }, - { scaleX: 0, scaleY: 0, alpha: 0 }, - 0, 0.2, - Easing.inQuad - ); - - job.addEventListener("complete", () => { - popup.visible = false; - }); - - job.start(); -} -``` - -#### コイン取得エフェクト - -```typescript -const { Tween, Easing } = next2d.ui; - -function coinCollectEffect(coin) { - const job = Tween.add( - coin, - { y: coin.y, alpha: 1, scaleX: 1, scaleY: 1 }, - { y: coin.y - 50, alpha: 0, scaleX: 0.5, scaleY: 0.5 }, - 0, 0.5, - Easing.outQuad - ); - - job.addEventListener("enterFrame", () => { - coin.rotation += 15; - }); - - job.addEventListener("complete", () => { - coin.parent?.removeChild(coin); - }); - - job.start(); -} -``` - -### 停止と制御 - -```typescript -const { Tween, Easing } = next2d.ui; - -const job = Tween.add( - sprite, - { x: 0 }, - { x: 400 }, - 0, 2, - Easing.linear -); - -job.start(); - -// 途中で停止 -stopButton.addEventListener("pointerDown", () => { - job.stop(); -}); -``` - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [イベントシステム](/ja/reference/player/events) - - ---- - -# Video - -Videoは、動画コンテンツを再生するためのDisplayObjectです。WebM、MP4などの動画フォーマットに対応しています。 - -## 継承関係 - -```mermaid -classDiagram - DisplayObject <|-- Video - - class Video { - +src: string - +videoWidth: number - +videoHeight: number - +duration: number - +currentTime: number - +volume: number - +loop: boolean - +autoPlay: boolean - +smoothing: boolean - +paused: boolean - +muted: boolean - +loaded: boolean - +ended: boolean - +isVideo: boolean - +play() Promise~void~ - +pause() void - +seek(offset) void - } -``` - -## プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| `src` | string | "" | ビデオコンテンツへのURLを指定します | -| `videoWidth` | number | 0 | ビデオの幅をピクセル単位で指定する整数です | -| `videoHeight` | number | 0 | ビデオの高さをピクセル単位で指定する整数です | -| `duration` | number | 0 | キーフレーム総数(動画の長さ) | -| `currentTime` | number | 0 | 現在のキーフレーム(再生位置) | -| `volume` | number | 1 | ボリュームです。範囲は 0(無音)~ 1(フルボリューム)です | -| `loop` | boolean | false | ビデオをループ再生するかどうかを指定します | -| `autoPlay` | boolean | true | ビデオの自動再生の設定 | -| `smoothing` | boolean | true | ビデオを拡大/縮小する際にスムージング(補間)するかどうかを指定します | -| `paused` | boolean | true | ビデオが一時停止しているかどうかを返します | -| `muted` | boolean | false | ビデオがミュートされているかどうかを返します | -| `loaded` | boolean | false | ビデオが読み込まれているかどうかを返します | -| `ended` | boolean | false | ビデオが終了したかどうかを返します | -| `isVideo` | boolean | true | Videoの機能を所持しているかを返却(読み取り専用) | - -## メソッド - -| メソッド | 戻り値 | 説明 | -|---------|--------|------| -| `play()` | Promise\ | ビデオファイルを再生します | -| `pause()` | void | ビデオの再生を一時停止します | -| `seek(offset: number)` | void | 指定された位置に最も近いキーフレームをシークします | - -## 使用例 - -### 基本的な動画再生 - -```typescript -const { Video } = next2d.media; - -// Videoオブジェクトを作成(幅、高さを指定) -const video = new Video(640, 360); - -// 動画のURLを設定(設定すると自動的に読み込み開始) -video.src = "video.mp4"; - -// プロパティ設定 -video.autoPlay = true; // 自動再生 -video.loop = false; // ループしない -video.smoothing = true; // スムージング有効 - -// ステージに追加 -stage.addChild(video); -``` - -### 再生コントロール - -```typescript -const { Video } = next2d.media; -const { PointerEvent } = next2d.events; - -const video = new Video(640, 360); -video.autoPlay = false; // 自動再生を無効化 -video.src = "video.mp4"; - -stage.addChild(video); - -// 再生ボタン -playButton.addEventListener(PointerEvent.POINTER_DOWN, async () => { - await video.play(); -}); - -// 一時停止ボタン -pauseButton.addEventListener(PointerEvent.POINTER_DOWN, () => { - video.pause(); -}); - -// 停止ボタン(先頭に戻って停止) -stopButton.addEventListener(PointerEvent.POINTER_DOWN, () => { - video.pause(); - video.seek(0); -}); - -// 10秒進む -forwardButton.addEventListener(PointerEvent.POINTER_DOWN, () => { - video.seek(video.currentTime + 10); -}); - -// 10秒戻る -backButton.addEventListener(PointerEvent.POINTER_DOWN, () => { - video.seek(Math.max(0, video.currentTime - 10)); -}); -``` - -### イベントリスニング - -```typescript -const { Video } = next2d.media; -const { VideoEvent } = next2d.events; - -const video = new Video(640, 360); - -// 再生イベント -video.addEventListener(VideoEvent.PLAY, () => { - console.log("再生リクエスト"); -}); - -// 再生開始イベント -video.addEventListener(VideoEvent.PLAYING, () => { - console.log("再生開始"); -}); - -// 一時停止イベント -video.addEventListener(VideoEvent.PAUSE, () => { - console.log("一時停止"); -}); - -// シークイベント -video.addEventListener(VideoEvent.SEEK, () => { - console.log("シーク:", video.currentTime); -}); - -video.src = "video.mp4"; -stage.addChild(video); -``` - -### 再生進捗の表示 - -```typescript -const { Video } = next2d.media; - -const video = new Video(640, 360); -video.src = "video.mp4"; -stage.addChild(video); - -// フレームごとに進捗を更新 -stage.addEventListener("enterFrame", () => { - if (video.duration > 0) { - const progress = video.currentTime / video.duration; - progressBar.scaleX = progress; - timeLabel.text = formatTime(video.currentTime) + " / " + formatTime(video.duration); - } -}); - -function formatTime(seconds) { - const min = Math.floor(seconds / 60); - const sec = Math.floor(seconds % 60); - return `${min}:${sec.toString().padStart(2, '0')}`; -} -``` - -### 音量コントロール - -```typescript -const { Video } = next2d.media; - -const video = new Video(640, 360); -video.src = "video.mp4"; -video.volume = 0.5; // 50% - -stage.addChild(video); - -// ミュートトグル -muteButton.addEventListener(PointerEvent.POINTER_DOWN, () => { - video.muted = !video.muted; -}); -``` - -### ループ再生 - -```typescript -const { Video } = next2d.media; - -const video = new Video(640, 360); -video.loop = true; // ループ有効 -video.src = "video.mp4"; - -stage.addChild(video); -``` - -## VideoEvent - -| イベント | 説明 | -|----------|------| -| `VideoEvent.PLAY` | 再生がリクエストされた時 | -| `VideoEvent.PLAYING` | 再生が開始された時 | -| `VideoEvent.PAUSE` | 一時停止時 | -| `VideoEvent.SEEK` | シーク時 | - -## サポートフォーマット - -| フォーマット | 拡張子 | 対応状況 | -|--------------|--------|----------| -| MP4 (H.264) | .mp4 | 推奨 | -| WebM (VP8/VP9) | .webm | 対応 | -| Ogg Theora | .ogv | ブラウザ依存 | - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [イベントシステム](/ja/reference/player/events) - - ---- - -# フィルター - -Next2D Playerは、DisplayObjectに適用できる様々なビジュアルフィルターを提供しています。 - -## フィルターの適用方法 - -```typescript -const { Sprite } = next2d.display; -const { BlurFilter, DropShadowFilter, GlowFilter } = next2d.filters; - -const sprite = new Sprite(); - -// 単一のフィルター -sprite.filters = [new BlurFilter(4, 4)]; - -// 複数のフィルター -sprite.filters = [ - new DropShadowFilter(4, 45, 0x000000, 0.5), - new GlowFilter(0xff0000, 1, 8, 8) -]; - -// フィルターの削除 -sprite.filters = null; -``` - -## 利用可能なフィルター - -| フィルター | 説明 | -|-----------|------| -| BlurFilter | ぼかし効果 | -| DropShadowFilter | ドロップシャドウ効果 | -| GlowFilter | グロー効果 | -| BevelFilter | ベベル効果 | -| ColorMatrixFilter | カラーマトリックス変換 | -| ConvolutionFilter | 畳み込み効果 | -| DisplacementMapFilter | 変位マップ効果 | -| GradientBevelFilter | グラデーションベベル効果 | -| GradientGlowFilter | グラデーショングロー効果 | - ---- - -## BlurFilter - -ぼかし効果を適用します。ソフトフォーカスからガウスぼかしまで作成できます。 - -```typescript -const { BlurFilter } = next2d.filters; - -new BlurFilter(blurX, blurY, quality); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| quality | number | 1 | ぼかしの実行回数(0〜15) | - ---- - -## DropShadowFilter - -ドロップシャドウ効果を適用します。内側シャドウ、外側シャドウ、ノックアウトモードなどのスタイルオプションがあります。 - -```typescript -const { DropShadowFilter } = next2d.filters; - -new DropShadowFilter( - distance, angle, color, alpha, - blurX, blurY, strength, quality, - inner, knockout, hideObject -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alpha | number | 1 | シャドウのアルファ透明度(0〜1) | -| angle | number | 45 | シャドウの角度(-360〜360度) | -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| color | number | 0 | シャドウの色(0x000000〜0xFFFFFF) | -| distance | number | 4 | シャドウのオフセット距離(-255〜255ピクセル) | -| hideObject | boolean | false | オブジェクトを非表示にするかどうか | -| inner | boolean | false | 内側シャドウにするかどうか | -| knockout | boolean | false | ノックアウト効果を適用するかどうか | -| quality | number | 1 | ぼかしの実行回数(0〜15) | -| strength | number | 1 | インプリントの強さ(0〜255) | - ---- - -## GlowFilter - -グロー効果を適用します。内側グロー、外側グロー、ノックアウトモードなどのスタイルオプションがあります。 - -```typescript -const { GlowFilter } = next2d.filters; - -new GlowFilter( - color, alpha, blurX, blurY, - strength, quality, inner, knockout -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alpha | number | 1 | グローのアルファ透明度(0〜1) | -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| color | number | 0 | グローの色(0x000000〜0xFFFFFF) | -| inner | boolean | false | 内側グローにするかどうか | -| knockout | boolean | false | ノックアウト効果を適用するかどうか | -| quality | number | 1 | ぼかしの実行回数(0〜15) | -| strength | number | 1 | インプリントの強さ(0〜255) | - ---- - -## BevelFilter - -ベベル効果を適用します。オブジェクトを3次元的に表現できます。 - -```typescript -const { BevelFilter } = next2d.filters; - -new BevelFilter( - distance, angle, highlightColor, highlightAlpha, - shadowColor, shadowAlpha, blurX, blurY, - strength, quality, type, knockout -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| angle | number | 45 | ベベルの角度(-360〜360度) | -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| distance | number | 4 | ベベルのオフセット距離(-255〜255ピクセル) | -| highlightAlpha | number | 1 | ハイライトのアルファ透明度(0〜1) | -| highlightColor | number | 0xFFFFFF | ハイライトの色(0x000000〜0xFFFFFF) | -| knockout | boolean | false | ノックアウト効果を適用するかどうか | -| quality | number | 1 | ぼかしの実行回数(0〜15) | -| shadowAlpha | number | 1 | シャドウのアルファ透明度(0〜1) | -| shadowColor | number | 0 | シャドウの色(0x000000〜0xFFFFFF) | -| strength | number | 1 | インプリントの強さ(0〜255) | -| type | string | "inner" | ベベルの配置("inner"、"outer"、"full") | - ---- - -## ColorMatrixFilter - -4x5カラーマトリックス変換を適用します。明度、コントラスト、彩度、色相などを調整できます。 - -```typescript -const { ColorMatrixFilter } = next2d.filters; - -new ColorMatrixFilter(matrix); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| matrix | number[] | 単位行列 | 4x5カラー変換用の20個の要素を持つ配列 | - -### マトリックスのデフォルト値(単位行列) -```typescript -[ - 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 0, 1, 0 -] -``` - ---- - -## ConvolutionFilter - -マトリックス畳み込みフィルター効果を適用します。ぼかし、エッジ検出、シャープ、エンボス、ベベルなどの効果を実現できます。 - -```typescript -const { ConvolutionFilter } = next2d.filters; - -new ConvolutionFilter( - matrixX, matrixY, matrix, divisor, bias, - preserveAlpha, clamp, color, alpha -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alpha | number | 0 | 範囲外ピクセルのアルファ透明度(0〜1) | -| bias | number | 0 | マトリックス変換結果に加算するバイアス量 | -| clamp | boolean | true | イメージをクランプするかどうか | -| color | number | 0 | 範囲外ピクセルの置換色(0x000000〜0xFFFFFF) | -| divisor | number | 1 | マトリックス変換中の除数 | -| matrix | number[] \| null | null | マトリックス変換に使用する値の配列 | -| matrixX | number | 0 | マトリックスのX次元(列数、0〜15) | -| matrixY | number | 0 | マトリックスのY次元(行数、0〜15) | -| preserveAlpha | boolean | true | アルファチャンネルを維持するかどうか | - ---- - -## DisplacementMapFilter - -BitmapDataオブジェクトのピクセル値を使用して、オブジェクトの変位を実行します。 - -```typescript -const { DisplacementMapFilter } = next2d.filters; - -new DisplacementMapFilter( - bitmapBuffer, bitmapWidth, bitmapHeight, - mapPointX, mapPointY, componentX, componentY, - scaleX, scaleY, mode, color, alpha -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alpha | number | 0 | 範囲外変位のアルファ透明度(0〜1) | -| bitmapBuffer | Uint8Array \| null | null | 変位マップデータを含むバッファ | -| bitmapHeight | number | 0 | 変位マップデータの高さ | -| bitmapWidth | number | 0 | 変位マップデータの幅 | -| color | number | 0 | 範囲外変位に使用する色(0x000000〜0xFFFFFF) | -| componentX | number | 0 | X変位に使用するカラーチャンネル | -| componentY | number | 0 | Y変位に使用するカラーチャンネル | -| mapPointX | number | 0 | マップポイントのXオフセット | -| mapPointY | number | 0 | マップポイントのYオフセット | -| mode | string | "wrap" | フィルターモード("wrap"、"clamp"、"ignore"、"color") | -| scaleX | number | 0 | X変位結果の乗数(-65535〜65535) | -| scaleY | number | 0 | Y変位結果の乗数(-65535〜65535) | - ---- - -## GradientBevelFilter - -グラデーションベベル効果を適用します。グラデーションカラーで強調された斜めのエッジでオブジェクトを3次元的に見せます。 - -```typescript -const { GradientBevelFilter } = next2d.filters; - -new GradientBevelFilter( - distance, angle, colors, alphas, ratios, - blurX, blurY, strength, quality, type, knockout -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alphas | number[] \| null | null | カラー配列の各色に対応するアルファ値の配列(各値0〜1) | -| angle | number | 45 | ベベルの角度(-360〜360度) | -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| colors | number[] \| null | null | グラデーションで使用するRGB 16進数カラー値の配列 | -| distance | number | 4 | ベベルのオフセット距離(-255〜255ピクセル) | -| knockout | boolean | false | ノックアウト効果を適用するかどうか | -| quality | number | 1 | ぼかしの実行回数(0〜15) | -| ratios | number[] \| null | null | カラー配列の各色に対応する色分布比率の配列(各値0〜255) | -| strength | number | 1 | インプリントの強さ(0〜255) | -| type | string | "inner" | ベベルの配置("inner"、"outer"、"full") | - ---- - -## GradientGlowFilter - -グラデーショングロー効果を適用します。制御可能なカラーグラデーションによるリアルな輝きを表現できます。 - -```typescript -const { GradientGlowFilter } = next2d.filters; - -new GradientGlowFilter( - distance, angle, colors, alphas, ratios, - blurX, blurY, strength, quality, type, knockout -); -``` - -### プロパティ - -| プロパティ | 型 | デフォルト | 説明 | -|-----------|------|----------|------| -| alphas | number[] \| null | null | カラー配列の各色に対応するアルファ値の配列(各値0〜1) | -| angle | number | 45 | グローの角度(-360〜360度) | -| blurX | number | 4 | 水平方向のぼかし量(0〜255) | -| blurY | number | 4 | 垂直方向のぼかし量(0〜255) | -| colors | number[] \| null | null | グラデーションで使用するRGB 16進数カラー値の配列 | -| distance | number | 4 | グローのオフセット距離(-255〜255ピクセル) | -| knockout | boolean | false | ノックアウト効果を適用するかどうか | -| quality | number | 1 | ぼかしの実行回数(0〜15) | -| ratios | number[] \| null | null | カラー配列の各色に対応する色分布比率の配列(各値0〜255) | -| strength | number | 1 | インプリントの強さ(0〜255) | -| type | string | "outer" | グローの配置("inner"、"outer"、"full") | - ---- - -## 使用例 - -### ボタンのホバー効果 - -```typescript -const { Sprite } = next2d.display; -const { GlowFilter } = next2d.filters; - -const button = new Sprite(); - -button.addEventListener("rollOver", () => { - button.filters = [ - new GlowFilter(0x00ff00, 0.8, 10, 10) - ]; -}); - -button.addEventListener("rollOut", () => { - button.filters = null; -}); -``` - -### 影付きテキスト - -```typescript -const { TextField } = next2d.text; -const { DropShadowFilter } = next2d.filters; - -const textField = new TextField(); -textField.text = "Hello World"; -textField.filters = [ - new DropShadowFilter(2, 45, 0x000000, 0.5, 2, 2) -]; -``` - -### 複合フィルター - -```typescript -const { GlowFilter, DropShadowFilter, BlurFilter } = next2d.filters; - -sprite.filters = [ - // 外側のグロー - new GlowFilter(0x0088ff, 0.8, 15, 15, 2, 1, false), - // ドロップシャドウ - new DropShadowFilter(4, 45, 0x000000, 0.6, 4, 4), - // 軽いぼかし - new BlurFilter(1, 1, 1) -]; -``` - -### カラーマトリックスによるグレースケール - -```typescript -const { ColorMatrixFilter } = next2d.filters; - -// グレースケール変換マトリックス -const grayscaleMatrix = [ - 0.299, 0.587, 0.114, 0, 0, - 0.299, 0.587, 0.114, 0, 0, - 0.299, 0.587, 0.114, 0, 0, - 0, 0, 0, 1, 0 -]; - -sprite.filters = [new ColorMatrixFilter(grayscaleMatrix)]; -``` - -### グラデーショングロー効果 - -```typescript -const { GradientGlowFilter } = next2d.filters; - -sprite.filters = [ - new GradientGlowFilter( - 4, 45, - [0xff0000, 0x00ff00, 0x0000ff], // colors - [1, 1, 1], // alphas - [0, 128, 255], // ratios - 10, 10, 2, 1, "outer", false - ) -]; -``` - ---- - -## 関連項目 - -- [DisplayObject](/ja/reference/player/display-object) -- [MovieClip](/ja/reference/player/movie-clip) - - ---- - diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 98a1bbd..1d1a709 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,6 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + - run: 'git config --global url."https://github.com/".insteadOf git@github.com:' + - run: git submodule sync --recursive + - run: git submodule update --init --recursive - uses: actions/setup-node@v6 with: node-version: 24 @@ -21,4 +24,4 @@ jobs: - run: npm install -g npm@latest - run: npm install - run: npm run build - - run: npm publish \ No newline at end of file + - run: npm publish diff --git a/.gitignore b/.gitignore index f4e2c6d..68bde6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ dist/ +next2d-development-assistant/ *.tsbuildinfo diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..35f14bf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "next2d-development-assistant"] + path = next2d-development-assistant + url = git@github.com:Next2D/next2d-development-assistant.git diff --git a/next2d-development-assistant b/next2d-development-assistant new file mode 160000 index 0000000..049d91f --- /dev/null +++ b/next2d-development-assistant @@ -0,0 +1 @@ +Subproject commit 049d91f1a3380fea7870f76bef98596887775f5c diff --git a/package.json b/package.json index c9ead0b..f3338e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next2d-development-mcp", - "version": "0.0.2", + "version": "0.0.3", "description": "MCP server for Next2D application development assistance", "type": "module", "author": "Toshiyuki Ienaga ", @@ -13,7 +13,7 @@ "main": "./dist/index.js", "scripts": { "build": "tsc && npm run copy-refs", - "copy-refs": "node -e \"const fs=require('fs');const p=require('path');const src=p.join('.github','skills','references');const dst=p.join('dist','references');fs.mkdirSync(dst,{recursive:true});fs.readdirSync(src).filter(f=>f.endsWith('.md')).forEach(f=>fs.copyFileSync(p.join(src,f),p.join(dst,f)));console.log('Copied references to dist/references/')\"", + "copy-refs": "node -e \"const fs=require('fs');const p=require('path');const roots=[p.join('next2d-development-assistant','skills','next2d-development-assistant','references'),p.join('next2d-development-assistant','.github','skills','references'),p.join('.github','skills','references')];const src=roots.find((dir)=>fs.existsSync(dir));if(!src){throw new Error('Reference directory not found. Expected next2d-development-assistant/skills/next2d-development-assistant/references');}const dst=p.join('dist','references');fs.mkdirSync(dst,{recursive:true});fs.readdirSync(src).filter((f)=>f.endsWith('.md')).forEach((f)=>fs.copyFileSync(p.join(src,f),p.join(dst,f)));console.log('Copied references from '+src+' to dist/references/');\"", "start": "node dist/index.js", "dev": "tsc --watch", "lint": "eslint src/ --ignore-pattern '*.test.ts'", diff --git a/src/resources/index.ts b/src/resources/index.ts index 9157ff2..ea46dd8 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -9,11 +9,51 @@ const __dirname = path.dirname(__filename); function loadReference(filename: string): string { // Search locations (in priority order): // 1. Bundled with package: dist/references/ (works after npm publish) - // 2. Development: .github/skills/references/ (relative to project root) - // 3. User's project: cwd/.github/skills/references/ (if user has specs locally) + // 2. Development submodule: next2d-development-assistant/skills/next2d-development-assistant/references/ + // 3. Development submodule (legacy layout): next2d-development-assistant/.github/skills/references/ + // 4. Development (legacy): .github/skills/references/ (relative to project root) + // 5. User's project submodule: cwd/next2d-development-assistant/skills/next2d-development-assistant/references/ + // 6. User's project submodule (legacy layout): cwd/next2d-development-assistant/.github/skills/references/ + // 7. User's project (legacy): cwd/.github/skills/references/ const candidates = [ path.join(__dirname, "..", "references", filename), + path.join( + __dirname, + "..", + "..", + "next2d-development-assistant", + "skills", + "next2d-development-assistant", + "references", + filename + ), + path.join( + __dirname, + "..", + "..", + "next2d-development-assistant", + ".github", + "skills", + "references", + filename + ), path.join(__dirname, "..", "..", ".github", "skills", "references", filename), + path.join( + process.cwd(), + "next2d-development-assistant", + "skills", + "next2d-development-assistant", + "references", + filename + ), + path.join( + process.cwd(), + "next2d-development-assistant", + ".github", + "skills", + "references", + filename + ), path.join(process.cwd(), ".github", "skills", "references", filename) ]; From bbcbdf3e2a7382ea90c8386f07c87c7ab53ce012 Mon Sep 17 00:00:00 2001 From: ienaga Date: Mon, 23 Feb 2026 13:09:28 +0900 Subject: [PATCH 3/3] edit README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b37bdfe..5f35862 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ Next2D +[![UnitTest](https://github.com/Next2D/next2d-development-mcp/actions/workflows/integration.yml/badge.svg?branch=main)](https://github.com/Next2D/next2d-development-mcp/actions/workflows/integration.yml) +[![CodeQL](https://github.com/Next2D/next2d-development-mcp/actions/workflows/github-code-scanning/codeql/badge.svg?branch=main)](https://github.com/Next2D/next2d-development-mcp/actions/workflows/github-code-scanning/codeql) +[![Lint](https://github.com/Next2D/next2d-development-mcp/actions/workflows/lint.yml/badge.svg?branch=main)](https://github.com/Next2D/next2d-development-mcp/actions/workflows/lint.yml) + +[![release](https://img.shields.io/github/v/release/Next2D/next2d-development-mcp)](https://github.com/Next2D/next2d-development-mcp/releases) + [Next2D](https://next2d.app) アプリケーション開発を支援する **MCP (Model Context Protocol) サーバー**です。 [framework-typescript-template](https://github.com/Next2D/framework-typescript-template) を使った **MVVM + Clean Architecture + Atomic Design** パターンに従ったコード生成、アーキテクチャ検証、API リファレンスを提供します。