【p5.js 2021（2つ目）】 Leap Motion（leap.js）を p5.js Web Editor上（JavaScript）で扱う

この記事は、[2021年の p5.js のアドベントカレンダー](https://qiita.com/advent-calendar/2021/p5js) の 14日目の記事です。

## この記事の内容
この記事は、以下のツイートに出てきている「Leap Motion」を、p5.js Web Editor上で扱おう、という話です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">久しぶりに触ってみるかな。<br>買ったのは、2013年というデバイス。<br><br>ちなみに、さすがに2013年から眠らせてた、とかいうことはないですw<br><br>●Ultraleap for Developers<br>　<a href="https://t.co/uqC0TNDsnt">https://t.co/uqC0TNDsnt</a> <a href="https://t.co/PixIVuE9pH">pic.twitter.com/PixIVuE9pH</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469828514828668930?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">Facebookで、2013年の6月に出荷絡みの連絡を受信、という投稿をしていたっぽい。 <a href="https://t.co/Usbjqjfv3j">pic.twitter.com/Usbjqjfv3j</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469839851550023684?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Leap Motion の 2021年12月版の情報
### PC側のアプリ
PC側に Leap Motion を扱うためのアプリは、以前から入れていてアップデートをしている状態でした。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">PC側のアプリで、「Webアプリケーションを許可」とかいう設定もあるので、こいつが仲介役なのかな。<br><br>（WebSocket で通信、といった情報がは別で見かけたけれど） <a href="https://t.co/umAFaknykC">pic.twitter.com/umAFaknykC</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469847299958652929?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

PC に、この Leap Motion用アプリが入っていると、以下にあるように `http://127.0.0.1:6437` の WebSocketサーバーが裏で動作するようです。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">「archive」とか URL についている資料に、以下の記載がある<br>------------<br>The WebSocket server listens to port 6347 on the localhost domain (http://127.0.0.1:6437).<br>------------<br><br>●WebSocket Communication — Leap Motion JavaScript SDK v3.2 Beta documentation<br>　<a href="https://t.co/h7iG07giMA">https://t.co/h7iG07giMA</a> <a href="https://t.co/Gvpb0ThhfH">pic.twitter.com/Gvpb0ThhfH</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469848044678316032?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### JavaScriptライブラリ
今回、ブラウザ上の JavaScript で扱うという方向で、最新の状況を確認してみました。
（Unity向けとかは、わりとアップデート情報が公式からアナウンスされてるのですが、JavaScript周りはその辺りが出てない気がしていたので）

そうすると、以下の公式のライブラリの更新が今年時点でも行われている、というのが確認できました（ページ内のリンク切れの情報があったりもしつつ...）。

●leapmotion/leapjs: JavaScript client for the Leap Motion Controller
　https://github.com/leapmotion/leapjs

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">公式ライブラリ、<br>今年、更新が行われていて、バージョン 1.1.1 というのがある。 <a href="https://t.co/Wv2lmF3bTI">pic.twitter.com/Wv2lmF3bTI</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469842185797640194?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

バージョン 1.1.1 というのが、2021年の12月時点での、最新バージョンのようです。

#### CDN
CDN からライブラリを読み込めるかググって探してみたところ、jsDelivr のものが最新版を読み込めるようになっていました。
別の CDN だと、バージョン 1．1．1 よりも古いものが出ていたりした感じでした。

●leapjs CDN by jsDelivr - A CDN for npm and GitHub
　https://www.jsdelivr.com/package/npm/leapjs
<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">CDN経由でミニファイされたファイルを読み込めた <a href="https://t.co/FZH6z7GGvE">pic.twitter.com/FZH6z7GGvE</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469836563597369345?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#### 簡単なサンプル
とりあえず動作確認をしたい、という場合は、以下を動かすと良いようです。
見た感じ、センサーからの情報取得をループでまわし、得られた情報の中から認識できた手の数をログ出力、というもののようです。

![leap.jsのプログラム例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e8556c8e-a689-d365-e812-0eb2fe21a4bb.jpeg)

まずは、p5.js Web Editor上で、この検出できた手の数の情報がとれるかどうかを確認していきます。

## p5.js Web Editor上で Leap Motion を使う
### 下準備
まずは p5.js Web Editor上で、上記の CDN にあるライブラリを読み込みます。
index.html の p5.js のライブラリを読み込んでいる部分の下で、leap.js を以下のように読み込みます。

```html
<script src="https://cdn.jsdelivr.net/npm/leapjs@1.1.1/leap-1.1.1.min.js"></script>
```

この後は、JavaScript のプログラムを書いていきます。

### JavaScript のプログラムを書く
それでは、sketch.js に手を加えていきます。

#### 検出できた手の数の情報をログ出力
上で出てきていた公式ページのサンプルを、少し変えて組み込みます。

ループでセンサーからの情報を得る処理は使いつつ、ループの中での処理を、ログ出力から変数への値の格納に変えます。
そして、 `draw()` の中でログ出力をさせるようにしてみました。

```javascript
let leapFrame;

Leap.loop(function(frame){
  leapFrame = frame;
});

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);

  if(leapFrame) {
    console.log(leapFrame.hands.length);    
  }
}
```

その結果、「0 から 2　の値（「手を検出できない/片手を検出/両手を検出」という意味）」を得ることができました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> Web Editor上で、Leap Motion の JavaScriptライブラリである「leap.js」の動作テスト（2021年12月版）。<br><br>検出できた手の数をログ出力する、というのが無事に動いているっぽい！ <a href="https://t.co/fm3E0cDVRn">pic.twitter.com/fm3E0cDVRn</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469845880807501825?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#### p5.js の描画と連動させてみる
次は、p5.js の処理との組み合わせを簡単に試すことにします。

そのために、以下にある公式サンプルを見ていきます。
　●leapjs/examples at master · leapmotion/leapjs
　　https://github.com/leapmotion/leapjs/tree/master/examples
![公式サンプル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/13758a88-b5ed-86da-de2e-c5e8d599b474.jpeg)

その中の [css-visualizer.html](https://github.com/leapmotion/leapjs/blob/master/examples/css-visualizer.html) の一部を参考に、以下を実装してみました。

```javascript
let leapFrame,
  leapFlag = false;

Leap.loop(function (frame) {
  leapFlag = true;
  leapFrame = frame;
});

function setup() {
  createCanvas(500, 500);
  frameRate(30);
}

function draw() {
  background(220);

  if (leapFlag) {
    if (leapFrame.hands.length > 0) {
      const handId = 0;
      const hand = leapFrame.hands[handId];

      const palmPosX = hand.palmPosition[0];
      const palmPosY = hand.palmPosition[2];
      const palmPosZ = hand.palmPosition[1];
      const posX = map(palmPosX, -250, 250, 0, width);
      const posY = map(palmPosY, -250, 250, 0, height);
      const posZ = map(palmPosZ, 0, 500, height, 0);

      noStroke();
      fill(100, 100, 255, 75);
      ellipse(posX, posY, 50);
      fill(100, 200, 205, 75);
      ellipse(posX, posZ, 50);
      leapFlag = false;
    }
  }
}
```

そして、実際に動作させてみたのが以下になります。
「手を動かす範囲をうつしつつ、ディスプレイをうつして、手がディスプレイの表示側を隠さないように」という調整がけっこう難しかったので、Leap Motion で検出可能な範囲全体では手を動かせていないです...
（あと、部屋の中はうつらないように、というのも合わせると）

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">懐かしの Leap Motion を使い、<br>検出した手の xyz の位置を、 <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> のキャンバス上の座標にマッピングして表示させたものです（とりあえず、片手のみという作りにて動作確認）。<br><br>2つの円のうち、片方は xy と連動していて、残りのほうは xz と連動しています。<br><br>動画を良い感じに撮るの、難しい 笑 <a href="https://t.co/3qMo8VI9E3">pic.twitter.com/3qMo8VI9E3</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1469872383448469509?ref_src=twsrc%5Etfw">December 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

無事に、xyz　のそれぞれの方向への移動を、p5.js の描画につなげることができました。