You can edit the below JavaScript code to customize the image tool.
Apply Changes
/**
* Game Image ID Finder
* Generates unique identifiers (like FNV-1a hashes and Crypto hashes)
* for an image's pixel data to be used as asset IDs in games/engines.
*
* @param {HTMLImageElement} originalImg - The original image file
* @param {string} idPrefix - Optional prefix to attach to generated IDs (e.g., "ASSET_")
* @param {string} hashAlgorithm - Algorithm for long unique ID (e.g., "SHA-256", "SHA-1")
* @returns {HTMLElement} A container displaying the image and its Game IDs.
*/
async function processImage(originalImg, idPrefix = "", hashAlgorithm = "SHA-256") {
// Create the main wrapper container
const container = document.createElement('div');
container.style.fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif';
container.style.textAlign = 'center';
container.style.padding = '24px';
container.style.backgroundColor = '#1e1e24';
container.style.color = '#ffffff';
container.style.borderRadius = '12px';
container.style.boxShadow = '0px 8px 16px rgba(0,0,0,0.5)';
container.style.boxSizing = 'border-box';
container.style.width = '100%';
// Title setup
const title = document.createElement('h2');
title.innerText = 'Game Asset ID Finder';
title.style.margin = '0 0 20px 0';
title.style.color = '#4facfe';
title.style.fontWeight = '600';
container.appendChild(title);
// Canvas for rendering and grabbing pixel data
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
ctx.drawImage(originalImg, 0, 0);
// Preview styling
const previewCanvas = document.createElement('canvas');
const previewCtx = previewCanvas.getContext('2d');
previewCanvas.width = originalImg.width;
previewCanvas.height = originalImg.height;
previewCtx.drawImage(originalImg, 0, 0);
previewCanvas.style.maxWidth = '100%';
previewCanvas.style.maxHeight = '240px';
previewCanvas.style.objectFit = 'contain';
previewCanvas.style.border = '1px solid #444';
previewCanvas.style.borderRadius = '8px';
previewCanvas.style.backgroundColor = 'transparent';
previewCanvas.style.marginBottom = '20px';
container.appendChild(previewCanvas);
// Get raw pixel data to compute deterministic hashes/IDs
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imgData.data;
// 1. Calculate a 32-bit Integer ID (FNV-1a Hash)
// FNV-1a is extremely common in game engines for creating quick integer asset IDs.
let hval = 0x811c9dc5;
for (let i = 0; i < data.length; i++) {
hval ^= data[i];
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
const assetId32Hex = (hval >>> 0).toString(16).toUpperCase().padStart(8, '0');
const assetIdInt = (hval >>> 0).toString();
// 2. Calculate a Cryptographic Unique Signature (e.g., SHA-256)
let cryptoHashHex = "Unavailable in HTTP context";
if (window.crypto && window.crypto.subtle) {
try {
// Validate algorithm against support
const validAlgos = ["SHA-1", "SHA-256", "SHA-384", "SHA-512"];
const algoParams = validAlgos.includes(hashAlgorithm.toUpperCase())
? hashAlgorithm.toUpperCase()
: "SHA-256";
const hashBuffer = await crypto.subtle.digest(algoParams, data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
cryptoHashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();
} catch (e) {
cryptoHashHex = "Error computing hash";
}
}
// Generate output fields
const idContainer = document.createElement('div');
idContainer.style.display = 'grid';
idContainer.style.gap = '16px';
idContainer.style.gridTemplateColumns = 'repeat(auto-fit, minmax(240px, 1fr))';
function addIdField(label, value) {
const fieldCard = document.createElement('div');
fieldCard.style.display = 'flex';
fieldCard.style.flexDirection = 'column';
fieldCard.style.alignItems = 'center';
fieldCard.style.background = '#2c2c36';
fieldCard.style.padding = '16px';
fieldCard.style.borderRadius = '8px';
fieldCard.style.border = '1px solid #3d3d4b';
const labelEl = document.createElement('span');
labelEl.innerText = label;
labelEl.style.fontSize = '12px';
labelEl.style.color = '#a1a1aa';
labelEl.style.textTransform = 'uppercase';
labelEl.style.letterSpacing = '0.5px';
labelEl.style.marginBottom = '8px';
fieldCard.appendChild(labelEl);
const valEl = document.createElement('div');
valEl.style.fontSize = '16px';
valEl.style.fontFamily = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
valEl.style.color = '#00e676';
valEl.style.wordBreak = 'break-all';
valEl.style.userSelect = 'all';
valEl.style.cursor = 'pointer';
valEl.title = 'Click to copy to clipboard';
const finalValue = idPrefix ? `${idPrefix}${value}` : value;
valEl.innerText = finalValue;
// Visual click-to-copy handler
valEl.addEventListener('click', () => {
if (navigator.clipboard) {
navigator.clipboard.writeText(finalValue).then(() => {
const originalColor = valEl.style.color;
valEl.style.color = '#ffffff'; // highlight white flash
setTimeout(() => { valEl.style.color = originalColor; }, 300);
}).catch(err => console.error("Copy failed", err));
}
});
fieldCard.appendChild(valEl);
idContainer.appendChild(fieldCard);
}
// Populate Fields
addIdField('Game Asset ID (Integer)', assetIdInt);
addIdField('Game Asset ID (Hex 32-bit)', assetId32Hex);
addIdField(`Checksum (${hashAlgorithm})`, cryptoHashHex);
container.appendChild(idContainer);
// Add instruction note
const note = document.createElement('p');
note.innerText = 'Click any ID above to copy it directly to your clipboard.';
note.style.fontSize = '12px';
note.style.color = '#71717a';
note.style.marginTop = '20px';
container.appendChild(note);
return container;
}
Apply Changes