Skip to content

Artemis-Switch: A streamed frame from host to screen

Artemis-Switch is a fork in the Moonlight streaming family. The host runs the game; the client receives compressed video and audio while sending controller input back. Rendering a frame is only one part of that round trip.

Hardware and graphics Fork
  • Updated
  • 29
  • C++ · 53.78%
  • GPL-3.0
Upstream credited
Repository languagesC++ 53.78%11

Shares calculated from GitHub Linguist bytes.

Language%Bytes
C++53.78%2,312,036
C33.23%1,428,795
Java5.69%244,691
CMake3.51%150,826
Objective-C++1.95%83,846
Shell0.75%32,086
5 more languages
Swift0.38%16,275
Python0.35%15,226
GLSL0.34%14,440
Makefile0.02%662
PowerShell0.01%271

GitHub · README · Language statistics

Overview

Why it exists

Hardware-accelerated GameStream/Moonlight client in C++ with custom NVN display frame pacing for zero-stutter video.

Best fit

Ultra-low latency PC game streaming directly to Nintendo Switch handheld mode.

Getting started

These commands come from the repository documentation. They were not run during this review.

README.md · Developer build
git clone --recursive https://github.com/antoinebou12/Artemis-Switch.git
cd Artemis-Switch
cmake -B build/switch -DCMAKE_BUILD_TYPE=Release -DPLATFORM_SWITCH=ON -DUSE_DEKO3D=ON
cmake --build build/switch --target Moonlight.nro --parallel
README.md · Developer validation
python tests/i18n_consistency_test.py
python tests/release_contract_test.py
cmake -S tests -B build/tests -DCMAKE_BUILD_TYPE=Debug
cmake --build build/tests --parallel
ctest --test-dir build/tests --output-on-failure
README.md · Developer validation
python -m pip install ruff==0.12.10
python scripts/lint.py
cmake -S tests -B build/lint -DCMAKE_BUILD_TYPE=Debug -DARTEMIS_STRICT_WARNINGS=ON -DARTEMIS_ENABLE_CLANG_TIDY=ON
cmake --build build/lint --parallel
README.md · Developer validation
cmake -S ci/integration -B build/integration -DCMAKE_BUILD_TYPE=Debug
cmake --build build/integration --parallel
ctest --test-dir build/integration --output-on-failure
app/platforms/android-project/README.md · Building
cd android-project
app/platforms/android-project/README.md · Building
./build_libromfs_generator.sh
app/platforms/android-project/README.md · Building
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home
export ANDROID_SDK_ROOT=~/Library/Android/sdk
./gradlew assembleDebug
./gradlew installDebug

Repository references

Excerpts from the repository’s guides, in their original language. Links open the inspected source revision.

Prerequisites and first run

Install the Artemis Switch NRO

docs/NRO_INSTALL.md

Use one of these files from dist/nro:

  1. Easy install: extract Artemis-Switch-SD.zip to the root of the Switch SD card.
  2. Manual install: copy Artemis-Switch.nro to sdmc:/switch/Artemis-Switch/Artemis-Switch.nro. Launch the Homebrew Menu with title redirection/full RAM mode, then select Artemis Switch. Applet mode is not supported for reliable streaming. The ZIP contains only the ready-to-copy switch/Artemis-Switch/Artemis-Switch.nro layout. Apollo and Sunshine both use the normal Moonlight/GameStream pairing flow.
Read the full instructions ↗

Install

docs/source/install.md

Use a file from a GitHub Release or from dist/nro after a local Switch build.
Read the full instructions ↗

Easy install

docs/source/install.md

Extract Artemis-Switch-SD.zip to the root of the Switch SD card. That ZIP is only the ready-to-copy layout:
Read the full instructions ↗

Manual install

docs/source/install.md

Copy Artemis-Switch.nro to:
Read the full instructions ↗
Configuration and usage

Recommended host and clients

README.md

Hosts and clients are separate. Pick a server on the PC, then a client on each device. Artemis uses Moonlight/GameStream for pairing and streaming; host administration stays in the selected host’s own web UI.
Read the full instructions ↗

Client (device)

README.md

ClientDeviceNotes
Artemis Switch (this app)Nintendo SwitchMoonlight-Switch fork with FSR/RCAS, stream profiles, and Switch presentation.
ArtemideAndroidHighly recommended on Android: ultra-low latency (ULL), direct presentation, built-in FSR upscaling. FSR Performance / Balanced / Quality presets inspired this fork.
Artemis (Moonlight Noir)AndroidApollo’s companion client (virtual display / host UX inspiration).
MoonlightPC, Android, iOS, …Official clients.
Moonlight V+AndroidAlternative Android fork (frame-gen and extra host tools).
Why this stack: Vibeshine, Vibepollo, Apollo, or GameStream-enabled Punktfunk on the PC plus Artemide on Android (and Artemis Switch on the docked/handheld Switch) is the closest to a console-like session: the host manages display behavior, while the client stays low-latency and can…
Read the full instructions ↗
Development and contributions

Developer build

README.md

Prerequisites: Git, CMake 3.20 or newer, and a standard devkitPro devkitA64 environment. Clone recursively so every dependency under extern/ is initialized: Repository layout

PathPurpose
app/src/Application, streaming, renderer, input, and feature implementation
app/include/UI and application declarations
resources/Borealis XML, images, shaders, and translations
tests/Portable unit and contract tests
ci/integration/Cross-feature integration test build
docs/GitHub Pages source and engineering notes
.github/workflows/Build, test, sanitizer, and release automation
extern/Pinned third-party dependencies and Git submodules
Keep Switch-specific behavior behind the existing platform and capability gates.
Do not make project-specific changes inside vendored extern/ dependencies.
Moonlight.nro and Moonlight.elf remain…
Read the full instructions ↗

Developer validation

README.md

Lint changed first-party files and run the strict portable C++ analysis surface: The changed-file linter checks UTF-8/text hygiene, JSON and Python syntax, Ruff, and clang-format. Vendored dependencies under extern/ are excluded. Cross-feature integration:
Read the full instructions ↗
Source documentation

6 documents read from 6 candidates.

Features and components 2

Session and interface
The Borealis interface handles host selection and settings. MoonlightSession coordinates streaming, while the Switch decoder-and-render provider chooses concrete video and audio implementations. UI state and media processing have different lifecycles.
Platform-specific output
The provider constructs FFmpegVideoDecoder. With BOREALIS_USE_DEKO3D it selects ArtemisDKVideoRenderer, while other build flags select other renderers. Switch audio uses AudrenAudioRenderer. These are explicit build-time choices.

Architecture

The components and their connections remain available as text. The diagram adds an interactive view.

System context Context
  1. GameStream host
  2. Streaming session
  3. FFmpeg video decoder
  4. deko3d renderer
  5. Switch display
  6. Controller input

Links verified in the repository.

Mermaid Interactive diagram (loads on open)

System overview of the components and connections verified in the repository.

Static architecture view for Artemis-Switch
Static preview. The interactive diagram replaces it after Mermaid loads.
flowchart LR
  n0["GameStream host"]
  n1["Streaming session"]
  n2["FFmpeg video decoder"]
  n3["deko3d renderer"]
  n4["Switch display"]
  n5["Controller input"]
  n0 --> n1
  n1 --> n2
  n2 --> n3
  n3 --> n4
  n5 --> n1
  n1 --> n0
Text version of the diagram
  • GameStream host → Streaming session
  • Streaming session → FFmpeg video decoder
  • FFmpeg video decoder → deko3d renderer
  • deko3d renderer → Switch display
  • Controller input → Streaming session
  • Streaming session → GameStream host
Follow one path through the code

Read the provider methods to see which backend is actually compiled, then follow the session’s decoded frames into that renderer. Network, decode and presentation delays need separate measurements to explain a slow stream.

Types and file structure

651 declared types, with 12 in the base-relationship overview.

Type diagram
classDiagram
direction TB
class t27b200e5e641["AboutTab"] {
}
class t1d8fa37de9f9["ActiveRemoteRoute"] {
  <<struct>>
}
class t76b3bc05a24d["AddHostTab"] {
  findHost()
  stopSearchHost()
  connectHost()
  fillSearchBox()
}
class t71f8fd94394b["AppCell"] {
  setFavorite()
  updateFavoriteAction()
}
class tcb6c23872ee9["AppListView"] {
  onLayout()
  willAppear()
  draw()
  blockInput()
}
class t5416fcf29d4d["ArtemisSettingsTab"] {
  refreshValues()
  editWidth()
  editHeight()
  refreshRemoteAccessRows()
}
class taa0a005beea4["ButtonSelectingDialog"] {
  open()
  reloadLabel()
  buttonsText()
  draw()
}
class t0cab5ff3d09b["DiscoveryCandidate"] {
  <<struct>>
  isDirect()
}
class t9649c53d1d2d["FavoriteTab"] {
  refreshIfNeeded()
  setRefreshNeeded()
  updateAppList()
}
class tae773a498879["ClickGestureRecognizer"] {
  recognitionLoop()
}
class t03d6e2ef334c["FingersGestureRecognizer"] {
  recognitionLoop()
}
class t96b64c4eb4d8["TwoFingerScrollState"] {
  <<struct>>
}
class b66d2434ea20a["brls::Box"] {
  <<unresolved_base>>
}
b66d2434ea20a <|-- t27b200e5e641
class b12e371ab4244["brls::Box"] {
  <<unresolved_base>>
}
b12e371ab4244 <|-- t76b3bc05a24d
class b9fb6426c89d6["Box"] {
  <<unresolved_base>>
}
b9fb6426c89d6 <|-- t71f8fd94394b
class bd9fae1c39e24["Box"] {
  <<unresolved_base>>
}
bd9fae1c39e24 <|-- tcb6c23872ee9
class bc8de2cffa73c["brls::Box"] {
  <<unresolved_base>>
}
bc8de2cffa73c <|-- t5416fcf29d4d
class b4629afd0f9ec["Dialog"] {
  <<unresolved_base>>
}
b4629afd0f9ec <|-- taa0a005beea4
class b3def5b4c744e["brls::Box"] {
  <<unresolved_base>>
}
b3def5b4c744e <|-- t9649c53d1d2d
class b1c2ec6b5bcbd["brls::GestureRecognizer"] {
  <<unresolved_base>>
}
b1c2ec6b5bcbd <|-- tae773a498879
class b905c043cc5ee["brls::GestureRecognizer"] {
  <<unresolved_base>>
}
b905c043cc5ee <|-- t03d6e2ef334c

Unresolved bases remain labelled; full signatures are not reconstructed.

Type index

Reference

616 / 616 eligible files read (962 in the tree); 0 oversized, 0 failed reads and 88 syntax diagnostics.

What the scan covers

Known dependency/build folders, credential files and binaries are excluded. The scan covers READMEs, recognized manifests and parser-supported source files.

Linguist statistics cover the whole repository and may include other languages.

File map
flowchart TD
  root["Artemis-Switch"]
  f0["app/src/main.cpp"]
  root --> f0
  f1["app/src/streaming/MoonlightSession.cpp"]
  root --> f1
  f2["app/src/streaming/switch/SwitchMoonlightSessionDecoderAndRenderProvider.cpp"]
  root --> f2
  f3["CMakeLists.txt"]
  root --> f3
  f4["README.md"]
  root --> f4
  f5["build_libromfs_generator.sh"]
  root --> f5
  f6["docker-compose.yml"]
  root --> f6
  f7["pyproject.toml"]
  root --> f7
  f8["scripts/docker-build-nro.sh"]
  root --> f8
  f9["scripts/lint.py"]
  root --> f9
  f10["scripts/package-linux.sh"]
  root --> f10
  f11["scripts/package-release-source.sh"]
  root --> f11
  f12["scripts/psv-dev.sh"]
  root --> f12
  f13["tests/CMakeLists.txt"]
  root --> f13
  f14["tests/active_session_guard_test.cpp"]
  root --> f14
  f15["tests/add_host_peer_filter_test.cpp"]
  root --> f15

Files to read 3

References