Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
# Piu Renderer(実装リファレンス)
本ドキュメントは PIU Renderer に関する既存メモを統合し、**現在の実装**を真としてまとめたものです。
以下のパスは特記がない限り `firmware/` からの相対パスです。
## 1. エントリポイントと全体構成
### Renderer のエントリポイント(現行)
- `stackchan/renderers-piu/renderer-simple.ts`
- `stackchan/renderers-piu/renderer-dog.ts`
- `stackchan/renderers-piu/renderer-small.ts`
各エントリポイントは、`AppController` を `Behavior` に持つ Piu `Application` を生成し、
その `behavior` を返します。
旧 API 互換の `RendererCompat` が `AppController` をラップし、`Robot` が期待する `Renderer` 形状を維持しています。
## 2. FaceContext の構成
`stackchan/renderers-piu/face-context.ts` で定義されています。
```ts
type FaceContext = {
mouth: { open: number }
eyes: {
left: { open: number; gazeX: number; gazeY: number }
right: { open: number; gazeX: number; gazeY: number }
}
breath: number
emotion: 'NEUTRAL' | 'ANGRY' | 'SAD' | 'HAPPY' | 'SLEEPY' | 'DOUBTFUL' | 'COLD' | 'HOT'
theme: {
primary: string
secondary: string
}
}
```
補足:
- `theme.primary` / `theme.secondary` は hex 文字列(例: `#ffffff`)。
- `defaultFaceContext` / `createFaceContext` / `copyFaceContext` が同ファイルにあります。
## 3. UI コンポーネント階層(現行)
```
Application (Behavior: AppController)
└─ FaceView (CommonView template)
├─ Main (FaceMainTemplate)
│ ├─ Face (FaceBase -> SimpleFace / DogFace / SmallFace)
│ │ ├─ Eye (Eyelid, Iris を含む)
│ │ └─ Mouth
│ │ └─ Dog parts (eyebrow / nose / mouth) [DogFace のみ]
│ └─ Effects container
│ ├─ SpeechBalloon
│ └─ Emoticon (heart / angry / sweat / tear / sleepy)
├─ AppBar (Content; 既定では高さ 0)
└─ Overlay (Container)
└─ Drawer (Container)
└─ Scroller -> Column -> DrawerButton*
```
## 4. UI コンポーネントの役割とテンプレート引数
### 4.1 Application + AppController(`renderers-piu/app-controller.ts`)
**役割:** View の構築と管理、顔更新の伝播、Drawer/Effect 操作の仲介。
**生成(現行エントリポイント):**
```ts
new Application(
{ face: new SimpleFace(), drawerButtons?: DrawerButtonSpec[] },
{ displayListLength: 2048, contents: [], Behavior: AppController }
)
```
**初期化引数(AppControllerParams = FaceViewParams):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `face` | `PiuContainer` | `main` が無い場合は必須 | Face コンテナ。 |
| `main` | `PiuContainer` | 任意 | 自前で root を作る場合。 |
| `effects` | `PiuContainer` | 任意 | Effects コンテナ(省略時は自動生成)。 |
| `skin` | `PiuSkin` | 任意 | 背景スキン。省略時はテーマ自動同期。 |
| `drawerButtons` | `DrawerButtonSpec[]` | 任意 | 初期 Drawer ボタン。 |
**パフォーマンス上の注意:**
- Renderer の各エントリポイントは `displayListLength` の既定値として `2048` を使います。
- より大きな display list が必要な UI の場合だけ renderer 設定から上書きし、全デバイス向けの固定値をむやみに増やさない方針にします。
**公開メソッド(Behavior):**
| メソッド | 説明 |
| --- | --- |
| `update(interval, faceContext)` | 顔更新をビューに反映。 |
| `addEffect(effect, key?)` | Effects に PiuContent を追加(任意キー)。 |
| `removeEffect(effect)` | Effects から PiuContent を削除。 |
| `removeEffectByKey(key)` | キー指定で削除(`name` を利用)。 |
| `setFace(face)` | Face コンテナを差し替え。 |
| `setDrawerButtons(buttons)` | Drawer ボタンを全置換。 |
| `addDrawerButton(button)` | Drawer ボタンを追加/差し替え。 |
| `removeDrawerButton(key)` | Drawer ボタンを削除。 |
| `setDrawerButtonState(key, active)` | トグル状態を更新。 |
| `openDrawer()` | Drawer を開く。 |
| `closeDrawer()` | Drawer を閉じる。 |
| `toggleDrawer()` | Drawer をトグル。 |
**Application へ付与される controller:**
| 名称 | 説明 |
| --- | --- |
| `application.drawerController` | Drawer ボタン操作用。 |
### 4.2 CommonView(`renderers-piu/common-view.ts`)
**役割:** Main + AppBar + Overlay を配置し、Drawer 状態を `CommonViewBehavior` で管理。
**テンプレート引数(CommonViewParams):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `MAIN` | `PiuContainer` | 必須 | Main のアンカー。 |
| `APP_BAR` | `PiuContent` | 必須 | AppBar のアンカー。 |
| `OVERLAY` | `PiuContainer` | 必須 | Overlay のアンカー。 |
| `main` | `PiuContainer` | 任意 | `MAIN` の省略指定。 |
| `drawerButtons` | `DrawerButtonSpec[]` | 任意 | 初期 Drawer ボタン。 |
**公開メソッド(CommonViewBehavior):**
| メソッド | 説明 |
| --- | --- |
| `openDrawer()` | Drawer を開き、Overlay を有効化。 |
| `closeDrawer()` | Drawer を閉じ、Overlay を無効化。 |
| `toggleDrawer()` | Drawer をトグル。 |
| `setDrawerButtons(buttons)` | Drawer ボタンを全置換。 |
| `addDrawerButton(button)` | Drawer ボタンを追加/差し替え。 |
| `removeDrawerButton(key)` | Drawer ボタンを削除。 |
| `setDrawerButtonState(key, active)` | トグル状態を更新。 |
**Behavior の補足:**
| 項目 | 説明 |
| --- | --- |
| Drawer 生成 | `new Drawer({ buttons })` |
| Overlay 終了 | Overlay の `onTouchEnded` が `onDrawerClose` を bubble。 |
### 4.3 FaceView(`renderers-piu/face-view.ts`)
**役割:** CommonView を顔描画用に拡張。テーマ同期、顔更新の配布、Effect 管理を追加。
**テンプレート引数(FaceViewParams):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `face` | `PiuContainer` | `main` が無い場合は必須 | Face コンテナ。 |
| `effects` | `PiuContainer` | 任意 | Effects コンテナ(省略時は自動生成)。 |
| `skin` | `PiuSkin` | 任意 | 背景スキン。省略時はテーマ自動同期。 |
| `FACE` | `PiuContainer` | `main` 指定時は必須 | Face のアンカー。 |
| `EFFECTS` | `PiuContainer` | `main` 指定時は必須 | Effects のアンカー。 |
|(継承)| `CommonViewParams` | — | `MAIN`, `APP_BAR`, `OVERLAY`, `drawerButtons`。 |
**公開メソッド(FaceViewBehavior):**
| メソッド | 説明 |
| --- | --- |
| `onFaceUpdate(faceContext)` | テーマ反映と face container への転送。 |
| `onFaceContext(faceContext)` | effects / overlay / app bar へ配布。 |
| `addEffect(effect, key?)` | Effects に追加(任意キー)。 |
| `removeEffect(effect)` | Effects から削除。 |
| `removeEffectByKey(key)` | キー指定で削除(`name` を利用)。 |
| `setFace(face)` | Face コンテナを差し替え。 |
### 4.4 FaceMainTemplate(`renderers-piu/face-view.ts`)
**役割:** Face + Effects を持つ全画面コンテナ(背景スキン付き)。
**引数(FaceViewParams を利用):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `face` | `PiuContainer` | 必須 | Face コンテナ。 |
| `effects` | `PiuContainer` | 任意 | Effects コンテナ(省略時は自動生成)。 |
| `skin` | `PiuSkin` | 任意 | 背景スキン(省略時は theme.secondary)。 |
### 4.5 FaceBase と Face テンプレート(`renderers-piu/behaviors/face.ts`)
#### FaceBase
**役割:** `FaceBehavior` を持つベース顔コンテナ。`contents` で構成部品を渡す。
**引数(FaceBaseParams):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `contents` | `PiuContent[]` | 任意 | Face パーツのインスタンス。 |
| `motions` | `FaceMotion[]` | 任意 | tick ごとに適用するモーション。 |
| `intervalMs` | `number` | 任意 | tick 間隔(既定 33ms)。 |
| `left/right/top/bottom/width/height` | `number` | 任意 | Face コンテナのレイアウト。 |
#### FaceBehavior
**役割:** `current` / `desired` の FaceContext を保持し、モーション適用・呼吸オフセット・`onFaceContext` 配布を担当。
**既定値:**
| 項目 | 値 |
| --- | --- |
| `intervalMs` | `33` |
| モーション | `createBlinkMotion` + `createBreathMotion`(saccade は既定で無効) |
| 呼吸オフセット | `container.top = baseTop + breath * 6` |
**公開メソッド(FaceBehavior):**
| メソッド | 説明 |
| --- | --- |
| `onFaceUpdate(faceContext)` | desired へコピー(FaceView/AppController から呼ばれる)。 |
| `pause()` | 更新停止+非表示化。 |
| `resume()` | 更新再開+表示化。 |
#### Face テンプレート
- `SimpleFace`: `Eye` x2 + `Mouth`
- `SmallFace`: 小さめの目/口レイアウト
- `DogFace`: 目 + 眉 + 犬口 + 犬鼻
各テンプレートは `FaceBase` の派生で、`FaceBaseParams`(位置・サイズ・モーション・interval)を受け取れます。
**初期化引数(Face テンプレート):**
| テンプレート | 引数 | 説明 |
| --- | --- | --- |
| `SimpleFace` | `FaceBaseParams` | 標準レイアウト。 |
| `SmallFace` | `FaceBaseParams` | コンパクトレイアウト。 |
| `DogFace` | `FaceBaseParams` | 犬顔レイアウト。 |
### 4.6 Face パーツ
#### Eye(`parts/eye.ts`)
**役割:** 虹彩 + まぶた。視線に応じて虹彩位置、感情/開閉でまぶた形状を更新。
**引数(EyeOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `radius` | `number` | 任意 | 虹彩の半径。 |
| `side` | `left`, `right` | 必須 | 目の左右。 |
| `eyelidWidth`, `eyelidHeight` | `number` | 任意 | まぶたのサイズ。 |
#### Eyelid(`parts/eye.ts`)
**役割:** 感情に応じたまぶた形状。
**引数(EyelidOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `width`, `height` | `number` | 必須 | まぶたのサイズ。 |
| `side` | `left`, `right` | 必須 | 目の左右。 |
#### Mouth(`parts/mouth.ts`)
**役割:** `mouth.open` に応じて拡縮する矩形の口。
**引数(MouthOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `minWidth`, `maxWidth` | `number` | 任意 | 幅の範囲。 |
| `minHeight`, `maxHeight` | `number` | 任意 | 高さの範囲。 |
#### Dog パーツ(`parts/dog/*.ts`)
**DogEyebrow(EyebrowOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `side` | `left`, `right` | 必須 | 目の左右。 |
| `canvasWidth`, `canvasHeight` | `number` | 任意 | Outline 用キャンバスサイズ。 |
**DogMouth(DogMouthOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `minWidth`, `maxWidth` | `number` | 任意 | 幅の範囲。 |
| `minHeight`, `maxHeight` | `number` | 任意 | 高さの範囲。 |
| `canvasWidth`, `canvasHeight` | `number` | 任意 | Outline 用キャンバスサイズ。 |
**DogNose(DogNoseOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `cx`, `cy` | `number` | 必須 | 中心座標。 |
| `minHeight`, `maxHeight` | `number` | 任意 | 高さの範囲。 |
| `canvasWidth`, `canvasHeight` | `number` | 任意 | Outline 用キャンバスサイズ。 |
### 4.7 Effects
#### Speech Balloon(`effects/speech-balloon.ts`)
**Template:** `SpeechBalloon`
**Options(SpeechBalloonOptions):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `name` | `string` | 任意 | Effect 管理用のキー。 |
| `left/right/top/bottom/width/height` | `number` | 任意 | レイアウト指定。 |
| `padding` | `number` | 任意 | 内側余白。 |
| `space` | `number` | 任意 | 繰り返し文字列の間隔。 |
| `radius` | `number` | 任意 | 角丸半径。 |
| `text` | `string` | 任意 | 表示文字列。 |
| `font` | `string` | 任意 | フォント指定。 |
| `speed` | `number` | 任意 | スクロール速度。 |
#### Emoticon(`effects/emoticon.ts`)
**Template:** `Emoticon`
**Params(EmoticonParams):**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `key` | `heart`, `angry`, `sweat`, `tear`, `sleepy` | 必須 | 感情種別。 |
| `name` | `string` | 任意 | Effect 管理用のキー。 |
| `left/right/top/bottom/width/height` | `number` | 任意 | レイアウト指定。 |
| `angle` | `number` | 任意 | 回転角。 |
| `interval` | `number` | 任意 | tick 間隔。 |
| `count` | `number` | 任意 | 粒数(sweat/tear)。 |
| `lanes` | `[number, number][]` | 任意 | レーン指定(tear)。 |
| `smallScale` | `number` | 任意 | 最小スケール(sweat)。 |
| `holdScale` | `number` | 任意 | 保持スケール(sweat)。 |
### 4.8 Drawer(`renderers-piu/drawer.ts`)
**Template:** `Drawer`
**テンプレート引数:**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `buttons` | `DrawerButtonSpec[]` | 任意 | 初期ボタン。 |
**DrawerButtonSpec:**
| 名称 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| `key` | `string` | 必須 | `bubble` に使うイベントキー。 |
| `label` | `string` | 必須 | ボタン表示。 |
| `kind` | `action`, `toggle` | 任意 | toggle はインジケータを表示。 |
| `active` | `boolean` | 任意 | 初期トグル状態。 |
**公開メソッド(DrawerBehavior):**
| メソッド | 説明 |
| --- | --- |
| `setOpen(container, open)` | 開閉アニメーション。 |
| `toggle(container)` | 開閉をトグル。 |
| `setButtonState(container, key, active)` | トグル表示を更新。 |
### 4.9 Motions(`renderers-piu/motions/*`)
**型とファクトリ:**
| 名称 | シグネチャ | 説明 |
| --- | --- | --- |
| `FaceMotion` | `(tickMillis: number, face: FaceContext) => void` | tick ごとに適用される関数。 |
| `createBlinkMotion` | `(options) => FaceMotion` | まばたきモーション。 |
| `createBreathMotion` | `(options) => FaceMotion` | 呼吸モーション。 |
| `createSaccadeMotion` | `(options) => FaceMotion` | 視線サッケード。 |
## 5. 利用例
### 5.1 Face の生成と set
```ts
import { createRenderer } from 'renderer-simple'
import { DogFace } from 'behaviors/face'
const controller = createRenderer()
const dogFace = new DogFace({})
controller.setFace(dogFace)
```
### 5.2 Emoticon / SpeechBalloon の生成と add/remove
```ts
import { createRenderer } from 'renderer-simple'
import { Emoticon } from 'effects/emoticon'
import { SpeechBalloon } from 'effects/speech-balloon'
const controller = createRenderer()
const heart = new Emoticon({ key: 'heart', left: 8, top: 8 })
const speech = new SpeechBalloon({ text: 'Hello from Stack-chan' })
controller.addEffect(heart)
controller.addEffect(speech)
controller.removeEffect(heart)
controller.removeEffect(speech)
```
## 6. FaceContext 更新 → 描画更新のシーケンス
```mermaid
sequenceDiagram
autonumber
participant Robot
participant RendererCompat
participant AppController
participant FaceViewBehavior
participant FaceBehavior
participant FaceParts
Robot->>Robot: updateFace() (33ms ごと)
Robot->>RendererCompat: update(interval, faceContext)
RendererCompat->>AppController: update(interval, faceContext)
AppController->>FaceViewBehavior: onFaceUpdate(faceContext)
FaceViewBehavior->>FaceViewBehavior: applyTheme()(auto の場合)
FaceViewBehavior->>FaceBehavior: onFaceUpdate(faceContext)
FaceBehavior-->>FaceBehavior: desired = faceContext
FaceBehavior-->>FaceBehavior: onTimeChanged() tick
FaceBehavior-->>FaceBehavior: current = desired + motions
FaceBehavior->>FaceParts: distribute('onFaceContext', current)
```
補足: `FaceViewBehavior.onFaceUpdate` から `onFaceContext` を呼び、effects/overlay のテーマ更新を伝播します。
`FaceBehavior` からは既定で view へ bubble していません。
## 7. Drawer ボタンタッチ → ハンドラ実行のシーケンス
```mermaid
sequenceDiagram
autonumber
participant User
participant DrawerButton
participant Application
participant Robot
participant DrawerController
User->>DrawerButton: tap
DrawerButton->>DrawerButton: onTouchEnded()
DrawerButton->>Application: bubble(key)
Application->>Application: behavior[key]()\n(Robot が登録)
Application->>Robot: callback(robot)
Robot->>DrawerController: setButtonState(key, active)\n(toggle の場合)
```
PIU テストアプリでも同様に、`AppController` にメソッドを割り当てる形でハンドラを登録しています。
## 7. 主要ファイル(参照用)
- `stackchan/renderers-piu/app-controller.ts`
- `stackchan/renderers-piu/face-view.ts`
- `stackchan/renderers-piu/common-view.ts`
- `stackchan/renderers-piu/behaviors/face.ts`
- `stackchan/renderers-piu/drawer.ts`
- `stackchan/renderers-piu/effects/*`
- `stackchan/renderers-piu/parts/*`
- `stackchan/robot.ts`
83227dbdbThis file is pinned to the selected release. Download the original to open it in your design tool.