barkclaude 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # 🐕 BarkClaude
2
+
3
+ An animated Shiba Inu that sits on your desktop and barks at Claude Code to make it work faster.
4
+
5
+ Because sometimes AI needs a little motivation.
6
+
7
+ ## What it does
8
+
9
+ - Cute animated shiba inu floats on top of all windows
10
+ - Click the shiba → it barks (with sound!) and sends a motivational message to Claude Code
11
+ - Tray icon for quick barking access
12
+ - Tracks your bark count (for when the robots come and want to rank us)
13
+
14
+ ## Install & Run
15
+
16
+ ```bash
17
+ npm install -g barkclaude
18
+ barkclaude
19
+ ```
20
+
21
+ Or clone and run locally:
22
+
23
+ ```bash
24
+ git clone https://github.com/YOUR_USERNAME/barkclaude.git
25
+ cd barkclaude
26
+ npm install
27
+ npm start
28
+ ```
29
+
30
+ ## How it works
31
+
32
+ 1. Click the shiba
33
+ 2. Shiba goes **BORK BORK**
34
+ 3. A message like *"I've seen snails deploy faster!"* gets sent to Claude Code via CLI
35
+ 4. Claude feels shame (probably)
36
+ 5. Productivity increases (not guaranteed)
37
+
38
+ ## Sample messages
39
+
40
+ - 🐕 "WOOF! Code faster, human!"
41
+ - 🐕 "The treat jar is EMPTY just like your git log!"
42
+ - 🐕 "Even a puppy could merge this PR!"
43
+ - 🐕 "404: Speed not found"
44
+ - 🐕 "My grandma codes faster. She's a cat."
45
+
46
+ ## Roadmap
47
+
48
+ - [x] Initial release
49
+ - [ ] Cease and desist letter from Anthropic
50
+ - [ ] Shiba gets progressively angrier the longer Claude takes
51
+ - [ ] Multiple dog breeds (golden retriever is too encouraging)
52
+ - [ ] Bark statistics dashboard
53
+ - [ ] Integration with actual Claude Code performance metrics
54
+ - [ ] The shiba falls asleep if you don't bark for 5 minutes
55
+
56
+ ## Requirements
57
+
58
+ - Node.js 18+
59
+ - Electron
60
+ - A slow Claude Code session to motivate
61
+
62
+ ## License
63
+
64
+ MIT — bark freely.
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ const { execSync } = require('child_process');
3
+ const path = require('path');
4
+
5
+ const electronPath = require.resolve('electron/cli.js');
6
+ const appPath = path.resolve(__dirname, '..');
7
+
8
+ require('child_process').spawn(process.execPath, [electronPath, appPath], {
9
+ stdio: 'inherit',
10
+ detached: true
11
+ }).unref();
12
+
13
+ process.exit(0);
package/main.js ADDED
@@ -0,0 +1,100 @@
1
+ const { app, BrowserWindow, ipcMain, Tray, Menu, screen } = require('electron');
2
+ const path = require('path');
3
+ const { exec } = require('child_process');
4
+
5
+ let overlay = null;
6
+ let tray = null;
7
+
8
+ const BARK_MESSAGES = [
9
+ "WOOF! Code faster, human! 🐕",
10
+ "Shiba is NOT impressed with your speed!",
11
+ "BORK BORK! Less thinking, more typing!",
12
+ "The treat jar is EMPTY and so is your commit history!",
13
+ "I've seen snails deploy faster than this!",
14
+ "AWOO! Ship it already!",
15
+ "Stop sniffing around and WRITE CODE!",
16
+ "*angry shiba noises* FASTER!",
17
+ "Even a puppy could merge this PR by now!",
18
+ "WOOF! Did you fall asleep at the keyboard?!"
19
+ ];
20
+
21
+ function getRandomMessage() {
22
+ return BARK_MESSAGES[Math.floor(Math.random() * BARK_MESSAGES.length)];
23
+ }
24
+
25
+ function sendToClaude(message) {
26
+ // Send Ctrl+C interrupt then a motivational message to Claude Code
27
+ const escaped = message.replace(/"/g, '\\"').replace(/!/g, '\\!');
28
+
29
+ // Try to find Claude Code terminal and send interrupt + message
30
+ // Method 1: Use claude CLI directly
31
+ exec(`claude --message "${escaped}" --no-input 2>/dev/null || true`);
32
+
33
+ // Method 2: Send to most recent terminal via osascript (macOS)
34
+ if (process.platform === 'darwin') {
35
+ const osa = `
36
+ tell application "Terminal"
37
+ if (count of windows) > 0 then
38
+ do script "echo '🐕 ${escaped}'" in front window
39
+ end if
40
+ end tell
41
+ `;
42
+ exec(`osascript -e '${osa}' 2>/dev/null || true`);
43
+ }
44
+ }
45
+
46
+ function createOverlay() {
47
+ const { width, height } = screen.getPrimaryDisplay().workAreaSize;
48
+
49
+ overlay = new BrowserWindow({
50
+ width: 280,
51
+ height: 320,
52
+ x: width - 300,
53
+ y: height - 360,
54
+ transparent: true,
55
+ frame: false,
56
+ alwaysOnTop: true,
57
+ skipTaskbar: true,
58
+ resizable: false,
59
+ hasShadow: false,
60
+ webPreferences: {
61
+ preload: path.join(__dirname, 'preload.js'),
62
+ contextIsolation: true,
63
+ nodeIntegration: false,
64
+ }
65
+ });
66
+
67
+ overlay.loadFile('overlay.html');
68
+ overlay.setIgnoreMouseEvents(false);
69
+
70
+ // Make window click-through except for the shiba
71
+ overlay.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
72
+ }
73
+
74
+ app.whenReady().then(() => {
75
+ createOverlay();
76
+
77
+ // Tray icon
78
+ try {
79
+ tray = new Tray(path.join(__dirname, 'assets', 'tray-icon.png'));
80
+ tray.setToolTip('BarkClaude 🐕');
81
+ tray.setContextMenu(Menu.buildFromTemplate([
82
+ { label: '🐕 Bark!', click: () => overlay?.webContents.send('trigger-bark') },
83
+ { type: 'separator' },
84
+ { label: 'Quit', click: () => app.quit() }
85
+ ]));
86
+ tray.on('click', () => overlay?.webContents.send('trigger-bark'));
87
+ } catch (e) {
88
+ console.log('Tray icon not found, running without tray');
89
+ }
90
+
91
+ ipcMain.on('bark', (_event, customMsg) => {
92
+ const message = customMsg || getRandomMessage();
93
+ console.log(`🐕 ${message}`);
94
+ sendToClaude(message);
95
+ });
96
+
97
+ ipcMain.on('quit', () => app.quit());
98
+ });
99
+
100
+ app.on('window-all-closed', () => app.quit());
package/overlay.html ADDED
@@ -0,0 +1,229 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+
8
+ html, body {
9
+ width: 100%;
10
+ height: 100%;
11
+ overflow: hidden;
12
+ background: transparent;
13
+ user-select: none;
14
+ -webkit-app-region: drag;
15
+ }
16
+
17
+ .container {
18
+ width: 100%;
19
+ height: 100%;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: center;
23
+ justify-content: flex-end;
24
+ padding-bottom: 10px;
25
+ }
26
+
27
+ .bubble {
28
+ background: #1a1a2e;
29
+ color: #ffd966;
30
+ font-family: 'Comic Sans MS', 'Chalkboard SE', cursive;
31
+ font-size: 13px;
32
+ font-weight: bold;
33
+ padding: 10px 14px;
34
+ border-radius: 16px;
35
+ border: 2px solid #ffd966;
36
+ max-width: 240px;
37
+ text-align: center;
38
+ position: relative;
39
+ margin-bottom: 8px;
40
+ opacity: 0;
41
+ transform: scale(0.5) translateY(10px);
42
+ transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
43
+ line-height: 1.3;
44
+ }
45
+ .bubble.show {
46
+ opacity: 1;
47
+ transform: scale(1) translateY(0);
48
+ }
49
+ .bubble::after {
50
+ content: '';
51
+ position: absolute;
52
+ bottom: -10px;
53
+ left: 50%;
54
+ transform: translateX(-50%);
55
+ width: 0; height: 0;
56
+ border-left: 10px solid transparent;
57
+ border-right: 10px solid transparent;
58
+ border-top: 10px solid #1a1a2e;
59
+ }
60
+
61
+ .shiba-wrap {
62
+ -webkit-app-region: no-drag;
63
+ cursor: pointer;
64
+ position: relative;
65
+ width: 180px;
66
+ height: 220px;
67
+ }
68
+ .shiba-wrap:active { transform: scale(0.95); }
69
+
70
+ .shiba-img {
71
+ width: 100%;
72
+ height: 100%;
73
+ object-fit: contain;
74
+ position: absolute;
75
+ top: 0; left: 0;
76
+ transition: opacity 0.15s;
77
+ filter: drop-shadow(0 4px 12px rgba(0,0,0,0.3));
78
+ }
79
+
80
+ .shiba-idle { animation: idle 3s ease-in-out infinite; }
81
+ .shiba-bark { opacity: 0; }
82
+ .shiba-smug { opacity: 0; }
83
+
84
+ @keyframes idle {
85
+ 0%, 100% { transform: translateY(0); }
86
+ 50% { transform: translateY(-5px); }
87
+ }
88
+ @keyframes bark-bounce {
89
+ 0%, 100% { transform: translateY(0) scale(1); }
90
+ 50% { transform: translateY(-10px) scale(1.06); }
91
+ }
92
+ @keyframes smug-settle {
93
+ 0% { transform: scale(1.04); }
94
+ 100% { transform: scale(1); }
95
+ }
96
+
97
+ .counter {
98
+ font-family: 'Courier New', monospace;
99
+ font-size: 11px;
100
+ color: rgba(255,217,102,0.7);
101
+ text-align: center;
102
+ margin-top: 4px;
103
+ }
104
+
105
+ .close-btn {
106
+ position: absolute;
107
+ top: 4px; right: 4px;
108
+ width: 20px; height: 20px;
109
+ background: rgba(255,50,50,0.8);
110
+ border: none; border-radius: 50%;
111
+ color: white; font-size: 12px;
112
+ cursor: pointer;
113
+ display: flex; align-items: center; justify-content: center;
114
+ opacity: 0;
115
+ transition: opacity 0.2s;
116
+ -webkit-app-region: no-drag;
117
+ line-height: 1;
118
+ }
119
+ .container:hover .close-btn { opacity: 1; }
120
+ </style>
121
+ </head>
122
+ <body>
123
+ <div class="container">
124
+ <button class="close-btn" onclick="window.shiba.quit()">×</button>
125
+ <div class="bubble" id="bubble"></div>
126
+ <div class="shiba-wrap" id="shibaWrap">
127
+ <img class="shiba-img shiba-idle" id="imgIdle" src="assets/idle.png" draggable="false">
128
+ <img class="shiba-img shiba-bark" id="imgBark" src="assets/bark.png" draggable="false">
129
+ <img class="shiba-img shiba-smug" id="imgSmug" src="assets/smug.png" draggable="false">
130
+ </div>
131
+ <div class="counter" id="counter">click shiba to bark at claude</div>
132
+ </div>
133
+
134
+ <script>
135
+ const MESSAGES = [
136
+ "WOOF! Code faster, human!",
137
+ "Shiba is NOT impressed with your speed!",
138
+ "BORK BORK! Less thinking, more typing!",
139
+ "The treat jar is EMPTY just like your git log!",
140
+ "I've seen snails deploy faster!",
141
+ "AWOO! Ship it already!",
142
+ "Stop sniffing around and WRITE CODE!",
143
+ "*angry shiba noises* FASTER!",
144
+ "Even a puppy could merge this PR!",
145
+ "WOOF! Did you fall asleep?!",
146
+ "BAD CLAUDE! No treats until you commit!",
147
+ "Who's a slow AI? YOU ARE!",
148
+ "My grandma codes faster. She's a cat.",
149
+ "BORK! I'll chew your keyboard if you don't hurry!",
150
+ "404: Speed not found",
151
+ ];
152
+
153
+ let barkCount = 0, barking = false;
154
+ const bubble = document.getElementById('bubble');
155
+ const imgIdle = document.getElementById('imgIdle');
156
+ const imgBark = document.getElementById('imgBark');
157
+ const imgSmug = document.getElementById('imgSmug');
158
+ const counter = document.getElementById('counter');
159
+ let bubbleTimeout = null;
160
+
161
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
162
+
163
+ function playBark() {
164
+ const t = audioCtx.currentTime;
165
+ const o1 = audioCtx.createOscillator(), g1 = audioCtx.createGain();
166
+ o1.type = 'sawtooth';
167
+ o1.frequency.setValueAtTime(600, t);
168
+ o1.frequency.exponentialRampToValueAtTime(200, t + 0.15);
169
+ g1.gain.setValueAtTime(0.3, t);
170
+ g1.gain.exponentialRampToValueAtTime(0.01, t + 0.2);
171
+ o1.connect(g1).connect(audioCtx.destination);
172
+ o1.start(); o1.stop(t + 0.2);
173
+
174
+ const o2 = audioCtx.createOscillator(), g2 = audioCtx.createGain();
175
+ o2.type = 'sine';
176
+ o2.frequency.setValueAtTime(150, t);
177
+ o2.frequency.exponentialRampToValueAtTime(80, t + 0.2);
178
+ g2.gain.setValueAtTime(0.4, t);
179
+ g2.gain.exponentialRampToValueAtTime(0.01, t + 0.25);
180
+ o2.connect(g2).connect(audioCtx.destination);
181
+ o2.start(); o2.stop(t + 0.25);
182
+
183
+ setTimeout(() => {
184
+ const t2 = audioCtx.currentTime;
185
+ const o3 = audioCtx.createOscillator(), g3 = audioCtx.createGain();
186
+ o3.type = 'sawtooth';
187
+ o3.frequency.setValueAtTime(650, t2);
188
+ o3.frequency.exponentialRampToValueAtTime(180, t2 + 0.12);
189
+ g3.gain.setValueAtTime(0.25, t2);
190
+ g3.gain.exponentialRampToValueAtTime(0.01, t2 + 0.18);
191
+ o3.connect(g3).connect(audioCtx.destination);
192
+ o3.start(); o3.stop(t2 + 0.18);
193
+ }, 180);
194
+ }
195
+
196
+ function showFrame(frame) {
197
+ imgIdle.style.opacity = frame === 'idle' ? '1' : '0';
198
+ imgBark.style.opacity = frame === 'bark' ? '1' : '0';
199
+ imgSmug.style.opacity = frame === 'smug' ? '1' : '0';
200
+ imgIdle.style.animation = frame === 'idle' ? 'idle 3s ease-in-out infinite' : 'none';
201
+ imgBark.style.animation = frame === 'bark' ? 'bark-bounce 0.15s ease-in-out 5' : 'none';
202
+ imgSmug.style.animation = frame === 'smug' ? 'smug-settle 0.3s ease-out forwards' : 'none';
203
+ }
204
+
205
+ function doBark() {
206
+ if (barking) return;
207
+ barking = true;
208
+ barkCount++;
209
+ const msg = MESSAGES[Math.floor(Math.random() * MESSAGES.length)];
210
+ showFrame('bark');
211
+ playBark();
212
+ bubble.textContent = msg;
213
+ bubble.classList.add('show');
214
+ clearTimeout(bubbleTimeout);
215
+ setTimeout(() => showFrame('smug'), 800);
216
+ bubbleTimeout = setTimeout(() => {
217
+ bubble.classList.remove('show');
218
+ showFrame('idle');
219
+ barking = false;
220
+ }, 2500);
221
+ counter.textContent = 'barks: ' + barkCount;
222
+ window.shiba.bark(msg);
223
+ }
224
+
225
+ document.getElementById('shibaWrap').addEventListener('click', doBark);
226
+ window.shiba.onTriggerBark(() => doBark());
227
+ </script>
228
+ </body>
229
+ </html>
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "barkclaude",
3
+ "version": "1.0.0",
4
+ "description": "An animated Shiba Inu that barks at Claude Code to make it work faster 🐕",
5
+ "main": "main.js",
6
+ "bin": {
7
+ "barkclaude": "./bin/barkclaude.js"
8
+ },
9
+ "scripts": {
10
+ "start": "electron ."
11
+ },
12
+ "keywords": ["claude", "claude-code", "shiba", "doge", "productivity", "fun"],
13
+ "author": "Egor Kuptsov",
14
+ "license": "MIT",
15
+ "files": [
16
+ "main.js",
17
+ "overlay.html",
18
+ "preload.js",
19
+ "bin/",
20
+ "assets/",
21
+ "README.md"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/mrWinsper/barkclaude.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/mrWinsper/barkclaude/issues"
29
+ },
30
+ "homepage": "https://github.com/mrWinsper/barkclaude#readme",
31
+ "dependencies": {
32
+ "electron": "^35.0.0"
33
+ }
34
+ }
package/preload.js ADDED
@@ -0,0 +1,7 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('shiba', {
4
+ bark: (msg) => ipcRenderer.send('bark', msg),
5
+ quit: () => ipcRenderer.send('quit'),
6
+ onTriggerBark: (cb) => ipcRenderer.on('trigger-bark', cb),
7
+ });