TS TypeScriptとViteで16×16ドット
絵ツールをビルドしてみた話

ViteとTypeScriptの使い方を体で理解するために、16×16のドット絵を描く小さなWebアプリを作ってみました。

<svg class="eyecatch-svg" viewBox="0 0 192 192" xmlns="http://www.w3.org/2000/svg">
  <!-- 背景 -->
  <rect width="192" height="192" fill="white" rx="32" ry="32"/>
  
  <!-- ピクセルグリッド(中央) -->
  <g transform="translate(56, 40)">
    <!-- グリッド枠 -->
    <rect x="0" y="0" width="80" height="80" fill="none" stroke="#607D8B" stroke-width="3" rx="4"/>
    
    <!-- グリッド線(縦) -->
    <line x1="20" y1="0" x2="20" y2="80" stroke="#E0E0E0" stroke-width="2"/>
    <line x1="40" y1="0" x2="40" y2="80" stroke="#E0E0E0" stroke-width="2"/>
    <line x1="60" y1="0" x2="60" y2="80" stroke="#E0E0E0" stroke-width="2"/>
    
    <!-- グリッド線(横) -->
    <line x1="0" y1="20" x2="80" y2="20" stroke="#E0E0E0" stroke-width="2"/>
    <line x1="0" y1="40" x2="80" y2="40" stroke="#E0E0E0" stroke-width="2"/>
    <line x1="0" y1="60" x2="80" y2="60" stroke="#E0E0E0" stroke-width="2"/>
    
    <!-- サンプルピクセル -->
    <rect x="6" y="6" width="12" height="12" fill="#2196F3" rx="2"/>
    <rect x="26" y="6" width="12" height="12" fill="#4CAF50" rx="2"/>
    <rect x="46" y="26" width="12" height="12" fill="#FF9800" rx="2"/>
    <rect x="26" y="46" width="12" height="12" fill="#F44336" rx="2"/>
    <rect x="62" y="62" width="12" height="12" fill="#9C27B0" rx="2"/>
  </g>
  
  <!-- Vite稲妻マーク(右上) -->
  <g transform="translate(140, 48)">
    <path d="M 0 0 L 8 20 L 4 20 L 12 40 L 2 22 L 6 22 Z" 
          fill="#FF9800" stroke="#FF9800" stroke-width="2" 
          stroke-linejoin="round"/>
  </g>
  
  <!-- TypeScript「TS」バッジ(左下) -->
  <g transform="translate(40, 135)">
    <rect width="40" height="40" fill="#2196F3" rx="6"/>
    <text x="20" y="28" font-family="Arial, sans-serif" font-size="20" 
          font-weight="bold" fill="white" text-anchor="middle">TS</text>
  </g>
  
  <!-- カラーパレット(下部) -->
  <g transform="translate(96, 145)">
    <circle cx="0" cy="10" r="8" fill="#2196F3"/>
    <circle cx="20" cy="10" r="8" fill="#4CAF50"/>
    <circle cx="40" cy="10" r="8" fill="#FF9800"/>
    <circle cx="60" cy="10" r="8" fill="#F44336"/>
  </g>
</svg>TypeScriptとViteで16×16ドット<br class="chiilabo-br is-on">絵ツールをビルドしてみた話

機能は単純ですが、Canvas、入力処理、ビルド、配布まで一通り触れるには、ちょうど良い規模でした。

関連記事

1. なぜViteとTypeScriptを選んだのか

1.1. TypeScriptを選んだ理由

TypeScriptはJavaScriptに型(データの種類)を追加した言語です。
記述量が少し増えますが、状態を持つアプリでは安心感が違います。

今回のツールでも、「16×16のピクセル配列」「選択中の色」「消しゴム状態」など、意外と管理する情報が多くなります。
型があることで、考えながら書ける感覚がありました。
ただし、公開前にJavaScriptに変換する作業が必要です。

1.2. Viteを選んだ理由

Vite(ヴィート)は、フロントエンド開発用のビルドツール兼開発サーバです。
「ビルドツール」とは、TypeScriptをJavaScriptに変換し、ブラウザで動く形にまとめる裏方の仕組みです。

Viteがないと、importの解決を手動で管理し、TypeScriptを自分でビルド設定し、ローカルサーバを用意する必要があります。

Viteは次の2つを担当します。

① 開発時

  • ローカル開発サーバを起動(Viteのデフォルトポートは 5173)
  • TypeScriptをその場でJavaScriptに変換
  • ファイル変更を検知して即時反映(HMR)
  • バンドルしないことで起動と更新が非常に速い

② 本番時

  • すべてのコードを解析
  • 依存関係をまとめる(バンドル)
  • 圧縮・最適化したファイルを生成

実際に触ってみると、Viteの良さは起動の速さでした。
npm run dev を実行すると、ほぼ待ち時間なくローカルサーバが立ち上がります。
ファイルを保存すると即座に画面が更新される。
このテンポの良さは、試行錯誤が多い個人開発ではかなり効きます。

2. プロジェクトの概要

完成したのは、次のようなツールです。

  • 16×16のマス目をCanvasに拡大表示
  • タップやドラッグで色を塗る
  • 16色のパレットから色を選択
  • 消しゴム、全消去
  • PNGとして保存、JSONとしてコピー
  • localStorageへの自動保存

Webアプリとして必要な要素は一通り入っています。

2.1. Step 1: プロジェクトを作る(npm create vite@latest)

まず最初に、Viteのテンプレートを使って dot16 プロジェクトを作成しました。

npm create vite@latest dot16 -- --template vanilla-ts
Code language: CSS (css)

「–template vanilla-ts」オプションは、フレームワークを使わない素のTypeScript構成を意味しています(つまり、ReactやVueは使わない、ということです)。
Canvas中心のアプリなので、この形が一番シンプルでした。

2.1. Step 1: プロジェクトを作る(npm create vite@latest)

2.2. Step 2: 依存関係をインストールする(npm install)

cd dot16
npm install

この時点では設定ファイルしか存在しません。
npm install を実行して、package.jsonで指定されているVite本体やTypeScript関連のライブラリを実体としてインストールしました。

2.3. Step 3: 開発サーバを起動する(npm run dev)

npm run dev

これでローカルサーバが起動し、ブラウザで「localhost: 5173」にアクセスすると動作を確認できます。

2.3. Step 3: 開発サーバを起動する(npm run dev)

ここからは、保存するたびに画面が更新される状態になります。

2.4. ローカルサーバにLANでアクセスできるようにする(vite –host)

ちなみに、ローカルサーバにLANでアクセスできるようにするには、package.jsonを少し変更します。

 "scripts": {
    "dev": "vite --host",
Code language: JavaScript (javascript)

viteコマンドに–hostオプションを追加します。

3. Canvasで16×16の世界を作る

内部では16×16のデータを持ち、表示だけを拡大する方針にしました。
実際のピクセルデータは Uint8Array(256) で管理しています。

これは、256個の箱が並んだ配列だと考えると分かりやすいです。各箱には「どの色か」を表す番号だけが入ります。色そのものはパレットとして別に定義しました。

描画は毎回Canvas全体を描き直します。最初は効率が悪そうに見えましたが、16×16程度では問題になりません。むしろ実装が単純になりました。

1マスずつ色を塗り、その上から薄い線でグリッドを引く。この繰り返しです。

3.1. 入力処理:マウスとスマホを同時に扱う

入力には pointer events を使いました。これはマウス、タッチ、ペン入力をまとめて扱える仕組みです。

最初はマウスイベントだけで書いていましたが、スマホで試したときにすぐ限界を感じました。pointer eventsに切り替えると、同じコードで両方に対応できます。

Canvas上の座標を16×16のマスに変換する処理は、地味ですが重要です。ここを間違えると、意図しないマスが塗られます。

3.2. localStorageでの自動保存

描画のたびに状態をlocalStorageへ保存するようにしました。localStorageは、ブラウザに小さなデータを保存できる仕組みです。

ページをリロードしても絵が残る。この安心感は大きいです。

3.3. PNGとJSONの出力

PNG保存では、表示用とは別に16×16サイズのCanvasを作り、そこに直接ピクセルを書き込みました。拡大表示用のCanvasを流用しなかった点がポイントです。

JSON出力では、配列をそのままテキスト化します。ゲーム用素材として再利用することを想定しました。

4. 本番ビルド(npm run build)

npm run build
4. 本番ビルド(npm run build)

内部で起きることは以下です。

  • TypeScript → JavaScript にトランスパイル
  • 依存関係を1つ(または少数)のJSにバンドル
  • 画像・音声などを含めて最適化

成果物は dist/ に出ます。

4. 本番ビルド(npm run build)
dist/
├─ index.html
├─ assets/
│  ├─ index-xxxxx.js
│  └─ index-xxxxx.css

4.1. ビルド結果の確認(npm run preview)

npm run preview

これは 本番ビルドをローカルで再現 します。
スマホ確認もLAN越しで可能です。

4.2. vite.config.tsを追加して再ビルド

開発中は問題なく動いていたのですが、公開用のファイルをアップロードしたところ、画面がうまく表示されませんでした。

4.2. vite.config.tsを追加して再ビルド

ブラウザの開発者ツールを見ると、index-xxxx.css が 404 になっています。
これはアプリをドメイン直下ではなく、

https://example.com/dot16/
Code language: JavaScript (javascript)

という サブディレクトリ に配置していることが原因でした。

Viteはデフォルト設定のままだと、CSSやJavaScriptを /assets/... のような 絶対パス で参照します。そのため、/dot16/ 配下に置いた場合でも、ブラウザはドメイン直下の /assets/ を探しに行き、404になってしまうのです。

そこで、Viteの設定ファイルを追加します。プロジェクトのルートに vite.config.ts を作成しました。

import { defineConfig } from 'vite'

export default defineConfig({
  base: '/dot16/',
})
Code language: JavaScript (javascript)

base は「このアプリがどのURLを起点として公開されるか」をViteに伝える設定です。今回のように https://example.com/dot16/ で公開する場合は、そのまま /dot16/ を指定します。

設定を追加して再ビルドします。

npm run build
4.2. vite.config.tsを追加して再ビルド

4.3. (参考) スマホアプリ化する場合

PWAやストア配布に進む場合の流れだけ書きます。

  • PWA
    • manifest.json 追加
    • Service Worker(Vite pluginで可)
  • iOS / Android
    • dist/Capacitor に渡す
    • Xcode / Android Studio でビルド

5. 作ってみて分かったこと

16×16のドット絵ツールは小さな題材ですが、Webアプリ開発の基本要素が詰まっています。

Viteは「設定を意識せずに作業に集中できる」点が一番の利点でした。
一方で、裏で何をしているかを理解しないと、トラブル時に手が止まります。今回のような小さなアプリで挙動を追うのは、良い練習になりました。