Shader <mv-shader>

独自のフラグメントシェーダーのためのフルフレーム WebGL2 エンジン:インライン GLSL、貼り付けた完全なシェーダー、シングルパスの mainImage() のいずれも要素のコンテンツの背後で動作し、ポインター、スクロール、テーマトークンの uniform が用意されています。

仕組み

独自のフラグメントシェーダーのためのフルフレーム WebGL2 エンジン:インライン GLSL、貼り付けた完全なシェーダー、シングルパスの mainImage() のいずれも要素のコンテンツの背後で動作し、ポインター、スクロール、テーマトークンの uniform が用意されています。画面外では一時停止し、ページの WebGL コンテキストの予算を共有し、モーション軽減では静止フレームを保ち、WebGL2 がない場合はトークンによるスケッチにフォールバックします。GLSL がない場合は、テーマカラーで漂う独自の等高線マップを描きます。

カテゴリー背景
タイプWeb Component(<mv-shader>)
ステータス安定版
Keywordssafe-rewrite, webgl, glsl, shader, background, runtime, contour

When to use

  • A custom fragment shader must run as a section background with off-screen pause and reduced motion built in
  • A reusable branded background should be built by subclassing with its own uniforms and GLSL
  • An existing GLSL effect needs to be ported without adding a WebGL library
  • A quiet, theme-aware contour texture is wanted behind a hero or a feature band

Avoid when

  • A ready-made preset already matches the look, e.g. a fluid brand gradient → use Mesh Gradient instead
  • Nobody on the team maintains GLSL; a CSS background is easier to own → use Aurora Background instead
  • More than 10 shaders are on screen at once; only 10 WebGL contexts stay live, so the extra ones keep being rebuilt

インストール

node scripts/add.mjs shader --out ./src/marvelous

Marvelous UI の MCP サーバーを使う AI エージェント:install_components({ slugs: ["shader"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。

コピーされるファイル(依存関係を含む):tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/i18n.js, core/motion.js, core/observe.js, core/webgl.js, components/shader/shader.js, components/shader/shader.css。

使い方

基本となるマークアップです。ここから属性、data-*、CSS 変数でカスタマイズしてください:

<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));width:100%;height:100%;min-height:320px">
  <mv-shader style="min-height:320px;display:grid;align-content:end;padding:1.25rem;color:var(--mv-fg)">
    <p style="margin:0;width:fit-content;padding:.6rem .85rem;border-radius:var(--mv-radius-md);background:color-mix(in oklch,var(--mv-bg) 82%,transparent);backdrop-filter:blur(6px);font:600 1.05rem/1.35 var(--mv-font-sans)">Built-in default<br><span style="font-weight:400;font-size:.85rem;color:var(--mv-fg-muted)">Contour map in your theme tokens. Hover to raise it.</span></p>
  </mv-shader>
  <mv-shader style="min-height:320px;display:grid;align-content:end;padding:1.25rem;color:var(--mv-fg)">
    <script type="x-shader/x-fragment">
      // Your GLSL ES 3.0: u_time, u_resolution, u_dpr, u_mouse, u_hover and u_palette are provided.
      void main() {
        vec3 ink = u_palette[0];
        vec3 paper = u_palette[1];
        float cell = 14.0 * u_dpr;
        vec2 f = fract(gl_FragCoord.xy / cell) - 0.5;
        vec2 c = (floor(gl_FragCoord.xy / cell) + 0.5) * cell / u_resolution.y;
        vec2 m = u_mouse * u_resolution / u_resolution.y;
        float wave = 0.5 + 0.3 * sin(c.x * 9.0 + c.y * 5.0 - u_time * 1.2) + 0.2 * sin(c.y * 13.0 - c.x * 4.0 + u_time * 0.8);
        wave += 0.6 * u_hover * exp(-dot(c - m, c - m) * 16.0);
        float calm = smoothstep(0.05, 0.55, gl_FragCoord.y / u_resolution.y);
        float r = 0.05 + 0.37 * clamp(wave, 0.0, 1.0) * calm;
        float dot_ = 1.0 - smoothstep(r - 1.0 / cell, r + 1.0 / cell, length(f));
        fragColor = vec4(mix(paper, ink, dot_ * 0.85), 1.0);
      }
    </script>
    <p style="margin:0;width:fit-content;padding:.6rem .85rem;border-radius:var(--mv-radius-md);background:color-mix(in oklch,var(--mv-bg) 82%,transparent);backdrop-filter:blur(6px);font:600 1.05rem/1.35 var(--mv-font-sans)">Your own GLSL<br><span style="font-weight:400;font-size:.85rem;color:var(--mv-fg-muted)">Inline halftone, same pause and theme handling.</span></p>
  </mv-shader>
</div>

API

Attributes

NameタイプDefaultDescription
colorsCSS colors (3)var(--mv-accent), var(--mv-bg), var(--mv-fg)Palette of <mv-shader> itself, as u_palette[3] (ink, paper, text): drawn by the built-in contour map and available to inline GLSL. Tokens accepted, read again on theme change.
speednumber1Time multiplier.
pausedbooleanFreezes the animation on the current frame.
interactivebooleanFollows the pointer only over the element (otherwise across the whole window).
dprnumber1.5Max pixel density (capped at 2).
data-fillbooleanFills the positioned parent (absolute, inset 0).

Properties

NameタイプDescription
fragmentstring | nullThe GLSL that runs. Setting it recompiles on the next frame; null goes back to the inline script or the built-in contour map.
static fragment / uniforms / chunksTo build a reusable background: class MvFoo extends MvShader { static chunks = ["noise"]; static uniforms = { u_colors: { attr: "colors", type: "colors", default: "var(--mv-accent), #0ea5e9", count: 3 } }; static fragment = void main() { … } }. Uniform types: number, color, colors, vec2, vec3, vec4, boolean. GLSL chunks: hash (hash12, hash22), noise (snoise, fbm), color (palette, gradient3).

Events

NameDescription
mv-errorThe GLSL failed to compile or link. detail: { message } (the compiler log). The element gets data-error and shows its fallback.

Content structure

NameDescription
<script type="x-shader/x-fragment">GLSL ES 3.0: a main() body, a complete shader, or a single-pass mainImage() (iTime, iResolution, iMouse mapped; no iChannel). Provided uniforms: u_time, u_resolution, u_dpr, u_mouse, u_hover, u_scroll, u_palette. data-chunks="noise color" adds GLSL chunks.
childrenContent placed inside the element sits above the canvas.

Accessibility

Decorative: the canvas is aria-hidden and never takes pointer events; content placed inside stays in the normal reading order. The loop stops off screen and in hidden tabs, and no context is created until the element comes near the viewport. Reduced motion (OS or <html data-motion="reduce">) and paused keep a still, representative frame. Without WebGL2, or when the GLSL does not compile, a static contour sketch in the theme tokens is shown; forced colors and print hide the canvas. Text placed over a custom shader needs its own contrast check.

このページは AI で翻訳されています。翻訳の問題を報告