glyphdust 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +59 -5
- package/dist/index.cjs +107 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -6
- package/dist/index.d.ts +58 -6
- package/dist/index.js +107 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -137,7 +137,7 @@ declare function buildVertexShader(keyframeCount: number): string;
|
|
|
137
137
|
* フラグメントシェーダ。キーフレーム数に依存しないため定数。
|
|
138
138
|
* 円形ソフト点 + アクセント色 + きらめき + 奥行き濃淡。
|
|
139
139
|
*/
|
|
140
|
-
declare const FRAGMENT_SHADER = "\n uniform vec3 uColorInk;\n uniform vec3 uColorAccent;\n\n varying float vSeed;\n varying float vAccent;\n varying float vDepth;\n varying float vForm;\n varying float vAlpha;\n varying float vSettle;\n\n void main() {\n // \u5186\u5F62\u306E\u30BD\u30D5\u30C8\u306A\u70B9\u3002\u4E2D\u5FC3\u3067 1\u3001\u7E01\u3067 0\uFF08smoothstep \u306F edge0<edge1 \u5FC5\u9808\u306A\u306E\u3067\u53CD\u8EE2\u3057\u3066\u4F7F\u3046\uFF09\u3002\n vec2 uv = gl_PointCoord - 0.5;\n float r = length(uv);\n float alpha = 1.0 - smoothstep(0.12, 0.5, r);\n if (alpha < 0.02) discard;\n\n // \u4E3B\u4F53\u306F\u30A4\u30F3\u30AF\u3001\u4E00\u90E8\u306E\u7C92\u3060\u3051\u30A2\u30AF\u30BB\u30F3\u30C8\u8272\u3002\u5B57\u5F62\u53CE\u675F\u6642\u306F\u3084\u3084\u63A7\u3048\u3081\u306B\u3002\n float accentAmt = vAccent * mix(0.85, 0.55, vForm);\n vec3 col = mix(uColorInk, uColorAccent, accentAmt);\n\n // \u4E00\u90E8\u306E\u7C92\u306B\u660E\u308B\u3044\u304D\u3089\u3081\u304D\uFF08\u98DB\u6563\u6642\u306B\u6620\u3048\u308B\uFF09\u3002\u6574\u5217\u6642\u306F\u63A7\u3048\u3081\u3002\n float spark = step(0.94, vSeed);\n col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle));\n\n // \u5965\u884C\u304D\u3067\u6FC3\u6DE1\uFF08\u660E\u80CC\u666F\u3067\u306E\u8996\u8A8D\u6027\u78BA\u4FDD\u306E\u305F\u3081\u4E0B\u9650\u3092\u6301\u305F\u305B\u308B\uFF09\u3002\n float floorFade = mix(0.45, 0.78, vSettle);\n float depthFade = clamp(1.0 - (vDepth - 3.0) * 0.10, floorFade, 1.0);\n\n // \u6574\u5217\u6642\u306F\u4E0D\u900F\u660E\u5BC4\u308A\u306B\u3057\u3066\u30A8\u30C3\u30B8\u3092\u7DE0\u3081\u308B\u3002\n float a = alpha * depthFade * vAlpha;\n a = mix(a, clamp(a * 1.3, 0.0, 1.0), vSettle);\n\n gl_FragColor = vec4(col, a);\n }\n";
|
|
140
|
+
declare const FRAGMENT_SHADER = "\n uniform vec3 uColorInk;\n uniform vec3 uColorAccent;\n uniform float uSparkle;\n\n varying float vSeed;\n varying float vAccent;\n varying float vDepth;\n varying float vForm;\n varying float vAlpha;\n varying float vSettle;\n\n void main() {\n // \u5186\u5F62\u306E\u30BD\u30D5\u30C8\u306A\u70B9\u3002\u4E2D\u5FC3\u3067 1\u3001\u7E01\u3067 0\uFF08smoothstep \u306F edge0<edge1 \u5FC5\u9808\u306A\u306E\u3067\u53CD\u8EE2\u3057\u3066\u4F7F\u3046\uFF09\u3002\n vec2 uv = gl_PointCoord - 0.5;\n float r = length(uv);\n float alpha = 1.0 - smoothstep(0.12, 0.5, r);\n if (alpha < 0.02) discard;\n\n // \u4E3B\u4F53\u306F\u30A4\u30F3\u30AF\u3001\u4E00\u90E8\u306E\u7C92\u3060\u3051\u30A2\u30AF\u30BB\u30F3\u30C8\u8272\u3002\u5B57\u5F62\u53CE\u675F\u6642\u306F\u3084\u3084\u63A7\u3048\u3081\u306B\u3002\n float accentAmt = vAccent * mix(0.85, 0.55, vForm);\n vec3 col = mix(uColorInk, uColorAccent, accentAmt);\n\n // \u4E00\u90E8\u306E\u7C92\u306B\u660E\u308B\u3044\u304D\u3089\u3081\u304D\uFF08\u98DB\u6563\u6642\u306B\u6620\u3048\u308B\uFF09\u3002\u6574\u5217\u6642\u306F\u63A7\u3048\u3081\u3002\n float spark = step(0.94, vSeed);\n col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle) * uSparkle);\n\n // \u5965\u884C\u304D\u3067\u6FC3\u6DE1\uFF08\u660E\u80CC\u666F\u3067\u306E\u8996\u8A8D\u6027\u78BA\u4FDD\u306E\u305F\u3081\u4E0B\u9650\u3092\u6301\u305F\u305B\u308B\uFF09\u3002\n float floorFade = mix(0.45, 0.78, vSettle);\n float depthFade = clamp(1.0 - (vDepth - 3.0) * 0.10, floorFade, 1.0);\n\n // \u6574\u5217\u6642\u306F\u4E0D\u900F\u660E\u5BC4\u308A\u306B\u3057\u3066\u30A8\u30C3\u30B8\u3092\u7DE0\u3081\u308B\u3002\n float a = alpha * depthFade * vAlpha;\n a = mix(a, clamp(a * 1.3, 0.0, 1.0), vSettle);\n\n gl_FragColor = vec4(col, a);\n }\n";
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* dom-overlay.ts — 実 DOM 文字との重ね合わせ/受け渡しのための幾何ユーティリティ。
|
|
@@ -248,8 +248,31 @@ interface ManualDriverConfig {
|
|
|
248
248
|
/** 0..1 の進捗。 */
|
|
249
249
|
progress: number;
|
|
250
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* 自動再生ドライバ設定。スクロール不要で、時間ベースに進捗 0→1 を進める。
|
|
253
|
+
* 「普通にテキストとして、どんな箱にも置いて勝手に動かす」用途の標準。
|
|
254
|
+
* 既定では画面内に入った瞬間に再生開始(`playOnView`)。
|
|
255
|
+
*/
|
|
256
|
+
interface AutoplayDriverConfig {
|
|
257
|
+
type: "autoplay";
|
|
258
|
+
/** 0→1 にかける秒数。既定 4。 */
|
|
259
|
+
duration?: number;
|
|
260
|
+
/** 再生開始までの遅延秒。既定 0。 */
|
|
261
|
+
delay?: number;
|
|
262
|
+
/** ループ再生。既定 false(1 回で 1.0 に張り付く)。 */
|
|
263
|
+
loop?: boolean;
|
|
264
|
+
/** ループ時に 0→1→0 を往復する(loop 必須)。既定 false。 */
|
|
265
|
+
pingpong?: boolean;
|
|
266
|
+
/** 画面内に入ってから再生開始(IntersectionObserver)。既定 true。 */
|
|
267
|
+
playOnView?: boolean;
|
|
268
|
+
}
|
|
251
269
|
/** ドライバ設定の合併型。 */
|
|
252
|
-
type DriverConfig = ScrollDriverConfig | ManualDriverConfig;
|
|
270
|
+
type DriverConfig = ScrollDriverConfig | ManualDriverConfig | AutoplayDriverConfig;
|
|
271
|
+
/**
|
|
272
|
+
* 自動再生ドライバの進捗を、経過秒から純粋に算出する。
|
|
273
|
+
* `loop`/`pingpong`/`delay` を解決し 0..1 を返す。SSR セーフ(時計は呼び出し側が渡す)。
|
|
274
|
+
*/
|
|
275
|
+
declare function computeAutoplayProgress(elapsedSec: number, cfg: Pick<AutoplayDriverConfig, "duration" | "delay" | "loop" | "pingpong">): number;
|
|
253
276
|
/**
|
|
254
277
|
* 要素の sticky スクロール進捗 0→1 を返すゲッターを作る。
|
|
255
278
|
* 進捗 = `-rect.top / (rect.height - innerHeight)`(要素上端が viewport 上端を通過し切るまでで 0→1)。
|
|
@@ -340,6 +363,32 @@ interface GlyphCamera {
|
|
|
340
363
|
/** 縦 fov(度)。既定 42。 */
|
|
341
364
|
fov?: number;
|
|
342
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* 粒子の見た目・モーションの質感。
|
|
368
|
+
* すべて省略可。{@link GlyphPreset} の上に個別上書きできる(プリセット+上書き)。
|
|
369
|
+
*/
|
|
370
|
+
interface GlyphStyle {
|
|
371
|
+
/** 点サイズ倍率。既定 1。大きいほど太い粒(可読性↓・密度感↑)。 */
|
|
372
|
+
size?: number;
|
|
373
|
+
/**
|
|
374
|
+
* 合成モード。
|
|
375
|
+
* - `"normal"`(既定)… 明背景で可読性が高い。
|
|
376
|
+
* - `"additive"` … 重なりで発光する。暗背景のアンビエント/グロー向け。
|
|
377
|
+
*/
|
|
378
|
+
blend?: "normal" | "additive";
|
|
379
|
+
/** アイドル/飛散時の漂い量 0..1。既定 1。0 で静止(端正)。 */
|
|
380
|
+
drift?: number;
|
|
381
|
+
/** きらめく粒の強さ 0..1。既定 1。0 で無効(ミニマル)。 */
|
|
382
|
+
sparkle?: number;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* 質感プリセット。`style` で部分上書きできる。
|
|
386
|
+
* - `"default"` … 現行の標準(バランス型)。
|
|
387
|
+
* - `"minimal"` … 漂い・きらめき控えめで端正。明背景の本文向け。
|
|
388
|
+
* - `"lively"` … 漂い・きらめき強めで躍動的。
|
|
389
|
+
* - `"glow"` … additive 合成の発光。暗背景のヒーロー/アンビエント向け。
|
|
390
|
+
*/
|
|
391
|
+
type GlyphPreset = "default" | "minimal" | "lively" | "glow";
|
|
343
392
|
/** インタラクション設定。 */
|
|
344
393
|
interface GlyphInteraction {
|
|
345
394
|
/** ポインタ追従(近傍反発)。既定 true。 */
|
|
@@ -353,6 +402,10 @@ interface GlyphDustProps {
|
|
|
353
402
|
keyframes: Keyframe[];
|
|
354
403
|
/** 進捗ドライバ。既定 `{ type: "scroll" }`。 */
|
|
355
404
|
driver?: DriverConfig;
|
|
405
|
+
/** 質感プリセット。既定 `"default"`。`style` で部分上書き可。 */
|
|
406
|
+
preset?: GlyphPreset;
|
|
407
|
+
/** 粒子の見た目・モーションの個別上書き(プリセットより優先)。 */
|
|
408
|
+
style?: GlyphStyle;
|
|
356
409
|
/** 配色。 */
|
|
357
410
|
colors?: GlyphColors;
|
|
358
411
|
/** デバイス別粒子数。 */
|
|
@@ -380,10 +433,9 @@ declare function GlyphDust(props: GlyphDustProps): react.JSX.Element;
|
|
|
380
433
|
* glyphdust — scroll-driven text → particles → glyph → real-text resolve
|
|
381
434
|
* for react-three-fiber.
|
|
382
435
|
*
|
|
383
|
-
* 公開 API はこのファイルから re-export
|
|
384
|
-
* 雛形段階のプレースホルダ。実装は Phase 1 (Task-002〜) で追加する。
|
|
436
|
+
* 公開 API はこのファイルから re-export する。
|
|
385
437
|
*/
|
|
386
438
|
/** ライブラリのバージョン(package.json と一致させる)。 */
|
|
387
|
-
declare const VERSION = "0.1
|
|
439
|
+
declare const VERSION = "0.2.1";
|
|
388
440
|
|
|
389
|
-
export { DEFAULT_TRIGGER_HEIGHT, type DenseTextTargetOptions, type DomGlyphOptions, type DriverConfig, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, type GlyphCamera, type GlyphColors, type GlyphCount, GlyphDust, type GlyphDustProps, type GlyphInteraction, type GlyphScreenRect, type Keyframe, type ManualDriverConfig, type Random, type ScatterKeyframe, type ScrollDriverConfig, type TextKeyframe, type TextTargetOptions, VERSION, type ViewSize, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
|
441
|
+
export { type AutoplayDriverConfig, DEFAULT_TRIGGER_HEIGHT, type DenseTextTargetOptions, type DomGlyphOptions, type DriverConfig, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, type GlyphCamera, type GlyphColors, type GlyphCount, GlyphDust, type GlyphDustProps, type GlyphInteraction, type GlyphPreset, type GlyphScreenRect, type GlyphStyle, type Keyframe, type ManualDriverConfig, type Random, type ScatterKeyframe, type ScrollDriverConfig, type TextKeyframe, type TextTargetOptions, VERSION, type ViewSize, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeAutoplayProgress, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
package/dist/index.d.ts
CHANGED
|
@@ -137,7 +137,7 @@ declare function buildVertexShader(keyframeCount: number): string;
|
|
|
137
137
|
* フラグメントシェーダ。キーフレーム数に依存しないため定数。
|
|
138
138
|
* 円形ソフト点 + アクセント色 + きらめき + 奥行き濃淡。
|
|
139
139
|
*/
|
|
140
|
-
declare const FRAGMENT_SHADER = "\n uniform vec3 uColorInk;\n uniform vec3 uColorAccent;\n\n varying float vSeed;\n varying float vAccent;\n varying float vDepth;\n varying float vForm;\n varying float vAlpha;\n varying float vSettle;\n\n void main() {\n // \u5186\u5F62\u306E\u30BD\u30D5\u30C8\u306A\u70B9\u3002\u4E2D\u5FC3\u3067 1\u3001\u7E01\u3067 0\uFF08smoothstep \u306F edge0<edge1 \u5FC5\u9808\u306A\u306E\u3067\u53CD\u8EE2\u3057\u3066\u4F7F\u3046\uFF09\u3002\n vec2 uv = gl_PointCoord - 0.5;\n float r = length(uv);\n float alpha = 1.0 - smoothstep(0.12, 0.5, r);\n if (alpha < 0.02) discard;\n\n // \u4E3B\u4F53\u306F\u30A4\u30F3\u30AF\u3001\u4E00\u90E8\u306E\u7C92\u3060\u3051\u30A2\u30AF\u30BB\u30F3\u30C8\u8272\u3002\u5B57\u5F62\u53CE\u675F\u6642\u306F\u3084\u3084\u63A7\u3048\u3081\u306B\u3002\n float accentAmt = vAccent * mix(0.85, 0.55, vForm);\n vec3 col = mix(uColorInk, uColorAccent, accentAmt);\n\n // \u4E00\u90E8\u306E\u7C92\u306B\u660E\u308B\u3044\u304D\u3089\u3081\u304D\uFF08\u98DB\u6563\u6642\u306B\u6620\u3048\u308B\uFF09\u3002\u6574\u5217\u6642\u306F\u63A7\u3048\u3081\u3002\n float spark = step(0.94, vSeed);\n col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle));\n\n // \u5965\u884C\u304D\u3067\u6FC3\u6DE1\uFF08\u660E\u80CC\u666F\u3067\u306E\u8996\u8A8D\u6027\u78BA\u4FDD\u306E\u305F\u3081\u4E0B\u9650\u3092\u6301\u305F\u305B\u308B\uFF09\u3002\n float floorFade = mix(0.45, 0.78, vSettle);\n float depthFade = clamp(1.0 - (vDepth - 3.0) * 0.10, floorFade, 1.0);\n\n // \u6574\u5217\u6642\u306F\u4E0D\u900F\u660E\u5BC4\u308A\u306B\u3057\u3066\u30A8\u30C3\u30B8\u3092\u7DE0\u3081\u308B\u3002\n float a = alpha * depthFade * vAlpha;\n a = mix(a, clamp(a * 1.3, 0.0, 1.0), vSettle);\n\n gl_FragColor = vec4(col, a);\n }\n";
|
|
140
|
+
declare const FRAGMENT_SHADER = "\n uniform vec3 uColorInk;\n uniform vec3 uColorAccent;\n uniform float uSparkle;\n\n varying float vSeed;\n varying float vAccent;\n varying float vDepth;\n varying float vForm;\n varying float vAlpha;\n varying float vSettle;\n\n void main() {\n // \u5186\u5F62\u306E\u30BD\u30D5\u30C8\u306A\u70B9\u3002\u4E2D\u5FC3\u3067 1\u3001\u7E01\u3067 0\uFF08smoothstep \u306F edge0<edge1 \u5FC5\u9808\u306A\u306E\u3067\u53CD\u8EE2\u3057\u3066\u4F7F\u3046\uFF09\u3002\n vec2 uv = gl_PointCoord - 0.5;\n float r = length(uv);\n float alpha = 1.0 - smoothstep(0.12, 0.5, r);\n if (alpha < 0.02) discard;\n\n // \u4E3B\u4F53\u306F\u30A4\u30F3\u30AF\u3001\u4E00\u90E8\u306E\u7C92\u3060\u3051\u30A2\u30AF\u30BB\u30F3\u30C8\u8272\u3002\u5B57\u5F62\u53CE\u675F\u6642\u306F\u3084\u3084\u63A7\u3048\u3081\u306B\u3002\n float accentAmt = vAccent * mix(0.85, 0.55, vForm);\n vec3 col = mix(uColorInk, uColorAccent, accentAmt);\n\n // \u4E00\u90E8\u306E\u7C92\u306B\u660E\u308B\u3044\u304D\u3089\u3081\u304D\uFF08\u98DB\u6563\u6642\u306B\u6620\u3048\u308B\uFF09\u3002\u6574\u5217\u6642\u306F\u63A7\u3048\u3081\u3002\n float spark = step(0.94, vSeed);\n col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle) * uSparkle);\n\n // \u5965\u884C\u304D\u3067\u6FC3\u6DE1\uFF08\u660E\u80CC\u666F\u3067\u306E\u8996\u8A8D\u6027\u78BA\u4FDD\u306E\u305F\u3081\u4E0B\u9650\u3092\u6301\u305F\u305B\u308B\uFF09\u3002\n float floorFade = mix(0.45, 0.78, vSettle);\n float depthFade = clamp(1.0 - (vDepth - 3.0) * 0.10, floorFade, 1.0);\n\n // \u6574\u5217\u6642\u306F\u4E0D\u900F\u660E\u5BC4\u308A\u306B\u3057\u3066\u30A8\u30C3\u30B8\u3092\u7DE0\u3081\u308B\u3002\n float a = alpha * depthFade * vAlpha;\n a = mix(a, clamp(a * 1.3, 0.0, 1.0), vSettle);\n\n gl_FragColor = vec4(col, a);\n }\n";
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
143
|
* dom-overlay.ts — 実 DOM 文字との重ね合わせ/受け渡しのための幾何ユーティリティ。
|
|
@@ -248,8 +248,31 @@ interface ManualDriverConfig {
|
|
|
248
248
|
/** 0..1 の進捗。 */
|
|
249
249
|
progress: number;
|
|
250
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* 自動再生ドライバ設定。スクロール不要で、時間ベースに進捗 0→1 を進める。
|
|
253
|
+
* 「普通にテキストとして、どんな箱にも置いて勝手に動かす」用途の標準。
|
|
254
|
+
* 既定では画面内に入った瞬間に再生開始(`playOnView`)。
|
|
255
|
+
*/
|
|
256
|
+
interface AutoplayDriverConfig {
|
|
257
|
+
type: "autoplay";
|
|
258
|
+
/** 0→1 にかける秒数。既定 4。 */
|
|
259
|
+
duration?: number;
|
|
260
|
+
/** 再生開始までの遅延秒。既定 0。 */
|
|
261
|
+
delay?: number;
|
|
262
|
+
/** ループ再生。既定 false(1 回で 1.0 に張り付く)。 */
|
|
263
|
+
loop?: boolean;
|
|
264
|
+
/** ループ時に 0→1→0 を往復する(loop 必須)。既定 false。 */
|
|
265
|
+
pingpong?: boolean;
|
|
266
|
+
/** 画面内に入ってから再生開始(IntersectionObserver)。既定 true。 */
|
|
267
|
+
playOnView?: boolean;
|
|
268
|
+
}
|
|
251
269
|
/** ドライバ設定の合併型。 */
|
|
252
|
-
type DriverConfig = ScrollDriverConfig | ManualDriverConfig;
|
|
270
|
+
type DriverConfig = ScrollDriverConfig | ManualDriverConfig | AutoplayDriverConfig;
|
|
271
|
+
/**
|
|
272
|
+
* 自動再生ドライバの進捗を、経過秒から純粋に算出する。
|
|
273
|
+
* `loop`/`pingpong`/`delay` を解決し 0..1 を返す。SSR セーフ(時計は呼び出し側が渡す)。
|
|
274
|
+
*/
|
|
275
|
+
declare function computeAutoplayProgress(elapsedSec: number, cfg: Pick<AutoplayDriverConfig, "duration" | "delay" | "loop" | "pingpong">): number;
|
|
253
276
|
/**
|
|
254
277
|
* 要素の sticky スクロール進捗 0→1 を返すゲッターを作る。
|
|
255
278
|
* 進捗 = `-rect.top / (rect.height - innerHeight)`(要素上端が viewport 上端を通過し切るまでで 0→1)。
|
|
@@ -340,6 +363,32 @@ interface GlyphCamera {
|
|
|
340
363
|
/** 縦 fov(度)。既定 42。 */
|
|
341
364
|
fov?: number;
|
|
342
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* 粒子の見た目・モーションの質感。
|
|
368
|
+
* すべて省略可。{@link GlyphPreset} の上に個別上書きできる(プリセット+上書き)。
|
|
369
|
+
*/
|
|
370
|
+
interface GlyphStyle {
|
|
371
|
+
/** 点サイズ倍率。既定 1。大きいほど太い粒(可読性↓・密度感↑)。 */
|
|
372
|
+
size?: number;
|
|
373
|
+
/**
|
|
374
|
+
* 合成モード。
|
|
375
|
+
* - `"normal"`(既定)… 明背景で可読性が高い。
|
|
376
|
+
* - `"additive"` … 重なりで発光する。暗背景のアンビエント/グロー向け。
|
|
377
|
+
*/
|
|
378
|
+
blend?: "normal" | "additive";
|
|
379
|
+
/** アイドル/飛散時の漂い量 0..1。既定 1。0 で静止(端正)。 */
|
|
380
|
+
drift?: number;
|
|
381
|
+
/** きらめく粒の強さ 0..1。既定 1。0 で無効(ミニマル)。 */
|
|
382
|
+
sparkle?: number;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* 質感プリセット。`style` で部分上書きできる。
|
|
386
|
+
* - `"default"` … 現行の標準(バランス型)。
|
|
387
|
+
* - `"minimal"` … 漂い・きらめき控えめで端正。明背景の本文向け。
|
|
388
|
+
* - `"lively"` … 漂い・きらめき強めで躍動的。
|
|
389
|
+
* - `"glow"` … additive 合成の発光。暗背景のヒーロー/アンビエント向け。
|
|
390
|
+
*/
|
|
391
|
+
type GlyphPreset = "default" | "minimal" | "lively" | "glow";
|
|
343
392
|
/** インタラクション設定。 */
|
|
344
393
|
interface GlyphInteraction {
|
|
345
394
|
/** ポインタ追従(近傍反発)。既定 true。 */
|
|
@@ -353,6 +402,10 @@ interface GlyphDustProps {
|
|
|
353
402
|
keyframes: Keyframe[];
|
|
354
403
|
/** 進捗ドライバ。既定 `{ type: "scroll" }`。 */
|
|
355
404
|
driver?: DriverConfig;
|
|
405
|
+
/** 質感プリセット。既定 `"default"`。`style` で部分上書き可。 */
|
|
406
|
+
preset?: GlyphPreset;
|
|
407
|
+
/** 粒子の見た目・モーションの個別上書き(プリセットより優先)。 */
|
|
408
|
+
style?: GlyphStyle;
|
|
356
409
|
/** 配色。 */
|
|
357
410
|
colors?: GlyphColors;
|
|
358
411
|
/** デバイス別粒子数。 */
|
|
@@ -380,10 +433,9 @@ declare function GlyphDust(props: GlyphDustProps): react.JSX.Element;
|
|
|
380
433
|
* glyphdust — scroll-driven text → particles → glyph → real-text resolve
|
|
381
434
|
* for react-three-fiber.
|
|
382
435
|
*
|
|
383
|
-
* 公開 API はこのファイルから re-export
|
|
384
|
-
* 雛形段階のプレースホルダ。実装は Phase 1 (Task-002〜) で追加する。
|
|
436
|
+
* 公開 API はこのファイルから re-export する。
|
|
385
437
|
*/
|
|
386
438
|
/** ライブラリのバージョン(package.json と一致させる)。 */
|
|
387
|
-
declare const VERSION = "0.1
|
|
439
|
+
declare const VERSION = "0.2.1";
|
|
388
440
|
|
|
389
|
-
export { DEFAULT_TRIGGER_HEIGHT, type DenseTextTargetOptions, type DomGlyphOptions, type DriverConfig, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, type GlyphCamera, type GlyphColors, type GlyphCount, GlyphDust, type GlyphDustProps, type GlyphInteraction, type GlyphScreenRect, type Keyframe, type ManualDriverConfig, type Random, type ScatterKeyframe, type ScrollDriverConfig, type TextKeyframe, type TextTargetOptions, VERSION, type ViewSize, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
|
441
|
+
export { type AutoplayDriverConfig, DEFAULT_TRIGGER_HEIGHT, type DenseTextTargetOptions, type DomGlyphOptions, type DriverConfig, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, type GlyphCamera, type GlyphColors, type GlyphCount, GlyphDust, type GlyphDustProps, type GlyphInteraction, type GlyphPreset, type GlyphScreenRect, type GlyphStyle, type Keyframe, type ManualDriverConfig, type Random, type ScatterKeyframe, type ScrollDriverConfig, type TextKeyframe, type TextTargetOptions, VERSION, type ViewSize, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeAutoplayProgress, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
package/dist/index.js
CHANGED
|
@@ -160,6 +160,8 @@ function buildVertexShader(keyframeCount) {
|
|
|
160
160
|
uniform vec3 uPointer;
|
|
161
161
|
uniform float uPointerActive;
|
|
162
162
|
uniform float uSize;
|
|
163
|
+
uniform float uSizeScale;
|
|
164
|
+
uniform float uDrift;
|
|
163
165
|
uniform float uPixelRatio;
|
|
164
166
|
|
|
165
167
|
${attributeDecls}
|
|
@@ -195,7 +197,7 @@ ${mixChain}
|
|
|
195
197
|
|
|
196
198
|
// \u30A2\u30A4\u30C9\u30EB\u306E\u6F02\u3044\uFF08\u6574\u5217\u6642 settle / \u5B57\u5F62\u6642 form \u3067\u5F31\u3081\u308B\uFF09\u3002
|
|
197
199
|
vSettle = uSettle;
|
|
198
|
-
float drift = (1.0 - uReduced) * (1.0 - uSettle * 0.9) * (1.0 - uForm);
|
|
200
|
+
float drift = (1.0 - uReduced) * (1.0 - uSettle * 0.9) * (1.0 - uForm) * uDrift;
|
|
199
201
|
pos.x += sin(uTime * 0.35 + ph) * 0.06 * drift;
|
|
200
202
|
pos.y += cos(uTime * 0.30 + ph * 1.7) * 0.06 * drift;
|
|
201
203
|
pos.z += sin(uTime * 0.27 + ph * 2.3) * 0.06 * drift;
|
|
@@ -223,9 +225,11 @@ ${mixChain}
|
|
|
223
225
|
float sizeVar = mix(0.55 + aSeed * 0.9, 0.72 + aSeed * 0.35, uSettle);
|
|
224
226
|
// \u5B57\u5F62\u53CE\u675F\u6642\u306F\u96A3\u63A5\u7C92\u5B50\u3067\u9699\u9593\u3092\u57CB\u3081\u308B\u305F\u3081\u308F\u305A\u304B\u306B\u5927\u304D\u3081\uFF06\u5747\u4E00\u306B\u3002
|
|
225
227
|
sizeVar = mix(sizeVar, 0.95 + aSeed * 0.18, uForm);
|
|
226
|
-
|
|
228
|
+
// \u9AD8 dpr \u74B0\u5883\u3067\u306F\u5C0F\u7C92\u30FB\u4E0A\u9650\u4F4E\u3081\u306E\u65B9\u304C\u30A8\u30C3\u30B8\u304C\u7DE0\u307E\u308A\u9AD8\u7CBE\u7D30\u306B\u898B\u3048\u308B
|
|
229
|
+
// \uFF08\u30B3\u30FC\u30DD\u30EC\u30FC\u30C8\u30B5\u30A4\u30C8\u5B9F\u88C5\u3067\u5B9F\u8A3C\u30020.62 \u3068 clamp 4\u301C5 \u304C\u6700\u3082\u300C\u971E\u307E\u306A\u3044\u300D\uFF09\u3002
|
|
230
|
+
float s = uSize * sizeVar * 0.62 * uSizeScale;
|
|
227
231
|
gl_PointSize = s * uPixelRatio * (1.0 / -mvPosition.z);
|
|
228
|
-
gl_PointSize = clamp(gl_PointSize, 1.0, mix(
|
|
232
|
+
gl_PointSize = clamp(gl_PointSize, 1.0, mix(4.0, 5.0, uForm) * uPixelRatio);
|
|
229
233
|
}
|
|
230
234
|
`
|
|
231
235
|
);
|
|
@@ -235,6 +239,7 @@ var FRAGMENT_SHADER = (
|
|
|
235
239
|
`
|
|
236
240
|
uniform vec3 uColorInk;
|
|
237
241
|
uniform vec3 uColorAccent;
|
|
242
|
+
uniform float uSparkle;
|
|
238
243
|
|
|
239
244
|
varying float vSeed;
|
|
240
245
|
varying float vAccent;
|
|
@@ -256,7 +261,7 @@ var FRAGMENT_SHADER = (
|
|
|
256
261
|
|
|
257
262
|
// \u4E00\u90E8\u306E\u7C92\u306B\u660E\u308B\u3044\u304D\u3089\u3081\u304D\uFF08\u98DB\u6563\u6642\u306B\u6620\u3048\u308B\uFF09\u3002\u6574\u5217\u6642\u306F\u63A7\u3048\u3081\u3002
|
|
258
263
|
float spark = step(0.94, vSeed);
|
|
259
|
-
col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle));
|
|
264
|
+
col = mix(col, uColorAccent, spark * mix(0.45, 0.15, vSettle) * uSparkle);
|
|
260
265
|
|
|
261
266
|
// \u5965\u884C\u304D\u3067\u6FC3\u6DE1\uFF08\u660E\u80CC\u666F\u3067\u306E\u8996\u8A8D\u6027\u78BA\u4FDD\u306E\u305F\u3081\u4E0B\u9650\u3092\u6301\u305F\u305B\u308B\uFF09\u3002
|
|
262
267
|
float floorFade = mix(0.45, 0.78, vSettle);
|
|
@@ -390,6 +395,21 @@ function computeScreenRect(targets, viewportW, viewportH, visibleWorldW) {
|
|
|
390
395
|
};
|
|
391
396
|
}
|
|
392
397
|
var DEFAULT_TRIGGER_HEIGHT = 2;
|
|
398
|
+
function triangle(x) {
|
|
399
|
+
const t = x % 2;
|
|
400
|
+
return t <= 1 ? t : 2 - t;
|
|
401
|
+
}
|
|
402
|
+
function computeAutoplayProgress(elapsedSec, cfg) {
|
|
403
|
+
const duration = cfg.duration && cfg.duration > 0 ? cfg.duration : 4;
|
|
404
|
+
const delay = cfg.delay && cfg.delay > 0 ? cfg.delay : 0;
|
|
405
|
+
const t = elapsedSec - delay;
|
|
406
|
+
if (t <= 0) return 0;
|
|
407
|
+
const raw = t / duration;
|
|
408
|
+
if (cfg.loop) {
|
|
409
|
+
return cfg.pingpong ? triangle(raw) : raw % 1;
|
|
410
|
+
}
|
|
411
|
+
return clamp01(raw);
|
|
412
|
+
}
|
|
393
413
|
function clamp01(x) {
|
|
394
414
|
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
395
415
|
}
|
|
@@ -501,6 +521,7 @@ function GlyphPoints(props) {
|
|
|
501
521
|
keyframes,
|
|
502
522
|
count,
|
|
503
523
|
colors,
|
|
524
|
+
style,
|
|
504
525
|
cameraZ,
|
|
505
526
|
cameraFov,
|
|
506
527
|
pointer: pointerEnabled,
|
|
@@ -584,6 +605,9 @@ function GlyphPoints(props) {
|
|
|
584
605
|
uPointer: { value: new THREE.Vector3(0, 0, 0) },
|
|
585
606
|
uPointerActive: { value: 0 },
|
|
586
607
|
uSize: { value: 1 },
|
|
608
|
+
uSizeScale: { value: style.size },
|
|
609
|
+
uDrift: { value: style.drift },
|
|
610
|
+
uSparkle: { value: style.sparkle },
|
|
587
611
|
uPixelRatio: { value: 1 },
|
|
588
612
|
uColorInk: { value: colors.ink.clone() },
|
|
589
613
|
uColorAccent: { value: colors.accent.clone() }
|
|
@@ -781,9 +805,19 @@ function GlyphPoints(props) {
|
|
|
781
805
|
const mat = matRef.current;
|
|
782
806
|
if (!mat) return;
|
|
783
807
|
const u = mat.uniforms;
|
|
784
|
-
u.uPixelRatio.value = Math.min(window.devicePixelRatio || 1,
|
|
808
|
+
u.uPixelRatio.value = Math.min(window.devicePixelRatio || 1, 3);
|
|
785
809
|
u.uSize.value = Math.min(size.height / 18, 26);
|
|
786
810
|
}, [size]);
|
|
811
|
+
useEffect(() => {
|
|
812
|
+
const mat = matRef.current;
|
|
813
|
+
if (!mat) return;
|
|
814
|
+
const u = mat.uniforms;
|
|
815
|
+
u.uSizeScale.value = style.size;
|
|
816
|
+
u.uDrift.value = style.drift;
|
|
817
|
+
u.uSparkle.value = style.sparkle;
|
|
818
|
+
mat.blending = style.blend === "additive" ? THREE.AdditiveBlending : THREE.NormalBlending;
|
|
819
|
+
mat.needsUpdate = true;
|
|
820
|
+
}, [style.size, style.drift, style.sparkle, style.blend]);
|
|
787
821
|
useFrame((state, delta) => {
|
|
788
822
|
const p = pointsRef.current;
|
|
789
823
|
const mat = matRef.current;
|
|
@@ -791,7 +825,7 @@ function GlyphPoints(props) {
|
|
|
791
825
|
const u = mat.uniforms;
|
|
792
826
|
const d = Math.min(delta, 0.05);
|
|
793
827
|
const raw = THREE.MathUtils.clamp(getProgress(), 0, 1);
|
|
794
|
-
stage.current =
|
|
828
|
+
stage.current = raw;
|
|
795
829
|
const s = stage.current;
|
|
796
830
|
let settle = 0;
|
|
797
831
|
let burst = 0;
|
|
@@ -808,6 +842,11 @@ function GlyphPoints(props) {
|
|
|
808
842
|
if (lastIsText && n >= 2) {
|
|
809
843
|
form = smooth(times[n - 2] ?? 0, times[n - 1] ?? 1, s);
|
|
810
844
|
}
|
|
845
|
+
const firstIsText = timeline.isText[0] === true;
|
|
846
|
+
if (firstIsText && n >= 2) {
|
|
847
|
+
const formStart = 1 - smooth(times[0] ?? 0, times[1] ?? 1, s);
|
|
848
|
+
form = Math.max(form, formStart);
|
|
849
|
+
}
|
|
811
850
|
const guard = THREE.MathUtils.clamp(Math.max(settle, form), 0, 1);
|
|
812
851
|
guardRef.current = guard;
|
|
813
852
|
const swapped = raw >= timeline.swapAt ? 1 : 0;
|
|
@@ -858,7 +897,7 @@ function GlyphPoints(props) {
|
|
|
858
897
|
uniforms,
|
|
859
898
|
transparent: true,
|
|
860
899
|
depthWrite: false,
|
|
861
|
-
blending: THREE.NormalBlending,
|
|
900
|
+
blending: style.blend === "additive" ? THREE.AdditiveBlending : THREE.NormalBlending,
|
|
862
901
|
vertexShader,
|
|
863
902
|
fragmentShader: FRAGMENT_SHADER
|
|
864
903
|
}
|
|
@@ -872,6 +911,12 @@ var DEFAULT_COUNT_MOBILE = 5200;
|
|
|
872
911
|
var DEFAULT_CAMERA_Z = 7;
|
|
873
912
|
var DEFAULT_CAMERA_FOV = 42;
|
|
874
913
|
var DEFAULT_DPR = [1, 1.75];
|
|
914
|
+
var PRESETS = {
|
|
915
|
+
default: { size: 1, blend: "normal", drift: 1, sparkle: 1 },
|
|
916
|
+
minimal: { size: 0.92, blend: "normal", drift: 0.35, sparkle: 0 },
|
|
917
|
+
lively: { size: 1.05, blend: "normal", drift: 1.4, sparkle: 1.4 },
|
|
918
|
+
glow: { size: 1.1, blend: "additive", drift: 1.1, sparkle: 1.5 }
|
|
919
|
+
};
|
|
875
920
|
function clamp012(x) {
|
|
876
921
|
return x < 0 ? 0 : x > 1 ? 1 : x;
|
|
877
922
|
}
|
|
@@ -890,6 +935,8 @@ function GlyphDust(props) {
|
|
|
890
935
|
const {
|
|
891
936
|
keyframes,
|
|
892
937
|
driver = { type: "scroll" },
|
|
938
|
+
preset = "default",
|
|
939
|
+
style,
|
|
893
940
|
colors,
|
|
894
941
|
count,
|
|
895
942
|
dpr = DEFAULT_DPR,
|
|
@@ -913,15 +960,62 @@ function GlyphDust(props) {
|
|
|
913
960
|
const resolveRef = useRef(null);
|
|
914
961
|
const manualRef = useRef(0);
|
|
915
962
|
if (driver.type === "manual") manualRef.current = clamp012(driver.progress);
|
|
963
|
+
const autoplay = driver.type === "autoplay" ? driver : null;
|
|
964
|
+
const playingRef = useRef(false);
|
|
965
|
+
const startMsRef = useRef(null);
|
|
966
|
+
const lastAutoRef = useRef(0);
|
|
967
|
+
useEffect(() => {
|
|
968
|
+
if (!autoplay) return;
|
|
969
|
+
if (autoplay.playOnView === false) {
|
|
970
|
+
playingRef.current = true;
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const el = wrapperRef.current;
|
|
974
|
+
if (el === null || typeof IntersectionObserver === "undefined") {
|
|
975
|
+
playingRef.current = true;
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const io = new IntersectionObserver(
|
|
979
|
+
(entries) => {
|
|
980
|
+
for (const e of entries) {
|
|
981
|
+
if (e.isIntersecting && !playingRef.current) {
|
|
982
|
+
playingRef.current = true;
|
|
983
|
+
startMsRef.current = null;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
{ threshold: 0.25 }
|
|
988
|
+
);
|
|
989
|
+
io.observe(el);
|
|
990
|
+
return () => io.disconnect();
|
|
991
|
+
}, [autoplay?.playOnView]);
|
|
916
992
|
const getProgress = useCallback(() => {
|
|
917
993
|
if (driver.type === "manual") return manualRef.current;
|
|
994
|
+
if (driver.type === "autoplay") {
|
|
995
|
+
if (!playingRef.current || typeof performance === "undefined") {
|
|
996
|
+
return lastAutoRef.current;
|
|
997
|
+
}
|
|
998
|
+
if (startMsRef.current === null) startMsRef.current = performance.now();
|
|
999
|
+
const elapsed = (performance.now() - startMsRef.current) / 1e3;
|
|
1000
|
+
lastAutoRef.current = computeAutoplayProgress(elapsed, driver);
|
|
1001
|
+
return lastAutoRef.current;
|
|
1002
|
+
}
|
|
918
1003
|
const el = wrapperRef.current;
|
|
919
1004
|
if (el === null || typeof window === "undefined") return 0;
|
|
920
1005
|
const rect = el.getBoundingClientRect();
|
|
921
1006
|
const total = rect.height - window.innerHeight;
|
|
922
1007
|
if (total <= 0) return 0;
|
|
923
1008
|
return clamp012(-rect.top / total);
|
|
924
|
-
}, [driver
|
|
1009
|
+
}, [driver]);
|
|
1010
|
+
const resolvedStyle = useMemo(() => {
|
|
1011
|
+
const base = PRESETS[preset] ?? PRESETS.default;
|
|
1012
|
+
return {
|
|
1013
|
+
size: style?.size ?? base.size,
|
|
1014
|
+
blend: style?.blend ?? base.blend,
|
|
1015
|
+
drift: style?.drift ?? base.drift,
|
|
1016
|
+
sparkle: style?.sparkle ?? base.sparkle
|
|
1017
|
+
};
|
|
1018
|
+
}, [preset, style?.size, style?.blend, style?.drift, style?.sparkle]);
|
|
925
1019
|
const resolvedColors = useMemo(
|
|
926
1020
|
() => ({
|
|
927
1021
|
ink: new THREE.Color(colors?.ink ?? DEFAULT_INK),
|
|
@@ -958,6 +1052,7 @@ function GlyphDust(props) {
|
|
|
958
1052
|
keyframes,
|
|
959
1053
|
count: particleCount,
|
|
960
1054
|
colors: resolvedColors,
|
|
1055
|
+
style: resolvedStyle,
|
|
961
1056
|
cameraZ,
|
|
962
1057
|
cameraFov,
|
|
963
1058
|
pointer: pointerEnabled,
|
|
@@ -991,10 +1086,11 @@ function GlyphDust(props) {
|
|
|
991
1086
|
}
|
|
992
1087
|
) : null
|
|
993
1088
|
] });
|
|
994
|
-
if (driver.type === "manual") {
|
|
1089
|
+
if (driver.type === "manual" || driver.type === "autoplay") {
|
|
995
1090
|
return /* @__PURE__ */ jsx(
|
|
996
1091
|
"div",
|
|
997
1092
|
{
|
|
1093
|
+
ref: wrapperRef,
|
|
998
1094
|
className,
|
|
999
1095
|
style: { position: "relative", width: "100%", height: "100%" },
|
|
1000
1096
|
children: scene
|
|
@@ -1026,8 +1122,8 @@ function GlyphDust(props) {
|
|
|
1026
1122
|
}
|
|
1027
1123
|
|
|
1028
1124
|
// src/index.ts
|
|
1029
|
-
var VERSION = "0.1
|
|
1125
|
+
var VERSION = "0.2.1";
|
|
1030
1126
|
|
|
1031
|
-
export { DEFAULT_TRIGGER_HEIGHT, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, GlyphDust, VERSION, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
|
1127
|
+
export { DEFAULT_TRIGGER_HEIGHT, FRAGMENT_SHADER, GLYPH_POSITION_ATTRIBUTE_PREFIX, GlyphDust, VERSION, buildDenseTextTargets, buildGlyphFromDOM, buildTextTargets, buildVertexShader, computeAutoplayProgress, computeScreenRect, createScrollProgress, glyphPositionAttribute, prefersReducedMotion, useReducedMotion, useScrollProgress, viewSizeAtZ0 };
|
|
1032
1128
|
//# sourceMappingURL=index.js.map
|
|
1033
1129
|
//# sourceMappingURL=index.js.map
|