Hardcoded developer local paths, non-existent source references, and integer underflow in asset-processing scripts

Author: codeCraft-RitikCreated Sep 12, 2026Updated Sep 12, 2026

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 .webp images were committed to the repository; none of the referenced .png source files exist under assets/.
  • 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 conditional if (a > 8) is never reached.
  • minX remains width and maxX remains 0.
  • 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 .mjs scripts import sharp (import sharp from "sharp";).
  • The repository has no package.json declaring dependencies or scripts.
  • Symptom: Executing node scripts/build-emil-sponsor-row.mjs fails with ERR_MODULE_NOT_FOUND.

Steps to Reproduce

  1. Clone the repository in a clean environment:
    git clone https://github.com/Leonxlnx/taste-skill.git
    cd taste-skill
    
  2. Attempt to run any maintenance script:
    node scripts/build-emil-sponsor-row.mjs
    
    Output: Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'sharp'
  3. Install sharp (npm i sharp) and execute asset conversion:
    node scripts/convert-readme-assets-webp.mjs
    
    Output: [Error: Input file is missing: .../assets/readme-banner.png]
  4. Run button processing script:
    node scripts/process-readme-buttons.mjs
    
    Output: [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.