Hardcoded developer local paths, non-existent source references, and integer underflow in asset-processing scripts
Issue Title
[BUG] Hardcoded developer local paths, non-existent source references, and integer underflow in asset-processing scripts
Description
All image and asset maintenance scripts under scripts/ (convert-readme-assets-webp.mjs, process-readme-buttons.mjs, process-sponsor-badge.mjs, build-emil-sponsor-row.mjs) fail immediately when executed in clean checkouts. They contain hardcoded developer-specific local Windows file paths (C:/Users/User/Downloads/...), reference missing .png source assets, suffer from negative dimension underflows in bounding-box calculations, and lack a root package.json dependency manifest.
Affected Files & Lines
scripts/convert-readme-assets-webp.mjs(Lines 7–14, 49–74, 93–133)scripts/process-readme-buttons.mjs(Lines 5–14, 54–79)scripts/process-sponsor-badge.mjs(Lines 5–7, 42–67)scripts/build-emil-sponsor-row.mjs(Line 3)- Root Repository (Missing
package.json)
Summary of Bugs
1. Hardcoded Local Machine Absolute Paths
In scripts/process-readme-buttons.mjs:
// Line 5
const srcDir = "C:/Users/User/Downloads";
const mapping = [
{ src: "ChatGPT Image Jun 17, 2026, 04_04_16 PM (1).png", out: "btn-site.png" },
// ...
];
In scripts/process-sponsor-badge.mjs and scripts/convert-readme-assets-webp.mjs:
const src = "C:/Users/User/Downloads/c4f8c4a7-2566-4644-b752-b652e0c103f5.png";
const jfif = "C:/Users/User/Downloads/6b610a0c-8889-49fc-9684-e172d7172ea0.jfif";
- The Problem: The scripts hardcode absolute file paths to a specific user account (
C:/Users/User/Downloads/) and transient filenames from local ChatGPT image downloads. - Symptom: The scripts fail immediately on any other machine, operating system (macOS/Linux), or CI/CD workflow with unhandled
Error: Input file is missing.
2. Referencing Non-Existent Source Files
In scripts/convert-readme-assets-webp.mjs:
const pngToWebp = [
"assets/readme-banner.png",
"assets/readme-buttons/btn-site.png",
"assets/readme-buttons/btn-mit.png",
"assets/readme-buttons/btn-agent-skills.png",
"assets/readme-buttons/btn-tools.png",
"assets/readme-buttons/btn-changelog.png",
];
- The Problem: Only
.webpimages were committed to the repository; none of the referenced.pngsource files exist underassets/. - Symptom: Running the script throws on the first iteration:
[Error: Input file is missing: .../assets/readme-banner.png].
3. Mathematical Integer Underflow in getBounds()
In convert-readme-assets-webp.mjs and process-readme-buttons.mjs:
function getBounds(rgba, width, height) {
let minX = width;
let minY = height;
let maxX = 0;
let maxY = 0;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const a = rgba[(y * width + x) * 4 + 3];
if (a > 8) {
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
}
}
const pad = 2;
return {
left: Math.max(0, minX - pad),
top: Math.max(0, minY - pad),
width: Math.min(width, maxX - minX + 1 + pad * 2),
height: Math.min(height, maxY - minY + 1 + pad * 2),
};
}
- The Problem: If an input image is transparent or if
removeOuterBackground()strips all pixels with alpha> 8, the conditionalif (a > 8)is never reached. minXremainswidthandmaxXremains0.- Formula evaluates to:
width = Math.min(width, 0 - width + 1 + 4) = 5 - width, which yields a negative integer for any image wider than 5px. - Symptom: Sharp crashes during
.extract(bounds):[Error: Expected positive integer for width but received -1395].
4. Missing Root package.json
- All
.mjsscripts importsharp(import sharp from "sharp";). - The repository has no
package.jsondeclaring dependencies or scripts. - Symptom: Executing
node scripts/build-emil-sponsor-row.mjsfails withERR_MODULE_NOT_FOUND.
Steps to Reproduce
- Clone the repository in a clean environment:
git clone https://github.com/Leonxlnx/taste-skill.git cd taste-skill - Attempt to run any maintenance script:
Output:node scripts/build-emil-sponsor-row.mjsError [ERR_MODULE_NOT_FOUND]: Cannot find package 'sharp' - Install sharp (
npm i sharp) and execute asset conversion:
Output:node scripts/convert-readme-assets-webp.mjs[Error: Input file is missing: .../assets/readme-banner.png] - Run button processing script:
Output:node scripts/process-readme-buttons.mjs[Error: Input file is missing: C:\Users\User\Downloads\ChatGPT Image Jun 17, 2026, 04_04_16 PM (1).png]
Proposed Fix / Drop-in Replacement
1. Add Root package.json
Create package.json at repository root:
{
"name": "taste-skill",
"version": "1.0.0",
"private": true,
"type": "module",
"description": "Anti-slop frontend design skills for AI agents",
"scripts": {
"assets:convert": "node scripts/convert-readme-assets-webp.mjs",
"assets:buttons": "node scripts/process-readme-buttons.mjs",
"assets:sponsors": "node scripts/build-emil-sponsor-row.mjs"
},
"devDependencies": {
"sharp": "^0.33.5"
}
}
2. Robust, Underflow-Proof getBounds() Implementation
Replace getBounds() in scripts/convert-readme-assets-webp.mjs, scripts/process-readme-buttons.mjs, and scripts/process-sponsor-badge.mjs with:
/**
* Safely computes non-transparent bounding box with boundary protection.
* Prevents integer underflows and crashes on fully-keyed or empty images.
*/
function getBounds(rgba, width, height, pad = 2) {
let minX = width;
let minY = height;
let maxX = -1;
let maxY = -1;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const alpha = rgba[(y * width + x) * 4 + 3];
if (alpha > 8) {
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
}
}
// Guard: If no non-transparent pixels exist, return fallback full-canvas dimensions
if (maxX === -1 || maxY === -1) {
return { left: 0, top: 0, width, height };
}
const left = Math.max(0, minX - pad);
const top = Math.max(0, minY - pad);
const right = Math.min(width, maxX + 1 + pad);
const bottom = Math.min(height, maxY + 1 + pad);
return {
left,
top,
width: Math.max(1, right - left),
height: Math.max(1, bottom - top),
};
}
3. Portable Script Configuration (Configurable Paths & File Existence Checks)
Replace hardcoded paths with CLI arguments and environment variables in scripts/process-readme-buttons.mjs:
import fs from "fs";
import path from "path";
import sharp from "sharp";
// Allow source directory override via CLI argument or environment variable
const srcDir = process.argv[2] || process.env.SOURCE_DIR || path.join(process.cwd(), "raw-assets");
const outDir = path.join(process.cwd(), "assets/readme-buttons");
if (!fs.existsSync(srcDir)) {
console.warn(`Source directory not found: ${srcDir}. Provide raw assets directory to run.`);
process.exit(0);
}
fs.mkdirSync(outDir, { recursive: true });
for (const { src, out } of mapping) {
const fullSrc = path.join(srcDir, src);
if (!fs.existsSync(fullSrc)) {
console.warn(`Skipping missing asset: ${src}`);
continue;
}
await processOne(fullSrc, path.join(outDir, out));
}
In scripts/convert-readme-assets-webp.mjs:
for (const file of pngToWebp) {
const input = path.join(root, file);
if (!fs.existsSync(input)) {
console.warn(`Skipping missing file: ${file}`);
continue;
}
await pngFileToWebp(file, {
maxWidth: file.includes("readme-buttons") ? 1400 : undefined,
});
}
Key Improvements in the Fix
| Area | Before | After |
|---|---|---|
| Portability | Hardcoded C:/Users/User/Downloads crashes on all other machines |
Environment variables / CLI arguments with local fallback directory. |
| Missing Files | Script crashes immediately when .png files are absent |
Safe fs.existsSync() checks skip missing files with informative warnings. |
| Bounding Box Math | minX=width and maxX=0 yields negative width (5 - width) |
Guard checks for maxX === -1 and safely clamps dimensions to Math.max(1, ...). |
| Dependency Setup | Missing package.json prevents npm install and script execution |
Fully configured root package.json with npm scripts and devDependencies. |
Source: Leonxlnx/taste-skill