3D Interactive Hero
blockheroHero section with hardware-accelerated 3D tilt perspective card, specular light glare, and multi-layer z-depth primitives.
Installation
$pnpm dlx uipkge-ng@latest add hero-3d-tilt-interactive-canvas$npx uipkge-ng@latest add hero-3d-tilt-interactive-canvas$yarn dlx uipkge-ng@latest add hero-3d-tilt-interactive-canvas$bunx uipkge-ng@latest add hero-3d-tilt-interactive-canvasManifest:
https://uipkge.dev/r/angular/hero-3d-tilt-interactive-canvas.jsonInstalls to:src/app/components/blocks/hero-3d-tilt-interactive-canvas/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (2)
src/app/components/blocks/hero-3d-tilt-interactive-canvas/hero-3d-tilt-interactive-canvas.component.ts8.6 kB
// Hardware-accelerated 3D perspective hero with dynamic specular reflection and // layered z-depth cards. Cursor position drives pitch/yaw rotation and glare. // Port of the React block 1:1. import { ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, signal } from '@angular/core' import { ArrowRight, Code2, Cpu, Layers, LucideAngularModule, MousePointerClick, Zap } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' export interface Hero3dTiltInteractiveCanvasProps { title?: string description?: string primaryActionLabel?: string secondaryActionLabel?: string } @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-hero-3d-tilt-interactive-canvas, [ui-hero-3d-tilt-interactive-canvas]', standalone: true, // React renders the root <section> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent], template: ` <section data-slot="hero-3d-tilt-interactive-canvas" [class]="rootClass"> <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <!-- Section Header --> <div class="mx-auto max-w-3xl space-y-4 text-center"> <a href="#3d-spatial" class="group border-border/80 bg-secondary/60 hover:bg-secondary text-foreground inline-flex items-center gap-2 rounded-full border px-3.5 py-1 text-xs font-medium shadow-2xs transition-colors" > <lucide-icon [img]="Layers" class="text-primary size-3.5" /> <span>Spatial 3D Design Engineering</span> <lucide-icon [img]="ArrowRight" class="text-muted-foreground size-3 transition-transform group-hover:translate-x-0.5" /> </a> <h1 class="text-foreground text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl"> {{ title }} </h1> <p class="text-muted-foreground text-base sm:text-lg"> {{ description }} </p> <div class="flex flex-wrap items-center justify-center gap-3 pt-2"> <button ui-button size="lg" class="gap-2 shadow-xs"> <span>{{ primaryActionLabel }}</span> <lucide-icon [img]="ArrowRight" class="size-4" /> </button> <button ui-button variant="outline" size="lg" class="gap-2"> <lucide-icon [img]="Code2" class="size-4" /> <span>{{ secondaryActionLabel }}</span> </button> </div> </div> <!-- 3D Perspective Stage Container --> <div class="mt-14 flex flex-col items-center justify-center [perspective:1200px]"> <div #card [style.transform]="'rotateX(' + rotateX() + 'deg) rotateY(' + rotateY() + 'deg)'" [style.transition]=" isHovering() ? 'transform 100ms ease-out' : 'transform 500ms cubic-bezier(0.16, 1, 0.3, 1)' " class="border-border bg-card relative w-full max-w-2xl cursor-crosshair overflow-hidden rounded-2xl border p-8 shadow-xl select-none [transform-style:preserve-3d]" (mousemove)="handleMouseMove($event)" (mouseenter)="handleMouseEnter()" (mouseleave)="handleMouseLeave()" > <!-- Dynamic Specular Reflection / Glare Gradient --> <div [style.background]=" 'radial-gradient(circle at ' + glareX() + '% ' + glareY() + '%, rgba(255,255,255,0.12) 0%, transparent 60%)' " class="pointer-events-none absolute inset-0 transition-opacity duration-300" [class.opacity-100]="isHovering()" [class.opacity-0]="!isHovering()" ></div> <!-- Layer 1: Base Grid Info --> <div class="border-border flex items-center justify-between border-b pb-4"> <div class="flex items-center gap-2"> <lucide-icon [img]="Layers" class="text-primary size-4" /> <span class="text-foreground text-sm font-bold">Spatial Component Viewport</span> </div> <span ui-badge variant="outline" class="border-border text-muted-foreground font-mono text-xs"> Pitch: {{ rotateX() }}° • Yaw: {{ rotateY() }}° </span> </div> <!-- Layer 2: Floating 3D Cards & Primitives (Preserve-3d + translateZ) --> <div class="mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2"> <!-- Floating Badge Card 1 --> <div style="transform: translateZ(35px)" class="border-border/90 bg-muted/40 space-y-2 rounded-xl border p-4 shadow-md transition-transform" > <div class="flex items-center gap-2"> <lucide-icon [img]="Cpu" class="text-primary size-4" /> <span class="text-foreground text-xs font-bold">GPU Accelerated Matrix</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Zero JavaScript bundle runtime. Calculated via pure CSS 3D matrix transforms. </p> </div> <!-- Floating Badge Card 2 --> <div style="transform: translateZ(50px)" class="border-primary/30 bg-primary/5 space-y-2 rounded-xl border p-4 shadow-lg transition-transform" > <div class="flex items-center gap-2"> <lucide-icon [img]="Zap" class="text-success size-4" /> <span class="text-foreground text-xs font-bold">Specular Ray Diffusion</span> </div> <p class="text-muted-foreground text-xs leading-relaxed"> Dynamic light reflection calculates azimuth angles relative to mouse coordinates. </p> </div> </div> <!-- Bottom Telemetry Bar --> <div style="transform: translateZ(25px)" class="border-border/80 bg-background/90 mt-6 flex items-center justify-between rounded-lg border p-3 text-xs" > <div class="text-muted-foreground flex items-center gap-2"> <lucide-icon [img]="MousePointerClick" class="text-primary size-3.5" /> <span>Hover and move cursor to orient viewport</span> </div> <span class="text-foreground font-mono text-xs font-bold"> {{ isHovering() ? 'Tracking Live' : 'Hover to Orbit' }} </span> </div> </div> </div> </div> </section> `, }) export class UiHero3dTiltInteractiveCanvasComponent { protected readonly ArrowRight = ArrowRight protected readonly Code2 = Code2 protected readonly Cpu = Cpu protected readonly Layers = Layers protected readonly MousePointerClick = MousePointerClick protected readonly Zap = Zap @Input() title = 'Fluid 3D Spatial Architecture rendered in pure CSS.' @Input() description = 'Experience zero-latency hardware-accelerated 3D perspective transforms with dynamic specular reflections and layered z-depth primitives.' @Input() primaryActionLabel = 'Explore 3D Primitives' @Input() secondaryActionLabel = 'Copy CSS Matrix Code' @Input('class') className?: string @ViewChild('card') cardRef?: ElementRef<HTMLDivElement> readonly rotateX = signal(0) readonly rotateY = signal(0) readonly glareX = signal(50) readonly glareY = signal(50) readonly isHovering = signal(false) get rootClass(): string { return cn('bg-background relative overflow-hidden py-16 sm:py-24', this.className) } handleMouseMove(event: MouseEvent): void { const el = this.cardRef?.nativeElement if (!el) return const rect = el.getBoundingClientRect() const x = event.clientX - rect.left const y = event.clientY - rect.top const centerX = rect.width / 2 const centerY = rect.height / 2 // Limit max rotation to +/- 14 degrees this.rotateY.set(Number(((x - centerX) / (centerX / 14)).toFixed(2))) this.rotateX.set(Number((-(y - centerY) / (centerY / 14)).toFixed(2))) this.glareX.set(Number(((x / rect.width) * 100).toFixed(1))) this.glareY.set(Number(((y / rect.height) * 100).toFixed(1))) } handleMouseEnter(): void { this.isHovering.set(true) } handleMouseLeave(): void { this.isHovering.set(false) this.rotateX.set(0) this.rotateY.set(0) } }src/app/components/blocks/hero-3d-tilt-interactive-canvas/index.ts0.1 kB
export { UiHero3dTiltInteractiveCanvasComponent, type Hero3dTiltInteractiveCanvasProps, } from './hero-3d-tilt-interactive-canvas.component'
Raw manifest:https://uipkge.dev/r/angular/hero-3d-tilt-interactive-canvas.json