mirror of
https://github.com/project-dorado/dorado-hd.git
synced 2026-10-12 02:21:19 +00:00
docs(parity): on-device parity audit vs Zune HD disassembly + gap register; correct kinetic provenance
This commit is contained in:
@@ -147,7 +147,9 @@ The full firmware reverse-engineering corpus (109 reconstructed ARM32 PE modules
|
||||
`scripts/ghidra_corpus.py` into the out-of-tree `zune-hd-disassembly/`. Synthesized
|
||||
analysis lives in [`docs/zune-hd-module-inventory.md`](docs/zune-hd-module-inventory.md),
|
||||
[`docs/zune-hd-api-reference.md`](docs/zune-hd-api-reference.md) and
|
||||
[`docs/zune-hd-assets.md`](docs/zune-hd-assets.md).
|
||||
[`docs/zune-hd-assets.md`](docs/zune-hd-assets.md). The on-device parity audit is
|
||||
[`docs/zune-hd-parity-audit.md`](docs/zune-hd-parity-audit.md) (machine-readable
|
||||
register: [`docs/zune-hd-parity-gaps.json`](docs/zune-hd-parity-gaps.json)).
|
||||
|
||||
### Tests
|
||||
|
||||
|
||||
@@ -20,13 +20,17 @@ object DoradoMotion {
|
||||
const val STAGGER_MS = 20L
|
||||
|
||||
/**
|
||||
* Kinetic scroller velocity retention per 60 Hz frame. This is
|
||||
* `XuiTouchSettings[0x1C]` as the Zune HD shell applied it
|
||||
* (`gemstone.exe` VA `0x1C900`–`0x1CB64`; the XUI default is 0.7, the
|
||||
* shell raised it to 0.95 for the device's long glide).
|
||||
* See docs/zune-hd-touch-settings.md §2–3.
|
||||
* Kinetic scroller velocity retention per frame — an **empirical
|
||||
* approximation**, not a device constant. The Zune HD integrator
|
||||
* (`xuidll.dll@0x41841D58`) is a dt-scaled glide (`pos += (dt_ms/1000)·v`,
|
||||
* with dt floored at 33.333 ms) that updates `v' = v·(1 + c[+0xB0])` clamped
|
||||
* to `±(step·c[+0xB4])` and ticks at 16 ms (62.5 Hz). It reads the element's
|
||||
* touch-settings fields `[0x08]/[0x0C]` — **not** `[0x1C]`.
|
||||
* See docs/zune-hd-touch-settings.md §6 and docs/zune-hd-parity-audit.md §3.
|
||||
*/
|
||||
const val KINETIC_FRAME_RETENTION = 0.95f
|
||||
|
||||
/** Device tick is 62.5 Hz (`FUN_41848B98`, 16 ms); 60 Hz is the closest frame rate. */
|
||||
const val KINETIC_FRAME_HZ = 60f
|
||||
|
||||
/**
|
||||
|
||||
@@ -235,6 +235,11 @@ referencing `dorado/src/Dorado.Application`); re-run it after any desktop
|
||||
1. **M10 closeout** (S–M) — richer lock-screen Now Playing art/controls + optional sleep timer.
|
||||
2. **M5/M6 community wishlist** (M) — share-sheet + Zune-Card artwork export, EQ presets, crossfade, live-radio cache.
|
||||
3. **Corpus mining** (M) — the full 109-module corpus is built (66.6k functions, symbols applied); mine the decompilation/strings for behavioral ground truth to tighten the canon.
|
||||
4. **Parity-audit follow-ups** (see [`zune-hd-parity-audit.md`](zune-hd-parity-audit.md) + [`zune-hd-parity-gaps.json`](zune-hd-parity-gaps.json)) — queue surface, picture pinch-zoom, Now Playing scrubber, library-search UI, HUD dimmer/status OSD, built-in playlists, inbox/user-card, PIN/Wi-Fi settings, string-parity pass, font-import decision.
|
||||
|
||||
The audit also re-derives the kinetic model: the device glide is dt-scaled
|
||||
(62.5 Hz, 30 fps floor) and the `0.95` retention is an empirical approximation
|
||||
(canon §6; `zune-hd-touch-settings.md` §6).
|
||||
|
||||
Front-loads the remaining always-on surfaces, then the community wishlist and
|
||||
disassembly-driven fidelity work.
|
||||
|
||||
@@ -175,7 +175,8 @@ Raw decompiled C, symbol dumps and string dumps are Microsoft-derived and stay i
|
||||
the external corpus; the repository keeps only synthesized metadata
|
||||
([`zune-hd-module-inventory.md`](zune-hd-module-inventory.md),
|
||||
[`zune-hd-api-reference.md`](zune-hd-api-reference.md),
|
||||
[`zune-hd-assets.md`](zune-hd-assets.md)).
|
||||
[`zune-hd-assets.md`](zune-hd-assets.md)), plus the on-device parity audit
|
||||
([`zune-hd-parity-audit.md`](zune-hd-parity-audit.md)).
|
||||
|
||||
### Output Directory Structure (`zune-hd-disassembly/`)
|
||||
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
# Zune HD on-device parity audit — Dorado-HD vs firmware disassembly
|
||||
|
||||
**Date:** 2026-09-10
|
||||
**Method:** systematic comparison of the reconstructed Zune HD firmware corpus
|
||||
(`zune-hd-disassembly/` — 109 ARM32 PE modules, 66,598 functions, 4,169 named
|
||||
exports, 22,479 strings) against the Dorado-HD Android app source.
|
||||
**Scope:** *on-device* parity — every behavior the Zune HD itself had. Dorado-HD's
|
||||
additions beyond the device (scrobble, lyrics, DSP, Dynamic Mix, cloud, LAN sync,
|
||||
Now Playing widget) are **not** scored here; they are post-device extensions
|
||||
(canon §10).
|
||||
|
||||
**Provenance.** Device evidence is cited as `module.dll@<VA>` (virtual address in
|
||||
the reconstructed PE) or as a recovered string. HD evidence is `path:line`. Raw
|
||||
decompiled C, symbol dumps and strings stay in the external corpus and are never
|
||||
committed; this document is synthesized analysis only.
|
||||
|
||||
**Companion:** [`zune-hd-parity-gaps.json`](zune-hd-parity-gaps.json) is the
|
||||
machine-readable gap register.
|
||||
|
||||
---
|
||||
|
||||
## 1. On-device parity scorecard
|
||||
|
||||
| Domain | On-device parity | Notes |
|
||||
|---|---:|---|
|
||||
| A. Shell & navigation | **~78%** | Core surfaces match; a set of device scenes is absent (audiobooks, share, queue, inbox…). |
|
||||
| B. Now Playing & transport | **~75%** | Music/video/radio work; no scrubber, queue list, or picture NP. |
|
||||
| C. Motion & kinetics | **~60%** | Shape matches; the integrator mathematics diverges (see §4). |
|
||||
| D. HUD / always-on | **~45%** | Transport overlay + shade; no dimmer/power-off, PIN lock, status OSD. |
|
||||
| E. Library & indexing | **~80%** | Pivots + A–Z rail; no search UI, no built-in playlists, no letter/grid thresholds. |
|
||||
| F. Playback engine | **~70%** | Playback/shuffle/repeat/hearts; no EQ, queue engine, RDS, WMA/DRM. |
|
||||
| G. Marketplace & commerce | **~30%** | Frozen 62-entry catalog; no client/search/cart. |
|
||||
| H. Social / inbox / identity | **~30%** | Feed mock; no inbox, user card, Passport. |
|
||||
| I. Settings & device | **~70%** | Most pages; no PIN/screen-lock, Wi-Fi info, TV-out. |
|
||||
| J. Tokens / fonts / strings | **~70%** | Palette/scale canon-derived; label vocabulary diverges. |
|
||||
|
||||
**Weighted on-device parity: ~68%.** (The device is 2009 hardware; several device
|
||||
subsystems — marketplace, DRM, Passport, MTPZ, TV-out, telemetry — are
|
||||
deliberately out of scope; see §12.)
|
||||
|
||||
---
|
||||
|
||||
## 2. Shell & navigation (gemstone.exe — 74 `Gem*Scene` identifiers)
|
||||
|
||||
Full device scene list recovered from `gemstone.exe.strings.json`. Status:
|
||||
✅ parity · 🟡 partial · ❌ missing · N/A out of scope.
|
||||
|
||||
| Device scene | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| `GemStartScene` / `GemStartListScene` | `ui/screens/HomeScreens.kt:68,111` | ✅ |
|
||||
| `GemTiltScene` (Quickplay) | `ui/screens/HomeScreens.kt:147` | ✅ |
|
||||
| `GemPivotScene` | `design/components/CrossbarBar.kt` | ✅ |
|
||||
| `GemOverlayScene` | `ui/screens/NowPlayingScreen.kt:477` | ✅ |
|
||||
| `GemSyncScene` | `ui/screens/DeviceScreen.kt` | ✅ |
|
||||
| `GemLibrarySongScene` / `LibraryListScene` | `ui/screens/MusicScreen.kt:257` | ✅ |
|
||||
| `GemLibraryArtistScene` (+About/Related) | `ui/screens/DetailScreens.kt:169,225,320` | ✅ |
|
||||
| `GemLibraryPodcastScene` / Video | `ui/screens/Podcasts.kt:142`; `MediaScreens.kt:76` | ✅ |
|
||||
| `GemLibraryLetterPickerScene` | `design/components/KineticList.kt:106` | ✅ |
|
||||
| `GemNowPlayingRadioPresetListScene` | `ui/screens/Radio.kt:110` | ✅ |
|
||||
| `GemMarketplaceScene` / Games | `ui/screens/MarketplaceScreens.kt:56,205` | ✅ |
|
||||
| `GemSettingScene` / About | `ui/screens/SettingsScreen.kt:43,254` | ✅ |
|
||||
| `GemStartGridScene` | — (list only) | ❌ |
|
||||
| `GemStartExtrasScene` | Marketplace apps/games pivots | 🟡 |
|
||||
| `GemQueueListScene` / `GemNowPlayingMusicListScene` | — (`enqueue` exists, no queue UI) | ❌ |
|
||||
| `GemLibraryAudiobookPartScene` | — (no audiobook model) | ❌ |
|
||||
| `GemLibrarySendComposeScene` / `…SendFriendsListScene` | — (no `ACTION_SEND`) | ❌ |
|
||||
| `GemPictureTouchClientScene` / `GemZoomTouch` | `MediaScreens.kt:657` static `Fit` | ❌ |
|
||||
| `GemLibraryArtistPhotoGridContentScene` | single image `DetailScreens.kt:275` | 🟡 |
|
||||
| `GemLibraryCategoryScene` | `DetailScreens.kt:484` (genre only) | 🟡 |
|
||||
| `GemLibraryGameScene` | Marketplace games pivot | 🟡 |
|
||||
| `GemNowPlayingPicturesScene` / `…MainScene` | no picture NP mode | 🟡 |
|
||||
| `GemNowPlayingRadioScene` / `…MainScene` | unified music NP reused | 🟡 |
|
||||
| `GemMarketplaceSearchScene` | — (frozen catalog) | ❌ |
|
||||
| `GemMarketplaceMusicTopScene` / `…GenresContentScene` | "featured" only `MarketplaceScreens.kt:256` | ❌ |
|
||||
| `GemMarketplaceDetailsScene` (album/artist) | `DetailScreens.kt:63` | ✅ |
|
||||
| `GemMarketplaceGamesDetailsScene` (+Screens) | catalog rows only | ❌ |
|
||||
| `GemCartScene` / `GemCartConfirmScene` | — | ❌ (N-A candidate) |
|
||||
| `GemSocialScene` | `MediaScreens.kt:632` (mock) | ✅/mock |
|
||||
| `GemUserCardScene` | — | ❌ |
|
||||
| `GemInboxListContentScene` / `GemInboxDetailsScene` | `ui/apps/mocks/Mocks.kt:90` (mock) | ❌ |
|
||||
| `GemSettingPinLockScene` / `…ScreenLockScene` | `LockShade` only (no PIN) | ❌ |
|
||||
| `GemSettingWifiInfoScene` | — | ❌ |
|
||||
| `GemSettingStorageScene` | `SettingsScreen.kt:124`, `DeviceScreen.kt:333` | 🟡 |
|
||||
| `GemSettingLegalScene` | footnote `SettingsScreen.kt:261` | 🟡 |
|
||||
| `GemRefreshScene` | Settings/library refresh (no scene) | 🟡 |
|
||||
| `GemTvOutputSelectorScene` | — | ❌ (hardware N-A) |
|
||||
| `GemAcsFWScene` | `cloud/CloudUpdateService.kt` (different path) | 🟡 |
|
||||
| Widgets (`GemContextMenu`, `GemWaitCursor`, `GemTimeline`, `GemTunerBar`, …) | Android/Compose runtime | N/A |
|
||||
|
||||
### Highest-value missing surfaces
|
||||
1. **Queue surface** (`GemQueueListScene` / `GemNowPlayingMusicListScene`) — `PlaybackController.enqueue` (`media/PlaybackController.kt:153`) already exists; only the list UI is missing.
|
||||
2. **Picture pinch-zoom/pan** (`GemPictureTouchClientScene` / `GemZoomTouch`) — device-signature viewer; HD is static.
|
||||
3. **Sharing** (`GemLibrarySendComposeScene`) — scoped as roadmap M5.
|
||||
4. **Audiobooks** (`GemLibraryAudiobookPartScene`) — whole media type absent.
|
||||
5. **Marketplace discovery** (search/top/genres) — makes the frozen catalog navigable.
|
||||
|
||||
---
|
||||
|
||||
## 3. Motion, touch & kinetics (resolved)
|
||||
|
||||
### 3.1 The device integrator (authoritative)
|
||||
Recovered from `xuidll.dll@0x41841D58` (scroll tick), `@0x4184C310` (drag
|
||||
velocity), `@0x41848B98` (timer), `@0x41848FC4` (rubber-band),
|
||||
`@0x4184C660` (default touch settings).
|
||||
|
||||
- **Position:** `pos += (dt_ms / 1000) · v`, where `dt_ms = max(33.333, now − lastTick)`
|
||||
(30 fps floor; literals `xuidll.dll@0x41801920 = 1000.0`,
|
||||
`@0x41803ce4 = 33.333`).
|
||||
- **Velocity (active/drag):** `v' = v · (1 + c[+0xB0])`, clamped to
|
||||
`±( step[+0x88] · c[+0xB4] )`.
|
||||
- **Stop:** when `pos` reaches the target `[+0xA0]`, the timer is killed and the
|
||||
shell snap callbacks fire; velocity zero-compare is `0.0`.
|
||||
- **Tick:** `XuiSetTimer(elem, 1, 0x10)` → **16 ms = 62.5 Hz** (`@0x41848B98`).
|
||||
- **Drag→velocity:** `(Δpx/Δt) · scale`, hard-capped at **32.0**
|
||||
(`@0x4184C310`, literal `@0x41804168 = 32`).
|
||||
- **Rubber-band:** explicit damped spring `-(pos−target)·k[+0xD8] − v[+0x50]·d[+0xD4] + v[+0x50]` (`@0x41848FC4`).
|
||||
- **Touch properties** (the ~20-float `XuiTouchSettings` vocabulary recovered from
|
||||
the `xuidll` string table `0x41803F74–0x41804150`): `HorzScroll`, `VertScroll`,
|
||||
`HorizontalFling`, `VerticalFling`, `HorizontalScrub`, `VerticalScrub`,
|
||||
`HorizontalRubberBand`, `VerticalRubberBand`, `FadeIn`, `FadeOut`,
|
||||
`PositionOffset`, `CenterSmallCanvas`, `EnableBandBreak`, `KeyScrollDistance`,
|
||||
`SmoothScroll`, `ScrollPaddingBefore/After`, `ZoomTarget`, `Hollow`, `Direction`.
|
||||
|
||||
### 3.2 Correction: the `0.95` retention provenance is false
|
||||
The previous docs (`zune-hd-touch-settings.md` §6, canon §6) attributed HD's
|
||||
per-frame retention to `XuiTouchSettings[0x1C] = 0.95`. **This is not supported:**
|
||||
- the integrator reads the element's in-place block at `+0xA8` fields **`+0xB0/+0xB4`**
|
||||
= settings **`[0x08]/[0x0C]`** — `xuidll` defaults **1.9 / 1.5**, shell **1.9 / 1.2**;
|
||||
- `[0x1C]` defaults to **0.7** and is **never read** by `@0x41841D58`;
|
||||
- the update `v·(1+c)` is multiplicative-with-clamp, **not** `v·retention`.
|
||||
|
||||
### 3.3 HD state and gaps
|
||||
|
||||
| Aspect | Device | Dorado-HD | Gap |
|
||||
|---|---|---|---|
|
||||
| Tick | 62.5 Hz (`@0x41848B98`) | `KINETIC_FRAME_HZ = 60f` (`design/DoradoMotion.kt:30`) | 4% friction-conversion drift |
|
||||
| Integrator | dt-scaled, 30 fps floor, step-clamped | continuous `animateDecay` (`design/components/ZuneFling.kt:31`) | model differs |
|
||||
| Retention | `(1+c)` clamp, no `[0x1C]` | `0.95`/`0.94` (`DoradoMotion.kt:29,38`) | empirical, provenance wrong |
|
||||
| Rubber-band | explicit spring (`@0x41848FC4`) | platform overscroll; "no springs" invariant | under-models device |
|
||||
| Axis hysteresis | `XuiTouchEnableAxisHysteresis` (`xuidll@0x418331CC`) | implicit Compose latch | not tunable |
|
||||
| Velocity cap | 32.0 | none | absent |
|
||||
| Item snap / SmoothScroll | `XuiTouchSnapToTarget` (`@0x41833134`) | `scrollToItem` for A–Z only | absent |
|
||||
| Navigation easing | per-element timelines (`TransFrom/To`, `EnterTransIndex/LeaveTransIndex`) | one bezier 380/420/340 ms | different model |
|
||||
|
||||
**Recommendation:** re-derive the HD fling friction from the dt-scaled device model
|
||||
(or explicitly label `0.95/0.94` an empirical approximation), and stop citing
|
||||
`[0x1C]`. Add the velocity cap and (optionally) item snapping.
|
||||
|
||||
---
|
||||
|
||||
## 4. HUD / always-on (`zhud_serv.dll`, 1,167 fns, 5 exports)
|
||||
|
||||
Device HUD scenes recovered: `HudMediaController{Music,Radio,Video}Scene`,
|
||||
`HudScreenLockScene`, `HudPinLockScene`, `HudDimmerScene`, `HudOffSwitchScene`,
|
||||
`HudMessageBoxScene`, `HudWaitMessageBoxScene`, `HudKeyboardScene`,
|
||||
`HudNetwork{Connect,List}Scene`, `HudAutoConnectScene`, `HudWaitCursorScene`,
|
||||
`HudDebugOverlayScene`, + root scenes (`ScreenLockRootScene`, `PinLockRootScene`,
|
||||
`MessageBoxRootScene`, `DimmerRootScene`, …).
|
||||
|
||||
Inline HUD dwells are **recoverable** from `XuiSetTimer` call sites (**contradicts
|
||||
`zune-hd-touch-settings.md` §5**): 7000 ms dim (`@0x419CD420`), 5000 ms saver,
|
||||
3000 ms notifications, 30000 ms background (`@0x419C0584`), 12000 ms constant.
|
||||
|
||||
| Device HUD | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Transport overlay (`HudMediaController*`) | `TransportOverlay` `ui/screens/NowPlayingScreen.kt:477` | ✅ |
|
||||
| Play/Pause/Next/Prev | `PlaybackController.kt:160-171`; `NowPlayingScreen.kt:563-592` | ✅ |
|
||||
| Volume + mute | swipe volume only; **no mute** | 🟡 |
|
||||
| `ProgressSlider` + `PlayPosition`/`Elapsed`/`Remaining` | no scrubber in NP | ❌ |
|
||||
| `Ffwd` | — | ❌ |
|
||||
| Lock/pin (`HudScreenLock`/`HudPinLock`) | `LockShade` (no PIN) `design/components/LockShade.kt` | ❌/🟡 |
|
||||
| Dimmer / power-off (`HudDimmer`/`HudOffSwitch`) | — | ❌ |
|
||||
| Message boxes | not modelled | ❌ |
|
||||
| Status OSD (`batteryIcon`,`wifiIcon`,`Clock`,`Ambient`) | — | ❌ |
|
||||
| Screensaver idle | `IDLE_SCREENSAVER_MS=5000` `design/DoradoTokens.kt:68` | ✅ |
|
||||
| Wait cursor | Compose loading | 🟡 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Library & indexing (`zcontent_serv.dll` + `zconfig_serv.dll`)
|
||||
|
||||
Device substrate: `zunedb.dat`, `zconfig.dat`, `drmStore.dat`, `AlbumArt`,
|
||||
`mtp:DatabaseGenerationNumber`, `CloudModifiedItems`; `zconfig_serv` exposes
|
||||
`LibraryLetterThreshold` / `AlbumGridThreshold`.
|
||||
|
||||
| Device behavior | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Indexed library (tracks/albums/artists/genres/playlists/pictures) | `data/repo/LibraryRepository.kt:35-48` | ✅ |
|
||||
| A–Z letter picker | `design/components/KineticList.kt:66,176` | ✅ |
|
||||
| **Indexed search** | `Daos.kt:68` `search()` defined, **no caller** | ❌ |
|
||||
| Letter/grid thresholds (settings) | — | ❌ |
|
||||
| Built-in playlists (`BuiltIn-FavoriteTracks`, `…MostPlayedArtists`, `…RecentTracks`) | Quickplay history/pins + Top Played `HomeScreens.kt:311` | 🟡 |
|
||||
| Sort keys (article-strip, `MMM yyyy`) | plain tags | 🟡 |
|
||||
| Album-art cache/thumbnails | per-track resolve | 🟡 |
|
||||
|
||||
---
|
||||
|
||||
## 6. Playback engine (`zmedia_serv.dll`)
|
||||
|
||||
Device: `CMediaQueueBase`/`CProgressivePlay`/`CTrackListQueue`, queue
|
||||
capacities/history, `ZMediaQueue/MediaItemPositioned|Stopped|Paused|Playing`;
|
||||
EQ (`Software\Microsoft\Zune\Equalizer`, `Preset%02d`); `FFTGRABBER`/`ZMedia/Viz`;
|
||||
`SmartDJStore.dat`; RDS (`Radio_RDS_Capture.dat`); marketplace image/related
|
||||
endpoints; DRM (`CeDRM_MGR_ParsePlayOPL`).
|
||||
|
||||
| Device behavior | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Play/shuffle/repeat/seek/hearts | `media/PlaybackController.kt:142-245` | ✅ |
|
||||
| Queue engine (capacity/history/position events) | thin Media3 wrapper | ❌ |
|
||||
| Equalizer presets | — (no `AudioEffect`) | ❌ |
|
||||
| FFT visualizer bound to playback | procedural bars; real FFT exists separately `analysis/FeatureMath.kt` | 🟡 |
|
||||
| WMA/WMV + WMDRM/PlayReady | `data/model/MediaFormats.kt:17-23` drops `wma`; no DRM | ❌ |
|
||||
| RDS / FM tuner | HTTP-stream presets only `Radio.kt` | ❌ |
|
||||
| Smart DJ store | `PlaybackController.smartShuffleOrder:245` | 🟡 |
|
||||
|
||||
---
|
||||
|
||||
## 7. Marketplace & commerce (gemstone + `znet_serv.dll`)
|
||||
|
||||
Device: `GemMarketplace*`, `GemCart*`; `znet_serv` endpoints
|
||||
(`album?q=%s`, `/albums?orderby=ReleaseDate`, `/recommendations/artists`,
|
||||
`chart/zune/tracks`), Passport sign-in (`SignInRequest/Response`,
|
||||
`urn:passport:compact`), usage reporting (`usageReport`, `SEID_Stats`).
|
||||
|
||||
| Device | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Marketplace catalog/search/artwork client | frozen 62-entry `data/official/OfficialCatalog.kt`; `MarketplaceScreens.kt:322` | ❌ |
|
||||
| Music genres / top charts | "featured" only | ❌ |
|
||||
| Game detail + screenshots | catalog rows | ❌ |
|
||||
| Cart / purchase / confirm | — | ❌ (N-A candidate) |
|
||||
| Sign-in / subscriptions | Last.fm + cloud OAuth only | ❌ |
|
||||
| Usage/telemetry | — | ❌ (privacy: N-A) |
|
||||
|
||||
---
|
||||
|
||||
## 8. Social / inbox / identity
|
||||
|
||||
| Device | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Social feed | `MediaScreens.kt:632` (mock); cloud social service exists | ✅/mock |
|
||||
| Inbox list/details (`GemInbox*`) | `ui/apps/mocks/Mocks.kt:90` | ❌ |
|
||||
| User card (`GemUserCardScene`) | — | ❌ |
|
||||
| WMA streaming / DRM (`ZWmtStreamer.dll`, `XDRM*`) | not supported | ❌ (N-A) |
|
||||
| Credentials/DRM store (`zcredentials_serv`) | no keyvault | ❌ (N-A) |
|
||||
| MTPZ/UPnP identity (`/Device.xml`, `urn:…mtpz:1`) | custom LAN sync (`sync/`) | 🟡 |
|
||||
|
||||
---
|
||||
|
||||
## 9. Settings & device (gemstone `GemSetting*` + `zconfig_serv`)
|
||||
|
||||
| Device | Dorado-HD | Status |
|
||||
|---|---|---|
|
||||
| Settings root / About / Storage | `SettingsScreen.kt:43,254,124` | ✅/🟡 |
|
||||
| Legal | footnote `SettingsScreen.kt:261` | 🟡 |
|
||||
| Screen lock / PIN lock | `LockShade` only | ❌ |
|
||||
| Set time / lock-on | OS-managed / wake shade | N-A |
|
||||
| Wi-Fi info (`GemSettingWifiInfoScene`) | — | ❌ |
|
||||
| TV-out selector | — | ❌ (hardware) |
|
||||
| Config store (`zconfig_serv`: `SwapEffect`, `ImageProduction`, …) | N/A (Android) | N/A |
|
||||
| Cloud/OTA (`UPDATE`, `DColdReboot`) | `cloud/CloudUpdateService.kt` | 🟡 |
|
||||
|
||||
---
|
||||
|
||||
## 10. Tokens, typography, strings, assets
|
||||
|
||||
- **No color hexes or numeric point sizes exist in the UI binaries.** XUI carries
|
||||
color/size as *property names* only (`TextColor`, `FillColor`, `PointSize`,
|
||||
`Font`, `LineHeight`, `TextScale`). HD's palette/scale are canon/review-derived,
|
||||
not byte-citable — the audit cannot verify them against the binaries.
|
||||
- **Font posture is correct:** HD bundles only OFL Selawik (`design/DoradoTheme.kt:16-20`);
|
||||
the device's six Zegoe UI faces live only in the external corpus. **Gap:** the
|
||||
docs promise "import your own Zegoe" (`zune-hd-ui-canon.md:20`,
|
||||
`DoradoTheme.kt:13`) but **no font-import path exists**. Also Selawik has no
|
||||
Black(900)/Medium(500), so `FontWeight.Medium` (`widget/NowPlayingWidget.kt:94`)
|
||||
snaps.
|
||||
- **String parity drift** (device vocabulary HD could adopt):
|
||||
- `"Various Artist"` (`gemstone@0x119A4`) vs HD `"unknown artist"`
|
||||
(`data/scan/MediaLibraryScanner.kt:64`);
|
||||
- `" by "` composition (`gemstone@0x15A60`) vs HD em-dash (`ui/components/Common.kt:291`);
|
||||
- empty-state keys **`Empty`**, **`noItems`/`noItems_local`/`noItems_online`**
|
||||
(`gemstone@0x12B7C`, `0x14160/0x148BC/0x14840`) vs bespoke HD copy;
|
||||
- transport/status words HD lacks: **`Ffwd`**, **`Mute`** (`gemstone@0x19D18/0x19D2C`;
|
||||
`zhud_serv@0x419B4C70/84`), `Disconnected`, `Refresh`, `Wishlist`.
|
||||
- **Docs↔code naming drift (values equal):** `SurfaceTileHover`→`tilePressed`,
|
||||
`SurfaceBorderSubtle`→`border`, accent labels; `TYPE_HEADER_CROP_VISIBLE=48`
|
||||
undocumented (`design/DoradoTokens.kt:25`).
|
||||
|
||||
---
|
||||
|
||||
## 11. Deliberately out of scope (device features we do not intend to reproduce)
|
||||
|
||||
These are device-era subsystems whose servers/hardware are dead or proprietary;
|
||||
they are recorded as **N-A**, not gaps:
|
||||
|
||||
- Marketplace backend + Passport/Microsoft account + subscriptions.
|
||||
- DRM license acquisition (`CeDRM_Mgr_*`), PlayReady/WMDRM, secure clock.
|
||||
- WMA/WMV playback and `ZWmtStreamer` HTTP streaming.
|
||||
- MTPZ/UPnP device identity and Wi-Fi config (`wzcsapi`).
|
||||
- TV-out selector; per-app power/display/suspend timeouts (ZAM).
|
||||
- Usage/telemetry reporting (`usageReport`, `SEID_Stats`).
|
||||
- ACS touch-controller firmware update (`GemAcsFWScene`).
|
||||
|
||||
---
|
||||
|
||||
## 12. Prioritized gap register (summary)
|
||||
|
||||
Full machine-readable register: [`zune-hd-parity-gaps.json`](zune-hd-parity-gaps.json).
|
||||
|
||||
| # | Gap | Axis | Effort | Status |
|
||||
|---|---|---|---|---|
|
||||
| 1 | Queue surface (`GemQueueListScene`) | device | S | ❌ |
|
||||
| 2 | Picture pinch-zoom/pan (`GemPictureTouchClientScene`/`GemZoomTouch`) | device | M | ❌ |
|
||||
| 3 | Now Playing scrubber + elapsed/remaining | device | S | ❌ |
|
||||
| 4 | Kinetic model re-derivation (dt-scaled; fix `0.95` provenance) | device | M | 🟡 |
|
||||
| 5 | Library search UI (wire existing `search()`) | device | S | ❌ |
|
||||
| 6 | HUD dimmer/power-off + status OSD | device | M | ❌ |
|
||||
| 7 | EQ presets | device | M | ❌ |
|
||||
| 8 | Share / `ACTION_SEND` + Zune-Card export | device | M | ❌ (M5) |
|
||||
| 9 | Audiobooks | device | L | ❌ |
|
||||
| 10 | Marketplace search/top/genres | device | L | ❌ |
|
||||
| 11 | Built-in playlists | device | M | 🟡 |
|
||||
| 12 | Inbox + user card | device | M | ❌ |
|
||||
| 13 | PIN/screen-lock + Wi-Fi info | device | M | ❌ |
|
||||
| 14 | String parity (`Various Artist`, ` by `, `noItems`, `Ffwd`, `Mute`) | device | XS | 🟡 |
|
||||
| 15 | Font-import path (or drop the claim) | doc/device | S | ❌ |
|
||||
| 16 | Velocity cap + item snap | device | S | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## 13. Corrections to existing docs
|
||||
|
||||
- **`zune-hd-touch-settings.md`**: replace the `[0x1C]=0.95` retention provenance
|
||||
with the resolved integrator model (§3); add the recoverable HUD timer
|
||||
constants; add the XUI touch property-name vocabulary; fix
|
||||
`XuiProcessMultiTouchMessage` VA to `0x4181F100`; correct §5 "not recoverable"
|
||||
claims (dwell timers **and** field names are now recoverable).
|
||||
- **`zune-hd-ui-canon.md` §6**: cite the device tick (62.5 Hz) and the
|
||||
`pos += (dt/1000)·v` model; do not cite `[0x1C]`.
|
||||
- **`design/DoradoMotion.kt`**: mark `0.95/0.94` as empirical approximations of the
|
||||
device glide, not device constants.
|
||||
- **Label parity**: canon-cite `"Various Artist"`, the ` by ` separator, and the
|
||||
`noItems`/`Empty` empty-state vocabulary before changing display copy.
|
||||
|
||||
## 14. Roadmap delta
|
||||
|
||||
Add to `parity-roadmap.md`: queue surface, picture touch/zoom, NP scrubber,
|
||||
library-search UI, HUD dimmer/status, built-in playlists, inbox/user-card,
|
||||
PIN/Wi-Fi settings, string-parity pass, font-import decision; and annotate
|
||||
marketplace/DRM/Passport/MTPZ as documented N-A (§11).
|
||||
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"audit": "zune-hd-parity-audit",
|
||||
"date": "2026-09-10",
|
||||
"corpus": "zune-hd-disassembly (109 modules, 66598 functions, 4169 exports, 22479 strings)",
|
||||
"axes": {
|
||||
"device": "behaviour the Zune HD itself had",
|
||||
"modern": "post-device extension (canon §10)",
|
||||
"na": "device subsystem deliberately out of scope"
|
||||
},
|
||||
"gaps": [
|
||||
{
|
||||
"id": "queue-surface",
|
||||
"surface": "Play queue list",
|
||||
"axis": "device",
|
||||
"priority": 1,
|
||||
"effort": "S",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemQueueListScene / GemNowPlayingMusicListScene",
|
||||
"hd_state": "PlaybackController.enqueue exists (media/PlaybackController.kt:153); no queue UI"
|
||||
},
|
||||
{
|
||||
"id": "picture-zoom",
|
||||
"surface": "Picture pinch-zoom / pan client",
|
||||
"axis": "device",
|
||||
"priority": 2,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemPictureTouchClientScene, GemZoomTouch",
|
||||
"hd_state": "static ContentScale.Fit (ui/screens/MediaScreens.kt:657)"
|
||||
},
|
||||
{
|
||||
"id": "np-scrubber",
|
||||
"surface": "Now Playing scrubber + elapsed/remaining",
|
||||
"axis": "device",
|
||||
"priority": 3,
|
||||
"effort": "S",
|
||||
"status": "missing",
|
||||
"device_evidence": "zhud_serv.dll ProgressSlider, PlayPosition, ElapsedTime/TotalTime/RemainingText",
|
||||
"hd_state": "time text only; seekTo exists but no UI (ui/screens/NowPlayingScreen.kt:237)"
|
||||
},
|
||||
{
|
||||
"id": "kinetic-model",
|
||||
"surface": "Kinetic integrator model + 0.95 provenance",
|
||||
"axis": "device",
|
||||
"priority": 4,
|
||||
"effort": "M",
|
||||
"status": "partial",
|
||||
"device_evidence": "xuidll.dll FUN_41841D58 pos+=(dt/1000)*v, dt floor 33.333; v'=v*(1+c[+0xB0]) clamped +/-step*c[+0xB4]; tick 16ms FUN_41848B98; velocity cap 32 FUN_4184C310",
|
||||
"hd_state": "exponentialDecay, KINETIC_FRAME_RETENTION=0.95 wrongly attributed to XuiTouchSettings[0x1C] (design/DoradoMotion.kt:29; docs/zune-hd-touch-settings.md)"
|
||||
},
|
||||
{
|
||||
"id": "library-search-ui",
|
||||
"surface": "Indexed library search UI",
|
||||
"axis": "device",
|
||||
"priority": 5,
|
||||
"effort": "S",
|
||||
"status": "missing",
|
||||
"device_evidence": "zcontent_serv.dll content service; gemstone search",
|
||||
"hd_state": "LibraryRepository/Daos search() defined with no caller (data/db/Daos.kt:68)"
|
||||
},
|
||||
{
|
||||
"id": "hud-dimmer-status",
|
||||
"surface": "HUD dimmer / power-off / status OSD",
|
||||
"axis": "device",
|
||||
"priority": 6,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "zhud_serv.dll HudDimmerScene/HudOffSwitchScene; batteryIcon/wifiIcon/Clock/Ambient; dwells 7000/5000/3000/30000/12000ms",
|
||||
"hd_state": "none"
|
||||
},
|
||||
{
|
||||
"id": "eq-presets",
|
||||
"surface": "Equalizer presets",
|
||||
"axis": "device",
|
||||
"priority": 7,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "zmedia_serv.dll Software\\Microsoft\\Zune\\Equalizer, Preset%02d",
|
||||
"hd_state": "no AudioEffect/Equalizer"
|
||||
},
|
||||
{
|
||||
"id": "share-send",
|
||||
"surface": "Share / ACTION_SEND + Zune-Card export",
|
||||
"axis": "device",
|
||||
"priority": 8,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemLibrarySendComposeScene, GemLibrarySendFriendsListScene",
|
||||
"hd_state": "none (roadmap M5)"
|
||||
},
|
||||
{
|
||||
"id": "audiobooks",
|
||||
"surface": "Audiobook parts",
|
||||
"axis": "device",
|
||||
"priority": 9,
|
||||
"effort": "L",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemLibraryAudiobookPartScene; AAXSDKWin.dll/audible.dll",
|
||||
"hd_state": "no audiobook model"
|
||||
},
|
||||
{
|
||||
"id": "marketplace-discovery",
|
||||
"surface": "Marketplace search / top / genres / game details",
|
||||
"axis": "device",
|
||||
"priority": 10,
|
||||
"effort": "L",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemMarketplaceSearchScene/MusicTopScene/MusicGenresContentScene/GamesDetailsScene; znet_serv.dll catalog endpoints",
|
||||
"hd_state": "frozen 62-entry OfficialCatalog (ui/screens/MarketplaceScreens.kt:322)"
|
||||
},
|
||||
{
|
||||
"id": "builtin-playlists",
|
||||
"surface": "Built-in playlists",
|
||||
"axis": "device",
|
||||
"priority": 11,
|
||||
"effort": "M",
|
||||
"status": "partial",
|
||||
"device_evidence": "zcontent_serv/zmedia_serv mtp:PlaylistRef_Favorite/Recent/TopArtists, BuiltIn-*",
|
||||
"hd_state": "Quickplay history/pins + Top Played only"
|
||||
},
|
||||
{
|
||||
"id": "inbox-usercard",
|
||||
"surface": "Inbox + social user card",
|
||||
"axis": "device",
|
||||
"priority": 12,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemInboxListContentScene/GemInboxDetailsScene/GemUserCardScene",
|
||||
"hd_state": "mock shells only (ui/apps/mocks/Mocks.kt:90)"
|
||||
},
|
||||
{
|
||||
"id": "pinlock-wifi",
|
||||
"surface": "PIN/screen lock + Wi-Fi info settings",
|
||||
"axis": "device",
|
||||
"priority": 13,
|
||||
"effort": "M",
|
||||
"status": "missing",
|
||||
"device_evidence": "gemstone.exe GemSettingPinLockScene/GemSettingScreenLockScene/GemSettingWifiInfoScene",
|
||||
"hd_state": "wake shade only (design/components/LockShade.kt)"
|
||||
},
|
||||
{
|
||||
"id": "string-parity",
|
||||
"surface": "Label/empty-state vocabulary",
|
||||
"axis": "device",
|
||||
"priority": 14,
|
||||
"effort": "XS",
|
||||
"status": "partial",
|
||||
"device_evidence": "gemstone.exe 'Various Artist'@0x119A4, ' by '@0x15A60, noItems/Empty@0x14160/0x12B7C, Ffwd/Mute@0x19D18/0x19D2C",
|
||||
"hd_state": "'unknown artist' (MediaLibraryScanner.kt:64), em-dash separator (Common.kt:291), bespoke empty states"
|
||||
},
|
||||
{
|
||||
"id": "font-import",
|
||||
"surface": "Zegoe import path (or drop the claim)",
|
||||
"axis": "device",
|
||||
"priority": 15,
|
||||
"effort": "S",
|
||||
"status": "missing",
|
||||
"device_evidence": "assets/fonts/ZegoeUI*.ttf; registered via registry Software\\Microsoft\\Zune\\Fonts",
|
||||
"hd_state": "docs promise import (zune-hd-ui-canon.md:20) but no code path; Selawik lacks Black/Medium"
|
||||
},
|
||||
{
|
||||
"id": "velocity-cap-snap",
|
||||
"surface": "Fling velocity cap + item snap + rubber-band",
|
||||
"axis": "device",
|
||||
"priority": 16,
|
||||
"effort": "S",
|
||||
"status": "missing",
|
||||
"device_evidence": "xuidll.dll FUN_4184C310 cap 32.0; XuiTouchSnapToTarget@0x41833134; FUN_41848FC4 rubber-band",
|
||||
"hd_state": "no cap/snap; relies on platform overscroll"
|
||||
}
|
||||
],
|
||||
"na": [
|
||||
{ "id": "na-marketplace-backend", "surface": "Marketplace backend + Passport + subscriptions", "device_evidence": "znet_serv.dll SEID_Catalog/SignInRequest/urn:passport:compact" },
|
||||
{ "id": "na-drm", "surface": "DRM license / PlayReady / WMDRM", "device_evidence": "CeDRM_Mgr_*, ZWmtStreamer XDRM*, wmdrm.dll" },
|
||||
{ "id": "na-wma", "surface": "WMA/WMV playback + HTTP streaming", "device_evidence": "ZWmtStreamer.dll 'Zune MarketPlace HTTP Streaming Source'" },
|
||||
{ "id": "na-mtpz", "surface": "MTPZ/UPnP identity + Wi-Fi config", "device_evidence": "znet_serv /Device.xml, urn:microsoft-com:device:mtpz:1; wzcsapi.dll" },
|
||||
{ "id": "na-tvout", "surface": "TV-out selector", "device_evidence": "gemstone.exe GemTvOutputSelectorScene" },
|
||||
{ "id": "na-telemetry", "surface": "Usage/telemetry reporting", "device_evidence": "znet_serv usageReport, SEID_Stats/UsageData" },
|
||||
{ "id": "na-acs", "surface": "ACS touch firmware update", "device_evidence": "gemstone.exe GemAcsFWScene, Acsapi_BeginFwUpdate" }
|
||||
]
|
||||
}
|
||||
@@ -33,7 +33,7 @@ typedef struct XuiTouchSettings { // 80 bytes, 20 x float32
|
||||
| `XuiScrollEndGetDirection` | `0x41832010` | Returns the scroll-end direction. |
|
||||
| `XuiTouchEnableAxisHysteresis/HorizontalAxis/VerticalAxis` | `0x418331CC` / … | Axis lock + hysteresis toggles. |
|
||||
| `XuiTouchGetPositionOffset` / `XuiTouchGetPositionTarget` / `XuiTouchGetState` / `XuiTouchGetCanvasSize` | `0x4183301C` … | Scroller state getters. |
|
||||
| `XuiProcessMultiTouchMessage` | — | Multi-touch dispatch. |
|
||||
| `XuiProcessMultiTouchMessage` | `0x4181F100` | Multi-touch dispatch. |
|
||||
|
||||
The default struct is populated by `FUN_4184C660` (`xuidll.dll` VA `0x4184C660`).
|
||||
|
||||
@@ -95,9 +95,17 @@ remain here for a future pass if symbol data surfaces.
|
||||
|
||||
- **High confidence:** the existence, address, size and 20 values of
|
||||
`XuiTouchSettings`; the accessor/override model; the per-offset values in §2.
|
||||
- **Low confidence:** any field *name*. No `.pdb`/`.map`/`.sym` is present in
|
||||
`PavoBaseline.Cab`; the Xbox 360/Windows CE XUI headers are not public.
|
||||
Names are therefore intentionally omitted rather than guessed.
|
||||
- **Medium confidence (recovered 2026-09-10):** the field *vocabulary*. The `xuidll`
|
||||
string table (`0x41803F74–0x41804150`) exposes ~20 touch/scroll property names —
|
||||
`HorzScroll`, `VertScroll`, `HorizontalFling`, `VerticalFling`,
|
||||
`HorizontalScrub`, `VerticalScrub`, `HorizontalRubberBand`,
|
||||
`VerticalRubberBand`, `FadeIn`, `FadeOut`, `PositionOffset`,
|
||||
`CenterSmallCanvas`, `EnableBandBreak`, `KeyScrollDistance`, `SmoothScroll`,
|
||||
`ScrollPaddingBefore/After`, `ZoomTarget`, `Hollow`, `Direction` — matching the
|
||||
struct arity. The name→offset **mapping is not proven**, so offsets remain the
|
||||
authoritative identifier.
|
||||
- **Low confidence:** the exact name↔offset assignment (no `.pdb`/`.map`/`.sym`
|
||||
exists in `PavoBaseline.Cab`; the XUI headers are not public).
|
||||
- **Method:** `scripts/disassemble_zune_hd.py` (ROM TOC → ARM32 PE rebuild),
|
||||
`llvm-objdump --triple=armv6-none-eabi`, and Ghidra headless decompilation
|
||||
(`ZuneHD_Project`). Float literals resolved from the reconstructed map.
|
||||
@@ -108,10 +116,12 @@ These were investigated for app parity and could not be pinned to a value from
|
||||
the corpus, so **no code change was made** (a guessed value would violate the
|
||||
canon-first rule):
|
||||
|
||||
- **HUD/overlay/volume dwell** — `zhud_serv.dll` drives its overlay timers
|
||||
through imported `XuiSetTimer`/`XuiKillTimer` (indirect via the IAT) and
|
||||
timeline assets rather than inline constants, so the dwell is not a
|
||||
recoverable float. Dorado-HD keeps its existing timing tokens.
|
||||
- **HUD/overlay/volume dwell — RECOVERED (2026-09-10).** `zhud_serv.dll` hides its
|
||||
dwell values behind `XuiSetTimer` call sites, recoverable from the decompiled
|
||||
timer arguments: **7000 ms** dim (`FUN_419CD420`), **5000 ms** screensaver,
|
||||
**3000 ms** notifications (`FUN_419CDAC8`/`FUN_419CDF00`), **30000 ms** background
|
||||
(`FUN_419C0584`), **12000 ms** constant. HD's single `IDLE_SCREENSAVER_MS = 5000`
|
||||
matches the saver but has no dimmer/notification ladder.
|
||||
- **Now Playing screensaver idle timeout** — no inline timeout constant is
|
||||
present near `GemNowPlayingMusicShowScene`; the value arrives through the
|
||||
shell's config reader (`gemstone.exe` `0x704AC`), not a literal.
|
||||
@@ -122,23 +132,33 @@ canon-first rule):
|
||||
not redistributed; Dorado-HD ships metric-compatible Selawik, so no token
|
||||
change is warranted.
|
||||
|
||||
## 6. Kinetic scroll integrator (observed)
|
||||
## 6. Kinetic scroll integrator (resolved 2026-09-10)
|
||||
|
||||
The XUI scroll tick lives at `xuidll.dll` VA `0x41841D58` (`FUN_41841D58`).
|
||||
It steps a scroll object's float state each frame:
|
||||
The XUI scroll tick is `xuidll.dll` VA `0x41841D58`. State (uint index → byte
|
||||
offset): flags `[0x25]`=+0x94 (bit 2 = active), velocity `[0x2A]`=+0xA8,
|
||||
position `[0x27]`=+0x9C, target `[0x28]`=+0xA0, step `[0x22]`=+0x88, last-tick
|
||||
`[0x2E]`=+0xB8, coefficients `[0x2C]`=+0xB0 and `[0x2D]`=+0xB4 (the element's
|
||||
in-place touch block at `+0xA8`, fields `+0x08`/`+0x0C`).
|
||||
|
||||
- velocity at `+0xA8`, position at `+0x9C`, bound/target at `+0xA0`;
|
||||
- decay coefficients read from `+0xB0` and `+0xB4` (the element's in-place
|
||||
`XuiTouchSettings` bytes `+0x08` and `+0x0C` — both `1.9` in the shell, the
|
||||
second the only field the shell tuned down from the XUI default `1.5` to
|
||||
`1.2`);
|
||||
- the new velocity is clamped against `param[0x22] * coefficient` and applied
|
||||
to the position.
|
||||
- **Position:** `pos += (dt_ms / 1000) · v`, dt floored at **33.333 ms** (30 fps);
|
||||
the divisor literal is `1000.0` (`xuidll@0x41801920`) and the floor is
|
||||
`33.333` (`@0x41803CE4`).
|
||||
- **Velocity:** `v' = v · (1 + c[+0xB0])`, clamped to `±( step · c[+0xB4] )`.
|
||||
- **Stop:** when `pos` reaches the target the timer is killed (`XuiKillTimer`)
|
||||
and the shell snap callback runs; the velocity zero-compare is `0.0`.
|
||||
- **Tick:** `XuiSetTimer(elem, 1, 0x10)` = **16 ms (62.5 Hz)** (`FUN_41848B98`).
|
||||
- **Drag→velocity:** `(Δpx/Δt)·scale`, capped at **32.0** (`FUN_4184C310`;
|
||||
literal `@0x41804168 = 32`).
|
||||
- **Rubber-band:** explicit damped spring
|
||||
`-(pos−target)·k[+0xD8] − v[+0x50]·d[+0xD4] + v[+0x50]` (`FUN_41848FC4`).
|
||||
|
||||
This is the engine behind the `KINETIC_FRAME_RETENTION` model in
|
||||
`DoradoMotion`: velocity is reduced proportionally each frame and the position
|
||||
integrates until the velocity threshold is reached — proportional (exponential)
|
||||
decay, no springs. Exact per-field names remain unavailable (see §4), so the
|
||||
integrator is recorded here for provenance rather than turned into tokens.
|
||||
**Correction:** the earlier claim that `XuiTouchSettings[0x1C]` (=0.95) is the
|
||||
per-frame retention is **not supported** — the integrator reads `+0xB0/+0xB4`
|
||||
(= fields `[0x08]/[0x0C]`; defaults 1.9/1.5, shell 1.9/1.2), never `[0x1C]`
|
||||
(default 0.7). The device is a **dt-scaled, clamped proportional glide at 62.5 Hz
|
||||
with a 30 fps floor**, not a per-frame `retention^k` model. HD's
|
||||
`DoradoMotion.KINETIC_FRAME_RETENTION` (0.95) / `KINETIC_LANE_FRAME_RETENTION`
|
||||
(0.94) are empirically tuned approximations of this glide and should be labelled
|
||||
as such (see [`zune-hd-parity-audit.md`](zune-hd-parity-audit.md) §3).
|
||||
|
||||
|
||||
|
||||
+33
-10
@@ -136,11 +136,18 @@ Ratings (tri-state heart, from the Zune desktop/HD family):
|
||||
- Everything fast: Metro is "designed to feel fast and responsive".
|
||||
- The device's touch/kinetic parameters are the `XuiTouchSettings` values the
|
||||
shell applied (`gemstone.exe` VA `0x1C900`–`0x1CB64`, handed to
|
||||
`XuiSetTouchSettings`). Dorado-HD consumes the corroborated fields:
|
||||
the drag/skip deadband `25.0` (`0x10` → `DoradoTokens.SKIP_DRAG_PX`) and the
|
||||
per-frame kinetic velocity retention `0.95` (`0x1C` →
|
||||
`DoradoMotion.KINETIC_FRAME_RETENTION`). Full extraction:
|
||||
`docs/zune-hd-touch-settings.md`.
|
||||
`XuiSetTouchSettings`). Dorado-HD consumes the corroborated drag/skip deadband
|
||||
`25.0` (`0x10` → `DoradoTokens.SKIP_DRAG_PX`).
|
||||
- **Kinetic integrator (device, cited).** `xuidll.dll@0x41841D58` integrates
|
||||
`pos += (dt_ms/1000)·v` with `dt` floored at 33.333 ms (30 fps), updates
|
||||
`v' = v·(1 + c[+0xB0])` clamped to `±(step·c[+0xB4])`, and ticks at 16 ms
|
||||
(62.5 Hz, `FUN_41848B98`); drag velocity is capped at 32.0 (`FUN_4184C310`).
|
||||
**Correction:** the earlier attribution of HD's retention `0.95` to
|
||||
`XuiTouchSettings[0x1C]` is wrong — the integrator reads `[0x08]/[0x0C]`, never
|
||||
`[0x1C]`. `DoradoMotion.KINETIC_FRAME_RETENTION` (0.95) /
|
||||
`…LANE_FRAME_RETENTION` (0.94) are empirical approximations of this glide.
|
||||
Full extraction: `docs/zune-hd-touch-settings.md` §6; audit:
|
||||
`docs/zune-hd-parity-audit.md` §3.
|
||||
|
||||
## 7. Banned in Dorado-HD (invariant list, mirrors Dorado)
|
||||
- `RoundedCornerShape` / any nonzero corner radius on UI chrome.
|
||||
@@ -199,8 +206,24 @@ and Device Link (mDNS discovery + paired LAN sync).
|
||||
**Pending:** EQ presets, crossfade, live-radio pause-and-cache, richer lock-screen
|
||||
art/controls, and a sleep timer — tracked in `docs/parity-roadmap.md` (M5/M6/M10).
|
||||
|
||||
- **Lane fling tuning.** The device applied one global kinetic retention to
|
||||
every surface (`XuiTouchSettings[0x1C]` = 0.95). Dorado-HD keeps that for
|
||||
vertical lists but uses a shorter retention
|
||||
(`DoradoMotion.KINETIC_LANE_FRAME_RETENTION` = 0.94) for horizontal lanes,
|
||||
because the device value over-glides a carousel on a modern phone.
|
||||
- **Lane fling tuning.** The device's kinetic glide is `pos += (dt/1000)·v` at
|
||||
62.5 Hz (`xuidll.dll@0x41841D58`; see §6). Dorado-HD approximates it with a
|
||||
`KINETIC_FRAME_RETENTION` of 0.95 for vertical lists and 0.94 for horizontal
|
||||
lanes (the longer retention over-glides a carousel on a modern phone). These are
|
||||
empirical approximations, not device constants (`zune-hd-parity-audit.md` §3).
|
||||
|
||||
## 11. Device label vocabulary (cited)
|
||||
|
||||
Original wording recovered from the shell resource keys, recorded so display copy
|
||||
can be aligned canon-first (do not change copy without updating this section):
|
||||
|
||||
- `"Various Artist"` (`gemstone.exe@0x119A4`) — HD currently uses `"unknown artist"`.
|
||||
- `" by "` title/artist separator (`gemstone.exe@0x15A60`) — HD uses an em dash.
|
||||
- Empty-state keys `noItems` / `noItems_local` / `noItems_online` / `Empty`
|
||||
(`gemstone.exe@0x14160/0x148BC/0x14840/0x12B7C`) — HD uses bespoke per-screen copy.
|
||||
- Transport/status words `Ffwd`, `Mute`, `Disconnected`, `Refresh`, `Wishlist`
|
||||
(`gemstone.exe@0x19D18/0x19D2C/0x19D50/0x12054/0x19790`).
|
||||
- Transport labels and the volume formatter also live in `zhud_serv.dll`
|
||||
(`Play/Pause/Ffwd/Mute@0x419B4C58-84`, `FormatVolumeEx@0x419D7E88`).
|
||||
|
||||
Tracked in [`zune-hd-parity-audit.md`](zune-hd-parity-audit.md) §10.
|
||||
|
||||
Reference in New Issue
Block a user