tvos-assets
Generate complete Images.xcassets bundles with parallax tvOS icons, iOS 18+ appearance variants, Top Shelf, and splash assets, plus the iOS 27 App Store creative assets with looping videos. Expo-first: the config plugin regenerates all of it on every prebuild.
What Goes In
you bring
- ├─icon.svg
- │or
- │ ├─layer-middle.svg
- │ └─layer-front.svg
- ├─background.png
- ├─#F39C12
- ├─artwork.svgApp Store
- └─music.mp3App Store
Two layers give real parallax, and the flat icon is built from them; --icon uses your own. The App Store art and music are optional.
tvos-assets writes
- ├─AppIcon.brandassets/30
- ├─AppIcon.appiconset/4
- ├─SplashScreenLogo.imageset/6
- ├─SplashScreenBackground.colorset/1
- ├─icon.png · preview.html3
- └─AppStore/9
44 files, plus 9 with --app-store: 5 images and 4 looping videos.
Three Ways To Run
Every Run Ships a Contact Sheet
Below is the tvOS and iOS catalog that tvos-assets@1.7.0 wrote from Tomo TV's brand resources, at true pixel dimensions. The same run writes preview.html with embedded images, colorset swatches, both parallax imagestacks, and the App Store images and four video loops.
tvOS
App Icon - Home Screen6 files
front@1x.png
400 × 240
front@2x.png
800 × 480
middle@1x.png
400 × 240
middle@2x.png
800 × 480
back@1x.png
400 × 240
back@2x.png
800 × 480
App Icon - App Store3 files
front@1x.png
1280 × 768
middle@1x.png
1280 × 768
back.png
1280 × 768
Top Shelf4 files
Standard and wide, composited from the same two inputs at 1x and 2x.
top@1x.png
1920 × 720
top@2x.png
3840 × 1440
wide@1x.png
2320 × 720
wide@2x.png
4640 × 1440
iOS
App Icon - Light / Dark / Tinted (iOS 18+)3 files
One appiconset, three appearances. Dark sits on transparency so iOS supplies the gradient; tinted ships as grayscale for the user's accent color. Both are derived from your icon, or overridden with --icon-dark and --icon-tinted.
icon-1024.png
1024 × 1024
icon-1024-dark.png
1024 × 1024
icon-1024-tinted.png
1024 × 1024
Shared
Splash Screen Logo5 files
200-icon@1x.png
200 × 200
200-icon@2x.png
400 × 400
200-icon@3x.png
600 × 600
200-icon-tv@1x.png
200 × 200
200-icon-tv@2x.png
400 × 400
Standalone1 file
icon.png
1024 × 1024
App Store Creative Assets
New in 1.6.0: --app-store also writes the iOS 27 and iPadOS 27 creative assets into AppStore/, beside Images.xcassets. Every placement App Store Connect takes is covered, each as an opaque PNG with the art inside the safe areas from Apple's creative asset templates, and the ones that take video get a seamless loop.
| Placement | Image | Video | Default |
|---|---|---|---|
| Product page header | header.png 3840 × 1646 | header.mp4, 5-30 s | on |
| Search results | search-results.png 3840 × 2560 | search-results.mp4, 5-30 s | on |
| Universal (header and search results in one) | universal.png 5244 × 2950 | none, PNG only | on |
| In-App Event card | event-card.png 3840 × 2160 | event-card.mp4, 15-30 s | off, needs source |
| In-App Event details page | event-details.png 2160 × 3840 | event-details.mp4, 15-30 s | off, needs source |
header.png 3840 × 1646
Product page header
Video: header.mp4, 5-30 s
Default: on
search-results.png 3840 × 2560
Search results
Video: search-results.mp4, 5-30 s
Default: on
universal.png 5244 × 2950
Universal (header and search results in one)
Video: none, PNG only
Default: on
event-card.png 3840 × 2160
In-App Event card
Video: event-card.mp4, 15-30 s
Default: off, needs source
event-details.png 2160 × 3840
In-App Event details page
Video: event-details.mp4, 15-30 s
Default: off, needs source
Below is what the published 1.7.0 package wrote for TomoTV's own listing: one SVG of row artwork for the header, search results and universal images, another for a Live TV In-App Event, every video a 20 s loop with music. Header and search cards rise and sink; the event cards slide in rows. These are web copies, so tap a video for sound; the originals are full-size H.264 High.





These files are in use: Tomo TV's App Store listing runs them, so the header and search results there are this tool's output.
Row artwork
Row artwork is an SVG whose <mask>holds rows of one repeated card over full-canvas fills, the wall of cards a Figma or Sketch export gives you, with anything fixed drawn on top. One file serves every placement: it is re-tiled to each canvas and centred on that placement's art safe area. Add animate: { rows: 20 } and the rows slide one card per loop, alternating direction, while the fixed layer stays put, so the last frame runs into the first. A shape drawn on top of one card rides its row, like the live dot above. Every rule is checked, and a file that breaks one fails with a message naming it.
Scene artwork
New in 1.10.0. A scene is any other SVG, a night sky or a wordmark on a gradient, cover-fitted to each canvas. animate: { loop: 20, elements: [...] } makes its video: each rule selects elements of the file (#id, tag or #id tag) and writes an <animate>on every one of them in SMIL's own words, attributeName, values, dur, additive and the rest, with staggerspreading the starts so no two neighbours move in step. The frames come from the Google Chrome on your machine, the file's animations paused and seeked to each frame's time, so the video is what Safari and Chrome play when they open the SVG. The file as played is written beside the still, so the loop can be previewed in a browser before it renders. An SVG that already carries its own <animate> tags needs no rules at all.
A fast renderer
Only the cards move, so each frame is blended from the artwork drawn once with every card lit and once with none, through a card mask built from row strips, several frames at a time. A 20 s 4K header loop takes about 30 s on an M1 Max. Art the blend cannot reproduce exactly is drawn in full each frame instead. Videos encode as H.264 High on libx264, whose quality holds steady across keyframes so the loop point does not hitch, or as ProRes 422 HQ. A simulator recording works too: header.video or searchResults.video is cut into the same kind of seamless loop.
Looped music
video.audioputs music on every video instead of the silent track, looped so it never cuts: each video takes a stretch of the track one second longer than itself and crossfades that last second into its first. The stretch sits where the beat a loop length later lines up with the beat at its start, and the level never drops below half the music's median.
From the Expo plugin
Give the plugin an appStore prop and every expo prebuild writes the creative assets into its outDir (default ./AppStore), outside ios/ so prebuild never wipes them. Unchanged files are skipped, so the videos only render again after their artwork or settings change.
One Config, Three Surfaces
Expo plugin
Add it to app.json. Every expo prebuild regenerates the full catalog, nothing gets committed under ios/.
CLI
One command, one zip. Made for scripts and CI, with --dry-run and --quiet included.
Config file
tvos-assets.config.json, read by both. Auto-discovered in the project root, schema included.
When the same setting arrives from two places, the more direct one wins: the config file overrides the defaults, --set overrides the config file, and --icon, --background, and --color always win.
CLI Reference
Inputs
| Flag | Description | Default |
|---|---|---|
| --icon <path> | Icon PNG or SVG (transparent background). Optional when --layer-front and --layer-middle are both given: the icon is assembled from them instead. | required |
| --background <path> | Background PNG or SVG | required |
| --color <hex> | Splash background color, light mode | required |
| --dark-color <hex> | Splash background color, dark mode | auto-darkened |
| --icon-dark <path> | iOS dark-appearance icon override | derived from --icon |
| --icon-tinted <path> | iOS tinted-appearance icon override | grayscale of --icon |
| --icon-border-radius <px> | Icon corner radius (0 = square) | 0 |
| --layer-front <path> | Custom front parallax layer art | — |
| --layer-middle <path> | Custom middle parallax layer art | — |
| --layer-back <path> | Custom back parallax layer art | — |
--icon <path>
Icon PNG or SVG (transparent background). Optional when --layer-front and --layer-middle are both given: the icon is assembled from them instead.
Required
--background <path>
Background PNG or SVG
Required
--color <hex>
Splash background color, light mode
Required
--dark-color <hex>
Splash background color, dark mode
Default: auto-darkened
--icon-dark <path>
iOS dark-appearance icon override
Default: derived from --icon
--icon-tinted <path>
iOS tinted-appearance icon override
Default: grayscale of --icon
--icon-border-radius <px>
Icon corner radius (0 = square)
Default: 0
--layer-front <path>
Custom front parallax layer art
--layer-middle <path>
Custom middle parallax layer art
--layer-back <path>
Custom back parallax layer art
Output
| Flag | Description | Default |
|---|---|---|
| --config <path> | Config JSON file | ./tvos-assets.config.json if present |
| --output <path> | Directory for the zip file | ~/Desktop |
| --out-dir <path> | Write Images.xcassets directly, no zip | — |
| --mode <zip|dir> | Output mode; --out-dir implies dir | zip |
| --platforms <list> | Icon families: tvos, ios, or both | both |
| --preview / --no-preview | Write preview.html contact sheet | on for zip, off for --out-dir |
--config <path>
Config JSON file
Default: ./tvos-assets.config.json if present
--output <path>
Directory for the zip file
Default: ~/Desktop
--out-dir <path>
Write Images.xcassets directly, no zip
--mode <zip|dir>
Output mode; --out-dir implies dir
Default: zip
--platforms <list>
Icon families: tvos, ios, or both
Default: both
--preview / --no-preview
Write preview.html contact sheet
Default: on for zip, off for --out-dir
App Store
| Flag | Description | Default |
|---|---|---|
| --app-store | Write the iOS 27 and iPadOS 27 App Store creative assets into AppStore/ | off |
| --app-store-background <path> | Backdrop for the creative assets | --background |
| --app-store-center <path> | Centre art, such as a wordmark, contain-fit in each safe area | the icon |
--app-store
Write the iOS 27 and iPadOS 27 App Store creative assets into AppStore/
Default: off
--app-store-background <path>
Backdrop for the creative assets
Default: --background
--app-store-center <path>
Centre art, such as a wordmark, contain-fit in each safe area
Default: the icon
Naming & selection
| Flag | Description | Default |
|---|---|---|
| --brand-name <name> | Name of the .brandassets bundle | AppIcon |
| --ios-icon-name <name> | Name of the iOS .appiconset | AppIcon |
| --splash-logo-name <name> | Splash logo imageset name | SplashScreenLogo |
| --splash-background-name <name> | Splash colorset name | SplashScreenBackground |
| --splash-logo-size <px> | Base splash logo size | 200 |
| --no-ios-icon | Skip the iOS appiconset | — |
| --no-top-shelf | Skip both Top Shelf imagesets | — |
| --no-splash | Skip splash logo and colorset | — |
--brand-name <name>
Name of the .brandassets bundle
Default: AppIcon
--ios-icon-name <name>
Name of the iOS .appiconset
Default: AppIcon
--splash-logo-name <name>
Splash logo imageset name
Default: SplashScreenLogo
--splash-background-name <name>
Splash colorset name
Default: SplashScreenBackground
--splash-logo-size <px>
Base splash logo size
Default: 200
--no-ios-icon
Skip the iOS appiconset
--no-top-shelf
Skip both Top Shelf imagesets
--no-splash
Skip splash logo and colorset
Advanced
| Flag | Description | Default |
|---|---|---|
| --set <path=value> | Override any config key by dotted path; repeatable | — |
| --dry-run | Report what would be written, then exit | — |
| --print-config | Print the fully merged config as JSON | — |
| --init [path] | Write a starter tvos-assets.config.json | — |
| --quiet | Only errors and the final output path | — |
--set <path=value>
Override any config key by dotted path; repeatable
--dry-run
Report what would be written, then exit
--print-config
Print the fully merged config as JSON
--init [path]
Write a starter tvos-assets.config.json
--quiet
Only errors and the final output path
Questions
What do I need installed?
Node.js 18 or later. sharp installs with the package, and ffmpeg is only needed for the App Store videos. Xcode is where the generated Images.xcassets ends up, not something the tool runs.
Does it work with Expo and React Native tvOS?
Yes. The tvos-assets/plugin entry in app.json regenerates the catalog on every expo prebuild, for tvOS (EXPO_TV=1) and for iOS. Each prebuild rewrites only the folders it owns and leaves the rest of the catalog alone.
Can the inputs be SVG?
Yes: the icon, the background, the iOS appearance overrides and the parallax layers. An SVG is rasterized at the density each output needs, so a small viewBox still makes a sharp 4640px Top Shelf image, and the minimum sizes do not apply to it.
How big should PNG inputs be?
The icon at least 1024x1024, on transparency. The background at least 2320x720; 4640x1440 matches the Top Shelf image at @2x and avoids upscaling. Anything smaller still runs, with a warning.
How are the dark and tinted iOS icons made?
Both are derived. Dark is your icon on transparency, because iOS draws the dark backdrop itself. Tinted is a grayscale render that iOS colors with the user's tint. Replace either with your own art through --icon-dark and --icon-tinted.
How do the parallax layers work?
A tvOS app icon is an imagestack of three layers, Front, Middle and Back, that the home screen tilts on focus. By default Front and Middle both carry the whole icon. Give each its own art with --layer-front and --layer-middle for real depth; with both set, --icon is optional and the flat icon is assembled from them.
What does --app-store add?
The iOS 27 and iPadOS 27 creative assets App Store Connect takes: product page header, search results, universal, and the In-App Event card and details. Each is an opaque PNG with the art inside Apple's safe area, and the placements that take video get a seamless loop.
Is it used in a shipped app?
Yes. Tomo TV's app icons, Top Shelf images, splash screen and App Store listing art are all written by this tool, and the app is live on the App Store.


