Liquid DOM
AndrewPrifer/liquid-dom · WebGPU liquid-glass · pnpm monorepo
Liquid DOM は、WebGPU で iOS 風リキッドグラス UI を描画するモノレポ。命令型シーングラフ、React 19 バインディング、Three.js / React Three Fiber 統合、レンダラー非依存の SwiftUI 風レイアウトを、統合レイヤごとに分割した npm パッケージとして提供する。
@liquid-dom/react、Three WebGPU 上に合成する場合は @liquid-dom/three / @liquid-dom/r3f。レイアウトだけ必要なら @liquid-dom/layout は他パッケージに依存しない。
| パッケージ | 役割 | 使う場面 |
|---|---|---|
@liquid-dom/core |
命令型シーングラフ、WebGPU Renderer、再利用可能な WebGPU コア、@liquid-dom/core/layout サブパス |
シーングラフを直接制御する、または別レンダラー向けアダプタを自作する |
@liquid-dom/react |
React 19 バインディング(LiquidCanvas / LiquidScene) |
React でグラス UI を宣言し、canvas とフレームループを LiquidCanvas に任せる |
@liquid-dom/three |
Three の WebGPU レンダラー内で liquid-glass コアをホスト | Three シーンを backdrop として描画し、その上にグラスをポスト合成する |
@liquid-dom/r3f |
@liquid-dom/three と @liquid-dom/react の R3F ブリッジ |
React Three Fiber + Three WebGPU で React グラス UI を重ねる |
@liquid-dom/layout |
レンダラー非依存の SwiftUI 風レイアウトエンジン | 測定・配置だけ必要で、WebGPU や React に依存したくない |
%%{init: {'theme': 'base', 'themeVariables': { 'fontSize': '14px', 'primaryColor': '#d4e8f4', 'primaryTextColor': '#1a2a35', 'primaryBorderColor': '#3a7a9a', 'lineColor': '#3a7a9a', 'secondaryColor': '#eef6fa', 'tertiaryColor': '#f5f0e0' }}}%%
flowchart TD
layout["@liquid-dom/layout"]
core["@liquid-dom/core"]
react["@liquid-dom/react"]
three["@liquid-dom/three"]
r3f["@liquid-dom/r3f"]
layout --> core
core --> react
core --> three
react --> r3f
three --> r3f
@liquid-dom/layout は独立。@liquid-dom/core が layout サブパスで利用。@liquid-dom/react は core の layout クラスを React コンポーネント化。@liquid-dom/three は Three WebGPU 内にコアをホスト。@liquid-dom/r3f が React と Three を結合する。
| ノード | 子として受け付ける型 | 要点 |
|---|---|---|
Scene |
Container, Html, Group |
ルート。兄弟は zIndex → 追加順で描画 |
Container |
Glass, Group |
同一 Container 内の Glass は 1 つの SDF フィールドに融合し光学設定を共有 |
Glass |
Html, Group |
cornerRadius + cornerSmoothing で squircle 近似。子 Html をグラス越しにサンプリング |
Html |
— | ライブ DOM を GPU テクスチャへコピー。blur はレンダラー側の適応ブラー |
Group / StackingContext |
親に応じた子 | Group は変換の合成。StackingContext は zIndex で子をグループ化 |
シーン直下の Html は、下位の Container の backdrop になる。より手前の Container より上にある Html は覆い、後続 Container の backdrop になる。
Adaptive blur
Html.blur > 0 のとき適応ブラーパイプライン。CSS filter ではなく DOM コピー後の GPU 処理。
Adaptive tint
Container の tint / blur / thickness で光学パラメータを一括制御。
Pointer events
Glass.pointerEvents でヒットテスト。命令型 API では typed リスナー、React では通常の DOM イベント。
Three 合成
Three シーンを RenderTarget に描画し、backdrop テクスチャとして ThreeGlassRenderer に渡す。
import { Container, Glass, Html, Renderer, Scene } from '@liquid-dom/core'
const scene = new Scene()
const container = new Container({ blur: 12, spacing: 28, thickness: 90 })
const glass = new Glass({ width: 280, height: 180, cornerRadius: 48, pointerEvents: true })
glass.add(new Html({ width: 180, height: 56, element: contentButton }))
container.add(glass)
scene.add(container)
const renderer = new Renderer({ scene })
document.body.append(renderer.canvas)
requestAnimationFrame(function frame() { renderer.render(); requestAnimationFrame(frame) })
import { Frame, Glass, GlassContainer, Html, LiquidCanvas } from '@liquid-dom/react'
export function App() {
return (
<LiquidCanvas style={{ width: '100vw', height: '100vh' }}>
<GlassContainer blur={12} spacing={28}>
<Frame width={280} height={160}>
<Glass cornerRadius={44} pointerEvents>
<Html sizing="fill"><button>Native content</button></Html>
</Glass>
</Frame>
</GlassContainer>
</LiquidCanvas>
)
}
LiquidScene は canvas を作らない headless モード。Three アダプタなど別レンダラーが出力を所有するときに ref 経由で update(proposal, delta) を呼ぶ。
import * as THREE from 'three/webgpu'
import { Container, Glass, Scene } from '@liquid-dom/core'
import { ThreeGlassRenderer } from '@liquid-dom/three'
const renderer = new THREE.WebGPURenderer({ canvas })
await renderer.init()
const backdrop = new THREE.RenderTarget(1, 1, { colorSpace: THREE.SRGBColorSpace })
const glassRenderer = new ThreeGlassRenderer({ renderer, scene: glassScene })
function frame() {
renderer.setRenderTarget(backdrop)
renderer.render(threeScene, camera)
renderer.setRenderTarget(null)
glassRenderer.render({ backdrop, width, height })
requestAnimationFrame(frame)
}
three/webgpu の WebGPURenderer が前提。
pnpm add @liquid-dom/core
pnpm add @liquid-dom/react react react-dom
pnpm add @liquid-dom/three @liquid-dom/core three
pnpm add @liquid-dom/r3f @liquid-dom/react @react-three/fiber react react-dom three
pnpm add @liquid-dom/layout
各パッケージ README に peer dependency の完全な一覧がある。React バインディングは React 19 を想定。
pnpm install
pnpm -r build
pnpm --filter @liquid-dom/layout test
pnpm --filter @liquid-dom/core test
pnpm --filter @liquid-dom/react test
# デモ(ルート package.json scripts)
pnpm dev # core + editor
pnpm dev:minimal # core + react + minimal demo
pnpm dev:three # core + three + three-integration
pnpm dev:three-react # + three-react-integration
pnpm dev:three-r3f # + three-r3f-integration
| 要件 | 対象 | 詳細 |
|---|---|---|
navigator.gpu |
グラス描画全体 | WebGPU 対応ブラウザが必須。シーングラフ構築だけならブラウザ風環境でも可 |
| HTML-in-Canvas | Html ノード |
実験 API。<canvas layoutsubtree> と canvas paint イベントで DOM をテクスチャ化 |
| Chrome フラグ | DOM バックド Html | chrome://flags/#canvas-draw-element を有効化(2026-05 時点) |
| Three WebGPU | @liquid-dom/three / r3f |
WebGLRenderer ではなく WebGPURenderer |
- GitHub: AndrewPrifer/liquid-dom — モノレポ本体
- README.md — パッケージ一覧とインストール
- packages/core — シーングラフ・Renderer API
- packages/react — LiquidCanvas / レイアウトコンポーネント
- WICG HTML-in-Canvas — Html ノードの前提 API