Prajwalit
Local preview
python3 -m http.server 8081 --bind 127.0.0.1
Open http://localhost:8081
Static GitHub Pages site; no build step.
Scroll, or use “Start the journey”, to fly across an imagined mountain lake.
Five chapters: introduction, current work, career background, journeys, and the summit.
The terrain is intentionally sculptural, with coral sunset light, cool mountain
silhouettes, reflective water, and a continuous camera route toward a summit.
The camera climbs to the central summit, then turns continuously at one revolution
every 90 seconds. The panorama can be paused and resumed.
No photographs, satellite imagery, or Trolltunga reconstruction appear in the
landscape; the only photograph on the site is the portrait in the about dialog.
Implementation
scripts/journey.js — deterministic procedural terrain, sky shader,
planar-reflection water, scroll camera, chapter fades, and dialogs.
styles/journey.css — desktop/mobile layout with fixed chapter panels.
scripts/vegetation.js — instanced conifers and grass, with slope/height limits
and roots sampled from the rendered terrain triangles. Meadow color fades
into exposed rock higher up; trees become smaller and sparser at the treeline.
scripts/pointer.js — the shared release-gesture and dismiss-on-outside-press
helpers used by the overlays and every dialog.
scripts/seeded-random.js — the one deterministic hash behind procedural
placement, so a seed gives the same detail in every module.
assets/water-normal.jpg — water normal map from the Three.js examples.
assets/vendor — locally vendored Three.js 0.170.0 and Water; MIT license.
Water includes a local extension for multisampled, mipmapped reflections
and viewport-aware render-target sizing (long edge capped at 1536).
Subpixel ripples fade with screen-space footprint; the 10-unit camera
near plane improves distant shoreline depth precision.
Typography — Google Fonts: Italiana and DM Sans.
Accessibility and fallbacks
Reduced-motion preferences disable ambient animation and camera smoothing.
Inactive panels are inert and hidden. Dialogs use native modal focus handling
and share one dismissal gesture: a press that both starts and ends outside the
panel. Dragging a dial, preview or control past the edge never closes it.
Manual scrolling, touch, or key input stops automatic playback.
If WebGL cannot initialize, the text becomes a normal readable page.
Current scope
One continuous landscape journey from lake level to a summit panorama.
The summit is derived from the actual central terrain vertices. The camera
uses terrain clearance during ascent and settles above the peak, holding a
level gaze so the horizon rests on the centre line throughout the turn.
Reduced-motion mode starts the panorama paused. Scrolling away from the
summit stops the turn; dialogs and background tabs also pause its clock.
At the summit, horizontal trackpad scrolling (or Shift + mouse wheel) pans
the view and pauses the automatic turn. Resume panorama continues from that
heading. Vertical scrolling still moves back down the journey.
Background music
Silent Trail is the only soundtrack. The 108-second, volume-reduced AAC clip
loops in the background and attempts to play on page load. Browsers that block
autoplay show a start control. Mute preference is saved in local storage.
Maintenance and SEO
Content and metadata are delivered in index.html without JavaScript.
The default readable layout also handles unavailable JavaScript or WebGL.
A canonical URL, description, Open Graph/Twitter metadata, and ProfilePage
structured data identify the public site at https://prajwalit.com/.
images/social-preview.jpg supplies the landscape preview for shared links.
images/profile-pic.png introduces the about dialog; it is lazy, so visitors
who never open the dialog never download it. The legacy social icons and the
retained Trolltunga photo have been removed; both remain in git history.
robots.txt advertises sitemap.xml; update both if the production domain changes.
Keep the local Three.js license and Water customizations when updating the vendor.
Validation
Requires Node.js 20 or newer; no npm install or build step is needed.
npm test
npm run check
The dependency-free Node tests cover panorama continuity, journey controls,
reduced motion, panning, audio/storage behavior, WebGL fallback, refresh reset,
metadata, sitemap consistency, and local asset/anchor references.
Browser boundaries are mocked; these tests do not validate GPU rendering,
browser autoplay policy, CSS layout, or actual search-engine indexing.
git diff --check
Preview the five chapters, sound controls, dialog, and summit pan.
Also check with JavaScript disabled and at a narrow viewport.
Screen wake lock
Automatic travel requests a screen wake lock on supporting secure browsers.
Pause, manual navigation, hidden tabs, and summit arrival release it. Returning
to the tab reacquires it only if automatic travel is still active. The summit
panorama does not keep the display awake. Unsupported browsers, battery-saving
denials, and OS revocation are handled quietly without a repeated retry loop.
Unit tests mock the browser API; verify actual dimming behaviour on a phone.
Optional exploration (experiment)
At the summit, Explore freely opens a bounded free-flight camera. Drag to look;
WASD/arrows move relative to the view, E/Q rise/descend. The on-screen joystick
and +/- controls work with pointer/touch input. Escape or Return to summit
restores the guided departure pose in 1.8 seconds (instant with reduced motion).
Terrain clearance samples rendered triangles; altitude and horizontal bounds
keep the camera above the lake and inside the scenery. Inputs clear on blur,
hidden tabs, pointer cancellation, and dialogs. The guided journey stays at
the departure point while exploring; returning leaves automatic motion paused.
No wake lock is held in free exploration. Music preference is preserved.
Exploration bounds: x ±7,800; z -13,500 to +4,200; altitude cap 3,300.
The extended terrain grid preserves the original spacing and vertex alignment,
with clearance sampled from the same visible mesh throughout the larger area.
Landscape discoveries
A cairn sits on a western ridge. Wildflowers grow on the opening lakeshore
near x 576 / z 984, about 15 units above the water, close to the early route.
Seven distant birds cross the visible sky every two minutes; a shooting star appears
first becomes due at 20 active seconds, then 20 seconds after each launch.
A varied path is chosen in the current camera view, above the terrain. If
sky is obscured, launch waits without accumulating a backlog. Once launched,
the world-space path stays fixed for its 1.15-second duration. The flock first becomes due at 120 seconds and crosses for 18 seconds,
fading in and out. It waits for clear sky, then keeps its chosen world-space
route even if the camera turns. Subsequent launches are 120 seconds apart.
Birds roost once the sun is a couple of degrees below the horizon. Darkness
defers a pass the way an obscured sky does, so a single flock crosses after
sunrise rather than a night's worth arriving together; a flock overtaken by
nightfall fades out with the light. Hidden tabs stop the clock.
Ground discoveries use actual terrain samples and distance culling. These
details total about 31,300 instanced triangles across the map. Additional
wildflower patches share two tiny geometry buffers and are culled beyond
280 units; their centres are more than 600 units apart, so at most one added
patch renders at a time (two draw calls);
reflections may draw them again. No added lights or shadow casters.
Reduced motion hides birds and shooting stars.
The compass beside the location label opens free exploration from any point,
including the beginning. Return to journey restores the point of departure;
summit entry still returns to the summit. Sound follows the saved preference.
Wildflowers
Small cream and dusty pink cups, basal leaves and varied stem heights are
planted against the actual terrain. The static patch is culled beyond 400
units and adds no image download. The tree, sailboat and reindeer trials have
been removed.
Fifteen additional wildflower patches grow on meadow-compatible lower slopes
and lake banks, between elevations 25 and 650. Each uses 30–54 flowers with
varied orientation, height and cluster size. Roots follow actual terrain.
The original opening patch remains in place, for sixteen locations total.
Day and night cycle
A 48-minute cycle begins at the existing sunset, passes through moonlit night
with stars and a soft Milky Way band, then sunrise and daylight, before
returning to sunset. It pauses while the tab is hidden. Reduced motion keeps
the opening sky until a visitor changes it. DAY_CYCLE_DURATION lives in scripts/sunset.js.
Celestial detail uses the existing sky shader and water reflection. The one
shadowed directional light alternates between sun and moon; no extra lights,
textures or rendering passes are added. Ambient light keeps night navigable.
Stars and the Milky Way rotate together around a tilted celestial axis, once
per 48-minute cycle. Atmospheric clouds and the horizon remain independent.
The galaxy has variable width, an asymmetric core and fragmented dust lanes.
Time controls in Explore freely
The moon icon beside Save a view opens a time slider and pause/resume control.
Selecting a time smoothly changes the light and holds it until Resume cycle.
Sunset lasts the first eight minutes of the 48-minute loop. Camera and music
controls remain independent; reduced motion starts the sky clock paused.
Sun and moon motion uses continuous positive tangents across phases and the loop seam.