Skip to content

crazy0104/Toy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Toy

中文

When work and gaming eat your attention, it is easy to forget to reply. Toy is a small desktop pet that helps you stay “present”: a tap or poke sends a preset message so you can nudge someone without breaking flow.

This monorepo hosts every Toy client: shared pet assets live next to each platform’s code.

Features

  • Transparent always-on-top window — the pet floats above other windows, frameless and out of the way of clicks.
  • 9 built-in pets — each with unique animated GIFs for idle, running, waiting, done, error, and drag directions.
  • Multi-device relay — WebSocket relay so pets on different devices can interact: poke pets for others in the same group or sync state changes.
  • System tray menu — switch pets, toggle bubble / low-power / always-on-top / relay, import custom pets, open settings.
  • State machine — unified idlerunningwaitingdone / error flow with auto-return timers.
  • Custom pet import — ZIP packs with a simple JSON manifest + GIF assets.
  • Position persistence — remembers the window position and clamps it to the current monitor layout.
  • Low-power mode — lowers GIF frame rate while idle to save CPU.

Built-in Pets

Assets come from the Codex Pets community.

ID Name Link
bubu Bubu https://codex-pets.net/#/pets/bubu-yier
guga Guga https://codex-pets.net/#/pets/guga
ikun iKun https://codex-pets.net/#/pets/ikun
miku Hatsune Miku https://codex-pets.net/#/pets/miku
miku-kimono Miku Kimono https://codex-pets.net/#/pets/miku-kimono
tiga Tiga (Ultraman) https://codex-pets.net/#/pets/tiga
xiaoba Xiaoba https://codex-pets.net/#/pets/xiaoba
xiaoyan Xiaoyan https://codex-pets.net/#/pets/xiaoyan
yier Yier https://codex-pets.net/#/pets/yier-gif

Architecture

┌─────────────────────────────────────────────────┐
│                    Frontend                      │
│  React + TypeScript (Vite)                       │
│  ┌──────────┐  ┌──────────────┐  ┌───────────┐  │
│  │ Pet.tsx  │  │ petState-    │  │ petRelay  │  │
│  │ (render) │  │ Machine.ts   │  │ (WebSocket)│  │
│  └──────────┘  └──────────────┘  └───────────┘  │
│  ┌──────────────────────────────────────────┐    │
│  │              App.tsx (orchestrator)       │    │
│  └──────────────────────────────────────────┘    │
│  ┌──────────────────────────────────────────┐    │
│  │            tauriApi.ts (IPC bridge)       │    │
│  └──────────────────────────────────────────┘    │
├─────────────────────────────────────────────────┤
│                    Backend                       │
│  Rust (Tauri v2)                                 │
│  ┌──────────────┐  ┌──────────────┐              │
│  │ lib.rs       │  │ pet_zip_     │              │
│  │ (tray, IPC,  │  │ import.rs     │              │
│  │  settings)   │  │ (user pets)   │              │
│  └──────────────┘  └──────────────┘              │
│  ┌──────────────────────────────────────┐        │
│  │         Settings (JSON file)          │        │
│  │   ~/AppData/.../settings.json        │        │
│  └──────────────────────────────────────┘        │
│  ┌──────────────────────────────────────┐        │
│  │     User Pets Dir (ZIP import)       │        │
│  │   ~/AppData/.../pets/               │        │
│  └──────────────────────────────────────┘        │
└─────────────────────────────────────────────────┘

State Machine

         ┌─────────┐
    ┌───→│  idle   │←──────────────┐
    │    └────┬────┘               │
    │         │ click / remote     │ auto-return
    │         ▼                    │ (timer)
    │    ┌─────────┐              │
    │    │ running │──────────┐   │
    │    └─────────┘          │   │
    │         │               │   │
    │    ┌────┴────┐     ┌───┴───┴──┐
    │    ▼         ▼     ▼          ▼
    │ waiting    done  error    (any state
    │                         via remote)
    └───────────────────────────────┘
  • idle — default standby
  • running — working / poked, shows bubble
  • waiting — waiting, no auto-return
  • done — finished, returns to idle after a delay (default 3s)
  • error — error, returns after max(5s, configured delay)

Relay (multi-device)

The relay uses a WebSocket service to sync actions for pets in the same group:

  • Join: each client uses groupId + groupToken.
  • Actions: show_bubble (poke), jump, wave, state_change.
  • Delivery: clicks are sent to the server and broadcast to other group members; your own client ignores self-originated messages.
  • Legacy: supports both the new event payload and older flat JSON messages.

Default relay server: wss://api.example.cn/pet-relay.

Repository Layout

Path Description
tool-pet-tauri/ Desktop: Tauri v2 + React + TypeScript — docs/tauri.md
tool-pet-android/ Android: Kotlin + Compose — docs/android.md
tool-pet-net48/ Windows .NET Framework 4.8: WinForms — docs/net48.md
sources/ Pet assets: shared GIFs and pet.json (synced into Tauri public/, Android assets, etc.)
docs/ Documentation: per-platform guides (CN / EN)

Settings

Setting Default Description
alwaysOnTop true Keep pet above other windows
lowPowerMode true Reduce GIF frame rate when idle
currentPetId bubu Active pet
showBubble true Show speech bubble
autoReturnToIdle true Auto-return from done / error to idle
autoReturnDelayMs 3000 Auto-return delay (ms)
windowWidth / windowHeight 100 / 120 Window size (px); 0 uses manifest size
relayEnabled true Enable WebSocket relay
relayServerUrl wss://api.example.cn/pet-relay Relay URL
relayGroupId peng1028-pet Group id
relayGroupToken (empty) Group token
relayDeviceId (auto-generated) Device id
relayUserName (system user) Display name in relay messages
relayMessageText 拍了你一下 Default poke text

Pet Manifest Format

Each pet folder contains a pet.json manifest:

{
  "id": "bubu",
  "name": "bubu",
  "version": "1.0.0",
  "width": 192,
  "height": 208,
  "defaultState": "idle",
  "states": {
    "idle":     { "src": "bubu-yier-idle.gif",    "bubble": "bubu准备好了" },
    "running":  { "src": "bubu-yier-running.gif",  "bubble": "bubu正在努力" },
    "waiting":  { "src": "bubu-yier-waiting.gif",  "bubble": "bubu在等待" },
    "done":     { "src": "bubu-yier-review.gif",   "bubble": "bubu完成了" },
    "error":    { "src": "bubu-yier-failed.gif",   "bubble": "bubu遇到错误" },
    "dragLeft": { "src": "bubu-yier-running-left.gif",  "bubble": "bubu向左移动" },
    "dragRight":{ "src": "bubu-yier-running-right.gif", "bubble": "bubu向右移动" }
  }
}

Fields:

  • id — unique id
  • name — display name (tray menu)
  • version — semver
  • width / height — art size (px)
  • defaultState — initial state (usually idle)
  • states — maps state → { "src", "bubble" } for GIF path and bubble text
  • Optional: dragLeft / dragRight for drag animation

Quick Start

Install npm dependencies and run frontend builds only under tool-pet-tauri/. If you ever ran npm install at the repo root, remove stray node_modules/ / dist/ there and reinstall inside tool-pet-tauri/.

Tech Stack

Layer Technology
Desktop Tauri v2
Frontend React 18 + TypeScript + Vite
Backend Rust (edition 2021, MSRV 1.77.2)
Assets GIF (animated)
Relay WebSocket (JSON)
Build scripts Node.js (sync-pet-sources.mjs, generate-default-pet-assets.mjs)

Custom Assets

See Codex Pets for community packs and authoring guidance.

License

See LICENSE at the repository root.

About

A multi client desktop pet (Toy).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors