Four directions per tile (neon box art / vector side art / amiga comic / 80s airbrush) generated on the farm, plus the picker page and the installer that ships chosen art and its risograph hover b-side. Recipe rules, all learned the hard way against the existing covers: tiles render 172-240px so silhouette and colour are all that read; the page draws every title in HTML so art carries no lettering (the old covers baked in garbled type); busy interiors smuggle text back via album sleeves and go muddy small, so it is one hero subject per card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
63 lines
2.8 KiB
Python
63 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Build the 4-variant card-art spec for monsterrobot.games from profiles.json.
|
|
|
|
Recipe rules, all learned from the bake-off against the existing covers:
|
|
* Tiles render 172-240px wide -> silhouette and colour are all that read.
|
|
* The page draws every title in HTML, so art carries NO lettering. The old
|
|
covers baked in garbled type ("INFTE! COPFRIICGN") - that is the slop tell.
|
|
* Busy interiors smuggle text back in via album sleeves/posters and go muddy
|
|
at thumbnail size. Single hero subject, always.
|
|
"""
|
|
import json, os, sys
|
|
|
|
OUT = sys.argv[2] if len(sys.argv) > 2 else '/private/tmp/claude-501/-Users-m3ultra-Documents/097e3817-807d-439d-b5f5-95a6ffd4a1f9/scratchpad/cards'
|
|
|
|
READS = ("single bold hero subject filling the frame, strong clean silhouette, "
|
|
"dramatic rim light, high contrast, saturated limited palette, "
|
|
"deep dark background, poster composition, reads clearly at thumbnail size")
|
|
NOTEXT = ("completely wordless, no text, no letters, no words, no title, no logo, "
|
|
"no signage, no watermark, no signature, blank unlabelled sleeves and "
|
|
"plain unmarked surfaces")
|
|
|
|
VARIANTS = [
|
|
# key model steps style
|
|
('neon', 'flux2-klein-4b', 4,
|
|
"1987 British home-computer game box art, airbrushed gouache, glossy "
|
|
"highlights, heroic low angle, screaming neon cyan and magenta on pure black"),
|
|
('vector', 'flux2-klein-4b', 4,
|
|
"1980s arcade cabinet side art, bold flat vector shapes, hard edges, thick "
|
|
"black outlines, blazing neon on black, geometric and graphic, no gradients"),
|
|
('comic', 'flux2-klein-4b', 4,
|
|
"early-1990s Amiga game cover painting, chunky saturated brushwork, bold cel "
|
|
"shading, comic-book energy, primary colours, dark vignette"),
|
|
('paint', 'z-image-turbo', 8,
|
|
"classic 1980s airbrush poster painting, silhouetted figures against a glowing "
|
|
"backlit haze, lush deep colour, cinematic, painted on black"),
|
|
]
|
|
|
|
|
|
def main():
|
|
profiles = json.load(open(sys.argv[1]))
|
|
spec = []
|
|
for p in profiles:
|
|
subj = p['hero_subject']
|
|
pal = p.get('palette') or ''
|
|
for key, model, steps, style in VARIANTS:
|
|
params = {
|
|
'prompt': f"{style}. {subj}. {pal + '. ' if pal else ''}{READS}. {NOTEXT}",
|
|
'model': model, 'steps': steps,
|
|
'width': 896, 'height': 1152, 'seed': 7,
|
|
}
|
|
if model == 'z-image-turbo':
|
|
params['quantize'] = '4'
|
|
spec.append({'out': f"{OUT}/{p['id']}__{key}.png",
|
|
'operator': 'flux_local', 'params': params})
|
|
os.makedirs(OUT, exist_ok=True)
|
|
path = OUT + '/spec.json'
|
|
json.dump(spec, open(path, 'w'), indent=1)
|
|
print(f'{len(spec)} jobs ({len(profiles)} games x {len(VARIANTS)}) -> {path}')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|