Conversation
Ports the hero refinements from the DevNepalFront prototype into the portal's own hero, taking only the visual layer. - NepalMap: Nepal drawn as a feathered field of blueprint grid, from the same Natural Earth 50m boundary the globe uses for its land mask. Pure SVG, no dependencies, sits behind the hero at -z-10. - sectionPadding / sectionGutter in lib/layout.ts: one definition of the gutter and vertical rhythm the landing sections already share by hand. The hero was the only section on py-16 rather than py-12 lg:py-16; it now lines up with the rest. - The globe's lower bound follows the viewport (clamp on 80svh) instead of a fixed 26rem, so it fills tall screens without overflowing short ones. Deliberately not taken from the prototype: its hero copy (which frames the portal as multi-ministry) and its CONTRIBUTORS naming for the globe waypoints. Both were corrected on main and stay corrected.
The globe chose its horizontal position from the shape of its own box: wide box, sit right of centre and leave room for the copy on the left. Below `lg` the hero stacks, and the globe's box is `h-64 w-full` — short and wide — so the same rule pushed the sphere to the right edge of a column that has no copy beside it. Box shape cannot tell the two compositions apart, so the caller decides now: `GlobeScene.setAlignment`, driven by a media query on the same `lg` breakpoint at which the hero switches to two columns. Above it nothing changes. Also capitalizes the second line of the hero heading, which is a sentence of its own.
Three review findings. The globe's alignment setter ran the full resize(), which ends in renderer.setSize() and so clears the drawing buffer, but did not paint the frame that every other resize() call site pairs with it. Nothing was visibly wrong only because crossing `lg` also changes the canvas box, so the ResizeObserver repainted a moment later; with the hero scrolled out of view the frame loop is stopped and the canvas would have stayed blank. Camera framing is now its own step, applyViewOffset(), which touches no GPU buffer: an alignment change costs a projection matrix instead of a reallocated canvas, and it paints itself. NepalMap covered its box, so once the hero stacked and the box went narrow and tall, three quarters of the map's width was cropped and what remained was an unreadable band of grid rather than Nepal. It fits the box now. The hero heading's second line was capitalized last commit; the page title and description still carried the lower-case form.
rosanyonghang
force-pushed
the
feat/landing-hero
branch
2 times, most recently
from
September 21, 2026 17:22
282fde6 to
6cebfc6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the hero work from the
DevNepalFrontprototype into the portal. Bothrepos already run the same stack — Base UI 1.8, Phosphor,
cn, shadcn 4.21,three 0.178, Tailwind 4, Next 16, React 19 — so this is a graft, not a port:
no new dependencies.
First of a section-by-section pass over the landing page. Navbar and the
government masthead follow in their own PR.
What changed
NepalMap— Nepal drawn as a feathered field of blueprint grid, from thesame Natural Earth 50m boundary the globe already uses for its land mask.
Pure SVG, no dependencies, sits behind the hero at
-z-10.lib/layout.ts—sectionGutter/sectionPadding: one definition ofthe gutter and vertical rhythm the landing sections already shared by hand.
The hero was the only section on
py-16rather thanpy-12 lg:py-16; it nowlines up with
members-sectionandproject-spotlight-section.clampon80svh) instead of a fixed26rem, so it fills tall screens without overflowing short ones.shape of its own box — "wide box, sit right of centre, leave room for the copy
on the left". Below
lgthe hero stacks and that box ish-64 w-full, shortand wide, so the rule fired exactly where it shouldn't and pushed the sphere
to the right edge of a column with nothing beside it. Box shape cannot tell
the two compositions apart (the desktop box is landscape too), so the caller
decides:
GlobeScene.setAlignment, driven by a media query on the samelgbreakpoint at which the hero switches to two columns.
to match.
Deliberately not taken from the prototype
CONTRIBUTORSnaming for the globe waypoints.Both were corrected on
mainand stay corrected. The prototype'sui/button.tsxwas also skipped — this repo's version is a superset, with thenativeButton/renderprops the CTAs depend on.Review fixes included
A review pass found and this PR fixes:
setAlignmentcleared the WebGL drawing buffer without painting the framethat every other
resize()call site pairs with it. Masked in practicebecause crossing
lgalso changes the canvas box, so the ResizeObserverrepainted — but with the hero scrolled out of view the frame loop is stopped
and the canvas would have stayed blank. Camera framing is now its own step,
applyViewOffset(), which touches no GPU buffer: an alignment change costs aprojection matrix instead of a reallocated canvas, and it paints itself. Also
removes two of the three
resize()passes that ran during hero mount onmobile, and adds the
disposedguard its sibling methods already had.NepalMapcovered its box, so once the hero stacked, 76% of the map'swidth was cropped and what remained was an unreadable band of grid rather
than Nepal. Measured at a 357×852 box before the fix; it fits the box now.
One design call worth a second opinion
Switching the map from
slicetomeettrades coverage for legibility: thecountry is now whole at every width, but in the stacked layout it occupies a
band across ~28% of the hero's height rather than filling it. Correctness of the
shape won, since the component's whole premise is that this is Nepal — but if
you'd rather treat it as pure texture, it is one attribute to revert.
Known, deliberately left for later
sectionGutterhas one consumer; ten other call sites still hardcode the samegutter. Converting the rest belongs with the navbar/masthead PR, which touches
those files anyway.
calc(80svh - 15rem)encodes the combined height of the masthead,navbar and hero padding, with nothing linking them. A
--site-chromecustomproperty is the right fix; also parked for the chrome PR.
NepalMap's SVG ids are document-global. Harmless with one instance; needsuseId()before a second.Verification
bun run lint,typecheck,test(135 passing) andbuildall green.Rendered and measured at 375, 820 and 1440, plus a live
lgcrossing at1440→820 without a reload — the case the ResizeObserver was previously papering
over. Globe repaints centred, WebGL context alive.
🤖 Generated with Claude Code