# Textillin v3.0.0

スクロール連動テキストアニメーションライブラリ（Vanilla JS / jQuery不要）

要素がビューポートに入ったタイミングで、文字単位のアニメーションを自動実行します。文字分割に [anime.js](https://animejs.com/) v4 の `splitText` を使い、モーションは CSS `transition` で行います（`@keyframes` は使いません）。

v2 系（Lettering.js + Textillate ベース）からの全面書き直しです。主な変更は「クラスの統一（`textroll-*`）」「FOUC（読み込み時のチラつき）の解消」「日本語の禁則保持」「内側HTMLの保持」「`animation` → `transition` 化（印刷・FireShot対策）」です。


## 必要ファイル

```
textillin.min.js    （splitText を同梱した自己完結スクリプト）
textillin.min.css   （コンパイル済みCSS）
```

jQuery は不要です。anime.js は `textillin.min.js` に同梱されているため、別途読み込む必要はありません（サイト側で使っている anime.js v3 等とは干渉しません）。


## 基本的な使い方

### 1. CDN

CSS は**通常読み込み**、JS は FOUC 対策のため **`<head>` で同期読み込み**します（`defer` や `media="print"` 遅延は使わないでください）。

```html
<head>
  <link rel="stylesheet" href="https://unpkg.com/@sarap422/lib-textillin@3.0.0/textillin.min.css">
  <script src="https://unpkg.com/@sarap422/lib-textillin@3.0.0/textillin.min.js"></script>
</head>
```

### 2. HTML に `textroll-エフェクト名` クラスを付与

```html
<strong class="textroll-fadeInBottom">テキストがふわっと下から表示されます</strong>
```

これだけで、要素がスクロールで画面内に入ると自動的にアニメーションします。ラッパー用の内側 `<span>` は不要です（付けても保持されます）。


## 利用可能なエフェクト（12種）

| クラス名 | 効果 |
|----------|------|
| `textroll-fadeIn` | フェードイン |
| `textroll-fadeInBottom` | 下からフェードイン |
| `textroll-fadeInTop` | 上からフェードイン |
| `textroll-fadeInLeft` | 左からフェードイン |
| `textroll-fadeInRight` | 右からフェードイン |
| `textroll-bounceIn` | バウンスイン |
| `textroll-bounceInBottom` | 下からバウンスイン |
| `textroll-bounceInTop` | 上からバウンスイン |
| `textroll-bounceInLeft` | 左からバウンスイン |
| `textroll-bounceInRight` | 右からバウンスイン |
| `textroll-flipInX` | X軸フリップイン |
| `textroll-flipInY` | Y軸フリップイン |


## 挙動を変える状態クラス

`data-in-*` 属性は廃止し、状態クラスに統一しました。

| クラス | 効果 |
|--------|------|
| `is-shuffled` | 文字をランダム順でアニメーション |
| `is-reversed` | 文字を逆順でアニメーション |
| `is-synced` | 全文字を同時にアニメーション |

```html
<strong class="textroll-fadeInBottom is-shuffled">シャッフル表示</strong>
<strong class="textroll-bounceInBottom is-reversed">逆順表示</strong>
```


## タイミング修飾クラス（Scrollin 共有）

Scrollin と同じ語彙・同じ数値スケールです。同一要素に付与します。

### 開始遅延（delayed）

`delayed-0`〜`delayed-6`（0s / 0.25s / 0.5s / 0.75s / 1s / 1.25s / 1.5s）

### 再生時間（slowed / fasted）

`slowed-1`〜`slowed-60`（1.5s〜60s）、`fasted-1`〜`fasted-3`（0.75s / 0.5s / 0.25s）

### 文字間隔（staggered）※旧 `data-in-delay`

`staggered-0` / `10` / `30` / `60` / `90` / `120`（ミリ秒）。デフォルトは 15ms。

```html
<strong class="textroll-fadeInBottom staggered-60 slowed-2">ゆっくり・大きく波打つ</strong>
```


## 無効化

`untextillin` 属性を持つ要素の配下は、分割もアニメーションもされず素のテキストのまま表示されます。

```html
<div untextillin>
  <strong class="textroll-fadeInBottom">ここは分割されない</strong>
</div>
```


## CSS 変数によるカスタマイズ

要素やサイト全体で上書きできます。

| 変数 | 説明 | デフォルト |
|------|------|-----------|
| `--textroll-duration` | 再生時間 | `1s` |
| `--textroll-delay` | 開始遅延 | `0s` |
| `--textroll-stagger` | 文字間隔 | `30ms` |
| `--textroll-distance` | 移動距離（`em`） | `1em` |
| `--textroll-ease` | イージング | fade系 `--ease-out-cubic` / bounce・flip系 `--ease-out-back` |


## JavaScript API

初期化後、`window.Textroll` からアクセスできます。

```js
Textroll.trigger(element);   // 手動で発火（is-scloaded を付与）
Textroll.refresh();          // 動的に追加した要素を取り込む
Textroll.getStats();         // → { animatedCount, armed }
Textroll.destroy();          // Observer 切断＋分割を元に戻す
Textroll.enableDebug();      // コンソールにログ出力
Textroll.disableDebug();
```

読み込み前に `window.TextrollDebug = true` を設定してもデバッグログが出ます。


## 動作の仕組み

1. スクリプトが `<head>` で実行された時点で `<html>` に `.textroll-armed` を付与。CSS がこれを見て、分割前の `textroll-*` 要素を `visibility: hidden` で隠す（＝FOUC防止）
2. フォント読み込み完了（`document.fonts.ready`）後に `textroll-*` 要素を検出し、`splitText` で文字（`<span data-char>`）に分割
3. 分割済み要素に `.is-split` を付けて可視に戻す（各文字は自身の `opacity: 0` で隠れた状態）
4. IntersectionObserver で監視。ビューポートに入ると `.is-scloaded` を付与し、CSS `transition` が発火して1文字ずつ表示。発火後は監視解除
5. `splitText` の `accessible` により、元テキストがスクリーンリーダー用に保持される

JS が実行されない環境では `.textroll-armed` が付かないため、テキストは通常どおり表示されます（消えません）。


## v2 からの移行

| v2 | v3 |
|----|----|
| `tlt-fadeInBottom` | `textroll-fadeInBottom` |
| `data-in-shuffle="true"` | `is-shuffled` |
| `data-in-reverse="true"` | `is-reversed` |
| `data-in-sync="true"` | `is-synced` |
| `data-in-delay="60"` | `staggered-60` |
| 内側の `<span>` ラッパー必須 | 不要（任意） |


## 対応ブラウザ

`splitText` が語順分割に `Intl.Segmenter` を使うため、対応ブラウザで最適に動作します。

- Chrome 87+
- Safari 14.1+
- Firefox 125+
- Edge 87+

`Intl.Segmenter` 非対応の古いブラウザでは `String.prototype.split()` にフォールバックします。


## ビルド

```bash
npm install
npm run build   # src/ → dist/（esbuild で splitText を同梱バンドル、sass で CSS 生成）
```


## ライセンス / クレジット

- Textillin: [sarap422](https://code-plus.jp/) (MIT License)
- splitText: [anime.js v4](https://github.com/juliangarnier/anime) — Julian Garnier (MIT License)
