ピクセルズ — Web で遊ぶ「思考に集中できる」ノノグラム (ピクチャーロジック)
ピクセルズとは
ピクセルズ は、行と列のヒント数字から塗るマスを論理だけで導く「ノノグラム / ピクチャーロジック」パズルを Web ブラウザで遊べるアプリです。
無料・登録不要、PWA でオフライン対応、5×5 から 25×25 まで合計 21 パズルを収録。すべての盤面は 「推測なしで論理だけで解ける (no-guess)」かつ「解が一意」 であることを CI で強制保証しています。
![]()
解決したかった「ノノグラムアプリの不揃い」
既存のノノグラムアプリは「広告だらけで集中できない」「課金導線が強くて遊びづらい」「論理だけで解けないパズルが混じっていて推測ゲーになる」「タッチ操作が荒くて 25×25 はストレス」など、不快ポイントが散りばめられていることが多いです。
そこでピクセルズは、最初から以下を満たすように設計しました。
- 広告ゼロ・課金ゼロ — 一旦最初から最後まで遊んでもらう前提
- 推測ゼロ — line solver で「ヒントだけで解ける」と CI 検証されたパズルのみ収録
- タッチでも快適 — 1 本指で塗り、2 本指でピンチズーム+パン (25×25 でも崩れない)
- 集中を妨げない — BGM はデフォルト OFF、ON にしても落ち着いた A マイナーペンタトニック
パズル一覧 (5×5 から 25×25 まで 21 個)
| カテゴリ | 数 | 例 | |---|---|---| | 5×5 | 3 | ハート、ダイヤ、プラス | | 10×10 | 8 | ねこ、いえ、ほし、きのこ、ハート(大)、かさ、ロケット、き | | 15×15 | 7 | りんご、うさぎ、さかな、きりん、ぞう、かに、かたつむり | | 25×25 | 3 | ちょう、しろ、ドラゴン |
![]()
すべて手描きの絵柄を image-to-puzzle パイプラインで .grid (ASCII art) → JSON 化し、QA suite (line solver + bounded backtrack + 可視性 + 対称性) を通過したものだけを収録しています。
「行/列が完成すると数字が緑になる」ライン完了表示
ノノグラムで一番気持ちいい瞬間は「ある行や列が完全に正解と一致したとき」。ピクセルズでは、行や列のセルが正解通りに塗られた瞬間に その行/列のヒント数字が緑色 に切り替わります。
これがあるだけで「あと何行で全部完成するか」が一目で分かり、パズルを進める手が止まりません。判定はクライアント側で全マスのチェックではなく、その行/列だけをチェックするので 25×25 でも一切の遅延なし。
25×25 はズーム+パン UI で快適に
25×25 の盤面はモバイルで全体表示するとセル幅が約 14px となり、塗り間違いが頻発します。そこで Pixi.js v8 の Container.scale + position で盤面 root だけにビューポート変換を適用し、以下のジェスチャーを実装しました。
- PC: マウスホイールでカーソル位置中心ズーム、
+−⤢ボタン - Mac トラックパッド: ピンチでズーム、2 本指 swipe でパン (
ctrlKey分岐で標準準拠) - スマホ/タブレット: 2 本指ピンチズーム、2 本指ドラッグでパン
排他制御は 'idle' / 'drawing' / 'gesture' の有限状態機械で、1 本指で塗っている途中に 2 本目が触れたら drawing をキャンセルして gesture に昇格、全指が離れるまで描画ロックします (誤爆防止)。
![]()
Undo / Redo は履歴をセーブにも統合
Cmd/Ctrl+Zで 1 ステップ undo、Cmd/Ctrl+YまたはCmd/Ctrl+Shift+Zで redo- HUD の
↶ ↷ボタンでも操作可能 - 履歴は
(board, marks)のスナップショット配列、上限 100 件 - LocalStorage の
activePuzzleに履歴も含めて保存 → ブラウザを閉じても再開時に Undo 可能
ドラッグ操作は「endDrag したタイミングで 1 エントリ」として記録 (途中の中間状態は記録しない)。連続塗りでガタガタ Undo にならず気持ちよく戻せます。
BGM は WebAudio 自前合成 (chiptune アンビエント)
BGM は音源ファイルを使わず、OfflineAudioContext で 1 ループ 24 秒分の AudioBuffer を事前合成して AudioBufferSourceNode.loop = true で再生する方式。
- テンポ: 80 BPM (落ち着き)
- キー: A マイナー pentatonic (集中を妨げない)
- 音色: ベース (sine 低音 / Am→Em→Fmaj→G の root note 進行) + メロディ (triangle / pentatonic 上下動)
- フィルター: ローパス 2400Hz (高音をカット → 長時間集中向き)
setTimeout でのスケジュールはタブ非アクティブ時にスロットリングされるため不採用。AudioBuffer + loop なら復帰後も完璧に同期します。
![]()
bundle サイズ増加は +5 KiB のみ (楽曲データはすべてコード生成)。PWA precache に余計な重さを足さず、オフラインでも完全に動作します。
アクセシビリティ — WCAG AAA + キーボード完結
| 項目 | 実装 |
|---|---|
| キーボード操作 | 矢印キー / Z (塗) / X (×) / C (消) で全操作完結 |
| アニメーション抑制 | prefers-reduced-motion + 設定モーダルで個別 OFF。クリア時の波状回転アニメも即終了 |
| ハイコントラスト | 黒背景 + 白塗の極限コントラスト (WCAG AAA 11:1 以上) |
| ARIA | 進捗バー / モーダル focus trap / aria-live 適切化 |
| タッチ領域 | 全 HUD ボタンが 44×44px 以上 (タッチターゲット最小) |
特にハイコントラストは設定モーダルでトグル可能。グレード達成だけでなく、低視力ユーザーが日常使いできるレベルを狙いました。
![]()
技術スタック
| 層 | 採用 |
|---|---|
| 描画 | Pixi.js 8.2 (WebGPU 既定 → WebGL2 fallback、bgRoot と boardRoot を分離してビューポート効果を盤面のみに限定) |
| UI | React 19 + Zustand 5 (Canvas は ref、UI は React のハイブリッド) |
| スキーマ | Valibot (型 + ランタイム検証 + LocalStorage マイグレーション) |
| パズル QA | line solver (overlap 推論) + bounded backtrack + 可視性 + 対称性 (src/qa/) |
| 音声 | WebAudio 自前合成 (SE: synth.ts、BGM: bgm.ts) |
| ビルド | Bun 1.2 + Vite 6 |
| PWA | vite-plugin-pwa (Service Worker、Manifest、precache 716 KiB) |
| 配信 | Cloudflare Pages + Universal SSL、pixels.howlrs.net |
| CI | GitHub Actions (typecheck + test + build + 全 21 パズル QA 検証) |
「論理だけで解ける」を CI で強制
ノノグラムにおいて最大のフラストレーションは「これは推測しないと解けない」というパズルに当たることです。ピクセルズでは line solver (overlap 推論を反復) で解けるパズルだけを収録するため、CI で全パズルを以下 4 観点で検証しています。
- 一意性: 解が 1 つだけか (line + bounded backtrack で 2 解目を探索)
- 論理可解性: line solver だけで解けるか (= no-guess)
- 可視性: 塗り比率 / 連結成分数 / bbox 充填率
- 対称性: 横/縦/点対称スコア
15×15 でも 1 ms 未満で判定し、25×25 では timeout + step 制限で計算爆発を防止。新しいパズルを追加するたびに bun run validate-puzzles が走り、QA を通らないと CI が落ちます。
開発過程の振り返り
| タグ | 内容 |
|---|---|
| β2.0 | HUD 分離 / SE / 共有 / 設定モーダル |
| β3.0 | ライン完了表示 / reduce-motion / 進捗% |
| β4.0 | ヘルプモーダル / ハイコントラスト |
| β5.0 | Undo / Redo |
| β6.0 | 動的 canvas 解像度 / クリアマーク復元 |
| β7.0 | 一時停止 (visibility 自動 paused) |
| β8.0 | Undo/Redo を autoSave に統合 |
| β9.0 | 画像→パズル変換パイプ (sharp 導入) |
| β10.0 | ズーム+パン UI |
| β11.0 | BGM (WebAudio 自前合成) |
各リリースで Gemini Pro Deep / Review にコードレビューを依頼し、累計 50+ の指摘を反映しました。「viewport を localStorage に永続化すると端末間で UX 破綻」「BGM を setTimeout でスケジュールするとタブ非アクティブで崩れる → AudioBuffer + loop=true が堅牢」など、独力では見落としがちな盲点を拾えたのが大きかったです。
まとめ
- 5×5 から 25×25 まで 21 パズル を収録、すべて no-guess + 一意解 を CI で強制
- Undo/Redo (履歴 100 件 + LocalStorage 永続化) で「やってみて戻す」が気軽
- 25×25 用に ズーム+パン UI (ピンチ / ホイール / トラックパッド / HUD ボタン)
- WebAudio 自前合成 BGM で bundle 0 KB を保ったまま集中向け楽曲
- PWA + オフライン対応、Cloudflare Pages で爆速配信
- 広告ゼロ、課金ゼロ、登録不要 → https://pixels.howlrs.net/
通勤中の暇つぶしから、深く集中したいタイミングまで、論理だけで楽しめるノノグラムをぜひ。