imadoko の画面
公開中

imadoko

WEB

Overview

URLを共有するだけで現在地をリアルタイムに共有できるWebアプリです。アプリインストールやアカウント登録は不要で、すぐに使い始められます。

Tech Stack

  • Next.js
  • Supabase
  • Tailwind CSS
  • Leaflet

「今どこ?」を1回で終わらせたかった

待ち合わせのたびに「今どこ?」「駅の東口にいる」「東口ってどっち?」とメッセージを往復させるのが、ずっと面倒でした。位置情報を共有できるアプリはすでにいくつもあります。でも、どれも「相手もアプリを入れていて、アカウントを持っていて、友だち登録している」ことが前提です。それに、一度つなぐと常に共有しっぱなしになるものが多く、「今日のこの30分だけ見せたい」という使い方には重すぎます。

imadoko は、その隙間を埋めるために作りました。やることは3つだけです。

  1. 共有を始めたい人(ホスト)がトップ画面のボタンを押す
  2. 表示された URL を LINE などで相手に送る
  3. 相手がそのリンクを開くと、お互いの現在地が同じ地図の上にリアルタイムで出る

アプリのインストールも、会員登録もありません。リンクを開いた瞬間に地図が出て、終わったらホストが共有を止めれば、その URL はもう誰の位置も映しません。共有は「セッション単位の使い捨て」にしてあります。

使ってみるとこうなる

地図の上には、参加している人がそれぞれ色の違う丸いピンで表示されます。ホストには「H」、自分には「ME」、ほかの参加者には番号のバッジが付くので、3人以上で待ち合わせても誰が誰かで迷いません。参加者の一覧から名前を押すと、その人の位置へ地図が飛びます。

地図の見た目は4種類から選べます。国土地理院の淡色地図、OpenStreetMap の日本版、CARTO の Voyager、Esri の航空写真です。駅の構内や大きな公園のように「道路の地図だと分かりにくい場所」では、航空写真に切り替えるだけで話が通じやすくなります。

位置情報の許可が下りていない、電波が悪くて現在地が取れない、といったときは、画面の上に理由ごとの案内を出します。位置共有アプリは「なぜか自分のピンが出ない」が一番のストレスなので、黙って失敗しないことを優先しました。

中身の話

画面は Next.js(App Router)と React、地図は Leaflet で描いています。位置の受け渡しには Supabase を使っていて、データベース(Postgres)の変更をリアルタイムで購読できる Supabase Realtime が、この仕組みの心臓です。

流れはシンプルです。各端末がブラウザの Geolocation API で自分の位置を取り、データベースの参加者の行を書き換えます。ほかの端末はその変更通知を購読していて、届いたらピンを動かします。サーバーで位置を計算したり配ったりする処理は持っていません。

3秒ごとに位置を取り、ほとんど動いていなければ送らない

位置は3秒ごとに取り直しています。ただ、止まっているときでも GPS の値は数メートル単位で揺れるので、そのまま全部送ると、誰も動いていないのに通信だけが増え続けます。そこで、前回送った位置から緯度・経度どちらも約3メートル(0.000027度)以上ずれていなければ、データベースへの書き込みを省いています。

一方で、書き込みを完全に止めてしまうと、今度は「じっと待っている人」と「アプリを閉じて消えた人」が区別できなくなります。そのため、動いていなくても20秒に1回は「まだいるよ」という生存信号だけは送るようにしました。最後の信号から1分以上途絶えた参加者は、ピンを半透明のグレーにして「◯分前」と添えます。消すのではなく薄くするのは、電車の地下区間で一時的に途切れただけの人まで地図から消えてしまうと、かえって不安になるからです。

ピンはワープさせず、600ミリ秒かけて滑らせる

3秒おきに届く位置をそのまま反映すると、ピンがカクッ、カクッと瞬間移動します。見ている側からすると、これが意外と「ちゃんと追えているのか」を不安にさせます。そこで、新しい位置が届いたら、前の位置から600ミリ秒かけて線形に補間しながら動かしています。たったこれだけで、地図の上の人が「歩いている」ように見えるようになりました。

自分のピンについては、データベースへの保存を待たずに先に画面を更新しています(楽観的更新)。サーバーの返事を待ってから動かすと、自分の位置なのに一拍遅れて追いかけてくる感じになるからです。

タブを閉じた人を、ちゃんと退室させる

位置共有で地味に難しいのが「いなくなった人の後始末」です。ボタンを押して退室してくれれば簡単ですが、実際にはタブをそのまま閉じる人がほとんどです。imadoko では、ページが閉じられる瞬間(pagehide)に navigator.sendBeacon で退室の通知を送っています。通常の通信はページが閉じた時点で打ち切られてしまいますが、sendBeacon はブラウザが閉じたあとも送り届けてくれます。

ここで困ったのが「リロード」です。リロードも一度ページを閉じるので、退室の通知が飛びます。そして読み込み直したページはすぐに再参加しようとします。この2つが競合すると、再参加した直後に遅れて届いた退室処理で自分が消える、ということが起きました。今は、閉じた時刻を記録しておき、3秒以内の再参加なら少し待ってから参加し直すようにしています。さらに、位置を送ったときに「あなたの行はもうありません」と返ってきたら、自動で参加し直す自己修復も入れてあります。

書き込めるのは、合言葉を知っている本人だけ

参加者の行をブラウザから直接書き換えられる作りにすると、URL を知っている人なら誰でも他人のピンを動かせてしまいます。そこで、データベースのテーブルへの直接の書き込みは行単位のセキュリティ(RLS)ですべて拒否し、書き込みは参加時に発行した秘密のトークンを確かめる関数(RPC)経由でしかできないようにしています。トークンはその端末のブラウザの中にだけ保存され、ほかの参加者には一切渡りません。ゲストが「ホスト」を名乗ることもできないようにしてあります。

作り直してきた記録

最初の版は2025年の8月から9月にかけて作りました。そこから何度か手を入れていて、大きかったのは2026年3月の作り直しです。参加・退室まわりの競合を潰すために、何度も「正しく動いていた状態」に戻しながら少しずつ直していきました。コミット履歴に「Revert」と「復旧」が並んでいるのは、その格闘の跡です。

2026年6月には、ホスティングを Vercel から Cloudflare Workers へ移しました。imadoko には退室通知を受けるための API ルートがあるので、静的なファイルとして書き出すことができません。そこで OpenNext を使い、Next.js をそのまま Workers 上で動かしています。同じ時期に、前回の共有に戻れる「前回の共有に戻る」ボタンや、利用規約・プライバシーポリシーも整えました。

これからやりたいこと

  • 共有リンクに有効期限を付ける
  • 動いていないときは位置を取る間隔を延ばして、電池の減りを抑える
  • 通信が切れている・つながっている、を画面ではっきり示す
  • 英語などほかの言語に対応する
  • ホーム画面に追加して、アプリのように開けるようにする(PWA)

待ち合わせの「今どこ?」は、一度使うとメッセージで聞く気がなくなります。次の待ち合わせでぜひ試してみてください。

imadoko を触ってみる

URLを共有するだけで現在地をリアルタイムに共有できるWebアプリです。アプリインストールやアカウント登録は不要で、すぐに使い始められます。

ほかの制作実績