Site landing-hero (blocklets/arcblock/.web/components/landing-hero/) accepts an optional
heroVisual prop that renders a full-bleed .landing-hero-visual target div behind the copy. Pair
it with an AUP widget child block naming a Web Device widget (here, webgl-hero — WebGL 3D
backgrounds, 24 modes, shipped with the runtime) and the hero becomes a real demonstration of what
Web Device's widget layer can render, not decoration bolted onto the page.
This page is a running catalog, not a tutorial: each candidate below is a real render with its exact config, kept here so a future pass doesn't have to re-derive which modes actually work and which look right for this site's editorial tone — see "Dead ends" for the ones that don't.
Gallery
All 24 webgl-hero modes, using this site's own ::gallery{folder} media block (see
Folder-backed media gallery) rather than a hand-built grid. Each mode's caption
notes what it renders and whether it reads the colors config or hardcodes its own palette; full
config and larger screenshots are in the reference section further down the page.
























How this is wired
component hero slot=site-introduction component=landing-hero variant=home
headlineVariant=balanced-statement maxLines=3 heroVisual=webgl
title=:k0 subtitle=:k1 ... {
widget hero-bg name=webgl-hero target=".landing-hero-visual" mode=topo
colors="#008f7a,#fcfdfc" opacity=0.5 speed=0.4 mouse=false
}heroVisual=webgl switches the component to single-column copy with a fixed max-width and a
readability scrim. Horizontal coverage is sized off the copy box (not the section — a scrim sized
in vw/% drifts out of sync with the text the wider the browser window gets). Vertical coverage
has to reach the hero edges: the copy sits in a padded, vertically-centered inner, so a scrim
that only extends a few rem around the copy leaves a strip of uncovered canvas under the header.
The trace/geometry aside used elsewhere on this site is suppressed when heroVisual is set —
pick one visual per hero, not both.
Below 760px the widget doesn't run at all — a small inline script registers a DOMContentLoaded
listener early enough to remove the widget's config <script> before the engine's own listener ever
scans for it, so no WebGL context, no Three.js, no render loop gets created on a phone. Matches this
site's rule that mobile layouts don't run WebGL/canvas effects; a plain hero (headline, subtitle,
actions) renders instead.
Live comparison pages (internal, not in nav): /en/hero-lab-topo/, /en/hero-lab-aurora/,
/en/hero-lab-cubegrid/ — same copy as the homepage hero, different heroVisual config, useful for
side-by-side judgment in a real browser before anything ships to the homepage itself.
These render correctly only against a locally-built arc. The CSS-override and opacity bugs
below are fixed upstream in ArcBlock/arc#4402 (merged),
and the topo coverage/aspect fix is in
ArcBlock/arc#4490 — until whichever of those hasn't
shipped in a release lands on the arc binary actually serving this blocklet, the live pages above
can still show the un-fixed behavior (widget mounts but collapses to height:0, or topo stretched
on wide screens). The screenshots in each candidate section are the honest record of what this looks
like on a fixed build; the live links are for local verification, not a guarantee of what the
deployed site currently shows.
Candidates
topo — dense contour fill

mode=topo colors="#008f7a,#fcfdfc" colorsDark="#2ec8ae,#061211" opacity=0.5 speed=0.4 mouse=falseVerdict: strongest candidate so far. Reads as a real technical texture (elevation lines), not a
generic AI-tech gradient, and holds up at both narrow and ultra-wide viewports once the plane-sizing
fix below landed. Full opacity control works (this mode respects opacity).
Known gaps fixed while building this:
TopoEngineused a fixed-sizePlaneGeometry(30, 20), which only covers hero aspect ratios up to about 2.4 — any wider browser window ran past the plane's edge and showed bare fill color down both sides. Fixed upstream to size the plane from the camera's actual visible frustum at render time (see "Upstream fixes" below).- That coverage fix exposed a second bug: the noise shader samples
vUv * 6.0on both axes, and vUv is 0-1 per axis regardless of the plane's physical aspect ratio — on a wide plane each noise cycle covers more physical width than height, so contours read as horizontally stretched streaks instead of round elevation-line blobs. Fixed upstream by scaling only the x sample by the plane's aspect ratio, keeping a noise cycle the same physical size on both axes. - The widget's
colorsconfig is static and theme-unaware — a light-mode config rendered as a bright rectangle in dark mode.landing-hero's render.js now accepts a matchingcolorsDark/bgDarkpair and swaps them in client-side before the widget parses its config, if the page loads with dark mode already active. Known remaining gap: switching the theme toggle live (no reload) does not retroactively recolor the already-rendered canvas — the swap only applies at load time.
aurora — atmospheric gradient

mode=aurora colors="#008f7a,#2ec8ae,#0f3d38" opacity=0.5 speed=0.4 mouse=falseVerdict: visually striking but reads closer to a generic "AI product" demo than this site's restrained editorial tone. Still needs either a lower-contrast color set or a narrower subtitle measure before it's a real candidate, not just a working one.
Bug found while building this: a dark, hard-edged band ran across the top of the hero, right
below the header. An earlier pass measured the section, the .landing-hero-visual target, and
the canvas as pixel-identical via getBoundingClientRect(), concluded it wasn't CSS, and spent
three attempts tuning camera.lookAt() on aurora / ocean / retrowave. That diagnosis was
wrong. The canvas does fill the section; the missing coverage is the readability scrim on
.landing-hero-copy::before. The copy sits in a padded, vertically-centered inner, and the
scrim only extended ±8rem around that box — about 45px of uncovered canvas under the header at
1440px, more at other widths. Dark modes make that strip obvious; light modes like topo hide
it. The published "fixed" retrowave screenshot still showed the band.
The actual fix is in landing-hero CSS: keep the scrim's horizontal sizing tied to the copy,
and stretch it vertically past the section (top/bottom: -100vmax, clipped by
.landing-hero { overflow: hidden }). Verified at 600/868/1221/1440/1920px. Camera tilt can
still leave empty sky in the 3D scene itself; that is a different, remaining widget issue, not
the header gap.
cubegrid — geometric wireframe grid

mode=cubegrid colors="#008f7a" opacity=0.6 speed=0.5 mouse=falseVerdict: the strongest thematic fit — the rotating wireframe cubes echo the actual ArcBlock
cube/pyramid mark instead of being an unrelated texture, and a single accent color keeps it quiet.
Worth testing against positioning.md's "would this still make sense on a generic AI site" question
before committing — the geometry argument is specific to us, but the effect alone is a common
pattern.
Dead ends
Rendered and screenshotted, not just described from reading the source — a mode that "should" work on
paper can still fail on screen, and the reverse (see rings below, corrected after actually looking).
Also live (internal, not in nav) for the same local-build caveat as above: /en/hero-lab-network/,
/en/hero-lab-wave/, /en/hero-lab-rings/.
network — dead, ignores brand color entirely

mode=network colors="#008f7a,#0f3d38" opacity=0.5 speed=0.4 mouse=falseVerdict: dead end, not a style judgment — NetworkEngine hardcodes its palette directly in the GLSL
fragment shader and never reads cfg.colors, so the teal config above has zero effect; what renders
is a generic blue-white constellation look with no connection to this site's palette. Not usable until
that color-hardcoding gap is fixed upstream (tracked in the issue, not fixed in this PR — bigger
change than the mechanical opacity fix).
wave — dead, too sparse to read as a background

mode=wave colors="#008f7a,#1f7a6e" bg="#fcfdfc" opacity=0.85 speed=0.4 mouse=falseVerdict: dead end. Technically the best-behaved mode (respects both opacity and colors, no
upstream bugs), but the wireframe sphere is small and sparse relative to a 1440×600+ full-bleed
canvas — it reads as a tiny starburst floating in mostly-empty space, not a background.
rings — not chosen, but wrongly assumed sparse before actually rendering it

mode=rings colors="#008f7a" bg="#fcfdfc" opacity=0.85 speed=0.4 mouse=falseVerdict: correction — an earlier draft of this page grouped rings with wave as "too sparse" based
on reading the engine's source, without actually rendering it. It isn't sparse at all: 18 overlapping
rings read as a bold, cohesive wireframe globe. Not chosen for a different reason, checked against
positioning.md's self-test ("would this still make sense on any generic AI site?") — a wireframe
globe/orbit is a common tech-marketing cliché with no connection to this site's own content, unlike
cubegrid's actual cube/pyramid mark. Left out on that basis, not because it doesn't render well.
Also surveyed
webgl-hero ships 24 modes total. The six above are the ones worth a real decision; the rest were
rendered and screenshotted for completeness, not left as an assumption from reading the source. Same
config shape throughout unless noted: teal-family colors, bg="#fcfdfc", opacity=0.6,
speed=0.4, mouse=false. Every mode covered on this page has a matching live page (internal, not
in nav) at /en/hero-lab-<mode>/, same local-build caveat as above.
Ignores the color config entirely (confirmed via source, not just the render)
crystal, phantom, lightcube, reflect, gyroid, tunnel, and abstract never read
cfg.colors — each hardcodes its own palette in-shader, the same class of bug as network. None are
usable without that fix landing upstream (not attempted here — bigger surface than the mechanical
opacity fix).
| Mode | Screenshot | Note |
|---|---|---|
| crystal | ![]() | Off-brand purple/blue glass shards. |
| phantom | ![]() | Off-brand white bokeh glow. |
| lightcube | ![]() | Muddy, off-brand, part of the frame renders flat black. |
| reflect | ![]() | Reads as stacked cardboard boxes, not abstract. |
| gyroid | ![]() | Psychedelic, jarring, wrong tone entirely. |
| tunnel | ![]() | Off-brand magenta/gold, mostly a black void. |
| abstract | ![]() | Off-brand iridescent oil-slick look. |
Too sparse or too small to read as a background

blob, collapse, meshline — same failure mode as wave: technically fine, geometrically too
thin against a full-bleed 1440×600+ canvas to register as a background at a glance.
Renders fine but reads as a generic tech-marketing cliché

galaxy — a bold, dense network-globe. Same call as rings: common "blockchain network" stock
imagery, not specific to this site.

landscape — full-bleed mountain/road/sunset scene. Reads as generic stock photography; also
ignored the teal config (rendered in neutral grays/tans regardless). Still not a candidate for
the stock-photo reason.

retrowave — the textbook synthwave sunset. The most generic "AI demo site" cliché in the whole
set; also overlaps the subtitle enough to hurt readability. The header-gap on this mode is the
CSS scrim bug described under aurora (screenshot above is after that fix; the grid floor is
still in the scene). Still not a candidate for the cliché reason.
Chaotic / visually noisy

cube — a wireframe box with heavy vertex jitter. Reads as a rendering glitch rather than an
intentional effect, and its right edge sits under the subtitle text.
On-brand color, decent render, not chosen for content reasons

ocean — actually picks up the teal config correctly (the "water" fill is on-brand) and looks calm.
Not chosen because the content itself — a literal ocean/sunset scene — has no connection to software
or this site's subject matter.

metaball — also correctly on-brand (soft teal glow blobs), the best-looking of this group. Reads as
a generic "lava lamp" ambient effect; kept as a fallback option worth reconsidering if none of the
three main candidates survive further design review.

marble — originally rendered nothing at all: two texture files it loader.load()s
(marble-noise.jpg, marble-noise3d.jpg) 404'd in every environment, never shipped anywhere in the
widget package. Filed as ArcBlock/arc#4417 and fixed
upstream in ArcBlock/arc#4440 (merged) by replacing the
missing textures with procedural noise. Now renders — a single large glossy sphere, on-brand color,
but no visible marble veining came through from the procedural swap; reads as a generic glass/chrome
orb rather than anything specific to this site. Not chosen for the same reason as metaball: a
correct, on-brand render of a generic effect.
Broken

clouds — rendered as a flat gradient wash with no visible volumetric detail. CloudsEngine has GPU
tier detection that drops march-step quality on a detected low-end/software renderer; this ran under
headless Chromium (SwiftShader), which may explain it — inconclusive without a real-GPU comparison,
noted here rather than guessed at.
Upstream fixes behind this
Four webgl-hero bugs surfaced while building the above, all now fixed upstream:
- ArcBlock/arc#4392 — the widget's own injected CSS
(
.wh{position:relative}) silently overrode this site'sposition:absolute;inset:0on the target element (equal specificity, later in the cascade), collapsing it toheight:0in every mode regardless of config. Also: 17 of ~24 modes discarded theopacityconfig via a duplicatesetClearColor(x, 1)call. Fix: ArcBlock/arc#4402 (merged) — appliescfg.opacityvia canvas CSS opacity instead of WebGL clear alpha, since three.js'sWebGLBackgroundhardcodes clear alpha to 1 for anyscene.backgroundColor regardless ofsetClearColor's alpha argument. An earlier attempt at this same fix (#4403, closed as a duplicate) took the per-engine route of nullingscene.backgroundon all 17 modes — #4402's single shared-function fix is the one that actually shipped. topo's plane was a fixedPlaneGeometry(30, 20), covering only ~2.4 aspect ratio — any wider hero ran past the plane's edge and showed bare clear color as a margin down both sides. Once fixed to size from the camera's actual frustum, this exposed a second bug: the noise shader sampled both axes at the same rate, stretching contours horizontally on any wide hero. Fix: ArcBlock/arc#4490.marbleloaded two texture files that don't exist anywhere in the widget package, rendering nothing. Filed as ArcBlock/arc#4417, fixed in ArcBlock/arc#4440 (merged) — see its entry above.
The header-band artifact investigated under aurora above was in arcblock-site's own readability
scrim, not this widget — webgl-hero's camera behavior was never the cause. See that section for
the fix.
Until the fixes above ship in a release, the candidates on this page only render correctly on a
locally-built arc — see the site's arc-upstream skill for what "upstream closed" vs. "we can
actually use it" means in practice.






