game-views: horizontal direction-aware title reel + smooth card slide for lateral nav
The carousel's lateral nav animated wrong: the h2 reel slid VERTICALLY (old word down, new word up — both visible at once), and a first attempt that put translateX+translateY on one transform produced a DIAGONAL blend on hex->views (ROOM+ATLAS+SCROLL all flashing, always landing on ATLAS). Fix — split the two axes onto NESTED elements so they never blend: - OUTER .gr-views-reel does translateY ONLY, gated on .is-scroll (the hex<->views vertical reel, in lockstep with ROOM sliding up/out). - INNER .gr-views-track does translateX -idx*100% (VIEW_ORDER atlas|scroll|post|chat|pulse), gated on data-active-view ALONE — so the active view's cell sits in the slot at ALL times, including at the hex. Default (pre-JS/unset) = SCROLL. Result: hex<->views is a pure vertical reel that lands on whatever view you left off on (POST returns to POST, no diagonal); lateral nav is a pure horizontal slide — old word out one side, new in from the other, direction from the translateX sign — same rusty linear() sequence as ROOM<->SCROLL, just left-right. Cards: goToView now smooth-scrolls (scrollTo behavior:smooth) instead of jumping scrollLeft, so the five .applet-scroll panes visibly SLIDE; an IO-suppression flag during the programmatic snap keeps the icon glow + reel from jittering through passed-over views (native touch-drag still updates via the IO). Initial land uses an instant placeView (no slide on arrival). Verified: 8 carousel FTs + the GAME ROOM<->SCROLL vertical-reel FT green; a 3-lens adversarial audit (vertical axis / horizontal axis+clipping / repo-wide regression sweep) returned holds with no findings. [[project-room-game-views-carousel]] Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -350,13 +350,10 @@ body {
|
||||
#000 calc(100% - var(--gr-fade)), transparent 100%);
|
||||
}
|
||||
.gr-word {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-inline-start: 0.4em; // match > span:last-child word gap
|
||||
transition: transform var(--gr-dur, 0.55s) var(--gr-ease, ease);
|
||||
will-change: transform;
|
||||
|
||||
// 3-letter base word (e.g. my_sea's SEA) clusters like
|
||||
@@ -364,28 +361,62 @@ body {
|
||||
// the slot edges.
|
||||
&[data-letters="3"] { justify-content: space-around; }
|
||||
}
|
||||
// ROOM rests in view at the hex; every view word (SCROLL is
|
||||
// the default) parks one notch below in the bottom fade.
|
||||
.gr-word--base { transform: translateY(0); } // resting in view
|
||||
.gr-word--scroll,
|
||||
.gr-word--atlas,
|
||||
.gr-word--post,
|
||||
.gr-word--chat,
|
||||
.gr-word--pulse { transform: translateY(100%); } // parked below the slot
|
||||
// Scrolled to the views pane (room-scroll.js adds `.is-scroll`)
|
||||
// → ROOM slides up & out and the ACTIVE view's word rises in.
|
||||
// The active view is carried by `data-active-view` on the h2
|
||||
// (room-views.js, the horizontal carousel axis); before JS
|
||||
// sets it, SCROLL (the landing view) shows.
|
||||
&.is-scroll {
|
||||
.gr-word--base { transform: translateY(-100%); } // up & out the top
|
||||
&:not([data-active-view]) .gr-word--scroll,
|
||||
&[data-active-view="scroll"] .gr-word--scroll,
|
||||
&[data-active-view="atlas"] .gr-word--atlas,
|
||||
&[data-active-view="post"] .gr-word--post,
|
||||
&[data-active-view="chat"] .gr-word--chat,
|
||||
&[data-active-view="pulse"] .gr-word--pulse { transform: translateY(0); }
|
||||
// ROOM (base) — standalone overlay word on the VERTICAL reel
|
||||
// only (hex ⇄ views). Rests in view at the hex; slides up &
|
||||
// out under `.is-scroll`.
|
||||
.gr-word--base {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
transition: transform var(--gr-dur, 0.55s) var(--gr-ease, ease);
|
||||
transform: translateY(0);
|
||||
}
|
||||
// The five view words ride two NESTED elements so the axes
|
||||
// never blend into a diagonal. OUTER `.gr-views-reel` = the
|
||||
// VERTICAL axis ONLY (hex ⇄ views): parked below at the hex,
|
||||
// rises into the slot under `.is-scroll` — in lockstep with
|
||||
// ROOM sliding up & out. Same rusty reel as before.
|
||||
.gr-views-reel {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
transition: transform var(--gr-dur, 0.55s) var(--gr-ease, ease);
|
||||
transform: translateY(100%); // parked below at the hex
|
||||
will-change: transform;
|
||||
}
|
||||
// INNER `.gr-views-track` = the HORIZONTAL axis ONLY, keyed by
|
||||
// `data-active-view` (room-views.js) ALONE — NOT `.is-scroll`.
|
||||
// The active view's cell therefore sits in the slot at ALL
|
||||
// times, including at the hex, so scrolling hex⇄views moves
|
||||
// only the reel's translateY (a pure vertical reel that lands
|
||||
// on whatever view you left off on), while lateral nav moves
|
||||
// only this translateX (a pure horizontal slide — old word out
|
||||
// one side, new in from the other; direction = translateX
|
||||
// sign). Default (pre-JS / no attr) = SCROLL, the landing view.
|
||||
.gr-views-track {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
transition: transform var(--gr-dur, 0.55s) var(--gr-ease, ease);
|
||||
transform: translateX(-100%); // default = SCROLL (idx 1)
|
||||
will-change: transform;
|
||||
|
||||
.gr-word {
|
||||
flex: 0 0 100%; // each cell = one slot width
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
&.is-scroll {
|
||||
.gr-word--base { transform: translateY(-100%); } // up & out
|
||||
.gr-views-reel { transform: translateY(0); } // rises in
|
||||
}
|
||||
// Horizontal cell (VIEW_ORDER atlas|scroll|post|chat|pulse) —
|
||||
// keyed on the active view ALONE so it holds at the hex too.
|
||||
&[data-active-view="atlas"] .gr-views-track { transform: translateX(0); }
|
||||
&[data-active-view="scroll"] .gr-views-track { transform: translateX(-100%); }
|
||||
&[data-active-view="post"] .gr-views-track { transform: translateX(-200%); }
|
||||
&[data-active-view="chat"] .gr-views-track { transform: translateX(-300%); }
|
||||
&[data-active-view="pulse"] .gr-views-track { transform: translateX(-400%); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user