Spaces:
Sleeping
Sleeping
Improve Living Graffiti naming size and growth
Browse files- CODEX_BUILD_LOG.md +1 -0
- README.md +3 -2
- app.py +106 -16
- docs/LIVING_GRAFFITI_MVP.md +18 -3
CODEX_BUILD_LOG.md
CHANGED
|
@@ -21,3 +21,4 @@ This file records how Codex was used to build the hackathon entry.
|
|
| 21 |
- Expanded the concept into a flat-world canvas economy: plot assignment, creative fusion, demo-point valuation, voting/auction packet, and Minecraft server blueprint.
|
| 22 |
- Added NeuroPets mini version: prompt-to-creature hatchery, survival leaderboard, lineage wall, cooldown, and Minecraft spawn packet.
|
| 23 |
- Re-centered the cash-prize build around Living Graffiti: 10-frame animated Minecraft artifacts, mutation/fusion/value metadata, and a `living_graffiti.mc.v1` server packet.
|
|
|
|
|
|
| 21 |
- Expanded the concept into a flat-world canvas economy: plot assignment, creative fusion, demo-point valuation, voting/auction packet, and Minecraft server blueprint.
|
| 22 |
- Added NeuroPets mini version: prompt-to-creature hatchery, survival leaderboard, lineage wall, cooldown, and Minecraft spawn packet.
|
| 23 |
- Re-centered the cash-prize build around Living Graffiti: 10-frame animated Minecraft artifacts, mutation/fusion/value metadata, and a `living_graffiti.mc.v1` server packet.
|
| 24 |
+
- Improved Living Graffiti with prompt-derived names, explicit 32x32 block sizing, 10-frame footprint metadata, and staged growth from seed sketch to server myth.
|
README.md
CHANGED
|
@@ -23,7 +23,7 @@ tags:
|
|
| 23 |
|
| 24 |
Living Graffiti MC is a Minecraft-native animated wall for the Build Small Hackathon.
|
| 25 |
|
| 26 |
-
Players type a prompt, sign it, and get a 10-frame Minecraft-style animated wall artifact.
|
| 27 |
|
| 28 |
NeuroPets and DreamWall remain as secondary modes, but the main cash-prize demo is now simple: prompt -> animated wall tile -> fusion/value -> Minecraft public wall.
|
| 29 |
|
|
@@ -32,6 +32,7 @@ NeuroPets and DreamWall remain as secondary modes, but the main cash-prize demo
|
|
| 32 |
Most hackathon apps stop at chat or image generation. Living Graffiti turns language into a shared animated place.
|
| 33 |
|
| 34 |
- **Animated:** each prompt becomes a 10-frame artifact, not a static image.
|
|
|
|
| 35 |
- **Minecraft-native:** the output is a wall packet, block palette, and row-run placement plan, not just a picture.
|
| 36 |
- **Creature-native:** prompts hatch named pets with survival odds, lineage, and server state.
|
| 37 |
- **Identity-aware:** the same prompt changes when the player signature or gallery zone changes.
|
|
@@ -116,7 +117,7 @@ Bonus quests:
|
|
| 116 |
- **Sharing is Caring:** open trace + server packet per generation.
|
| 117 |
- **Field Notes:** this repo includes `FIELD_NOTES.md`.
|
| 118 |
|
| 119 |
-
Next high-impact demo step: use PebbleHost Paper to show one generated
|
| 120 |
|
| 121 |
## Codex Track
|
| 122 |
|
|
|
|
| 23 |
|
| 24 |
Living Graffiti MC is a Minecraft-native animated wall for the Build Small Hackathon.
|
| 25 |
|
| 26 |
+
Players type a prompt, sign it, and get a named 10-frame Minecraft-style animated wall artifact. Each artifact is designed as a **32x32 block wall tile** with **1,024 blocks per frame**, a wall slot, mutation rate, growth stage, fusion/value readout, creator credit, and a `living_graffiti.mc.v1` packet for the Minecraft server.
|
| 27 |
|
| 28 |
NeuroPets and DreamWall remain as secondary modes, but the main cash-prize demo is now simple: prompt -> animated wall tile -> fusion/value -> Minecraft public wall.
|
| 29 |
|
|
|
|
| 32 |
Most hackathon apps stop at chat or image generation. Living Graffiti turns language into a shared animated place.
|
| 33 |
|
| 34 |
- **Animated:** each prompt becomes a 10-frame artifact, not a static image.
|
| 35 |
+
- **Grows:** artifacts unlock stages from seed sketch to server myth based on value and mutation.
|
| 36 |
- **Minecraft-native:** the output is a wall packet, block palette, and row-run placement plan, not just a picture.
|
| 37 |
- **Creature-native:** prompts hatch named pets with survival odds, lineage, and server state.
|
| 38 |
- **Identity-aware:** the same prompt changes when the player signature or gallery zone changes.
|
|
|
|
| 117 |
- **Sharing is Caring:** open trace + server packet per generation.
|
| 118 |
- **Field Notes:** this repo includes `FIELD_NOTES.md`.
|
| 119 |
|
| 120 |
+
Next high-impact demo step: use PebbleHost Paper to show one generated artifact as a named 32x32 wall slot, then record a 30-45 second video.
|
| 121 |
|
| 122 |
## Codex Track
|
| 123 |
|
app.py
CHANGED
|
@@ -570,6 +570,74 @@ def render_graffiti_gif(frames: list[Image.Image], seed: int) -> str:
|
|
| 570 |
return path
|
| 571 |
|
| 572 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
def living_graffiti(prompt: str, player: str, wall_zone: str):
|
| 574 |
prompt = (prompt or "").strip() or "a glowing bird made of storm clouds"
|
| 575 |
player = (player or "anonymous").strip()
|
|
@@ -586,28 +654,30 @@ def living_graffiti(prompt: str, player: str, wall_zone: str):
|
|
| 586 |
plot = plot_for_seed(seed)
|
| 587 |
canvas_text, value_packet = canvas_report(prompt, player, moods, palette_names, plot)
|
| 588 |
value_data = json.loads(value_packet)
|
| 589 |
-
|
| 590 |
-
"Cloud",
|
| 591 |
-
"Signal",
|
| 592 |
-
"Glyph",
|
| 593 |
-
"Shrine",
|
| 594 |
-
"Echo",
|
| 595 |
-
"Mascot",
|
| 596 |
-
"Portal",
|
| 597 |
-
"Comet",
|
| 598 |
-
"Bloom",
|
| 599 |
-
"Circuit",
|
| 600 |
-
]
|
| 601 |
-
title = f"{title_words[seed % len(title_words)]} #{str(seed)[-4:]}"
|
| 602 |
mutation_rate = round(0.18 + abs(vec[5]) * 0.42, 3)
|
| 603 |
permanence = int(40 + value_data["valuation"]["creative_value"] * 0.7)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 604 |
storyboard = [
|
| 605 |
f"# {title}",
|
| 606 |
f"Creator: **{player}**",
|
|
|
|
| 607 |
f"Wall slot: **({plot['x']}, {plot['z']})** in {wall_zone}",
|
|
|
|
| 608 |
f"Mutation rate: **{mutation_rate}**",
|
| 609 |
f"Creative value: **{value_data['valuation']['creative_value']} demo points**",
|
| 610 |
f"Wall permanence: **{permanence}%**",
|
|
|
|
| 611 |
"",
|
| 612 |
"10-frame loop:",
|
| 613 |
"1. seed image appears",
|
|
@@ -616,8 +686,25 @@ def living_graffiti(prompt: str, player: str, wall_zone: str):
|
|
| 616 |
"4. nearby context mutates the pattern",
|
| 617 |
"5. artifact stabilizes as a named wall memory",
|
| 618 |
"",
|
| 619 |
-
"
|
| 620 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 621 |
packet = {
|
| 622 |
"protocol": "living_graffiti.mc.v1",
|
| 623 |
"title": title,
|
|
@@ -626,14 +713,17 @@ def living_graffiti(prompt: str, player: str, wall_zone: str):
|
|
| 626 |
"wall_zone": wall_zone,
|
| 627 |
"plot": plot,
|
| 628 |
"frames": 10,
|
|
|
|
| 629 |
"palette": palette_names,
|
| 630 |
"moods": moods,
|
| 631 |
"mutation_rate": mutation_rate,
|
| 632 |
"permanence": permanence,
|
|
|
|
| 633 |
"market": value_data,
|
| 634 |
"minecraft": {
|
| 635 |
"placement": "animated_wall_tile",
|
| 636 |
"fallback": "use first frame as static map art if animation is unavailable",
|
|
|
|
| 637 |
"world_origin": f"{plot['world_x']} 80 {plot['world_z']}",
|
| 638 |
"wall_label": f"{title} by {player}",
|
| 639 |
},
|
|
@@ -851,9 +941,9 @@ with gr.Blocks(css=CSS, title="DreamWall MC") as demo:
|
|
| 851 |
)
|
| 852 |
graffiti_player = gr.Textbox(label="Creator signature", value="ArnavS")
|
| 853 |
graffiti_zone = gr.Textbox(label="Wall zone", value="main wall, launch row")
|
| 854 |
-
graffiti_button = gr.Button("
|
| 855 |
with gr.Column(scale=4):
|
| 856 |
-
graffiti_gif = gr.Image(label="10-frame living graffiti loop", type="filepath", height=360)
|
| 857 |
with gr.Row():
|
| 858 |
graffiti_story = gr.Markdown(label="Artifact story")
|
| 859 |
graffiti_canvas = gr.Textbox(label="Fusion/value readout", lines=14, max_lines=20)
|
|
|
|
| 570 |
return path
|
| 571 |
|
| 572 |
|
| 573 |
+
def keywords_for_title(prompt: str) -> list[str]:
|
| 574 |
+
stop = {
|
| 575 |
+
"the",
|
| 576 |
+
"and",
|
| 577 |
+
"with",
|
| 578 |
+
"from",
|
| 579 |
+
"that",
|
| 580 |
+
"this",
|
| 581 |
+
"into",
|
| 582 |
+
"through",
|
| 583 |
+
"around",
|
| 584 |
+
"made",
|
| 585 |
+
"your",
|
| 586 |
+
"their",
|
| 587 |
+
"over",
|
| 588 |
+
"under",
|
| 589 |
+
"for",
|
| 590 |
+
"a",
|
| 591 |
+
"an",
|
| 592 |
+
"of",
|
| 593 |
+
"in",
|
| 594 |
+
"on",
|
| 595 |
+
}
|
| 596 |
+
words = [word.strip(".,!?;:()[]{}\"'").lower() for word in prompt.split()]
|
| 597 |
+
words = [word for word in words if len(word) >= 4 and word not in stop]
|
| 598 |
+
ranked = sorted(set(words), key=lambda word: (-len(word), word))
|
| 599 |
+
return ranked[:3] or ["wall", "dream"]
|
| 600 |
+
|
| 601 |
+
|
| 602 |
+
def artifact_title(prompt: str, seed: int, moods: list[str]) -> str:
|
| 603 |
+
keys = keywords_for_title(prompt)
|
| 604 |
+
prefix_bank = {
|
| 605 |
+
"cozy": ["Lantern", "Hearth", "Soft"],
|
| 606 |
+
"cursed": ["Cursed", "Void", "Haunt"],
|
| 607 |
+
"ancient": ["Relic", "Fossil", "Temple"],
|
| 608 |
+
"mechanical": ["Circuit", "Signal", "Chrome"],
|
| 609 |
+
"wild": ["Storm", "Root", "Cloud"],
|
| 610 |
+
"royal": ["Crown", "Banner", "Gold"],
|
| 611 |
+
}
|
| 612 |
+
prefix_options = prefix_bank.get(moods[0], ["Living", "Dream", "Wall"])
|
| 613 |
+
prefix = prefix_options[seed % len(prefix_options)]
|
| 614 |
+
core = "".join(word.capitalize() for word in keys[:2])
|
| 615 |
+
return f"{prefix} {core}"
|
| 616 |
+
|
| 617 |
+
|
| 618 |
+
def growth_stages(value: float, mutation_rate: float) -> list[dict]:
|
| 619 |
+
max_stage = 1
|
| 620 |
+
if value >= 45:
|
| 621 |
+
max_stage = 2
|
| 622 |
+
if value >= 58:
|
| 623 |
+
max_stage = 3
|
| 624 |
+
if value >= 70:
|
| 625 |
+
max_stage = 4
|
| 626 |
+
if value >= 82 or mutation_rate >= 0.44:
|
| 627 |
+
max_stage = 5
|
| 628 |
+
labels = [
|
| 629 |
+
("seed sketch", "appears as a small 16x16 study tile"),
|
| 630 |
+
("wall tile", "claims a full 32x32 block slot"),
|
| 631 |
+
("animated mural", "loops all 10 frames on the wall"),
|
| 632 |
+
("fusion landmark", "can merge with nearby artifacts"),
|
| 633 |
+
("server myth", "earns a named sign and center-wall placement"),
|
| 634 |
+
]
|
| 635 |
+
return [
|
| 636 |
+
{"stage": idx + 1, "name": name, "unlocked": idx < max_stage, "meaning": meaning}
|
| 637 |
+
for idx, (name, meaning) in enumerate(labels)
|
| 638 |
+
]
|
| 639 |
+
|
| 640 |
+
|
| 641 |
def living_graffiti(prompt: str, player: str, wall_zone: str):
|
| 642 |
prompt = (prompt or "").strip() or "a glowing bird made of storm clouds"
|
| 643 |
player = (player or "anonymous").strip()
|
|
|
|
| 654 |
plot = plot_for_seed(seed)
|
| 655 |
canvas_text, value_packet = canvas_report(prompt, player, moods, palette_names, plot)
|
| 656 |
value_data = json.loads(value_packet)
|
| 657 |
+
title = artifact_title(prompt, seed, moods)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 658 |
mutation_rate = round(0.18 + abs(vec[5]) * 0.42, 3)
|
| 659 |
permanence = int(40 + value_data["valuation"]["creative_value"] * 0.7)
|
| 660 |
+
stages = growth_stages(value_data["valuation"]["creative_value"], mutation_rate)
|
| 661 |
+
unlocked = [stage for stage in stages if stage["unlocked"]]
|
| 662 |
+
next_locked = next((stage for stage in stages if not stage["unlocked"]), None)
|
| 663 |
+
footprint = {
|
| 664 |
+
"blocks": "32 x 32",
|
| 665 |
+
"frames": 10,
|
| 666 |
+
"minecraft_area": "1,024 blocks per frame",
|
| 667 |
+
"wall_slot": f"({plot['x']}, {plot['z']})",
|
| 668 |
+
"world_origin": f"{plot['world_x']} 80 {plot['world_z']}",
|
| 669 |
+
"fallback": "first frame can be placed as static map art if animation is not wired yet",
|
| 670 |
+
}
|
| 671 |
storyboard = [
|
| 672 |
f"# {title}",
|
| 673 |
f"Creator: **{player}**",
|
| 674 |
+
f"Size: **32x32 blocks**, **10 frames**, **1,024 blocks per frame**",
|
| 675 |
f"Wall slot: **({plot['x']}, {plot['z']})** in {wall_zone}",
|
| 676 |
+
f"Minecraft origin: **{plot['world_x']} 80 {plot['world_z']}**",
|
| 677 |
f"Mutation rate: **{mutation_rate}**",
|
| 678 |
f"Creative value: **{value_data['valuation']['creative_value']} demo points**",
|
| 679 |
f"Wall permanence: **{permanence}%**",
|
| 680 |
+
f"Growth stage: **{unlocked[-1]['stage']} - {unlocked[-1]['name']}**",
|
| 681 |
"",
|
| 682 |
"10-frame loop:",
|
| 683 |
"1. seed image appears",
|
|
|
|
| 686 |
"4. nearby context mutates the pattern",
|
| 687 |
"5. artifact stabilizes as a named wall memory",
|
| 688 |
"",
|
| 689 |
+
"Growth path:",
|
| 690 |
]
|
| 691 |
+
storyboard.extend(
|
| 692 |
+
f"- {'unlocked' if stage['unlocked'] else 'locked'} Stage {stage['stage']}: {stage['name']} - {stage['meaning']}"
|
| 693 |
+
for stage in stages
|
| 694 |
+
)
|
| 695 |
+
if next_locked:
|
| 696 |
+
storyboard.extend(
|
| 697 |
+
[
|
| 698 |
+
"",
|
| 699 |
+
f"Next growth target: raise value/mutation to unlock **Stage {next_locked['stage']} - {next_locked['name']}**.",
|
| 700 |
+
]
|
| 701 |
+
)
|
| 702 |
+
storyboard.extend(
|
| 703 |
+
[
|
| 704 |
+
"",
|
| 705 |
+
"Why people use it: they can get their name and idea onto a public Minecraft wall that mutates and fuses with other prompts.",
|
| 706 |
+
]
|
| 707 |
+
)
|
| 708 |
packet = {
|
| 709 |
"protocol": "living_graffiti.mc.v1",
|
| 710 |
"title": title,
|
|
|
|
| 713 |
"wall_zone": wall_zone,
|
| 714 |
"plot": plot,
|
| 715 |
"frames": 10,
|
| 716 |
+
"footprint": footprint,
|
| 717 |
"palette": palette_names,
|
| 718 |
"moods": moods,
|
| 719 |
"mutation_rate": mutation_rate,
|
| 720 |
"permanence": permanence,
|
| 721 |
+
"growth_stages": stages,
|
| 722 |
"market": value_data,
|
| 723 |
"minecraft": {
|
| 724 |
"placement": "animated_wall_tile",
|
| 725 |
"fallback": "use first frame as static map art if animation is unavailable",
|
| 726 |
+
"block_size": {"width": 32, "height": 32, "frames": 10},
|
| 727 |
"world_origin": f"{plot['world_x']} 80 {plot['world_z']}",
|
| 728 |
"wall_label": f"{title} by {player}",
|
| 729 |
},
|
|
|
|
| 941 |
)
|
| 942 |
graffiti_player = gr.Textbox(label="Creator signature", value="ArnavS")
|
| 943 |
graffiti_zone = gr.Textbox(label="Wall zone", value="main wall, launch row")
|
| 944 |
+
graffiti_button = gr.Button("Grow Living Wall Artifact", variant="primary")
|
| 945 |
with gr.Column(scale=4):
|
| 946 |
+
graffiti_gif = gr.Image(label="10-frame 32x32-block living graffiti loop", type="filepath", height=360)
|
| 947 |
with gr.Row():
|
| 948 |
graffiti_story = gr.Markdown(label="Artifact story")
|
| 949 |
graffiti_canvas = gr.Textbox(label="Fusion/value readout", lines=14, max_lines=20)
|
docs/LIVING_GRAFFITI_MVP.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
| 5 |
Living Graffiti is the fastest demo for the OpenAI cash track:
|
| 6 |
|
| 7 |
```text
|
| 8 |
-
prompt -> 10-frame
|
| 9 |
```
|
| 10 |
|
| 11 |
It is more efficient than full creature simulation and more visual than a static painting.
|
|
@@ -15,14 +15,23 @@ It is more efficient than full creature simulation and more visual than a static
|
|
| 15 |
1. Enter a prompt.
|
| 16 |
2. Sign it with a creator name.
|
| 17 |
3. Pick a wall zone.
|
| 18 |
-
4. The Space generates a 10-frame
|
| 19 |
-
5. The app assigns a wall slot and computes mutation/fusion/value.
|
| 20 |
6. The Minecraft packet can be placed on a PebbleHost wall.
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
## Why People Participate
|
| 23 |
|
| 24 |
- Their name appears on the wall.
|
| 25 |
- Their artifact can fuse with nearby prompts.
|
|
|
|
| 26 |
- The wall becomes a public memory of the community.
|
| 27 |
- Animation makes the result feel alive even before full server automation.
|
| 28 |
|
|
@@ -43,3 +52,9 @@ Generate three artifacts:
|
|
| 43 |
3. `storm clouds around the public tree`
|
| 44 |
|
| 45 |
Then show the fusion/value readout and Minecraft wall packet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
Living Graffiti is the fastest demo for the OpenAI cash track:
|
| 6 |
|
| 7 |
```text
|
| 8 |
+
prompt -> named 32x32 wall artifact -> 10-frame living loop -> growth stage -> fusion/value -> public server artifact
|
| 9 |
```
|
| 10 |
|
| 11 |
It is more efficient than full creature simulation and more visual than a static painting.
|
|
|
|
| 15 |
1. Enter a prompt.
|
| 16 |
2. Sign it with a creator name.
|
| 17 |
3. Pick a wall zone.
|
| 18 |
+
4. The Space generates a named 10-frame Minecraft-style artifact.
|
| 19 |
+
5. The app assigns a 32x32 block wall slot and computes mutation/fusion/value.
|
| 20 |
6. The Minecraft packet can be placed on a PebbleHost wall.
|
| 21 |
|
| 22 |
+
## Artifact Shape
|
| 23 |
+
|
| 24 |
+
- **Name:** prompt-derived, so `storm cloud bird carrying an AI sigil` becomes a readable artifact name instead of a random number.
|
| 25 |
+
- **Size:** each artifact is a **32x32 block wall tile**.
|
| 26 |
+
- **Footprint:** each animation frame maps to **1,024 Minecraft blocks**.
|
| 27 |
+
- **Loop:** 10 frames, with the first frame usable as static map art if live animation is not ready.
|
| 28 |
+
- **Growth:** value and mutation unlock five stages: seed sketch, wall tile, animated mural, fusion landmark, server myth.
|
| 29 |
+
|
| 30 |
## Why People Participate
|
| 31 |
|
| 32 |
- Their name appears on the wall.
|
| 33 |
- Their artifact can fuse with nearby prompts.
|
| 34 |
+
- Their artifact can grow into a higher-status server object.
|
| 35 |
- The wall becomes a public memory of the community.
|
| 36 |
- Animation makes the result feel alive even before full server automation.
|
| 37 |
|
|
|
|
| 52 |
3. `storm clouds around the public tree`
|
| 53 |
|
| 54 |
Then show the fusion/value readout and Minecraft wall packet.
|
| 55 |
+
|
| 56 |
+
Best short demo line:
|
| 57 |
+
|
| 58 |
+
```text
|
| 59 |
+
This is not image generation in a frame. It is a named, growing Minecraft artifact with a public wall address.
|
| 60 |
+
```
|