next2d-development-mcp 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -113,7 +113,7 @@ Edit the configuration file:
113
113
  ```json
114
114
  {
115
115
  "mcpServers": {
116
- "next2d": {
116
+ "next2d-development-mcp": {
117
117
  "command": "npx",
118
118
  "args": ["-y", "next2d-development-mcp"]
119
119
  }
@@ -132,7 +132,7 @@ Create `.mcp.json` at the project root:
132
132
  ```json
133
133
  {
134
134
  "mcpServers": {
135
- "next2d": {
135
+ "next2d-development-mcp": {
136
136
  "command": "npx",
137
137
  "args": ["-y", "next2d-development-mcp"]
138
138
  }
@@ -155,7 +155,7 @@ Create `.codex/mcp.json` at the project root:
155
155
  ```json
156
156
  {
157
157
  "mcpServers": {
158
- "next2d": {
158
+ "next2d-development-mcp": {
159
159
  "command": "npx",
160
160
  "args": ["-y", "next2d-development-mcp"]
161
161
  }
@@ -175,7 +175,7 @@ Create `.gemini/settings.json` at the project root:
175
175
  ```json
176
176
  {
177
177
  "mcpServers": {
178
- "next2d": {
178
+ "next2d-development-mcp": {
179
179
  "command": "npx",
180
180
  "args": ["-y", "next2d-development-mcp"]
181
181
  }
@@ -196,7 +196,7 @@ Add the MCP server from Cline settings:
196
196
  ```json
197
197
  {
198
198
  "mcpServers": {
199
- "next2d": {
199
+ "next2d-development-mcp": {
200
200
  "command": "npx",
201
201
  "args": ["-y", "next2d-development-mcp"]
202
202
  }
@@ -215,7 +215,7 @@ Add to Cursor settings:
215
215
  ```json
216
216
  {
217
217
  "mcpServers": {
218
- "next2d": {
218
+ "next2d-development-mcp": {
219
219
  "command": "npx",
220
220
  "args": ["-y", "next2d-development-mcp"]
221
221
  }
@@ -233,7 +233,7 @@ Add to Windsurf MCP configuration:
233
233
  ```json
234
234
  {
235
235
  "mcpServers": {
236
- "next2d": {
236
+ "next2d-development-mcp": {
237
237
  "command": "npx",
238
238
  "args": ["-y", "next2d-development-mcp"]
239
239
  }
@@ -1033,6 +1033,154 @@ export class YourMolecule extends ButtonAtom
1033
1033
  }
1034
1034
  ```
1035
1035
 
1036
+ ## Button Enable/Disable Pattern (連打防止)
1037
+
1038
+ `ButtonAtom` は `enable()` / `disable()` メソッドを持ち、ボタンの連続タップを防止できる。
1039
+
1040
+ ### ButtonAtom の enable/disable API
1041
+
1042
+ ```typescript
1043
+ // src/ui/component/atom/ButtonAtom.ts
1044
+ export class ButtonAtom extends Sprite {
1045
+ constructor() {
1046
+ super();
1047
+ this.buttonMode = true;
1048
+ }
1049
+
1050
+ // ボタンを有効化 (mouseEnabled/mouseChildren = true)
1051
+ enable(): void {
1052
+ this.mouseEnabled = true;
1053
+ this.mouseChildren = true;
1054
+ }
1055
+
1056
+ // ボタンを無効化 (mouseEnabled/mouseChildren = false)
1057
+ disable(): void {
1058
+ this.mouseEnabled = false;
1059
+ this.mouseChildren = false;
1060
+ }
1061
+ }
1062
+ ```
1063
+
1064
+ ### パターン1: 通常ボタン (PointerEvent.POINTER_UP で再有効化)
1065
+
1066
+ ボタン押下時に `disable()` し、`POINTER_UP` のタイミングで `enable()` を呼ぶ。
1067
+
1068
+ ```typescript
1069
+ import { ButtonAtom } from "../atom/ButtonAtom";
1070
+ import { PointerEvent } from "@next2d/events";
1071
+
1072
+ export class YourBtnMolecule extends ButtonAtom {
1073
+ onPointerDown(): void {
1074
+ this.disable(); // 押下時に無効化して連打防止
1075
+ // ... 処理
1076
+ }
1077
+
1078
+ onPointerUp(): void {
1079
+ // ... 処理
1080
+ this.enable(); // POINTER_UP 時に再有効化
1081
+ }
1082
+ }
1083
+
1084
+ // View でのイベント登録例
1085
+ btn.addEventListener(PointerEvent.POINTER_DOWN, () => btn.onPointerDown());
1086
+ btn.addEventListener(PointerEvent.POINTER_UP, () => btn.onPointerUp());
1087
+ ```
1088
+
1089
+ ### パターン2: Tween アニメーションあり (Job の COMPLETE イベントで再有効化)
1090
+
1091
+ アニメーション完了まで操作不可にする場合は、`Job` の `Event.COMPLETE` で `enable()` を呼ぶ。
1092
+
1093
+ ```typescript
1094
+ import { ButtonAtom } from "../atom/ButtonAtom";
1095
+ import { Tween, Easing, type Job } from "@next2d/ui";
1096
+ import { Event } from "@next2d/events";
1097
+
1098
+ export class YourBtnMolecule extends ButtonAtom {
1099
+ onPointerUp(): Promise<void> {
1100
+ this.disable(); // アニメーション開始前に無効化
1101
+ return new Promise<void>((resolve) => {
1102
+ new YourBtnPointerUpAnimation(this, resolve).start();
1103
+ // アニメーション側の Job.COMPLETE で enable() を呼ぶ
1104
+ });
1105
+ }
1106
+ }
1107
+
1108
+ // Animation クラス側での実装例
1109
+ export class YourBtnPointerUpAnimation {
1110
+ private readonly _job: Job;
1111
+
1112
+ constructor(sprite: Sprite, callback?: () => void) {
1113
+ this._job = Tween.add(sprite,
1114
+ { "scaleX": 1.0, "scaleY": 1.0 },
1115
+ { "scaleX": 0.9, "scaleY": 0.9 },
1116
+ 0.2, 0, Easing.outQuad
1117
+ );
1118
+
1119
+ this._job.addEventListener(Event.COMPLETE, () => {
1120
+ (sprite as unknown as ButtonAtom).enable(); // アニメーション完了時に有効化
1121
+ if (callback) callback();
1122
+ });
1123
+ }
1124
+
1125
+ start(): void { this._job.start(); }
1126
+ }
1127
+ ```
1128
+
1129
+ ### 実装例 (NormalPlayBtnMolecule より)
1130
+
1131
+ ```typescript
1132
+ // src/ui/component/molecule/NormalPlayBtnMolecule.ts
1133
+ export class NormalPlayBtnMolecule extends ButtonAtom {
1134
+ onPointerDown(): void {
1135
+ new HomeNormalPlayBtnPointerDownAnimation(this).start();
1136
+ }
1137
+
1138
+ onPointerUp(): Promise<void> {
1139
+ this.disable(); // 押下時に無効化
1140
+ return new Promise<void>((resolve) => {
1141
+ // アニメーション完了時に resolve → 呼び出し側でチェーン処理
1142
+ new HomeNormalPlayBtnPointerUpAnimation(this, resolve).start();
1143
+ // Animation の Job.COMPLETE 内で enable() を呼ぶ
1144
+ });
1145
+ }
1146
+ }
1147
+ ```
1148
+
1149
+ ### 判断基準
1150
+
1151
+ | ケース | `enable()` のタイミング |
1152
+ |--------|----------------------|
1153
+ | 通常ボタン(アニメーションなし) | `PointerEvent.POINTER_UP` |
1154
+ | Tween アニメーションあり | `Job` の `Event.COMPLETE` |
1155
+ | 非同期処理後に有効化したい | `Promise` の `resolve` 後または `await` 後 |
1156
+
1157
+ ### Anti-Patterns
1158
+
1159
+ ```typescript
1160
+ // NG: disable のみで enable し忘れる → ボタンが永遠に操作不可になる
1161
+ onPointerDown(): void {
1162
+ this.disable();
1163
+ // enable() の呼び忘れ
1164
+ }
1165
+
1166
+ // NG: アニメーション完了前に enable() を呼ぶ → 連打防止が無効
1167
+ onPointerUp(): void {
1168
+ this.disable();
1169
+ new SomeAnimation(this).start();
1170
+ this.enable(); // NG: アニメーション開始直後に有効化してしまう
1171
+ }
1172
+
1173
+ // OK: Job の COMPLETE イベント内で enable()
1174
+ constructor(sprite: Sprite) {
1175
+ this._job = Tween.add(sprite, { alpha: 0 }, { alpha: 1 }, 0.3);
1176
+ this._job.addEventListener(Event.COMPLETE, () => {
1177
+ (sprite as unknown as ButtonAtom).enable(); // OK
1178
+ });
1179
+ }
1180
+ ```
1181
+
1182
+ ---
1183
+
1036
1184
  ## Anti-Patterns
1037
1185
 
1038
1186
  ```typescript
@@ -1396,6 +1544,85 @@ npm run generate
1396
1544
 
1397
1545
  `routing.json`のトッププロパティ値を分解し、`view`ディレクトリ直下に対象ディレクトリがなければ作成。View/ViewModelが存在しない場合のみ新規クラスを生成。
1398
1546
 
1547
+ ---
1548
+
1549
+ # Security Configuration
1550
+
1551
+ ## Content-Security-Policy (CSP) 設定時の注意事項
1552
+
1553
+ Next2D Player は WebGL/WebGPU による描画、Web Worker、Blob URL を内部で使用するため、CSP の設定には制約がある。
1554
+ 誤った設定を行うとアプリが動作しなくなる。
1555
+
1556
+ ### 必須ディレクティブ
1557
+
1558
+ ```
1559
+ Content-Security-Policy:
1560
+ default-src 'self' data: blob:;
1561
+ script-src 'self';
1562
+ style-src 'self' 'unsafe-inline';
1563
+ connect-src 'self' https://{{ドメイン}};
1564
+ worker-src 'self' blob: data:;
1565
+ ```
1566
+
1567
+ | ディレクティブ | 必要な値 | 理由 |
1568
+ |------------|---------|------|
1569
+ | `default-src` | `'self' data: blob:` | Blob URL・Data URI を Player 内部で使用するため |
1570
+ | `script-src` | `'self'` | インラインスクリプト不要。`'unsafe-inline'` は不要 |
1571
+ | `style-src` | `'self' 'unsafe-inline'` | Next2D が動的にスタイルを挿入するため `'unsafe-inline'` が必須 |
1572
+ | `connect-src` | `'self' https://{{ドメイン}}` | API・コンテンツエンドポイントへの通信を許可 |
1573
+ | `worker-src` | `'self' blob: data:` | Web Worker を Blob/Data URI で生成するため |
1574
+
1575
+ ### 使用禁止の設定
1576
+
1577
+ ```
1578
+ # NG: frame-ancestors を設定するとエラーになる
1579
+ frame-ancestors 'none'; # ← 追加してはいけない
1580
+ ```
1581
+
1582
+ `frame-ancestors 'none'` を追加するとアプリケーションがエラーになる。設定しないこと。
1583
+
1584
+ ### Vite での設定例 (vite.config.ts)
1585
+
1586
+ ```typescript
1587
+ import { defineConfig } from "vite";
1588
+
1589
+ export default defineConfig({
1590
+ server: {
1591
+ headers: {
1592
+ "Content-Security-Policy": [
1593
+ "default-src 'self' data: blob:",
1594
+ "script-src 'self'",
1595
+ "style-src 'self' 'unsafe-inline'",
1596
+ "connect-src 'self' https://example.com",
1597
+ "worker-src 'self' blob: data:"
1598
+ ].join("; ")
1599
+ }
1600
+ }
1601
+ });
1602
+ ```
1603
+
1604
+ ### nginx での設定例
1605
+
1606
+ ```nginx
1607
+ add_header Content-Security-Policy "default-src 'self' data: blob:; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://example.com; worker-src 'self' blob: data:";
1608
+ ```
1609
+
1610
+ ### Anti-Patterns
1611
+
1612
+ ```
1613
+ # NG: frame-ancestors を追加する
1614
+ Content-Security-Policy: default-src 'self' data: blob:; ... frame-ancestors 'none';
1615
+
1616
+ # NG: worker-src に blob: を含めない → Web Worker が動作しない
1617
+ worker-src 'self';
1618
+
1619
+ # NG: default-src に blob: を含めない → Player の内部処理が失敗する
1620
+ default-src 'self';
1621
+
1622
+ # NG: style-src に 'unsafe-inline' を含めない → スタイルが適用されない
1623
+ style-src 'self';
1624
+ ```
1625
+
1399
1626
  ## Anti-Patterns
1400
1627
 
1401
1628
  ```typescript
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "next2d-development-mcp",
3
3
  "displayName": "Next2D Development MCP",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "description": "MCP server for Next2D application development assistance",
6
6
  "type": "module",
7
7
  "author": "Toshiyuki Ienaga <ienaga@next2d.app>",
@@ -48,16 +48,16 @@
48
48
  ]
49
49
  },
50
50
  "dependencies": {
51
- "@modelcontextprotocol/sdk": "^1.26.0"
51
+ "@modelcontextprotocol/sdk": "^1.27.1"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@eslint/js": "^10.0.1",
55
55
  "@types/node": "^25.3.0",
56
- "@types/vscode": "^1.99.0",
57
- "@typescript-eslint/eslint-plugin": "^8.56.0",
58
- "@typescript-eslint/parser": "^8.56.0",
59
- "@vscode/vsce": "^3.0.0",
60
- "eslint": "^10.0.1",
56
+ "@types/vscode": "^1.109.0",
57
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
58
+ "@typescript-eslint/parser": "^8.56.1",
59
+ "@vscode/vsce": "^3.7.1",
60
+ "eslint": "^10.0.2",
61
61
  "eslint-plugin-unused-imports": "^4.4.1",
62
62
  "globals": "^17.3.0",
63
63
  "typescript": "^5.9.3",
@@ -65,6 +65,6 @@
65
65
  },
66
66
  "engines": {
67
67
  "node": ">=22.0.0",
68
- "vscode": "^1.99.0"
68
+ "vscode": "^1.109.0"
69
69
  }
70
70
  }