Threejs spectral ocean
Skill linegel/threejs-complete-set-of-skill/skills/threejs-spectral-ocean
25 expert agent skills for ambitious Three.js WebGPU/TSL scenes — procedural oceans, clouds, planets, water optics, image pipelines, and screenshot-backed visual validation. For Claude Code, Codex, Cursor, and any skill-aware agent.
npx -y skills add linegel/threejs-complete-set-of-skill --skill threejs-spectral-oceanAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Synthesize broad-band offshore seas with spectral FFT cascades in Three.js WebGPU/TSL. Use for homogeneous directional wind sea or swell, transported foam history, bounded CPU surface queries, or offshore forcing of a separate coastal model.
SKILL.md
11.2 KB, as published. Nobody here has run it
Spectral Ocean
Build a dimensioned random sea from directional variance density to one displaced, shaded surface. The spectral domain is a horizontally homogeneous periodic patch with one mean depth and one dispersion relation per cascade.
1. Gate the representation
Choose from the required observable, not the desired look:
| Observable | Owner |
|---|---|
| A few authored modes or exact cheap CPU queries | Parametric waves in $threejs-water-optics |
| Bounded disturbances or explicit walls | Bounded heightfield in $threejs-water-optics |
| Broad stochastic directional sea | This spectral FFT skill |
| Depth-varying refraction, diffraction, breaking, run-up, or wet/dry fronts | Coastal branch in $threejs-water-optics; this skill may supply offshore forcing |
| Overturning, entrained air, jets, or three-dimensional vortices | External free-surface solver |
Select FFT cascades only when the visible wavelength band contains enough independent modes that direct summation is more expensive or visibly repetitive. Record the visible wavelength interval, footprint, tolerated phase/slope error, periodic repeat distance, interaction needs, and measured storage budget.
Complete when: one row owns every required water observable, and every rejected row has a stated validity or cost reason.
2. Freeze the spectral convention
Use metres, seconds, radians per metre, and radians per second. Declare:
- stable horizontal physics frame and water datum;
- patch length, resolution,
Delta k, represented radial band, and guard band for every cascade; - inverse-transform sign, normalization, and centered-index correction;
- gravity, mean depth, surface tension, density, and uniform current;
- spectrum family, direction convention, seed, and cascade power windows;
- one coefficient/state clock and one render-surface owner.
The required inverse convention is
f[j] = sum_n F[n] exp(+i 2 pi n dot j / N).
If the implementation uses a normalized inverse, rescale coefficient initialization rather than tuning the sea afterward. Current is a separate water velocity and Doppler term; atmospheric wind never becomes water current.
For wind sea, record the sampled wind vector, reference height, averaging window and footprint, profile/drag calibration, stability treatment, fetch, forcing duration or wave age, spreading model, and represented source terms. Retarget a statistical state continuously; gusts may affect spray but do not reseed mature waves.
Load only the reference sections for environment forcing, wavevector and transform convention, and dispersion and dimensional spectrum while freezing this contract.
Complete when: every coefficient and clock has unambiguous units, the same transform convention appears in initialization and validation, and replaying one forcing snapshot reproduces the same coefficients and phase.
3. Build deterministic cascades
Load the reference sections for
cascade power and deterministic coefficients,
displacement and derivative spectra,
packing and inverse FFT,
and the transform gate.
When implementing or changing the transform, import or adapt the
FFT convention oracle. Feed every
makeConventionFixtures() spectrum through the implementation, then pass its
measureTransform() metrics and caller-declared gates to applyTolerances()
before loading the production spectrum.
For directional angular-frequency variance density S_omega,
P(k_x,k_z) = S_omega(omega(k),theta) |d omega/dk| / |k|,
[P] = m^4.
Include Delta k_x Delta k_z in discrete coefficient variance. Power windows
obey sum_c w_c(k)=1 over the represented band; smooth overlap uses
sqrt(w_c) on amplitude. Generate normals from
(seed,cascade,index_x,index_z) so masks and quality changes do not perturb
surviving coefficients.
Evolve a Hermitian height field, construct derivatives in wavevector space, then transform height, horizontal displacement, slopes, and displacement derivatives. Treat DC and self-conjugate Nyquist cells explicitly before any division.
Complete when: directional normalization, power-window sum, target versus realized variance, coefficient determinism, Hermitian partner error, DC, both axis bins, an oblique bin, a conjugate pair, every Nyquist parity case, CPU-DFT error, Parseval error, and post-IFFT imaginary leakage all pass declared gates.
4. Assemble one exact surface
Load only exact displaced geometry for the composite tangent, velocity, sampling, and fold rules.
Sum all cascade fields before nonlinear geometry. For
P(q) = (q_x + chi D_x, h, q_z + chi D_z),
derive both parametric tangents from the summed displacement and set the normal
to normalize(cross(P_qz,P_qx)). Compute the full horizontal Jacobian,
including the mixed derivative. A nonpositive determinant is a fold, not a
normal-map defect.
Choose the sign of chi with the one-mode criterion: under the positive
inverse convention, h=a cos(kx) and positive choppiness must produce
X=x-chi a sin(kx), compressing the crest.
Geometry must resolve the represented displacement band. Filter or omit modes that its footprint cannot resolve, and report their height/slope contribution. One mesh/material owns every displayed location.
Complete when: the one-mode travel and displacement signs are correct; analytic tangents and normals match finite differences; combined variance and minimum Jacobian are measured; folds are counted; and position, normal, velocity, foam, and temporal consumers read the same immutable state pair.
5. Add only represented optional state
Foam
When foam is enabled, load only the foam section.
Build one source from combined-cascade compression, Jacobian evolution, curvature, or a calibrated breaking proxy, then evolve one bounded history. Declare Lagrangian parameter storage, Eulerian advection, or conservative density transport. Source, transport, reaction, diffusion, and display coverage remain separately inspectable.
Queries
When CPU queries are enabled, load only the CPU queries section.
Retain a deterministic coefficient subset on CPU. Expose parameter-coordinate
sampling separately from physics-horizontal sampling. Choppy Eulerian queries
invert X(q)=x; the omitted-mode bound, inversion residual, numeric error, and
GPU probe discrepancy stay separate. The frame path performs no synchronous
map readback.
Optics
When $threejs-water-optics is installed and available, invoke it for Fresnel,
refraction, Beer-Lambert, and receiver-caustic rules. Surface geometry,
derivatives, foam, and optics then share one cause and one final output
transform. When it is unavailable, report missing optics owner and keep
optics outside this implementation and its claims.
Complete when: each enabled option has an owner, validity interval, support/filter, reset rule, and failure diagnostic; disabled options allocate no state and make no claim.
6. Couple a coast only when required
When the sea feeds a depth-varying or wet/dry owner, load only the
coastal donor
section and its phase-resolved, phase-averaged, and ownership subsections.
Before either solver runs, record the spectral donor, coastal consumer, and
forcing, reaction, render-surface, and foam owners; SI units; common physics
frame/origin and water datum; clock, sample instant or transfer interval,
cadence, and sample phase; band support, filter, and quadrature; validity,
staleness, and error; and donor/receiver state and resource versions. Keep
atmospheric forcing, mean current, wave transfer, and coastal reaction as
separate signals. Reset dependent boundary, query, foam, geometry, and temporal
state after a clock discontinuity, rebase, incompatible version,
representation change, or ownership change. Invoke $threejs-choose-skills if
the composed route still lacks one owner per observable.
Choose exactly one:
- Phase resolved: transfer elevation and depth-integrated discharge with common phase, intrinsic frequency, sample instant, band identity, and error. Prescribe only the incoming characteristic; retain the coastal outgoing one.
- Phase averaged: transfer dimensioned wave action/energy, intrinsic frequency, group velocity, current, direction, quadrature, and band identity. The receiver separately owns local display phase.
The FFT remains the offshore donor. It does not gain refraction, diffraction, breaking, run-up, or wet/dry ownership by sampling bathymetry in its material. Coherent donor/receiver copies use one spatial render owner; power windows apply only to independent or orthogonal bands.
Complete when: producer, consumer, interval, sample phase, units, support, filter, validity, staleness, error, state versions, reflection scope, and render/foam ownership are explicit; single-mode normal and oblique tests close phase, elevation, discharge or action, transmitted power, and reflection.
7. Integrate and verify the GPU path
Load only WebGPU and performance for backend, resource, dispatch, precision, and lifecycle requirements.
Initialize WebGPURenderer before checking its backend or limits. Use
StorageTexture data with NoColorSpace and explicit precision. A global
producer/consumer dependency crosses a dispatch boundary. Select a validated
global ping-pong FFT—Stockham autosort or explicit-bit-reversal radix-2—or
workgroup-resident rows from transform correctness, initialized device limits,
occupancy, traffic, and sustained timing.
Render through one RenderPipeline and one output transform. Keep coefficient,
resolved-map, foam, query, and presentation generations immutable while a
render lease consumes them; resize, seed, spectrum, cadence, representation, or
origin changes either migrate compatible state or reset all dependent history.
Report actual allocations, peak live bytes, dispatches, precision comparison, warm sustained timings, and fixed-camera final/no-foam/no-detail/no-post captures for each named target.
Complete when: the initialized backend and selected limits are recorded; all numerical gates above pass; no frame-critical readback exists; lifecycle rebuild/dispose reaches an allocation plateau; and the final image has one surface owner and one output transform.