{"schema_version":1,"slug":"graphics-lab","title":"Graphics Lab, a technical record","project":{"title":"Graphics Lab","url":"/projects/graphics-lab/","source":"_projects/graphics-lab.md"},"record_url":"/projects/graphics-lab/record/","json_url":"/assets/json/design-records/graphics-lab.json","repository":"https://github.com/DylanTao/dylantao.github.io","branch":"main","updated":"2026-10-18","summary":"The rendering and simulation experiments behind the homepage's coastal home, one technique at a time: what each does in the scene now and which files and functions hold it, the papers it adapts, what it cannot do yet, and newer papers that would take it further, each with what it would add and a rough effort.","scope":"Each experiment adapts a published method in a small, bounded form for a browser scene, and each entry says where it simplifies. Thumbnails are frames of the live scene captured on October 16 and 17, 2026; the light well, the steam and the onsen are dated in late August, when the noon sun reaches the shaft and the bath runs in daylight. Measurements come from one Windows desktop unless an entry says otherwise. Shader warmup and loading are in the coastal home record.","credit":"Compiled on October 16 to 18, 2026 by Anthropic's Claude from the code, the scene notes and the coastal home record, for Sirui Tao to review. Every citation was checked against its DOI record, its publisher's page or its authors' page.","read_first":[{"path":"_data/design_records/homepage-desk-scene.yml","why":"The coastal home record. Each technique's full implementation notes, its design moves and the house's constraints."},{"path":"docs/homepage-desk-scene-brief.md","why":"The active brief. The 2D-first rule, the San Diego routine and the acceptance evidence map."},{"path":"assets/js/home-scene/PHYSICS.md","why":"The ocean, the coast's wind, the record mechanics and the curtains, with equations, sources, evidence and limits."},{"path":"assets/js/home-scene/CONTACT-LIGHTING.md","why":"The horizon integral, its reconstruction and the controlled comparisons."},{"path":"assets/js/home-scene/ONSEN-WATER.md","why":"The height-field pool, its hand coupling and its numerical evidence."},{"path":"assets/js/home-scene/SKIN-DIFFUSION.md","why":"The curved-patch diffusion integral, metric curvature and the exact shader hook."},{"path":"assets/js/home-scene/THERMAL-STEAM.md","why":"Steam transport, light integration around glass and the light-well mask."},{"path":"docs/static-light-field.md","why":"The traced sky and lamp bounce, its probes and its cost."},{"path":"docs/coherent-wind-equations.md","why":"The curl field, leaf attachment and particle integration."}],"constraints":["The homepage opens in 2D on every screen, 3D loads only on request, and any WebGL or model failure returns the 2D desk. No experiment may change that.","Every simulation advances on the scene's active clock in fixed ticks, accepts at most 0.25 s per call and drops the rest. Paused, hidden, offscreen and reduced-motion scenes compose a still frame.","Every new material, pass or override draw joins `program-warmup.mjs`, or its first draw blocks the page.","A change meant only to save cost must change 0 pixels in seeded, paused-clock captures; a change of look needs a matched A/B, measured interleaved.","The scene renders through WebGL2 and three.js r164, with no compute shaders and no ray queries; GPU work is vertex and fragment passes.","Each technique's notes say where it simplifies the paper it adapts. Never present an adaptation as a full reproduction or as the state of the art."],"tests":[{"path":"test/test_design_records.py","covers":"This record's schema, paths, named functions, links to the coastal home record, sources and watchlists.","command":"python -m unittest test.test_design_records"},{"path":"test/light-lab.test.mjs","covers":"The light lab's optics against Fresnel and Snell, its water hits, and agreement between the two estimators.","command":"node --test test/light-lab.test.mjs"},{"path":"test/coastal-physics.test.mjs","covers":"Wave derivatives, slope-energy accounting, water Fresnel and La Jolla's sun.","command":"node --test test/coastal-physics.test.mjs"},{"path":"test/coast-wind.test.mjs","covers":"The coast's breeze against the station means, its gust fronts, the wind sea and the planting's sway.","command":"node --test test/coast-wind.test.mjs"},{"path":"test/onsen-water.test.mjs","covers":"Conservation, reflecting boundaries, energy decay and the hand's coupling in the pool.","command":"node --test test/onsen-water.test.mjs"},{"path":"test/steam-transport.test.mjs","covers":"Steam transport across frame rates, positive diffusion and Beer–Lambert composition.","command":"node --test test/steam-transport.test.mjs"},{"path":"test/curtain-cloth.test.mjs","covers":"Cloth strain, stability, determinism, sleep and wake, and the openness model.","command":"node --test test/curtain-cloth.test.mjs test/curtain-schedule.test.mjs"},{"path":"test/skin-diffusion.test.mjs","covers":"The diffusion integral's normalization, limits and curvature.","command":"node --test test/skin-diffusion.test.mjs"},{"path":"test/coastal-lift-rig.test.mjs","covers":"The lifts' reach, contacts and head clearances on every avatar.","command":"node --test test/coastal-lift-rig.test.mjs test/coastal-gym-session.test.mjs test/coastal-training.test.mjs"},{"path":"test/visual/desk-scene.spec.js","covers":"Nonblank WebGL, the rooms, recovery and reduced motion in a real browser.","command":"npm.cmd run test:visual:scene"}],"systems":[{"id":"light-transport","name":"Light","summary":"Light that has to be traced rather than rasterized: down a drilled shaft, around the house's walls, into the creases where things touch, and through rippled water in a lab page of its own.","techniques":[{"id":"light-paths","name":"Light paths through the onsen","status":"experimental","since":"2026-10-14","page":{"title":"Light Paths in the Onsen","url":"/projects/light-paths/"},"thumbnail":{"path":"assets/img/project_pics/graphics-lab/light-paths.webp","alt":"The lab's onsen rendered twice, specks of path tracing on the left and Metropolis light transport's sunlit pool floor on the right","frame":"The lab's eleven-minute comparison at 800 × 600, scaled."},"what":"A plain-JavaScript renderer races path tracing against Metropolis light transport on the sunlight the light well bends through the onsen's water.","how":"`createRenderer` in `core.mjs` builds one path sampler that reads every random decision from a fixed coordinate of a sample vector. `PathTracer` feeds it fresh numbers and `MetropolisRenderer` feeds it Kelemen and colleagues' small and large mutations, so the two estimators share every line of path construction. Both use next-event estimation to the sun and sky with power-heuristic multiple importance sampling, after Veach, and water hits use safeguarded Newton iteration on seven frozen ripples. The page runs each estimator in a module worker for the same wall time, and `make_light_lab_reference.mjs` splits path space at the first hit for a 24-minute reference.","files":[{"path":"assets/js/light-lab/core.mjs","role":"The scene, the path sampler and both estimators.","functions":["createRenderer","createScene","tracePath","MetropolisRenderer"]},{"path":"assets/js/light-lab/worker.mjs","role":"One estimator per worker."},{"path":"assets/js/light-lab/page.mjs","role":"The race, its chart and the still frames."},{"path":"bin/make_light_lab_reference.mjs","role":"The reference renderer, split by path type."}],"tests":["test/light-lab.test.mjs"],"sources":["veach1997mlt","kelemen2002pssmlt","veach1997thesis","pbrt3-mlt"],"related":[{"record":"homepage-desk-scene","techniques":["lab-renderer","lab-race","lab-reference"]}],"limits":["A simplified scene. A box grotto, frozen ripples, no steam, a round opening instead of the tilted shaft, and a sun three times its real size by default.","Metropolis takes its total brightness from independent samples that usually miss the sun, and its chains start in skylight."],"watchlist":[{"source":"zeltner2020sms","effort":"medium","adds":"Solves for the path through the water from a point on the pool floor to the sun, so even plain path tracing could aim at the sun. The lab's pool has a single refracting surface, the method's simplest case."},{"source":"loubet2020slope","effort":"medium","adds":"Integrates the light arriving through each facet of a triangulated water surface in closed form, a next-event estimator for caustics under water."},{"source":"jakob2012manifold","effort":"large","adds":"Moves a chain along the family of paths that stay connected through the water instead of hoping a random change does, so the race's caustic paths would mix much faster."},{"source":"muller2017guiding","effort":"medium","adds":"Learns which directions reach the sun from each region and samples them, an unbiased alternative to Metropolis whose independent samples also give the image's brightness."}],"next":[{"move":"Add the pool light to the lab scene and render its caustics on the vault.","readiness":"needs-research"}]},{"id":"light-well","name":"A light well with traced shaft light","status":"shipped","since":"2026-10-14","thumbnail":{"path":"assets/img/project_pics/graphics-lab/light-well.webp","alt":"The onsen at noon in late August, a hazy beam from the light well slanting across the room onto the pool","frame":"Onsen view, 12:40 on August 20, 2026 (page clock fixed), reduced motion."},"what":"A shaft drilled from the clifftop brings sun into the onsen, and its beam, its sun patch, its skylight and the lit steam share one visibility function.","how":"`bin/coastal_lightwell.py` drills a shaft of 0.42 m radius through 1.67 m of rock, leaning 28° toward the noon sun. `createLightWell` in `light-well.mjs` follows four light paths. The sun's shadow map carries the patch on the floor or the water. Dust and humid air in the beam are single scattering with a forward Henyey–Greenstein phase, marched only inside the shaft's elliptic cylinder, after Wronski. `shaftExitRadiance` path-traces the drilled cylinder on a fixed Halton sequence for the radiance leaving the aperture, and the aperture and the sun patch then light the bath as two small area lights in closed form (`wellIrradianceGLSL`).","files":[{"path":"assets/js/home-scene/light-well.mjs","role":"Shaft visibility, the beam, the traced aperture radiance and the area lights.","functions":["createLightWell","shaftExitRadiance","wellOpenFraction","wellSunPatch","wellIrradianceGLSL"]},{"path":"bin/coastal_lightwell.py","role":"The drilled shaft and the shadow-only vault."},{"path":"assets/js/home-scene/steam-volume.mjs","role":"Masks the steam's sunlight with the shaft's visibility."}],"tests":["test/light-well.test.mjs"],"sources":["wronski2014fog"],"related":[{"record":"homepage-desk-scene","techniques":["light-well"]}],"limits":["The shaft passes 5.5 % of the sky, so outside midday the grotto is darker than an open bath. The beam needs a high sun; the October 16 noon frame shows none, the August 20 frame does.","The two area lights are Lambertian, so the wet rim and the water show no glossy reflection of the aperture.","The beam's scattering sees only the shaft's own visibility, not the bather or the screens."],"watchlist":[{"source":"heitz2016ltc","effort":"medium","adds":"Shades polygonal area lights with rough specular lobes in closed form, so the aperture and the sun patch would gleam on the wet rim and the water instead of only lighting them diffusely."},{"source":"chen2011minmax","effort":"medium","adds":"Computes single scattering with shadows from a shadow map, one slice of rays at a time, so the beam and the steam could show the bather's shadow."}],"next":[]},{"id":"light-field","name":"Traced sky and lamp bounce","status":"shipped","since":"2026-10-02","thumbnail":{"path":"assets/img/project_pics/graphics-lab/light-field.webp","alt":"The study at 23:10, Sirui coding under the desk lamp, its warm light bouncing onto the shelves and walls","frame":"Study view, 23:10 on October 16, 2026, reduced motion."},"what":"A CPU ray tracer bakes sky visibility and one diffuse bounce into probe cages once, then relights them from the actual sky and lamp powers without tracing again.","how":"`createStaticLightField` builds a triangle BVH over the house's static opaque meshes (`createTriangleBVH`), traces eight cosine-weighted sky rays per primary hit, and stores irradiance as first-order spherical harmonics (`accumulateL1`, `evaluateL1`) in 56 probes with octahedral distance moments, after Ramamoorthi and Hanrahan and the probe visibility of Majercik and colleagues. Unit sky and lamp bases let a change of hour recombine the cache with zero rays. The field replaces three.js's ambient terms once; direct light, reflections and refraction stay native. The bake runs in yielded slices and frees its accelerator afterwards.","files":[{"path":"assets/js/home-scene/static-light-field.mjs","role":"Probe cages, the bake and the shader binding.","functions":["createStaticLightField","STATIC_LIGHT_REGIONS"]},{"path":"assets/js/home-scene/light-trace-core.mjs","role":"The triangle BVH and the diffuse quadrature.","functions":["createTriangleBVH","cosineDirections","accumulateL1","evaluateL1"]},{"path":"docs/static-light-field.md","role":"Equations, ownership and cost."}],"tests":["test/static-light-field.test.mjs","test/visual/static-light-field.spec.js"],"sources":["ramamoorthi2001irradiance","majercik2019ddgi","pbrt4-bvh"],"related":[{"record":"homepage-desk-scene","techniques":["static-light-field"]}],"limits":["Static and one bounce. People, props and swaying plants do not shade it.","Four coefficients lose directional contrast, and sparse probes can leak at thin walls."],"watchlist":[{"source":"iwanicki2017dice","effort":"medium","adds":"A basis of twelve lobes on an icosahedron's vertices with close to third-order quality from fewer reads, which would restore the directional contrast four coefficients flatten."},{"source":"silvennoinen2017probes","effort":"large","adds":"Precomputes, for each receiver, which few probes it can see, so the bounce would stop leaking through thin walls."},{"source":"rodriguez2020glossy","effort":"large","adds":"Stores multi-bounce glossy light in probes and reprojects it, so the glass, the water and the polished wood would reflect the lit house rather than the environment map."}],"next":[]},{"id":"contact-light","name":"Horizon-based contact light","status":"shipped","since":"2026-10-01","thumbnail":{"path":"assets/img/project_pics/graphics-lab/contact-light.webp","alt":"The study at 15:00, Sirui at the desk, soft contact shadows under the laptop, the turntable, the plant and the shelves","frame":"Study view, 15:00 on October 16, 2026, reduced motion."},"what":"A visibility buffer computed before the beauty pass darkens only indirect diffuse light near contacts, with the closed-form horizon integral of ground-truth ambient occlusion.","how":"`contact-occlusion.mjs` projects the geometric normal into four fixed view-aligned slices and integrates the cosine-weighted visibility above each slice's two horizons in closed form (`horizonIntegral`), Jimenez and colleagues' inner integral, with at most 32 depth probes per pixel. A 3 × 3 reconstruction keeps neighbours on the same tangent plane (`bilateralWeight`), and the paper's cubic fit adds back the light a pale neighbourhood bounces (`bounceVisibility`). `bindContactLighting` scales only each material's indirect diffuse term, so sunlight, emission and reflections are untouched, and a still composes the same way every time.","files":[{"path":"assets/js/home-scene/contact-occlusion.mjs","role":"The horizon integral and the edge-aware reconstruction.","functions":["horizonIntegral","bounceVisibility","bilateralWeight","bindContactLighting"]},{"path":"assets/js/home-scene/realism.mjs","role":"The room finish that runs the pass.","functions":["createFinish"]},{"path":"assets/js/home-scene/CONTACT-LIGHTING.md","role":"Equations, controlled comparisons and cost."},{"path":"assets/js/home-scene/contact-lab.html","role":"An unlisted comparison page."}],"tests":["test/coastal-contact-lighting.test.mjs","test/coastal-contact-rendering.test.mjs"],"sources":["jimenez2016gtao"],"related":[{"record":"homepage-desk-scene","techniques":["contact-occlusion"]}],"limits":["Screen-space, so it cannot see hidden or offscreen geometry and overestimates thin occluders.","Four fixed slices keep a directional bias, and there are no bent normals or specular occlusion."],"watchlist":[{"source":"therrien2023bitmask","effort":"medium","adds":"Replaces the two horizons with a bitmask of occluded sectors, so light passes behind thin shelves and chair legs and nearby surfaces add one bounce of their colour."}],"next":[{"move":"Specular occlusion and bent normals from the same report (its GTSO), so reflections dim in creases too.","readiness":"needs-research"}]}]},{"id":"water-air","name":"Water, air and sky","summary":"Two bodies of water with different models, bath steam carried by its own heat, one breeze from the Pacific through the house, and a sun placed by La Jolla's clock.","techniques":[{"id":"ocean","name":"A Pacific of Gerstner waves","status":"shipped","since":"2026-10-01","thumbnail":{"path":"assets/img/project_pics/graphics-lab/ocean.webp","alt":"The Pacific from the beach at 16:00, choppy waves in front fading into a smooth, sunlit sea toward the horizon","frame":"Lab camera on the beach, 16:00 on October 16, 2026, reduced motion."},"what":"Ten Gerstner waves displace the sea and its normals together, with a wind sea that grows with the breeze, gusty ripples and whitecaps, a lit shoreline and a live mirror of the cliff.","how":"`sampleOcean` in `ocean-spectrum.mjs` sums ten choppy Gerstner components from 24.7 m to 6.1 cm with gravity–capillary dispersion and analytic tangents, after Finch, and keeps the steepness sum under 0.3 so the surface never folds. Each amplitude fades with the pixel's footprint, and the slope energy it loses widens the GGX lobe, a scalar version of Bruneton, Neyret and Holzschuch's transition from geometry to BRDF. Since October 16 the seven shorter components are a wind sea that turns and grows with the coast's breeze under a Pierson–Moskowitz cut (`windSeaScale`), pixel ripples follow the local gusty wind by the Cox–Munk slope law (`rippleScale`), and whitecaps cover Monahan and Ó Muircheartaigh's fraction (`whitecapCoverage`). `createPacific` adds swash, wet sand and lit foam, and `createSeaReflection` renders a mirror with exact water Fresnel.","files":[{"path":"assets/js/home-scene/ocean-spectrum.mjs","role":"Wave components, footprint filtering, the wind sea and the CPU wave sampler.","functions":["sampleOcean","windSeaScale","rippleScale","whitecapCoverage","waterFresnel"]},{"path":"assets/js/home-scene/environment.mjs","role":"The sea shader, the swash and the foam.","functions":["createPacific"]},{"path":"assets/js/home-scene/reflection.mjs","role":"The planar mirror and its Fresnel.","functions":["createSeaReflection"]},{"path":"assets/js/home-scene/PHYSICS.md","role":"Equations and evidence."}],"tests":["test/coastal-physics.test.mjs","test/coast-wave-motion.test.mjs","test/coast-wind.test.mjs"],"sources":["finch2004gerstner","bruneton2010ocean","pierson1964spectrum","cox1954glitter","monahan1980whitecaps","arcblanc2025"],"related":[{"record":"homepage-desk-scene","techniques":["ocean-spectrum","shoreline","sea-reflection","coast-wind"]}],"limits":["A sparse authored spectrum on a finite 400 m surface, with no FFT, cascades, bathymetry or weather.","The roughness widening is a scalar isotropic fit, not the paper's anisotropic slope statistics.","Waves run straight through the shore and the rocks; nothing reflects, refracts or breaks.","Close up, the swell components draw a faint diamond pattern on the near water."],"watchlist":[{"source":"jeschke2020boundary","effort":"medium","adds":"Keeps procedural waves but makes them respect the terrain's boundary, so swells would slow, turn toward the beach and wrap around the rocks."},{"source":"dupuy2012whitecaps","effort":"medium","adds":"Derives whitecap coverage from a wave-deformation criterion that filters with distance, so foam would form where waves steepen without the tenfold exaggeration."},{"source":"jeschke2018wavelets","effort":"large","adds":"Stores wave amplitude by position, direction and wavelength, so waves could reflect off the cliff and bend around the headlands."},{"source":"horvath2015spectra","effort":"large","adds":"Empirical directional spectra, including a shallow-water spectrum and a swell parameter, to drive an FFT ocean if the spectral-ocean move goes ahead."}],"next":[]},{"id":"onsen-water","name":"A height-field onsen","status":"shipped","since":"2026-10-02","thumbnail":{"path":"assets/img/project_pics/graphics-lab/onsen-water.webp","alt":"Sirui soaking in the onsen on a Saturday afternoon, one hand at the water's surface","frame":"Lab camera over the pool, 16:10 on Saturday, August 22, 2026 (page clock fixed), after seven seconds of motion."},"what":"The onsen is a 40 × 40 shallow-water height field whose waves carry water between cells, reflect off the rim and the bather, and start from the bather's hand.","how":"`createHeightfieldWater` follows section 2.1 of Chentanez and Müller: staggered heights and face velocities, conservative upwind depth fluxes, pressure from the free-surface gradient and reflecting solid faces, at fixed 1/120 s ticks with CFL subdivision; total volume holds to about 10⁻¹⁴. `measurePoolGeometry` measures the real basin, about 0.127 m deep. `createPoolStroke` drives a slow hand skim, and the palm's submerged velocity relaxes nearby face velocities inside each step, so a resting hand adds no energy. `createOnsenWater` packs elevation, slopes and wet weight into a texture for the pool's material and runs only when the camera can see the pool.","files":[{"path":"assets/js/home-scene/heightfield-water.mjs","role":"The conservative shallow-water solver.","functions":["createHeightfieldWater"]},{"path":"assets/js/home-scene/onsen-water.mjs","role":"The renderer adapter and the palm coupling.","functions":["createOnsenWater"]},{"path":"assets/js/home-scene/pool-geometry.mjs","role":"Measures the native basin.","functions":["measurePoolGeometry"]},{"path":"assets/js/home-scene/pool-stroke.mjs","role":"The prescribed hand skim.","functions":["createPoolStroke","samplePoolStroke"]},{"path":"assets/js/home-scene/ONSEN-WATER.md","role":"Equations, coupling limits and numerical evidence."}],"tests":["test/onsen-water.test.mjs","test/pool-geometry.test.mjs","test/pool-stroke.test.mjs"],"sources":["chentanez2010water"],"related":[{"record":"homepage-desk-scene","techniques":["onsen-water"]}],"limits":["Shallow-water waves travel at the wrong speed when their wavelength nears the 12.7 cm depth or is shorter, so the hand's ripples are off.","One-way coupling, with no wet and dry cells, splashes, buoyancy or caustics."],"watchlist":[{"source":"jeschke2023dispersive","effort":"medium","adds":"Splits each step into shallow-water bulk flow and Airy surface waves, so the hand's short ripples would travel at their true speed in this shallow basin."},{"source":"chentanez2015coupling","effort":"large","adds":"Couples a height field to a 3D grid and particles where the surface breaks, for splashes when someone steps in or the spout drips."}],"next":[{"move":"A steady drip from the bamboo spout into the solver at the spout's mouth.","readiness":"ready"}]},{"id":"steam","name":"Thermal steam","status":"shipped","since":"2026-10-02","thumbnail":{"path":"assets/img/project_pics/graphics-lab/steam.webp","alt":"Bath air over the onsen at noon in late August, the light well's beam showing as a pale shaft through it","frame":"Lab camera beside the pool, 12:40 on August 20, 2026 (page clock fixed), reduced motion."},"what":"Bath mist is two transported fields, droplet concentration and temperature, rendered with single scattering that composes in order around the glass and the water.","how":"`createSteamDensity` advects an 18³ concentration and temperature field at a fixed 30 Hz with midpoint semi-Lagrangian backtracing, after Stam, and lets warmer cells rise faster, after Fedkiw, Stam and Jensen's separate smoke density and temperature; diffusion and cooling use exact exponential factors, and since October 16 the drift follows the house's share of the coast's breeze (`setWind`). `createSteamVolume` marches up to 40 samples with Beer–Lambert extinction and a Henyey–Greenstein phase (`integrateSteamSamples`, `steamPhase`), after Wronski, and splits each ray once at the nearest glass or water (`steamRayIntervals`) so the gas in front and behind composes in order.","files":[{"path":"assets/js/home-scene/steam-density.mjs","role":"Concentration and temperature transport.","functions":["createSteamDensity","setWind"]},{"path":"assets/js/home-scene/steam-volume.mjs","role":"The single-scattering march and the interface split.","functions":["createSteamVolume","integrateSteamSamples","steamPhase","steamRayIntervals"]},{"path":"assets/js/home-scene/volume-depth.mjs","role":"Opaque and nearest-transmissive depth for the split.","functions":["createVolumeDepth"]},{"path":"assets/js/home-scene/THERMAL-STEAM.md","role":"Model, light integration and cost."}],"tests":["test/steam-transport.test.mjs"],"sources":["stam1999stable","fedkiw2001smoke","wronski2014fog"],"related":[{"record":"homepage-desk-scene","techniques":["thermal-steam"]}],"limits":["A prescribed buoyant rise with no pressure solve; semi-Lagrangian transport blurs the field and does not conserve its mass exactly.","Single scattering only, with no shadow from opaque geometry beyond the light well's mask."],"watchlist":[{"source":"qu2019bimocq","effort":"medium","adds":"Advects along forward and backward maps for about the cost of two semi-Lagrangian steps, so the 18³ field would keep its wisps instead of blurring them away."},{"source":"kim2008wavelet","effort":"medium","adds":"Synthesizes the turbulence a coarse grid misses with wavelet noise, detail far finer than 18 cells at shader cost."},{"source":"zehnder2018advection","effort":"large","adds":"If the steam ever gains a pressure solve, a reflection at mid-step keeps its swirls far longer than projection alone."}],"next":[]},{"id":"coast-wind","name":"One wind for the coast","status":"shipped","since":"2026-10-16","thumbnail":{"path":"assets/img/project_pics/graphics-lab/coast-wind.webp","alt":"The date palm on the clifftop and its shadow on the sand, fronds that sway in the afternoon sea breeze","frame":"Lab camera on the clifftop, 15:00 on October 16, 2026, reduced motion."},"what":"One breeze, measured at Scripps Pier and carried by gust fronts that travel downwind, moves the sea, the clifftop planting, the room plants, the curtains, the steam and the particles.","how":"`createCoastWind` in `wind-field.mjs` runs a periodic cubic Hermite through the October hourly means at Scripps Pier (NDBC LJPC1, 2023–2025) and writes every gust as a function of retarded time t − x·d/c, so a front reaches each place in turn at the mean wind's speed, Taylor's frozen turbulence. An exact integer hash makes the shader chunk (`coastWindGLSL`) and the CPU agree on every gust. Indoors, a six-mode curl-noise field adds the house's own eddies (`sampleWind`), exactly divergence-free, after Bridson, Hourihan and Nordenstam. `patchFloraSway` bends the planting by a lean that grows like U^1.4, as streamlining leaves' drag does, and a sway at each species' own frequency phased by retarded time, so gusts roll across the bluff; the room plants bend around their real stems.","files":[{"path":"assets/js/home-scene/wind-field.mjs","role":"The daily breeze, the gust fronts, the indoor eddies and the shared GLSL.","functions":["createCoastWind","coastWindGLSL","sampleWind","sampleWindPotential"]},{"path":"assets/js/home-scene/plant-motion.mjs","role":"The planting's sway and the room plants' rooted bend.","functions":["patchFloraSway","patchPlantShader","buildPlantAttributes"]},{"path":"assets/js/home-scene/coastal-wind.mjs","role":"Binds the room plants to the field and the coast's state.","functions":["createCoastalWind"]},{"path":"assets/js/home-scene/wind-particles.mjs","role":"Dust and spray carried by the wind.","functions":["createWindParticles"]},{"path":"docs/coherent-wind-equations.md","role":"The curl field, leaf attachment and particle integration."}],"tests":["test/coast-wind.test.mjs","test/coastal-wind.test.mjs","test/coastal-transport-rendering.test.mjs"],"sources":["ndbc-ljpc1","taylor1938turbulence","bridson2007curl","delangre2008wind","vogel1989drag","py2006lockin","wellons2018hash"],"related":[{"record":"homepage-desk-scene","techniques":["coast-wind","curl-wind","rooted-leaves","clifftop-sway","wind-particles"]}],"limits":["Frozen turbulence over flat ground. There is no shelter or speed-up from the bluff, the house or the cliff, and no change with height.","The outdoor field is not divergence-free; only the indoor eddies keep the curl field's guarantee.","October's daily cycle all year.","Trunks and branches stay rigid; only leaves, needles and fronds move."],"watchlist":[{"source":"diener2009wind","effort":"medium","adds":"Projects the wind onto a few precomputed modal stresses per tree, so the Torrey pines and the palm would sway as whole structures, evaluated on the GPU."},{"source":"habel2009trees","effort":"medium","adds":"Precomputes branch responses to turbulent wind in a motion texture read by one vertex shader, so branches would bend by their own stiffness."},{"source":"jahrmann2017grass","effort":"large","adds":"Draws grass blades as geometry with gravity, wind and collisions on any surface, so the bluff's grass could part around the rabbits."}],"next":[{"move":"Follow the station's monthly cycles, so summer afternoons blow harder than October's.","readiness":"ready"}]},{"id":"sun-sky","name":"Sun position and sky","status":"shipped","since":"2026-10-01","thumbnail":{"path":"assets/img/project_pics/graphics-lab/sun-sky.webp","alt":"The sun low over the Pacific at 17:40, a glitter path on the water below a pale, hazy sky","frame":"Lab camera on the beach looking west, 17:40 on October 16, 2026, reduced motion."},"what":"The sun, its shadows and the sun's disc follow NOAA's solar equations for La Jolla on the scene's Pacific clock; the sky's colours are authored.","how":"`coastalDaylight` in `daylight.mjs` uses NOAA's fractional-year approximation at 32.83° N, 117.27° W, with Pacific daylight saving. In `environment.mjs`, `setPalette` sets the sky shader's zenith and horizon colours by time of day and points its sun from the daylight model, and `makeEnvironment` captures the sky into a prefiltered environment map at twenty-minute steps with one generator for the home's lifetime. On the coast the sun's shadow map follows the camera, snapped to whole texels. Night's key light is an authored moon.","files":[{"path":"assets/js/home-scene/daylight.mjs","role":"Solar position.","functions":["coastalDaylight","LA_JOLLA"]},{"path":"assets/js/home-scene/environment.mjs","role":"The sky shader, its environment captures and the haze.","functions":["setPalette","makeEnvironment"]}],"tests":["test/coastal-physics.test.mjs","test/sun-arc-math.test.mjs"],"sources":["noaa-solar"],"related":[{"record":"homepage-desk-scene","techniques":["daylight"]}],"limits":["Not an atmospheric scattering model. The sky's colours and the haze are chosen by hand, so a sunset does not redden by physics.","Reflections can lag the sun within a twenty-minute step, and there is no lunar astronomy."],"watchlist":[{"source":"hosek2012sky","effort":"small","adds":"An analytic sky-dome model fitted to radiative-transfer simulations, a few coefficients per colour band, the quickest step to a sky gradient and sunset that follow the sun."},{"source":"hillaire2020sky","effort":"medium","adds":"A physically based sky and aerial perspective from small lookup tables, with multiple scattering, cheap per frame, so sunsets and the coast's haze would come from scattering."},{"source":"bruneton2008atmosphere","effort":"medium","adds":"Precomputed multiple scattering for every view and sun direction, the method the 2020 work builds on, in case per-frame tables cost too much."}],"next":[]}]},{"id":"cloth-bodies","name":"Cloth, skin and motion","summary":"Fabric that moves in the breeze or drapes over a sleeper, skin and hair that take light like skin and hair, and bodies and animals posed on the house's real geometry.","techniques":[{"id":"curtains","name":"Sheer curtains in the breeze","status":"shipped","since":"2026-10-16","thumbnail":{"path":"assets/img/project_pics/graphics-lab/curtains.webp","alt":"Two sheer curtain panels in the kitchen at 16:45, drawn part way against the low western sun","frame":"Kitchen view, 16:45 on October 16, 2026, reduced motion (settled drape)."},"what":"Four sheer panels inside the glass front, a position-based cloth in the coast's breeze, with a weave whose openness, glow and shadow change with the angle.","how":"`createCurtainCloth` steps 29 × 25 particle panels with small-step extended position-based dynamics: colour-batched structural, shear and bend constraints, long-range tethers, and a kinematic heading of carrier rings whose sine folds gather or spread. Air acts per triangle from the wind relative to the cloth, a flat-plate normal force plus skin friction applied semi-implicitly, and `createFacadeDraft` feeds jets through an open door from the coast's onshore breeze. `weaveOpenness` treats the voile as a plain weave of round yarns, so its gaps close toward grazing angles; back light passes as a thin Lambertian sheet plus a forward Henyey–Greenstein lobe, and a dithered shadow pass leaves a partial pool of light. `createCurtainRig` steps panels on screen at 30 Hz, and `curtainSchedule` draws them against the low sun.","files":[{"path":"assets/js/home-scene/curtain-cloth.mjs","role":"The cloth solver, the facade draft and the schedule.","functions":["createCurtainCloth","createFacadeDraft","createFacadeCurtains","curtainSchedule"]},{"path":"assets/js/home-scene/sheer-fabric.mjs","role":"Weave openness, transmission and the dithered shadow.","functions":["weaveOpenness","createSheerFabric","patchSheerShader","patchSheerShadowShader"]},{"path":"assets/js/home-scene/curtain-rig.mjs","role":"The live scene's curtains and their visibility budget.","functions":["createCurtainRig"]},{"path":"assets/js/home-scene/PHYSICS.md","role":"Equations, sources, cost and limits (\"Curtain cloth\")."}],"tests":["test/curtain-cloth.test.mjs","test/curtain-schedule.test.mjs"],"sources":["macklin2016xpbd","macklin2019smallsteps","muller2007pbd","kim2012lra","keckeisen2004wind","kotey2009screens","estevez2017sheen","henyey1941"],"related":[{"record":"homepage-desk-scene","techniques":["facade-curtains"]}],"limits":["No self-collision, so gathered stacks can pass through themselves in strong gusts.","The air has no shielding or wake, so a stack's inner folds feel the full wind.","Depth shadow maps cannot colour the light the yarn lets through.","The fabric is authored, not measured; there is no yarn-level or microcylinder model."],"watchlist":[{"source":"zhu2023yarn","effort":"medium","adds":"Shades cloth from its yarn hierarchy with fibre-level reflection and transmission, so the sheer's glow and openness would follow the yarn rather than one cylinder per thread."},{"source":"wu2020repulsion","effort":"large","adds":"Repulsion-based self-collision for cloth on the GPU, so gathered stacks would stop passing through themselves."},{"source":"chen2024vbd","effort":"large","adds":"Solves the cloth one vertex block at a time with local Newton steps, stable at large time steps, so the panels could keep their stiffness at 30 Hz without XPBD's substeps."}],"next":[]},{"id":"bedding","name":"Bedding draped by position-based dynamics","status":"shipped","since":"2026-10-14","thumbnail":{"path":"assets/img/project_pics/graphics-lab/bedding.webp","alt":"Sirui asleep at 04:00 under a duvet draped over his body, the pillow dented under his head","frame":"Sleep view, 04:00 on October 16, 2026, reduced motion."},"what":"Each avatar's duvet is dropped over the sleeping body offline by a position-based cloth solver and its pillow pressed in by the head, so no cover cuts through a chest; in the scene the cover breathes.","how":"`draped_duvet` in `bin/coastal_bedding.py` builds a height field of everything under the cover (`support_field`: sleeper, pillow, mattress, frame and bedside table) and `drape` drops a cloth grid onto it with coloured Gauss–Seidel distance constraints and a soft bend, after Müller and colleagues and Fratarcangeli, Tibaldo and Pellacini; the cover is then trimmed across the chest, quilted and given 3 cm of fill. `sleepers` poses every avatar's sleep clip at its deepest and shallowest breath, and `pillow` presses each pillow wherever a sleeping head rests. `bin/refresh_coastal_bedding.py` rebuilds the six bed variants in the retained house. In the scene, `createBreathingCover` in `bedding-breath.mjs` lifts the sleeper's cover a few millimetres along its normals around the chest at about fourteen breaths a minute, inhaling over 40 % of each breath (`breathAt`).","files":[{"path":"bin/coastal_bedding.py","role":"The position-based drape and the pressed pillows.","functions":["drape","draped_duvet","support_field","sleepers","pillow"]},{"path":"bin/refresh_coastal_bedding.py","role":"Builds the six variants in the retained house."},{"path":"bin/review_coastal_models.py","role":"Asserts the body, cover and pillow clearances."},{"path":"assets/js/home-scene/bedding-breath.mjs","role":"The cover's breath in the scene.","functions":["createBreathingCover","breathAt"]}],"tests":["test/bedding-breath.test.mjs"],"sources":["muller2007pbd","fratarcangeli2016vivace"],"related":[{"record":"homepage-desk-scene","techniques":["fitted-bedding"]}],"limits":["The drape is offline. In the scene the cover only breathes, a scripted swell of 7 mm at the chest, so it cannot follow a sleeper who turns.","Contact is against an upper envelope of the bodies, not two-sided collision.","The drape itself has no automated test; the review script records its clearances in `artwork/coastal-home/reviews/bedding.json`."],"watchlist":[{"source":"li2021cipc","effort":"large","adds":"Intersection-free contact for cloth and thin shells, so an offline drape could hold the duvet off every body without the trim and the fill that hide contact today."},{"source":"chen2024vbd","effort":"medium","adds":"The same block-descent solver offline, a stable replacement for the Gauss–Seidel drape that converges in fewer iterations."}],"next":[]},{"id":"skin","name":"Preintegrated skin diffusion","status":"shipped","since":"2026-10-02","thumbnail":{"path":"assets/img/project_pics/graphics-lab/skin.webp","alt":"Sirui drinking coffee at breakfast, close up, his face lit softly by the daylight from the glass front","frame":"Lab camera at the face, 11:45 on October 16, 2026, reduced motion."},"what":"Skin spreads direct light across a curved patch with a normalized diffusion profile, so a shadow's edge on the face turns warm instead of hard.","how":"`buildDiffusionTable` in `skin-diffusion-profile.mjs` integrates Christensen and Burley's normalized two-exponential profile over a locally spherical patch (`diffuseResponse`, with 96-node Gauss–Legendre quadrature) into a 257 × 49 half-float table. `createSkinDiffusion` measures mean curvature in metres from view-space derivatives of the skinned surface and replaces only the direct diffuse term of three.js's physical material with a 70/30 mix of diffused and ordinary response (`patchSkinDiffusionShader`). The red, green and blue distances, 3.2, 1.2 and 0.65 mm, are authored, not measured.","files":[{"path":"assets/js/home-scene/skin-diffusion-profile.mjs","role":"The profile integral and the lookup table.","functions":["buildDiffusionTable","diffuseResponse","estimateMeanCurvature"]},{"path":"assets/js/home-scene/skin-diffusion.mjs","role":"Curvature and the material hook.","functions":["createSkinDiffusion","patchSkinDiffusionShader"]},{"path":"assets/js/home-scene/SKIN-DIFFUSION.md","role":"Derivation, integration and limits."}],"tests":["test/skin-diffusion.test.mjs"],"sources":["christensen2015profiles","jimenez2015separable","chen2014pdss"],"related":[{"record":"homepage-desk-scene","techniques":["skin-diffusion"]}],"limits":["A local convex-sphere approximation with pointwise shadows, so no light crosses a shadow's edge and nothing shines through an ear.","Anisotropic shapes reduce to scalar mean curvature."],"watchlist":[{"source":"xie2020sss","effort":"medium","adds":"One-pass screen-space subsurface scattering with variance-guided sampling, so light would cross shadow edges on the face, which a per-point table cannot."}],"next":[{"move":"A spatial, diffuse-only buffer filtered with separable kernels, after Jimenez and colleagues, to carry light across shadow edges.","readiness":"needs-research"}]},{"id":"hair","name":"Strand highlights on hair","status":"shipped","since":"2026-10-13","thumbnail":{"path":"assets/img/project_pics/graphics-lab/hair.webp","alt":"Sirui at the desk at night, the desk lamp drawing bright bands across his long black hair","frame":"Lab camera at the head, 23:10 on October 16, 2026, reduced motion."},"what":"Hair gets two shifted highlight bands across its strands, the primary and secondary lobes of hair scattering, instead of a round spot.","how":"`strandHighlights` in `realism.mjs` adds two lobes to each avatar's hair material: a near-white primary shifted toward the tips and a broader, hair-tinted secondary shifted toward the roots, the R and TRT lobes of Marschner and colleagues in Scheuermann's real-time form, on Kajiya and Kay's strand model. The avatars carry no strand tangents, so each strand direction is combed from the crown of the hair mesh's bind pose and skinned like a normal. Widening each lobe by the normal's variance across the pixel, while keeping its energy, removes sparkle at the hairline.","files":[{"path":"assets/js/home-scene/realism.mjs","role":"The strand-highlight material hook.","functions":["strandHighlights","finishPhysicalMaterial"]}],"tests":[],"sources":["kajiya1989fur","marschner2003hair","scheuermann2004hair","kaplanyan2016normals","tokuyoshi2019gsaa"],"related":[{"record":"homepage-desk-scene","techniques":["hair-highlights"]}],"limits":["Direct light only. Environment reflections on hair stay a plain rough response, so hair in shade reads flat.","Mesh hair with combed directions, not strands, and no light scattered through the hair's volume.","No automated test."],"watchlist":[{"source":"chiang2016hair","effort":"medium","adds":"An energy-conserving, artist-controllable fibre model, so the two lobes' widths and tints could come from a physical fit."},{"source":"zinke2008dual","effort":"medium","adds":"Approximates light scattered through many hairs, so long dark hair would read as a volume rather than a shell."}],"next":[]},{"id":"gym-lifts","name":"Lifts posed on each figure","status":"shipped","since":"2026-10-16","thumbnail":{"path":"assets/img/project_pics/graphics-lab/gym-lifts.webp","alt":"Sirui doing pull-ups on the gym's wall frame at 18:12, hands on the bar, the power cage and the training board behind him","frame":"Gym view, 18:12 on October 16, 2026, reduced motion."},"what":"Every lift in Sirui's program is solved each frame on the avatar's own skeleton, so the hands meet the real bar whatever the body's proportions.","how":"`createLiftRig` in `lift-rig.mjs` poses the hips, pelvis, spine and head for each movement, then reaches each hand and foot target with an analytic two-bone solve toward a pole hint (`solveLimb`): knees out over the toes, elbows back on dips. Clearances come from each figure's own head, measured from the skinned bind-pose vertices (`measureHead`), so a bar passes under or behind a cartoon head. Each repetition eases in and out (`lowerThenDrive`, `driveThenLower`), the slow in and slow out that Thomas and Johnston describe and Lasseter carried into 3D animation. `trainingAt` turns the date into the day's nSuns session, `sessionPose` stages it and routes walks around the equipment on a visibility graph (`planRoute`), and `createGymProps` loads the plates and draws the board.","files":[{"path":"assets/js/home-scene/lift-rig.mjs","role":"Per-frame lifts on the avatar's own skeleton.","functions":["createLiftRig","solveLimb","measureHead","lowerThenDrive","driveThenLower"]},{"path":"assets/js/home-scene/gym-session.mjs","role":"Staged choreography and routing around the equipment.","functions":["sessionPose","planRoute","gymLayout"]},{"path":"assets/js/home-scene/training.mjs","role":"The program as pure functions of the date.","functions":["trainingAt","sessionPlan","sessionTimeline"]},{"path":"assets/js/home-scene/gym-props.mjs","role":"Bars, plates, dumbbells, the backrest and the board.","functions":["createGymProps","drawTrainingBoard"]},{"path":"bin/coastal_gym.py","role":"The gym room and its equipment."}],"tests":["test/coastal-lift-rig.test.mjs","test/coastal-gym-session.test.mjs","test/coastal-training.test.mjs"],"sources":["tolani2000ik","thomas1981illusion","lasseter1987principles","lozanoperez1979visibility"],"related":[{"record":"homepage-desk-scene","techniques":["gym-training"]}],"limits":["Kinematic poses, not dynamics. The body does not strain, sway or balance under the load.","Two-bone limbs on a set torso pose per lift, so the spine and the shoulders do not share the work."],"watchlist":[{"source":"aristidou2011fabrik","effort":"small","adds":"An iterative solver over whole chains, so the spine, shoulders and arms could solve together for presses and pull-ups."},{"source":"starke2020phases","effort":"large","adds":"Learns movement with many contacts from a phase per contact, so lifts, walks and handoffs of the bar could come from motion data."},{"source":"peng2021amp","effort":"large","adds":"Physics-based control with a learned motion prior, so a simulated body could strain and settle under the bar's weight."}],"next":[]},{"id":"wildlife","name":"Animals that plant their feet","status":"shipped","since":"2026-10-02","thumbnail":{"path":"assets/img/project_pics/graphics-lab/wildlife.webp","alt":"Harbor seals on the sand, sea lions on the rocks and sandpipers at the swash below the cave house","frame":"Lab camera over the beach, 15:00 on October 16, 2026, reduced motion."},"what":"Rabbits, sea lions, harbor seals, a raccoon, gulls and sandpipers move on choreography sampled from time, with feet that hold their contacts on the exported terrain.","how":"The acting is original and sampled from absolute active time, so a pause or a slow frame cannot accumulate drift. `rabbitActing` holds a rabbit's travel at takeoff and landing and advances it only in the air, with quintic travel so velocity and acceleration never jump. `raccoonMotion` keeps stance paws on world anchors while two-joint legs follow (`plantedFoot`), `shorebirdMotion` turns sandpipers at each zero-speed reversal, and `gullMotion` joins flight and perch with transitions continuous in acceleration. `solvePerchLanding` fits each gull's webbed foot to exported perch triangles.","files":[{"path":"assets/js/home-scene/wildlife-motion.mjs","role":"Rabbit and marine acting.","functions":["rabbitActing","pinnipedActing"]},{"path":"assets/js/home-scene/wildlife-neighbor-motion.mjs","role":"Raccoon, sandpiper and gull acting.","functions":["raccoonMotion","shorebirdMotion","gullMotion","plantedFoot"]},{"path":"assets/js/home-scene/wildlife-perch-contact.mjs","role":"Gull feet on real perches.","functions":["solvePerchLanding","samplePerchActing"]},{"path":"assets/js/home-scene/wildlife.mjs","role":"Instances, habitats and inspection."}],"tests":["test/wildlife-motion.test.mjs","test/wildlife-neighbors.test.mjs","test/wildlife-perch-contact.test.mjs"],"sources":[],"related":[{"record":"homepage-desk-scene","techniques":["animal-acting","perch-contact"]}],"limits":["Deterministic choreography, with no aerodynamics, collision solver or feather simulation.","Contacts are checked at samples, with no guarantee between them."],"watchlist":[{"source":"coros2011quadrupeds","effort":"large","adds":"Physics-based quadruped gaits with a flexible spine, so a rabbit's hop or the raccoon's walk would answer slope and landing."},{"source":"zhang2018mann","effort":"large","adds":"Blends expert controllers learned from quadruped motion capture, for natural transitions between walking, trotting, sitting and standing."},{"source":"ju2013flight","effort":"large","adds":"Controls flapping flight from wingbeat data, so the gulls could flap, glide and recover in the coast's gusts."}],"next":[]},{"id":"gliders","name":"Gliders soaring the bluffs","status":"shipped","since":"2026-10-15","thumbnail":{"path":"assets/img/project_pics/graphics-lab/gliders.webp","alt":"A red and white paraglider over a canyon in the north bluffs, with Torrey pines beyond","frame":"Lab camera 50 m from the gliders' route along the north bluffs, 15:00 on October 17, 2026, reduced motion."},"what":"Three paragliders and a hang glider follow closed loops along the north bluffs, banking into their turns, posed from the scene clock.","how":"`createRoute` in `gliders.mjs` tabulates a closed centripetal Catmull–Rom curve by arc length, and `gliderPose` moves each wing along it at its ground speed, banking by tan(bank) = v²κ/g, a coordinated turn. Poses are pure functions of the scene clock, so pause, hidden tabs and reduced motion hold every glider where it is.","files":[{"path":"assets/js/home-scene/gliders.mjs","role":"Routes, poses and banking.","functions":["createRoute","gliderPose","bindGliders"]}],"tests":["test/coastal-hinterland.test.mjs"],"sources":["banked-turn"],"related":[{"record":"homepage-desk-scene","techniques":["ridge-gliders"]}],"limits":["Authored loops, with no response to the wind."],"watchlist":[],"next":[{"move":"Crab into the live coast wind.","readiness":"needs-decision"}]}]},{"id":"camera-land","name":"Camera and land","summary":"A camera that knows the house's walls from its own geometry, and land that continues past the mainland in every direction, out to a coast the camera can now see from 160 m.","techniques":[{"id":"camera-field","name":"A camera that knows the house's walls","status":"shipped","since":"2026-10-15","thumbnail":{"path":"assets/img/project_pics/graphics-lab/camera-field.webp","alt":"The cave house in its cliff from far out over the Pacific, with the mesa, its planting and the coast running on into the haze","frame":"Lab camera about 155 m out over the sea, 15:00 on October 17, 2026, reduced motion."},"what":"Every static mesh is voxelized into a 12 cm field once it loads, and a spring arm keeps the camera on the near side of anything between it and the subject, so visitors can orbit freely and zoom the coast to 160 m.","how":"`createCameraField` in `camera-field.mjs` voxelizes each static house, room and coast mesh in a module worker (`camera-field-worker.mjs`), and `camera.mjs` classifies the cells: pieces under 45 cm in every direction are detail, a cell blocks when its neighbourhood holds a plane's worth of structure, and blocking cells grow a 24 cm clearance shell. Rays walk the field cell by cell, after Amanatides and Woo. `cameraArm` places the camera at the farthest point on the orbit ray the path reaches without crossing a blocking cell, with side rays that pull in before an edge reaches it, and `steerOrbit` refuses steps that would leave the arm under 40 % of the requested distance. `farView` lets the haze, the clip planes and the sun's shadow follow the coast's orbit out to 160 m.","files":[{"path":"assets/js/home-scene/camera-field.mjs","role":"Voxelizes the loaded meshes and decides what may hold the camera back.","functions":["createCameraField","collidable","airSeeds"]},{"path":"assets/js/home-scene/camera-field-worker.mjs","role":"Voxelizes off the main thread."},{"path":"assets/js/home-scene/camera.mjs","role":"Classifies the cells, walks rays and steers the arm.","functions":["createCollisionGrid","cameraArm","steerOrbit","farView","outsideClearance"]}],"tests":["test/coastal-camera.test.mjs","test/coastal-camera-motion.test.mjs","test/visual/desk-scene.spec.js"],"sources":["amanatides1987voxel","epic-spring-arm","reed2015depth"],"related":[{"record":"homepage-desk-scene","techniques":["camera-collision-field","spring-arm","far-coast-view"]}],"limits":["Ready about 3.3 s after the rooms stream in. Characters, P, the animals and the clifftop planting are not in the field.","Nothing scores the composition, and one 40 % threshold serves every room."],"watchlist":[{"source":"oskam2009visibility","effort":"medium","adds":"Plans camera transitions through a visibility roadmap, so the subject stays in view while the camera moves around obstacles, a step past refusing moves that would hide it."},{"source":"lino2015toric","effort":"medium","adds":"A compact camera space built around on-screen subject positions, so a room's framing could be composed rather than only kept clear."}],"next":[{"move":"Score candidate yaws for the subject's visibility near obstacles.","readiness":"needs-research"}]},{"id":"hinterland","name":"The land beyond the mainland's walls","status":"shipped","since":"2026-10-15","thumbnail":{"path":"assets/img/project_pics/graphics-lab/hinterland.webp","alt":"Sandstone bluffs north of the house cut by a canyon, the gliderport's lawn and Torrey pines on top, and a paraglider overhead","frame":"Lab camera about 120 m off the north bluffs, 15:00 on October 17, 2026, reduced motion."},"what":"A terraced mesa with badland canyons, bluffs with the gliderport, a headland with sea caves and a distant point continue the coast past the mainland's flat walls.","how":"`bin/build_coastal_hinterland.py` snaps the new ground to the mainland's 225 back-edge and 41 end-edge vertices (`snap`, `end_edge`) and continues the mainland's own height, cliff and beach functions across each seam, eased over 25 m. One constrained Delaunay triangulation, after Shewchuk's Triangle, runs from 0.5 m triangles at the walls to 18 m on the far hill, with occlusion baked into vertex colours. Planting, trails, the gliderport's lawn and a deck over three sea caves follow photographs of Torrey Pines, Black's Beach, Goldfish Point and the gliderport. `bindHinterland` loads the 1.36 MB model on the first visit outside and merges its terrain into the camera's height grid (`mergeCameraGrid`), and `bindWindsock` turns the gliderport's wind sock with the coast's wind.","files":[{"path":"bin/build_coastal_hinterland.py","role":"Seams, terrain, triangulation and the baked occlusion.","functions":["snap","end_edge","build_coast","build_beach","ground_spacing"]},{"path":"bin/coastal_hinterland.py","role":"The land's height, cliff and beach functions."},{"path":"bin/coastal_hinterland_props.py","role":"The gliderport, the deck and the planting."},{"path":"assets/js/home-scene/hinterland.mjs","role":"Loads the land, merges its camera grid and binds the wind sock.","functions":["bindHinterland","mergeCameraGrid","bindWindsock"]},{"path":"assets/models/home/hinterland.glb","role":"The exported land."}],"tests":["test/test_coastal_hinterland.py","test/coastal-hinterland.test.mjs"],"sources":["shewchuk-triangle","z3lvs-torrey-badlands","stch2022-torrey-sandstone","andrek02-sea-cave","matejicek-goldfish-point","ncysea-gliderport"],"related":[{"record":"homepage-desk-scene","techniques":["hinterland"]}],"limits":["The 400 m sea plane ends at |x| = 200 m while the coast runs about 700 m each way, and the new beaches have no surf.","Shrubs read as mounds within about 20 m."],"watchlist":[{"source":"cordonnier2017landscapes","effort":"large","adds":"Couples erosion with vegetation simulation, so the canyons and the planting could grow together instead of being placed by distance."},{"source":"paris2019amplification","effort":"large","adds":"Amplifies terrain with implicit 3D features, the overhangs and caves a height field cannot hold, so the sea caves and undercut cliffs could belong to the ground itself."}],"next":[{"move":"Extend the shore samples so surf follows the new beaches.","readiness":"needs-decision"}]}]},{"id":"drawing","name":"Drawing","summary":"The house drawn in pen while it loads, traced offline from the authored views' geometry and morphed from drawing to drawing as each piece arrives.","techniques":[{"id":"loading-sketch","name":"A pen sketch while the house loads","status":"shipped","since":"2026-10-14","thumbnail":{"path":"assets/img/project_pics/graphics-lab/loading-sketch.webp","alt":"Pen strokes drawing the bedroom while the 3D home loads, the bed, a framed picture, a plant and the doorway","frame":"The homepage 4.1 s into loading on October 16, 2026, reduced motion (each drawing still)."},"what":"Pen strokes traced offline from geometry buffers draw the sea, the cliff, the cut-away house and the occupied room while the scene loads, then trace the first rendered frame.","how":"`strokesFrom` in `bin/build_loading_sketch.cjs` traces each authored view's object-ID and surface-normal passes, after Saito and Takahashi's geometry buffers: object outlines weighted by how much of the frame each object fills, creases sharper than about 57°, and long straight runs favoured by the structure tensor's coherence. Eight drawings pack into 45 KB. `createSketchEngine` flies strokes on a damped spring (`springStep`), pairs them with their next targets in Hilbert-curve order (`hilbertIndex`) so a morph flows instead of tangling, and lets a resting drawing breathe (`breathDepth`). `createLoadingSketch` hands an OffscreenCanvas to a worker so model parsing never stalls the strokes.","files":[{"path":"bin/build_loading_sketch.cjs","role":"Traces the drawings from the authored views.","functions":["strokesFrom"]},{"path":"assets/js/home-scene/loading-sketch-core.mjs","role":"Stroke motion, Hilbert pairing, breathing and edge tracing.","functions":["createSketchEngine","springStep","hilbertIndex","breathDepth","frameStrokes"]},{"path":"assets/js/home-scene/loading-sketch.mjs","role":"The page side, the worker hand-off and the first-frame trace.","functions":["createLoadingSketch"]},{"path":"assets/js/home-scene/loading-sketch-worker.mjs","role":"Draws off the main thread."},{"path":"assets/models/home/loading-sketch.json","role":"The packed drawings."}],"tests":["test/loading-sketch.test.mjs"],"sources":["saito1990comprehensible"],"related":[{"record":"homepage-desk-scene","techniques":["loading-sketch"]}],"limits":["The drawings are fixed captures of the authored views and go stale when a room or a camera changes.","Image-space outlines and creases only, with no view-dependent lines such as suggestive contours."],"watchlist":[{"source":"decarlo2003suggestive","effort":"medium","adds":"Draws lines where a contour would appear from a nearby viewpoint, so rounded stones and the cliff's bulges would read as volume."},{"source":"yang2018ftpsc","effort":"medium","adds":"Matches strokes between drawings while keeping their neighbours' layout, so morphs would pair strokes by shape instead of by Hilbert order."},{"source":"benard2012active","effort":"medium","adds":"Image-space snakes that keep stylized lines coherent on animated 3D models, for the hand-off where the strokes trace the first live frame."},{"source":"cole2008lines","effort":"small","adds":"Measures where artists draw lines on the same models, a test for which lines the tracer keeps."}],"next":[]}]},{"id":"method","name":"How the lab is kept","index":false,"summary":"The tools that keep the Graphics Lab page and this record honest: stills captured from the live scene, and a brief that ranks the next moves and the papers to try.","techniques":[{"id":"lab-stills","name":"Stills from the live scene","status":"shipped","since":"2026-10-16","what":"Each thumbnail is a frame of the running scene at a named hour, room and camera, scaled but not retouched.","how":"`bin/capture_graphics_lab_stills.cjs` opens the homepage's authoring lab (`?scene-lab=1`) in headless Chromium, sets the hour, the room and, where the authored view does not show a technique, a lab camera. It fixes the page clock for a dated frame, removes the homepage's feathered edge so a frame reads on either theme, and writes each 4:3 frame with its scene evidence to an unwatched folder. `bin/make_graphics_lab_thumbnails.py` scales the chosen frames to 480 × 360 WebP and lays four of them out as the card teaser.","files":[{"path":"bin/capture_graphics_lab_stills.cjs","role":"Drives the live scene and writes the frames and their ledger.","functions":["STILLS","objectPosition"]},{"path":"bin/make_graphics_lab_thumbnails.py","role":"Picks, scales and lays out the frames.","functions":["FRAMES","TEASER","fit_4x3"]},{"path":"assets/img/project_pics/graphics-lab/","role":"The thumbnails and the teaser."}],"tests":["test/test_design_records.py"],"sources":[],"limits":["Frames go stale when the scene changes; recapture after a room, camera or look change.","Captured in headless Chromium on one machine's integrated GPU, so colours follow its driver."],"next":[{"move":"Recapture the stills once the renovation and the wildlife work land; every frame of the house predates the renovated plaster, stone and edges.","readiness":"ready"}]},{"id":"lab-brief","name":"A brief that proposes the next paper","status":"shipped","since":"2026-10-16","what":"The brief script ranks each technique's next moves by readiness and lists the papers to try by effort, so a later pass starts from the record.","how":"`bin/design_record_brief.py graphics-lab` prints each system's current state, its limits, where its last move pointed, the candidate moves ranked by readiness and then by how recently their system moved, and every watchlist paper sorted by effort with its citation. `test/test_design_records.py` checks that each named function appears in its file, that every watchlist paper is a listed source the technique does not already build on, and that each link to the coastal home record resolves.","files":[{"path":"bin/design_record_brief.py","role":"The brief, with candidate moves and papers to try.","functions":["build_brief","watchlist","markdown"]},{"path":"test/test_design_records.py","role":"The record's checks."}],"tests":["test/test_design_records.py"],"sources":[],"limits":["Effort is a guess from the code's shape, not a measured estimate."],"next":[]}]}],"shortlist":[{"technique":"light-paths","source":"zeltner2020sms"},{"technique":"sun-sky","source":"hillaire2020sky"},{"technique":"onsen-water","source":"jeschke2023dispersive"},{"technique":"coast-wind","source":"diener2009wind"}],"history":[{"date":"2026-10-14","title":"Two renderers, one minute","system":"light-transport","frame":"I agreed to the Metropolis experiment. Show, on light the house actually has, when Markov chain Monte Carlo beats independent sampling and when it does not.","dimensions":["paths next-event estimation cannot connect","the sun's size against a minute's budget","what equal means","how error is measured","where the reference comes from","how much of a visitor's processor the page may use"],"move":"A dependency-free renderer of a simplified onsen whose single path sampler is fed independent numbers (path tracing) or mutated ones (Kelemen's Metropolis), raced in module workers on its own page.","backtalk":"After a minute path tracing was off by 984 % and Metropolis by 180 %. Metropolis's total brightness is itself a rare-event estimate, because the bootstrap usually holds no sun path. Lazily replayed small steps left a few-percent bias until unread coordinates were redrawn, and a slab shortcut created ghost water hits that tests now catch.","reframe":"The engine is ready for the pool light's caustics, and for manifold-based mutations if the race should be won outright.","commit":"a1b4d3bd3","sources":["veach1997mlt","kelemen2002pssmlt","jakob2012manifold","zeltner2020sms"]},{"date":"2026-10-16","title":"One lab instead of a page per experiment","system":"method","frame":"Sirui wanted the graphics experiments written up as a record that newer SIGGRAPH papers could extend, and found a project page for every experiment too much, so he asked for a hierarchy.","dimensions":["how many entries the projects index shows","what each experiment gets (its own page or a section of the record)","what a row says at a glance","where the papers to try live","how a still stays honest"],"move":"One Graphics Lab entry on the projects index, with a row per experiment that opens its own page (the light lab) or its section of this record, which gains entry-point functions, links to the coastal home record and a watchlist of newer papers with effort guesses. Light Paths in the Onsen keeps its address as a child of the lab.","backtalk":"The October noon sun stays below the light well's shaft, so the first light-well still showed no beam and the frame moved to an August noon. Night frames hid the steam and the hand's ripples, so those stills moved to daylight. A pattern meant to find the pines framed the avatar's spine instead. Checking the papers caught four DOIs in the draft list that resolved to other papers.","reframe":"Which paper comes first is Sirui's call; the shortlist puts a visible change in each of light, sky, water and wind.","sources":["zeltner2020sms","hillaire2020sky","jeschke2023dispersive","diener2009wind"]}],"open_problems":[{"id":"next-experiment","title":"Which paper first","system":"method","why_hard":"Every watchlist entry would make a technique more faithful, but they differ by an order of magnitude in effort and in how much a visitor would notice. The shortlist proposes four with a visible payoff; the choice is a taste call.","candidate_moves":["Light paths: specular manifold sampling, to win the race on the caustics outright.","Sun and sky: a scattering sky, for real sunsets and a terrace hour at dusk.","Onsen: dispersive surface waves, so the hand's ripples travel at their true speed.","Wind: a wind projection basis, so the pines and the palm sway as trees."],"sources":["zeltner2020sms","hillaire2020sky","jeschke2023dispersive","diener2009wind"],"readiness":"needs-decision"},{"id":"gpu-compute","title":"Simulation without compute shaders","system":"water-air","why_hard":"The scene renders through WebGL2 and three.js r164, which have no compute shaders. An FFT ocean, a pressure solve for the steam, cloth on the GPU and probe updates all want them, so each must become chains of fragment passes or wait for WebGPU, a move that would touch every material and pass the shader warmup knows.","candidate_moves":["Prototype one FFT pass chain as fragment passes on a separate page and time it against the authored spectrum.","Keep the small solvers (the onsen, the steam, the cloth) on the CPU and move only the ocean's spectrum to the GPU.","Price a WebGPU renderer for the home as its own experiment before any paper depends on it."],"sources":["tessendorf2004ocean","horvath2015spectra"],"readiness":"needs-decision"},{"id":"hard-paths","title":"Light that only a tracer can find","system":"light-transport","why_hard":"Caustics on the onsen's floor and vault, glossy reflections of the lit house and light through the sheer all follow paths a rasterizer cannot aim at. The light lab finds them on the CPU, but the house has no runtime tracer, and WebGL offers no ray queries.","candidate_moves":["Precompute a caustic pattern in the lab and project it in the onsen, moved by the solver's slopes.","Shade the light well's aperture with glossy area lights, the cheapest specular path the house is missing."],"sources":["loubet2020slope","heitz2016ltc"],"readiness":"needs-research"}],"sources":[{"id":"veach1997mlt","label":"Veach and Guibas 1997","citation":"Eric Veach and Leonidas J. Guibas. *Metropolis Light Transport*. Proceedings of SIGGRAPH 97, 65–76, 1997.","url":"https://doi.org/10.1145/258734.258775"},{"id":"kelemen2002pssmlt","label":"Kelemen et al. 2002","citation":"Csaba Kelemen, László Szirmay-Kalos, György Antal and Ferenc Csonka. *A Simple and Robust Mutation Strategy for the Metropolis Light Transport Algorithm*. Computer Graphics Forum 21(3), 531–540, Eurographics 2002.","url":"https://doi.org/10.1111/1467-8659.t01-1-00703"},{"id":"veach1997thesis","label":"Veach 1997, thesis","citation":"Eric Veach. *Robust Monte Carlo Methods for Light Transport Simulation*. PhD thesis, Stanford University, 1997.","url":"https://graphics.stanford.edu/papers/veach_thesis/"},{"id":"pbrt3-mlt","label":"PBRT 3rd edition, Metropolis","citation":"Matt Pharr, Wenzel Jakob and Greg Humphreys. *Physically Based Rendering*, 3rd edition, Morgan Kaufmann, 2016, section 16.4, Metropolis Light Transport.","url":"https://pbr-book.org/3ed-2018/Light_Transport_III_Bidirectional_Methods/Metropolis_Light_Transport"},{"id":"jakob2012manifold","label":"Jakob and Marschner 2012","citation":"Wenzel Jakob and Steve Marschner. *Manifold Exploration: A Markov Chain Monte Carlo Technique for Rendering Scenes with Difficult Specular Transport*. ACM Transactions on Graphics 31(4), article 58, SIGGRAPH 2012.","url":"https://doi.org/10.1145/2185520.2185554","venue":"SIGGRAPH 2012","year":2012},{"id":"zeltner2020sms","label":"Zeltner, Georgiev and Jakob 2020","citation":"Tizian Zeltner, Iliyan Georgiev and Wenzel Jakob. *Specular Manifold Sampling for Rendering High-Frequency Caustics and Glints*. ACM Transactions on Graphics 39(4), article 149, SIGGRAPH 2020.","url":"https://doi.org/10.1145/3386569.3392408","venue":"SIGGRAPH 2020","year":2020},{"id":"loubet2020slope","label":"Loubet et al. 2020","citation":"Guillaume Loubet, Tizian Zeltner, Nicolas Holzschuch and Wenzel Jakob. *Slope-Space Integrals for Specular Next Event Estimation*. ACM Transactions on Graphics 39(6), article 239, SIGGRAPH Asia 2020.","url":"https://doi.org/10.1145/3414685.3417811","venue":"SIGGRAPH Asia 2020","year":2020},{"id":"muller2017guiding","label":"Müller, Gross and Novák 2017","citation":"Thomas Müller, Markus Gross and Jan Novák. *Practical Path Guiding for Efficient Light-Transport Simulation*. Computer Graphics Forum 36(4), 91–100, EGSR 2017.","url":"https://doi.org/10.1111/cgf.13227","venue":"EGSR 2017","year":2017},{"id":"wronski2014fog","label":"Wronski 2014","citation":"Bartlomiej Wronski. *Volumetric Fog: Unified Compute Shader-Based Solution to Atmospheric Scattering*. SIGGRAPH 2014 course, Advances in Real-Time Rendering in 3D Graphics and Games.","url":"https://bartwronski.com/wp-content/uploads/2014/08/bwronski_volumetric_fog_siggraph2014.pdf"},{"id":"heitz2016ltc","label":"Heitz et al. 2016","citation":"Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt. *Real-Time Polygonal-Light Shading with Linearly Transformed Cosines*. ACM Transactions on Graphics 35(4), article 41, SIGGRAPH 2016.","url":"https://doi.org/10.1145/2897824.2925895","venue":"SIGGRAPH 2016","year":2016},{"id":"chen2011minmax","label":"Chen et al. 2011","citation":"Jiawen Chen, Ilya Baran, Frédo Durand and Wojciech Jarosz. *Real-Time Volumetric Shadows using 1D Min-Max Mipmaps*. ACM Symposium on Interactive 3D Graphics and Games (I3D), 39–46, 2011.","url":"https://doi.org/10.1145/1944745.1944752","venue":"I3D 2011","year":2011},{"id":"ramamoorthi2001irradiance","label":"Ramamoorthi and Hanrahan 2001","citation":"Ravi Ramamoorthi and Pat Hanrahan. *An Efficient Representation for Irradiance Environment Maps*. Proceedings of SIGGRAPH 2001, 497–500.","url":"https://doi.org/10.1145/383259.383317"},{"id":"majercik2019ddgi","label":"Majercik et al. 2019","citation":"Zander Majercik, Jean-Philippe Guertin, Derek Nowrouzezahrai and Morgan McGuire. *Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields*. Journal of Computer Graphics Techniques 8(2), 1–30, 2019.","url":"https://jcgt.org/published/0008/02/01/"},{"id":"pbrt4-bvh","label":"PBRT 4th edition, BVHs","citation":"Matt Pharr, Wenzel Jakob and Greg Humphreys. *Physically Based Rendering*, 4th edition, MIT Press, 2023, section 7.3, Bounding Volume Hierarchies.","url":"https://www.pbr-book.org/4ed/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies"},{"id":"iwanicki2017dice","label":"Iwanicki and Sloan 2017","citation":"Michał Iwanicki and Peter-Pike Sloan. *Ambient Dice*. Eurographics Symposium on Rendering 2017, Experimental Ideas \u0026 Implementations, 19–29.","url":"https://doi.org/10.2312/sre.20171191","venue":"EGSR 2017","year":2017},{"id":"silvennoinen2017probes","label":"Silvennoinen and Lehtinen 2017","citation":"Ari Silvennoinen and Jaakko Lehtinen. *Real-time Global Illumination by Precomputed Local Reconstruction from Sparse Radiance Probes*. ACM Transactions on Graphics 36(6), article 230, SIGGRAPH Asia 2017.","url":"https://doi.org/10.1145/3130800.3130852","venue":"SIGGRAPH Asia 2017","year":2017},{"id":"rodriguez2020glossy","label":"Rodriguez et al. 2020","citation":"Simon Rodriguez, Thomas Leimkühler, Siddhant Prakash, Chris Wyman, Peter Shirley and George Drettakis. *Glossy Probe Reprojection for Interactive Global Illumination*. ACM Transactions on Graphics 39(6), article 237, SIGGRAPH Asia 2020.","url":"https://doi.org/10.1145/3414685.3417823","venue":"SIGGRAPH Asia 2020","year":2020},{"id":"jimenez2016gtao","label":"Jimenez et al. 2016","citation":"Jorge Jimenez, Xian-Chun Wu, Angelo Pesce and Adrian Jarabo. *Practical Realtime Strategies for Accurate Indirect Occlusion*. Activision technical memo ATVI-TR-16-01, 2016, presented in the SIGGRAPH 2016 course Physically Based Shading in Theory and Practice.","url":"https://www.activision.com/cdn/research/PracticalRealtimeStrategiesTRfinal.pdf"},{"id":"therrien2023bitmask","label":"Therrien, Levesque and Gilet 2023","citation":"Olivier Therrien, Yannick Levesque and Guillaume Gilet. *Screen Space Indirect Lighting with Visibility Bitmask*. The Visual Computer 39(11), 5925–5936, 2023.","url":"https://doi.org/10.1007/s00371-022-02703-y","venue":"The Visual Computer","year":2023},{"id":"finch2004gerstner","label":"Finch 2004","citation":"Mark Finch. *Effective Water Simulation from Physical Models*. In GPU Gems, edited by Randima Fernando, chapter 1, Addison-Wesley, 2004.","url":"https://developer.nvidia.com/gpugems/gpugems/part-i-natural-effects/chapter-1-effective-water-simulation-physical-models"},{"id":"bruneton2010ocean","label":"Bruneton, Neyret and Holzschuch 2010","citation":"Eric Bruneton, Fabrice Neyret and Nicolas Holzschuch. *Real-time Realistic Ocean Lighting using Seamless Transitions from Geometry to BRDF*. Computer Graphics Forum 29(2), 487–496, Eurographics 2010.","url":"https://doi.org/10.1111/j.1467-8659.2009.01618.x"},{"id":"tessendorf2004ocean","label":"Tessendorf, Simulating Ocean Water","citation":"Jerry Tessendorf. *Simulating Ocean Water*. SIGGRAPH course notes, revised 1999–2004.","url":"https://jtessen.people.clemson.edu/reports/papers_files/coursenotes2004.pdf"},{"id":"arcblanc2025","label":"Algis et al. 2025","citation":"David Algis, Bérenger Bramas, Emmanuelle Darles and Lilian Aveneau. *Arc Blanc: a real time ocean simulation framework*. Journal of Computer Graphics Techniques 14(1), 70–115, 2025.","url":"https://jcgt.org/published/0014/01/05/"},{"id":"pierson1964spectrum","label":"Pierson and Moskowitz 1964","citation":"Willard J. Pierson and Lionel Moskowitz. *A proposed spectral form for fully developed wind seas based on the similarity theory of S. A. Kitaigorodskii*. Journal of Geophysical Research 69, 1964.","url":"https://doi.org/10.1029/JZ069i024p05181"},{"id":"cox1954glitter","label":"Cox and Munk 1954","citation":"Charles Cox and Walter Munk. *Measurement of the Roughness of the Sea Surface from Photographs of the Sun's Glitter*. Journal of the Optical Society of America 44, 1954.","url":"https://doi.org/10.1364/JOSA.44.000838"},{"id":"monahan1980whitecaps","label":"Monahan and O'Muircheartaigh 1980","citation":"Edward C. Monahan and Iognáid Ó Muircheartaigh. *Optimal Power-Law Description of Oceanic Whitecap Coverage Dependence on Wind Speed*. Journal of Physical Oceanography 10, 1980.","url":"https://doi.org/10.1175/1520-0485%281980%29010%3C2094:OPLDOO%3E2.0.CO;2"},{"id":"jeschke2020boundary","label":"Jeschke et al. 2020","citation":"Stefan Jeschke, Christian Hafner, Nuttapong Chentanez, Miles Macklin, Matthias Müller-Fischer and Chris Wojtan. *Making Procedural Water Waves Boundary-aware*. Computer Graphics Forum 39(8), 47–54, SCA 2020.","url":"https://doi.org/10.1111/cgf.14100","venue":"SCA 2020","year":2020},{"id":"dupuy2012whitecaps","label":"Dupuy and Bruneton 2012","citation":"Jonathan Dupuy and Eric Bruneton. *Real-time Animation and Rendering of Ocean Whitecaps*. SIGGRAPH Asia 2012 Technical Briefs, article 15.","url":"https://doi.org/10.1145/2407746.2407761","venue":"SIGGRAPH Asia 2012 Technical Briefs","year":2012},{"id":"jeschke2018wavelets","label":"Jeschke et al. 2018","citation":"Stefan Jeschke, Tomáš Skřivan, Matthias Müller-Fischer, Nuttapong Chentanez, Miles Macklin and Chris Wojtan. *Water Surface Wavelets*. ACM Transactions on Graphics 37(4), article 94, SIGGRAPH 2018.","url":"https://doi.org/10.1145/3197517.3201336","venue":"SIGGRAPH 2018","year":2018},{"id":"horvath2015spectra","label":"Horvath 2015","citation":"Christopher J. Horvath. *Empirical Directional Wave Spectra for Computer Graphics*. Proceedings of the Symposium on Digital Production (DigiPro), 29–39, 2015.","url":"https://doi.org/10.1145/2791261.2791267","venue":"DigiPro 2015","year":2015},{"id":"chentanez2010water","label":"Chentanez and Müller 2010","citation":"Nuttapong Chentanez and Matthias Müller. *Real-time Simulation of Large Bodies of Water with Small Scale Details*. Symposium on Computer Animation, 197–206, 2010.","url":"https://doi.org/10.2312/SCA/SCA10/197-206"},{"id":"jeschke2023dispersive","label":"Jeschke and Wojtan 2023","citation":"Stefan Jeschke and Chris Wojtan. *Generalizing Shallow Water Simulations with Dispersive Surface Waves*. ACM Transactions on Graphics 42(4), article 83, SIGGRAPH 2023.","url":"https://doi.org/10.1145/3592098","venue":"SIGGRAPH 2023","year":2023},{"id":"chentanez2015coupling","label":"Chentanez, Müller and Kim 2015","citation":"Nuttapong Chentanez, Matthias Müller and Tae-Yong Kim. *Coupling 3D Eulerian, Heightfield and Particle Methods for Interactive Simulation of Large Scale Liquid Phenomena*. IEEE Transactions on Visualization and Computer Graphics 21(10), 1116–1128, 2015, first presented at SCA 2014.","url":"https://doi.org/10.1109/TVCG.2015.2449303","venue":"IEEE TVCG (SCA 2014)","year":2015},{"id":"stam1999stable","label":"Stam 1999","citation":"Jos Stam. *Stable Fluids*. Proceedings of SIGGRAPH 99, 121–128, 1999.","url":"https://doi.org/10.1145/311535.311548"},{"id":"fedkiw2001smoke","label":"Fedkiw, Stam and Jensen 2001","citation":"Ronald Fedkiw, Jos Stam and Henrik Wann Jensen. *Visual Simulation of Smoke*. Proceedings of SIGGRAPH 2001, 15–22.","url":"https://doi.org/10.1145/383259.383260"},{"id":"qu2019bimocq","label":"Qu et al. 2019","citation":"Ziyin Qu, Xinxin Zhang, Ming Gao, Chenfanfu Jiang and Baoquan Chen. *Efficient and Conservative Fluids Using Bidirectional Mapping*. ACM Transactions on Graphics 38(4), article 128, SIGGRAPH 2019.","url":"https://doi.org/10.1145/3306346.3322945","venue":"SIGGRAPH 2019","year":2019},{"id":"kim2008wavelet","label":"Kim et al. 2008","citation":"Theodore Kim, Nils Thürey, Doug James and Markus Gross. *Wavelet Turbulence for Fluid Simulation*. ACM Transactions on Graphics 27(3), article 50, SIGGRAPH 2008.","url":"https://doi.org/10.1145/1360612.1360649","venue":"SIGGRAPH 2008","year":2008},{"id":"zehnder2018advection","label":"Zehnder, Narain and Thomaszewski 2018","citation":"Jonas Zehnder, Rahul Narain and Bernhard Thomaszewski. *An Advection-Reflection Solver for Detail-Preserving Fluid Simulation*. ACM Transactions on Graphics 37(4), article 85, SIGGRAPH 2018.","url":"https://doi.org/10.1145/3197517.3201324","venue":"SIGGRAPH 2018","year":2018},{"id":"ndbc-ljpc1","label":"NDBC station LJPC1","citation":"NOAA National Data Buoy Center. *Station LJPC1, La Jolla, CA*, hourly standard meteorological records 2023–2025.","url":"https://www.ndbc.noaa.gov/station_page.php?station=ljpc1"},{"id":"taylor1938turbulence","label":"Taylor 1938","citation":"G. I. Taylor. *The Spectrum of Turbulence*. Proceedings of the Royal Society A 164, 1938.","url":"https://doi.org/10.1098/rspa.1938.0032"},{"id":"bridson2007curl","label":"Bridson, Hourihan and Nordenstam 2007","citation":"Robert Bridson, Jim Hourihan and Marcus Nordenstam. *Curl-Noise for Procedural Fluid Flow*. ACM Transactions on Graphics 26(3), article 46, SIGGRAPH 2007.","url":"https://doi.org/10.1145/1276377.1276435"},{"id":"delangre2008wind","label":"de Langre 2008","citation":"Emmanuel de Langre. *Effects of Wind on Plants*. Annual Review of Fluid Mechanics 40, 2008.","url":"https://doi.org/10.1146/annurev.fluid.40.111406.102135"},{"id":"vogel1989drag","label":"Vogel 1989","citation":"Steven Vogel. *Drag and Reconfiguration of Broad Leaves in High Winds*. Journal of Experimental Botany 40, 1989.","url":"https://doi.org/10.1093/jxb/40.8.941"},{"id":"py2006lockin","label":"Py, de Langre and Moulia 2006","citation":"Charlotte Py, Emmanuel de Langre and Bruno Moulia. *A frequency lock-in mechanism in the interaction between wind and crop canopies*. Journal of Fluid Mechanics 568, 2006.","url":"https://doi.org/10.1017/S0022112006002667"},{"id":"wellons2018hash","label":"Wellons 2018","citation":"Chris Wellons. *Prospecting for Hash Functions*, 2018.","url":"https://nullprogram.com/blog/2018/07/31/"},{"id":"diener2009wind","label":"Diener et al. 2009","citation":"Julien Diener, Mathieu Rodriguez, Lionel Baboud and Lionel Reveret. *Wind Projection Basis for Real-Time Animation of Trees*. Computer Graphics Forum 28(2), 533–540, Eurographics 2009.","url":"https://doi.org/10.1111/j.1467-8659.2009.01393.x","venue":"Eurographics 2009","year":2009},{"id":"habel2009trees","label":"Habel, Kusternig and Wimmer 2009","citation":"Ralf Habel, Alexander Kusternig and Michael Wimmer. *Physically Guided Animation of Trees*. Computer Graphics Forum 28(2), 523–532, Eurographics 2009.","url":"https://doi.org/10.1111/j.1467-8659.2009.01391.x","venue":"Eurographics 2009","year":2009},{"id":"jahrmann2017grass","label":"Jahrmann and Wimmer 2017","citation":"Klemens Jahrmann and Michael Wimmer. *Responsive Real-Time Grass Rendering for General 3D Scenes*. ACM Symposium on Interactive 3D Graphics and Games (I3D), article 6, 2017.","url":"https://doi.org/10.1145/3023368.3023380","venue":"I3D 2017","year":2017},{"id":"noaa-solar","label":"NOAA solar equations","citation":"NOAA Global Monitoring Division. *General Solar Position Calculations*.","url":"https://gml.noaa.gov/grad/solcalc/solareqns.PDF"},{"id":"hosek2012sky","label":"Hosek and Wilkie 2012","citation":"Lukas Hosek and Alexander Wilkie. *An Analytic Model for Full Spectral Sky-Dome Radiance*. ACM Transactions on Graphics 31(4), article 95, SIGGRAPH 2012.","url":"https://doi.org/10.1145/2185520.2185591","venue":"SIGGRAPH 2012","year":2012},{"id":"hillaire2020sky","label":"Hillaire 2020","citation":"Sébastien Hillaire. *A Scalable and Production Ready Sky and Atmosphere Rendering Technique*. Computer Graphics Forum 39(4), 13–22, EGSR 2020.","url":"https://doi.org/10.1111/cgf.14050","venue":"EGSR 2020","year":2020},{"id":"bruneton2008atmosphere","label":"Bruneton and Neyret 2008","citation":"Eric Bruneton and Fabrice Neyret. *Precomputed Atmospheric Scattering*. Computer Graphics Forum 27(4), 1079–1086, EGSR 2008.","url":"https://doi.org/10.1111/j.1467-8659.2008.01245.x","venue":"EGSR 2008","year":2008},{"id":"macklin2016xpbd","label":"Macklin, Müller and Chentanez 2016","citation":"Miles Macklin, Matthias Müller and Nuttapong Chentanez. *XPBD: Position-Based Simulation of Compliant Constrained Dynamics*. Motion in Games (MIG), 49–54, 2016.","url":"https://doi.org/10.1145/2994258.2994272"},{"id":"macklin2019smallsteps","label":"Macklin et al. 2019","citation":"Miles Macklin, Kier Storey, Michelle Lu, Pierre Terdiman, Nuttapong Chentanez, Stefan Jeschke and Matthias Müller. *Small Steps in Physics Simulation*. Symposium on Computer Animation (SCA), article 39, 2019.","url":"https://doi.org/10.1145/3309486.3340247"},{"id":"muller2007pbd","label":"Müller et al. 2007","citation":"Matthias Müller, Bruno Heidelberger, Marcus Hennix and John Ratcliff. *Position Based Dynamics*. Journal of Visual Communication and Image Representation 18(2), 109–118, 2007; first at VRIPHYS 2006.","url":"https://doi.org/10.1016/j.jvcir.2007.01.005"},{"id":"kim2012lra","label":"Kim, Chentanez and Müller-Fischer 2012","citation":"Tae-Yong Kim, Nuttapong Chentanez and Matthias Müller-Fischer. *Long Range Attachments: A Method to Simulate Inextensible Clothing in Computer Games*. Symposium on Computer Animation (SCA), 305–310, 2012.","url":"https://doi.org/10.2312/SCA/SCA12/305-310"},{"id":"keckeisen2004wind","label":"Keckeisen et al. 2004","citation":"Michael Keckeisen, Stefan Kimmerle, Bernhard Thomaszewski and Markus Wacker. *Modelling Effects of Wind Fields in Cloth Animations*. Journal of WSCG 12(1–3), 205–212, 2004.","url":"http://wscg.zcu.cz/wscg2004/Papers_2004_Full/C73.pdf"},{"id":"kotey2009screens","label":"Kotey, Wright and Collins 2009","citation":"Nathan A. Kotey, John L. Wright and Michael R. Collins. *Determining Off-Normal Solar Optical Properties of Insect Screens*. ASHRAE Transactions 115(1), 155–164, 2009.","url":"https://uwspace.uwaterloo.ca/handle/10012/11550"},{"id":"estevez2017sheen","label":"Estevez and Kulla 2017","citation":"Alejandro Conty Estevez and Christopher Kulla. *Production Friendly Microfacet Sheen BRDF*. Supplemental document to the talk Revisiting Physically Based Shading at Imageworks, SIGGRAPH 2017 course Physically Based Shading in Theory and Practice.","url":"https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_sheen.pdf"},{"id":"henyey1941","label":"Henyey and Greenstein 1941","citation":"L. G. Henyey and J. L. Greenstein. *Diffuse Radiation in the Galaxy*. Astrophysical Journal 93, 70–83, 1941.","url":"https://doi.org/10.1086/144246"},{"id":"zhu2023yarn","label":"Zhu et al. 2023","citation":"Junqiu Zhu, Zahra Montazeri, Jean-Marie Aubry, Ling-Qi Yan and Andrea Weidlich. *A Practical and Hierarchical Yarn-based Shading Model for Cloth*. Computer Graphics Forum 42(4), EGSR 2023.","url":"https://doi.org/10.1111/cgf.14894","venue":"EGSR 2023","year":2023},{"id":"wu2020repulsion","label":"Wu et al. 2020","citation":"Longhua Wu, Botao Wu, Yin Yang and Huamin Wang. *A Safe and Fast Repulsion Method for GPU-based Cloth Self Collisions*. ACM Transactions on Graphics 40(1), article 5, 2020.","url":"https://doi.org/10.1145/3430025","venue":"ACM TOG 40(1)","year":2020},{"id":"chen2024vbd","label":"Chen et al. 2024","citation":"Anka He Chen, Ziheng Liu, Yin Yang and Cem Yuksel. *Vertex Block Descent*. ACM Transactions on Graphics 43(4), article 116, SIGGRAPH 2024.","url":"https://doi.org/10.1145/3658179","venue":"SIGGRAPH 2024","year":2024},{"id":"fratarcangeli2016vivace","label":"Fratarcangeli, Tibaldo and Pellacini 2016","citation":"Marco Fratarcangeli, Valentina Tibaldo and Fabio Pellacini. *Vivace: A Practical Gauss-Seidel Method for Stable Soft Body Dynamics*. ACM Transactions on Graphics 35(6), article 214, SIGGRAPH Asia 2016.","url":"https://doi.org/10.1145/2980179.2982437"},{"id":"li2021cipc","label":"Li, Kaufman and Jiang 2021","citation":"Minchen Li, Danny M. Kaufman and Chenfanfu Jiang. *Codimensional Incremental Potential Contact*. ACM Transactions on Graphics 40(4), article 170, SIGGRAPH 2021.","url":"https://doi.org/10.1145/3450626.3459767","venue":"SIGGRAPH 2021","year":2021},{"id":"christensen2015profiles","label":"Christensen and Burley 2015","citation":"Per H. Christensen and Brent Burley. *Approximate Reflectance Profiles for Efficient Subsurface Scattering*. Pixar Technical Memo 15-04, 2015.","url":"https://research.pixar.com/docs/2015.TechnicalReport.CB.pdf"},{"id":"jimenez2015separable","label":"Jimenez et al. 2015","citation":"Jorge Jimenez, Károly Zsolnai, Adrian Jarabo, Christian Freude, Thomas Auzinger, Xian-Chun Wu, Javier von der Pahlen, Michael Wimmer and Diego Gutierrez. *Separable Subsurface Scattering*. Computer Graphics Forum 34(6), 188–197, 2015.","url":"https://doi.org/10.1111/cgf.12529"},{"id":"chen2014pdss","label":"Chen, Lambert and Penner 2014","citation":"Xi M. Chen, Timothy Lambert and Eric Penner. *Pre-Integrated Deferred Subsurface Scattering*. ACM SIGGRAPH 2014 Posters.","url":"https://doi.org/10.1145/2614217.2614248"},{"id":"xie2020sss","label":"Xie et al. 2020","citation":"Tiantian Xie, Marc Olano, Brian Karis and Krzysztof Narkowicz. *Real-time Subsurface Scattering with Single Pass Variance-guided Adaptive Importance Sampling*. Proceedings of the ACM on Computer Graphics and Interactive Techniques 3(1), 2020.","url":"https://doi.org/10.1145/3384536","venue":"Proceedings of the ACM on Computer Graphics and Interactive Techniques 3(1)","year":2020},{"id":"kajiya1989fur","label":"Kajiya and Kay 1989","citation":"James T. Kajiya and Timothy L. Kay. *Rendering Fur with Three Dimensional Textures*. Computer Graphics 23(3), 271–280, SIGGRAPH 1989.","url":"https://doi.org/10.1145/74334.74361"},{"id":"marschner2003hair","label":"Marschner et al. 2003","citation":"Stephen R. Marschner, Henrik Wann Jensen, Mike Cammarano, Steve Worley and Pat Hanrahan. *Light Scattering from Human Hair Fibers*. ACM Transactions on Graphics 22(3), 780–791, SIGGRAPH 2003.","url":"https://doi.org/10.1145/882262.882345"},{"id":"scheuermann2004hair","label":"Scheuermann 2004","citation":"Thorsten Scheuermann. *Practical Real-Time Hair Rendering and Shading*. ACM SIGGRAPH 2004 Sketches, 147.","url":"https://doi.org/10.1145/1186223.1186408"},{"id":"kaplanyan2016normals","label":"Kaplanyan et al. 2016","citation":"Anton S. Kaplanyan, Stephen Hill, Anjul Patney and Aaron Lefohn. *Filtering Distributions of Normals for Shading Antialiasing*. High Performance Graphics, 151–162, 2016.","url":"https://doi.org/10.2312/hpg.20161201"},{"id":"tokuyoshi2019gsaa","label":"Tokuyoshi and Kaplanyan 2019","citation":"Yusuke Tokuyoshi and Anton S. Kaplanyan. *Improved Geometric Specular Antialiasing*. ACM SIGGRAPH Symposium on Interactive 3D Graphics and Games (I3D), 2019.","url":"https://doi.org/10.1145/3306131.3317026"},{"id":"chiang2016hair","label":"Chiang et al. 2016","citation":"Matt Jen-Yuan Chiang, Benedikt Bitterli, Chuck Tappan and Brent Burley. *A Practical and Controllable Hair and Fur Model for Production Path Tracing*. Computer Graphics Forum 35(2), 275–283, 2016.","url":"https://doi.org/10.1111/cgf.12830","venue":"Computer Graphics Forum 35(2)","year":2016},{"id":"zinke2008dual","label":"Zinke et al. 2008","citation":"Arno Zinke, Cem Yuksel, Andreas Weber and John Keyser. *Dual Scattering Approximation for Fast Multiple Scattering in Hair*. ACM Transactions on Graphics 27(3), article 32, SIGGRAPH 2008.","url":"https://doi.org/10.1145/1360612.1360631","venue":"SIGGRAPH 2008","year":2008},{"id":"tolani2000ik","label":"Tolani, Goswami and Badler 2000","citation":"Deepak Tolani, Ambarish Goswami and Norman I. Badler. *Real-Time Inverse Kinematics Techniques for Anthropomorphic Limbs*. Graphical Models 62(5), 353–388, 2000.","url":"https://doi.org/10.1006/gmod.2000.0528"},{"id":"thomas1981illusion","label":"Thomas and Johnston 1981","citation":"Frank Thomas and Ollie Johnston. *Disney Animation: The Illusion of Life*. Abbeville Press, New York, 1981.","url":"https://openlibrary.org/isbn/0896592324"},{"id":"lasseter1987principles","label":"Lasseter 1987","citation":"John Lasseter. *Principles of Traditional Animation Applied to 3D Computer Animation*. Proceedings of SIGGRAPH 87, 35–44, 1987.","url":"https://doi.org/10.1145/37401.37407"},{"id":"lozanoperez1979visibility","label":"Lozano-Pérez and Wesley 1979","citation":"Tomás Lozano-Pérez and Michael A. Wesley. *An Algorithm for Planning Collision-Free Paths Among Polyhedral Obstacles*. Communications of the ACM 22(10), 560–570, 1979.","url":"https://doi.org/10.1145/359156.359164"},{"id":"aristidou2011fabrik","label":"Aristidou and Lasenby 2011","citation":"Andreas Aristidou and Joan Lasenby. *FABRIK: A fast, iterative solver for the Inverse Kinematics problem*. Graphical Models 73(5), 243–260, 2011.","url":"https://doi.org/10.1016/j.gmod.2011.05.003","venue":"Graphical Models","year":2011},{"id":"starke2020phases","label":"Starke et al. 2020","citation":"Sebastian Starke, Yiwei Zhao, Taku Komura and Kazi Zaman. *Local Motion Phases for Learning Multi-Contact Character Movements*. ACM Transactions on Graphics 39(4), article 54, SIGGRAPH 2020.","url":"https://doi.org/10.1145/3386569.3392450","venue":"SIGGRAPH 2020","year":2020},{"id":"peng2021amp","label":"Peng et al. 2021","citation":"Xue Bin Peng, Ze Ma, Pieter Abbeel, Sergey Levine and Angjoo Kanazawa. *AMP: Adversarial Motion Priors for Stylized Physics-Based Character Control*. ACM Transactions on Graphics 40(4), article 144, SIGGRAPH 2021.","url":"https://doi.org/10.1145/3450626.3459670","venue":"SIGGRAPH 2021","year":2021},{"id":"coros2011quadrupeds","label":"Coros et al. 2011","citation":"Stelian Coros, Andrej Karpathy, Ben Jones, Lionel Reveret and Michiel van de Panne. *Locomotion Skills for Simulated Quadrupeds*. ACM Transactions on Graphics 30(4), article 59, SIGGRAPH 2011.","url":"https://doi.org/10.1145/2010324.1964954","venue":"SIGGRAPH 2011","year":2011},{"id":"zhang2018mann","label":"Zhang et al. 2018","citation":"He Zhang, Sebastian Starke, Taku Komura and Jun Saito. *Mode-Adaptive Neural Networks for Quadruped Motion Control*. ACM Transactions on Graphics 37(4), article 145, SIGGRAPH 2018.","url":"https://doi.org/10.1145/3197517.3201366","venue":"SIGGRAPH 2018","year":2018},{"id":"ju2013flight","label":"Ju et al. 2013","citation":"Eunjung Ju, Jungdam Won, Jehee Lee, Byungkuk Choi, Junyong Noh and Min Gyu Choi. *Data-Driven Control of Flapping Flight*. ACM Transactions on Graphics 32(5), article 151, 2013, presented at SIGGRAPH 2014.","url":"https://doi.org/10.1145/2516971.2516976","venue":"ACM TOG 32(5), SIGGRAPH 2014","year":2013},{"id":"saito1990comprehensible","label":"Saito and Takahashi 1990","citation":"Takafumi Saito and Tokiichiro Takahashi. *Comprehensible Rendering of 3-D Shapes*. Computer Graphics 24(4), 197–206, SIGGRAPH 1990.","url":"https://doi.org/10.1145/97880.97901"},{"id":"decarlo2003suggestive","label":"DeCarlo et al. 2003","citation":"Doug DeCarlo, Adam Finkelstein, Szymon Rusinkiewicz and Anthony Santella. *Suggestive Contours for Conveying Shape*. ACM Transactions on Graphics 22(3), 848–855, SIGGRAPH 2003.","url":"https://doi.org/10.1145/882262.882354","venue":"SIGGRAPH 2003","year":2003},{"id":"yang2018ftpsc","label":"Yang et al. 2018","citation":"Wenwu Yang, Hock-Soon Seah, Quan Chen, Hong-Ze Liew and Daniel Sýkora. *FTP-SC: Fuzzy Topology Preserving Stroke Correspondence*. Computer Graphics Forum 37(8), 125–135, SCA 2018.","url":"https://doi.org/10.1111/cgf.13518","venue":"SCA 2018","year":2018},{"id":"benard2012active","label":"Bénard et al. 2012","citation":"Pierre Bénard, Jingwan Lu, Forrester Cole, Adam Finkelstein and Joëlle Thollot. *Active Strokes: Coherent Line Stylization for Animated 3D Models*. Symposium on Non-Photorealistic Animation and Rendering (NPAR), 37–46, 2012.","url":"https://doi.org/10.2312/PE/NPAR/NPAR12/037-046","venue":"NPAR 2012","year":2012},{"id":"cole2008lines","label":"Cole et al. 2008","citation":"Forrester Cole, Aleksey Golovinskiy, Alex Limpaecher, Heather Stoddart Barros, Adam Finkelstein, Thomas Funkhouser and Szymon Rusinkiewicz. *Where Do People Draw Lines?* ACM Transactions on Graphics 27(3), article 88, SIGGRAPH 2008.","url":"https://doi.org/10.1145/1360612.1360687","venue":"SIGGRAPH 2008","year":2008},{"id":"amanatides1987voxel","label":"Amanatides and Woo 1987","citation":"John Amanatides and Andrew Woo. *A Fast Voxel Traversal Algorithm for Ray Tracing*. Eurographics 1987 Technical Papers.","url":"https://doi.org/10.2312/egtp.19871000"},{"id":"epic-spring-arm","label":"Epic Games, spring arm","citation":"Epic Games. *Using Spring Arm Components in Unreal Engine*, Unreal Engine documentation.","url":"https://dev.epicgames.com/documentation/en-us/unreal-engine/using-spring-arm-components-in-unreal-engine"},{"id":"reed2015depth","label":"Reed 2015","citation":"Nathan Reed. *Depth Precision Visualized*, 2015.","url":"https://www.reedbeta.com/blog/depth-precision-visualized/"},{"id":"oskam2009visibility","label":"Oskam et al. 2009","citation":"Thomas Oskam, Robert W. Sumner, Nils Thuerey and Markus Gross. *Visibility Transition Planning for Dynamic Camera Control*. Symposium on Computer Animation (SCA), 55–65, 2009.","url":"https://doi.org/10.1145/1599470.1599478","venue":"SCA 2009","year":2009},{"id":"lino2015toric","label":"Lino and Christie 2015","citation":"Christophe Lino and Marc Christie. *Intuitive and Efficient Camera Control with the Toric Space*. ACM Transactions on Graphics, SIGGRAPH 2015.","url":"https://doi.org/10.1145/2766965","venue":"SIGGRAPH 2015","year":2015},{"id":"shewchuk-triangle","label":"Shewchuk's Triangle","citation":"Jonathan Richard Shewchuk. *Triangle: A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator*.","url":"https://www.cs.cmu.edu/~quake/triangle.html"},{"id":"z3lvs-torrey-badlands","label":"Z3lvs 2021, Torrey Pines badlands","citation":"Z3lvs. *Eroded sandstone badlands and sea cliffs looking south toward La Jolla, Torrey Pines State Natural Reserve*. Wikimedia Commons, 2021 (CC0).","url":"https://commons.wikimedia.org/wiki/File:Eroded_sandstone_badlands_and_sea_cliffs_looking_south_toward_La_Jolla,_Torrey_Pines_State_Natural_Reserve,_California.jpg"},{"id":"stch2022-torrey-sandstone","label":"Stch2022, Torrey Sandstone cliffs","citation":"Stch2022. *Overlooking the steep Torrey Sandstone cliffs of Torrey Pines State Natural Reserve and Black's Beach below*. Wikimedia Commons (CC0).","url":"https://commons.wikimedia.org/wiki/File:Overlooking_the_steep_Torrey_Sandstone_cliffs_of_Torrey_Pines_State_Natural_Resever_and_Black%27s_Beach_below.jpg"},{"id":"andrek02-sea-cave","label":"Andrek02 2022, La Jolla sea cave","citation":"Andrek02. *La Jolla 005 - sea cave*. Wikimedia Commons, 2022 (CC0).","url":"https://commons.wikimedia.org/wiki/File:La_Jolla_005_-_sea_cave.jpg"},{"id":"matejicek-goldfish-point","label":"JiriMatejicek 2019, Goldfish Point","citation":"JiriMatejicek. *San Diego La Jolla Goldfish Point*. Wikimedia Commons, 2019 (CC BY-SA 4.0).","url":"https://commons.wikimedia.org/wiki/File:San_Diego_La_Jolla_Goldfish_Point.jpg"},{"id":"ncysea-gliderport","label":"Ncysea 2020, Torrey Pines Gliderport","citation":"Ncysea. *Torrey Pines Gliderport 1*. Wikimedia Commons, 2020 (CC BY-SA 4.0).","url":"https://commons.wikimedia.org/wiki/File:Torrey_Pines_Gliderport_1.jpg"},{"id":"cordonnier2017landscapes","label":"Cordonnier et al. 2017","citation":"Guillaume Cordonnier, Eric Galin, James Gain, Bedrich Benes, Eric Guérin, Adrien Peytavie and Marie-Paule Cani. *Authoring Landscapes by Combining Ecosystem and Terrain Erosion Simulation*. ACM Transactions on Graphics 36(4), article 134, SIGGRAPH 2017.","url":"https://doi.org/10.1145/3072959.3073667","venue":"SIGGRAPH 2017","year":2017},{"id":"paris2019amplification","label":"Paris et al. 2019","citation":"Axel Paris, Eric Galin, Adrien Peytavie, Eric Guérin and James Gain. *Terrain Amplification with Implicit 3D Features*. ACM Transactions on Graphics 38(5), article 147, 2019.","url":"https://doi.org/10.1145/3342765","venue":"ACM TOG 38(5)","year":2019},{"id":"banked-turn","label":"the banked-turn relation","citation":"Wikipedia. *Banked turn*, on the bank angle of a coordinated turn.","url":"https://en.wikipedia.org/wiki/Banked_turn"}]}