はじめに
こんにちは。
今日は2025年12月31日、大晦日ですね。
みなさん、煩悩は溜まっていますか? 私は溜まっています。
一年の締めくくりといえば「除夜の鐘」。
108つの煩悩を祓うために鐘を突きに行きたいところですが、外は寒いし、近所のお寺は並んでいるかもしれない……。
「じゃあ、ブラウザで突き放題にすればいいじゃない」
そう思い立ち、みんなが投稿した煩悩を、鐘の音とともに浄化できるWebアプリを突貫工事で開発しました。
技術構成は HTML/JS + Google Apps Script (GAS) + Netlify です。
作ったもの:除夜の鐘 - 煩悩ガチャ
百聞は一見に如かず。まずは音を出して突いてみてください。(※音が出ます)
🔔 アプリはこちら
https://joya-no-kane-2025-2026.netlify.app/
※注意: 本アプリは「除夜の鐘」という性質上、年が明けたら(1/1中には)サービスを停止する予定です。 今のうちに心ゆくまで鳴らしてください!
- 鐘をクリック: 厳かな音とともに鐘が揺れ、誰かの「煩悩」がランダムで表示されて浄化(フェードアウト)されます。
- 奉納機能: 自分の煩悩を投稿できます。投稿されたデータは即座にDB(スプレッドシート)に反映され、次の誰かの鐘つきで表示されます。
- リアルタイムカウンター: 全世界で浄化された煩悩の総数がカウントされています。
本記事では、このアプリをどのように 爆速で実装・デプロイまで持っていったか を紹介します。
技術構成
今回は「とにかく早く公開する」「コストをかけない(無料)」を最優先にし、サーバーレス構成を採用しました。
- Frontend: HTML5, CSS3, Vanilla JS (フレームワークなし)
- Backend: Google Apps Script (GAS)
- Database: Google Spreadsheets
- Hosting: Netlify (Drag & Dropデプロイ)
アーキテクチャ
非常にシンプルです。クライアント(HTML)から fetch でGASのWebアプリURLを叩き、GASがスプレッドシートを読み書きしてJSONを返す仕組みです。
[ Browser ] <---> [ GAS (API) ] <---> [ Spreadsheet (DB) ]
実装のポイント:GASを簡易バックエンドにする
Google Apps Scriptは doGet 関数を定義して「Webアプリとして導入」することで、簡単にGETリクエストを受け付けるAPIエンドポイントになります。
今回はクエリパラメータ action の値によって処理を3つに分岐させました。
GAS側のコード(抜粋)
function doGet(e) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const action = e.parameter.action;
// 1. 初期データ取得(煩悩リストと総カウント)
if (action === 'getData') {
const lastRow = sheet.getLastRow();
// A列にある煩悩テキストを配列化して取得
const bonnoList = sheet.getRange(1, 1, lastRow, 1).getValues().flat().filter(String);
// 総回数はプロパティストア(高速なKVS的な領域)から取得
const count = PropertiesService.getScriptProperties().getProperty('TOTAL_COUNT') || 0;
return responseJSON({ bonnoList, count });
}
// 2. カウントアップ(鐘が突かれたとき)
else if (action === 'tap') {
const props = PropertiesService.getScriptProperties();
// 現在値を数値化してインクリメント
let count = parseInt(props.getProperty('TOTAL_COUNT')) || 0;
count++;
props.setProperty('TOTAL_COUNT', count);
return responseJSON({ status: 'ok', count });
}
// 3. 煩悩の追加(投稿されたとき)
else if (action === 'add') {
const text = e.parameter.text;
if (text) {
sheet.appendRow([text]); // スプシの末尾に追加
return responseJSON({ status: 'saved' });
}
}
}
// JSONを返すヘルパー関数
function responseJSON(data) {
return ContentService.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
※重要ポイント: GASをデプロイする際、「アクセスできるユーザー」を 「全員(Anyone)」 に設定しないと、外部から fetch した際にCORSエラーや403エラーになるので注意が必要です。
この30行程度のコードで、**「データの取得」「カウントの永続化」「新規データの書き込み」**というWebアプリに必要なCRUD(UとDはないですが)機能が揃います。
特に、カウント数はスプレッドシートのセルではなく PropertiesService(スクリプトプロパティ)に保存することで、読み書きの速度を上げ、排他制御の問題も軽減させています。
実装のポイント:フロントエンド
フロントエンドは素のJavaScriptです。
ユーザー体験(UX)を損なわないよう、APIのレスポンスを待たずにアニメーションや音を先行して再生させています。
// 鐘を突く処理
bellBtn.addEventListener('click', async () => {
// 1. UI演出:アニメーションと音再生(即座に反応させる)
bellBtn.classList.remove('shake');
void bellBtn.offsetWidth; // リフロー発生でアニメーションリセット
bellBtn.classList.add('shake');
audio.currentTime = 0;
audio.play();
// 2. 煩悩の表示(ロード済みのリストからランダム選出)
showRandomBonno();
// 3. カウントアップ送信(非同期で裏側実行)
try {
// キャッシュ回避のために現在時刻(t)を付与
await fetch(`${API_URL}?action=tap&t=${Date.now()}`);
} catch (e) {
console.error("送信エラー", e);
}
});
ここでのハマりポイントは ブラウザのキャッシュ でした。
単純に同じURL(?action=tap)を叩き続けると、ブラウザが通信を省略してしまいGAS側のカウントが増えない現象が発生。
URLの末尾に &t=${Date.now()} をつけて毎回異なるリクエストに見せることで解決しました。
デザインと生成AI活用
見た目(デザイン)の実装も爆速化の鍵でした。
今回は、コードの修正案出しから画像生成まで、**生成AI(Gemini)**とペアプログラミングのような形で進めました。
鐘の素材
最初はCSSで簡単な台形を描画していましたが、「もっとリアルな鐘を突きたい」という欲が出ました。そこで、鐘の画像生成もAIに依頼しました。
私: 「日本の古いお寺にある、大きな青銅製の釣鐘(梵鐘)の画像を生成してください。苔むしていて、重厚感があるイラストで。正面の画像。背景は真っ黒で」
AI: 「承知しました。こちらはいかがでしょうか。(画像生成)」
これで数秒でリアルな鐘の画像(bell.png)が手に入りました。これをHTMLに配置し、CSS Animationでクリック時に小刻みに振動させることで、打撃感を表現しています。
浄化のエフェクト
煩悩のテキストがフワッと消えるエフェクトも、AIと相談しながら調整しました。
/* 浄化のアニメーション */
@keyframes purify {
0% {
opacity: 0;
transform: translateY(15px) scale(0.9);
filter: blur(2px);
}
20% {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
100% {
opacity: 0;
/* 上に昇りながら拡大し、ぼやけて消える */
transform: translateY(-30px) scale(1.1);
filter: blur(10px);
}
}
「ただ消えるだけでなく、浄化される感じで」とオーダーしたところ、transform で上昇させつつ、filter: blur() でぼかしを加えるアイデアが提案され、それがそのまま採用されています。
デプロイ:フォルダを投げるだけ
開発の最後、公開作業も時間をかけずに終わらせました。
今回はフレームワークを使っていない(生のHTML/JS)ため、ビルドプロセスは不要です。
Netlify Drop を使えば、文字通り「フォルダを投げるだけ」で公開されます。
-
index.html、bell.png、bell.mp3を1つのフォルダにまとめる - Netlifyの管理画面("Drag and drop your site output folder here")にフォルダごとドロップ
- 即座にHTTPSで公開完了
コマンドラインも設定ファイルも一切不要。
この手軽さが、締め切り(年越し)に追われる季節モノ開発には最強の味方でした。
さいごに
こうして、アイデア出しからデプロイまで、実質数時間で「Web除夜の鐘」が完成しました。
サーバーもDBも用意せず、Googleアカウントと静的ホスティングだけで動的なWebアプリが作れてしまう。GASのポテンシャルを改めて感じる開発でした。
奉納をお待ちしています
このアプリは、みなさんの煩悩データが集まることで完成します。
今年のうちに吐き出しておきたいことがあれば、ぜひ「奉納」していってください。匿名ですし、即座にサーバーに送られて、次の誰かの鐘つきで浄化されます。
🔔 鐘つきはこちらから(再掲)
https://joya-no-kane-2025-2026.netlify.app/
※冒頭にも書きましたが、明日1/1中にはサービスを停止してWeb上の鐘もつき納めとする予定です。 今年限りの煩悩、今のうちに全て浄化していってください!
それではみなさん、良いお年を!
