Spaces:
Sleeping
Sleeping
Reframe DreamWall as AfterBlock Museum
Browse files- .github/workflows/build-plugin.yml +38 -0
- CODEX_BUILD_LOG.md +1 -0
- README.md +28 -21
- app.py +557 -13
- docs/COMPETITION_GOAL.md +21 -21
- docs/DEMO_RUNBOOK.md +14 -15
- docs/MINECRAFT_SERVER_BLUEPRINT.md +33 -14
- docs/MUSEUM_CURATION.md +42 -0
- paper-plugin/README.md +37 -12
.github/workflows/build-plugin.yml
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Build Paper Plugin
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
paths:
|
| 6 |
+
- "paper-plugin/**"
|
| 7 |
+
- ".github/workflows/build-plugin.yml"
|
| 8 |
+
pull_request:
|
| 9 |
+
paths:
|
| 10 |
+
- "paper-plugin/**"
|
| 11 |
+
- ".github/workflows/build-plugin.yml"
|
| 12 |
+
workflow_dispatch:
|
| 13 |
+
|
| 14 |
+
jobs:
|
| 15 |
+
build-plugin:
|
| 16 |
+
runs-on: ubuntu-latest
|
| 17 |
+
defaults:
|
| 18 |
+
run:
|
| 19 |
+
working-directory: paper-plugin
|
| 20 |
+
steps:
|
| 21 |
+
- name: Checkout
|
| 22 |
+
uses: actions/checkout@v4
|
| 23 |
+
|
| 24 |
+
- name: Set up Java
|
| 25 |
+
uses: actions/setup-java@v4
|
| 26 |
+
with:
|
| 27 |
+
distribution: temurin
|
| 28 |
+
java-version: "21"
|
| 29 |
+
cache: maven
|
| 30 |
+
|
| 31 |
+
- name: Build jar
|
| 32 |
+
run: mvn -B package
|
| 33 |
+
|
| 34 |
+
- name: Upload plugin jar
|
| 35 |
+
uses: actions/upload-artifact@v4
|
| 36 |
+
with:
|
| 37 |
+
name: dreamwall-paper-bridge
|
| 38 |
+
path: paper-plugin/target/*.jar
|
CODEX_BUILD_LOG.md
CHANGED
|
@@ -25,3 +25,4 @@ This file records how Codex was used to build the hackathon entry.
|
|
| 25 |
- Added Living Moving Canvas mode: a multi-prompt 12x12 Minecraft wall simulation with neighbor fusion, attention weather, growth stages, and a `living_canvas.mc.v1` packet.
|
| 26 |
- Upgraded Living Moving Canvas into an animated wall: stable Minecraft coordinates, pulsing timeline frames, visible fusion links, evolution events, and a clearer Thousand Token Wood demo runbook.
|
| 27 |
- Added per-tile Minecraft origins/bounds and documented the Paper bridge path for placing Living Canvas tiles and representing motion through particles, map updates, or block-frame updates.
|
|
|
|
|
|
| 25 |
- Added Living Moving Canvas mode: a multi-prompt 12x12 Minecraft wall simulation with neighbor fusion, attention weather, growth stages, and a `living_canvas.mc.v1` packet.
|
| 26 |
- Upgraded Living Moving Canvas into an animated wall: stable Minecraft coordinates, pulsing timeline frames, visible fusion links, evolution events, and a clearer Thousand Token Wood demo runbook.
|
| 27 |
- Added per-tile Minecraft origins/bounds and documented the Paper bridge path for placing Living Canvas tiles and representing motion through particles, map updates, or block-frame updates.
|
| 28 |
+
- Reframed the project as DreamWall: AfterBlock Museum with `dreamwall.museum.v1`, deterministic hall placement, curation scores, artifact spirits, passport cards, seeded relic demos, museum-terminal UI, and a GitHub Actions Paper plugin build workflow.
|
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
emoji: 🧱
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
|
@@ -19,20 +19,24 @@ tags:
|
|
| 19 |
- codex
|
| 20 |
---
|
| 21 |
|
| 22 |
-
#
|
| 23 |
|
| 24 |
-
|
| 25 |
|
| 26 |
-
|
| 27 |
|
| 28 |
-
|
| 29 |
|
| 30 |
-
|
| 31 |
|
| 32 |
## Why This Is Different
|
| 33 |
|
| 34 |
-
Most hackathon apps stop at chat or image generation.
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
- **Animated:** each prompt becomes a 10-frame artifact, not a static image.
|
| 37 |
- **Grows:** artifacts unlock stages from seed sketch to server myth based on value and mutation.
|
| 38 |
- **Collective:** many prompts become one shared moving canvas, not isolated images.
|
|
@@ -51,12 +55,12 @@ Most hackathon apps stop at chat or image generation. Living Graffiti turns lang
|
|
| 51 |
- **Track:** An Adventure in Thousand Token Wood
|
| 52 |
- **Small model constraint:** the app uses a local semantic fingerprint engine, far below the 32B limit, with no cloud API dependency.
|
| 53 |
- **Built on Gradio:** this Space is the official Gradio submission surface.
|
| 54 |
-
- **Show, don't tell:** the demo is
|
| 55 |
|
| 56 |
## Bonus Quests
|
| 57 |
|
| 58 |
-
- **Off-Brand:** custom Minecraft
|
| 59 |
-
- **Sharing is Caring:** the app emits
|
| 60 |
- **Field Notes:** see `FIELD_NOTES.md`.
|
| 61 |
|
| 62 |
## Minecraft Server Layer
|
|
@@ -64,6 +68,7 @@ Most hackathon apps stop at chat or image generation. Living Graffiti turns lang
|
|
| 64 |
The MVP emits:
|
| 65 |
|
| 66 |
- WorldEdit-style row instructions
|
|
|
|
| 67 |
- a `living_graffiti.mc.v1` animated wall packet
|
| 68 |
- a `living_canvas.mc.v1` multi-prompt animated wall packet
|
| 69 |
- a `dreamwall.mc.v1` JSON bridge packet
|
|
@@ -73,6 +78,7 @@ The MVP emits:
|
|
| 73 |
- a named Gradio API endpoint: `hatch_pet`
|
| 74 |
- a named Gradio API endpoint: `living_graffiti`
|
| 75 |
- a named Gradio API endpoint: `living_canvas`
|
|
|
|
| 76 |
|
| 77 |
Each `living_canvas.mc.v1` tile includes a stable `minecraft_origin` and `minecraft_bounds`, so the Paper bridge can place it directly on the 384x384 wall.
|
| 78 |
|
|
@@ -83,27 +89,28 @@ The repo also includes a Paper plugin scaffold in [`paper-plugin/`](paper-plugin
|
|
| 83 |
Use the Space API with the named endpoint:
|
| 84 |
|
| 85 |
```text
|
| 86 |
-
POST https://build-small-hackathon-dreamwall-mc.hf.space/gradio_api/call/
|
| 87 |
```
|
| 88 |
|
| 89 |
Input order:
|
| 90 |
|
| 91 |
```json
|
| 92 |
[
|
| 93 |
-
"
|
| 94 |
-
"
|
| 95 |
-
"
|
| 96 |
-
"
|
|
|
|
| 97 |
]
|
| 98 |
```
|
| 99 |
|
| 100 |
-
The final output is a plugin-ready
|
| 101 |
|
| 102 |
## Design Docs
|
| 103 |
|
| 104 |
- [`docs/COMPETITION_GOAL.md`](docs/COMPETITION_GOAL.md)
|
| 105 |
- [`docs/MINECRAFT_SERVER_BLUEPRINT.md`](docs/MINECRAFT_SERVER_BLUEPRINT.md)
|
| 106 |
-
- [`docs/
|
| 107 |
- [`docs/LIVING_GRAFFITI_MVP.md`](docs/LIVING_GRAFFITI_MVP.md)
|
| 108 |
- [`docs/NEUROPETS_MVP.md`](docs/NEUROPETS_MVP.md)
|
| 109 |
- [`docs/DEMO_RUNBOOK.md`](docs/DEMO_RUNBOOK.md)
|
|
@@ -114,9 +121,9 @@ DreamWall MC is aimed at **An Adventure in Thousand Token Wood** plus the **Open
|
|
| 114 |
|
| 115 |
Judging fit:
|
| 116 |
|
| 117 |
-
- **Genuinely delightful:**
|
| 118 |
-
- **AI is load-bearing:** semantic
|
| 119 |
-
- **Originality:** it is a
|
| 120 |
- **Polish:** custom Gradio skin plus Minecraft bridge packet.
|
| 121 |
|
| 122 |
Bonus quests:
|
|
@@ -125,7 +132,7 @@ Bonus quests:
|
|
| 125 |
- **Sharing is Caring:** open trace + server packet per generation.
|
| 126 |
- **Field Notes:** this repo includes `FIELD_NOTES.md`.
|
| 127 |
|
| 128 |
-
Next high-impact demo step: use PebbleHost Paper to
|
| 129 |
|
| 130 |
## Codex Track
|
| 131 |
|
|
|
|
| 1 |
---
|
| 2 |
+
title: DreamWall AfterBlock Museum
|
| 3 |
emoji: 🧱
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
|
|
|
| 19 |
- codex
|
| 20 |
---
|
| 21 |
|
| 22 |
+
# DreamWall: AfterBlock Museum
|
| 23 |
|
| 24 |
+
AfterBlock Museum is a Minecraft-native memory museum for the Build Small Hackathon.
|
| 25 |
|
| 26 |
+
Visitors scan a relic, memory, animal spirit, or prompted painting. The app assigns a museum hall, computes a curation score, awakens a tiny artifact spirit, prints a shareable passport card, and emits a `dreamwall.museum.v1` packet for the Minecraft server.
|
| 27 |
|
| 28 |
+
Living Graffiti and Living Moving Canvas remain as secondary modes. They power museum placement, resonance, and Minecraft wall mechanics.
|
| 29 |
|
| 30 |
+
The main cash-prize demo is now simple: relic -> hall -> spirit -> passport -> Minecraft museum placement.
|
| 31 |
|
| 32 |
## Why This Is Different
|
| 33 |
|
| 34 |
+
Most hackathon apps stop at chat or image generation. AfterBlock turns language and memory into a place visitors can walk through.
|
| 35 |
|
| 36 |
+
- **Museum-native:** every input becomes an artifact with a hall, plaque, passport, and Minecraft coordinates.
|
| 37 |
+
- **Spirit-bearing:** each artifact awakens a constrained spirit that speaks only from its object and lore.
|
| 38 |
+
- **Resonance-based:** curation score replaces market/auction language.
|
| 39 |
+
- **Off-brand:** the Gradio app feels like a Minecraft museum terminal.
|
| 40 |
- **Animated:** each prompt becomes a 10-frame artifact, not a static image.
|
| 41 |
- **Grows:** artifacts unlock stages from seed sketch to server myth based on value and mutation.
|
| 42 |
- **Collective:** many prompts become one shared moving canvas, not isolated images.
|
|
|
|
| 55 |
- **Track:** An Adventure in Thousand Token Wood
|
| 56 |
- **Small model constraint:** the app uses a local semantic fingerprint engine, far below the 32B limit, with no cloud API dependency.
|
| 57 |
- **Built on Gradio:** this Space is the official Gradio submission surface.
|
| 58 |
+
- **Show, don't tell:** the demo is scan relic -> hall placement -> spirit -> passport -> Minecraft pedestal.
|
| 59 |
|
| 60 |
## Bonus Quests
|
| 61 |
|
| 62 |
+
- **Off-Brand:** custom Minecraft museum terminal UI styling.
|
| 63 |
+
- **Sharing is Caring:** the app emits open museum and bridge packets for each artifact.
|
| 64 |
- **Field Notes:** see `FIELD_NOTES.md`.
|
| 65 |
|
| 66 |
## Minecraft Server Layer
|
|
|
|
| 68 |
The MVP emits:
|
| 69 |
|
| 70 |
- WorldEdit-style row instructions
|
| 71 |
+
- a `dreamwall.museum.v1` artifact/passport/spirit packet
|
| 72 |
- a `living_graffiti.mc.v1` animated wall packet
|
| 73 |
- a `living_canvas.mc.v1` multi-prompt animated wall packet
|
| 74 |
- a `dreamwall.mc.v1` JSON bridge packet
|
|
|
|
| 78 |
- a named Gradio API endpoint: `hatch_pet`
|
| 79 |
- a named Gradio API endpoint: `living_graffiti`
|
| 80 |
- a named Gradio API endpoint: `living_canvas`
|
| 81 |
+
- a named Gradio API endpoint: `curate_artifact`
|
| 82 |
|
| 83 |
Each `living_canvas.mc.v1` tile includes a stable `minecraft_origin` and `minecraft_bounds`, so the Paper bridge can place it directly on the 384x384 wall.
|
| 84 |
|
|
|
|
| 89 |
Use the Space API with the named endpoint:
|
| 90 |
|
| 91 |
```text
|
| 92 |
+
POST https://build-small-hackathon-dreamwall-mc.hf.space/gradio_api/call/curate_artifact
|
| 93 |
```
|
| 94 |
|
| 95 |
Input order:
|
| 96 |
|
| 97 |
```json
|
| 98 |
[
|
| 99 |
+
"Arnav",
|
| 100 |
+
"@Wildstash",
|
| 101 |
+
"object_photo",
|
| 102 |
+
"white AirPods from my first year of university",
|
| 103 |
+
"They carried private worlds through public noise during my first year away."
|
| 104 |
]
|
| 105 |
```
|
| 106 |
|
| 107 |
+
The final output is a plugin-ready museum packet with artifact title, hall, coordinates, palette/materials, plaque text, spirit first line, owner handle, and passport payload.
|
| 108 |
|
| 109 |
## Design Docs
|
| 110 |
|
| 111 |
- [`docs/COMPETITION_GOAL.md`](docs/COMPETITION_GOAL.md)
|
| 112 |
- [`docs/MINECRAFT_SERVER_BLUEPRINT.md`](docs/MINECRAFT_SERVER_BLUEPRINT.md)
|
| 113 |
+
- [`docs/MUSEUM_CURATION.md`](docs/MUSEUM_CURATION.md)
|
| 114 |
- [`docs/LIVING_GRAFFITI_MVP.md`](docs/LIVING_GRAFFITI_MVP.md)
|
| 115 |
- [`docs/NEUROPETS_MVP.md`](docs/NEUROPETS_MVP.md)
|
| 116 |
- [`docs/DEMO_RUNBOOK.md`](docs/DEMO_RUNBOOK.md)
|
|
|
|
| 121 |
|
| 122 |
Judging fit:
|
| 123 |
|
| 124 |
+
- **Genuinely delightful:** ordinary objects become Minecraft museum artifacts with tiny spirits.
|
| 125 |
+
- **AI is load-bearing:** semantic curation chooses halls, spirits, plaques, resonance, and placement.
|
| 126 |
+
- **Originality:** it is a memory museum ritual, not a chatbot wrapper.
|
| 127 |
- **Polish:** custom Gradio skin plus Minecraft bridge packet.
|
| 128 |
|
| 129 |
Bonus quests:
|
|
|
|
| 132 |
- **Sharing is Caring:** open trace + server packet per generation.
|
| 133 |
- **Field Notes:** this repo includes `FIELD_NOTES.md`.
|
| 134 |
|
| 135 |
+
Next high-impact demo step: use PebbleHost Paper to place one AfterBlock artifact pedestal/sign from the `dreamwall.museum.v1` packet, then record a 45-75 second video.
|
| 136 |
|
| 137 |
## Codex Track
|
| 138 |
|
app.py
CHANGED
|
@@ -4,6 +4,7 @@ import math
|
|
| 4 |
import os
|
| 5 |
import tempfile
|
| 6 |
from dataclasses import dataclass
|
|
|
|
| 7 |
|
| 8 |
import gradio as gr
|
| 9 |
import numpy as np
|
|
@@ -101,6 +102,56 @@ LIVING_WALL_PROMPTS = [
|
|
| 101 |
"a cloud dragon sleeping inside a circuit board",
|
| 102 |
]
|
| 103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
@dataclass
|
| 106 |
class ArtResult:
|
|
@@ -375,6 +426,371 @@ def canvas_report(prompt: str, player: str, moods: list[str], palette_names: lis
|
|
| 375 |
return "\n".join(report), json.dumps(packet, indent=2)
|
| 376 |
|
| 377 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
HABITATS = {
|
| 379 |
"redstone caves": ["electric", "mechanical", "small", "curious"],
|
| 380 |
"sky forest": ["flying", "social", "light", "watchful"],
|
|
@@ -1118,43 +1534,117 @@ def gradio_generate(prompt: str, player: str, origin: str, gallery_zone: str):
|
|
| 1118 |
|
| 1119 |
CSS = """
|
| 1120 |
:root {
|
| 1121 |
-
--mc-ink: #
|
| 1122 |
-
--mc-paper: #
|
| 1123 |
--mc-green: #57744a;
|
| 1124 |
--mc-gold: #d39b45;
|
|
|
|
|
|
|
|
|
|
| 1125 |
}
|
| 1126 |
body, .gradio-container {
|
| 1127 |
-
background: #
|
| 1128 |
color: var(--mc-ink);
|
| 1129 |
}
|
| 1130 |
.gradio-container {
|
| 1131 |
max-width: 1180px !important;
|
| 1132 |
}
|
| 1133 |
.dreamwall-hero {
|
| 1134 |
-
background: linear-gradient(135deg, #
|
| 1135 |
-
border: 3px solid #
|
| 1136 |
-
box-shadow: 0 10px 0 #
|
| 1137 |
padding: 22px;
|
| 1138 |
margin: 14px 0 18px;
|
| 1139 |
}
|
| 1140 |
.dreamwall-hero h1 {
|
| 1141 |
margin: 0;
|
| 1142 |
font-size: 42px;
|
| 1143 |
-
color: #
|
| 1144 |
}
|
| 1145 |
.dreamwall-hero p {
|
| 1146 |
max-width: 760px;
|
| 1147 |
font-size: 17px;
|
| 1148 |
line-height: 1.45;
|
|
|
|
| 1149 |
}
|
| 1150 |
.badge-row span {
|
| 1151 |
display: inline-block;
|
| 1152 |
-
border: 2px solid #
|
| 1153 |
-
background: #
|
|
|
|
| 1154 |
padding: 6px 10px;
|
| 1155 |
margin: 4px 5px 0 0;
|
| 1156 |
font-weight: 700;
|
| 1157 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1158 |
textarea, input {
|
| 1159 |
font-family: ui-monospace, SFMono-Regular, Menlo, monospace !important;
|
| 1160 |
}
|
|
@@ -1165,11 +1655,11 @@ with gr.Blocks(css=CSS, title="DreamWall MC") as demo:
|
|
| 1165 |
gr.HTML(
|
| 1166 |
"""
|
| 1167 |
<section class="dreamwall-hero">
|
| 1168 |
-
<h1>
|
| 1169 |
<p>
|
| 1170 |
-
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
</p>
|
| 1174 |
<div class="badge-row">
|
| 1175 |
<span>Adventure in Thousand Token Wood</span>
|
|
@@ -1182,6 +1672,60 @@ with gr.Blocks(css=CSS, title="DreamWall MC") as demo:
|
|
| 1182 |
</section>
|
| 1183 |
"""
|
| 1184 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1185 |
gr.HTML("<h2>Living Graffiti Wall</h2>")
|
| 1186 |
with gr.Row():
|
| 1187 |
with gr.Column(scale=5):
|
|
|
|
| 4 |
import os
|
| 5 |
import tempfile
|
| 6 |
from dataclasses import dataclass
|
| 7 |
+
from datetime import datetime, timezone
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
import numpy as np
|
|
|
|
| 102 |
"a cloud dragon sleeping inside a circuit board",
|
| 103 |
]
|
| 104 |
|
| 105 |
+
MUSEUM_HALLS = [
|
| 106 |
+
"Hall of Firsts",
|
| 107 |
+
"Hall of Companions",
|
| 108 |
+
"Hall of Turning Points",
|
| 109 |
+
"Hall of Worlds",
|
| 110 |
+
"Hall of Soft Things",
|
| 111 |
+
"Hall of Tools",
|
| 112 |
+
"Hall of Lost Signals",
|
| 113 |
+
"Grand Painting Hall",
|
| 114 |
+
"Animal Spirit Grove",
|
| 115 |
+
]
|
| 116 |
+
|
| 117 |
+
DEMO_ARTIFACTS = {
|
| 118 |
+
"Star Wars childhood book": {
|
| 119 |
+
"owner_name": "Arnav",
|
| 120 |
+
"owner_handle": "@Wildstash",
|
| 121 |
+
"input_type": "memory_prompt",
|
| 122 |
+
"source_prompt": "a worn Star Wars childhood book with bent corners and a silver spaceship on the cover",
|
| 123 |
+
"memory_text": "I kept reopening it because the galaxy felt bigger than my room.",
|
| 124 |
+
},
|
| 125 |
+
"AirPods from first year of university": {
|
| 126 |
+
"owner_name": "Arnav",
|
| 127 |
+
"owner_handle": "@Wildstash",
|
| 128 |
+
"input_type": "object_photo",
|
| 129 |
+
"source_prompt": "white AirPods from my first year of university",
|
| 130 |
+
"memory_text": "They carried private worlds through public noise during my first year away.",
|
| 131 |
+
},
|
| 132 |
+
"Monitor used for first Bitcoin trade": {
|
| 133 |
+
"owner_name": "Arnav",
|
| 134 |
+
"owner_handle": "@Wildstash",
|
| 135 |
+
"input_type": "object_photo",
|
| 136 |
+
"source_prompt": "a black monitor used for my first Bitcoin trade",
|
| 137 |
+
"memory_text": "A screen where numbers first started feeling like weather.",
|
| 138 |
+
},
|
| 139 |
+
"School bag carried through exams": {
|
| 140 |
+
"owner_name": "Arnav",
|
| 141 |
+
"owner_handle": "@Wildstash",
|
| 142 |
+
"input_type": "object_photo",
|
| 143 |
+
"source_prompt": "a school bag carried through exams",
|
| 144 |
+
"memory_text": "It held pencils, snacks, panic, and the weight of every morning.",
|
| 145 |
+
},
|
| 146 |
+
"Prompted painting: red dragon above childhood home": {
|
| 147 |
+
"owner_name": "Arnav",
|
| 148 |
+
"owner_handle": "@Wildstash",
|
| 149 |
+
"input_type": "painting_prompt",
|
| 150 |
+
"source_prompt": "a red dragon above my childhood home",
|
| 151 |
+
"memory_text": "A fantasy guardian hovering over the place I learned to imagine from.",
|
| 152 |
+
},
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
|
| 156 |
@dataclass
|
| 157 |
class ArtResult:
|
|
|
|
| 426 |
return "\n".join(report), json.dumps(packet, indent=2)
|
| 427 |
|
| 428 |
|
| 429 |
+
def object_guess_for(input_type: str, source_prompt: str, memory_text: str) -> str:
|
| 430 |
+
text = f"{source_prompt} {memory_text}".lower()
|
| 431 |
+
guesses = [
|
| 432 |
+
("book", ["book", "novel", "comic", "star wars", "cover"]),
|
| 433 |
+
("earbuds", ["airpods", "earpods", "earbuds", "headphones", "music"]),
|
| 434 |
+
("monitor", ["monitor", "screen", "display", "trade", "bitcoin"]),
|
| 435 |
+
("school bag", ["bag", "backpack", "exams", "school"]),
|
| 436 |
+
("painting", ["painting", "dragon", "prompted", "canvas"]),
|
| 437 |
+
("animal spirit", ["pet", "animal", "dog", "cat", "bird", "creature"]),
|
| 438 |
+
("tool", ["tool", "keyboard", "mouse", "camera", "phone"]),
|
| 439 |
+
]
|
| 440 |
+
for guess, hints in guesses:
|
| 441 |
+
if any(hint in text for hint in hints):
|
| 442 |
+
return guess
|
| 443 |
+
if input_type == "painting_prompt":
|
| 444 |
+
return "prompted painting"
|
| 445 |
+
if input_type == "animal_spirit":
|
| 446 |
+
return "animal spirit"
|
| 447 |
+
return "personal relic"
|
| 448 |
+
|
| 449 |
+
|
| 450 |
+
def hall_for_artifact(input_type: str, object_guess: str, source_prompt: str, memory_text: str, seed: int) -> tuple[str, str]:
|
| 451 |
+
text = f"{object_guess} {source_prompt} {memory_text}".lower()
|
| 452 |
+
if input_type == "painting_prompt":
|
| 453 |
+
return "Grand Painting Hall", "paintings that were imagined before they were found"
|
| 454 |
+
if input_type == "animal_spirit" or any(word in text for word in ["pet", "animal", "dog", "cat", "bird", "creature"]):
|
| 455 |
+
return "Animal Spirit Grove", "the artifact behaves more like a companion than an object"
|
| 456 |
+
if any(word in text for word in ["first", "university", "bitcoin", "started"]):
|
| 457 |
+
return "Hall of Firsts", "the memory marks a first threshold"
|
| 458 |
+
if any(word in text for word in ["airpods", "bag", "friend", "carried", "companion"]):
|
| 459 |
+
return "Hall of Companions", "it stayed close to the owner through ordinary days"
|
| 460 |
+
if any(word in text for word in ["exam", "trade", "turning", "changed", "panic"]):
|
| 461 |
+
return "Hall of Turning Points", "the object sits near a decision or pressure point"
|
| 462 |
+
if any(word in text for word in ["star wars", "galaxy", "home", "world", "dragon"]):
|
| 463 |
+
return "Hall of Worlds", "it opened a world larger than the room around it"
|
| 464 |
+
if any(word in text for word in ["soft", "noise", "private", "morning"]):
|
| 465 |
+
return "Hall of Soft Things", "the memory is quiet, protective, and intimate"
|
| 466 |
+
if any(word in text for word in ["monitor", "tool", "screen", "keyboard"]):
|
| 467 |
+
return "Hall of Tools", "the artifact helped the owner act on the world"
|
| 468 |
+
if any(word in text for word in ["signal", "lost", "radio", "noise"]):
|
| 469 |
+
return "Hall of Lost Signals", "the artifact carries private signal through public static"
|
| 470 |
+
hall = MUSEUM_HALLS[seed % len(MUSEUM_HALLS)]
|
| 471 |
+
return hall, "the museum placed it by symbolic resonance"
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def museum_zone_for(hall: str, seed: int) -> str:
|
| 475 |
+
zones = {
|
| 476 |
+
"Hall of Firsts": ["threshold alcove", "first-light row", "origin cabinet"],
|
| 477 |
+
"Hall of Companions": ["pocket gallery", "everyday pedestal", "quiet bench"],
|
| 478 |
+
"Hall of Turning Points": ["pressure corridor", "exam arch", "decision stair"],
|
| 479 |
+
"Hall of Worlds": ["portal bay", "map room", "myth shelf"],
|
| 480 |
+
"Hall of Soft Things": ["hush wing", "warm glass case", "felt-lit corner"],
|
| 481 |
+
"Hall of Tools": ["workbench row", "instrument vault", "copper desk"],
|
| 482 |
+
"Hall of Lost Signals": ["static aisle", "radio archive", "dim receiver"],
|
| 483 |
+
"Grand Painting Hall": ["large frame wall", "dragon bay", "painted sky"],
|
| 484 |
+
"Animal Spirit Grove": ["moss enclosure", "companion path", "moonlit pen"],
|
| 485 |
+
}
|
| 486 |
+
choices = zones.get(hall, ["west wing"])
|
| 487 |
+
return choices[seed % len(choices)]
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
def curation_scores(
|
| 491 |
+
source_prompt: str,
|
| 492 |
+
memory_text: str,
|
| 493 |
+
input_type: str,
|
| 494 |
+
moods: list[str],
|
| 495 |
+
palette_names: list[str],
|
| 496 |
+
plot: dict,
|
| 497 |
+
) -> dict:
|
| 498 |
+
text = f"{source_prompt} {memory_text}".lower()
|
| 499 |
+
density = prompt_density(text)
|
| 500 |
+
neighbors = nearby_artworks(plot)
|
| 501 |
+
adjacency = min(1.0, sum(max(0, 3 - item["distance"]) for item in neighbors) / 6)
|
| 502 |
+
palette_rarity = len(set(palette_names).intersection({"obsidian", "amethyst_block", "sea_lantern", "glowstone"})) / 4
|
| 503 |
+
def score(words: list[str], base: float = 28.0) -> int:
|
| 504 |
+
hits = sum(1 for word in words if word in text)
|
| 505 |
+
return int(min(100, base + density * 35 + hits * 14))
|
| 506 |
+
|
| 507 |
+
scores = {
|
| 508 |
+
"nostalgia": score(["childhood", "school", "first", "home", "kept", "morning"]),
|
| 509 |
+
"symbolism": score(["dragon", "galaxy", "signal", "cover", "weather", "guardian"]),
|
| 510 |
+
"identity": score(["my", "first", "owner", "university", "trade"], 34),
|
| 511 |
+
"companionship": score(["carried", "airpods", "bag", "private", "through"], 30),
|
| 512 |
+
"transformation": score(["first", "trade", "exam", "changed", "started"], 26),
|
| 513 |
+
"rarity": int(min(100, 35 + len(set(moods)) * 10 + density * 25)),
|
| 514 |
+
"palette_rarity": int(round(palette_rarity * 100)),
|
| 515 |
+
"adjacency_resonance": int(round(adjacency * 100)),
|
| 516 |
+
"visitor_echoes": int(min(100, 12 + len(neighbors) * 17 + density * 34)),
|
| 517 |
+
}
|
| 518 |
+
weighted = (
|
| 519 |
+
scores["nostalgia"] * 0.16
|
| 520 |
+
+ scores["symbolism"] * 0.14
|
| 521 |
+
+ scores["identity"] * 0.14
|
| 522 |
+
+ scores["companionship"] * 0.12
|
| 523 |
+
+ scores["transformation"] * 0.12
|
| 524 |
+
+ scores["rarity"] * 0.1
|
| 525 |
+
+ scores["palette_rarity"] * 0.08
|
| 526 |
+
+ scores["adjacency_resonance"] * 0.08
|
| 527 |
+
+ scores["visitor_echoes"] * 0.06
|
| 528 |
+
)
|
| 529 |
+
scores["curation_score"] = int(round(weighted))
|
| 530 |
+
return scores
|
| 531 |
+
|
| 532 |
+
|
| 533 |
+
def spirit_for_artifact(title: str, object_guess: str, memory_text: str, hall: str, seed: int) -> dict:
|
| 534 |
+
traits_bank = {
|
| 535 |
+
"book": ["wide-eyed", "paper-worn", "portal-minded"],
|
| 536 |
+
"earbuds": ["private", "signal-carrying", "soft-spoken"],
|
| 537 |
+
"monitor": ["watchful", "electric", "threshold-bound"],
|
| 538 |
+
"school bag": ["patient", "burdened", "loyal"],
|
| 539 |
+
"painting": ["mythic", "paint-lit", "protective"],
|
| 540 |
+
"animal spirit": ["restless", "companionable", "wild"],
|
| 541 |
+
"personal relic": ["quiet", "symbolic", "half-remembered"],
|
| 542 |
+
}
|
| 543 |
+
traits = traits_bank.get(object_guess, traits_bank["personal relic"])
|
| 544 |
+
suffix = ["mote", "keeper", "echo", "sprite", "shade", "wisp"][seed % 6]
|
| 545 |
+
spirit_name = "".join(word.capitalize() for word in keywords_for_title(title)[:1]) + suffix.capitalize()
|
| 546 |
+
first_line = f"I am what remained when {object_guess} became a place."
|
| 547 |
+
if "airpods" in object_guess or object_guess == "earbuds":
|
| 548 |
+
first_line = "I carried private worlds through public noise."
|
| 549 |
+
elif object_guess == "book":
|
| 550 |
+
first_line = "I opened a galaxy small enough to fit in your hands."
|
| 551 |
+
elif object_guess == "monitor":
|
| 552 |
+
first_line = "I watched numbers become weather."
|
| 553 |
+
elif object_guess == "school bag":
|
| 554 |
+
first_line = "I carried the mornings you were not ready for."
|
| 555 |
+
elif object_guess == "painting":
|
| 556 |
+
first_line = "I guard the home that imagination returned to."
|
| 557 |
+
questions = [
|
| 558 |
+
"What do you remember?",
|
| 559 |
+
"Why are you in this hall?",
|
| 560 |
+
"What should visitors notice?",
|
| 561 |
+
]
|
| 562 |
+
responses = [
|
| 563 |
+
first_line,
|
| 564 |
+
f"The curator placed me in {hall} because this memory still has a shape.",
|
| 565 |
+
f"Look for the detail that does not shout: {memory_text[:110]}",
|
| 566 |
+
]
|
| 567 |
+
return {
|
| 568 |
+
"spirit_name": spirit_name,
|
| 569 |
+
"spirit_traits": traits,
|
| 570 |
+
"spirit_first_line": first_line,
|
| 571 |
+
"rules": [
|
| 572 |
+
"speak only from the object, memory, and artifact lore",
|
| 573 |
+
"do not behave like a generic assistant",
|
| 574 |
+
"answer as a quiet museum presence",
|
| 575 |
+
],
|
| 576 |
+
"sample_visitor_questions": questions,
|
| 577 |
+
"sample_spirit_responses": responses,
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
|
| 581 |
+
def resonance_links_for_artifact(hall: str, moods: list[str], plot: dict) -> list[dict]:
|
| 582 |
+
links = []
|
| 583 |
+
for art in nearby_artworks(plot):
|
| 584 |
+
shared = sorted(set(moods).intersection(art["moods"]))
|
| 585 |
+
links.append(
|
| 586 |
+
{
|
| 587 |
+
"title": art["title"],
|
| 588 |
+
"creator": art["player"],
|
| 589 |
+
"distance": art["distance"],
|
| 590 |
+
"resonance": "shared mood" if shared else "nearby museum placement",
|
| 591 |
+
"shared_moods": shared,
|
| 592 |
+
"hall_echo": hall,
|
| 593 |
+
}
|
| 594 |
+
)
|
| 595 |
+
return links
|
| 596 |
+
|
| 597 |
+
|
| 598 |
+
def passport_html(artifact: dict) -> str:
|
| 599 |
+
palette = artifact["palette"][:5]
|
| 600 |
+
swatches = "".join(
|
| 601 |
+
f"<span class='museum-swatch' title='{name}' style='background: rgb({rgb[0]}, {rgb[1]}, {rgb[2]})'></span>"
|
| 602 |
+
for name, rgb in [next((block for block in BLOCKS if block[0] == item), ("stone", (120, 120, 120))) for item in palette]
|
| 603 |
+
)
|
| 604 |
+
return f"""
|
| 605 |
+
<section class="passport-card">
|
| 606 |
+
<div class="passport-kicker">Preserved in AfterBlock Museum</div>
|
| 607 |
+
<h2>{artifact['title']}</h2>
|
| 608 |
+
<p class="passport-owner">{artifact['owner_handle']} · {artifact['hall']}</p>
|
| 609 |
+
<div class="passport-grid">
|
| 610 |
+
<div class="passport-preview">{swatches}<strong>{artifact['spirit_name']}</strong></div>
|
| 611 |
+
<div>
|
| 612 |
+
<p><strong>Plot</strong> ({artifact['plot']['x']}, {artifact['plot']['z']})</p>
|
| 613 |
+
<p><strong>Coordinates</strong> {artifact['minecraft_coordinates']['x']} {artifact['minecraft_coordinates']['y']} {artifact['minecraft_coordinates']['z']}</p>
|
| 614 |
+
<p><strong>Plaque</strong> {artifact['plaque_line']}</p>
|
| 615 |
+
<p><strong>QR payload</strong> <code>{artifact['qr_payload']}</code></p>
|
| 616 |
+
</div>
|
| 617 |
+
</div>
|
| 618 |
+
</section>
|
| 619 |
+
"""
|
| 620 |
+
|
| 621 |
+
|
| 622 |
+
def floor_map_html(artifact: dict) -> str:
|
| 623 |
+
cells = []
|
| 624 |
+
for z in range(CANVAS_SIZE):
|
| 625 |
+
for x in range(CANVAS_SIZE):
|
| 626 |
+
active = x == artifact["plot"]["x"] and z == artifact["plot"]["z"]
|
| 627 |
+
label = "★" if active else ""
|
| 628 |
+
cells.append(f"<span class='floor-cell {'active' if active else ''}'>{label}</span>")
|
| 629 |
+
return f"<div class='floor-map'>{''.join(cells)}</div>"
|
| 630 |
+
|
| 631 |
+
|
| 632 |
+
def build_museum_artifact(
|
| 633 |
+
owner_name: str,
|
| 634 |
+
owner_handle: str,
|
| 635 |
+
input_type: str,
|
| 636 |
+
source_prompt: str,
|
| 637 |
+
memory_text: str,
|
| 638 |
+
) -> dict:
|
| 639 |
+
owner_name = (owner_name or "Anonymous").strip()
|
| 640 |
+
owner_handle = (owner_handle or "@unknown").strip()
|
| 641 |
+
input_type = (input_type or "memory_prompt").strip()
|
| 642 |
+
source_prompt = (source_prompt or "a mysterious object from a half-remembered room").strip()
|
| 643 |
+
memory_text = (memory_text or "No memory text was provided, so the museum listens to the object itself.").strip()
|
| 644 |
+
text = f"afterblock={owner_name}|{owner_handle}|{input_type}|{source_prompt}|{memory_text}"
|
| 645 |
+
seed = stable_seed(text)
|
| 646 |
+
vec = embedding(text)
|
| 647 |
+
moods = top_moods(text, vec)
|
| 648 |
+
palette = palette_from_vector(vec, seed, moods)
|
| 649 |
+
palette_names = [name for name, _ in palette]
|
| 650 |
+
object_guess = object_guess_for(input_type, source_prompt, memory_text)
|
| 651 |
+
hall, placement_reason = hall_for_artifact(input_type, object_guess, source_prompt, memory_text, seed)
|
| 652 |
+
zone = museum_zone_for(hall, seed)
|
| 653 |
+
plot = plot_for_seed(seed)
|
| 654 |
+
title = artifact_title(source_prompt, seed, moods)
|
| 655 |
+
artifact_id = hashlib.sha256(text.encode("utf-8")).hexdigest()[:16]
|
| 656 |
+
scores = curation_scores(source_prompt, memory_text, input_type, moods, palette_names, plot)
|
| 657 |
+
spirit = spirit_for_artifact(title, object_guess, memory_text, hall, seed)
|
| 658 |
+
coordinates = {"x": plot["world_x"], "y": 80, "z": plot["world_z"]}
|
| 659 |
+
plaque_line = spirit["spirit_first_line"]
|
| 660 |
+
lore_short = f"{object_guess.title()} placed in {hall.lower()} because {placement_reason}."
|
| 661 |
+
artifact = {
|
| 662 |
+
"artifact_id": artifact_id,
|
| 663 |
+
"owner_name": owner_name,
|
| 664 |
+
"owner_handle": owner_handle,
|
| 665 |
+
"input_type": input_type,
|
| 666 |
+
"title": title,
|
| 667 |
+
"source_prompt": source_prompt,
|
| 668 |
+
"memory_text": memory_text,
|
| 669 |
+
"object_guess": object_guess,
|
| 670 |
+
"hall": hall,
|
| 671 |
+
"zone": zone,
|
| 672 |
+
"plot": plot,
|
| 673 |
+
"minecraft_coordinates": coordinates,
|
| 674 |
+
"palette": palette_names,
|
| 675 |
+
"minecraft_materials": palette_names,
|
| 676 |
+
"plaque_line": plaque_line,
|
| 677 |
+
"lore_short": lore_short,
|
| 678 |
+
"spirit_name": spirit["spirit_name"],
|
| 679 |
+
"spirit_traits": spirit["spirit_traits"],
|
| 680 |
+
"spirit_first_line": spirit["spirit_first_line"],
|
| 681 |
+
"placement_reason": placement_reason,
|
| 682 |
+
"curation_scores": scores,
|
| 683 |
+
"resonance_links": resonance_links_for_artifact(hall, moods, plot),
|
| 684 |
+
"passport_card": {
|
| 685 |
+
"title": title,
|
| 686 |
+
"owner_handle": owner_handle,
|
| 687 |
+
"hall": hall,
|
| 688 |
+
"plot": plot,
|
| 689 |
+
"minecraft_coordinates": coordinates,
|
| 690 |
+
"plaque_line": plaque_line,
|
| 691 |
+
"preservation_line": "Preserved in AfterBlock Museum",
|
| 692 |
+
},
|
| 693 |
+
"qr_payload": f"afterblock://artifact/{artifact_id}",
|
| 694 |
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
| 695 |
+
}
|
| 696 |
+
artifact.update(spirit)
|
| 697 |
+
return artifact
|
| 698 |
+
|
| 699 |
+
|
| 700 |
+
def museum_packet_for(artifact: dict) -> dict:
|
| 701 |
+
return {
|
| 702 |
+
"type": "dreamwall.museum.v1",
|
| 703 |
+
"artifact": artifact,
|
| 704 |
+
"museum": {
|
| 705 |
+
"hall": artifact["hall"],
|
| 706 |
+
"zone": artifact["zone"],
|
| 707 |
+
"plot": artifact["plot"],
|
| 708 |
+
"coordinates": artifact["minecraft_coordinates"],
|
| 709 |
+
"placement_reason": artifact["placement_reason"],
|
| 710 |
+
},
|
| 711 |
+
"spirit": {
|
| 712 |
+
"name": artifact["spirit_name"],
|
| 713 |
+
"traits": artifact["spirit_traits"],
|
| 714 |
+
"first_line": artifact["spirit_first_line"],
|
| 715 |
+
"rules": artifact["rules"],
|
| 716 |
+
"sample_visitor_questions": artifact["sample_visitor_questions"],
|
| 717 |
+
"sample_spirit_responses": artifact["sample_spirit_responses"],
|
| 718 |
+
},
|
| 719 |
+
"passport": artifact["passport_card"],
|
| 720 |
+
"minecraft": {
|
| 721 |
+
"protocol": "dreamwall.mc.v1",
|
| 722 |
+
"import_mode": "museum_artifact",
|
| 723 |
+
"title": artifact["title"],
|
| 724 |
+
"hall": artifact["hall"],
|
| 725 |
+
"coordinates": artifact["minecraft_coordinates"],
|
| 726 |
+
"materials": artifact["minecraft_materials"],
|
| 727 |
+
"plaque_text": artifact["plaque_line"],
|
| 728 |
+
"spirit_first_line": artifact["spirit_first_line"],
|
| 729 |
+
"owner_handle": artifact["owner_handle"],
|
| 730 |
+
"passport_qr_payload": artifact["qr_payload"],
|
| 731 |
+
"pedestal": "place sign, item frame, and blocky preview at coordinates",
|
| 732 |
+
},
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
+
|
| 736 |
+
def curate_afterblock_artifact(
|
| 737 |
+
owner_name: str,
|
| 738 |
+
owner_handle: str,
|
| 739 |
+
input_type: str,
|
| 740 |
+
source_prompt: str,
|
| 741 |
+
memory_text: str,
|
| 742 |
+
):
|
| 743 |
+
artifact = build_museum_artifact(owner_name, owner_handle, input_type, source_prompt, memory_text)
|
| 744 |
+
packet = museum_packet_for(artifact)
|
| 745 |
+
placement = [
|
| 746 |
+
f"# {artifact['title']}",
|
| 747 |
+
f"Owner: **{artifact['owner_handle']}**",
|
| 748 |
+
f"Hall: **{artifact['hall']}** / {artifact['zone']}",
|
| 749 |
+
f"Plot: **({artifact['plot']['x']}, {artifact['plot']['z']})**",
|
| 750 |
+
f"Minecraft coordinates: **{artifact['minecraft_coordinates']['x']} {artifact['minecraft_coordinates']['y']} {artifact['minecraft_coordinates']['z']}**",
|
| 751 |
+
f"Curation score: **{artifact['curation_scores']['curation_score']}**",
|
| 752 |
+
"",
|
| 753 |
+
f"Placement reason: {artifact['placement_reason']}",
|
| 754 |
+
f"Plaque: _{artifact['plaque_line']}_",
|
| 755 |
+
"",
|
| 756 |
+
"Resonance links:",
|
| 757 |
+
]
|
| 758 |
+
if artifact["resonance_links"]:
|
| 759 |
+
placement.extend(
|
| 760 |
+
f"- {link['title']} by {link['creator']}: {link['resonance']}, distance {link['distance']}"
|
| 761 |
+
for link in artifact["resonance_links"]
|
| 762 |
+
)
|
| 763 |
+
else:
|
| 764 |
+
placement.append("- No nearby resonance yet. This artifact becomes an anchor for future visitors.")
|
| 765 |
+
spirit_lines = [
|
| 766 |
+
f"# {artifact['spirit_name']}",
|
| 767 |
+
f"Traits: {', '.join(artifact['spirit_traits'])}",
|
| 768 |
+
f"First line: _{artifact['spirit_first_line']}_",
|
| 769 |
+
"",
|
| 770 |
+
"Visitor questions and spirit responses:",
|
| 771 |
+
]
|
| 772 |
+
for question, response in zip(artifact["sample_visitor_questions"], artifact["sample_spirit_responses"]):
|
| 773 |
+
spirit_lines.append(f"- **{question}** {response}")
|
| 774 |
+
passport = passport_html(artifact) + floor_map_html(artifact)
|
| 775 |
+
return (
|
| 776 |
+
"\n".join(placement),
|
| 777 |
+
spirit_lines and "\n".join(spirit_lines),
|
| 778 |
+
passport,
|
| 779 |
+
json.dumps(packet, indent=2),
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
def load_demo_artifact(name: str):
|
| 784 |
+
data = DEMO_ARTIFACTS.get(name) or next(iter(DEMO_ARTIFACTS.values()))
|
| 785 |
+
return (
|
| 786 |
+
data["owner_name"],
|
| 787 |
+
data["owner_handle"],
|
| 788 |
+
data["input_type"],
|
| 789 |
+
data["source_prompt"],
|
| 790 |
+
data["memory_text"],
|
| 791 |
+
)
|
| 792 |
+
|
| 793 |
+
|
| 794 |
HABITATS = {
|
| 795 |
"redstone caves": ["electric", "mechanical", "small", "curious"],
|
| 796 |
"sky forest": ["flying", "social", "light", "watchful"],
|
|
|
|
| 1534 |
|
| 1535 |
CSS = """
|
| 1536 |
:root {
|
| 1537 |
+
--mc-ink: #f4ecd8;
|
| 1538 |
+
--mc-paper: #171410;
|
| 1539 |
--mc-green: #57744a;
|
| 1540 |
--mc-gold: #d39b45;
|
| 1541 |
+
--museum-stone: #1f211f;
|
| 1542 |
+
--museum-panel: #2b251c;
|
| 1543 |
+
--museum-glow: #f2c15f;
|
| 1544 |
}
|
| 1545 |
body, .gradio-container {
|
| 1546 |
+
background: #10110f !important;
|
| 1547 |
color: var(--mc-ink);
|
| 1548 |
}
|
| 1549 |
.gradio-container {
|
| 1550 |
max-width: 1180px !important;
|
| 1551 |
}
|
| 1552 |
.dreamwall-hero {
|
| 1553 |
+
background: linear-gradient(135deg, #1b1d1b 0%, #322719 100%);
|
| 1554 |
+
border: 3px solid #8b6a3d;
|
| 1555 |
+
box-shadow: 0 10px 0 #060605, inset 0 0 28px rgba(242, 193, 95, 0.12);
|
| 1556 |
padding: 22px;
|
| 1557 |
margin: 14px 0 18px;
|
| 1558 |
}
|
| 1559 |
.dreamwall-hero h1 {
|
| 1560 |
margin: 0;
|
| 1561 |
font-size: 42px;
|
| 1562 |
+
color: #ffe4a3;
|
| 1563 |
}
|
| 1564 |
.dreamwall-hero p {
|
| 1565 |
max-width: 760px;
|
| 1566 |
font-size: 17px;
|
| 1567 |
line-height: 1.45;
|
| 1568 |
+
color: #ead7b0;
|
| 1569 |
}
|
| 1570 |
.badge-row span {
|
| 1571 |
display: inline-block;
|
| 1572 |
+
border: 2px solid #8b6a3d;
|
| 1573 |
+
background: #211a12;
|
| 1574 |
+
color: #ffdc8a;
|
| 1575 |
padding: 6px 10px;
|
| 1576 |
margin: 4px 5px 0 0;
|
| 1577 |
font-weight: 700;
|
| 1578 |
}
|
| 1579 |
+
.museum-terminal {
|
| 1580 |
+
background: #171916;
|
| 1581 |
+
border: 2px solid #6f6a57;
|
| 1582 |
+
box-shadow: inset 0 0 18px rgba(242, 193, 95, 0.1);
|
| 1583 |
+
padding: 14px;
|
| 1584 |
+
margin: 10px 0;
|
| 1585 |
+
}
|
| 1586 |
+
.passport-card {
|
| 1587 |
+
background: #221d16;
|
| 1588 |
+
border: 3px solid #b98a46;
|
| 1589 |
+
box-shadow: 0 8px 0 #080705, inset 0 0 24px rgba(242, 193, 95, 0.14);
|
| 1590 |
+
color: #f9e4b4;
|
| 1591 |
+
padding: 18px;
|
| 1592 |
+
}
|
| 1593 |
+
.passport-card h2 {
|
| 1594 |
+
margin: 4px 0;
|
| 1595 |
+
font-size: 30px;
|
| 1596 |
+
color: #ffe6a6;
|
| 1597 |
+
}
|
| 1598 |
+
.passport-kicker {
|
| 1599 |
+
color: #e2b86f;
|
| 1600 |
+
font-size: 12px;
|
| 1601 |
+
letter-spacing: 0.08em;
|
| 1602 |
+
text-transform: uppercase;
|
| 1603 |
+
}
|
| 1604 |
+
.passport-owner {
|
| 1605 |
+
color: #cdbd9b;
|
| 1606 |
+
}
|
| 1607 |
+
.passport-grid {
|
| 1608 |
+
display: grid;
|
| 1609 |
+
grid-template-columns: minmax(160px, 240px) 1fr;
|
| 1610 |
+
gap: 16px;
|
| 1611 |
+
}
|
| 1612 |
+
.passport-preview {
|
| 1613 |
+
min-height: 150px;
|
| 1614 |
+
border: 2px solid #6f6a57;
|
| 1615 |
+
background: repeating-linear-gradient(45deg, #2b2d29 0, #2b2d29 10px, #242520 10px, #242520 20px);
|
| 1616 |
+
display: flex;
|
| 1617 |
+
flex-wrap: wrap;
|
| 1618 |
+
align-content: center;
|
| 1619 |
+
justify-content: center;
|
| 1620 |
+
gap: 8px;
|
| 1621 |
+
padding: 12px;
|
| 1622 |
+
}
|
| 1623 |
+
.museum-swatch {
|
| 1624 |
+
width: 30px;
|
| 1625 |
+
height: 30px;
|
| 1626 |
+
border: 2px solid #0b0b09;
|
| 1627 |
+
display: inline-block;
|
| 1628 |
+
}
|
| 1629 |
+
.floor-map {
|
| 1630 |
+
display: grid;
|
| 1631 |
+
grid-template-columns: repeat(12, 18px);
|
| 1632 |
+
gap: 3px;
|
| 1633 |
+
margin-top: 12px;
|
| 1634 |
+
}
|
| 1635 |
+
.floor-cell {
|
| 1636 |
+
width: 18px;
|
| 1637 |
+
height: 18px;
|
| 1638 |
+
background: #34372f;
|
| 1639 |
+
border: 1px solid #57513f;
|
| 1640 |
+
color: #1b160e;
|
| 1641 |
+
text-align: center;
|
| 1642 |
+
line-height: 18px;
|
| 1643 |
+
}
|
| 1644 |
+
.floor-cell.active {
|
| 1645 |
+
background: #f2c15f;
|
| 1646 |
+
box-shadow: 0 0 10px #f2c15f;
|
| 1647 |
+
}
|
| 1648 |
textarea, input {
|
| 1649 |
font-family: ui-monospace, SFMono-Regular, Menlo, monospace !important;
|
| 1650 |
}
|
|
|
|
| 1655 |
gr.HTML(
|
| 1656 |
"""
|
| 1657 |
<section class="dreamwall-hero">
|
| 1658 |
+
<h1>DreamWall: AfterBlock Museum</h1>
|
| 1659 |
<p>
|
| 1660 |
+
Scan a relic, memory, animal spirit, or prompted painting. The museum assigns
|
| 1661 |
+
a hall, chisels a Minecraft placement, awakens a tiny spirit, and prints an
|
| 1662 |
+
artifact passport for the server.
|
| 1663 |
</p>
|
| 1664 |
<div class="badge-row">
|
| 1665 |
<span>Adventure in Thousand Token Wood</span>
|
|
|
|
| 1672 |
</section>
|
| 1673 |
"""
|
| 1674 |
)
|
| 1675 |
+
gr.HTML("<h2>AfterBlock Museum Terminal</h2><div class='museum-terminal'>chiseling memory into blocks... consulting the museum curator... assigning hall placement... awakening artifact spirit...</div>")
|
| 1676 |
+
with gr.Row():
|
| 1677 |
+
with gr.Column(scale=5):
|
| 1678 |
+
demo_choice = gr.Dropdown(
|
| 1679 |
+
label="Seeded demo relic",
|
| 1680 |
+
choices=list(DEMO_ARTIFACTS),
|
| 1681 |
+
value="AirPods from first year of university",
|
| 1682 |
+
)
|
| 1683 |
+
owner_name = gr.Textbox(label="Owner name", value="Arnav")
|
| 1684 |
+
owner_handle = gr.Textbox(label="Owner handle", value="@Wildstash")
|
| 1685 |
+
input_type = gr.Dropdown(
|
| 1686 |
+
label="Input type",
|
| 1687 |
+
choices=["object_photo", "painting_prompt", "memory_prompt", "animal_spirit"],
|
| 1688 |
+
value="object_photo",
|
| 1689 |
+
)
|
| 1690 |
+
relic_prompt = gr.Textbox(
|
| 1691 |
+
label="Scan relic / prompt",
|
| 1692 |
+
lines=3,
|
| 1693 |
+
value="white AirPods from my first year of university",
|
| 1694 |
+
)
|
| 1695 |
+
memory_text = gr.Textbox(
|
| 1696 |
+
label="Memory text",
|
| 1697 |
+
lines=3,
|
| 1698 |
+
value="They carried private worlds through public noise during my first year away.",
|
| 1699 |
+
)
|
| 1700 |
+
museum_button = gr.Button("Curate Artifact", variant="primary")
|
| 1701 |
+
with gr.Column(scale=5):
|
| 1702 |
+
with gr.Tabs():
|
| 1703 |
+
with gr.Tab("Curate Placement"):
|
| 1704 |
+
museum_placement = gr.Markdown()
|
| 1705 |
+
with gr.Tab("Awaken Spirit"):
|
| 1706 |
+
museum_spirit = gr.Markdown()
|
| 1707 |
+
with gr.Tab("Passport Card"):
|
| 1708 |
+
museum_passport = gr.HTML()
|
| 1709 |
+
with gr.Tab("Minecraft Bridge"):
|
| 1710 |
+
museum_packet = gr.Textbox(label="dreamwall.museum.v1", lines=22, max_lines=32)
|
| 1711 |
+
|
| 1712 |
+
demo_choice.change(
|
| 1713 |
+
load_demo_artifact,
|
| 1714 |
+
inputs=[demo_choice],
|
| 1715 |
+
outputs=[owner_name, owner_handle, input_type, relic_prompt, memory_text],
|
| 1716 |
+
)
|
| 1717 |
+
museum_button.click(
|
| 1718 |
+
curate_afterblock_artifact,
|
| 1719 |
+
inputs=[owner_name, owner_handle, input_type, relic_prompt, memory_text],
|
| 1720 |
+
outputs=[museum_placement, museum_spirit, museum_passport, museum_packet],
|
| 1721 |
+
api_name="curate_artifact",
|
| 1722 |
+
)
|
| 1723 |
+
demo.load(
|
| 1724 |
+
curate_afterblock_artifact,
|
| 1725 |
+
inputs=[owner_name, owner_handle, input_type, relic_prompt, memory_text],
|
| 1726 |
+
outputs=[museum_placement, museum_spirit, museum_passport, museum_packet],
|
| 1727 |
+
)
|
| 1728 |
+
|
| 1729 |
gr.HTML("<h2>Living Graffiti Wall</h2>")
|
| 1730 |
with gr.Row():
|
| 1731 |
with gr.Column(scale=5):
|
docs/COMPETITION_GOAL.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
| 1 |
-
# DreamWall
|
| 2 |
|
| 3 |
## Goal
|
| 4 |
|
| 5 |
-
Win the Build Small Hackathon by making DreamWall
|
| 6 |
|
| 7 |
## Submission Bet
|
| 8 |
|
| 9 |
-
|
| 10 |
|
| 11 |
-
-
|
| 12 |
-
-
|
| 13 |
-
- each artifact
|
| 14 |
-
-
|
| 15 |
-
- the
|
| 16 |
-
- the Minecraft server becomes the proof surface
|
| 17 |
|
| 18 |
## What To Avoid For V1
|
| 19 |
|
|
@@ -22,25 +22,25 @@ DreamWall is not a chatbot and not a normal image generator. It is a social imag
|
|
| 22 |
- Complex ownership law
|
| 23 |
- Persistent public multiplayer economy before the demo works
|
| 24 |
|
| 25 |
-
Use **
|
| 26 |
|
| 27 |
## Winning Demo
|
| 28 |
|
| 29 |
One continuous video:
|
| 30 |
|
| 31 |
1. Open the Hugging Face Space.
|
| 32 |
-
2.
|
| 33 |
-
3.
|
| 34 |
-
4.
|
| 35 |
-
5.
|
| 36 |
-
6.
|
| 37 |
-
7.
|
| 38 |
-
8.
|
| 39 |
-
9.
|
| 40 |
-
10. End with: "100 people prompt the wall; nobody knows what public mural survives."
|
| 41 |
|
| 42 |
## Target Prizes
|
| 43 |
|
| 44 |
- OpenAI Codex Track: public GitHub repo with Codex-authored commits.
|
| 45 |
-
- Adventure in Thousand Token Wood: strange,
|
| 46 |
-
-
|
|
|
|
|
|
| 1 |
+
# DreamWall: AfterBlock Museum Competition Goal
|
| 2 |
|
| 3 |
## Goal
|
| 4 |
|
| 5 |
+
Win the Build Small Hackathon by making DreamWall feel like a new way to preserve memory: an emotional Minecraft museum where real objects, prompted paintings, animals, and personal symbols become placed artifacts with passports and tiny spirits.
|
| 6 |
|
| 7 |
## Submission Bet
|
| 8 |
|
| 9 |
+
AfterBlock Museum is not a chatbot and not a normal image generator. It is a Minecraft museum ritual:
|
| 10 |
|
| 11 |
+
- visitors scan a relic, memory, animal spirit, or prompted painting
|
| 12 |
+
- the curator assigns a hall and museum placement
|
| 13 |
+
- each artifact receives curation scores, resonance links, and a plaque
|
| 14 |
+
- a constrained spirit awakens and speaks from the artifact lore
|
| 15 |
+
- the app prints a passport card and emits `dreamwall.museum.v1`
|
| 16 |
+
- the Minecraft server becomes the proof surface
|
| 17 |
|
| 18 |
## What To Avoid For V1
|
| 19 |
|
|
|
|
| 22 |
- Complex ownership law
|
| 23 |
- Persistent public multiplayer economy before the demo works
|
| 24 |
|
| 25 |
+
Use **curation score**, **visitor echoes**, and **resonance** instead of auction language.
|
| 26 |
|
| 27 |
## Winning Demo
|
| 28 |
|
| 29 |
One continuous video:
|
| 30 |
|
| 31 |
1. Open the Hugging Face Space.
|
| 32 |
+
2. Pick the AirPods seeded demo.
|
| 33 |
+
3. Show the hall assignment, curation score, and placement reason.
|
| 34 |
+
4. Open **Awaken Spirit** and read the first line: "I carried private worlds through public noise."
|
| 35 |
+
5. Open **Passport Card** and show the Minecraft coordinates.
|
| 36 |
+
6. Open **Minecraft Bridge** and show `dreamwall.museum.v1`.
|
| 37 |
+
7. Switch to Minecraft.
|
| 38 |
+
8. Place or mock one pedestal/sign using the packet coordinates.
|
| 39 |
+
9. End with: "AfterBlock turns the things people would throw away into places they can visit."
|
|
|
|
| 40 |
|
| 41 |
## Target Prizes
|
| 42 |
|
| 43 |
- OpenAI Codex Track: public GitHub repo with Codex-authored commits.
|
| 44 |
+
- Adventure in Thousand Token Wood: strange, emotional, delightful, AI-load-bearing, and small enough to run without a giant model dependency.
|
| 45 |
+
- Off-Brand: Minecraft museum terminal rather than default chatbot UI.
|
| 46 |
+
- Best Demo: object to hall to spirit to passport to Minecraft proof in under 75 seconds.
|
docs/DEMO_RUNBOOK.md
CHANGED
|
@@ -1,29 +1,28 @@
|
|
| 1 |
-
# Demo Runbook
|
| 2 |
|
| 3 |
## Story
|
| 4 |
|
| 5 |
-
|
| 6 |
|
| 7 |
## Script
|
| 8 |
|
| 9 |
1. Show the Hugging Face Space.
|
| 10 |
-
2.
|
| 11 |
-
3.
|
| 12 |
-
4.
|
| 13 |
-
5.
|
| 14 |
-
6.
|
| 15 |
-
7. Open
|
| 16 |
-
8.
|
| 17 |
-
9.
|
| 18 |
-
10.
|
| 19 |
-
11. End with: "100 people prompt the wall; nobody knows what public mural survives."
|
| 20 |
|
| 21 |
## Video Requirements
|
| 22 |
|
| 23 |
-
- Keep the final demo under
|
| 24 |
- Show both the Space and Minecraft world.
|
| 25 |
- Do not explain implementation details in the voiceover.
|
| 26 |
-
- Focus on the magic:
|
| 27 |
|
| 28 |
## Submission Checklist
|
| 29 |
|
|
@@ -32,4 +31,4 @@ Living Graffiti is a social Minecraft wall where anonymous prompts become animat
|
|
| 32 |
- GitHub commits are Codex-authored.
|
| 33 |
- Field notes are present.
|
| 34 |
- Demo video shows real UI and Minecraft proof.
|
| 35 |
-
- Social post says this is a
|
|
|
|
| 1 |
+
# AfterBlock Demo Runbook
|
| 2 |
|
| 3 |
## Story
|
| 4 |
|
| 5 |
+
AfterBlock Museum preserves ordinary objects as Minecraft artifacts. The Space acts like a museum terminal: it scans a relic, assigns a hall, awakens a tiny spirit, prints a passport card, and emits a bridge packet for the server.
|
| 6 |
|
| 7 |
## Script
|
| 8 |
|
| 9 |
1. Show the Hugging Face Space.
|
| 10 |
+
2. Select **AirPods from first year of university**.
|
| 11 |
+
3. Click **Curate Artifact**.
|
| 12 |
+
4. Show **Curate Placement**: Hall of Companions or Lost Signals, plot, coordinates, curation score.
|
| 13 |
+
5. Open **Awaken Spirit** and read: "I carried private worlds through public noise."
|
| 14 |
+
6. Open **Passport Card** and show the blocky card/floor map.
|
| 15 |
+
7. Open **Minecraft Bridge** and show `dreamwall.museum.v1`.
|
| 16 |
+
8. Switch to Minecraft.
|
| 17 |
+
9. Show a pedestal/sign/painting marker at the packet coordinates.
|
| 18 |
+
10. End with: "AfterBlock turns the things people would throw away into places they can visit."
|
|
|
|
| 19 |
|
| 20 |
## Video Requirements
|
| 21 |
|
| 22 |
+
- Keep the final demo under 75 seconds.
|
| 23 |
- Show both the Space and Minecraft world.
|
| 24 |
- Do not explain implementation details in the voiceover.
|
| 25 |
+
- Focus on the magic: a memory becomes a place with a spirit.
|
| 26 |
|
| 27 |
## Submission Checklist
|
| 28 |
|
|
|
|
| 31 |
- GitHub commits are Codex-authored.
|
| 32 |
- Field notes are present.
|
| 33 |
- Demo video shows real UI and Minecraft proof.
|
| 34 |
+
- Social post says this is a Minecraft memory museum, not a chatbot.
|
docs/MINECRAFT_SERVER_BLUEPRINT.md
CHANGED
|
@@ -29,7 +29,7 @@ Optional:
|
|
| 29 |
|
| 30 |
## World Shape
|
| 31 |
|
| 32 |
-
Flat world with one
|
| 33 |
|
| 34 |
Suggested layout:
|
| 35 |
|
|
@@ -37,10 +37,10 @@ Suggested layout:
|
|
| 37 |
spawn
|
| 38 |
|
|
| 39 |
+-- welcome board
|
| 40 |
-
+--
|
| 41 |
-
+--
|
| 42 |
-
+--
|
| 43 |
-
+--
|
| 44 |
```
|
| 45 |
|
| 46 |
Coordinates:
|
|
@@ -52,12 +52,13 @@ grid: 12 x 12
|
|
| 52 |
total canvas: 384 x 384 blocks
|
| 53 |
```
|
| 54 |
|
| 55 |
-
##
|
| 56 |
|
| 57 |
-
- Each submission gets a deterministic
|
| 58 |
-
-
|
| 59 |
-
-
|
| 60 |
-
-
|
|
|
|
| 61 |
|
| 62 |
## First Server Milestone
|
| 63 |
|
|
@@ -65,14 +66,32 @@ total canvas: 384 x 384 blocks
|
|
| 65 |
2. Install Paper and WorldEdit.
|
| 66 |
3. Upload DreamWall bridge jar.
|
| 67 |
4. Run `/dreamwall fetch`.
|
| 68 |
-
5. Call the `
|
| 69 |
-
6. Manually place one
|
| 70 |
-
7. Add signs for title,
|
| 71 |
8. Record a 20-second proof clip.
|
| 72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
## Living Canvas Packet
|
| 74 |
|
| 75 |
-
The
|
| 76 |
|
| 77 |
It gives the server:
|
| 78 |
|
|
|
|
| 29 |
|
| 30 |
## World Shape
|
| 31 |
|
| 32 |
+
Flat world with one museum campus plus the existing public canvas as a secondary wing.
|
| 33 |
|
| 34 |
Suggested layout:
|
| 35 |
|
|
|
|
| 37 |
spawn
|
| 38 |
|
|
| 39 |
+-- welcome board
|
| 40 |
+
+-- AfterBlock Museum terminal
|
| 41 |
+
+-- hall corridor
|
| 42 |
+
+-- artifact pedestals/signs
|
| 43 |
+
+-- DreamWall canvas wing at y=80
|
| 44 |
```
|
| 45 |
|
| 46 |
Coordinates:
|
|
|
|
| 52 |
total canvas: 384 x 384 blocks
|
| 53 |
```
|
| 54 |
|
| 55 |
+
## Museum Rules
|
| 56 |
|
| 57 |
+
- Each submission gets a deterministic hall, zone, plot, and Minecraft coordinate.
|
| 58 |
+
- Curation score replaces market value.
|
| 59 |
+
- Plaques show title, owner handle, spirit first line, and hall.
|
| 60 |
+
- Resonance links connect nearby or emotionally similar artifacts.
|
| 61 |
+
- No real-money ownership, blockchain, or NFT claims.
|
| 62 |
|
| 63 |
## First Server Milestone
|
| 64 |
|
|
|
|
| 66 |
2. Install Paper and WorldEdit.
|
| 67 |
3. Upload DreamWall bridge jar.
|
| 68 |
4. Run `/dreamwall fetch`.
|
| 69 |
+
5. Call the `curate_artifact` Space endpoint and copy the `dreamwall.museum.v1` packet.
|
| 70 |
+
6. Manually place one pedestal/sign at `museum.coordinates`.
|
| 71 |
+
7. Add signs for title, owner handle, hall, plaque line, and spirit first line.
|
| 72 |
8. Record a 20-second proof clip.
|
| 73 |
|
| 74 |
+
## Museum Packet
|
| 75 |
+
|
| 76 |
+
The main demo packet is `dreamwall.museum.v1`.
|
| 77 |
+
|
| 78 |
+
It gives the server:
|
| 79 |
+
|
| 80 |
+
- artifact title
|
| 81 |
+
- owner handle
|
| 82 |
+
- hall and zone
|
| 83 |
+
- plot and coordinates
|
| 84 |
+
- block palette/materials
|
| 85 |
+
- plaque text
|
| 86 |
+
- spirit first line
|
| 87 |
+
- passport QR payload
|
| 88 |
+
- curation scores and resonance links
|
| 89 |
+
|
| 90 |
+
The Paper plugin V1 only needs to import the packet and place a pedestal/sign/painting marker at the coordinates.
|
| 91 |
+
|
| 92 |
## Living Canvas Packet
|
| 93 |
|
| 94 |
+
The secondary canvas packet is `living_canvas.mc.v1`.
|
| 95 |
|
| 96 |
It gives the server:
|
| 97 |
|
docs/MUSEUM_CURATION.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Museum Curation
|
| 2 |
+
|
| 3 |
+
AfterBlock Museum should feel like memories have resonance, not like plots are being sold.
|
| 4 |
+
|
| 5 |
+
## Curation Signals
|
| 6 |
+
|
| 7 |
+
The app computes curation from:
|
| 8 |
+
|
| 9 |
+
- **Nostalgia:** childhood, firsts, school, home, and remembered routines.
|
| 10 |
+
- **Symbolism:** objects that carry myth, signal, protection, or identity.
|
| 11 |
+
- **Identity:** how strongly the relic belongs to the owner.
|
| 12 |
+
- **Companionship:** objects that stayed close through ordinary days.
|
| 13 |
+
- **Transformation:** exams, trades, moves, first years, and turning points.
|
| 14 |
+
- **Rarity:** unusual object/memory combinations.
|
| 15 |
+
- **Palette rarity:** rare Minecraft materials in the artifact palette.
|
| 16 |
+
- **Adjacency resonance:** nearby museum artifacts that echo the new relic.
|
| 17 |
+
- **Visitor echoes:** how likely visitors are to ask about it.
|
| 18 |
+
|
| 19 |
+
## Resonance
|
| 20 |
+
|
| 21 |
+
Resonance replaces auction language.
|
| 22 |
+
|
| 23 |
+
Examples:
|
| 24 |
+
|
| 25 |
+
- AirPods from first year of university resonate with Lost Signals and Soft Things.
|
| 26 |
+
- A childhood Star Wars book resonates with Worlds and Firsts.
|
| 27 |
+
- A monitor used for a first Bitcoin trade resonates with Tools and Turning Points.
|
| 28 |
+
- A school bag carried through exams resonates with Companions and pressure memories.
|
| 29 |
+
|
| 30 |
+
The key is emotional legibility: visitors should immediately understand why the artifact belongs in its hall.
|
| 31 |
+
|
| 32 |
+
## Why Not Market Language
|
| 33 |
+
|
| 34 |
+
Auction, reserve, and blockchain language distract from the stronger demo.
|
| 35 |
+
|
| 36 |
+
The winning V1 is:
|
| 37 |
+
|
| 38 |
+
```text
|
| 39 |
+
relic -> hall -> spirit -> passport -> Minecraft museum placement
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
The old `dreamwall.market.v1` packet can remain for compatibility, but the main user-facing packet is now `dreamwall.museum.v1`.
|
paper-plugin/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
-
# DreamWall Paper Bridge
|
| 2 |
|
| 3 |
-
This is the Minecraft server bridge for DreamWall
|
| 4 |
|
| 5 |
The hackathon Space is the official submission surface. This plugin scaffold is the live-demo layer: it connects a Paper server to the Space API and prepares the path for placing generated wall art inside Minecraft.
|
| 6 |
|
|
@@ -8,12 +8,33 @@ The hackathon Space is the official submission surface. This plugin scaffold is
|
|
| 8 |
|
| 9 |
- `/dreamwall` shows the configured Space endpoint.
|
| 10 |
- `/dreamwall fetch` calls the Space app domain and confirms the bridge can reach Hugging Face.
|
| 11 |
-
- A scheduled task can be extended to poll approved
|
| 12 |
-
- The Space now emits `
|
|
|
|
| 13 |
|
| 14 |
## Planned Placement Behavior
|
| 15 |
|
| 16 |
-
The Space
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
- `job_id`
|
| 19 |
- `player`
|
|
@@ -26,7 +47,7 @@ The Space emits a `dreamwall.mc.v1` JSON packet with:
|
|
| 26 |
- `grid.row_runs`
|
| 27 |
- WorldEdit preview lines
|
| 28 |
|
| 29 |
-
The
|
| 30 |
|
| 31 |
- `tile_size_blocks`: `32 x 32`
|
| 32 |
- `canvas_size_tiles`: `12 x 12`
|
|
@@ -57,12 +78,12 @@ The Space also emits a `neuropets.mc.v1` packet from the `hatch_pet` endpoint. T
|
|
| 57 |
|
| 58 |
For the hackathon video, the safest route is:
|
| 59 |
|
| 60 |
-
1. Run
|
| 61 |
-
2. Copy the `
|
| 62 |
-
3. Place one
|
| 63 |
-
4. Add signs for
|
| 64 |
-
5. Use particles
|
| 65 |
-
6. Walk through the
|
| 66 |
|
| 67 |
## Flat World Canvas
|
| 68 |
|
|
@@ -84,6 +105,10 @@ For `living_canvas.mc.v1`, the packet already includes `tiles[].minecraft_origin
|
|
| 84 |
|
| 85 |
## Build
|
| 86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
```bash
|
| 88 |
mvn package
|
| 89 |
```
|
|
|
|
| 1 |
+
# DreamWall AfterBlock Paper Bridge
|
| 2 |
|
| 3 |
+
This is the Minecraft server bridge for DreamWall: AfterBlock Museum.
|
| 4 |
|
| 5 |
The hackathon Space is the official submission surface. This plugin scaffold is the live-demo layer: it connects a Paper server to the Space API and prepares the path for placing generated wall art inside Minecraft.
|
| 6 |
|
|
|
|
| 8 |
|
| 9 |
- `/dreamwall` shows the configured Space endpoint.
|
| 10 |
- `/dreamwall fetch` calls the Space app domain and confirms the bridge can reach Hugging Face.
|
| 11 |
+
- A scheduled task can be extended to poll approved museum artifacts.
|
| 12 |
+
- The Space now emits `dreamwall.museum.v1`, the main AfterBlock packet for the hackathon demo.
|
| 13 |
+
- The Space also emits `living_canvas.mc.v1` for the secondary wall/canvas mode.
|
| 14 |
|
| 15 |
## Planned Placement Behavior
|
| 16 |
|
| 17 |
+
The main Space endpoint is `curate_artifact`, which emits `dreamwall.museum.v1` with:
|
| 18 |
+
|
| 19 |
+
- artifact title
|
| 20 |
+
- owner handle
|
| 21 |
+
- hall and zone
|
| 22 |
+
- plot and coordinates
|
| 23 |
+
- block palette/materials
|
| 24 |
+
- plaque text
|
| 25 |
+
- spirit first line
|
| 26 |
+
- passport QR payload
|
| 27 |
+
- curation scores
|
| 28 |
+
- resonance links
|
| 29 |
+
|
| 30 |
+
Expected `/dreamwall fetch` V1 behavior:
|
| 31 |
+
|
| 32 |
+
1. Fetch latest artifact packet.
|
| 33 |
+
2. Place pedestal/sign/painting marker at coordinates.
|
| 34 |
+
3. Display plaque line and owner handle.
|
| 35 |
+
4. Optionally create particles or a simple animation based on artifact type.
|
| 36 |
+
|
| 37 |
+
The legacy `generate_art` endpoint emits a `dreamwall.mc.v1` JSON packet with:
|
| 38 |
|
| 39 |
- `job_id`
|
| 40 |
- `player`
|
|
|
|
| 47 |
- `grid.row_runs`
|
| 48 |
- WorldEdit preview lines
|
| 49 |
|
| 50 |
+
The secondary canvas path uses `living_canvas.mc.v1` from the `living_canvas` endpoint:
|
| 51 |
|
| 52 |
- `tile_size_blocks`: `32 x 32`
|
| 53 |
- `canvas_size_tiles`: `12 x 12`
|
|
|
|
| 78 |
|
| 79 |
For the hackathon video, the safest route is:
|
| 80 |
|
| 81 |
+
1. Run AfterBlock Museum in the Space.
|
| 82 |
+
2. Copy the `dreamwall.museum.v1` packet or call the Gradio API.
|
| 83 |
+
3. Place one artifact pedestal/sign at `museum.coordinates`.
|
| 84 |
+
4. Add signs for owner, title, hall, plaque, and spirit first line.
|
| 85 |
+
5. Use particles around the pedestal for the artifact spirit.
|
| 86 |
+
6. Walk through the museum gallery.
|
| 87 |
|
| 88 |
## Flat World Canvas
|
| 89 |
|
|
|
|
| 105 |
|
| 106 |
## Build
|
| 107 |
|
| 108 |
+
GitHub Actions builds the jar through `.github/workflows/build-plugin.yml`.
|
| 109 |
+
|
| 110 |
+
Local build, if Maven is installed:
|
| 111 |
+
|
| 112 |
```bash
|
| 113 |
mvn package
|
| 114 |
```
|