first commit

This commit is contained in:
2026-05-25 19:07:12 +07:00
commit f29c67bff4
62 changed files with 13196 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
import fs from 'fs'
import path from 'path'
import { trace } from 'potrace'
import sharp from 'sharp'
const assetsDir = path.resolve(process.cwd(), 'src', 'assets')
const outJson = path.resolve(process.cwd(), 'src', 'data', 'slotClipPaths.json')
// theme slot definitions to inspect (matching stripThemes.js layout)
const themesToTrace = {
pink: { file: '1.png', slots: [ { x:80,y:160,width:440,height:290 }, { x:80,y:615,width:440,height:290 }, { x:80,y:1070,width:440,height:290 } ] },
ticket: { file: '8.png', slots: [ { x:80,y:160,width:440,height:290 }, { x:80,y:615,width:440,height:290 }, { x:80,y:1070,width:440,height:290 } ] },
music: { file: '9.png', slots: [ { x:78,y:50,width:444,height:333 }, { x:78,y:545,width:444,height:333 }, { x:78,y:1040,width:444,height:333 } ] },
bowtie: { file: '12.png', slots: [ { x:77,y:160,width:380,height:271 }, { x:77,y:549,width:380,height:271 }, { x:77,y:939,width:380,height:271 } ] },
}
async function traceSlot(themeId, fileName, slot, index, options) {
const src = path.join(assetsDir, fileName)
const tmp = path.join(process.cwd(), 'tmp', `${themeId}-slot-${index}.png`)
await fs.promises.mkdir(path.dirname(tmp), { recursive: true })
// crop the slot area with a small padding to capture edges
const pad = 2
await sharp(src)
.extract({ left: Math.max(0, slot.x - pad), top: Math.max(0, slot.y - pad), width: slot.width + pad*2, height: slot.height + pad*2 })
.resize(slot.width, slot.height)
.toFile(tmp)
const traceOptions = Object.assign({ background: 'transparent' }, options || {})
return new Promise((resolve, reject) => {
trace(tmp, traceOptions, (err, svg) => {
if (err) return reject(err)
// extract path d attribute
const m = svg.match(/<path[^>]*d="([^"]+)"/)
const d = m ? m[1] : null
resolve(d)
})
})
}
async function main() {
const out = {}
// parse CLI args for tuning options: --turdSize=20 --threshold=128 --optTolerance=0.4
const argv = process.argv.slice(2)
const cli = {}
for (const a of argv) {
const parts = a.replace(/^--/, '').split('=')
cli[parts[0]] = parts[1] === undefined ? true : parts[1]
}
const options = {}
if (cli.turdSize) options.turdSize = parseInt(cli.turdSize, 10)
if (cli.threshold) options.threshold = parseInt(cli.threshold, 10)
if (cli.optTolerance) options.optTolerance = parseFloat(cli.optTolerance)
if (cli.turnPolicy) options.turnPolicy = cli.turnPolicy
if (cli.background) options.background = cli.background
console.log('Tracing with options:', options)
for (const [themeId, info] of Object.entries(themesToTrace)) {
const paths = []
for (let i = 0; i < info.slots.length; i++) {
try {
process.stdout.write(`Tracing ${themeId} slot ${i}... `)
const d = await traceSlot(themeId, info.file, info.slots[i], i, options)
paths.push(d)
console.log('ok')
} catch (err) {
console.error('failed', err.message)
paths.push(null)
}
}
out[themeId] = paths
}
await fs.promises.writeFile(outJson, JSON.stringify(out, null, 2), 'utf8')
console.log('Wrote', outJson)
}
main().catch(err => { console.error(err); process.exit(1) })