Live Demo · GitHub Repository · npm Package
A React background component that recreates the soft animated HyperOS-style backdrop with WebGL.
The package currently exposes a single component: BgEffectBackground.
This implementation was recreated by studying and reimplementing the logic from the original BgEffectBackground.kt in the miuix project:
Many thanks to the original author(s) and the compose-miuix-ui/miuix project for the source inspiration.
- HyperOS-inspired gradient background rendered with
canvas+ WebGL - Two shader paths:
OS2andOS3 - Built-in presets for
PHONEandPAD - Built-in light and dark color schemes
- Optional animated color-stage transitions
- Custom color override via the
colorsprop - Configurable alpha and host/background styling
- Content slot via
childrenor thecontentprop - SSR-friendly markup output with browser-only WebGL setup in
useEffect
npm install hyperos-bgpnpm add hyperos-bgPeer dependencies:
react >= 18react-dom >= 18
import { BgEffectBackground } from "hyperos-bg";BgEffectBackground extends ComponentPropsWithoutRef<"div"> except for the native content prop.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
dynamicBackground |
boolean |
no | true |
Enables animated stage-to-stage color interpolation. |
bgStyle |
CSSProperties |
no | undefined |
Inline styles applied to the internal <canvas>. |
isFullSize |
boolean |
no | false |
Uses the full host height instead of the default cropped draw region. |
effectBackground |
boolean |
no | true |
Disables the shader contribution when false while preserving layout/content. |
isOs3Effect |
boolean |
no | false |
Switches between the newer OS3 shader/preset set and the older OS2 one. |
deviceType |
"PHONE" | "PAD" |
no | "PAD" |
Selects the geometric preset family. |
colorScheme |
"light" | "dark" |
no | "light" |
Selects the preset color scheme. |
colors |
Partial<BgEffectColors> |
no | undefined |
Overrides preset colors. See Custom colors. |
alpha |
() => number |
no | () => 1 |
Returns the current effect alpha. Values are clamped to 0..1. |
content |
ReactNode | (() => ReactNode) |
no | undefined |
Content rendered above the canvas. Takes priority over children. |
children |
ReactNode |
no | undefined |
Fallback content when content is not provided. |
The package ships TypeScript declarations and exports BgEffectBackgroundProps.
import { BgEffectBackground, type BgEffectBackgroundProps } from "hyperos-bg";
const backgroundProps: BgEffectBackgroundProps = {
dynamicBackground: true,
effectBackground: true,
deviceType: "PAD",
colorScheme: "dark",
bgStyle: { opacity: 1 },
};
export function TypedHero() {
return (
<BgEffectBackground
{...backgroundProps}
alpha={() => 0.92}
style={{ minHeight: 480, borderRadius: 28 }}
>
<div style={{ minHeight: 480 }} />
</BgEffectBackground>
);
}import { BgEffectBackground } from "hyperos-bg";
export function Hero() {
return (
<BgEffectBackground
dynamicBackground
effectBackground
isOs3Effect
deviceType="PAD"
colorScheme="dark"
alpha={() => 0.96}
style={{ minHeight: 520, borderRadius: 32 }}
bgStyle={{ opacity: 1 }}
>
<div
style={{
minHeight: 520,
display: "grid",
placeItems: "end start",
padding: 32,
color: "white",
}}
>
<h2 style={{ margin: 0, fontSize: 56 }}>HyperOS Background</h2>
</div>
</BgEffectBackground>
);
}<BgEffectBackground
dynamicBackground={false}
effectBackground
colorScheme="light"
bgStyle={{ opacity: 1 }}
content={() => <div>Overlay content</div>}
/>The colors prop overrides the preset color stages. Each stage is an array of 16 floats: 4 RGBA colors (one per light blob) in 0..1 range. Provided stages replace the preset ones; omitted stages keep the preset values.
import { BgEffectBackground } from "hyperos-bg";
const customColors = {
colors1: [
0.55,
0.36,
0.96,
0.9, // blob 1: purple
0.93,
0.28,
0.6,
0.9, // blob 2: pink
0.23,
0.51,
0.96,
0.9, // blob 3: blue
0.96,
0.62,
0.04,
0.9, // blob 4: orange
],
colors2: [
/* ... */
],
colors3: [
/* ... */
],
};
<BgEffectBackground isOs3Effect colors={customColors} bgStyle={{ opacity: 1 }} />;When dynamicBackground is enabled, the effect transitions between colors1 → colors2 → colors3 over time. Setting all three stages to the same array keeps the colors static. Keep the colors object stable (e.g. via useMemo) so the WebGL context is not recreated on every render.
- The component renders a wrapping
<div>, an absolutely positioned<canvas>, and a foreground content layer. - WebGL setup happens only on the client inside
useEffect. - If WebGL is unavailable, the component still renders its layout and foreground content; only the shader effect is skipped.
This repository uses Vite+.
vp install
vp devOpen the preview page to interact with the live playground from demo/main.tsx.
Useful commands:
vp check
vp test
vp pack
vp buildvp buildbuilds the demo site for GitHub Pages intosite/vp packbuilds the publishable package intodist/
src/
BgEffectBackground.tsx # Public React component
index.ts # Package exports
webgl/
os2-preset.ts # OS2 preset values
os2-shader.ts # OS2 fragment shader
os3-preset.ts # OS3 preset values
os3-shader.ts # OS3 fragment shader
presets.ts # Preset selector
shaders.ts # Shader selector + vertex shader
types.ts # Shared types
utils.ts # WebGL and interpolation helpers
demo/
main.tsx # Interactive preview playground
styles.css # Preview page styles
tests/
index.test.tsx # Server-render tests for wrapper/content- Presets are selected by
deviceType,colorScheme, andisOs3Effect. - Animated transitions are driven by a spring-smoothed stage index.
- The default non-full-size mode draws into a cropped region (
78%of host height). - The package exports
BgEffectBackground,BgEffectBackgroundProps, andBgEffectColors.
Before publishing or cutting a release, run:
vp check
vp test
vp pack