---
title: "GlassMotion コンポーネント — zenit Zig UI"
description: "ガラスの変形と、スクロールに合わせて浮かぶツールバー。変形アニメーション中やスクロール中は、backdrop を毎フレーム再サンプリングします。"
url: https://zenit.z.express/ja/components/glassmotion
language: ja
alternate_en: https://zenit.z.express/components/glassmotion.md
alternate_zh: https://zenit.z.express/zh/components/glassmotion.md
alternate_es: https://zenit.z.express/es/components/glassmotion.md
alternate_ko: https://zenit.z.express/ko/components/glassmotion.md
alternate_fr: https://zenit.z.express/fr/components/glassmotion.md
alternate_de: https://zenit.z.express/de/components/glassmotion.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# GlassMotion

`ui.widgets.GlassBox`

ガラスの変形と、スクロールに合わせて浮かぶツールバー。

[Video](https://zenit.z.express/media/stories/glassmotion.mp4?v=4eeab6c693)

**BEHAVIOR CONTRACT**

変形アニメーション中やスクロール中は、backdrop を毎フレーム再サンプリングします。

**RECORDED INTERACTION**

harness が Morph と Scroll +80 を実行します。

`examples/storybook/stories.zig:3604`

```zig
pub fn buildGlassMotion(scope: *ui.Scope, cx: *ui.Cx) anyerror!*ui.Node {
    const a = cx.allocator;
    const c = try col(cx, 16);

    // ── morph：绝对定位玻璃在两个几何/profile 之间过渡 ──
    try c.appendChild(a, try label(cx, "Morph — glass transitions between two geometries/profiles"));
    const morph_stage = try glassBackdrop(cx, 200);
    morph_stage.style.justify = .start;
    morph_stage.style.align_items = .start;
    const gm = try ui.widgets.GlassBox(.{ .title = "Morph", .width = 150, .height = 84 }).mountWithState(scope, cx);
    gm.box.style.position = .absolute;
    (try gm.box.style.ensureExtFallible(a)).inset = .{ .left = .{ .px = 12 }, .top = .{ .px = 12 } };
    gm.box.meta.ownership.meta.test_id = "story.glassmotion.morph";
    try morph_stage.appendChild(a, gm.box);
    try c.appendChild(a, morph_stage);

    // ── scroll-edge：玻璃工具条覆盖 ScrollArea 顶部，滚动出现边缘渐变 ──
    try c.appendChild(a, try label(cx, "Scroll-edge — glass bar over scrolling content"));
    const se_stage = try ui.box(cx, .{ .width = .{ .px = 420 }, .height = .{ .px = 220 }, .position = .relative }, .{});
    const sa = try W.mountScrollArea(.{ .width = 420, .height = 220, .direction = .vertical }, scope, cx);
    var i: usize = 0;
    while (i < 40) : (i += 1) {
        var buf: [32]u8 = undefined;
        const txt = try std.fmt.bufPrint(&buf, "Content row {d}", .{i});
        try sa.content.appendChild(a, try ui.text(cx, txt, .{ .font_size = 13, .color = light.color.fg_primary }));
    }
    try se_stage.appendChild(a, sa.container);
    const bar = try ui.widgets.GlassBox(.{ .height = 44, .padding = ui.Padding.symmetric(8, 12) })
        .scrollEdge(.{ .scroll = sa.state, .edge = .top, .fade_width = 28 })
        .mountWithState(scope, cx);
    bar.box.style.position = .absolute;
    bar.box.style.width = .{ .px = 420 };
    (try bar.box.style.ensureExtFallible(a)).inset = .{ .left = .{ .px = 0 }, .top = .{ .px = 0 } };
    bar.box.meta.ownership.meta.test_id = "story.glassmotion.bar";
    try bar.body.appendChild(a, try glassLabel(cx, "Floating glass toolbar", 600));
    try se_stage.appendChild(a, bar.box);
    try c.appendChild(a, se_stage);

    const st = try cx.bindState(GlassMotionStory, .{ .glass = gm.state, .scroll = sa.state, .content = sa.content });
    const controls = try ui.box(cx, .{ .direction = .row, .gap = 10 }, .{});
    const morph_btn = try W.Button(.{ .label = "Morph", .on_click = cx.on(GlassMotionStory, st, GlassMotionStory.morph) }).mount(scope, cx);
    morph_btn.meta.ownership.meta.test_id = "story.glassmotion.morphbtn";
    try controls.appendChild(a, morph_btn);
    const scroll_btn = try W.Button(.{ .label = "Scroll +80", .on_click = cx.on(GlassMotionStory, st, GlassMotionStory.scrollDown) }).mount(scope, cx);
    scroll_btn.meta.ownership.meta.test_id = "story.glassmotion.scrollbtn";
    try controls.appendChild(a, scroll_btn);
    try c.appendChild(a, controls);
    return c;
}
```

[GitHub でソースを見るexamples/storybook/stories.zig:3604](https://github.com/version-next/zenit/blob/HEAD/examples/storybook/stories.zig#L3604)

Storybook にあるこの story のコードそのままです（zenit 5f9add5+wip 2026-09-30）。`W` は `ui.widgets` のことで、`col` / `row` / `label` は Storybook 内の小さなレイアウトヘルパーです。

### GlassBoxProps

`ui.widgets.GlassBox`

[src/ui/components/glass\_box/mod.zig:48](https://github.com/version-next/zenit/blob/HEAD/src/ui/components/glass_box/mod.zig#L48)

```zig
fn GlassBox(props: GlassBoxProps) GlassBoxBuilder
```

| フィールド | 型 | デフォルト値 | 説明 |
| --- | --- | --- | --- |
| `title` | `?[]const u8` | `null` | — |
| `subtitle` | `?[]const u8` | `null` | — |
| `width` | `?f32` | `null` | — |
| `height` | `?f32` | `null` | — |
| `padding` | `?Padding` | `null` | — |
| `body_gap` | `f32` | `12` | — |
| `radius` | `f32` | `18` | — |
| `readability` | `GlassBoxReadability` `.balanced` `.preferred` `.maximum` | `.preferred` | — |
| `emphasis` | `GlassBoxEmphasis` `.subtle` `.regular` `.prominent` | `.regular` | — |
| `variant` | `GlassBoxVariant` `.regular` `.clear` | `.regular` | — |
| `tint` | `?Color` | `null` | — |
| `interactive` | `bool` | `false` | Apple Liquid Glass interactive：hover 提亮高光、press 玻璃增厚 + 微放大。 |
| `scroll_edge` | `?ScrollEdgeBinding` | `null` | scroll-edge effect：绑定 ScrollArea 后，内容滚过玻璃边缘时出现渐进 模糊/压暗带（随滚动位置实时驱动 + 插值平滑）。 |

### \*Node

`ui.widgets.GlassBox`

mount は `*Node` を直接返します。親ノードに append してください。
