p5.toioのα版リリースについて

# サマリ
[p5.js](https://p5js.org/)の環境で[toio™](https://toio.io/)のプログラミングを簡単に楽しめるライブラリ[p5.toio](https://github.com/tetunori/p5.toio)の[α版（v0.5.0）をリリース] (https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.min.js)いたしました。https://github.com/tetunori/p5.toio
<img src="https://tetunori.github.io/p5.toio/images/logo-a.png" width="600px">  

ブラウザからアクセスするだけで、下記の様なサンプルをすぐに確認・制作できます。
toioのCubeと、p5.js及びp5.toioの多様なライブラリ群を利用することで、今まで画面内に閉じていたプログラミングの表現を簡単に現実世界へと拡張することが出来ます。
芸術作品だけでなく、プロトタイプ作成や、デーリーコーディング、ゲーム制作、小学生からのテキストプログラミングなど色々と使ってみてください。（α版なので、いろいろ制約事項有ります。）

[P5 Editor](https://editor.p5js.org/)でもすぐに始められますよ!（[OpenProcessing](https://www.openprocessing.org/)は非対応:sob:）
**[P5 Editor: p5.toio basic sample](https://preview.p5js.org/tetunori/present/x-m5aIlWp)**

# 成果物
minifyした成果物は[こちら](https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.min.js)ですが、[TypeScriptで書いた元のソースコード群](https://github.com/tetunori/p5.toio)もどうぞ。
※詳細は後述ですが[API Reference](https://tetunori.github.io/p5.toio/)もあるよ。
いずれもMIT Licenseです。

# 開発モチベーション
## 課題
toio™Core Cubeを使って趣味で色々なものを作ってきて、下記の課題を感じています。

- 手軽に開発できない
  - Node.jsはまだ導入が簡単な部類だが、とはいえ『`yarn`/`npm install`実行したのに、なんか動かない』問題でどれだけの人類の心を折ってきただろうか。ほんとの初心者にはつらいと思う。
- toio™Visual Programmingは手軽だけどスケールしない
  - コピペできない、成果物をシェアしにくい、凝ったロジックを作ると膨大なブロック数になり、メンテは・・・
  - 別途アプリ立ち上げが必要だったり、始めるまでにステップ数が最小ではない
- 個人的にはWebBluetoothを良く使うが、手続きが多くてしんどい
    - 俺はただ、ランプをつけたいだけなのに、なぜこんなにコード行数必要なのだ？何回Promiseさせるんだい・・・と。
    - ↑WebBluetoothは悪くなく、クラス化していない自分が悪い。
- toioの制御ライブラリがプリミティブなものしか存在しない。
    - もう`Math.atan2`の計算したくない。
- 成果物をシェアするのに、毎回GitHubリポジトリ作るのは面倒だな
- JSの開発環境に関する知識が周回遅れになってしまっていて、話題についていけないので、モダンな開発手法に再チャレンジしたい

## きっかけ
全然別の話題ですが、最近Daily Coding勢のツイートがよくタイムラインに表示されており、[P5 Editor](https://editor.p5js.org/)や[OpenProcessing](https://www.openprocessing.org/)などのオンラインツールを使って、**気軽に**楽しそうにプログラミングをし成果物をシェアされていました。  
早速僕も[p5.js](https://p5js.org/)の勉強がてらOpenProcessingで色々作っては公開する日々を続けてみましたが、これは良い。  
本当に気軽だし、p5.jsのライブラリも多いのでエンドレスなやりこみ要素もある。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">任意の次数のベジエ曲線を描けるようになりました。より高次の表現は複雑だが美しい。<br><br>HigherBezier<a href="https://t.co/BroWbhMnDC">https://t.co/BroWbhMnDC</a><a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> <a href="https://twitter.com/hashtag/creativecoding?src=hash&amp;ref_src=twsrc%5Etfw">#creativecoding</a> <a href="https://twitter.com/hashtag/GenerativeArtWithMath?src=hash&amp;ref_src=twsrc%5Etfw">#GenerativeArtWithMath</a> <a href="https://t.co/Qilk6nkgya">pic.twitter.com/Qilk6nkgya</a></p>&mdash; Tetsunori NAKAYAMA | 中山 哲法 (@tetunori_lego) <a href="https://twitter.com/tetunori_lego/status/1243812382490558471?ref_src=twsrc%5Etfw">March 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この手軽さでtoioもプログラミングできないか？と思い、P5 EditorでWebBluetoothを仮実装してみたところうまく動作したので、課題を解決するソリューションを作ってみようと奮起した次第であります。

## 課題解決の方針
下記を満たす、JSライブラリ`p5.toio`を作成する

- URLにアクセスするだけで、手軽に始められる、使える、創れる。 ⇒ toio™初心者歓迎
- [P5 Editor](https://editor.p5js.org/)で動作する ⇒ URLで作品シェアできる。
- `WebBluetooth`でスマホ・PC問わず、広く使える
- 面倒な処理はぜーーーんぶラップしてAPI提供 ⇒ 『追いかけっこ』すら1行とか。
- JSのClass, ES6記法, TypeScript, ESLint, Prettier, TypeDoc, Jest, Docusaurus など自分にとって新しい技術領域にチャレンジする。

# p5.toioのライブラリ構成
**p5.toio**は2つのクラス`P5tCube`と`P5tId`から構成されています。  
`P5tCube`クラスは、キューブを簡単にコントロールするためのたくさんのAPIやユーティリティを提供します。詳細は[P5tCube Interface](https://tetunori.github.io/p5.toio/docs/cube/classes/p5tcube)でご確認ください。   
また、`P5tId`クラスは、toio™のマットやカード、ステッカーなどに印刷されているtoio™IDについてのAPI・プロパティ群となっています。こちらも、[P5tId Interface](https://tetunori.github.io/p5.toio/docs/id/classes/p5tid)をご参照ください。

なお、今回説明した2クラスは`p5.js`に特化する形でライブラリ化していますが、この2つのクラス以外は通常の`WebBluetooth`でもほぼ同等の機能が使用可能なので、そちらもぜひご利用ください。

# 使い方
## 動作環境
### toio™Core Cube
少なくとも1つは必要です。最近単売が始まったので、お手軽に導入できますね。Chargerも忘れずに!
また、**本ライブラリを使う際は、スマホアプリから最新のFWへアップデートを御願いします**。

- toio™コア キューブ
  - [Amazon](https://www.amazon.co.jp/dp/B085TTFQTH), [スイッチサイエンス](https://www.switch-science.com/catalog/6300/)等  
- toio™コア キューブ専用充電器
  - [Amazon](https://www.amazon.co.jp/dp/B085TTG74K), [スイッチサイエンス](https://www.switch-science.com/catalog/6301/)等  

### PC環境
本ライブラリは`WebBluetooth`へ依存しているため、下記の環境での動作となります。

- OS: Windows, MacOS, Android。iOS/iPadOSは非サポート。  
- Browser: Google Chromeを強く推奨。

また、[P5 Editor](https://editor.p5js.org/)では動作確認できていますが、[OpenProcessing](https://www.openprocessing.org/)は残念ながら、動作出来ませんでした。(iFrameでSketchが動く都合、`WebBluetooth`に必要なユーザーアクションが不正と判断されるため)

## ライブラリのインポート
`<head>`の中で、2つの`p5.js`スクリプト`p5.js`と`p5.sound.min.js`の後に、1行読み込んでください。

```html 
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/addons/p5.sound.min.js"></script>

<!-- INSERT HERE -->
<script src="https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.min.js"></script>
```
Minifyする前のライブラリも一応あるので、そちらでもOKです。 
 
```html
<script src="https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.js"></script>
```

## スケッチで使う
### 1. Cubeと接続しよう
API `P5tCube.connectNewP5tCube()`をコールして、`Promise`で`resolve`された、`P5tCube`インスタンスを受け取ってください。これだけで、すべてのAPIにアクセス可能です！簡単！
なお、このAPIは`WebBluetooth`に依存しておりますので、接続の処理は必ず、ユーザーアクションの関数`mouseClicked()`や`keyPressed()`などで実施してください。さもなくばエラーが出てしまいます。  

```javascript
const gCubes = [];

function mouseClicked() {
  P5tCube.connectNewP5tCube().then( cube => {
    // 'cube' is an instance of connected toio™Core Cube.
    // Now you can call any API!
    gCubes.push( cube );
  } );
}
```
**[P5 Editor Sample 1: Turn Light On](https://editor.p5js.org/tetunori/sketches/gkMCIKNk-)**

### 2. APIを発行しよう
#### 使用例 1: ランプを点灯する
`P5tCube`インスタンスがあれば、API発行は簡単です。
得られたインスタンスが`cube`だとして、ランプを白につけてみましょう。

```javascript
// Turn the light on with white
cube?.turnLightOn( 'white' );
```
Done. これだけ。 
**[P5 Editor Sample 1: Turn Light On](https://editor.p5js.org/tetunori/sketches/gkMCIKNk-)**

こんな感じで、全ての機能にアクセスできますので、詳しくは、下記の~~TypeDoc~~ API Referenceを参照してください。~~後日、ちゃんとした説明のドキュメント作成します。~~ (2020/05/23更新済)
- [P5tCube](https://tetunori.github.io/p5.toio/docs/cube/classes/p5tcube)
- [P5tId](https://tetunori.github.io/p5.toio/docs/id/classes/p5tid)

#### 使用例 2: MIDI メロディーを再生する
```javascript
// Play sequence C-D-E
cube?.playMelody( [ 
  { note: 0x3C, duration: 0x1E }, 
  { note: 0x3E, duration: 0x1E }, 
  { note: 0x40, duration: 0x1E } 
] );
```
**[P5 Editor Sample 2: Play MIDI melody](https://editor.p5js.org/tetunori/sketches/yfFYiyMRx)**

#### 使用例 3: マウスのX座標の方を向く
複数のキューブをtoioCollectionの土俵マットの右上においてください。複数のキューブがマウスのX座標の方を追いかけて回転します。

```javascript
// Keep on gazing at mouse point
for( const cube of connectedCubeArray ){
  const x = Math.floor(mouseX * 300 / windowWidth + 200);
  const y = 144;
  const speed = 115; 
  cube?.turnToXY( x, y, speed );
}
```
**[P5 Editor Sample 3: Keep on gazing at mouse point](https://editor.p5js.org/tetunori/sketches/HNZniaSdx)**

#### 使用例 4: 2つのキューブのインタラクション
2つのキューブをtoioCollectionの土俵マットの上においてください。

```javascript
// Keep on gazing at the othre Cube
const speed = 115;
cubeP?.turnToCube( cubeQ, speed );
```
**[P5 Editor Sample 4-1: Keep on gazing at the other Cube](https://editor.p5js.org/tetunori/sketches/wsYXbuRL5)**

```javascript
// Keep on chasing the othre Cube
const moveType = P5tCube.moveTypeId.withoutBack;
const speed = 80;
cubeP?.moveToCube( cubeQ, speed, moveType );
```
**[P5 Editor Sample 4-2: Keep on chasing the other Cube](https://editor.p5js.org/tetunori/sketches/gSg6D4zGC)**

#### 使用例 5: カラータイルのマット
キューブをtoioCollectionのカラータイルマットの上においてください。

```javascript
  // Set background color with touched colored tile on mat
  const color = P5tId.ColorTileMat.getTileColor(cube?.x, cube?.y);
  background( color );
```
**[P5 Editor Sample 5: Change background color with touched mat color](https://editor.p5js.org/tetunori/sketches/cHerL4iap)**

### 3. Eventを受信しよう
本ライブラリでは、各種通知の取り扱い方法として、`addEventListener`と、`p5.js`っぽいコールバック関数の定義(`mouseClicked()`や`keyPressed()`等と一緒)の両方をサポートしております。

#### 使用例 6: addEventListner
```javascript
// Button press event
const type = 'buttonpress';
cube?.addEventListener(type, ()=>{
  console.log(type);
});
```
```javascript
// Posture change event
const type = 'sensorposturechange';
cube?.addEventListener(type, (posture)=>{
  console.log(type, posture);
});
```
**[P5 Editor Sample 6: addEventListner](https://editor.p5js.org/tetunori/sketches/xTCH-scLp)**

#### 使用例 7: コールバック関数定義
もしこれらの関数が定義されていたら、通知が発生次第コールバックされます。

```javascript
const cubePositionIdChanged = (info) => {
  console.log('cubePositionIdChanged!', info);
}

const cubeStandardIdChanged = (info) => {
  console.log('cubeStandardIdChanged!', info);
}
```
**[P5 Editor Sample 7: Callback definition](https://editor.p5js.org/tetunori/sketches/tlc8-qE9d)**

以下に全てのコールバック関数定義をリストアップします。

```javascript
const onButtonPressed()
const onButtonReleased()
const onBatteryLevelChanged(batteryLevel: number)
const onFlatChanged(flat: boolean)
const onCollisionOccurred()
const onDoubleTapped()
const onPostureChanged(posture: string)
const onPositionIdChanged(info: positionIdInfo)
const onStandardIdChanged(info: standardIdInfo)
```

## Tips
### パフォーマンスを上げるには
#### CubeのAPIコールにはasyncを使おう
もちろんPC環境にもよりますが、Cubeへのコマンドと`p5.js`上の描画処理等をシーケンシャルに動かすと両方のパフォーマンスが落ちてしまうことが多いです。    
そのため、それほど高いフレームレートを要求しないCubeのAPI発行はは下記の様に非同期関数としてもらえると、全体のパフォーマンスが向上します。

```javascript
function draw() {
  // Cube control command with async
  asyncCubeControl();

  // Then code your sketch...
  ellipse( mouseX, mouseY, 20, 20 );
}

async function asyncCubeControl() {
  // Cube control.
}
```

#### フレームレートあげる
このライブラリでは、僕のプアなPC環境でも満足に動くように、`WebBluetooth`経由のAPI発行レートを15fpsに抑えています。（どんなに早く発行しても、15fpsを超えるものは破棄される）
そのため、位置情報の追従などは、若干精度に問題があるように感じるかたもいらっしゃると思います。そんなときはCubeのフレームレートを変更(上限30fps)してあげると、パフォーマンス向上する場合がありますので、お試しください。新しいMacBookなどではめっちゃ改善しますよ。

```javascript
cube?.setFrameRate(30);
```

### わかっている問題点
特定のWindows環境でのみですが、`moveToMulti` APIが、3位置以上の指定をするとエラーが出てしまっています。Mac等では問題ない。  

## 制約事項
`p5.toio`はまだα版(0.5.0)のため、テストコードや詳細なAPIの説明資料、豊富なサンプル等が内包されていません。また、API仕様も改変する可能性もありますので、ご了承くださいませ。
次回のβ版(0.8.0)ではそのあたりも改善したものにする予定ですので、ご期待してお待ちください。  

Enjoy!!!