Built specifically for the Switch version of Tomodachi Life.
Updated: 2026-05-22 Status: active development
This verification pass covered the desktop app, the web flasher, and ESP32 firmware compilation in the current repository:
npm run ci:local:quick: passed, including desktop type-checking,94desktop tests, flasher type-checking,8flasher tests, and the flasher web buildnpm run build: passed, including root TypeScript compilation and static asset copying~/.platformio/penv/bin/pio run -d firmware/esp32 -e esp32dev_wireless: passed~/.platformio/penv/bin/pio run -d firmware/esp32 -e esp32dev_wireless_switch2: passed~/.platformio/penv/bin/pio run -d firmware/esp32 -e esp32dev_wireless_switch_lite: passednpm run build --prefix site/flasher: passed and produced the web flasher release outputnpm run verify:pages --prefix site/flasher: passed
Notes:
- On this machine,
python3 -m platformiois not available, but~/.platformio/penv/bin/piois available; firmware compilation was verified through the fullpiopath documented for repo-based usage - These results only cover automated tests, builds, and firmware compilation; real flashing, Bluetooth pairing, timing tuning, and drawing still need device-by-device validation through the quick-start flow
- Original source author: Xiaohongshu creator
惜羽拓麻镇 - The repository currently uses the
GPL-3.0-or-laterlicense - If you publicly repost, mirror, or redistribute this project, it is recommended that you credit
惜羽拓麻镇 - If you publicly repost, mirror, or redistribute this project, it is also recommended that you include the original publication link
The current objective is not to complete fully automatic, high-fidelity multicolor drawing for arbitrary images in one step. The current objective is to make this real-world usage chain stable first:
Packaged desktop app / repo-based workflow -> Firmware Flash -> Controller Test -> Timing Tune / Benchmark -> Script Studio -> serial ACK execution -> ESP32 Bluetooth controller output -> stable reproduction on the Switch drawing canvas
Current priorities:
- stable Bluetooth connection and long-duration execution
- stable mono, official-palette, and custom-multicolor drawing
- keep calibrating color sources and offset assumptions
- only then move on to more ambitious automation
The project currently has two real entry routes:
Packaged desktop app: formacOSandWindows x64Repo-based workflow: for development, debugging, and protocol validation
In the current implementation:
apps/desktop/src/electron/main.tsis responsible for the desktop shell, runtime path selection, local web-server startup, and main-window lifecyclepackage.jsonalready contains scripts such aselectron:dev,dist:mac, anddist:win:x64- packaged builds do not run firmware directly from a read-only resource directory; they first copy
firmware/esp32into a writable location before handing it toPlatformIO - the
Windowspackage includesdrivers/windowsresources so the desktop UI can expose driver-helper entry points apps/desktop/src/web/recoverySessions.tsis responsible for recovery-session persistence, reload, cleanup, and state conversion- recovery sessions are currently stored under the user's documents directory in
FriendMaker/recovery-sessions apps/desktop/src/drawingTemplates.tsowns drawing-template definitions, and template masks / previews are loaded from static assets
So the real development shape is no longer just "CLI + webpage". It is:
Electron desktop app + embedded local web workspace + TypeScript development toolchain
As of the current version, these parts are already verified or basically usable:
- packaged desktop build scripts and a desktop entry already exist for
macOSandWindows x64 - the web UI already covers
Script Studio / Firmware Flash / Controller Test / Timing Tune / Benchmark - the page can directly invoke
PlatformIOto compile and flash firmware - the page can directly run controller connection, Bluetooth reset, and button / D-pad / stick tests
- the page can directly tune
inputDelay / buttonPressDurationand run loopback timing tests - a
256x256script-coordinate canvas - the public UI currently exposes six square-pixel brush sizes:
1 / 3 / 7 / 13 / 19 / 27 - round pixel brushes are still reserved / guarded, and the main generation and execution path does not depend on them
- drawing starts from the center of the canvas after entering the drawing page
- after recovery, re-entering the drawing page is still modeled as starting again from the center
Ais used for drawing / confirming a stroke- the D-pad is used for one-cell movement
- the page can import images, generate previews, inspect statistics, and execute commands
- the mono drawing path is already working
- the official-palette drawing path is already integrated through
image-q - the custom-multicolor path is already integrated as a formal feature and can write batches into the
9custom color slots - official colors are quantized into the
7 x 12/84-color base palette and then mapped into the game's right-side9palette slots - the drawing-template system already supports categories, previews, masks, and command-time cropping
- automatic background removal, preview guides, and official-palette previews are already integrated
- the image import path currently supports
PNG / JPG / WEBP / SVG - execution logs, flash logs, and test logs are all observable in the page
inputDelaycurrently behaves more like a stability knob, whilebuttonPressDurationbehaves more like an input-strength knob- recovery tasks are persisted after pause, stop, or abnormal exit; if the app exits while paused, that task is converted into a recoverable task on the next launch
- packaged desktop builds include firmware resources, app icons, and bundled
Windowsdriver resources - ESP32 already supports the base serial protocol
- ESP32 already supports the ACK execution path required by formal drawing
- ESP32 already supports test commands such as
TAP <BUTTON> <COUNT>,HOLD <BUTTON> <MS>, andSTICK <X> <Y> <MS> - the web flasher can currently publish the two visible models,
Switch 1 and Lite firmwareandSwitch 2, while hiding the old standardSwitchfirmware entry
The current target drawing page is modeled with these fixed rules:
- after entering the drawing page, the cursor is at the center of the main canvas
- there is currently no reliable reset semantic that can always move the main canvas cursor back to the top-left corner
- because of that, the recovery flow must also assume that the user re-enters the drawing page and starts again from the canvas center
- the current tool is the brush
Ais used for drawing- the D-pad moves one cell per action
- the canvas is handled as
256x256script coordinates
That means the current mainline for Script Studio is:
- fixed
256x256 - fixed center-start assumption
- three formal routes: mono, official-palette, and custom-multicolor
- fixed public-UI mainline around square pixel brushes; round pixel brushes are not a formal drawing entry yet
Important distinction:
- if the docs mention "reset to top-left" or "top-left start", that does not refer to the main canvas by default
- those descriptions only apply to internal navigation modeling in color lists, the base-color page, or the custom-color edit page
There are currently two possible multicolor routes.
This is the current recommended mainline.
Known facts:
- the base colors are the system default palette
- the base color area is
7 rows x 12 columns - there are
84directly selectable base colors
Advantages of this route:
- the color set is limited
- it does not require precise tuning inside the custom-color edit page
- it is more suitable for open-loop control
- it is easier to stabilize for automated drawing
The long-term plan for this route should be:
- record the complete
7 x 12base color table - define a fixed
row / colfor each color - quantize input images into these
84colors in the web UI - let ESP32 only open the color page and move to the correct cell
Currently implemented design:
- the web UI already includes
official palette drawing - official-palette drawing quantizes the input image into
84base colors - the script layer already has the
BC <slot> <row> <col>command - the firmware configures the 9 palette slots through
slot -> base-color page row/col - the current strategy no longer tries to "reset to top-left"; instead, it assumes all 9 slots begin from the game's default colors and then tracks each slot's current
row / col - the script starts with
BC RESETto reset the firmware's internal slot-tracking state back to the default-slot assumption BC RESETonly resets palette-slot tracking state; it does not mean the main canvas cursor is reset to top-left- after moving to the target cell on the base-color page, pressing
Areturns directly to the canvas, so official-palette slot configuration no longer sends extraB / A / B
Current conclusion:
base colors 7x12 are the recommended mainline path for future multicolor drawing.
This is the route already integrated formally as custom multicolor.
Known facts:
- the color page has two tabs:
base colorsandcustom colors - pressing
Yon the drawing page opens the palette list - the palette list has
9palette slots - there are other non-palette items above the list
- pressing
Yagain enters the palette edit page - inside the edit page,
Rswitches to thecustom colorstab andLswitches to thebase colorstab Bexits the palette page / edit pageAselects the current palette slot- inside the edit page,
ZL / ZRcontrol the hue bar at the bottom, while the large block above is a two-dimensional color area - the direction semantics for
M 1 0 / M -1 0 / M 0 -1 / M 0 1are already confirmed
Why custom-color automation still needs more work:
- the displacement relationship between
TAP DLEFT 20andTAP DLEFT 40is still unstable - the number of taps and the actual cursor displacement are not strictly linear
- long holds and taps do not behave the same; holds can accelerate
- without visual feedback, there is no guarantee that
#RRGGBBlands precisely on the intended location
Current conclusion:
custom color auto tuning is already connected as a formal part of custom multicolor, but both color precision and stability still need more work.
Even though auto color editing is already connected, these confirmed facts still need to be kept because they are part of future optimization work.
Yopens the palette list- repeatedly pressing
Downcan stably reach the bottom - there are
9palette slots between the bottom and the top
This means the stable selection strategy for the palette list should be:
- open the list
- move all the way down to the bottom
- move back upward to the target slot
Confirmed:
- in the large color block above:
M 1 0moves rightM -1 0moves leftM 0 -1moves upM 0 1moves down
- in the hue bar below:
ZLmoves leftZRmoves right
Confirmed:
- after entering the edit page in the custom-color flow, pressing
Rfirst is required to land on the correct custom-color tab - after entering the edit page in the official-color flow, pressing
Lfirst is required to land on the correct base-color tab - diagonal movement is not stable
- it is more reasonable to reset vertically first, then horizontally, then reset the hue bar
- the current custom-color experiment branch now prefers testing the
top-left startassumption - one currently stable reset parameter set is: push up
1500ms, push left3000ms, and holdZLfor2500ms
Recommended reset order:
- reset upward
- reset leftward
- hold
ZLto the left edge of the hue bar
Current observed behavior:
- the horizontal range in the large color block is obviously long
- the vertical range is about half the same order of magnitude as the horizontal one
- measuring the hue bar with
HOLDtime is unreliable because a long hold may accelerate - based on current real-device testing, the custom-color edit page can be approximated as:
- hue around
200steps - saturation around
213steps - brightness around
112steps
- hue around
- the hue forward direction under
ZRis opposite to the usual increasingHSV huedirection, so conversion needs a reverse mapping - after resetting to top-left, the bright end is closer to the starting point; lowering brightness requires moving downward, not upward
Current conclusion:
If custom-color automation is pushed further later, it must:
- prioritize
TAPcounts - stop using raw
HOLDduration as a direct color-coordinate conversion
In addition to the original drawing commands, the protocol now includes these test commands.
Format:
TAP <BUTTON> <COUNT>Examples:
TAP DRIGHT 216
TAP DLEFT 110
TAP ZR 20Meaning:
- tap a button repeatedly for a specified count
- this is a discrete step command
- it is suitable for calibrating step counts in the edit page or hue bar
Format:
HOLD <BUTTON> <MS>Examples:
HOLD ZL 10000
HOLD ZR 2000Meaning:
- hold a button for a specified number of milliseconds
- suitable only for rough range observation
- not suitable as the final basis for precise color tuning
Format:
STICK <X> <Y> <MS>Rules:
Xcan only be-1 / 0 / 1Ycan only be-1 / 0 / 1- they cannot both be
0 0 MSis the duration, from1to60000
Direction convention:
STICK 0 -1 <MS>: left stick upwardSTICK 0 1 <MS>: left stick downwardSTICK -1 0 <MS>: left stick leftSTICK 1 0 <MS>: left stick right
Examples:
STICK 0 -1 1500
STICK -1 0 3000
HOLD ZL 2500Meaning:
- push the left stick toward a direction and keep holding for a duration
- suitable for directly testing simulated stick reset behavior in the custom-color edit page
- this is a raw input command with no position calibration
The current recommendations should be fixed clearly as:
Continue using it as the mainline development and validation route.
Prioritize the base colors 7x12 route.
Already included as one of the formal automatic-drawing capabilities, but still needs more optimization in color precision and stability.
The code path keeps a time-saving recenter strategy, and it is covered by path-generation and /api/generate tests. The public UI currently keeps this entry hidden and off by default; the real-device mainline should still be validated as "no recenter, center-start" first.
- keep improving Bluetooth connection stability and long-duration drawing stability
- keep improving custom-multicolor color correction, color fidelity, and real-device appearance
- keep optimizing drawing paths, command execution paths, and long-run efficiency
- keep improving user experience, including logs, status cards, failure-recovery prompts, packaged desktop install flow, and internal validation guidance