I modded my Samsung UA55UE84AFULXL with an AI coding agent over the home network. The computer and TV had no direct cable connection. I handled Developer Mode, design choices, and physical remote tests; the agent changed the launcher and checked the TV through network tools.

The work produced Dot Home, native Home-button routing, and a model-specific cleanup of optional packages and services. It also exposed the limits: restart maintenance still needs an awake Windows helper, and I have no measured RAM, storage, bandwidth, or sustained TV frame-rate improvement to report.

For the visual story, read the companion build article. The repository record contains the source notes, evidence limits, and maintenance documentation.

Dot Home browser preview showing pixel app names, two ocean waves, and the pixel clock

The screenshots and recording reproduce the launcher in a desktop browser. They are not live framebuffer captures. TV-only status values are unpopulated.

Version 2.0.18, recorded in a browser at 1920 × 1080 and 60 fps for 17.9 seconds. Native app loading and the central Back icon are simulated. Their timing does not measure native app performance.

The compatibility boundary

ItemObserved value
TV modelSamsung 55-inch Crystal UHD UA55UE84AFULXL
Operating systemTizen 9.0
FirmwareT-KSU2EFUABC-0090-1300.9
Linux kernel5.4.261
Process architecture32-bit ARM, armv7
SDK execution identity used by Home helperUID 901
Launcher packageDclHome001
Main applicationDclHome001.Home
Local coordination serviceDclHome001.Watcher
Initial approved remote-navigation baseline2.0.12
Current installed visual and transition revision2.0.18

The TV’s product information file supplied the firmware string. The native helper checks that string before it changes Home settings. It also checks process width and execution identity.

Do not weaken those checks to make another TV pass. A different result means the port needs investigation.

I did not flash a firmware partition. The launcher remained a signed Tizen web package. Privileged changes used a temporary owner-device root session and a saved device-specific baseline.

Sources, tools, and what I changed

The launcher began with AeroTizen at commit 9206a924041fda5c760470555c76e05fac1c1b2a. It supplied the launcher foundation and TV integration code.

The Home work used arn0-tv at fe09cc1050e6d1a4777eb0b92bbeade265e5b0a3. Its original target was a different TV and Tizen release. My native helper added this device’s guards and verified writes.

The privileged command route used samsung-tv-root at 4ad2c4d3b0d0e0da4b5b7ebe4a787e94596f416b. My local changes handled this firmware’s runtime discovery, script delivery, and longer command sessions.

The interface work added matrix lettering, a vertical selector, connection panels, app transitions, a dark app library, and the projected ocean. It also removed app-state polling from the launcher service.

The repository source snapshot retains upstream licenses. Native app logos remain their owners’ property. This project has no affiliation with Samsung or the streaming services.

Separate the jobs before changing anything

The build has several independent parts:

Physical remote
    -> Tizen main operation
    -> DclHome001.Home
        -> selected app or input
        -> local launch acknowledgement service

Windows maintenance helper
    -> verify device identity
    -> temporary privileged command session
    -> check fixed package allowlist
    -> reapply runtime service blocks
    -> verify state and cleanup

The launcher does not need Windows to receive Home. The maintenance helper does need the computer to keep selected background blocks applied after restart.

This separation makes failures easier to interpret. A working Home button does not prove service maintenance succeeded. An inactive service list does not prove native app playback works.

Developer mode and the first connection

The TV and computer were on the same home network. I identified the TV through its device information and network interfaces.

Samsung’s TV device guide describes the developer-mode connection process. The Host PC IP field expects the development computer’s address, not the TV’s address.

On this TV, the path went through the Apps area and App Settings. Entering 12345 opened the developer-mode dialog. The compact remote had no physical number keys. Its 123 button opened the number interface instead.

I enabled developer mode, entered the computer address, confirmed, and restarted the TV. The restart was necessary before treating the SDK connection as ready.

Use placeholders in saved commands and documentation:

# Replace the placeholder locally. Do not copy the article's text literally.
sdb connect "<TV_IP>:26101"
sdb devices

The observed SDK port was 26101. The TV also exposed application information on port 8001 and remote-control WebSocket access on 8002. Their presence did not imply root access.

I used Samsung’s SDB binary and a command-capture wrapper. Ordinary developer access did not provide a normal unrestricted root shell. The successful capture route used the root project’s SDK command runner.

Two SDB implementations also competed during the work. The official SDB server and AeroTizen’s raw transport could not own the same connection simultaneously. Stopping one before using the other avoided misleading connection failures.

What root meant in this session

The archive-based root route returned UID 0, an elevated capability set, and the expected security label. The tool checked temporary staging cleanup and unchanged protected system-file hashes after each session.

This was an on-demand privileged command route from the computer. I did not install a permanent root daemon or replace the TV firmware.

Several local adaptations mattered:

Failure or constraintChange
TV’s dotnet --list-runtimes was unsupportedInspect the installed shared-runtime directories instead
Script staging did not execute reliably through the existing delivery pathDeliver the staged script through cat piped to bash
Longer command batches exceeded capture timeIncrease the capture budget to include command count and accept time
Deferred reboot kept the callback connection openClose inherited callback descriptor 3 in the background command
Root command strings contained Windows carriage returnsNormalize CRLF to LF before serializing them

The timeout adjustment used this budget:

capture_timeout = max(
    accept_timeout + 20,
    command_timeout * (len(commands) + 1),
)

These details belong to the tested route on this firmware. They are not evidence that another Samsung model supports the same root method.

A loopback SDK experiment failed. The developer Host PC restriction may have rejected the loopback address, but I did not prove that cause. I did not change the host restriction to pursue it.

A signed launcher before native Home changes

The custom source overlays are separate from the generated launcher/ directory. The build copies the pinned AeroTizen launcher, applies the custom changes, then writes the generated output.

This distinction prevents a common mistake: editing a generated file, rebuilding, and silently losing the fix.

The source snapshot supports a local build from the pinned upstream checkout:

git clone https://github.com/helalaou/AeroTizen.git
git -C AeroTizen checkout 9206a924041fda5c760470555c76e05fac1c1b2a
$env:AEROTIZEN_SOURCE = (Resolve-Path AeroTizen).Path
python docs/dot-home/source/build.py

This generates source, not a trusted ready-to-install package. Native brand assets are excluded from the repository snapshot. The wave source in the snapshot is the approved baseline.

Installation also needs the owner’s signing profile and device authorization. Use Samsung’s certificate workflow for the current toolchain. My local certificate files and passwords are deliberately excluded.

The pinned AeroTizen CLI exposes the following certificate and install route:

python -m pip install ./AeroTizen
aerotizen --tv <TV_IP> certs
aerotizen --tv <TV_IP> install docs/dot-home/source/launcher

The TV address is a placeholder. Certificate creation requires the owner’s Samsung sign-in and device authorization. The CLI signs the source directory, pushes the device profile, installs the widget, and checks the installed package list.

I used the project’s signer with its raw SDB transport after creating the certificates. The CLI commands above describe the inspected upstream entry points, not a claim that I used that exact command line for every revision.

Keep the application and package identifiers consistent between the manifest and Home helper. A successfully installed widget with a different ID will not satisfy this helper’s checks.

Before changing the system default, launch the app directly and test navigation. A visible launcher proves only that the widget can run. It does not prove the TV can boot it or dispatch Home to it.

Native Home needed two fixes

The original Home operation resolved to com.samsung.tv.csfs, Samsung Home. The saved baseline also recorded related configuration keys and the auto-start flag.

The adapted C# helper used native library calls to query the current main operation and change its default app. It ran through the SDK execution identity, with firmware and architecture checks.

The important native interfaces were:

libbundle.so.0
  bundle_create, bundle_free
libaul.so.0
  aul_svc_set_operation, aul_get_default_app
libcapi-appfw-app-operation-tv.so.0
  app_operation_set_current_app
libapp-context-manager-common.so
  util_is_appbooting_supported_webapp_byappid
libvconf.so.0
  vconf_get_str, vconf_set_str, vconf_get_int, vconf_set_int

The source snapshot includes the guarded helper. Build its managed output on the computer:

dotnet build docs/dot-home/source/Control.csproj -c Release -o <LOCAL_OUTPUT>

Stage the resulting DLL, runtime configuration, and dependency metadata in the owner’s SDK tool directory. My directory was /home/owner/share/tmp/sdk_tools/dot-home-startup/. Use the established SDK capture route to create that directory, then SDB to push the build output.

The execution shapes on the TV are:

# Run through the verified SDK command-capture route, not a presumed root shell.
/usr/bin/dotnet <TV_TOOL_DIRECTORY>/DotHomeControl.dll query
/usr/bin/dotnet <TV_TOOL_DIRECTORY>/DotHomeControl.dll verify <TV_TOOL_DIRECTORY>/original-home.json
/usr/bin/dotnet <TV_TOOL_DIRECTORY>/DotHomeControl.dll apply <TV_TOOL_DIRECTORY>/original-home.json

The first query returns ARN0_QUERY= followed by JSON. Save that JSON as the device’s original-home.json before any apply. Preserve another copy off the TV. Run verify against it before apply, and query afterward.

The repository includes a sanitized sdk-command.py wrapper for this capture route. It reads TV_IP from the environment. The root tool’s source and SDB path remain explicit local dependencies.

Do not copy the entire prefixed output into the JSON file. Do not reuse somebody else’s baseline. The helper checks the saved values, package directory, and TV app-boot eligibility before applying.

The operation was http://tizen.org/appcontrol/operation/main. The helper set that operation and db/appfw/home_appid to DclHome001.Home. It preserved the saved auto-start value.

The helper did not blindly write every startup key. It recorded startup_appid, booting_appid_backup, and first_screen/type as part of the baseline. The TV later updated the startup and backup app values itself.

The first restart launched Dot Home. But Home inside Prime Video left Prime open. That separated startup success from button-dispatch success.

The missing part was the widget manifest:

<tizen:application
  id="DclHome001.Home"
  package="DclHome001"
  required_version="2.4"/>

<tizen:app-control>
  <tizen:src name="index.html" reload="disable"/>
  <tizen:operation
    name="http://tizen.org/appcontrol/operation/main"/>
</tizen:app-control>

The reload attribute requires a compatible manifest version. Leaving the older 2.3 requirement while adding the attribute was invalid.

The Tizen manifest reference documents that version boundary.

Tizen’s application-control guide explains dispatch to web applications. The registered operation let the existing app receive Home without rebuilding its whole state.

Dot Home listens for the application-control event and foreground return. It closes transient panels and schedules the return to the first item. A short debounce prevents duplicate foreground events from starting competing scrolls.

After the manifest fix in version 2.0.6, a physical Home press from Prime Video returned to Dot Home. Three updated-launcher restart tests also showed Dot Home automatically, without a host launch command.

Some restarts needed a wake packet when the TV stayed offline. These are not unplugged cold-start tests. Future firmware changes remain untested.

Samsung Home remains usable

The original fallback action exited Dot Home. With Dot Home now assigned as Home, exiting simply returned to Dot Home again.

The working action launches the Samsung app explicitly:

tizen.application.launch('com.samsung.tv.csfs');

I checked this with the remote: Samsung Home opened. The physical Home button still routes through the new assignment.

Keeping Samsung Home installed reduced the need for destructive system changes. I also retained native settings, the app store, networking, Bluetooth, inputs, and SmartThings components.

Preserving those packages is not the same as certifying every feature. In particular, the project did not validate protected video playback or every DRM path.

Package cleanup used a fixed inventory

The initial inventory contained 431 packages. I selected 45 optional package registrations, kept their files, and used package-manager disable flags.

The operation shape was:

# Record of the operation, not a universal recommendation.
pkgcmd -D -t tpk -n <EXACT_REVIEWED_PACKAGE_ID>

The widget packages used -t wgt. I did not use a blanket wildcard or delete package directories. The package database supplied readback evidence, rather than trusting the command’s exit status alone.

The following is the complete build-specific inventory. Names describe package labels, not verified packet-level behavior.

Package identifierTypeLabel
com.samsung.tv.adplayertpkAdPlayer
com.samsung.tv.ad-web-frameworktpkAd Web Framework
adplatformwgtAd Player
com.samsung.tv.targeted-ad-servicetpkTargeted advertising
com.samsung.tv.acr-service-apptpkACRServiceApp
com.samsung.tv.iacrtpkiacr
com.samsung.tv.canalysis-servicetpkcanalysis-daemon
com.samsung.tizen.samsung-analyticstpkSamsung analytics
com.samsung.tv.pisa-servicetpkpisa-service
com.samsung.tv.context-aware-agenttpkContextAwareAgent
com.samsung.tv.context-aware-servicetpkContextAwareService
com.samsung.tv.contents-recognition-dbmgrtpkContent recognition data manager
com.samsung.tv.photo-analysis-datamgrtpkPhoto analysis data manager
yL49PNFmjWwgtSamsung Promotion
2025ePop02wgt2025.SmartTV.Kant
com.samsung.tv.remindertpkReminder
com.samsung.tv.tvPlusDeeplinkertpkSamsung TV Plus
com.samsung.tv.AICompanionUINoticetpkVision AI Notice
com.samsung.tv.AICompanionAgenttpkAICompanionAgent
com.samsung.tv.AICompanionUILaunchertpkVision AI Companion
com.samsung.tv.AICompanionUItpkAICompanionUI
com.samsung.tv.ai-discovery-uitpkAI discovery UI
com.samsung.tv.ai-discovery-servicetpkAI discovery service
com.samsung.tv.bixby-context-clienttpkBixby Context Client
com.samsung.tv.bixby-promotiontpkBixby
com.samsung.tv.bixby-provtpkBixby Provisioning
com.samsung.tv.mybixbytpkVoiceDiscoveryMenu
com.samsung.tv.bixbycapsuleviewertpkBixby capsule viewer
com.samsung.tv.wakeup-engine-bixbytpkBixby wakeup engine
com.samsung.tv.ondevice-voicetpkOn-device voice
com.samsung.tv.voice-instant-apptpkVoice instant application
com.samsung.tv.voiceassistant-musictpkVoice assistant music
com.samsung.tv.utterance-recommender-servicetpkUtterance recommender
com.samsung.tv.gamehometpkGameHome
com.samsung.tv.gaminghubtpkGamingHub
com.samsung.tv.ghdaemontpkGHDaemon
com.samsung.tv.ghservicetpkGHService
com.samsung.tv.gamepadguidetpkGamePadGuide
com.samsung.tv.health-mde-settingtpkHealth settings
com.samsung.tv.health-mde-workout-trackertpkWorkout Tracker
com.samsung.tv.health-mde-servicetpkHealth service
com.samsung.tv.ambientftetpkAmbientFTE
com.samsung.tv.ambient-supporttpkAmbientSupport
com.samsung.tv.ambientinfo-resourcestpkAmbientInfo resources
com.samsung.tv.wizard.AmbientInfotpkWizard AITech

Per-package or per-service internet usage: not measured for every entry above and below. I did not capture baseline counters, packet traces, or a controlled observation interval. A name containing “analytics” does not establish a bandwidth number.

Disabling Bixby and voice packages intentionally removes related voice behavior. The cleanup also backed up and removed selected TV Plus automatic-start flags.

Fourteen service targets needed two mechanisms

Eight unit definitions contained existing condition-file checks. I created only the markers recognized by those definitions, under /opt/usr/share/systemd/system/.

UnitCondition marker basename
pisa-service.servicepisa-service
canalysis-service.servicecanalysis-daemon
com.samsung.tv.context-aware-agent.servicecom.samsung.tv.context-aware-agent
com.samsung.tv.context-aware-service.servicecom.samsung.tv.context-aware-service
com.samsung.tv.AICompanionAgent.servicecom.samsung.tv.AICompanionAgent
com.samsung.tv.ghdaemon.servicecom.samsung.tv.ghdaemon
com.samsung.tv.bixby-prov.servicecom.samsung.tv.bixby-prov
com.samsung.tv.ondevice-voice.servicecom.samsung.tv.ondevice-voice

Do not assume another unit recognizes an invented marker. I inspected the installed definitions. Their CRLF line endings also broke an exact full-line comparison, so the check used a fixed substring match.

The markers alone did not keep every target inactive in later checks. The maintenance helper therefore stops all eight after startup and verifies their state.

Six additional units used runtime masks:

media-analytics-service.service
ambient-ua-agent.service
pisa-service.socket
com.samsung.tv.voiceassistant-music.service
reminder-service.service
org.tizen.tv.sp-kpi.service

Normal persistent masking failed because the relevant filesystem was read-only. Runtime masks worked under /run, but restart cleared them. I kept that limitation instead of remounting or modifying firmware partitions.

After applying the masks, the helper stops the targets and checks ActiveState and UnitFileState. It only escalates to killing processes for the exact selected units that remain active or deactivating.

Final verification found all 14 selected service targets inactive. That is a point-in-time result after maintenance, not proof that every background Samsung process disappeared.

Why the Windows helper exists

An early verification found all package disable flags preserved. Later testing found 29 targets enabled again. The early README therefore describes an incomplete intermediate state.

I did not isolate whether restart, installation, or another firmware action caused the change. The final helper reads the existing 45-item allowlist and reapplies only missing disable flags.

Its sequence is:

  1. Verify the computer’s configured address and the TV’s expected network identity.
  2. Wait for the TV to return online and settle.
  3. Open the temporary privileged command route.
  4. Recheck and apply the fixed package allowlist.
  5. Mask the six runtime units and stop the eight optional units.
  6. Read back package counts and service states.
  7. Verify root-session cleanup and protected-file hashes.
  8. Save the successful boot identifier and result path.

The watcher checks connectivity about every eight seconds. It waits 15 seconds after reconnection before maintenance. Failed attempts back off rather than running continuously.

The helper starts at Windows sign-in. It needs the computer awake, signed in, and on the home network. The native Home assignment and Dot Home startup remain independent of it.

A Windows process-wait bug made this harder than expected. Start-Process -Wait waited for the descendant SDB server too. The privileged command had finished, but the maintenance script appeared hung.

The fix waited for the Python runner itself:

$process = Start-Process -FilePath $python -ArgumentList $arguments `
  -WindowStyle Hidden -PassThru `
  -RedirectStandardOutput $stdoutFile `
  -RedirectStandardError $stderrFile
$process.WaitForExit()
$process.Refresh()

Capturing standard output and error into separate files also prevented PowerShell error records from obscuring the runner’s actual result.

The visual implementation

The source uses HTML, CSS, JavaScript, inline SVG lettering, and Canvas 2D. It does not add a client-side framework.

Matrix lettering and row motion

Characters use a five-column, seven-row cell pattern. The renderer turns lit cells into SVG dots. That makes the app label and clock share a visual system without a font download.

The main app text is 84 pixels tall. Rows are spaced 132 pixels apart in the list coordinate system. The selected row stays at a fixed anchor, with neighboring rows progressively dimmed.

The implementation reuses existing row nodes when the list changes. Selection state uses the application key, so a refresh does not casually move focus to another app. Direction hints use chevrons for the remote’s up, down, left, and right actions.

Colors are assigned by app identity. They are repeated in the launch wash, so an app retains its visual identity during the handoff.

Two independent ocean waves

The first approved background used a corner projection. The current renderer keeps its 104-column, 72-row mesh but uses the wider ocean preview’s projection. Distant rows converge around an upper-middle horizon. The foreground spreads across and beyond the bottom of the screen.

Each point combines three moving height terms. Spatial sine and cosine values are cached once. Per-frame temporal values combine with them through angle identities:

var wave = p.sinA * cosA - p.cosA * sinA +
  (p.sinB * cosB + p.cosB * sinB) * .43 +
  (p.cosD * cosD + p.sinD * sinD) * .22;

The blue surface has full opacity. A second teal surface has opacity .38, a phase offset of 5.6, and speed multiplier -.83. It moves independently in the opposite temporal direction, rather than merely copying the first wave’s frame. A small position offset separates the ridges. A three-layer trial felt choppy and was dropped.

Each layer allocates 72 soft cell highlights and 160 dot glints, twice the previous count. Their positions and fade cycles vary. These are allocation counts, not the number visible in every frame.

Five dot brightness batches reduce repeated paint-state changes. Cell highlights and glints use eight brightness groups instead of a separate fill operation per highlight. Off-screen points skip height and brightness calculations. The backing width is capped at 1280 pixels. Frame pacing targets 60 draws per second and retains timing remainders between animation callbacks. The current motion multiplier is 1.35. The output video is 60 fps; sustained TV rendering performance has not been measured.

The code pauses when hidden, during editing, while an input view is active, and beneath the app cover. It paints a static surface for reduced-motion preferences.

Keep the clock simpler than the background

The clock retains the five-by-seven pixel glyphs and updates once per second. Hours, minutes, and seconds have two digits each. A train departure board flip was implemented and tested, then rejected after viewing it. Version 2.0.18 restores the simpler clock. That experiment was a design decision, not a reason to keep extra animation running.

Direction hints use small square key boxes. Their SVG chevrons have a centred view box, a 3.2-unit stroke, and rounded ends. Flex alignment centres the SVG vertically and horizontally in each box. The browser check measured zero offset between the icon centre and its box centre.

Launch and return transitions

The launcher clones the selected label’s SVG into its own cover. It translates and scales that label while the app color fades across the right half.

The transition lasts 460 milliseconds. The label scale reaches 1.10. On return, the movement reverses and the cover remains until the return completes.

Prime Video transition with pixel text and a blue wash fading into black

Browser capture of the custom transition. This does not measure the native app’s startup time.

The visibilitychange handler cancels timers that should not survive suspension. Without that, a resumed watchdog could remove the cover immediately and expose a broken-looking intermediate frame.

Native app composition still belongs to the TV. I improved the part I own and tested the observed result. I did not replace each app’s internal startup screen.

Version 2.0.15 fixed a separate return problem. The list’s visibility handler reset the selection to the first row while the transition still needed the original row. It now defers that reset while the cover is busy. A native Home application-control event still requests the top row after the transition. Back preserves the app and its original list position.

The browser regression starts on JioHotstar, records its label at vertical position 418 pixels, opens the cover, and returns. The intermediate label moves toward that position and finishes at 418 pixels on the same selected row node.

The recording uses a browser-only simulator, guarded by if (A.tizen) { return; }. After the faded launch page it shows black with a central spinner. Back replaces the spinner with an icon for 550 milliseconds, reveals the faded page for 350 milliseconds, then reverses the label transition. These demonstration timings do not insert a spinner into native TV apps.

Remote repeat handling

Two animation experiments failed for different reasons. Fractional hold movement made the entire list nudge without a clear selection change. A synthetic repeat timer later made one press advance twice.

Version 2.0.12 removed the synthetic timer. The first non-repeat keydown advances once. Further movement requires actual repeated keydowns after a 450-millisecond hold threshold.

Accepted repeats stay at least 65 milliseconds apart. Keyup clears input state and never changes the selection. Orphan repeats after release are ignored.

The regression case was deliberately concrete: start on Apple TV, hold a single press for 350 milliseconds, release, then deliver a late repeat. The selected app must remain Netflix.

Fast scrolling still works when the remote emits held repeats. A 22-pixel, 430-millisecond bounce only runs when fast travel reaches an endpoint. Ordinary middle-row movement does not bounce.

Home-to-top has a separate eased animation. It reads the current rendered position and moves monotonically toward the first item. Duplicate Home events are debounced.

Connection controls and honest status

The home screen labels the Wi-Fi name and signal. Four bars provide a quick visual reading. The address is masked on Home and available in the network detail panel.

Bluetooth, Wi-Fi, TV settings, and the speed test share side-to-side remote navigation. Unsupported reads show a fallback instead of fabricated values.

The RAM meter reads Tizen system information:

var total = tizen.systeminfo.getTotalMemory();
var available = tizen.systeminfo.getAvailableMemory();
var used = Math.max(0, total - available);

These APIs return memory sizes in bytes. The displayed used-memory value is a snapshot of system memory, not Dot Home’s private allocation and not a measured saving.

The speed test downloads about 5 MB only when requested. Its result includes connection and request overhead. It is not a continuous background monitor.

Storage has its own label. Middle dots separate the status items. Removing vague “memory optimized” wording made the display more accurate and easier to understand.

App library, music shortcuts, and HDMI

Customize Home uses a dark two-column app library. It refreshes the installed app list, exposes Add or On Home state, and saves the chosen order.

Customize Home browser preview with installed-app choices and dark controls

The library controls visibility in Dot Home. It does not install packages. New native apps still come from the TV’s app store, subject to model and regional availability.

The requested app order was YouTube, Prime Video, JioHotstar, Netflix, Apple TV, SonyLIV, Spotify, and YouTube Music. A one-time migration sets that order without overwriting later edits.

Spotify was already installed at version 2.1.71. Its entry was added and a launch was tested. The YouTube Music entry opens YouTube; the viewer can choose its Music section. YouTube’s TV guidance describes that route.

HDMI sources are read from the TV input integration. You can hide a source or save a friendlier launcher label. The input switch remains a native TV operation.

Brand icons needed separate attention. Generic placeholders made JioHotstar and SmartThings too similar. Local native assets and Spotify’s green mark improved recognition. The source snapshot does not redistribute extracted proprietary icon files.

The test loop and its limits

I used three kinds of evidence:

Test surfaceWhat it establishedWhat it could not establish
Desktop browserLayout, canvas motion, transition state, key handlingTV privileges, native app composition
TV SDK and privileged queriesPackage flags, service state, app visibility, Home settingsPerceived remote feel, protected playback
Physical remote checksHome destination, navigation feel, control actionsExact frame timing or RAM savings

A live-inspector attempt failed for the already-running app. The attempted stop route did not yield a usable inspector port. I therefore did not claim live browser debugging of the TV.

The device log attempt also yielded no useful application log stream. Local regression checks, explicit SDK queries, screenshots, and physical feedback carried the investigation.

Successful app launch requests do not prove protected playback. The final report preserves that gap. I tested navigation, fast scrolling, transitions, and connection controls on the TV.

Later capture tests obtained full-resolution TV screenshots through the privileged compositor route. Continuous buffer capture was less useful: the short 480 × 270 test produced about 12 fps and could capture individual surfaces. It did not provide a smooth recording of all TV screens. The published video therefore uses the launcher code in a browser, with simulated native handoff screens. Private TV screenshots are excluded.

Timing and revision record

The first signed 2.0.0 artifact was timestamped 14:39 on 21 October 2026. The initial approved 2.0.12 artifact was timestamped 18:01 that day, in IST. Later work continued through the installed 2.0.18 revision.

That artifact window is 3 hours and 22 minutes. It excludes earlier research, developer-mode setup, and root work. File times also do not measure uninterrupted human effort.

The recording experiments, return correction, and later visual revisions are outside that initial window.

Revision or phaseEvidence-backed change
2.0.0First signed custom-launcher artifact in the recorded window
Cleanup phase45 optional package targets; eight condition markers; six runtime masks
Native Home phaseGuarded helper, saved baseline, app-boot eligibility query
2.0.6Manifest main-operation registration; physical Home return confirmed
Restart tests 2 to 4Updated launcher appeared automatically without a host launch request
2.0.8Shared-label app cover, color wash, hidden-timer handling, labeled memory status
2.0.9Dark library work and an unsuccessful fractional hold-motion experiment
2.0.10Return to discrete logical selection with visual interpolation
2.0.11Right-side brand preview experiment, later rejected
2.0.12Actual remote repeats only; no right logo; larger text; full lower wave coverage and dot glints
Final remote checkUp/down, fast held movement, side controls, and transitions worked as intended
2.0.13 to 2.0.14Three-wave and two-wave trials; reduced background work and increased motion speed
2.0.15Preserve original selection on Back; add a browser-only handoff simulator
2.0.16Single-wave comparison with richer highlights
2.0.17Wider ocean projection, two independent waves, chevron hints, and a split-flap clock trial
2.0.18Restore simple clock, double highlights, batch drawing, skip off-screen geometry, target 60 fps, and centre bolder chevrons

The repository evidence ledger preserves these distinctions without publishing private raw logs. Earlier notes that say “no helper installed” or “startup unresolved” describe intermediate states, not the final build.

What I can and cannot call a benefit

The final maintenance check reported 45 disabled package targets. A separate query found all 14 selected service targets inactive.

The custom home has no ad feed. Its app list stays under the owner’s control. Native streaming apps remain responsible for their own ads, accounts, subscriptions, and content access.

I did not measure RAM savings. I did not measure storage recovery, and disabled package files remain present. I did not measure traffic per service or total bandwidth saved.

The useful next measurement would hold firmware, app state, runtime, and observation interval constant. It would record a baseline before changing package state. Re-enabling services now simply to manufacture a comparison would disturb the working setup.

If you are recreating this setup, preserve the exact compatibility checks, collect a fresh baseline, and test Home separately from startup. Treat UI screenshots as UI evidence and service queries as service evidence.

Want help with your TV skin? Email me for guidance or a custom setup. We can agree on a small fee before work starts.