xiaosong858473 downloadsA cute 3D cartoon robot inside your note-taking editor.
Project: https://github.com/xiaosong8584/obsidian-desktoppet
A cute 3D cartoon robot desktop pet floating inside your Obsidian window. Built with parametric geometry (Sphere / Cylinder / Capsule / Torus), zero external assets, install and play.
--background-secondary, --background-modifier-box-shadow), auto-follow themeCtrl+P command palette (status bar is desktop-only)pointer-events: none, only pet is interactive)onunload releases renderer / geometry / material / rAF / listeners
Settings panel — visibility toggle, size slider (1.25x), primary color, position X/Y and reset. The pet itself is visible in the bottom-right corner, showing a speech bubble.
cd obsidian-desktoppet
npm install
npm run dev # watch mode: rebuild on save (non-minified, inline sourcemap)
npm run build # production build: tsc type-check + minified main.js
npm run build:dev # one-off development build (non-minified, inline sourcemap; exits when done)
npm run build to generate main.js.obsidian/plugins/desktoppet/:<your-vault>/.obsidian/plugins/desktoppet/
├── main.js # required (build artifact)
├── manifest.json # required
└── styles.css # required
Source .ts files are not needed in the plugin directory.Note: Works on both desktop and mobile (
isDesktopOnly: false). Interaction is built on Pointer Events, so mouse, touch and stylus all drive the same drag / click logic.
Ctrl+P → search "Show/Hide Pet"desktoppet/
├── main.ts # Plugin entry (Plugin class + lifecycle + commands + status bar)
├── pet/
│ ├── PetScene.ts # Three.js scene (renderer / scene / camera / lights / rAF loop)
│ ├── PetModel.ts # Parametric 3D robot model (geometry composition)
│ ├── PetAnimator.ts # Animation controller (idle / blink / click / drag tilt)
│ └── PetInteraction.ts # Interaction layer (Pointer Events drag + click)
├── settings/
│ └── SettingsTab.ts # Settings panel + DEFAULT_SETTINGS
├── styles.css # Floating container / bubble / status bar styles (theme aware)
├── manifest.json # Obsidian plugin manifest
├── package.json # npm dependencies
├── tsconfig.json # TypeScript config
├── esbuild.config.mjs # Build script
├── images/ # README screenshots
└── README.md # This file
any)0.160.xthree at runtime; everything else is dev-onlyPetModel tags the material it builds for the body/antenna/limbs with material.userData.isPrimary = true. PetScene.applyColor() walks the model and swaps exactly those materials to the target color — nothing else is touched.
No color-value heuristics ("white/dark/blush are not primary"): a heuristic both under-matches (the primary color could never be changed back if it happened to equal the detail color) and over-matches (any new auxiliary material of an unexpected shade would be repainted as primary).
Click feedback (scale pulse + happy eyes + antenna bounce) is driven entirely by the animation loop's elapsed clock:
scalePulse = 1 + Math.sin(t * Math.PI) * 0.3;
group.scale.setScalar(scalePulse);
PetAnimator.triggerClickFeedback() reads the cached lastElapsed written by update(). It must not query performance.now() — that clock counts from page load while the loop's elapsed counts from scene creation, so mixing the two made elapsed - clickStartAt permanently negative and the feedback never converged.
The pet's visual size is controlled solely by the container / canvas size; the model itself always stays at 1:1 inside it.
During drag, compute a tilt target from the X velocity (-0.3 ~ +0.3 rad), then smooth it with a first-order low-pass filter:
tiltCurrent += (tiltTarget - tiltCurrent) * Math.min(1, delta * 8);
The filter runs every frame (not only while dragging), so releasing the pointer lets the tilt decay back to zero instead of staying frozen at its last angle.
WebGLRenderer({ alpha: true }) + setClearColor(0x000000, 0)pointer-events: none, only inner canvas pointer-events: autopointer-events: none — opacity: 0 alone still receives hitstouch-action: none), so scrolling / zooming gestures that start on the pet itself are suppressed by design — drag it from elsewhere if you need to scrollMIT © xiaosong8584