Skip to content

Artemis-N3DS: Streaming within a dual-screen client

Artemis-N3DS adapts Moonlight Embedded to the Nintendo 3DS family. It combines host discovery and pairing with a console-specific interface, input handling and video presentation. The New 3DS hardware path is a particular concern.

Hardware and graphics Fork Docker
  • Updated
  • C++ · 76.05%
  • GPL-3.0
Upstream credited
Repository languagesC++ 76.05%6

Shares calculated from GitHub Linguist bytes.

Language%Bytes
C++76.05%385,430
C15.71%79,616
CMake4.36%22,072
Makefile2.84%14,414
Shell0.64%3,221
Dockerfile0.4%2,051

GitHub · README · Language statistics

Overview

Why it exists

Constrained systems engineering streaming 60fps video over 802.11n Wi-Fi to a dual-screen ARM11 device.

Best fit

Remote desktop and gaming on legacy Nintendo New 3DS hardware.

Getting started

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

README.md · Local (devkitPro)
make
README.md · Docker (easiest)
docker build --network=host -t moonlight-n3ds .
docker run --rm -it -v .:/moonlight-N3DS -w /moonlight-N3DS moonlight-n3ds:latest
make

Repository references

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

Prerequisites and first run

Requirements

README.md

  • New 3DS / New 3DS XL / New 2DS XL recommended (hardware H.264 decode)
  • Original 3DS / 2DS works with software decode only — expect lower FPS
  • PC running Sunshine (or compatible GameStream host) on the same network
  • CFW + FBI for CIA install
Read the full instructions ↗

Install

README.md

Full FBI steps: dist/INSTALL.md. CIA (HOME Menu): copy dist/artemis.cia to the SD card → open FBI → Install and delete CIA. 3DSX: copy dist/artemis.3dsx to sd:/3ds/artemis/artemis.3dsx and launch from the Homebrew Launcher.
Read the full instructions ↗
Configuration and usage

Configuration

README.md

Settings can be changed in-app or in: That path is legacy (kept so existing pairing and configs keep working). See dist/SD-DATA.md for the full SD layout (keys, paired hosts, diagnostics). Default settings are aimed at New 3DS.
Read the full instructions ↗
Development and contributions

Contribute

README.md

  1. Fork the repo
  2. Make your changes
  3. Open a pull request
Read the full instructions ↗
Source documentation

2 documents read from 2 candidates.

Features and components 2

Control plane
n3ds_main.cpp brings together host discovery, pair records, profiles and connection state. The selected host and application determine the stream request. Graphics lifecycle state is tracked separately from stream configuration.
Media and interaction
Audio, input and video live in separate src modules. Hardware capabilities influence the guidance shown to the user. The UI can return from a stream, while explicit system-close handling must unwind the application instead.

Architecture

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

System context Context
  1. Host discovery and pairing
  2. Selected app and profile
  3. GameStream connection
  4. Video and audio backends
  5. 3DS screens and controls

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-N3DS
Static preview. The interactive diagram replaces it after Mermaid loads.
flowchart LR

subgraph group_host["Hosts and pairing"]
  node_discovery["Host discovery<br/>[host_discovery.cpp]"]
  node_pairing[("Pair records<br/>[pair_record.cpp]")]
  node_gamestream["GameStream client<br/>[client.c]"]
  node_xml["Protocol XML<br/>[xml.c]"]
end

subgraph group_session["Session coordination"]
  node_main["Application flow<br/>[n3ds_main.cpp]"]
  node_ui["Console menus<br/>[n3ds_ui.cpp]"]
  node_connection["Stream connection"]
  node_dispatcher["Message dispatcher<br/>[dispatcher.cpp]"]
end

subgraph group_stream["Stream pipeline"]
  node_presentation["Presentation state"]
  node_decoder["Video decoders"]
  node_mvd["Hardware decode<br/>[n3ds_video_mvd.cpp]"]
  node_software["Software decode"]
  node_renderer["Screen renderers"]
  node_graphics["Graphics lifecycle"]
  node_audio["Audio output<br/>[n3ds_audio.cpp]"]
end

subgraph group_interaction["Input and helpers"]
  node_input["Console input<br/>[n3ds_input.cpp]"]
  node_touch["Touch handlers<br/>[TouchHandler.hpp]"]
  node_menuhub["In-stream helper hub"]
  node_bottomui["Bottom-screen UI"]
end

subgraph group_state["Settings and telemetry"]
  node_config[("Configuration<br/>[config.cpp]")]
  node_appcache[("App list cache<br/>[app_list_cache.cpp]")]
  node_profiles["Stream profiles<br/>[stream_profile.cpp]"]
  node_telemetry[("Stream telemetry")]
  node_benchmark["Performance metrics"]
end

node_user(("3DS user"))

node_user -->|"uses"| node_main
node_main -->|"finds hosts"| node_discovery
node_main -->|"pairs host"| node_pairing
node_main -.->|"manages host"| node_gamestream
node_gamestream -->|"parses responses"| node_xml
node_discovery -->|"uses records"| node_pairing
node_main -->|"shows menus"| node_ui
node_main -->|"lists apps"| node_appcache
node_main -->|"starts session"| node_connection
node_main -->|"loads settings"| node_config
node_main -->|"selects profile"| node_profiles
node_main -->|"handles controls"| node_input
node_input -->|"posts events"| node_dispatcher
node_input -->|"owns handlers"| node_touch
node_main -->|"dispatches events"| node_dispatcher
node_user -->|"opens helpers"| node_menuhub
node_menuhub -->|"posts actions"| node_dispatcher
node_menuhub -.->|"draws interface"| node_bottomui
node_user -->|"chooses stream"| node_connection
node_connection -.->|"receives video"| node_decoder
node_decoder -.->|"hardware path"| node_mvd
node_decoder -.->|"software path"| node_software
node_decoder -->|"renders frames"| node_renderer
node_renderer -->|"uses layout state"| node_presentation
node_renderer -->|"uses graphics lifecycle"| node_graphics
node_connection -.->|"streams audio"| node_audio
node_user -->|"views or saves metrics"| node_telemetry
node_user -->|"views performance"| node_benchmark
node_main -->|"uses telemetry store"| node_telemetry


class node_discovery,node_pairing,node_gamestream,node_xml,node_user toneBlue
class node_main,node_ui,node_connection,node_dispatcher toneAmber
class node_presentation,node_decoder,node_mvd,node_software,node_renderer,node_graphics,node_audio toneMint
class node_input,node_touch,node_menuhub,node_bottomui toneRose
class node_config,node_appcache,node_profiles,node_telemetry,node_benchmark toneIndigo

A Nintendo 3DS GameStream client. Users discover or add a Sunshine-compatible host, pair the console, choose an application and start streaming through session, video, rendering, input and bottom-screen subsystems.

Components
25
Connections
29
Links supported by code or README
23/29
Text version of the diagram
  • Host discovery and pairing → Selected app and profile
  • Selected app and profile → GameStream connection
  • GameStream connection → Video and audio backends
  • Video and audio backends → 3DS screens and controls
  • 3DS screens and controls → GameStream connection
Follow one path through the code

Follow SelectedHost and stream-profile selection before entering the media path. System close and a normal return to the menu are different transitions; the explicit close flag exists to keep those paths apart.

Deployment and operations

The ports, storage, and startup relationships below come from the repository configuration. depends_on records startup order, not service readiness.

Types and file structure

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

Type diagram
classDiagram
direction TB
class tc0387bd4c68b["SelectedHost"] {
  <<struct>>
}
class t72fa5c6e15be["RemoteApp"] {
  <<struct>>
}
class tf7c6d6aec7da["InputLoopContext"] {
  <<struct>>
}
class ta7f589e4be09["VideoDecoderBase"] {
  accept()
  _accept_touch_state_changed()
  _accept_keyboard_state_changed()
}
class tb2f58dc75feb["MockVideoDecoder"] {
}
class t391f53097446["SoftVideoDecoder"] {
  submit_decode_unit()
  _write_yuv_to_framebuffer()
}
class t4ad2ea8a811e["MvdDecoder"] {
  submit_decode_unit()
  _decode()
}
class t891d7e467987["_SERVER_DATA"] {
  <<struct>>
}
class ta59617f1a5fa["cb_ctx"] {
  <<struct>>
}
class tcb0c88684e67["_HTTP_DATA"] {
  <<struct>>
}
class taa2e3cf225d0["_CERT_KEY_PAIR"] {
  <<struct>>
}
class t91f7677e0266["xml_query"] {
  <<struct>>
}
class b34b203f09b57["ISubscriber"] {
  <<unresolved_base>>
}
b34b203f09b57 <|-- ta7f589e4be09
ta7f589e4be09 <|-- tb2f58dc75feb
ta7f589e4be09 <|-- t391f53097446
ta7f589e4be09 <|-- t4ad2ea8a811e

Unresolved bases remain labelled; full signatures are not reconstructed.

Type index

Reference

101 / 101 eligible files read (174 in the tree); 0 oversized, 0 failed reads and 6 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-N3DS"]
  f0["src/hardware_capabilities.cpp"]
  root --> f0
  f1["src/n3ds_main.cpp"]
  root --> f1
  f2["src/video/video.hpp"]
  root --> f2
  f3["CMakeLists.txt"]
  root --> f3
  f4["Makefile"]
  root --> f4
  f5["README.md"]
  root --> f5
  f6["3ds/build-expat.sh"]
  root --> f6
  f7["3ds/build-ffmpeg.sh"]
  root --> f7
  f8["3ds/build-openssl.sh"]
  root --> f8
  f9["libgamestream/CMakeLists.txt"]
  root --> f9
  f10["libgamestream/client.c"]
  root --> f10
  f11["libgamestream/client.h"]
  root --> f11
  f12["libgamestream/discover.c"]
  root --> f12
  f13["libgamestream/discover.h"]
  root --> f13
  f14["libgamestream/errors.h"]
  root --> f14
  f15["libgamestream/http.c"]
  root --> f15

Files to read 3

References