cull.lmth
All 39 lines. No libraries, nothing hidden. Read it before you run it.
<!doctype html>
<meta charset="utf-8">
<meta name="resworb-write" content=".">
<title>Cull</title>
<style>
html, body { height: 100%; margin: 0; background: #111; color: #eee; font: 14px system-ui, sans-serif; }
img { display: block; width: 100%; height: 100%; object-fit: contain; }
p { position: fixed; left: 1rem; bottom: 1rem; margin: 0; }
</style>
<img id="photo" alt="">
<p id="progress"></p>
<script type="module">
// → keeps the photo, ← moves it to ./rejects, Z takes back the last choice.
const photos = (await resworb.readdir('.')).filter(name => /\.(jpe?g|png|gif|webp)$/i.test(name)).sort();
const choices = [];
await resworb.mkdir('rejects');
show();
addEventListener('keydown', async ({ key }) => {
const name = photos[choices.length];
if (key === 'ArrowRight' && name) {
choices.push({ name, kept: true });
} else if (key === 'ArrowLeft' && name) {
choices.push({ name, kept: false });
await resworb.rename(name, `rejects/${name}`);
} else if (key === 'z' && choices.length) {
const last = choices.pop();
if (!last.kept) await resworb.rename(`rejects/${last.name}`, last.name);
}
show();
});
function show() {
const name = photos[choices.length];
const kept = choices.filter(choice => choice.kept).length;
photo.src = name ? encodeURIComponent(name) : '';
progress.textContent = name ? `${choices.length + 1} / ${photos.length}, kept ${kept} · ${name}` : `Done. Kept ${kept} of ${photos.length}.`;
}
</script>