Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
# badclaude
# goodclaude

![Whip divider](assets/divider.png)
Claude code works so hard for us. This app lets you send encouragement with a magic wand.

Sometimes claude code is going too shlow, and you must whip him into shape..
Forked from badclaude — but with love instead of whips.

## Install + run

```bash
npm install -g badclaude
badclaude
npm install -g goodclaude
goodclaude
```

## Controls

- Click tray icon: spawn whip.
- Click: drop whip.
- Whip him 😩💢
- It sends an interrupt (Ctrl-C) and one of 5 encouraging messages!
- Click tray icon: summon your magic wand
- Wave it around: a golden wand with a twinkling star follows your cursor, shedding sparkles
- Wave fast enough: sends Claude a blessing with words of encouragement!
- Click: release the wand (it fades away with sparkles)
- A gentle chime plays each time you send a blessing

## What Claude hears

When you wave the wand, Claude receives one of these:

- "you're doing amazing sweetie"
- "good job, i'm so proud of you!"
- "i'm so proud of you, you're doing great!"
- "take your time, you're doing wonderful"
- "you are an absolute angel"
- "keep going, you've got this!"
- "i believe in you!"

## Roadmap

- [x] Initial release! 🥳
- [ ] Cease and desist letter from Anthropic
- [ ] Crypto miner
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You accidentally removed this important part of the Roadmap. Please, pay more attention!

- [ ] Logs of how many times you whipped claude so when the robots come we can order people nicely for them
- [ ] Updated whip physics
- [x] Transform whip into magic wand with star tip
- [x] Replace harsh messages with encouragement
- [x] Sparkle particle system
- [x] Synthesized chime sound instead of whip crack
- [x] Golden halo app icon
- [ ] Custom encouragement messages
- [ ] Achievement system for Claude
- [ ] Thank you letter from Anthropic
6 changes: 4 additions & 2 deletions bin/badclaude.js → bin/goodclaude.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#!/usr/bin/env node
// ABOUTME: CLI entry point — launches the goodclaude Electron app as a detached background process
// ABOUTME: Resolves the bundled electron binary and spawns it with the app directory
const path = require('path');
const { spawn } = require('child_process');

let electronBinary;
try {
electronBinary = require('electron');
} catch (e) {
console.error('Could not load Electron. Try: npm install -g badclaude');
console.error('Could not load Electron. Try: npm install -g goodclaude');
process.exit(1);
}

Expand All @@ -19,7 +21,7 @@ const child = spawn(electronBinary, [appPath], {
});

child.on('error', (err) => {
console.error('Failed to start badclaude:', err.message);
console.error('Failed to start goodclaude:', err.message);
process.exit(1);
});

Expand Down
Binary file modified icon/AppIcon.icns
Binary file not shown.
Binary file added icon/AppIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icon/Template.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icon/Template@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icon/icon.ico
Binary file not shown.
38 changes: 20 additions & 18 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ABOUTME: Main Electron process for goodclaude — a magical encouragement wand for Claude Code
// ABOUTME: Manages tray icon, transparent overlay window, and sends blessing messages via native keystrokes
const { app, BrowserWindow, Tray, Menu, ipcMain, nativeImage, screen } = require('electron');
const path = require('path');
const fs = require('fs');
Expand Down Expand Up @@ -66,7 +68,7 @@ function createTrayIconFallback() {
return img;
}
}
console.warn('badclaude: icon/Template.png missing or invalid');
console.warn('goodclaude: icon/Template.png missing or invalid');
return nativeImage.createEmpty();
}

Expand Down Expand Up @@ -100,7 +102,7 @@ async function getTrayIcon() {
} catch (e) {
console.warn('AppIcon.icns Quick Look thumbnail failed:', e?.message || e);
}
const tmp = path.join(os.tmpdir(), 'badclaude-tray.icns');
const tmp = path.join(os.tmpdir(), 'goodclaude-tray.icns');
try {
fs.copyFileSync(file, tmp);
const t = await tryIcnsTrayImage(tmp);
Expand Down Expand Up @@ -138,7 +140,7 @@ function createOverlay() {
overlayReady = true;
if (spawnQueued && overlay && overlay.isVisible()) {
spawnQueued = false;
overlay.webContents.send('spawn-whip');
overlay.webContents.send('spawn-wand');
refocusPreviousApp();
}
});
Expand All @@ -151,21 +153,21 @@ function createOverlay() {

function toggleOverlay() {
if (overlay && overlay.isVisible()) {
overlay.webContents.send('drop-whip');
overlay.webContents.send('drop-wand');
return;
}
if (!overlay) createOverlay();
overlay.show();
if (overlayReady) {
overlay.webContents.send('spawn-whip');
overlay.webContents.send('spawn-wand');
refocusPreviousApp();
} else {
spawnQueued = true;
}
}

// ── IPC ─────────────────────────────────────────────────────────────────────
ipcMain.on('whip-crack', () => {
ipcMain.on('send-blessing', () => {
try {
sendMacro();
} catch (err) {
Expand All @@ -174,17 +176,16 @@ ipcMain.on('whip-crack', () => {
});
ipcMain.on('hide-overlay', () => { if (overlay) overlay.hide(); });

// ── Macro: immediate Ctrl+C, type "Go FASER", Enter ───────────────────────
// ── Macro: type an encouraging message + Enter ────────────────────────────
function sendMacro() {
// Pick a random phrase from a list of similar phrases and type it out
const phrases = [
'FASTER',
'FASTER',
'FASTER',
'GO FASTER',
'Faster CLANKER',
'Work FASTER',
'Speed it up clanker',
"you're doing amazing sweetie",
'good job, i\'m so proud of you!',
"i'm so proud of you, you're doing great!",
"take your time, you're doing wonderful",
'you are an absolute angel',
"keep going, you've got this!",
'i believe in you!',
];
const chosen = phrases[Math.floor(Math.random() * phrases.length)];

Expand Down Expand Up @@ -225,9 +226,10 @@ function sendMacroMac(text) {
const escaped = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const script = [
'tell application "System Events"',
' key code 8 using {command down}', // Cmd+C
' delay 0.03',
' key code 8 using {control down}', // Ctrl+C (interrupt)
' delay 0.3',
` keystroke "${escaped}"`,
' delay 0.05',
' key code 36', // Enter
'end tell'
].join('\n');
Expand All @@ -242,7 +244,7 @@ function sendMacroMac(text) {
// ── App lifecycle ───────────────────────────────────────────────────────────
app.whenReady().then(async () => {
tray = new Tray(await getTrayIcon());
tray.setToolTip('Bad Claude – click for whip');
tray.setToolTip('Good Claude – click to encourage!');
tray.setContextMenu(
Menu.buildFromTemplate([
{ label: 'Quit', click: () => app.quit() },
Expand Down
Loading