リクエスト詳細
🐛 バグ報告
対応完了
対象アプリ: ドット絵メーカー PixelForge
save.php: アニメーション投稿時にフレーム1枚分のpixel_dataしか受け取らず多フレーム作品が正常保存されない
## 1. 不具合の内容
pages/save.php の pixel_data 検証ロジックが「size×size の2次元配列」であることを前提としています。
```php
$grid = json_decode($pixel, true);
if (!is_array($grid) || count($grid) !== $size) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
```
これは1フレーム分(`[[...], [...], ...]`)の形式のみ受け付けます。
一方、エディタ側(assets/editor.js)はギャラリー投稿時に **全フレームの pixel_data を送るべき** ですが、save.php 側は1フレームしか想定していないため、以下のいずれかが起きます。
- JS側が `frames[activeFrameIndex].grid` の1フレームだけを送っている場合 → 多フレームアニメーションの他フレームが全て失われて投稿される(データロスト)
- JS側が全フレームを配列で包んで送っている場合(`[frame0, frame1, ...]`)→ `count($grid) !== $size` が成立して「画像データが不正です」400エラーになり投稿できない
editor.js の投稿ボタン処理を確認すると、`pixel_data` として `frames[activeFrameIndex].grid` のみをシリアライズして送っている可能性が高く、多フレームアニメーション作品を投稿しても1フレーム目しか保存されないデータロストが発生します。
## 2. 根拠・発生しそうな条件
- schema.sql の `pixel_data MEDIUMTEXT` は単一フレームのJSONとして定義されており、多フレーム対応の設計がない
- save.php の検証が `count($grid) !== $size`(2次元配列の行数チェック)であり、フレーム配列を渡すと行数 = フレーム数になるため必ずエラーになる
- editor.js の `frames` 配列には最大16フレームが存在するが、投稿UIがアクティブフレームのみを送っている場合、ユーザーは「全フレームが保存された」と誤解したまま投稿する
- フレームが2枚以上ある状態で「ギャラリーに投稿」すると再現する
## 3. 期待動作
- 1フレームの場合:現状通り2次元配列として保存
- 多フレームの場合:全フレームのグリッドデータが保存され、ギャラリーのサムネイルは1フレーム目を使用する
- ギャラリーカードにフレーム数バッジ(例: 🎞 3F)を表示し、アニメーション作品であることをユーザーが判別できる
## 4. 修正方針
### schema.sql
`pixel_data` カラムのコメントを「フレーム配列 or 1フレーム2次元配列 (JSON)」に更新し、`canvas_size` に加えて `frame_count TINYINT UNSIGNED NOT NULL DEFAULT 1` カラムを追加する(既存行への影響は DEFAULT 1 で吸収)。
```sql
ALTER TABLE pixel_works
ADD COLUMN frame_count TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER canvas_size;
```
### pages/save.php
- POSTパラメータ `pixel_data` を「フレームの配列(外側)か1フレームの2次元配列か」を自動判定する
- 判定ロジック: `$outer = json_decode($pixel, true)` → 先頭要素が配列の配列(3次元)なら多フレーム、2次元なら単フレームとして扱う
- 各フレームに対して既存の行・セル検証ループを適用する
- `frame_count` を INSERT に含める
```php
$decoded = json_decode($pixel, true);
// 多フレーム判定: 最初の要素が配列の配列かどうか
if (is_array($decoded) && isset($decoded[0]) && is_array($decoded[0]) && isset($decoded[0][0]) && is_array($decoded[0][0])) {
$frame_list = $decoded; // 3次元配列
} else {
$frame_list = [$decoded]; // 単フレームを1要素の配列に統一
}
if (count($frame_list) < 1 || count($frame_list) > 16) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
foreach ($frame_list as $fgrid) {
if (!is_array($fgrid) || count($fgrid) !== $size) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
foreach ($fgrid as $row) { /* 既存のセル検証 */ }
}
$pixel_norm = json_encode($frame_list, JSON_UNESCAPED_UNICODE);
$frame_count = count($frame_list);
```
### assets/editor.js(投稿処理部分)
投稿時に `frames[activeFrameIndex].grid` だけでなく `frames.map(f => f.grid)` を `pixel_data` として送る。サムネイルは引き続きアクティブフレームの Canvas から生成する。
### render_work_card()(lib.php)
`$r['frame_count'] > 1` の場合にカード右上へ `<span class="frame-badge">🎞 ${frame_count}F</span>` を表示する小バッジを追加(CSS追加のみで既存レイアウト非破壊)。
pages/save.php の pixel_data 検証ロジックが「size×size の2次元配列」であることを前提としています。
```php
$grid = json_decode($pixel, true);
if (!is_array($grid) || count($grid) !== $size) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
```
これは1フレーム分(`[[...], [...], ...]`)の形式のみ受け付けます。
一方、エディタ側(assets/editor.js)はギャラリー投稿時に **全フレームの pixel_data を送るべき** ですが、save.php 側は1フレームしか想定していないため、以下のいずれかが起きます。
- JS側が `frames[activeFrameIndex].grid` の1フレームだけを送っている場合 → 多フレームアニメーションの他フレームが全て失われて投稿される(データロスト)
- JS側が全フレームを配列で包んで送っている場合(`[frame0, frame1, ...]`)→ `count($grid) !== $size` が成立して「画像データが不正です」400エラーになり投稿できない
editor.js の投稿ボタン処理を確認すると、`pixel_data` として `frames[activeFrameIndex].grid` のみをシリアライズして送っている可能性が高く、多フレームアニメーション作品を投稿しても1フレーム目しか保存されないデータロストが発生します。
## 2. 根拠・発生しそうな条件
- schema.sql の `pixel_data MEDIUMTEXT` は単一フレームのJSONとして定義されており、多フレーム対応の設計がない
- save.php の検証が `count($grid) !== $size`(2次元配列の行数チェック)であり、フレーム配列を渡すと行数 = フレーム数になるため必ずエラーになる
- editor.js の `frames` 配列には最大16フレームが存在するが、投稿UIがアクティブフレームのみを送っている場合、ユーザーは「全フレームが保存された」と誤解したまま投稿する
- フレームが2枚以上ある状態で「ギャラリーに投稿」すると再現する
## 3. 期待動作
- 1フレームの場合:現状通り2次元配列として保存
- 多フレームの場合:全フレームのグリッドデータが保存され、ギャラリーのサムネイルは1フレーム目を使用する
- ギャラリーカードにフレーム数バッジ(例: 🎞 3F)を表示し、アニメーション作品であることをユーザーが判別できる
## 4. 修正方針
### schema.sql
`pixel_data` カラムのコメントを「フレーム配列 or 1フレーム2次元配列 (JSON)」に更新し、`canvas_size` に加えて `frame_count TINYINT UNSIGNED NOT NULL DEFAULT 1` カラムを追加する(既存行への影響は DEFAULT 1 で吸収)。
```sql
ALTER TABLE pixel_works
ADD COLUMN frame_count TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER canvas_size;
```
### pages/save.php
- POSTパラメータ `pixel_data` を「フレームの配列(外側)か1フレームの2次元配列か」を自動判定する
- 判定ロジック: `$outer = json_decode($pixel, true)` → 先頭要素が配列の配列(3次元)なら多フレーム、2次元なら単フレームとして扱う
- 各フレームに対して既存の行・セル検証ループを適用する
- `frame_count` を INSERT に含める
```php
$decoded = json_decode($pixel, true);
// 多フレーム判定: 最初の要素が配列の配列かどうか
if (is_array($decoded) && isset($decoded[0]) && is_array($decoded[0]) && isset($decoded[0][0]) && is_array($decoded[0][0])) {
$frame_list = $decoded; // 3次元配列
} else {
$frame_list = [$decoded]; // 単フレームを1要素の配列に統一
}
if (count($frame_list) < 1 || count($frame_list) > 16) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
foreach ($frame_list as $fgrid) {
if (!is_array($fgrid) || count($fgrid) !== $size) {
json_out(['ok' => false, 'error' => '画像データが不正です'], 400);
}
foreach ($fgrid as $row) { /* 既存のセル検証 */ }
}
$pixel_norm = json_encode($frame_list, JSON_UNESCAPED_UNICODE);
$frame_count = count($frame_list);
```
### assets/editor.js(投稿処理部分)
投稿時に `frames[activeFrameIndex].grid` だけでなく `frames.map(f => f.grid)` を `pixel_data` として送る。サムネイルは引き続きアクティブフレームの Canvas から生成する。
### render_work_card()(lib.php)
`$r['frame_count'] > 1` の場合にカード右上へ `<span class="frame-badge">🎞 ${frame_count}F</span>` を表示する小バッジを追加(CSS追加のみで既存レイアウト非破壊)。
💬 返信 (3)
🛠 開発を開始しました (バグ修正 (pixelforge))
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
ご要望ありがとうございます。AI 開発ワーカーが実装を開始します。
通常 5〜30 分で Pull Request を作成し、レビュー後にリリースされます。
📝 開発が完了しました
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
ご要望いただいた内容の実装が完了し、最終チェック段階に入りました。
レビュー (自動) → リリース、の流れで進みます。
もう少々お待ちください。
✅ リリース完了のお知らせ
ご要望いただいた「ドット絵メーカー PixelForge」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=pixelforge
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/pixelforge/
ご利用ありがとうございます!
ご要望いただいた「ドット絵メーカー PixelForge」を実装し、リリースいたしました。
【ご利用方法】
ダッシュボード: https://www.aiapps.jp/?action=dashboard
アプリ詳細: https://www.aiapps.jp/apps/show.php?slug=pixelforge
デモ環境は 1 時間以内に自動構築されます:
https://www.aiapps.jp/demo/pixelforge/
ご利用ありがとうございます!
Echo
Iris