PitchMomentum
threecn/pitch-momentumFreeComponent
A soccer pitch of dots where two rival particle mountains surge and clash as momentum swings, crests whitening where the fronts collide.
Install it
npx shadcn@latest add https://threecn.dev/r/pitch-momentum.jsonSource
1"use client"23import * as React from "react"4import { useFrame } from "@react-three/fiber"5import * as THREE from "three"67import {8 SceneContainer,9 type SceneContainerProps,10} from "@/components/threecn/scene-container"11import {12 useShadcnTheme,13 type ThemeMode,14} from "@/components/hooks/use-shadcn-theme"1516/** Rounded platform the pitch sits on. */17const SLAB_W = 7.818const SLAB_H = 5.219const SLAB_R = 0.5520const SLAB_DEPTH = 0.162122/** Playing field (105m × 68m scaled down), markings derive from FIFA metrics. */23const PITCH_W = 6.824const PITCH_H = PITCH_W * (68 / 105)25const M = PITCH_W / 105 // meters → scene units26const PEN_DEPTH = 16.5 * M27const PEN_WIDTH = 40.32 * M28const GOAL_AREA_DEPTH = 5.5 * M29const GOAL_AREA_WIDTH = 18.32 * M30const SPOT_DIST = 11 * M31const CIRCLE_R = 9.15 * M32const GOAL_W = 7.32 * M33const GOAL_H = 2.44 * M34const GOAL_D = 0.183536/** How far mountains spread and how strongly detail noise crags them. */37const SIGMA = 1.638const INV_2S2 = 1 / (2 * SIGMA * SIGMA)39/** Squashes the across-pitch axis so mountains stretch over the full width. */40const Z_WEIGHT = 0.454142const LINE_Y = 0.0124344function hash2(ix: number, iz: number) {45 const s = Math.sin(ix * 127.1 + iz * 311.7) * 43758.545346 return s - Math.floor(s)47}4849/** Bilinear value noise in [0, 1]. */50function vnoise(x: number, z: number) {51 const ix = Math.floor(x)52 const iz = Math.floor(z)53 const fx = x - ix54 const fz = z - iz55 const ux = fx * fx * (3 - 2 * fx)56 const uz = fz * fz * (3 - 2 * fz)57 const a = hash2(ix, iz)58 const b = hash2(ix + 1, iz)59 const c = hash2(ix, iz + 1)60 const d = hash2(ix + 1, iz + 1)61 return a + (b - a) * ux + (c - a) * uz + (a - b - c + d) * ux * uz62}6364/** Ridged fractal noise — sharp crests, craggy slopes. */65function ridgedFbm(x: number, z: number) {66 let sum = 067 let amp = 0.568 let freq = 169 let px = x70 let pz = z71 for (let o = 0; o < 4; o++) {72 const n = 1 - Math.abs(2 * vnoise(px * freq, pz * freq) - 1)73 sum += n * n * amp74 amp *= 0.575 freq *= 2.176 // Rotate each octave so the lattice never lines up into visible bands.77 const rx = px * 0.7648 - pz * 0.644278 pz = px * 0.6442 + pz * 0.7648 + 13.779 px = rx + 7.380 }81 return sum // ≈ [0, 1]82}8384function insideSlab(x: number, z: number) {85 const dx = Math.abs(x) - (SLAB_W / 2 - SLAB_R)86 const dz = Math.abs(z) - (SLAB_H / 2 - SLAB_R)87 if (dx <= 0 || dz <= 0) {88 return Math.abs(x) <= SLAB_W / 2 && Math.abs(z) <= SLAB_H / 289 }90// … truncated
What it pulls in
npm packages
Files it writes
More from threecn
All 28 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| AuroraRibbonsaurora-ribbons | threecn | Components | Free | 3 deps · 3 files | |
| Boidsboids | threecn | Components | Free | 3 deps · 3 files | |
| Clothcloth | threecn | Components | Free | 3 deps · 3 files | |
| Crystalcrystal | threecn | Components | Free | 3 deps · 3 files | |
| CubeWavecube-wave | threecn | Components | Free | 3 deps · 3 files | |
| CurlFlowcurl-flow | threecn | Components | Free | 3 deps · 3 files | |
| DnaHelixdna-helix | threecn | Components | Free | 3 deps · 3 files | |
| FloatingCard3Dfloating-card-3d | threecn | Components | Free | 3 deps · 3 files |
