Spaces:
Running on Zero
Running on Zero
Make sprites change with theme
Browse files
app.py
CHANGED
|
@@ -2,6 +2,7 @@ import base64
|
|
| 2 |
import hashlib
|
| 3 |
import io
|
| 4 |
import json
|
|
|
|
| 5 |
import random
|
| 6 |
import re
|
| 7 |
import tempfile
|
|
@@ -377,18 +378,19 @@ def draw_background(spec: AssetSpec, rng: random.Random) -> bytes:
|
|
| 377 |
|
| 378 |
|
| 379 |
def draw_sprite(spec: AssetSpec, rng: random.Random) -> bytes:
|
| 380 |
-
colors = palette_for(spec.prompt)
|
| 381 |
image = Image.new("RGBA", (spec.width, spec.height), (0, 0, 0, 0))
|
| 382 |
draw = ImageDraw.Draw(image, "RGBA")
|
| 383 |
cx, cy = spec.width // 2, spec.height // 2
|
| 384 |
scale = min(spec.width, spec.height) / 128
|
|
|
|
| 385 |
role_prompt = f"{spec.role} {spec.prompt}".lower()
|
| 386 |
outline = (18, 24, 31, 255)
|
| 387 |
body = colors[0] + (255,)
|
| 388 |
accent = colors[1] + (255,)
|
| 389 |
trim = colors[3] + (255,)
|
| 390 |
|
| 391 |
-
if any(word in role_prompt for word in ("bullet", "projectile", "laser", "energy")):
|
| 392 |
glow = colors[1] + (85,)
|
| 393 |
draw.ellipse((cx - 30 * scale, cy - 42 * scale, cx + 30 * scale, cy + 42 * scale), fill=glow)
|
| 394 |
draw.rounded_rectangle(
|
|
@@ -405,9 +407,9 @@ def draw_sprite(spec: AssetSpec, rng: random.Random) -> bytes:
|
|
| 405 |
image.save(out, format="PNG")
|
| 406 |
return out.getvalue()
|
| 407 |
|
| 408 |
-
if any(word in role_prompt for word in ("enemy", "drone", "alien", "monster")):
|
| 409 |
draw.ellipse((cx - 38 * scale, cy - 28 * scale, cx + 38 * scale, cy + 28 * scale), fill=outline)
|
| 410 |
-
draw.ellipse((cx - 32 * scale, cy - 22 * scale, cx + 32 * scale, cy + 22 * scale), fill=
|
| 411 |
draw.ellipse((cx - 16 * scale, cy - 16 * scale, cx + 16 * scale, cy + 16 * scale), fill=accent)
|
| 412 |
for side in (-1, 1):
|
| 413 |
draw.polygon(
|
|
@@ -419,33 +421,47 @@ def draw_sprite(spec: AssetSpec, rng: random.Random) -> bytes:
|
|
| 419 |
fill=outline,
|
| 420 |
)
|
| 421 |
draw.line((cx + side * 14 * scale, cy, cx + side * 58 * scale, cy), fill=trim, width=max(2, int(5 * scale)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 422 |
out = io.BytesIO()
|
| 423 |
image.save(out, format="PNG")
|
| 424 |
return out.getvalue()
|
| 425 |
|
| 426 |
-
if any(word in role_prompt for word in ("shooter", "ship", "tank", "hero", "player", "armored")):
|
| 427 |
shadow = (int(cx - 36 * scale), int(cy + 34 * scale), int(cx + 36 * scale), int(cy + 48 * scale))
|
| 428 |
draw.ellipse(shadow, fill=(0, 0, 0, 55))
|
|
|
|
|
|
|
| 429 |
draw.polygon(
|
| 430 |
[
|
| 431 |
-
(cx, cy -
|
| 432 |
-
(cx -
|
| 433 |
(cx, cy + 20 * scale),
|
| 434 |
-
(cx +
|
| 435 |
],
|
| 436 |
fill=outline,
|
| 437 |
)
|
| 438 |
draw.polygon(
|
| 439 |
[
|
| 440 |
-
(cx, cy -
|
| 441 |
-
(cx -
|
| 442 |
(cx, cy + 12 * scale),
|
| 443 |
-
(cx +
|
| 444 |
],
|
| 445 |
fill=body,
|
| 446 |
)
|
| 447 |
draw.ellipse((cx - 11 * scale, cy - 14 * scale, cx + 11 * scale, cy + 10 * scale), fill=accent)
|
| 448 |
draw.line((cx, cy - 42 * scale, cx, cy - 62 * scale), fill=trim, width=max(3, int(6 * scale)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 449 |
out = io.BytesIO()
|
| 450 |
image.save(out, format="PNG")
|
| 451 |
return out.getvalue()
|
|
|
|
| 2 |
import hashlib
|
| 3 |
import io
|
| 4 |
import json
|
| 5 |
+
import math
|
| 6 |
import random
|
| 7 |
import re
|
| 8 |
import tempfile
|
|
|
|
| 378 |
|
| 379 |
|
| 380 |
def draw_sprite(spec: AssetSpec, rng: random.Random) -> bytes:
|
| 381 |
+
colors = palette_for(f"{spec.role} {spec.prompt}")
|
| 382 |
image = Image.new("RGBA", (spec.width, spec.height), (0, 0, 0, 0))
|
| 383 |
draw = ImageDraw.Draw(image, "RGBA")
|
| 384 |
cx, cy = spec.width // 2, spec.height // 2
|
| 385 |
scale = min(spec.width, spec.height) / 128
|
| 386 |
+
role = slugify(spec.role)
|
| 387 |
role_prompt = f"{spec.role} {spec.prompt}".lower()
|
| 388 |
outline = (18, 24, 31, 255)
|
| 389 |
body = colors[0] + (255,)
|
| 390 |
accent = colors[1] + (255,)
|
| 391 |
trim = colors[3] + (255,)
|
| 392 |
|
| 393 |
+
if role in ("bullet", "projectile", "laser", "shot") or any(word in role_prompt for word in ("bullet", "projectile", "laser", "energy")):
|
| 394 |
glow = colors[1] + (85,)
|
| 395 |
draw.ellipse((cx - 30 * scale, cy - 42 * scale, cx + 30 * scale, cy + 42 * scale), fill=glow)
|
| 396 |
draw.rounded_rectangle(
|
|
|
|
| 407 |
image.save(out, format="PNG")
|
| 408 |
return out.getvalue()
|
| 409 |
|
| 410 |
+
if role in ("enemy", "monster", "alien", "drone", "foe", "boss") or any(word in role_prompt for word in ("enemy", "drone", "alien", "monster")):
|
| 411 |
draw.ellipse((cx - 38 * scale, cy - 28 * scale, cx + 38 * scale, cy + 28 * scale), fill=outline)
|
| 412 |
+
draw.ellipse((cx - 32 * scale, cy - 22 * scale, cx + 32 * scale, cy + 22 * scale), fill=body)
|
| 413 |
draw.ellipse((cx - 16 * scale, cy - 16 * scale, cx + 16 * scale, cy + 16 * scale), fill=accent)
|
| 414 |
for side in (-1, 1):
|
| 415 |
draw.polygon(
|
|
|
|
| 421 |
fill=outline,
|
| 422 |
)
|
| 423 |
draw.line((cx + side * 14 * scale, cy, cx + side * 58 * scale, cy), fill=trim, width=max(2, int(5 * scale)))
|
| 424 |
+
for _ in range(5):
|
| 425 |
+
angle = rng.random() * 6.283
|
| 426 |
+
r = rng.randint(int(12 * scale), int(30 * scale))
|
| 427 |
+
px = cx + int(r * math.cos(angle))
|
| 428 |
+
py = cy + int(r * math.sin(angle))
|
| 429 |
+
draw.ellipse((px - 3 * scale, py - 3 * scale, px + 3 * scale, py + 3 * scale), fill=trim)
|
| 430 |
out = io.BytesIO()
|
| 431 |
image.save(out, format="PNG")
|
| 432 |
return out.getvalue()
|
| 433 |
|
| 434 |
+
if role in ("player", "hero", "ship", "tank", "avatar") or any(word in role_prompt for word in ("shooter", "ship", "tank", "hero", "player", "armored")):
|
| 435 |
shadow = (int(cx - 36 * scale), int(cy + 34 * scale), int(cx + 36 * scale), int(cy + 48 * scale))
|
| 436 |
draw.ellipse(shadow, fill=(0, 0, 0, 55))
|
| 437 |
+
wing = rng.randint(28, 39)
|
| 438 |
+
nose = rng.randint(45, 56)
|
| 439 |
draw.polygon(
|
| 440 |
[
|
| 441 |
+
(cx, cy - nose * scale),
|
| 442 |
+
(cx - wing * scale, cy + 34 * scale),
|
| 443 |
(cx, cy + 20 * scale),
|
| 444 |
+
(cx + wing * scale, cy + 34 * scale),
|
| 445 |
],
|
| 446 |
fill=outline,
|
| 447 |
)
|
| 448 |
draw.polygon(
|
| 449 |
[
|
| 450 |
+
(cx, cy - (nose - 8) * scale),
|
| 451 |
+
(cx - (wing - 10) * scale, cy + 23 * scale),
|
| 452 |
(cx, cy + 12 * scale),
|
| 453 |
+
(cx + (wing - 10) * scale, cy + 23 * scale),
|
| 454 |
],
|
| 455 |
fill=body,
|
| 456 |
)
|
| 457 |
draw.ellipse((cx - 11 * scale, cy - 14 * scale, cx + 11 * scale, cy + 10 * scale), fill=accent)
|
| 458 |
draw.line((cx, cy - 42 * scale, cx, cy - 62 * scale), fill=trim, width=max(3, int(6 * scale)))
|
| 459 |
+
for side in (-1, 1):
|
| 460 |
+
x1 = cx + side * rng.randint(14, 23) * scale
|
| 461 |
+
x2 = cx + side * rng.randint(24, 32) * scale
|
| 462 |
+
y1 = cy + rng.randint(8, 18) * scale
|
| 463 |
+
y2 = cy + rng.randint(20, 30) * scale
|
| 464 |
+
draw.rectangle((min(x1, x2), y1, max(x1, x2), y2), fill=trim)
|
| 465 |
out = io.BytesIO()
|
| 466 |
image.save(out, format="PNG")
|
| 467 |
return out.getvalue()
|