
Vega Multi Tv Migration
- 3.8k installs
- 4 repo stars
- Updated June 30, 2026
- amazonappdev/devices-agent-skills
vega-multi-tv-migration is a skill for migrating Vega OS Fire TV apps to multi-platform React Native TV monorepos.
About
vega-multi-tv-migration guides migrating Vega OS Fire TV applications into a multi-platform React Native monorepo targeting Android TV, Apple TV, and Vega OS with 70-85% code reuse. A decision tree routes work through four phases: analysis, implementation, platform support, and configuration troubleshooting. Phase 1 analyzes codebase dependencies as shared, platform-specific, or VMRP-compatible. Phase 2 scaffolds Yarn workspaces monorepo structure with templates for root package.json, tsconfig, yarnrc deduplication, shared and expotv packages, and Metro configs. Phase 3 adds Android TV and Apple TV platform support including native modules. Quick checks verify packages/shared, packages/vega, packages/expotv, VMRP babel preset, and Metro resolution. Problem mapping links Metro errors, duplicate React versions, VMRP import mapping, and TypeScript path issues to PHASE1_ANALYSIS, PHASE2_IMPLEMENTATION, and PHASE3_PLATFORM_SUPPORT reference files plus assets/templates and VALIDATION_CHECKLIST.md verification at each phase checkpoint before advancing.
- 70-85% code reuse across Android TV, Apple TV, and Vega OS.
- Four-phase decision tree: analysis, implementation, platform, config.
- Yarn workspaces templates for shared, vega, and expotv packages.
- VMRP preset checks and Metro monorepo resolution configs.
- Validation checklist for phase checkpoints before advancing.
Vega Multi Tv Migration by the numbers
- 3,840 all-time installs (skills.sh)
- +292 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #39 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
vega-multi-tv-migration capabilities & compatibility
- Capabilities
- dependency classification for tv migration analy · yarn workspaces monorepo scaffolding templates · vmrp import mapping configuration · android tv and apple tv platform addition · metro and typescript monorepo resolution fixes · phase validation checklist verification
- Works with
- aws
- Use cases
- frontend · api development
- Pricing
- Free
What vega-multi-tv-migration says it does
70-85% code reuse across Android TV, Apple TV, and Vega OS.
ls -la packages/shared packages/vega packages/expotv
grep "vmrp" packages/vega/babel.config.js
npx skills add https://github.com/amazonappdev/devices-agent-skills --skill vega-multi-tv-migrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3.8k |
|---|---|
| repo stars | ★ 4 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 30, 2026 |
| Repository | amazonappdev/devices-agent-skills ↗ |
How do I migrate a Vega Fire TV app to Android TV and Apple TV with shared code?
Migrate Vega OS Fire TV apps to a multi-platform React Native monorepo for Android TV, Apple TV, and Vega OS.
Who is it for?
Teams migrating single-platform Vega TV apps to multi-platform React Native monorepos.
Skip if: Skip for phone-only React Native apps without TV platform targets.
When should I use this skill?
User mentions Vega migration, multi-platform TV monorepo, VMRP, or Android TV and Apple TV support.
What you get
Phased monorepo with shared packages, VMRP mapping, and platform-specific TV targets.
- TV-ready app.json
- expo-build-properties native targets
By the numbers
- Sets Android kotlinVersion to 1.9.25 via expo-build-properties
- Sets iOS deploymentTarget to 15.1 for TV builds
Files
Vega Multi-Platform Migration
Overview
Migrate Vega OS (Fire TV) apps to multi-platform React Native monorepo with 70-85% code reuse across Android TV, Apple TV, and Vega OS.
When to Apply
Use this skill when user mentions:
- Migrating Vega/Fire TV app to other platforms
- Building multi-platform TV application
- Converting single-platform TV app to monorepo
- Adding Android TV or Apple TV support
- Sharing code between TV platforms
- Setting up Yarn workspaces for TV apps
Phase Priority Guide
| Priority | Phase | Impact | When to Use |
|---|---|---|---|
| 1 | Analysis | CRITICAL | Starting migration, no existing analysis |
| 2 | Implementation | CRITICAL | Have analysis, need monorepo structure |
| 3 | Platform Support | HIGH | Have working Vega monorepo, adding platforms |
| 4 | Configuration | MEDIUM | Troubleshooting build/resolution issues |
Quick Decision Tree
User has existing Vega app?
├─ YES → Do they have migration analysis?
│ ├─ NO → Start Phase 1 (Analysis)
│ └─ YES → Is monorepo set up?
│ ├─ NO → Start Phase 2 (Implementation)
│ └─ YES → Start Phase 3 (Platform Support)
└─ NO → Starting from scratch?
└─ YES → Skip Phase 1, start Phase 2 with new projectQuick Reference
Critical: Project Structure
# Verify monorepo structure exists
ls -la packages/shared packages/vega packages/expotv
# Check Yarn workspaces configured
grep -A5 "workspaces:" package.jsonCritical: Dependency Classification
Common patterns for analysis:
- Shared: Business logic, UI components, utilities, state management
- Platform-specific: Navigation, video players, DRM, native modules
- VMRP-compatible: Standard RN libraries that map to Vega equivalents
High: VMRP Configuration
Quick check if VMRP is working:
# Should see @vega-tv/react-native-module-resolver-preset
grep "vmrp" packages/vega/babel.config.jsReferences
Phase 1: Analysis (analysis-*)
| File | Impact | Description |
|---|---|---|
| PHASE1_ANALYSIS.md | CRITICAL | Codebase analysis, dependency classification, migration planning |
Use when: Starting migration, no existing analysis document
Phase 2: Implementation (impl-*)
| File | Impact | Description |
|---|---|---|
| PHASE2_IMPLEMENTATION.md | CRITICAL | Monorepo scaffolding, code migration, VMRP setup with template references |
Use when: Have analysis, ready to build monorepo structure
Phase 3: Platform Support (platform-*)
| File | Impact | Description |
|---|---|---|
| PHASE3_PLATFORM_SUPPORT.md | HIGH | Android TV and Apple TV implementation |
Use when: Have working Vega monorepo, adding new platforms
Templates
All configuration templates in assets/templates/ with companion .md docs:
root-package.json- Yarn workspaces setuproot-tsconfig.json- TypeScript project referencesyarnrc.yml- Dependency deduplication (CRITICAL)shared-package.json+.md- Shared package config with rulesvega-metro.config.js- Vega Metro with monorepo resolutionexpotv-package.json+.md- Expo TV package configexpotv-app.json+.md- Expo TV configuration with pluginsexpotv-metro.config.js- Expo Metro with TV extensions
Problem → Skill Mapping
| Problem | Start With |
|---|---|
| Need to analyze existing Vega app | PHASE1_ANALYSIS.md |
| Have analysis, need monorepo setup | PHASE2_IMPLEMENTATION.md → templates |
| Monorepo exists, adding Android TV | PHASE3_PLATFORM_SUPPORT.md |
| Metro resolution errors | PHASE2_IMPLEMENTATION.md → Metro config |
| Duplicate React versions | PHASE2_IMPLEMENTATION.md → .yarnrc.yml |
| VMRP not mapping imports | PHASE2_IMPLEMENTATION.md → VMRP section |
| TypeScript path errors | PHASE2_IMPLEMENTATION.md → TypeScript config |
| Native module integration | PHASE3_PLATFORM_SUPPORT.md → Native Modules |
| Build configuration issues | PHASE2_IMPLEMENTATION.md → Configuration Files |
| Starting from scratch | PHASE2_IMPLEMENTATION.md (skip Phase 1) |
Workflow
1. Use the decision tree above to determine the starting phase 2. Load the appropriate reference file for that phase 3. Follow Quick Start → Deep Dive pattern in each reference 4. Verify at each phase's checkpoint before moving to the next phase 5. Use VALIDATION_CHECKLIST.md for comprehensive verification
Attribution
Based on Vega OS multi-platform migration patterns and React Native monorepo best practices.
{
"expo": {
"name": "MyAppTV",
"slug": "myapp-tv",
"orientation": "landscape",
"platforms": ["android", "ios"],
"scheme": "myapp-tv",
"plugins": [
"@react-native-tvos/config-tv",
[
"expo-build-properties",
{
"android": {
"kotlinVersion": "1.9.25"
},
"ios": {
"deploymentTarget": "15.1"
}
}
],
"expo-router"
]
}
}
Expo TV app.json Configuration
Critical Settings
plugins
@react-native-tvos/config-tv- Enables TV support (REQUIRED)expo-build-properties- Configures native build settingsexpo-router- File-based routing for the TV app
expo-build-properties
android.kotlinVersion: "1.9.25"- CRITICAL: Fixes Kotlin/Compose compiler compatibilityios.deploymentTarget: "15.1"- REQUIRED for ExpoModulesCore (may need manual fix for tvOS)
platforms
- Only
["android", "ios"]- No web support for TV apps
orientation
"landscape"- TV apps are always landscape
scheme
"myapp-tv"- URL scheme for deep linking with expo-router
Customization
Replace these values:
name- Your app display nameslug- URL-friendly identifierscheme- Your app's URL scheme
const { getDefaultConfig } = require("expo/metro-config");
const path = require("path");
const projectRoot = __dirname;
const monorepoRoot = path.resolve(projectRoot, "..");
const config = getDefaultConfig(projectRoot);
// Watch shared package for hot reload
config.watchFolders = [path.resolve(monorepoRoot, "shared")];
// Resolve from local and parent node_modules
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(monorepoRoot, "node_modules"),
];
config.resolver.resolverMainFields = ["react-native", "browser", "main"];
// TV-specific file extensions: .tv.tsx, .tv.ts resolved before .tsx, .ts
// Allows platform-specific implementations for TV platforms
if (process.env?.EXPO_TV === "1") {
const originalSourceExts = config.resolver.sourceExts;
config.resolver.sourceExts = [
...originalSourceExts.map((e) => `tv.${e}`),
...originalSourceExts,
];
}
module.exports = config;
{
"name": "mytvproject",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "EXPO_TV=1 npx expo start",
"android": "EXPO_TV=1 npx expo run:android --device",
"ios": "EXPO_TV=1 npx expo run:ios",
"web": "EXPO_TV=1 npx expo start --web",
"prebuild": "EXPO_TV=1 npx expo prebuild --clean && ./scripts/fix-tvos-deployment.sh",
"clean": "rm -rf node_modules android ios .expo"
},
"dependencies": {
"@myapp/shared": "*",
"expo": "~52.0.0",
"expo-build-properties": "~0.13.0",
"expo-router": "~4.0.0",
"react": "18.3.1",
"react-native": "npm:react-native-tvos@~0.76.0-0"
},
"devDependencies": {
"@react-native-tvos/config-tv": "~0.0.12"
}
}
Expo TV Package Configuration
Critical Settings
Package Name
name: "mytvproject"- The workspace package name referenced by root scripts
scripts
- All scripts MUST use
EXPO_TV=1environment variable --deviceflag on android avoids conflicts with Vega simulatorwebscript usesexpo start --webfor web target
dependencies
react-native: "npm:react-native-tvos@~0.76.0-0"- Uses react-native-tvos fork@myapp/shared: "*"- Always uses local workspace versionexpo-router: "~4.0.0"- File-based routing
Target Versions
- Expo SDK: ~52.0.0
- react-native-tvos: ~0.76.0-0
- React: 18.3.1
- expo-router: ~4.0.0
Customization
Replace @myapp with your project namespace in the shared dependency
{
"name": "@myapp/workspace",
"version": "0.1.0",
"description": "Monorepo for MyApp across Vega and Expo TV",
"scripts": {
"clean": "yarn workspaces foreach --all run clean ; rm -rf node_modules",
"vega:build": "yarn workspace @myapp/vega run build:debug",
"expotv": "yarn workspace mytvproject",
"expotv:prebuild": "yarn workspace mytvproject run prebuild",
"expotv:android": "yarn workspace mytvproject run android",
"expotv:ios": "yarn workspace mytvproject run ios",
"expotv:web": "yarn workspace mytvproject run web"
},
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/react",
"**/react-dom",
"**/react-native",
"**/react-native/**"
]
},
"private": true,
"packageManager": "yarn@4.5.0+sha512.837566d24eec14ec0f5f1411adb544e892b3454255e61fdef8fd05f3429480102806bac7446bc9daff3896b01ae4b62d00096c7e989f1596f2af10b927532f39"
}{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"lib": ["es2019"],
"jsx": "react-native",
"strict": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"exclude": ["node_modules"]
}{
"name": "@myapp/shared",
"version": "0.0.1",
"description": "Shared app code",
"main": "src/index.ts",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
}
Migration Validation Checklist
Use this checklist to verify each phase is complete before proceeding.
Phase 1: Analysis ✓
- [ ] Project structure documented
- [ ] All dependencies classified (Category A, B, C)
- [ ] Screen-by-screen analysis complete
- [ ] Services inventory created
- [ ] Native modules identified
- [ ] Migration phases defined
- [ ] Effort estimates provided
- [ ] Risk assessment complete
- [ ] Analysis document reviewed and approved
Before proceeding to Phase 2:
- [ ] Stakeholders have reviewed the analysis
- [ ] Any descoping decisions have been made
- [ ] Development environment is ready
---
Phase 2: Implementation ✓
Step 2A: Scaffold Monorepo
- [ ] Root workspace configured with Yarn 4.5+
- [ ] Root
tsconfig.jsoncreated (required by Expo CLI) - [ ]
.yarnrc.ymlhasnmHoistingLimits: workspaces - [ ] Shared package created with
"main": "src/index.ts" - [ ] Shared package has barrel exports (
src/index.ts) - [ ] Code copied to shared package per Phase 1 analysis
- [ ] Vega package references
@myapp/shared - [ ] Metro configs updated for monorepo resolution
- [ ] Vega builds successfully with original imports
- [ ] Duplicated code removed from vega package
- [ ] Babel config aliases updated to point to shared
- [ ] TypeScript paths updated to point to shared
- [ ] Vega builds and runs after cleanup
Step 2B: Component Extraction (Optional)
- [ ] Decision made: extract now or defer to Phase 3?
- [ ] If extracting now:
- [ ] Shared components identified
- [ ] Platform-specific implementations created
- [ ] Components exported from
@myapp/shared - [ ] Screens updated to use shared components
- [ ] Vega builds and runs with extracted components
Step 2C: VMRP / Generic Imports
- [ ] Shared package imports refactored to standard library names
- [ ] VMRP configured in vega
babel.config.js - [ ] Both library versions added to vega
package.json - [ ] Kepler-only components kept in vega package
- [ ] Vega builds successfully with refactored imports
- [ ] All tests pass
- [ ] App runs identically to before migration
Before proceeding to Phase 3:
- [ ] Vega app is stable and fully functional
- [ ] No regressions from original app
- [ ] Code review completed
- [ ] CI/CD updated for monorepo (if applicable)
---
Phase 3: Platform Support ✓
Expo TV Setup
- [ ] Root
tsconfig.jsonexists (from Phase 2) - [ ] Expo TV package created
- [ ]
app.jsonconfigured with correct plugins - [ ]
package.jsonhas correct Expo 52 dependencies - [ ] Metro config set up for monorepo + TV extensions
- [ ] Babel config created
- [ ]
@myapp/shareddependency added - [ ]
yarn expotv:prebuildsucceeds
Android TV
- [ ] Prebuild generates Android project
- [ ] Kotlin version set to 1.9.25
- [ ] App launches on Android TV emulator
- [ ] All screens render without crashes
- [ ] Navigation works correctly
- [ ] Focus management works
- [ ] Scaling utility applied to shared components
- [ ] Core functionality tested
Apple TV
- [ ] Prebuild generates iOS project
- [ ] tvOS deployment target set to 15.1+
- [ ] Fix script created (if needed)
- [ ] App launches on Apple TV simulator
- [ ] All screens render without crashes
- [ ] Navigation works correctly
- [ ] Focus management works
- [ ] Core functionality tested
Platform-Specific Implementations
- [ ] All Vega dependencies have replacements identified
- [ ] Platform-specific files created where needed
- [ ] Video player implemented (if applicable)
- [ ] DRM implemented (if applicable)
- [ ] Native modules implemented (if applicable)
- [ ] Platform-specific services implemented
Testing & Validation
- [ ] Unit tests pass on all platforms
- [ ] Integration tests pass on all platforms
- [ ] Manual testing completed on physical devices
- [ ] Performance acceptable on all platforms
- [ ] No memory leaks detected
- [ ] Error handling works correctly
Final Validation:
- [ ] All three platforms build successfully
- [ ] All three platforms run without crashes
- [ ] Core features work on all platforms
- [ ] Code reuse target achieved (70-85%)
- [ ] Documentation updated
- [ ] Team trained on new structure
---
Post-Migration
- [ ] CI/CD pipelines updated
- [ ] Deployment process documented
- [ ] Monitoring and analytics configured
- [ ] Team onboarding materials created
- [ ] Architecture decision records (ADRs) written
- [ ] Performance benchmarks established
- [ ] Rollback plan documented
---
Troubleshooting Reference
If you encounter issues, check:
- Metro resolution errors: Verify
watchFoldersandnodeModulesPathsin metro.config.js - Duplicate React versions: Check
.yarnrc.ymlhasnmHoistingLimits: workspaces - VMRP mapping errors: Verify babel.config.js and library versions
- Expo prebuild failures: Review app.json configuration
- tvOS deployment errors: Run fix-tvos-deployment.sh script
- Focus issues: Check platform-specific focus implementations
- Scaling issues: Verify scaling utility is applied to all hardcoded values
For detailed troubleshooting, see the phase reference documents.
const path = require("path");
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const config = {
// Watch parent directory (packages/) to enable hot reload for shared package
watchFolders: [path.resolve(__dirname, "..")],
resolver: {
// Resolve dependencies from local, parent, and root node_modules
// Required for monorepo to find shared package and its dependencies
nodeModulesPaths: [
path.resolve(__dirname, "node_modules"),
path.resolve(__dirname, "../node_modules"),
path.resolve(__dirname, "../../node_modules"),
],
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
nodeLinker: node-modules
# CRITICAL: Prevent hoisting to keep workspace dependencies isolated
# This prevents React/React Native version conflicts between Vega (RN 0.72) and Expo TV (RN 0.76)
# Each workspace gets its own node_modules with correct versions
nmHoistingLimits: workspaces
MIT License
Copyright (c) 2025 Vega Skills
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Vega Shared Workspace Migration Analysis
Guidance for analyzing Vega React Native codebases for conversion to a shared workspace (monorepo). The monorepo enables code reuse across Vega, Android TV, and Apple TV while keeping platform-specific implementations where necessary.
When to Use
- Planning multi-platform TV support from a single codebase
- Evaluating migration complexity before committing resources
- Maximizing code reuse between Vega and Stock React Native
Target Monorepo Structure
myapp/
├── package.json # Root workspaces config
├── tsconfig.json # Shared TypeScript config
├── .yarnrc.yml # Yarn 4 config
├── packages/
│ ├── shared/ # @myapp/shared
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── index.ts # Barrel exports
│ │ └── src/
│ │ ├── assets/ # Shared images, animations
│ │ ├── components/ # Shared UI components
│ │ ├── hooks/ # Shared custom hooks
│ │ ├── providers/ # Context providers
│ │ ├── reactquery/ # React Query hooks/config
│ │ ├── services/ # API/business logic
│ │ └── utils/
│ ├── vega/ # @myapp/vega
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── metro.config.js
│ │ ├── manifest.toml
│ │ └── src/
│ │ ├── components/ # Vega-specific components
│ │ ├── navigation/
│ │ └── screens/ # Screen containers
│ └── expotv/ # @myapp/expotv
│ ├── package.json
│ ├── tsconfig.json
│ ├── app.json # Expo config
│ ├── metro.config.js
│ ├── app/ # Expo Router screens
│ │ ├── _layout.tsx
│ │ └── (tabs)/ # Tab-based navigation
│ ├── assets/ # Expo TV-specific assets
│ ├── components/ # Expo TV-specific components
│ ├── constants/ # Theme constants
│ ├── hooks/ # Platform-specific hooks
│ └── layouts/ # Layout componentsRoot workspaces config uses nohoist for React/React Native to avoid duplicate module issues in native builds.
Key constraint: vega/expotv import FROM shared, but shared CANNOT import from vega/expotv. Use dependency injection when shared code needs platform behavior.
Dependency Classification
Categorize all @amazon-devices/* dependencies into three categories.
Category A: JS Implementations → Shared Package
Pure JavaScript/TypeScript with no native code: custom hooks, utilities, UI components wrapping platform APIs, state management (Zustand, Context), business logic services.
Category B: VMRP-Compatible → Shared Package
Use standard import paths in shared code. VMRP maps them to @amazon-devices/* at bundle time for Vega.
| Standard Import | Vega Equivalent |
|---|---|
react-native-reanimated | @amazon-devices/react-native-reanimated |
react-native-gesture-handler | @amazon-devices/react-native-gesture-handler |
react-native-screens | @amazon-devices/react-native-screens |
react-native-safe-area-context | @amazon-devices/react-native-safe-area-context |
react-native-linear-gradient | @amazon-devices/react-native-linear-gradient |
react-native-svg | @amazon-devices/react-native-svg |
react-native-fast-image | @amazon-devices/react-native-fast-image |
react-native-device-info | @amazon-devices/react-native-device-info |
react-native-vector-icons | @amazon-devices/react-native-vector-icons |
react-native-mmkv | @amazon-devices/react-native-mmkv |
react-native-qrcode-svg | @amazon-devices/react-native-qrcode-svg |
lottie-react-native | @amazon-devices/lottie-react-native |
@react-navigation/* | @amazon-devices/react-navigation-* |
@react-native-async-storage/async-storage | @amazon-devices/async-storage |
@react-native-cookies/cookies | @amazon-devices/cookies |
@react-native-masked-view/masked-view | @amazon-devices/masked-view |
expo-* libraries | Various @amazon-devices/expo-* |
TV Focus APIs share the same API across Vega and react-native-tvos: TVFocusGuideView, nextFocusUp/Down/Left/Right, hasTVPreferredFocus, isTVSelectable.
Category C: Requires Native Implementation → Platform Package
These MUST remain in the vega package. Other platforms need native implementations (Kotlin/Swift):
@amazon-devices/headless-task-manager
@amazon-devices/kepler-player-server
@amazon-devices/kepler-player-client
@amazon-devices/keplerscript-turbomodule-api
@amazon-devices/react-native-w3cmedia
@amazon-devices/asset-resolver-lib
@amazon-devices/kepler-channel
@amazon-devices/kepler-epg-provider
@amazon-devices/kepler-epg-sync-scheduler
@amazon-devices/kepler-performance-api
@amazon-devices/kepler-media-controls
@amazon-devices/kepler-media-types
@amazon-devices/kepler-ui-components
@amazon-devices/keplerscript-audio-lib
@amazon-devices/keplerscript-kepleri18n-lib
@amazon-devices/keplerscript-netmgr-lib
@amazon-devices/kepler-cli-platform
@amazon-devices/kepler-file-system
@amazon-devices/kepler-media-account-login
@amazon-devices/kepler-media-content-launcher
@amazon-devices/keplerscript-appstore-iap-lib
@amazon-devices/security-manager-lib@amazon-devices/react-native-kepler is a special case—it belongs in the vega package, but most components using it go in shared since they map 1:1 to @react-native-tvos.
Screen Analysis
For each screen, determine placement:
- Container → Shared: Entire screen is platform-agnostic
- Container → Vega, Components → Shared: Container has platform-specific logic, child components are reusable
Common pattern:
vega/screens/HomeScreen.tsx → platform-specific container
└── imports <HomeContent /> → from shared/
└── uses <ContentRow /> → from shared/
└── uses <HeroCard /> → from shared/Per-Screen Documentation
For each screen, capture: file path, complexity rating, container placement, Vega dependencies used, migration path per dependency, native code requirements.
Complexity ratings:
| Rating | Criteria |
|---|---|
| Low | No native deps, standard UI patterns |
| Medium | Some VMRP-compatible deps, moderate state |
| High | Multiple native deps, complex navigation |
| Critical | Heavy native integration (player, EPG) |
Component Extraction
For shared components: purpose, required props/callbacks, platform-specific dependencies.
For platform-specific components: why it can't be shared, common interface both platforms use, whether to use file extensions (.android.tsx, .kepler.tsx).
Example:
SelectUserProfile Screen:
├── Shared: Layout, styling, props interface (profiles[], onSelect, onAdd)
├── Vega: <Avatar> from kepler-ui-components
├── Android: <Image> + Pressable with onFocus/onBlur
└── Use SelectUserProfile.kepler.tsx / .android.tsxServices Inventory
Identify services referenced by 2+ screens. Services with no Vega dependencies are prime shared candidates.
| Service | Used By | Vega Dependencies | Placement |
|---|---|---|---|
| AuthService | Login, Home, Settings | None | Shared |
| PlayerService | Details, Player | kepler-player-client | Vega |
| AnalyticsService | All screens | None | Shared |
Pre-Migration Refactoring
Recommend light refactoring before migration only if:
- 2+ screens tightly mix platform-specific logic with UI rendering
- Duplicated patterns (loading states, error handling) appear 3+ times
- No clear prop boundaries between platform-specific and platform-agnostic code
Refactoring scope: extract content components from screens, define prop interfaces between container and content. Do NOT restructure folders or change navigation.
Migration Phases
Group screens by dependency complexity:
1. Foundation — Scaffolding, shared navigation, theme, core utilities, auth flow 2. Core UI Components — Shared buttons, cards, lists, modals with platform-specific implementations where needed 3. Content/Browse Screens — Home, browse, search, details (read-heavy, standard UI) 4. Interactive Features — Settings, profiles, favorites, watchlists (state management, limited native) 5. Media Playback — Player, controls, progress tracking (heavy native, most complex)
Effort Estimation
Typical code reuse percentages:
| Category | Expected Reuse |
|---|---|
| Services | 70-90% |
| Utilities/Hooks | 80-95% |
| Components | 50-70% |
| Screens | 30-50% |
| Overall | 50-70% |
Analysis Output Format
Use this as a sensible default structure, adapting sections based on what the analysis reveals:
# [PROJECT NAME] → MONOREPO MIGRATION ANALYSIS
## Executive Summary
[2-3 sentences on complexity and key challenges]
**Estimated Code Reuse: ~XX-XX% overall**
## 1. Project Overview
## 2. Vega Dependency Classification (A/B/C)
## 3. Screen-by-Screen Dependency Mapping
## 4. Services Inventory
## 5. Migration Phases
## 6. Native Modules Required
## 7. Estimated Effort
## 8. Risk Assessment
## 9. Next StepsKey Rules
- Start with screens having fewest native dependencies
- Validate Vega builds after each change
- Use platform file extensions (
.vega.tsx,.android.tsx) for divergent implementations - Do NOT migrate player/media screens first
- Do NOT over-abstract before understanding platform differences
Related Documents
- Implementation: PHASE2_IMPLEMENTATION.md
- Platform support: PHASE3_PLATFORM_SUPPORT.md
- Templates: assets/templates/
Vega Shared Workspace Conversion
Convert an existing Vega OS project to a yarn workspaces monorepo enabling code reuse across Vega, Android TV, and Apple TV.
Prerequisites
- Completed Phase 1 analysis document (see PHASE1_ANALYSIS.md)
- Source Vega project path
- Target monorepo destination path
Tools
| Tool | Version | Purpose |
|---|---|---|
| yarn | 4.5.0+ | Package manager with workspaces |
| node | 18.x+ | JavaScript runtime |
| metro | 0.72.x | React Native bundler |
| babel | 7.x | JavaScript compiler with VMRP preset |
yarn init -2 # Initialize yarn 4
yarn set version stable # Set to latest stable
yarn install # Install dependencies
yarn workspace @myapp/vega run <script> # Run vega package scriptsConversion Parts
| Part | Description | Checkpoint |
|---|---|---|
| A | Scaffold monorepo, preserve original imports | Vega builds identically |
| B | Screen-by-screen component extraction (optional) | Shared components work |
| C | Refactor to generic imports via VMRP | Platform-agnostic shared code |
Replace myapp with project name throughout.
Target Structure
myapp/
├── package.json # Root workspace config
├── tsconfig.json # Required by Expo CLI
├── .yarnrc.yml # Yarn 4 config
├── packages/
│ ├── shared/ # @myapp/shared
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── index.ts # Barrel exports
│ │ └── src/
│ │ ├── assets/ # Shared images, animations
│ │ ├── components/ # Shared UI (with platform extensions)
│ │ ├── hooks/ # Shared custom hooks
│ │ ├── providers/ # Context providers
│ │ ├── reactquery/ # React Query hooks/config
│ │ ├── services/ # API clients, business logic
│ │ └── utils/ # Utility functions (scaling, math, etc.)
│ ├── vega/ # @myapp/vega
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ ├── metro.config.js
│ │ ├── babel.config.js
│ │ ├── manifest.toml
│ │ ├── index.js
│ │ └── src/
│ │ ├── App.tsx # Main app entry
│ │ ├── assets/ # Vega-specific assets
│ │ ├── components/ # Vega-specific components
│ │ ├── navigation/ # Navigation config
│ │ └── screens/ # Screen containers
│ └── expotv/ # @myapp/expotv
│ ├── package.json
│ ├── tsconfig.json
│ ├── metro.config.js
│ ├── app.json # Expo config
│ ├── app/ # Expo Router screens
│ │ ├── _layout.tsx
│ │ └── (tabs)/ # Tab-based navigation
│ ├── assets/ # Expo TV-specific assets
│ ├── components/ # Expo TV-specific components
│ ├── constants/ # Theme constants (Colors, TextStyles)
│ ├── hooks/ # Platform-specific hooks (useScale, useColorScheme)
│ └── layouts/ # Layout components (TabLayout)Configuration Templates
All templates in assets/templates/ with companion .md docs for critical settings. Templates are referenced in each Part below where they're needed.
Expo TV templates:
- package.json — Template | Docs
- app.json — Template | Docs
- metro.config.js — Template
Part A: Scaffold Monorepo
Create the monorepo structure, move code per Phase 1 analysis, keep all @amazon-devices/* imports unchanged.
Directory Setup
mkdir myapp
cd myapp
yarn init -2
yarn set version stable
mkdir -p packages/shared/src/{assets,components,hooks,providers,reactquery,services,utils}
mkdir -p packages/vega/src/{assets,components,navigation,screens}
mkdir -p packages/expotv/{app,assets,components,constants,hooks,layouts}
mkdir -p packages/expotv/app/\(tabs\)
mkdir -p packages/expotv/assets/{fonts,images,tv_icons}
mkdir -p packages/expotv/components/navigation
mkdir -p packages/expotv/scriptsConfiguration Files
Apply templates from assets/templates/:
1. Root package.json — Template: workspaces config with nohoist for React/React Native 2. Root tsconfig.json — Template: required by Expo CLI 3. .yarnrc.yml — Template: MUST have nmHoistingLimits: workspaces 4. Shared package.json — Template: ONLY peerDependencies, no devDependencies for react/react-native 5. Vega metro.config.js — Template: monorepo resolution with watchFolders
Shared Package Barrel Exports
packages/shared/index.ts (at package root, not in src/):
// Re-export from src modules
export * from "./src/components/Banner";
export * from "./src/components/HomeScreen";
export * from "./src/utils/scaling";
export * from "./src/services/httpClient";
// Add more exports as neededpackages/shared/src/index.ts (optional, for internal use):
export { Banner } from "./components/Banner";
export { HomeScreen } from "./components/HomeScreen";
export { scaleWidth, scaleHeight } from "./utils/scaling";Vega Package Setup
Copy existing Vega project to packages/vega/. Add shared dependency to packages/vega/package.json:
{
"name": "@myapp/vega",
"dependencies": {
"@myapp/shared": "*"
}
}The * version ensures Yarn uses the local workspace version.
Code Migration
Per Phase 1 analysis, move to packages/shared/src/:
- Category A dependencies (JS-only)
- Category B dependencies (VMRP-compatible)
- Shared components, hooks, services, utils
Keep original @amazon-devices/* imports unchanged. Update consumer imports to use @myapp/shared:
import { Banner, useFocusState } from "@myapp/shared";Platform-specific files use extensions:
components/
├── BannerLogo.tsx # Default/fallback
├── BannerLogo.kepler.tsx # Vega-specific
├── BannerLogo.android.tsx # Android TV
├── BannerLogo.ios.tsx # Apple TV
└── BannerLogo.web.tsx # WebCheckpoint: yarn install && yarn vega:build — app builds and runs identically to before.
Part B: Component Extraction (Optional)
Skip if extracting components later during Phase 3.
For each screen: 1. Identify shared UI vs platform-specific components 2. Create shared component with platform-agnostic props 3. Create platform-specific implementations where needed (.kepler.tsx, .android.tsx) 4. Update screen to import from shared 5. Verify on Vega
Platform-Specific Strategies
Strategy 1: File Extensions
Metro resolves the correct file based on target platform:
Component.tsx # Default/fallback
Component.kepler.tsx # Vega
Component.android.tsx # Android TV
Component.ios.tsx # Apple TVUse when: implementation differs significantly but API is identical.
Strategy 2: Inline Conditionals
import { Platform } from "react-native";
const padding = Platform.select({ kepler: 20, android: 16, web: 24 });Use when: small styling or feature flag differences.
Strategy 3: Screen Container Pattern
vega/screens/HomeScreen.tsx → Platform container
expotv/screens/HomeScreen.tsx → Platform container
└── both import <HomeContent /> → from @myapp/sharedUse when: screens have platform-specific navigation/lifecycle but share visual layout. Also for components requiring different native modules (VideoPlayer, MediaControls).
Strategy 4: VMRP
Write standard React Native imports; VMRP maps to @amazon-devices/* at bundle time:
// Shared code writes:
import Animated from "react-native-reanimated";
// VMRP resolves to @amazon-devices/react-native-reanimated on VegaUse when: third-party libraries have Vega-ported equivalents.
Strategy Selection
| Scenario | Strategy |
|---|---|
| Different native implementations | File Extensions |
| Minor styling/feature differences | Inline Conditionals |
| Platform-specific navigation/lifecycle | Screen Container |
| Platform-specific native modules (VideoPlayer) | Screen Container |
| Third-party library with Vega port | VMRP |
Part C: VMRP Configuration
Refactor shared package to standard React Native imports. VMRP handles mapping to @amazon-devices/* at bundle time.
1. Add VMRP Dependencies
packages/vega/package.json devDependencies:
{
"devDependencies": {
"@amazon-devices/kepler-module-resolver-preset": "^0.1.15",
"babel-plugin-module-resolver": "^5.0.2"
}
}2. Configure Babel
packages/vega/babel.config.js:
module.exports = {
presets: [
"module:metro-react-native-babel-preset",
"module:@amazon-devices/kepler-module-resolver-preset",
],
plugins: [["@babel/plugin-transform-react-jsx", { runtime: "automatic" }]],
};3. Add Both Library Versions
For each VMRP-compatible library, add both standard and Vega versions to packages/vega/package.json:
{
"dependencies": {
"react-native-reanimated": "3.5.4",
"@amazon-devices/react-native-reanimated": "~2.0.0",
"react-native-gesture-handler": "2.13.0",
"@amazon-devices/react-native-gesture-handler": "2.0.0+2.13.0",
"@react-navigation/native": "6.1.9",
"@amazon-devices/react-navigation__native": "^2.0.0"
}
}4. Refactor Shared Imports
Change from @amazon-devices/* to standard imports:
// Before
import Animated from "@amazon-devices/react-native-reanimated";
// After
import Animated from "react-native-reanimated";Checkpoint: yarn install && yarn vega:build — shared code uses standard imports, ready for other platforms.
Expo TV Scaffold
The Expo TV package uses Expo Router for file-based routing. It will NOT fully work until platform dependencies are implemented in Phase 3.
packages/expotv/package.json:
{
"name": "mytvproject",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "EXPO_TV=1 npx expo start",
"android": "EXPO_TV=1 npx expo run:android --device",
"ios": "EXPO_TV=1 npx expo run:ios",
"web": "EXPO_TV=1 npx expo start --web",
"prebuild": "EXPO_TV=1 npx expo prebuild --clean && ./scripts/fix-tvos-deployment.sh",
"clean": "rm -rf node_modules android ios .expo"
},
"dependencies": {
"@myapp/shared": "*",
"expo": "~52.0.0",
"expo-build-properties": "~0.13.0",
"expo-router": "~4.0.0",
"react": "18.3.1",
"react-native": "npm:react-native-tvos@~0.76.0-0"
},
"devDependencies": {
"@react-native-tvos/config-tv": "~0.0.12"
}
}Root scripts reference by package name:
{
"scripts": {
"expotv": "yarn workspace mytvproject",
"expotv:prebuild": "yarn workspace mytvproject run prebuild",
"expotv:android": "yarn workspace mytvproject run android",
"expotv:ios": "yarn workspace mytvproject run ios",
"expotv:web": "yarn workspace mytvproject run web"
}
}packages/expotv/app.json:
{
"expo": {
"name": "MyAppTV",
"slug": "myapp-tv",
"orientation": "landscape",
"platforms": ["android", "ios"],
"scheme": "myapp-tv",
"plugins": [
"@react-native-tvos/config-tv",
["expo-build-properties", {
"android": { "kotlinVersion": "1.9.25" },
"ios": { "deploymentTarget": "15.1" }
}],
"expo-router"
]
}
}Migration Checklist
Part A
- [ ] Root workspace configured with yarn 4.5
- [ ] Root tsconfig.json created
- [ ] .yarnrc.yml has
nmHoistingLimits: workspaces - [ ] Shared package created with barrel exports
- [ ] Code moved to shared per Phase 1 analysis
- [ ] Vega package references
@myapp/shared - [ ] Metro config updated for monorepo
- [ ] Vega builds and runs
Part B (Optional)
- [ ] Shared components extracted
- [ ] Platform-specific implementations created where needed
- [ ] Vega builds with extracted components
Part C
- [ ] VMRP configured in babel.config.js
- [ ] Both library versions in vega package.json
- [ ] Shared imports refactored to standard names
- [ ] Vega builds with refactored imports
Common Issues
| Issue | Solution |
|---|---|
| Yarn 3.x or lower installed | corepack enable && yarn set version stable |
| Node.js < 20 | Upgrade to Node.js 20+; use nvm install --lts && nvm use --lts |
| Wrong yarn version used in CI | Add "packageManager": "yarn@4.5.0" to root package.json |
| node_modules not found after install | Ensure .yarnrc.yml has nodeLinker: node-modules (Yarn 4 defaults to PnP) |
| Metro can't resolve shared | Configure watchFolders and nodeModulesPaths in metro.config.js |
| Symlink resolution failures | Add resolver.unstable_enableSymlinks: true to metro.config.js |
| Duplicate React versions | Verify .yarnrc.yml has nmHoistingLimits: workspaces |
Can't find @myapp/shared at runtime | Verify "@myapp/shared": "*" in consumer's dependencies, not just imports |
| Workspace changes not detected | Run yarn install after modifying any workspace package.json |
| Lint/type errors in shared package | Add dependencies as devDependencies in shared's package.json (not just peerDependencies) |
| TypeScript path aliases not resolving | Add paths mapping in root tsconfig.json for @myapp/* packages |
| Kepler imports fail in shared | Use .kepler.tsx extension or move to vega package |
| Babel cache stale after VMRP changes | Run yarn vega run clean or delete node_modules/.cache |
| Native module version mismatch | Ensure native deps (reanimated, gesture-handler) have identical versions across all packages |
Related Documents
- Analysis (previous phase): PHASE1_ANALYSIS.md
- Platform dependencies (next phase): PHASE3_PLATFORM_SUPPORT.md
- Templates: assets/templates/
Vega Shared Workspace Platform Dependencies
Implement Android TV and Apple TV support for a Vega shared workspace monorepo by replacing Vega-specific dependencies with Stock React Native equivalents.
Prerequisites
- Completed Phase 1 analysis (see PHASE1_ANALYSIS.md)
- Completed Phase 2 monorepo setup (see PHASE2_IMPLEMENTATION.md)
- Vega build working in monorepo
- Root
tsconfig.jsonexists
Tools
| Tool | Version | Purpose |
|---|---|---|
| expo | ~52.0.0 | Expo SDK for TV builds |
| react-native-tvos | ~0.76.0-0 | React Native fork for TV |
| @react-native-tvos/config-tv | ~0.0.12 | TV configuration plugin |
| expo-build-properties | ~0.13.0 | Build configuration |
yarn expotv:prebuild # Generate native projects
yarn expotv:android # Run on Android TV
yarn expotv:ios # Run on Apple TVScaffold Expo TV Package
If packages/expotv/ doesn't exist, create the structure and apply templates:
mkdir -p packages/expotv/{assets,components,constants,hooks,layouts}
mkdir -p packages/expotv/app/\(tabs\)
mkdir -p packages/expotv/assets/{fonts,images,tv_icons}
mkdir -p packages/expotv/components/navigation
mkdir -p packages/expotv/scriptsApply templates from assets/templates/:
- package.json — Template | Docs
- app.json — Template | Docs
- metro.config.js — Template
The expotv package typically uses a simple name (mytvproject) rather than scoped. Root package.json scripts reference it by package name:
{
"scripts": {
"expotv": "yarn workspace mytvproject",
"expotv:prebuild": "yarn workspace mytvproject run prebuild",
"expotv:android": "yarn workspace mytvproject run android",
"expotv:ios": "yarn workspace mytvproject run ios",
"expotv:web": "yarn workspace mytvproject run web"
}
}The package uses Expo Router for file-based routing:
app/_layout.tsx— Root layout with providersapp/(tabs)/_layout.tsx— Tab navigation layoutapp/(tabs)/index.tsx— Home screen
Dependency Replacements
Reference Phase 1 "Category C" dependencies. For each, find a replacement:
| Vega Package | Android/Expo Replacement | Notes |
|---|---|---|
@amazon-devices/react-native-kepler | react-native-tvos + @react-navigation/native | Focus handling, TV navigation |
@amazon-devices/kepler-player-client | react-native-video | Video playback |
@amazon-devices/react-native-w3cmedia | react-native-video or expo-av | Media APIs |
@amazon-devices/kepler-ui-components | Custom components | Rebuild with RN primitives |
@amazon-devices/kepler-file-system | expo-file-system | File operations |
@amazon-devices/keplerscript-netmgr-lib | @react-native-community/netinfo | Network state |
@amazon-devices/security-manager-lib | expo-secure-store | Secure storage |
Scaling Utility
Android TV renders at different resolutions than Vega (1920x1080). Add to shared package:
packages/shared/src/utils/scaling.ts:
import { Dimensions, PixelRatio } from "react-native";
const { width: SCREEN_WIDTH } = Dimensions.get("window");
const BASE_WIDTH = 1920;
const WIDTH_SCALE = SCREEN_WIDTH / BASE_WIDTH;
export const scaleWidth = (size: number): number =>
PixelRatio.roundToNearestPixel(WIDTH_SCALE * size);
export const scaleHeight = (size: number): number =>
PixelRatio.roundToNearestPixel(WIDTH_SCALE * size);
export const scaleFontSize = (size: number): number =>
PixelRatio.roundToNearestPixel(WIDTH_SCALE * size);Export from packages/shared/index.ts:
export { scaleWidth, scaleHeight, scaleFontSize } from "./src/utils/scaling";On Vega (1920x1080), WIDTH_SCALE = 1.0 (no effect). On Android TV at 1280x720, WIDTH_SCALE ≈ 0.67.
Apply to all hardcoded pixel values in shared components:
import { scaleWidth, scaleFontSize } from "@myapp/shared";
const styles = StyleSheet.create({
card: { width: scaleWidth(320), height: scaleHeight(180), marginRight: scaleWidth(30) },
title: { fontSize: scaleFontSize(32) },
});The Expo TV package may also have its own hooks/useScale.ts with web support (useScale.web.ts).
Reanimated limitation: Scaling functions cannot be called inside useAnimatedStyle worklets. Pre-calculate scaled values outside the worklet.
Focus State Handling
TV Focus APIs are largely the same across Vega and react-native-tvos:
| Vega Approach | Android TV Equivalent |
|---|---|
hasTVPreferredFocus | Same in react-native-tvos |
FocusGuideView | TVFocusGuideView from react-native-tvos |
| kepler-ui focus styling | Pressable onFocus/onBlur with state |
Example focus state pattern:
const [isFocused, setIsFocused] = useState(false);
<Pressable
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
style={[styles.card, isFocused && styles.cardFocused]}
>Platform Strategy Selection
| Scenario | Strategy |
|---|---|
| Significantly different implementations | File extensions (.android.tsx, .kepler.tsx) |
| Small styling differences | Inline Platform.OS conditionals |
| Heavy native dependencies | Screen Container pattern |
Build Android TV
yarn expotv:prebuild
yarn expotv:androidBuild Apple TV
Fix tvOS Deployment Target
expo-build-properties doesn't always update tvOS deployment targets. ExpoModulesCore requires tvOS 15.1+. Try building first — only apply this fix if you see deployment target errors.
Create packages/expotv/scripts/fix-tvos-deployment.sh:
#!/bin/bash
set -e
echo "🔧 Fixing tvOS deployment targets..."
cd "$(dirname "$0")/../ios"
APP_NAME=$(ls -d *.xcodeproj 2>/dev/null | head -1 | sed 's/.xcodeproj//')
if [ -z "$APP_NAME" ]; then
echo "❌ No .xcodeproj found"; exit 1
fi
sed -i '' 's/TVOS_DEPLOYMENT_TARGET = 1[0-3]\.[0-4];/TVOS_DEPLOYMENT_TARGET = 15.1;/g' "${APP_NAME}.xcodeproj/project.pbxproj"
sed -i '' 's/TVOS_DEPLOYMENT_TARGET = 1[0-3]\.[0-4];/TVOS_DEPLOYMENT_TARGET = 15.1;/g' Pods/Pods.xcodeproj/project.pbxproj 2>/dev/null || true
echo "✅ tvOS deployment targets updated to 15.1"chmod +x packages/expotv/scripts/fix-tvos-deployment.sh
yarn expotv:prebuild
yarn expotv:iosThe expotv package.json template already chains this script into the prebuild command.
Expo 52 Library Version Overrides
Some VMRP library versions must be overridden in packages/expotv/package.json to match Expo 52:
| Library | VMRP Version | Expo 52 Version |
|---|---|---|
| react-native-reanimated | 3.5.4 | ~3.16.1 |
| react-native-svg | 13.14.0 | ~15.8.0 |
| react-native-gesture-handler | 2.13.0 | ~2.20.2 |
| react-native-vector-icons | 9.2.0 | ^10.2.0 |
| lottie-react-native | 6.0.0-rc.1 | ^6.7.0 |
| @shopify/flash-list | 1.6.3 | ^1.7.2 |
The shared package uses standard imports. Vega resolves to its versions via VMRP, Expo TV uses the versions above.
Verification Checklist
Android TV
- [ ] All Vega dependencies have replacements identified
- [ ] Platform-specific files created where needed
- [ ]
yarn expotv:prebuildsucceeds - [ ] App launches on Android TV emulator/device
- [ ] All screens render without crashes
- [ ] Navigation works
- [ ] Media playback works (if applicable)
Apple TV
- [ ] tvOS deployment target set to 15.1+
- [ ]
yarn expotv:ioslaunches on Apple TV simulator - [ ] All screens render without crashes
- [ ] Navigation works
- [ ] Media playback works (if applicable)
Common Issues
| Issue | Solution |
|---|---|
| Kotlin version mismatch | Add expo-build-properties with kotlinVersion: "1.9.25" |
| tvOS deployment target error | Run fix-tvos-deployment.sh script |
| Reanimated babel error | Add react-native-reanimated/plugin to babel.config.js |
| Missing icon | Create ./assets/icon.png or update path in app.json |
| Library incompatibility | Use Expo 52 compatible versions from table above |
| Expo prebuild fails with workspace deps | Run yarn install from root before prebuild |
| iOS pod install fails in monorepo | Add node_modules paths to Podfile's react_native_post_install |
Related Documents
- Analysis: PHASE1_ANALYSIS.md
- Monorepo conversion: PHASE2_IMPLEMENTATION.md
- Templates: assets/templates/
Related skills
How it compares
Pick vega-multi-tv-migration over generic Expo setup skills when the deliverable is television targets rather than standard iOS and Android phone builds.
FAQ
Where start if no migration analysis exists?
Start Phase 1 analysis to classify shared versus platform-specific dependencies.
What monorepo folders should exist?
Verify packages/shared, packages/vega, and packages/expotv with Yarn workspaces configured.
How fix duplicate React versions?
Follow Phase 2 implementation guidance for .yarnrc.yml dependency deduplication.
Is Vega Multi Tv Migration safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.