mirror of
https://github.com/GitFrog1111/badclaude.git
synced 2026-06-07 07:33:55 +02:00
Initial commit
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
out/
|
||||
@@ -0,0 +1,42 @@
|
||||
# badclaude
|
||||
|
||||
Tiny Electron tray app that spawns a fake physics whip overlay and fires a terminal macro when the whip "cracks".
|
||||
|
||||
## Install + run (global CLI)
|
||||
|
||||
```bash
|
||||
npm install -g badclaude
|
||||
badclaude
|
||||
```
|
||||
|
||||
## Local dev
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Controls
|
||||
|
||||
- Click tray icon: show overlay + spawn whip.
|
||||
- Click tray icon again: drop/despawn whip (falls off-screen, overlay hides).
|
||||
- Fast whip motion triggers crack detection and macro send.
|
||||
- Mouse click while overlay is open also drops the whip.
|
||||
|
||||
## Macro on crack
|
||||
|
||||
On each crack event, the app immediately:
|
||||
|
||||
1. Sends interrupt (`Ctrl+C` on Windows, `Cmd+C` on macOS)
|
||||
2. Types a fast phrase
|
||||
3. Presses `Enter`
|
||||
|
||||
## Tweak physics
|
||||
|
||||
All whip tuning lives in `overlay.html` under the `P` settings object (`segments`, `constraintIters`, `crackSpeed`, gravity, arc, etc).
|
||||
|
||||
## Notes
|
||||
|
||||
- Windows macro path uses `koffi` + Win32 key events.
|
||||
- macOS macro path uses `osascript` (`System Events`) and requires Accessibility permission for the app/terminal running `badclaude`.
|
||||
- MVP/hacky by design.
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
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');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const appPath = path.resolve(__dirname, '..');
|
||||
|
||||
const child = spawn(electronBinary, [appPath], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
child.on('error', (err) => {
|
||||
console.error('Failed to start badclaude:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.unref();
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,211 @@
|
||||
const { app, BrowserWindow, Tray, Menu, ipcMain, nativeImage, screen } = require('electron');
|
||||
const path = require('path');
|
||||
const zlib = require('zlib');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const { execFile } = require('child_process');
|
||||
|
||||
// ── Win32 FFI (Windows only) ────────────────────────────────────────────────
|
||||
let keybd_event, VkKeyScanA;
|
||||
if (process.platform === 'win32') {
|
||||
try {
|
||||
const koffi = require('koffi');
|
||||
const user32 = koffi.load('user32.dll');
|
||||
keybd_event = user32.func('void __stdcall keybd_event(uint8_t bVk, uint8_t bScan, uint32_t dwFlags, uintptr_t dwExtraInfo)');
|
||||
VkKeyScanA = user32.func('int16_t __stdcall VkKeyScanA(int ch)');
|
||||
} catch (e) {
|
||||
console.warn('koffi not available – macro sending disabled', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Globals ─────────────────────────────────────────────────────────────────
|
||||
let tray, overlay;
|
||||
let overlayReady = false;
|
||||
let spawnQueued = false;
|
||||
|
||||
const VK_CONTROL = 0x11;
|
||||
const VK_RETURN = 0x0D;
|
||||
const VK_C = 0x43;
|
||||
const KEYUP = 0x0002;
|
||||
|
||||
// ── Tiny PNG encoder (for tray icon, no deps) ──────────────────────────────
|
||||
function makePNG(w, h, rgba) {
|
||||
const tbl = new Int32Array(256);
|
||||
for (let n = 0; n < 256; n++) {
|
||||
let c = n; for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
tbl[n] = c;
|
||||
}
|
||||
const crc32 = buf => { let c = -1; for (let i = 0; i < buf.length; i++) c = tbl[(c ^ buf[i]) & 0xff] ^ (c >>> 8); return (c ^ -1) >>> 0; };
|
||||
const chunk = (type, data) => {
|
||||
const t = Buffer.from(type), len = Buffer.alloc(4), crc = Buffer.alloc(4);
|
||||
len.writeUInt32BE(data.length);
|
||||
crc.writeUInt32BE(crc32(Buffer.concat([t, data])));
|
||||
return Buffer.concat([len, t, data, crc]);
|
||||
};
|
||||
const ihdr = Buffer.alloc(13);
|
||||
ihdr.writeUInt32BE(w, 0); ihdr.writeUInt32BE(h, 4); ihdr[8] = 8; ihdr[9] = 6;
|
||||
const raw = Buffer.alloc(h * (1 + w * 4));
|
||||
for (let y = 0; y < h; y++) { raw[y * (1 + w * 4)] = 0; rgba.copy(raw, y * (1 + w * 4) + 1, y * w * 4, (y + 1) * w * 4); }
|
||||
return Buffer.concat([Buffer.from([137,80,78,71,13,10,26,10]), chunk('IHDR', ihdr), chunk('IDAT', zlib.deflateSync(raw)), chunk('IEND', Buffer.alloc(0))]);
|
||||
}
|
||||
|
||||
function createTrayIconFallback() {
|
||||
const s = 16, px = Buffer.alloc(s * s * 4);
|
||||
for (let y = 0; y < s; y++) for (let x = 0; x < s; x++) {
|
||||
const i = (y * s + x) * 4, d = Math.hypot(x - 7.5, y - 7.5);
|
||||
if (d < 6.5) { px[i] = 200; px[i+1] = 40; px[i+2] = 40; px[i+3] = 255; }
|
||||
}
|
||||
const tmp = path.join(os.tmpdir(), 'badclaude-icon.png');
|
||||
fs.writeFileSync(tmp, makePNG(s, s, px));
|
||||
return nativeImage.createFromPath(tmp);
|
||||
}
|
||||
|
||||
function getTrayIcon() {
|
||||
const iconDir = path.join(__dirname, 'icon');
|
||||
const file =
|
||||
process.platform === 'win32' ? path.join(iconDir, 'icon.ico')
|
||||
: process.platform === 'darwin' ? path.join(iconDir, 'AppIcon.icns')
|
||||
: null;
|
||||
if (file && fs.existsSync(file)) {
|
||||
const img = nativeImage.createFromPath(file);
|
||||
if (!img.isEmpty()) return img;
|
||||
}
|
||||
return createTrayIconFallback();
|
||||
}
|
||||
|
||||
// ── Overlay window ──────────────────────────────────────────────────────────
|
||||
function createOverlay() {
|
||||
const { bounds } = screen.getPrimaryDisplay();
|
||||
overlay = new BrowserWindow({
|
||||
x: bounds.x, y: bounds.y,
|
||||
width: bounds.width, height: bounds.height,
|
||||
transparent: true,
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
focusable: false,
|
||||
skipTaskbar: true,
|
||||
resizable: false,
|
||||
hasShadow: false,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
},
|
||||
});
|
||||
overlay.setAlwaysOnTop(true, 'screen-saver');
|
||||
overlayReady = false;
|
||||
overlay.loadFile('overlay.html');
|
||||
overlay.webContents.on('did-finish-load', () => {
|
||||
overlayReady = true;
|
||||
if (spawnQueued && overlay && overlay.isVisible()) {
|
||||
spawnQueued = false;
|
||||
overlay.webContents.send('spawn-whip');
|
||||
}
|
||||
});
|
||||
overlay.on('closed', () => {
|
||||
overlay = null;
|
||||
overlayReady = false;
|
||||
spawnQueued = false;
|
||||
});
|
||||
}
|
||||
|
||||
function toggleOverlay() {
|
||||
if (overlay && overlay.isVisible()) {
|
||||
overlay.webContents.send('drop-whip');
|
||||
return;
|
||||
}
|
||||
if (!overlay) createOverlay();
|
||||
overlay.show();
|
||||
if (overlayReady) {
|
||||
overlay.webContents.send('spawn-whip');
|
||||
} else {
|
||||
spawnQueued = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ── IPC ─────────────────────────────────────────────────────────────────────
|
||||
ipcMain.on('whip-crack', () => {
|
||||
try {
|
||||
sendMacro();
|
||||
} catch (err) {
|
||||
console.warn('sendMacro failed:', err?.message || err);
|
||||
}
|
||||
});
|
||||
ipcMain.on('hide-overlay', () => { if (overlay) overlay.hide(); });
|
||||
|
||||
// ── Macro: immediate Ctrl+C, type "Go FASER", 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',
|
||||
];
|
||||
const chosen = phrases[Math.floor(Math.random() * phrases.length)];
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
sendMacroWindows(chosen);
|
||||
} else if (process.platform === 'darwin') {
|
||||
sendMacroMac(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
function sendMacroWindows(text) {
|
||||
if (!keybd_event || !VkKeyScanA) return;
|
||||
const tapKey = vk => {
|
||||
keybd_event(vk, 0, 0, 0);
|
||||
keybd_event(vk, 0, KEYUP, 0);
|
||||
};
|
||||
const tapChar = ch => {
|
||||
const packed = VkKeyScanA(ch.charCodeAt(0));
|
||||
if (packed === -1) return;
|
||||
const vk = packed & 0xff;
|
||||
const shiftState = (packed >> 8) & 0xff;
|
||||
if (shiftState & 1) keybd_event(0x10, 0, 0, 0); // Shift down
|
||||
tapKey(vk);
|
||||
if (shiftState & 1) keybd_event(0x10, 0, KEYUP, 0); // Shift up
|
||||
};
|
||||
|
||||
// Ctrl+C (interrupt)
|
||||
keybd_event(VK_CONTROL, 0, 0, 0);
|
||||
keybd_event(VK_C, 0, 0, 0);
|
||||
keybd_event(VK_C, 0, KEYUP, 0);
|
||||
keybd_event(VK_CONTROL, 0, KEYUP, 0);
|
||||
for (const ch of text) tapChar(ch);
|
||||
keybd_event(VK_RETURN, 0, 0, 0);
|
||||
keybd_event(VK_RETURN, 0, KEYUP, 0);
|
||||
}
|
||||
|
||||
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',
|
||||
` keystroke "${escaped}"`,
|
||||
' key code 36', // Enter
|
||||
'end tell'
|
||||
].join('\n');
|
||||
|
||||
execFile('osascript', ['-e', script], err => {
|
||||
if (err) {
|
||||
console.warn('mac macro failed (enable Accessibility for terminal/app):', err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── App lifecycle ───────────────────────────────────────────────────────────
|
||||
app.whenReady().then(() => {
|
||||
tray = new Tray(getTrayIcon());
|
||||
tray.setToolTip('Bad Claude – click for whip');
|
||||
tray.setContextMenu(
|
||||
Menu.buildFromTemplate([
|
||||
{ label: 'Quit', click: () => app.quit() },
|
||||
])
|
||||
);
|
||||
tray.on('click', toggleOverlay);
|
||||
});
|
||||
|
||||
app.on('window-all-closed', e => e.preventDefault()); // keep alive in tray
|
||||
+454
@@ -0,0 +1,454 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; cursor: none; }
|
||||
html, body { overflow: hidden; background: transparent; width: 100%; height: 100%; }
|
||||
canvas { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c"></canvas>
|
||||
<script>
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// PHYSICS SETTINGS — TWEAK EVERYTHING HERE
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
const P = {
|
||||
// Rope structure
|
||||
segments: 28, // number of chain links
|
||||
segmentLength: 25, // base length of each link (px)
|
||||
taper: 0.6, // tip segment is this fraction of base length
|
||||
|
||||
// Physics
|
||||
gravity: 1.2, // normal gravity
|
||||
dropGravity: 0.95, // gravity when dropping/despawning
|
||||
damping: 0.96, // velocity retention per frame (1 = no loss)
|
||||
constraintIters:20, // higher = stiffer chain
|
||||
maxStretchRatio: 1.2, // hard cap for per-link stretch during fast whips
|
||||
|
||||
// Dynamic handle aim (target angle + restoring spring, not static lock)
|
||||
baseTargetAngle: -1.12, // radians, default "up-right" resting direction
|
||||
handleAimByMouseX: 0.4, // horizontal mouse movement influence on target angle
|
||||
handleAimByMouseY: 0.2, // vertical mouse movement influence on target angle
|
||||
handleAimClamp: 2.0, // max radians target can deviate from base angle
|
||||
handleSpring: 0.7, // restoring force to target angle
|
||||
handleAngularDamping: 0.078, // angular velocity damping
|
||||
basePoseSegments: 2, // how many early segments are strongly guided
|
||||
basePoseStiffStart: 0.9, // stiffness near handle
|
||||
basePoseStiffEnd: 0.8, // stiffness near end of guided region
|
||||
|
||||
// Elastic bend limits by chain position (handle stiff, tip floppy)
|
||||
handleMaxBendDeg: 16, // max angle between links near handle
|
||||
tipMaxBendDeg: 130, // max angle between links near tip
|
||||
bendRigidityStart: 0.8, // correction strength near handle
|
||||
bendRigidityEnd: 0.12, // correction strength near tip
|
||||
|
||||
// Screen-edge slap
|
||||
wallBounce: 0.42, // velocity retained after wall hit
|
||||
wallFriction: 0.86, // tangential damping on wall hit
|
||||
|
||||
// Crack detection
|
||||
crackSpeed: 340, // tip velocity threshold to trigger crack
|
||||
crackCooldownMs:200, // min ms between cracks
|
||||
firstCrackGraceMs: 350, // no crack (macro) until this long after spawn
|
||||
|
||||
// Visuals
|
||||
lineWidthHandle: 7, // rope thickness near handle
|
||||
lineWidthTip: 5, // rope thickness near tip
|
||||
outlineWidth: 3, // white halo on each side of the stroke (approx px)
|
||||
handleExtraWidth: 5, // added core + outline thickness on first handleThickSegments links only
|
||||
handleThickSegments: 2, // how many links from the handle get handleExtraWidth
|
||||
bgAlpha: 0.011, // barely-visible bg so window captures mouse events
|
||||
|
||||
// Initial arc shape
|
||||
arcWidth: 260, // how far right the arc extends from mouse
|
||||
arcHeight: 185, // how high the arc goes above mouse
|
||||
};
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const canvas = document.getElementById('c');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let W, H;
|
||||
|
||||
function resize() { W = canvas.width = window.innerWidth; H = canvas.height = window.innerHeight; }
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
let mouseX = 0, mouseY = 0;
|
||||
let prevMouseX = 0, prevMouseY = 0;
|
||||
let whip = null;
|
||||
let dropping = false;
|
||||
let lastCrackTime = 0;
|
||||
let whipSpawnTime = 0;
|
||||
let handleAngle = P.baseTargetAngle;
|
||||
let handleAngVel = 0;
|
||||
|
||||
const WHIP_CRACK_SOUNDS = ['sounds/A.mp3', 'sounds/B.mp3', 'sounds/C.mp3', 'sounds/D.mp3', 'sounds/E.mp3'];
|
||||
|
||||
document.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; });
|
||||
document.addEventListener('mousedown', () => {
|
||||
if (whip && !dropping) dropping = true;
|
||||
});
|
||||
|
||||
// ── Whip creation ───────────────────────────────────────────────────────────
|
||||
function spawnWhip(mx, my) {
|
||||
dropping = false;
|
||||
lastCrackTime = 0;
|
||||
whipSpawnTime = Date.now();
|
||||
const pts = [];
|
||||
for (let i = 0; i < P.segments; i++) {
|
||||
const t = i / (P.segments - 1);
|
||||
// Nice upward arc from handle (mouse) to tip
|
||||
const x = mx + t * P.arcWidth;
|
||||
const y = my - Math.sin(t * Math.PI * 0.75) * P.arcHeight;
|
||||
pts.push({ x, y, px: x, py: y });
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
|
||||
function segLen(i) {
|
||||
const t = i / (P.segments - 1);
|
||||
return P.segmentLength * (1 - t * (1 - P.taper));
|
||||
}
|
||||
|
||||
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
||||
const lerp = (a, b, t) => a + (b - a) * t;
|
||||
|
||||
/** Point on Catmull–Rom spline (extrapolated ends) for index i in `pts`. */
|
||||
function catmullPoint(pts, i) {
|
||||
const n = pts.length;
|
||||
if (n === 0) return { x: 0, y: 0 };
|
||||
if (i < 0) {
|
||||
if (n >= 2) {
|
||||
return { x: 2 * pts[0].x - pts[1].x, y: 2 * pts[0].y - pts[1].y };
|
||||
}
|
||||
return { x: pts[0].x, y: pts[0].y };
|
||||
}
|
||||
if (i >= n) {
|
||||
if (n >= 2) {
|
||||
const a = pts[n - 2], b = pts[n - 1];
|
||||
return { x: 2 * b.x - a.x, y: 2 * b.y - a.y };
|
||||
}
|
||||
return { x: pts[n - 1].x, y: pts[n - 1].y };
|
||||
}
|
||||
return pts[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cubic Bézier from p1→p2 matching uniform Catmull–Rom through p0,p1,p2,p3.
|
||||
* Control points: C1 = p1 + (p2-p0)/6, C2 = p2 - (p3-p1)/6.
|
||||
*/
|
||||
function whipSegmentBezier(pts, i) {
|
||||
const p0 = catmullPoint(pts, i - 1);
|
||||
const p1 = pts[i];
|
||||
const p2 = pts[i + 1];
|
||||
const p3 = catmullPoint(pts, i + 2);
|
||||
return {
|
||||
cp1x: p1.x + (p2.x - p0.x) / 6,
|
||||
cp1y: p1.y + (p2.y - p0.y) / 6,
|
||||
cp2x: p2.x - (p3.x - p1.x) / 6,
|
||||
cp2y: p2.y - (p3.y - p1.y) / 6,
|
||||
x2: p2.x,
|
||||
y2: p2.y,
|
||||
};
|
||||
}
|
||||
const wrapPi = a => {
|
||||
while (a > Math.PI) a -= Math.PI * 2;
|
||||
while (a < -Math.PI) a += Math.PI * 2;
|
||||
return a;
|
||||
};
|
||||
|
||||
function playCrackSound() {
|
||||
if (!WHIP_CRACK_SOUNDS.length) return;
|
||||
const src = WHIP_CRACK_SOUNDS[Math.floor(Math.random() * WHIP_CRACK_SOUNDS.length)];
|
||||
const a = new Audio(src);
|
||||
a.play().catch(() => {});
|
||||
}
|
||||
|
||||
function updateHandleAim() {
|
||||
if (dropping) return;
|
||||
const mvx = mouseX - prevMouseX;
|
||||
const mvy = mouseY - prevMouseY;
|
||||
const delta = clamp(
|
||||
mvx * P.handleAimByMouseX + mvy * P.handleAimByMouseY,
|
||||
-P.handleAimClamp,
|
||||
P.handleAimClamp
|
||||
);
|
||||
const target = P.baseTargetAngle + delta;
|
||||
const err = wrapPi(target - handleAngle);
|
||||
handleAngVel += err * P.handleSpring;
|
||||
handleAngVel *= P.handleAngularDamping;
|
||||
handleAngle = wrapPi(handleAngle + handleAngVel);
|
||||
}
|
||||
|
||||
function applyBasePose() {
|
||||
if (!whip || dropping) return;
|
||||
const dx = Math.cos(handleAngle);
|
||||
const dy = Math.sin(handleAngle);
|
||||
const guided = Math.min(P.basePoseSegments, whip.length - 1);
|
||||
for (let i = 1; i <= guided; i++) {
|
||||
const t = (i - 1) / Math.max(guided - 1, 1);
|
||||
const stiff = lerp(P.basePoseStiffStart, P.basePoseStiffEnd, t);
|
||||
const prev = whip[i - 1];
|
||||
const p = whip[i];
|
||||
const targetLen = segLen(i - 1);
|
||||
const tx = prev.x + dx * targetLen;
|
||||
const ty = prev.y + dy * targetLen;
|
||||
p.x = lerp(p.x, tx, stiff);
|
||||
p.y = lerp(p.y, ty, stiff);
|
||||
}
|
||||
}
|
||||
|
||||
function applyBendLimits() {
|
||||
if (!whip || whip.length < 3) return;
|
||||
for (let i = 1; i < whip.length - 1; i++) {
|
||||
const a = whip[i - 1];
|
||||
const b = whip[i];
|
||||
const c = whip[i + 1];
|
||||
|
||||
const v1x = a.x - b.x;
|
||||
const v1y = a.y - b.y;
|
||||
const v2x = c.x - b.x;
|
||||
const v2y = c.y - b.y;
|
||||
const l1 = Math.hypot(v1x, v1y) || 0.0001;
|
||||
const l2 = Math.hypot(v2x, v2y) || 0.0001;
|
||||
const n1x = v1x / l1, n1y = v1y / l1;
|
||||
const n2x = v2x / l2, n2y = v2y / l2;
|
||||
|
||||
const dot = clamp(n1x * n2x + n1y * n2y, -1, 1);
|
||||
const angle = Math.acos(dot);
|
||||
const t = i / (whip.length - 2);
|
||||
const maxBend = lerp(P.handleMaxBendDeg, P.tipMaxBendDeg, t) * Math.PI / 180;
|
||||
const bend = Math.PI - angle; // bend away from a straight line
|
||||
if (bend <= maxBend) continue;
|
||||
|
||||
// Clamp to max bend while preserving side/sign of the bend.
|
||||
const cross = n1x * n2y - n1y * n2x;
|
||||
const sign = cross >= 0 ? 1 : -1;
|
||||
const targetAngle = Math.PI - maxBend;
|
||||
const targetA = Math.atan2(n1y, n1x) + sign * targetAngle;
|
||||
const tx = b.x + Math.cos(targetA) * l2;
|
||||
const ty = b.y + Math.sin(targetA) * l2;
|
||||
const rigidity = lerp(P.bendRigidityStart, P.bendRigidityEnd, t);
|
||||
|
||||
c.x = lerp(c.x, tx, rigidity);
|
||||
c.y = lerp(c.y, ty, rigidity);
|
||||
}
|
||||
}
|
||||
|
||||
function capSegmentStretch() {
|
||||
if (!whip || whip.length < 2) return;
|
||||
for (let i = 0; i < whip.length - 1; i++) {
|
||||
const a = whip[i];
|
||||
const b = whip[i + 1];
|
||||
const dx = b.x - a.x;
|
||||
const dy = b.y - a.y;
|
||||
const dist = Math.hypot(dx, dy) || 0.0001;
|
||||
const maxLen = segLen(i) * P.maxStretchRatio;
|
||||
if (dist <= maxLen) continue;
|
||||
const k = maxLen / dist;
|
||||
b.x = a.x + dx * k;
|
||||
b.y = a.y + dy * k;
|
||||
}
|
||||
}
|
||||
|
||||
function applyWallCollisions() {
|
||||
if (!whip || dropping) return; // disable collisions while dropping
|
||||
const start = 1; // keep pinned handle untouched
|
||||
for (let i = start; i < whip.length; i++) {
|
||||
const p = whip[i];
|
||||
let vx = p.x - p.px;
|
||||
let vy = p.y - p.py;
|
||||
let hit = false;
|
||||
|
||||
if (p.x < 0) {
|
||||
p.x = 0;
|
||||
if (vx < 0) vx = -vx * P.wallBounce;
|
||||
vy *= P.wallFriction;
|
||||
hit = true;
|
||||
} else if (p.x > W) {
|
||||
p.x = W;
|
||||
if (vx > 0) vx = -vx * P.wallBounce;
|
||||
vy *= P.wallFriction;
|
||||
hit = true;
|
||||
}
|
||||
|
||||
if (p.y < 0) {
|
||||
p.y = 0;
|
||||
if (vy < 0) vy = -vy * P.wallBounce;
|
||||
vx *= P.wallFriction;
|
||||
hit = true;
|
||||
} else if (p.y > H) {
|
||||
p.y = H;
|
||||
if (vy > 0) vy = -vy * P.wallBounce;
|
||||
vx *= P.wallFriction;
|
||||
hit = true;
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
p.px = p.x - vx;
|
||||
p.py = p.y - vy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Physics step ────────────────────────────────────────────────────────────
|
||||
function update() {
|
||||
if (!whip) return;
|
||||
|
||||
const g = dropping ? P.dropGravity : P.gravity;
|
||||
updateHandleAim();
|
||||
|
||||
// Verlet integration
|
||||
const start = dropping ? 0 : 1; // if dropping, handle is free too
|
||||
for (let i = start; i < whip.length; i++) {
|
||||
const p = whip[i];
|
||||
const vx = (p.x - p.px) * P.damping;
|
||||
const vy = (p.y - p.py) * P.damping;
|
||||
p.px = p.x;
|
||||
p.py = p.y;
|
||||
p.x += vx;
|
||||
p.y += vy + g;
|
||||
}
|
||||
|
||||
// Pin handle to mouse
|
||||
if (!dropping) {
|
||||
whip[0].x = mouseX;
|
||||
whip[0].y = mouseY;
|
||||
whip[0].px = mouseX;
|
||||
whip[0].py = mouseY;
|
||||
}
|
||||
|
||||
// Prevent rubber-band stretching spikes before constraints.
|
||||
capSegmentStretch();
|
||||
applyWallCollisions();
|
||||
|
||||
// Keep early whip segments posed upward from handle.
|
||||
applyBasePose();
|
||||
|
||||
// Distance constraints (multiple iterations for stiffness)
|
||||
for (let iter = 0; iter < P.constraintIters; iter++) {
|
||||
for (let i = 0; i < whip.length - 1; i++) {
|
||||
const a = whip[i], b = whip[i + 1];
|
||||
const dx = b.x - a.x, dy = b.y - a.y;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy) || 0.0001;
|
||||
const target = segLen(i);
|
||||
const diff = (dist - target) / dist * 0.5;
|
||||
const ox = dx * diff, oy = dy * diff;
|
||||
if (i === 0 && !dropping) {
|
||||
// Handle is pinned – push only the next point
|
||||
b.x -= ox * 2;
|
||||
b.y -= oy * 2;
|
||||
} else {
|
||||
a.x += ox; a.y += oy;
|
||||
b.x -= ox; b.y -= oy;
|
||||
}
|
||||
}
|
||||
// Clamp bend angle per joint; near handle = stiffer, near tip = floppier.
|
||||
applyBendLimits();
|
||||
if (!dropping) applyBasePose();
|
||||
capSegmentStretch();
|
||||
applyWallCollisions();
|
||||
}
|
||||
|
||||
// Tip velocity for crack detection
|
||||
const tip = whip[whip.length - 1];
|
||||
const tipVel = Math.hypot(tip.x - tip.px, tip.y - tip.py);
|
||||
|
||||
if (!dropping && tipVel > P.crackSpeed) {
|
||||
const now = Date.now();
|
||||
if (now - whipSpawnTime >= P.firstCrackGraceMs && now - lastCrackTime > P.crackCooldownMs) {
|
||||
lastCrackTime = now;
|
||||
playCrackSound();
|
||||
window.bridge.whipCrack();
|
||||
}
|
||||
}
|
||||
|
||||
// If dropping, check if everything fell off screen
|
||||
if (dropping && whip.every(p => p.y > H + 60)) {
|
||||
whip = null;
|
||||
dropping = false;
|
||||
window.bridge.hideOverlay();
|
||||
}
|
||||
prevMouseX = mouseX;
|
||||
prevMouseY = mouseY;
|
||||
}
|
||||
|
||||
// ── Rendering ───────────────────────────────────────────────────────────────
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
|
||||
// Near-invisible fill so the window captures mouse events on Windows
|
||||
ctx.fillStyle = `rgba(0,0,0,${P.bgAlpha})`;
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
if (!whip) return;
|
||||
|
||||
// White: thin halo on full spline, then extra thickness only over handle links.
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
ctx.strokeStyle = '#fff';
|
||||
if (whip.length >= 2) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(whip[0].x, whip[0].y);
|
||||
for (let i = 0; i < whip.length - 1; i++) {
|
||||
const { cp1x, cp1y, cp2x, cp2y, x2, y2 } = whipSegmentBezier(whip, i);
|
||||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2);
|
||||
}
|
||||
ctx.lineWidth = P.lineWidthTip + P.outlineWidth * 2;
|
||||
ctx.stroke();
|
||||
|
||||
const thickLinks = Math.min(P.handleThickSegments, whip.length - 1);
|
||||
if (thickLinks > 0 && P.handleExtraWidth > 0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(whip[0].x, whip[0].y);
|
||||
for (let i = 0; i < thickLinks; i++) {
|
||||
const { cp1x, cp1y, cp2x, cp2y, x2, y2 } = whipSegmentBezier(whip, i);
|
||||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2);
|
||||
}
|
||||
ctx.lineWidth =
|
||||
P.lineWidthHandle + P.handleExtraWidth + P.outlineWidth * 2;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
ctx.strokeStyle = '#111';
|
||||
for (let i = 0; i < whip.length - 1; i++) {
|
||||
const t = i / Math.max(1, whip.length - 2);
|
||||
const extra = i < P.handleThickSegments ? P.handleExtraWidth : 0;
|
||||
ctx.lineWidth = lerp(P.lineWidthHandle, P.lineWidthTip, t) + extra;
|
||||
const { cp1x, cp1y, cp2x, cp2y, x2, y2 } = whipSegmentBezier(whip, i);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(whip[i].x, whip[i].y);
|
||||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Main loop ───────────────────────────────────────────────────────────────
|
||||
function loop() {
|
||||
update();
|
||||
draw();
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
loop();
|
||||
|
||||
// ── IPC from main process ───────────────────────────────────────────────────
|
||||
window.bridge.onSpawnWhip(() => {
|
||||
whip = spawnWhip(mouseX || W / 2, mouseY || H / 2);
|
||||
dropping = false;
|
||||
prevMouseX = mouseX;
|
||||
prevMouseY = mouseY;
|
||||
handleAngle = P.baseTargetAngle;
|
||||
handleAngVel = 0;
|
||||
});
|
||||
|
||||
window.bridge.onDropWhip(() => {
|
||||
if (whip && !dropping) dropping = true;
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+815
@@ -0,0 +1,815 @@
|
||||
{
|
||||
"name": "badclaude",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "badclaude",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"electron": "^33.0.0",
|
||||
"koffi": "^2.9.0"
|
||||
},
|
||||
"bin": {
|
||||
"badclaude": "bin/badclaude.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/get": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
|
||||
"integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"env-paths": "^2.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"got": "^11.8.5",
|
||||
"progress": "^2.0.3",
|
||||
"semver": "^6.2.0",
|
||||
"sumchecker": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"global-agent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-cache-semantics": "*",
|
||||
"@types/keyv": "^3.1.4",
|
||||
"@types/node": "*",
|
||||
"@types/responselike": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
"integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/keyv": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
|
||||
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/responselike": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
|
||||
"integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/boolean": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
||||
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-lookup": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
|
||||
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-request": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
|
||||
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clone-response": "^1.0.2",
|
||||
"get-stream": "^5.1.0",
|
||||
"http-cache-semantics": "^4.0.0",
|
||||
"keyv": "^4.0.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"normalize-url": "^6.0.1",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-response": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||
"integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response/node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/defer-to-connect": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
|
||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "33.4.11",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-33.4.11.tgz",
|
||||
"integrity": "sha512-xmdAs5QWRkInC7TpXGNvzo/7exojubk+72jn1oJL7keNeIlw7xNglf8TGtJtkR4rWC5FJq0oXiIXPS9BcK2Irg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"@types/node": "^20.9.0",
|
||||
"extract-zip": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"electron": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.20.55"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/env-paths": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-error": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
||||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/extract-zip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"extract-zip": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@types/yauzl": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
|
||||
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"matcher": "^3.0.0",
|
||||
"roarr": "^2.15.3",
|
||||
"semver": "^7.3.2",
|
||||
"serialize-error": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/globalthis": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.1",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "11.8.6",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
"@types/cacheable-request": "^6.0.1",
|
||||
"@types/responselike": "^1.0.0",
|
||||
"cacheable-lookup": "^5.0.3",
|
||||
"cacheable-request": "^7.0.2",
|
||||
"decompress-response": "^6.0.0",
|
||||
"http2-wrapper": "^1.0.0-beta.5.2",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/got?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/http2-wrapper": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
|
||||
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve-alpn": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/koffi": {
|
||||
"version": "2.15.3",
|
||||
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.15.3.tgz",
|
||||
"integrity": "sha512-xpMeXDn471TJdrnPoTh/v3ekTdmxaD0DD2PsxgKTeetiXY+1+LeVdthleh2bOZGT7aMZnR+20U9mj4UkIlP8kA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://liberapay.com/Koromix"
|
||||
}
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/matcher": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-url": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/p-cancelable": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/quick-lru": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-alpn": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/responselike": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lowercase-keys": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"detect-node": "^2.0.4",
|
||||
"globalthis": "^1.0.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"semver-compare": "^1.0.0",
|
||||
"sprintf-js": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/semver-compare": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/serialize-error": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
|
||||
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sumchecker": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "badclaude",
|
||||
"version": "1.0.0",
|
||||
"description": "Whip Claude into shape",
|
||||
"license": "MIT",
|
||||
"main": "main.js",
|
||||
"bin": {
|
||||
"badclaude": "./bin/badclaude.js"
|
||||
},
|
||||
"os": [
|
||||
"darwin",
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"electron",
|
||||
"tray",
|
||||
"overlay",
|
||||
"cli"
|
||||
],
|
||||
"files": [
|
||||
"main.js",
|
||||
"preload.js",
|
||||
"overlay.html",
|
||||
"sounds",
|
||||
"icon",
|
||||
"bin/badclaude.js",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"dev": "electron .",
|
||||
"pack": "npm pack"
|
||||
},
|
||||
"dependencies": {
|
||||
"electron": "^33.0.0",
|
||||
"koffi": "^2.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld('bridge', {
|
||||
whipCrack: () => ipcRenderer.send('whip-crack'),
|
||||
hideOverlay: () => ipcRenderer.send('hide-overlay'),
|
||||
onSpawnWhip: (fn) => ipcRenderer.on('spawn-whip', () => fn()),
|
||||
onDropWhip: (fn) => ipcRenderer.on('drop-whip', () => fn()),
|
||||
});
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user