Fix TV artwork, episode layout and focus visibility
This commit is contained in:
parent
34087d8eb5
commit
9d2471c5b1
28 changed files with 466 additions and 117 deletions
61
data/tv-spec/spec.md
Normal file
61
data/tv-spec/spec.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Wolfskin TV specification — revision 5
|
||||
|
||||
2026-11-06. This feedback amendment applies to the approved revision-4 specification and frozen frames at `data/tv-v2/focus-2026-11-06/` (prototype SHA-256 `1bb7f4097a5303a58e45ec5e61cf867fa6cfdcbfe12fc7a196f00acacae5e48d`). Unchanged geometry, navigation, typography, colours and motion remain governed by those frames and the [written specification](https://pages.justinvisser.org/wolfskin/tv-spec). The amendment's prototype delta is `data/tv-v2/feedback-2026-11-06/`.
|
||||
|
||||
## Who’s watching
|
||||
|
||||
The Settings gear is horizontally centred beneath the complete people row, independent of person count or selection. Justin confirmed this placement. It uses the same 4 px accent straddle ring as the people, with the existing 1.08 scale and focus-only Settings caption. Down still reaches it only from the final person; Up returns to that person.
|
||||
|
||||
## Focus visibility
|
||||
|
||||
“Centered” means consistent visibility, not geometric centering. Keep the approved shelf rule: one-card lookahead, shifting after the second-last visible slot, with first/last positions clamped to the actual contents. Short rows do not manufacture empty scroll space. Poster, tile, wide, service, episode, cast and related shelves follow the same rule.
|
||||
|
||||
The focused card and its ring remain fully inside the viewport, with at least the Level 2 gap (40 px) of horizontal clearance at each screen edge. Focused rows clear the nav band and the bottom edge. Preserve the approved 168 px heading pin and initial fully-visible-row exceptions; hero/header anchors remain zero. First entry, row changes, row ends and Back from a title must reconcile retained logical selection with the actual scroll position. A frame is recorded as positioned only after its scroll finishes. Discover uses the approved six poster slots, not a rounded-down five-slot approximation.
|
||||
|
||||
Library and Person grids retain six columns and the existing Level 2 row spacing. The final Person column keeps the full poster width; horizontal padding must not shrink it.
|
||||
|
||||
## Episode artwork and dimensions
|
||||
|
||||
Episode cards use **400×280 px (200×140 dp)** art: 55 px / 24.4% taller than the previous 400×225 px tile. Other tile and wide-card sizes are unchanged. The episode shelf is `84 + 280 + 68 = 432 px`; its heading band and 68 px clearance before Cast remain Level 2. Cast moves down by the additional card height rather than overlapping it.
|
||||
|
||||
Choose available art in this order:
|
||||
|
||||
1. Episode `Primary` image — Jellyfin stores episode stills under this type.
|
||||
2. Episode `Thumb` image.
|
||||
3. Series `Backdrop`, centre-cropped to the episode slot.
|
||||
4. The existing missing-art treatment when none is available.
|
||||
|
||||
A series-page read supplies its already-read backdrop to the episode projection; it does not make one series request per episode. Saved pages rebuild the same projection from cached metadata. Thumbnail reads and prefetch use the 400×280 px episode request, not the unrelated poster dimensions.
|
||||
|
||||
Read-only Jellyfin evidence: all ten The Bear season-three episodes have Primary tags and no episode Backdrop tags. Tomorrow’s Primary source is 2100×1182; the series Backdrop is 3840×2160. These are existing aired files, not missing/unaired episode placeholders.
|
||||
|
||||
## Episode summaries and series header spacing
|
||||
|
||||
In episode context, the summary belongs to the episode: focused episode first, explicitly opened episode next, otherwise the Up-next episode. Use the show overview only when no episode context is selected. An absent episode overview stays absent instead of substituting the show's description. The focused episode card can show two ellipsised lines of its own overview below its episode label.
|
||||
|
||||
A held series header measures its actual copy, actions and action-caption band, then leaves **40 px** before the Seasons row. Remove the unconditional 900 px series-header spacer. Films, non-held titles and loading/error layouts retain their approved fixed header geometry. Measured series geometry also drives the frame offsets and focus-follow calculation, preventing season/episode rows from scrolling to stale offsets. Long titles or summaries may grow the header; controls must never overlap the seasons.
|
||||
|
||||
## Hero image quality and memory
|
||||
|
||||
| Surface | Requested/decode bound | Format policy |
|
||||
|---|---|---|
|
||||
| Home and Discover hero; title backdrop | 1920×1080 | ARGB, 7.91 MiB at the bound |
|
||||
| Upright hero poster | 420×630 | RGB565 where supported, 0.50 MiB |
|
||||
| Episode card | 400×280 | ARGB, 0.43 MiB |
|
||||
| Library poster, ordinary tile/wide, cast | Existing slot dimensions | Existing RGB565/ARGB policy |
|
||||
|
||||
Jellyfin image URLs discard conflicting width/height/max/fill caps and request the consuming slot while preserving image tags, quality and other query parameters. Jellyfin quality remains **96**. TMDB heroes use the original source rather than the previous 780 px source; Coil constrains decoding to the panel. Upright TMDB sheets use a suitable poster tier. Intentionally blurred poster-only washes remain bounded to the upright source, not an oversized portrait bitmap. Decode fitting prevents allocation of an oversized off-ratio source merely to fill a crop.
|
||||
|
||||
The shared memory cache remains **64 MiB**, disk cache **128 MiB**, image concurrency **4**. Three 1080p hero bitmaps consume 23.73 MiB, leaving 40.27 MiB of the cache for other art. These are allocation bounds, not measured TV resident-memory claims; do not request or decode 4K hero bitmaps on the 2 GB armv7 box.
|
||||
|
||||
Read-only source measurement: Desperate Housewives has a 2732×1536 Backdrop. With quality 96, Jellyfin returned a 1281×720 JPEG of 438,329 bytes for the old fill request and a 1921×1080 JPEG of 982,435 bytes for the new request; the extra source pixel is Jellyfin aspect-ratio rounding. The display decode stays bounded to 1920×1080.
|
||||
|
||||
## Discover lane spacing
|
||||
|
||||
Every Discover lane, including Movies for you, Series for you, service entries, service-specific lanes and Hidden picks, uses a **104 px heading band**: heading line plus **60 px heading-to-card gap**, up from 40 px. This is a consistent Level 2 extension, not a Series-only exception. Poster shelves become 652 px high and service-entry shelves 316 px. Captions and frame scroll offsets use the same heading band. Home headings remain unchanged.
|
||||
|
||||
## Sources and verification
|
||||
|
||||
Authoritative changed values live in `wolfskin-design/tokens.json`, `title-tokens.json` and `discover-tokens.json`; regenerate Kotlin, CSS and the drift manifest with `python3 wolfskin-design/generate_tokens.py`.
|
||||
|
||||
The feedback prototype delta links the native 1920×1080 before/after frames. `HomeViewportTest` exercises short and long poster/tile/wide rows, first focus, both row directions and native Back from the shipped title surface. The real-Bear capture harness reads recorded Jellyfin metadata through `TitleReadFacade`; it is a throwaway proof and is not shipped. The final gates are `make test` and `make apk-debug`. No TV access or optimized-APK build is part of this worker's validation.
|
||||
50
data/tv-v2/feedback-2026-11-06/delta.json
Normal file
50
data/tv-v2/feedback-2026-11-06/delta.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"specRevision": 5,
|
||||
"base": "data/tv-v2/focus-2026-11-06/index.html",
|
||||
"baseSha256": "1bb7f4097a5303a58e45ec5e61cf867fa6cfdcbfe12fc7a196f00acacae5e48d",
|
||||
"stagePx": [1920, 1080],
|
||||
"density": 2,
|
||||
"picker": {
|
||||
"gearAlignment": "center of the complete people row",
|
||||
"gearRing": "same accent straddle ring as picker people",
|
||||
"gearFocusScale": 1.08,
|
||||
"navigation": "unchanged: Down from the final person only"
|
||||
},
|
||||
"focus": {
|
||||
"horizontalRule": "second-last-slot lookahead; clamp first/last to real contents",
|
||||
"minimumScreenSideMarginPx": 40,
|
||||
"headingPinPx": 168,
|
||||
"geometricCentering": false,
|
||||
"discoverPosterSlots": 6
|
||||
},
|
||||
"episode": {
|
||||
"artPx": [400, 280],
|
||||
"shelfHeightPx": 432,
|
||||
"gapBeforeCastPx": 68,
|
||||
"artFallback": ["episode Primary", "episode Thumb", "series Backdrop crop", "missing art"],
|
||||
"summaryContext": ["focused episode", "explicitly opened episode", "up-next episode", "show when no episode context"],
|
||||
"focusedCardSummaryLines": 2
|
||||
},
|
||||
"seriesHeader": {
|
||||
"height": "measured copy, actions and caption band plus gap",
|
||||
"gapBeforeSeasonsPx": 40,
|
||||
"otherTitleHeaders": "unchanged"
|
||||
},
|
||||
"discover": {
|
||||
"allLaneHeadingBandPx": 104,
|
||||
"allLaneHeadingToCardGapPx": 60,
|
||||
"posterShelfHeightPx": 652,
|
||||
"serviceShelfHeightPx": 316,
|
||||
"homeHeadingBand": "unchanged"
|
||||
},
|
||||
"images": {
|
||||
"heroDecodeBoundPx": [1920, 1080],
|
||||
"heroPosterDecodeBoundPx": [420, 630],
|
||||
"jellyfinQuality": 96,
|
||||
"memoryCacheMiB": 64,
|
||||
"diskCacheMiB": 128,
|
||||
"concurrentReads": 4
|
||||
},
|
||||
"nativeFrames": "https://pages.justinvisser.org/wolfskin/tv-fb1-visual/",
|
||||
"specification": "../../tv-spec/spec.md"
|
||||
}
|
||||
36
data/tv-v2/feedback-2026-11-06/index.html
Normal file
36
data/tv-v2/feedback-2026-11-06/index.html
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Wolfskin TV · feedback delta · revision 5</title>
|
||||
<style>
|
||||
:root { color-scheme: dark; font: 16px/1.5 system-ui, sans-serif; }
|
||||
body { max-width: 1440px; margin: 32px auto; padding: 0 24px; background: #07070a; color: #f4f4f6; }
|
||||
a { color: #cfb0f6; } nav { display: flex; flex-wrap: wrap; gap: 24px; }
|
||||
section { margin: 48px 0; } h2 { margin-bottom: 8px; }
|
||||
img { display: block; width: 100%; height: auto; margin: 16px 0; border: 1px solid #33333b; }
|
||||
summary { cursor: pointer; } .note { color: #b9b9c1; }
|
||||
</style>
|
||||
<h1>Wolfskin TV · feedback delta</h1>
|
||||
<p>Specification revision 5. The approved frames remain the baseline; these native 1920×1080 frames show only the requested feedback changes. This is a frame prototype, not a simulated Jellyfin client.</p>
|
||||
<nav><a href="#picker">Who’s watching</a><a href="#home">Home</a><a href="#discover">Discover</a><a href="#series">Series</a><a href="#episodes">Episodes</a><a href="#person">Person</a><a href="delta.json">Exact delta values</a></nav>
|
||||
<section id="picker"><h2>Who’s watching</h2><p>Gear centred beneath everyone, with the person-style focus ring.</p>
|
||||
<img width="1920" height="1080" alt="Native picker after: Settings centred below the complete people row" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/picker.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native picker before: gear below the final person" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/picker.png"></details></section>
|
||||
<section id="home"><h2>Home</h2><p>Approved edge scrolling retained. Short/long poster, tile and wide rows, row changes and native title Back exercise the same visibility contract.</p>
|
||||
<img loading="lazy" width="1920" height="1080" alt="Native Home after: focused card safely inside a long shelf" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/home.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native Home baseline" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/home.png"></details>
|
||||
<details><summary>Real-source hero request comparison</summary><p class="note">Same native renderer and source artwork: old 720p response, then panel-sized response. Intentionally blurred poster washes are unchanged.</p><img loading="lazy" width="1920" height="1080" alt="Native hero using the old 720p source response" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/home-hero.png"><img loading="lazy" width="1920" height="1080" alt="Native hero using the panel-resolution source response" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/home-hero.png"></details></section>
|
||||
<section id="discover"><h2>Discover</h2><p>60 px from lane title to cards; all lanes use the same 104 px heading band.</p>
|
||||
<img loading="lazy" width="1920" height="1080" alt="Native Discover after: more space above every lane's cards" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/discover.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native Discover before: smaller heading gap" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/discover.png"></details></section>
|
||||
<section id="series"><h2>Series header</h2><p>Episode-context summary and a measured header instead of the empty fixed-height spacer. Season chips and thumbnail artwork enter the initial view.</p>
|
||||
<img loading="lazy" width="1920" height="1080" alt="Native Bear series header after: episode overview and visible thumbnail row" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/series.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native Bear series header before: show overview and empty space before seasons" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/series.png"></details></section>
|
||||
<section id="episodes"><h2>Episode shelf</h2><p>Real episode Primary artwork, 400×280 px cards and the focused episode's own overview. Cast retains its Level 2 clearance.</p>
|
||||
<img loading="lazy" width="1920" height="1080" alt="Native Bear episodes after: taller thumbnail cards, focused overview and Cast below" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/episodes.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native Bear episodes before: monitor placeholders" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/episodes.png"></details></section>
|
||||
<section id="person"><h2>Person</h2><p>Six full-width poster columns; no shrinking of the final column.</p>
|
||||
<img loading="lazy" width="1920" height="1080" alt="Native Person after" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/after/person.png">
|
||||
<details><summary>Before</summary><img loading="lazy" width="1920" height="1080" alt="Native Person before" src="https://pages.justinvisser.org/wolfskin/tv-fb1-visual/before/person.png"></details></section>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue