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

機能は単純ですが、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.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.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

内部で起きることは以下です。
- TypeScript → JavaScript にトランスパイル
- 依存関係を1つ(または少数)のJSにバンドル
- 画像・音声などを含めて最適化
成果物は dist/ に出ます。

dist/
├─ index.html
├─ assets/
│ ├─ index-xxxxx.js
│ └─ index-xxxxx.css
4.1. ビルド結果の確認(npm run preview)
npm run preview
これは 本番ビルドをローカルで再現 します。
スマホ確認もLAN越しで可能です。
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.3. (参考) スマホアプリ化する場合
PWAやストア配布に進む場合の流れだけ書きます。
- PWA
manifest.json追加- Service Worker(Vite pluginで可)
- iOS / Android
dist/を Capacitor に渡す- Xcode / Android Studio でビルド
5. 作ってみて分かったこと
16×16のドット絵ツールは小さな題材ですが、Webアプリ開発の基本要素が詰まっています。
Viteは「設定を意識せずに作業に集中できる」点が一番の利点でした。
一方で、裏で何をしているかを理解しないと、トラブル時に手が止まります。今回のような小さなアプリで挙動を追うのは、良い練習になりました。