東洋大学赤羽台祭におけるシステム部の取り組み

はじめに
さくらのナレッジ編集部の法林です。
さくらインターネットはさまざまなITコミュニティの活動を支援しています。その一環として、東洋大学赤羽台祭という大学祭にサーバを提供しました。そこで本記事では、2025年11月2日〜3日(日月)に開催された第9回赤羽台祭にて使用したシステムについてご紹介します。赤羽台祭実行委員会システム部の皆さんにご説明いただきました。
取り組みの全体像
今回ご紹介いただいたシステムは以下の5つです。
- Webサイト
- ARスタンプラリー
- 企画コンテスト
- プログラミング体験
- 脱出企画
以下、順に説明します。
Webサイト
Webサイトの役割は、大学祭の情報(アクセスや企画情報など)を集約して来場者に見せることです。Webサイトが備える機能としては、すべての企画の一覧表示、各企画の詳細(場所や注意事項など)の表示、各企画のソート表示などがあります。
Webサイトで使用している技術としては、フロントエンドにはNext.jsを使用し、構築したサイトをSSG(Static Site Generation)により静的なコンテンツに変換して読み込む方法を採用しています。そして、書き出した静的なコンテンツを配置する場所として、さくらインターネットから提供されたサーバ(さくらのレンタルサーバ)を利用しています。このような構成にするとアクセスがあるたびにデータベースへ問い合わせする必要がないため、大量のアクセスが来ても高速かつ安定してサイトを表示できます。特に大学祭の当日は多くの人がWebサイトを利用するので、急激なアクセス増加に耐えるように信頼性を重視した結果、この構成を採用しました。
構築における工夫は2点あります。1つは開発プロセスの効率化で、Claude AIを利用してコードレビューを自動化する仕組みを導入しました。昨年までは大学の先輩方がコードレビューをしてプルリクエストを通すという感じで作業に時間がかかっていましたが、それを効率化しようということで、Claude AIにレビューをしてもらいました。もう1つの工夫はUI/デザインの統一です。Storybookを導入し、UIコンポーネントの開発と確認を容易にしました。大学祭のサイトを全体的に同じような雰囲気のデザインにするためにデザインの統一性を重視し、そのためにStorybookを使って統一感を保ちつつ効率的に実装できるようにしました。
開発する中で苦労した点は3つありました。1つ目は開発スピードを上げるために挑戦したAI運用です。大規模な開発を短期間で行うためにClaude AIを導入し、GitHubと連携させてプルリクエストを自動で行えるようにしました。AIを活用することで、ベストプラクティスに基づいた助言など一定の効果を上げることができました。しかしAIはコード単体のチェックはできても、どうしても人間によるレビューには及ばないところがあります。そのためAIによる指摘を鵜呑みにすることはできず、結局は経験のあるメンバーがすべてのコードを二重にチェックする形になってしまいました。AIによるレビューと人力によるレビューをどのように共存させるのがよいかは今後の課題です。
2つ目はドキュメントと標準化です。ドキュメント化に膨大な工数がかかり、開発を優先すべきかドキュメント化を優先すべきかというバランス調整に苦労しました。しかし苦労した甲斐あってWebサイトのデザインは良いものになり、多くの人から高い評価をいただいたのはよかったと思っています。
3つ目は技術というよりも現場の運用で苦労した点ですが、企画情報の修正です。Webサイトは大学祭の顔であり、掲載される企画情報は正確であることを重視しています。そのため届いたデータを一つ一つ手作業で確認と反映を行っていました。この作業が長期化し、Webサイトの公開直前まで続いたため、非常に大きな負担がかかりました。情報の集約と反映をシステマチックに行うことが課題として浮き彫りになりました。
ARスタンプラリー
ARスタンプラリーは大学構内、および私たちの大学の校舎がある赤羽駅周辺の商業施設に設置されたARマーカーを巡り、デジタルスタンプを集める回遊型の企画です。体験の概要としては、体験者が自身のスマートフォンでマーカーを読み取り、画面上に現れるARをスワイプすることでポイント(1ptもしくは2pt)を獲得します。獲得したポイントに応じて景品交換の抽選権が得られる仕組みとなっており、より多くの場所を巡ることでより高価な景品が当たる上位の挑戦権へとステップアップできます。
ARスタンプラリーのシステムの核となるのは、ブラウザ上で動作するマーカーベースARです。A‑FrameとAR.jsを組み合わせて構築することで専用アプリのインストールを不要としています。来場者がQRコードを読み込んでから数秒で体験を開始できる手軽さを最優先しました。機能面では、単に画像を表示するだけでなく、画面上のスワイプ検知でスタンプ取得のアクションを判定する仕組みや、参加者のスタンプ取得やポイント獲得状況をリアルタイムに集計し、景品交換を行うロジックを実装しています。また、デザインにはTailwind CSSを使用し、統一されたヘッダー・フッターとルック&フィールの調整を行いました。
使用している技術を紹介します。ARのコアとなる描画エンジンにはA‑FrameとAR.jsを採用しました。また、高度な演出を実現するためにA‑Frameの内部APIを通じてThree.jsを直接制御し、動的なスプライトシートアニメーションを実装しています。これにより、1pt地点では静止画AR、2pt地点ではキャラクターが動くスプライト画像が表示されるなど、場所による体験の差別化を実現しました。UIデザインはTailwind CSSを活用し、Webサイト本体と統一したルックにしました。それからデータの永続化が必要なのでlocalStorageを利用して、クライアント側でスタンプ情報や景品交換履歴、モーダル取得情報などを保持し、同じ人が2回目の訪問を行った時にも情報を使用できるようにしました。この他に、モーダルの表示にはMicromodalやdialog-polyfill、アクセス情報の分析にはGoogle Analyticsを使っています。スタンプラリーのWebサイトもさくらのレンタルサーバ上に設置しています。
ARスタンプラリーの構築・運用においてもさまざまな工夫をしました。今回のAR体験において視覚的な楽しさを生み出しているのは動的AR演出です。A-Frame拡張コンポーネント(sprite-sheet/marker-sprite-control)を使って実装することでスプライト画像の切り替えとリセットを行い、マーカー上にキャラクターが浮き出てくるような没入感のあるアニメーションを実現しています。次に、システム内部でデータの整合性を保つために安全なスタンプロジックを構築しました。スタンプには1ptと2ptの2種類がありますが、同じグループのマーカーを複数回読み込んだ場合でも、JavaScript側で常にそのグループ内での最高ポイントのみを加算するように制御しています。
それから本システムは屋外でも使うので、誤操作を抑制するためにglobal-swipe-handlerを実装し、カメラが現在どのマーカーを追跡しているかを常に監視しました。マーカーが正しく認識されているときのみ入力を受け付けることで、意図しないタッチやスワイプによる誤操作を最小限に抑えました。こうすることで来場者が快適にスタンプを獲得する環境を作り上げています。さらにもう1つ、リピーターへの配慮として、再訪問時の体験をスムーズにする工夫をしています。初回起動時に表示される注意喚起モーダルの既読情報をlocalStorageで保持し、2回目以降の訪問時には不要な説明をスキップするようにしました。
それからモーダルの汎用化にも取り組みました。複数の案内を連続して表示する箇所ではtransitionModalに集約し、ナビゲーションの「戻る」「進む」といった挙動をシンプルに共通化することで、コードの肥大化を防ぎつつ一貫した操作性を提供しています。最後にスタッフ向けフローの工夫として、システムは来場者だけでなく現場のスタッフにとっても使いやすいものであるべきだと考え、景品交換モーダルではユーザーが保有しているポイントを自動集計し、現在のポイントでどの景品と交換可能か、あるいはすでに交換済みかというステータスを即時に反映しました。
ARスタンプラリーの開発で苦労した点としては、AR画面上での正確なスワイプ検出やThree.jsを用いた動くスプライト画像の表示、1ptから2ptに上書きするときの安全なロジック構築などがあります。体験設計面では、屋外での誤操作を防ぐUI配置や、初見でも迷わない説明モーダルの実装など、Web技術を現実空間で快適に動かすための最適化に注力しました。
企画コンテスト
企画コンテストは、来場者が楽しいと思った企画に投票してもらい、人気企画を表彰するものです。体験の流れとしては、複数の部門に分かれた企画の中から来場者1人あたり3票という投票権を持って投票します。投票後には主催者側で各部門の企画表彰を行います。来場者にとっては推し企画を応援できますし、企画を考える人達もこれのために頑張ることで大学祭の盛り上げになればと考えて実施しました。
企画コンテストのシステム概要を以下に説明します。このシステムは2つに分かれています。1つ目が来場者向けインターフェースで、スマートフォンから直接操作できるように各企画を見やすくカード形式で一覧表示しました。膨大な企画の中から自分が体験したものを検索などで見つけ出し、タップで選択して投票できるUIになっています。もう1つはスタッフ向けの画面です。まず企画の登録、一覧、編集などが行える管理画面があります。それから投票結果を可視化し、全体や部門ごとに面グラフ形式で表示する画面も用意しました。これによってどのような投票がなされているかを一目で把握できるようにしました。なお、投票はイベント会場内でのみ可能とするため、それ以外の場所からのアクセスを制限するような簡易のBasic認証を設けています。
このシステムのインフラは、Cloudflare Workersを利用したサーバーレスな構成にしました。多数のエッジサーバを持つCloudflareを利用することで、来場者が集中しても高速なレスポンスを維持することができました。もう1つの技術的ポイントはCloudflare D1という、CloudflareネイティブなSQLデータベースです。これはCloudflare Workersとの親和性が高いため採用しました。
アプリケーションはNext.jsを用いて開発しました。@opennextjs/cloudflareを使うことでCloudflareの環境に最適化してデプロイしました。また、D1データベースを効率的かつ安全に操作するためにTypeScriptを採用しました。デザインは一貫性を保つためにTailwind CSSを使用しました。それから投票結果の面グラフの描写にはRechartsというグラフ描画ライブラリを使用しました。これのおかげで、複雑な集計データを直感的に美しいグラフへ変換できるようになりました。(下図参照)
このシステムの構築・運用において一番がんばったのはこの部分です。従来からシステムはありましたが、そこで行っていたのは投票と単純な集計だけで、これでは運営側の負担が大きい上にデータも無駄になってしまうため、ここを改善することを試みました。対策として今年度は企画のマスターデータ管理から投票結果のグラフィカルな可視化までをすべてシステム上でできるようにしました。上図のように現在どの企画に投票が集まっているかがリアルタイムで可視化されることで、運営スタッフのモチベーション向上にもつながり、表彰式の演出プランも投票結果をもとに迅速に対応できるようになりました。
苦労した点としては情報の多重管理があります。企画情報はシステムの中に存在するだけでなく、Webサイトや来場者に配布するパンフレットなどにも使用しています。ここで企画内容の変更があると、これらの情報もすべて手動で更新する必要がありました。システムを便利にするために導入したはずなのに、情報の整合性を保つための手動オペレーションが増えてしまうという問題に直面しました。今後は情報の一元管理を目指したいと思います。
プログラミング体験
プログラミング体験は来場者にプログラミングやWebサイト制作を体験してもらう企画です。体験の流れとしては、PythonによるタートルグラフィックスやHTML/CSSによるWeb制作を行う教材を用意し、来場者に基本的なコーディング体験をしていただきます。体験後は制作した作品がデータベースに保存され、来場者には作品閲覧用QRコード付きの記念カードを配布して、後ほど自宅などで作品を家族や友人に披露できるようにしました。
システムとして用意したものは、まず来場者向けの教材ページです。教材の中にコードの書き方などを表示しながら、Pythonコード記述エディター、Pythonコード実行、タートルの描写機能を付け、体験者が分かりやすく教材を学べるようにしました。次に作品表示ページです。これはWeb制作作品とタートル作品の表示ができるようにしました。最後にスタッフ向け機能として作品の登録ページおよび管理画面を用意しました。
このシステムで使用している技術としては、インフラ・ミドルウェアはコンテスト企画でも使用したCloudflare WorkersとCloudflare D1、アプリケーションはNext.jsと@opennextjs/cloudflare、CSSはTailwind CSSとdaisyuiを使っています。それからブラウザ上でのPython実行環境を構築するためにPyodideを採用しています。通常、Pythonのタートルグラフィックスはデスクトップ向けのGUIに依存していますが、今回はブラウザで動作させるために導入しました。また、Monaco EditorというVS Code風のエディタを教材に埋め込み、入力補完など本格的な開発体験を提供しました。最後に、保存された作品を閲覧する際にPythonコードを美しく表示するためのシンタックスハイライトとしてshikiを使用しています。
構築・運用における工夫としては、来場者が作成した作品をカードとQRコードという物理的な記念品で持ち帰ってもらうという点に注力しました。教材の作成においては、教材をステップごとに分け、初心者にもわかりやすい構成にしました。最後に、現場で来場者から得たフィードバックを即座にシステムに反映するというアジャイルなアプローチを採用しました。
苦労した点としては、PythonやタートルグラフィックスをWebブラウザ上で動作させるためのバンドラー設定があります。PyodideやMonaco Editorは重いので、これらをNext.jsで動作させるための複雑な設定に時間を費やしました。また、参加対象者のターゲット層が定まっていなかったので教材が必ずしも参加者に適したものになっておらず、改善の必要性を感じました。
脱出企画
最後に紹介するのが脱出企画です。これは、Web技術と学内のIoT設備を連携させ、没入感のある体験を実現した脱出ゲームです。体験者は出題された謎を解き、iPadに答えを入力します。それが正解だとドアが開放され、次のステージへ進行するという仕組みになっています。
システム概要としては、まず進行・演出機能として、体験者が手元のiPadに解答を入力したり、隠されたQRコードをスキャンするなどの挙動に応じて、照明を明るくするなどストーリーシーンを遷移させます。また進行状況に合わせてSEや動画を自動的に再生するなどの演出も行います。次はIoT・物理連携で、体験者の入力アクションに応じて学内IoT設備の制御を行います。最後にモニタリング機能として、センサーによる体験者の動きの検知や、検知と連動したペナルティの付与(残り時間の減算)などを実装しました。
使用した技術は、体験者が使用するiPadの画面はNext.jsで構築したものを静的ファイルにし、さくらのレンタルサーバに配置しています。バックエンドはFlaskとOpenCVを利用しています。これは会場内のPCで稼働しており、PCに接続されたカメラ映像をOpenCVで解析し、体験者の動きをリアルタイムで検知しています。学内IoTとの連携については、ドア開錠や照明の制御は学内専用のIoT設備のAPIを使って行いました。セキュリティ上の観点から自己署名証明書を使用してローカル環境全体をHTTPS化し、0.1秒間隔の高速ポーリングでリアルタイム同期を実現しました。
構築・運用における工夫で最も苦労した点は、ネットワーク制約への対応とリアルタイム性の確保です。学内ネットワークからしかアクセスできないIoT設備があるため、iPadのブラウザからサーバを介さずにIoTのAPIへ直接リクエストを送る方式を採用しました。また、リアルタイム性を確保するために新たなWebSocketサーバを構築せず、フロントエンドからFlaskへ0.1秒間隔でポーリングすることで同期を実現しました。
苦労した点としては、開発中に企画側から要件変更があり、開発もそれに応じて修正する必要が生じたことです。当初はタブレット(ブラウザ)とモニタリングシステム(会場PC)をそれぞれ別物として稼働することを想定していたのですが、要件変更によりタブレット(ブラウザ)とモニタリングシステム(会場PC)を接続することが必須になりました。また、フロントエンドはHTTPS、ローカル環境はHTTPで通信しており、どこかでプロトコルを合わせる必要も生じました。これについては自己署名証明書を用いてローカル環境全体をHTTPS化することで解決しました。
おわりに
システム部のメンバーは総勢17人だそうで、そのメンバーが分担してこれらのシステムを構築しました。システム構築は6月ぐらいから開始し、企画に関するシステムは9月ぐらいから制作に入ったそうです。大学祭の本番が11月初頭であることを考えると2か月ぐらいしかないのでかなり短期間です。人数がある程度いるとは言うものの、なかなかハードな作業だったのではないかと思われます。
そのような短期間の中でこれだけ多くのシステムを作り、また新しい技術も数多く使っていることに感心しました。開発はローカル環境で行い、さくらのレンタルサーバを公開用サイトとして利用するという策も、コストを安く抑えることができるという点で良いと思いました。
ちなみに東洋大学の赤羽台キャンパスには情報連携学部(INIAD)という学部があり、システム部の皆さんはそこの学生が中心です。最先端の技術を学んだ学生の皆さんが社会に出てどのような活躍をするのか、とても楽しみです。このたびは取材にご協力いただきありがとうございました。