socket.ioでkintoneにいたずらした話 – CybozuDays2025 HAW”AI”I? –

CybozuDays2025、ジョイゾーブースには遊びに来ていただけたでしょうか。ジョイゾーTech.チームです。

ジョイゾーTech.チームは、ジョイゾーブースにテックでハックな展示をいくつかさせていただきました。

さらに、展示用のPCで真面目にサービスのご紹介をしているところに、画面をハックしていたずらをしてやろうじゃなか、ということで、5台の画面にキャラクターが順番に走り回るというカスタマイズをしてみました。
単に動きだけでなく、スケジュールやアニメーションの制御にいろんな技術を組み合わせているので、その裏側を紹介します。

(noteでもご紹介してます)

企画のポイント

  • サイボウズデイズでの展示として、来場者に楽しんでもらえるよう “キャラクターが走り回る” いたずらを用意。
  • kintone アプリを「タイマー/スケジュール管理」に利用し、演出開始時間や長さを誰でも設定できるように。
  • Node.js + Socket.io でリアルタイム通信。WebSocket を使うことでサーバーとブラウザ間で双方向のイベント通信を実現。
  • HTML5 Canvas とアニメーションを駆使し、ローカルにある 5 台の PC それぞれに別々の役割を持たせ、キャラクターの動きを制御。
  • ログ監視や PM2 を利用した運用で長時間稼働でも安定。


kintone をタイマーにして演出を制御

今回の仕組みでは、演出の開始時刻と持続時間を kintone のアプリにレコードとして登録し、その情報をサーバーが定期的に取得します。
取得したレコードには演出の開始時刻(起動日時)と長さ(演出時間)が含まれており、サーバーはこの情報を見張って「そろそろ演出を始める時間だ!」と判断したらクライアントに通知を送ります。

実際のコードでは、axios を使って kintone からレコードを取得し、未来の予定だけを Map に登録しています👇

async function fetchScheduledActivations() {
  const url = `https://${KINTONE_CONFIG.subdomain}/k/v1/records.json`;
  const params = { app: KINTONE_CONFIG.appId, fields: ['起動日時', '演出時間'] };
  const response = await axios.get(url, {
    params,
    headers: { 'X-Cybozu-API-Token': KINTONE_CONFIG.apiToken }
  });
  const records = response.data.records || [];
  scheduledActivations.clear();
  records.forEach(record => {
    const startTime = new Date(record['起動日時'].value);
    const duration = record['演出時間']?.value || '60秒';
    if (startTime > new Date()) {
      scheduledActivations.set(startTime.getTime(), duration);
    }
  });
}

こうしておくことで、展示直前になっても kintone から最新情報を取りに行き、予定表を更新できる柔軟性があります。


Node.js + Socket.io で WebSocket 通信

サーバーは Node.js と Express で構築し、リアルタイム通信には Socket.io を利用しました。
Socket.io は「ブラウザとサーバー間でリアルタイム・双方向・イベントベースの通信を可能にするライブラリ」で、クライアントとサーバー双方がイベントを emit / on でやり取りします。

この仕組みにより、5台の PC(sub1〜sub5)でキャラクターが蛇行しながら順番にバトンを受け取る演出が可能になりました。
WebSocket が使えない環境では自動的に HTTP ロングポーリングにフォールバックするため、会場のネットワーク事情にも柔軟に対応できました。


フロントエンド:Canvas とアニメーション

各 PC には kintone のカスタマイズとして全体JavaScriptを配置し、HTML5 Canvas 上でキャラクターを描画しています。
各クライアントは roleId という値で自分の役割(main か sub1〜sub5)を決め、Socket.io 経由で受け取ったイベントに応じて動きます。

socket.on('characterSnakeMove', (data) => {
  console.log('=== characterSnakeMove イベント受信 ===');
  if (renderer.getState().isAnimating) return;
  renderer.enableCharacter();
  renderer.animateSnakeMoveAcross(() => {
    socket.emit('snakeMoveComplete', { roleId: roleId });
  });
});

アニメーションが終わると snakeMoveComplete イベントを送ることで、サーバーが次のクライアントにバトンを渡す仕組みになっています。
Canvas 上では PNG や GIF のキャラクター画像を読み込み、透過やフレーム管理を工夫して軽快な動きを実現しました。


ログ監視と運用

長時間稼働を安定させるために PM2 で Node.js プロセスをデーモン化し、ログを出力・分析しました。
analyze_logs.sh で以下のような項目を自動解析しています。

  • エラー発生回数
  • 接続/切断イベントの回数
  • メモリ使用量の増加傾向(リーク検出)
  • サーバー無応答時間の検出

展示期間中も安定稼働し、kintone のスケジュール情報に基づいて確実に演出が実行されました。


まとめ

「いたずらデイズ」は JOYZO のTech.チームが 遊び心を大切にしながら技術を組み合わせたプロジェクトでした。
kintone をタイマーとして活用し、Socket.io と Node.js でリアルタイム通信を行うことで、5台の画面が連動する演出を実現。

キャラクターの動きやログ解析まで含めるとかなりテッキーですが、来場者の楽しそうな反応を見るとすべて報われます。

今後もこうした「遊び × 技術」のチャレンジで、チームの価値を発揮していきます!来年もまたCybozuDaysでお会いしましょう!

同じカテゴリーの記事