feat: wire HermesWorld MJ assets (#374)
Co-authored-by: Aurora release bot <release@outsourc-e.com>
475
public/assets/hermesworld/MANIFEST.json
Normal file
@@ -0,0 +1,475 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"generatedBy": "Hermes asset wiring inventory",
|
||||
"sourceRoots": [
|
||||
"public/assets/hermesworld/art",
|
||||
"public/assets/hermesworld/characters",
|
||||
"public/assets/hermesworld/zones",
|
||||
"public/assets/hermesworld/v2",
|
||||
"public/assets/hermesworld/video"
|
||||
],
|
||||
"assetCount": 38,
|
||||
"notes": [
|
||||
"Inventory covers existing files only; no image generation performed.",
|
||||
"Video dimensions are read from the first video stream when ffprobe is available.",
|
||||
"v2 contact sheets are source/reference assets; individual runtime usage should crop or object-fit as needed."
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-app-icon.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-app-icon.png",
|
||||
"extension": "png",
|
||||
"bytes": 1257,
|
||||
"sizeLabel": "1.2 KB",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "app_icon"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-app-icon.svg",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-app-icon.svg",
|
||||
"extension": "svg",
|
||||
"bytes": 259,
|
||||
"sizeLabel": "0.3 KB",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "app_icon"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-app-icon@2x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-app-icon@2x.png",
|
||||
"extension": "png",
|
||||
"bytes": 26594,
|
||||
"sizeLabel": "26.0 KB",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "app_icon"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-app-icon@3x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-app-icon@3x.png",
|
||||
"extension": "png",
|
||||
"bytes": 52299,
|
||||
"sizeLabel": "51.1 KB",
|
||||
"width": 768,
|
||||
"height": 768,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "app_icon"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-caduceus-badge.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-caduceus-badge.png",
|
||||
"extension": "png",
|
||||
"bytes": 162956,
|
||||
"sizeLabel": "159.1 KB",
|
||||
"width": 467,
|
||||
"height": 280,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-caduceus-favicon.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-caduceus-favicon.png",
|
||||
"extension": "png",
|
||||
"bytes": 15211,
|
||||
"sizeLabel": "14.9 KB",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "app_icon"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-caduceus.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-caduceus.png",
|
||||
"extension": "png",
|
||||
"bytes": 124317,
|
||||
"sizeLabel": "121.4 KB",
|
||||
"width": 467,
|
||||
"height": 280,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-h.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-h.png",
|
||||
"extension": "png",
|
||||
"bytes": 15211,
|
||||
"sizeLabel": "14.9 KB",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-horizontal.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-horizontal.png",
|
||||
"extension": "png",
|
||||
"bytes": 37128,
|
||||
"sizeLabel": "36.3 KB",
|
||||
"width": 520,
|
||||
"height": 156,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-horizontal.svg",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-horizontal.svg",
|
||||
"extension": "svg",
|
||||
"bytes": 273,
|
||||
"sizeLabel": "0.3 KB",
|
||||
"width": 520,
|
||||
"height": 156,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-horizontal@2x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-horizontal@2x.png",
|
||||
"extension": "png",
|
||||
"bytes": 137541,
|
||||
"sizeLabel": "134.3 KB",
|
||||
"width": 1040,
|
||||
"height": 312,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-horizontal@3x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-horizontal@3x.png",
|
||||
"extension": "png",
|
||||
"bytes": 258461,
|
||||
"sizeLabel": "252.4 KB",
|
||||
"width": 1560,
|
||||
"height": 468,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-stacked.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-stacked.png",
|
||||
"extension": "png",
|
||||
"bytes": 99870,
|
||||
"sizeLabel": "97.5 KB",
|
||||
"width": 360,
|
||||
"height": 300,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-stacked.svg",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-stacked.svg",
|
||||
"extension": "svg",
|
||||
"bytes": 267,
|
||||
"sizeLabel": "0.3 KB",
|
||||
"width": 360,
|
||||
"height": 300,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-stacked@2x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-stacked@2x.png",
|
||||
"extension": "png",
|
||||
"bytes": 335190,
|
||||
"sizeLabel": "327.3 KB",
|
||||
"width": 720,
|
||||
"height": 600,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-logo-stacked@3x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-logo-stacked@3x.png",
|
||||
"extension": "png",
|
||||
"bytes": 640821,
|
||||
"sizeLabel": "625.8 KB",
|
||||
"width": 1080,
|
||||
"height": 900,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-sigil.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-sigil.png",
|
||||
"extension": "png",
|
||||
"bytes": 15211,
|
||||
"sizeLabel": "14.9 KB",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-sigil.svg",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-sigil.svg",
|
||||
"extension": "svg",
|
||||
"bytes": 253,
|
||||
"sizeLabel": "0.2 KB",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-sigil@2x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-sigil@2x.png",
|
||||
"extension": "png",
|
||||
"bytes": 51261,
|
||||
"sizeLabel": "50.1 KB",
|
||||
"width": 320,
|
||||
"height": 320,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/hermesworld-sigil@3x.png",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "hermesworld-sigil@3x.png",
|
||||
"extension": "png",
|
||||
"bytes": 96409,
|
||||
"sizeLabel": "94.1 KB",
|
||||
"width": 480,
|
||||
"height": 480,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "brand_logo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/art/social-preview-hero.jpg",
|
||||
"directory": "public/assets/hermesworld/art",
|
||||
"fileName": "social-preview-hero.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 82326,
|
||||
"sizeLabel": "80.4 KB",
|
||||
"width": 1200,
|
||||
"height": 630,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "social_share_preview"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/characters/README.md",
|
||||
"directory": "public/assets/hermesworld/characters",
|
||||
"fileName": "README.md",
|
||||
"extension": "md",
|
||||
"bytes": 684,
|
||||
"sizeLabel": "0.7 KB",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "character_asset_placeholder"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/cityscape.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "cityscape.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 63712,
|
||||
"sizeLabel": "62.2 KB",
|
||||
"width": 1920,
|
||||
"height": 600,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_background_hero"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/hero.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "hero.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 119035,
|
||||
"sizeLabel": "116.2 KB",
|
||||
"width": 1280,
|
||||
"height": 780,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_background_hero"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-1.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-1.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 28167,
|
||||
"sizeLabel": "27.5 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-2.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-2.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 41268,
|
||||
"sizeLabel": "40.3 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-3.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-3.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 48092,
|
||||
"sizeLabel": "47.0 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-4.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-4.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 48371,
|
||||
"sizeLabel": "47.2 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-5.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-5.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 40418,
|
||||
"sizeLabel": "39.5 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/zones/zone-6.jpg",
|
||||
"directory": "public/assets/hermesworld/zones",
|
||||
"fileName": "zone-6.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 59446,
|
||||
"sizeLabel": "58.1 KB",
|
||||
"width": 600,
|
||||
"height": 520,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "zone_fallback_background"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/v2/IMAGEGEN-STATUS.md",
|
||||
"directory": "public/assets/hermesworld/v2",
|
||||
"fileName": "IMAGEGEN-STATUS.md",
|
||||
"extension": "md",
|
||||
"bytes": 796,
|
||||
"sizeLabel": "0.8 KB",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "v2_pipeline_doc"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/v2/MANIFEST.md",
|
||||
"directory": "public/assets/hermesworld/v2",
|
||||
"fileName": "MANIFEST.md",
|
||||
"extension": "md",
|
||||
"bytes": 358,
|
||||
"sizeLabel": "0.3 KB",
|
||||
"width": null,
|
||||
"height": null,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "v2_pipeline_doc"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/v2/wave-a-source/A03-A08-rerolls.png",
|
||||
"directory": "public/assets/hermesworld/v2/wave-a-source",
|
||||
"fileName": "A03-A08-rerolls.png",
|
||||
"extension": "png",
|
||||
"bytes": 1605926,
|
||||
"sizeLabel": "1.53 MB",
|
||||
"width": 1774,
|
||||
"height": 887,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "source_contact_sheet_or_portrait_reference"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/v2/wave-a-source/all-images-contact-sheet.png",
|
||||
"directory": "public/assets/hermesworld/v2/wave-a-source",
|
||||
"fileName": "all-images-contact-sheet.png",
|
||||
"extension": "png",
|
||||
"bytes": 2131604,
|
||||
"sizeLabel": "2.03 MB",
|
||||
"width": 1536,
|
||||
"height": 1024,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "source_contact_sheet_or_portrait_reference"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/video/hero-720p.mp4",
|
||||
"directory": "public/assets/hermesworld/video",
|
||||
"fileName": "hero-720p.mp4",
|
||||
"extension": "mp4",
|
||||
"bytes": 644082,
|
||||
"sizeLabel": "629.0 KB",
|
||||
"width": 1280,
|
||||
"height": 874,
|
||||
"durationSeconds": 9.683333,
|
||||
"suggestedUseCategory": "video_demo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/video/hero-poster.jpg",
|
||||
"directory": "public/assets/hermesworld/video",
|
||||
"fileName": "hero-poster.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 64556,
|
||||
"sizeLabel": "63.0 KB",
|
||||
"width": 1280,
|
||||
"height": 874,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "video_poster"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/video/world-demo-720p.mp4",
|
||||
"directory": "public/assets/hermesworld/video",
|
||||
"fileName": "world-demo-720p.mp4",
|
||||
"extension": "mp4",
|
||||
"bytes": 10353994,
|
||||
"sizeLabel": "9.87 MB",
|
||||
"width": 1076,
|
||||
"height": 720,
|
||||
"durationSeconds": 75.033333,
|
||||
"suggestedUseCategory": "video_demo"
|
||||
},
|
||||
{
|
||||
"path": "public/assets/hermesworld/video/world-demo-poster.jpg",
|
||||
"directory": "public/assets/hermesworld/video",
|
||||
"fileName": "world-demo-poster.jpg",
|
||||
"extension": "jpg",
|
||||
"bytes": 63007,
|
||||
"sizeLabel": "61.5 KB",
|
||||
"width": 1076,
|
||||
"height": 720,
|
||||
"durationSeconds": null,
|
||||
"suggestedUseCategory": "video_poster"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 159 KiB |
BIN
public/assets/hermesworld/art/hermesworld-logo-caduceus.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
21
public/assets/hermesworld/v2/IMAGEGEN-STATUS.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Imagegen Status — 2026-05-06 07:05 EDT
|
||||
|
||||
## Result: Imagegen blocked tonight
|
||||
|
||||
All 3 configured image models failed:
|
||||
|
||||
- `google/gemini-3.1-flash-image-preview` — no API key configured
|
||||
- `minimax/image-01` — plan does not support this model
|
||||
- `openai/gpt-image-1` — **billing hard limit reached**
|
||||
|
||||
## What we have
|
||||
|
||||
- WAVE-A-PROMPTS.md is complete (PR #13) — 18 prompts ready to feed into any working imagegen
|
||||
- Style lock + brand sheet in place (PR #18)
|
||||
- Once Eric resolves billing or adds Google API key, all 18 prompts can be batched and saved to `wave-a-source/`
|
||||
|
||||
## Recommended next step for Eric
|
||||
|
||||
1. Top up OpenAI billing (gpt-image-1)
|
||||
2. Or add Google AI Studio API key for gemini-3.1-flash-image-preview
|
||||
3. Then re-dispatch swarm5 or run from orchestrator with WAVE-A-PROMPTS.md
|
||||
9
public/assets/hermesworld/v2/MANIFEST.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# HermesWorld v2 Asset Manifest
|
||||
|
||||
All Wave A/B/C/D/E generated assets land here. Each row tracks prompt, model, batch, vision-review status.
|
||||
|
||||
| File | Wave | Prompt | Model | Status | Vision Review |
|
||||
|------|------|--------|-------|--------|---------------|
|
||||
| (TBD) | A | TBD | gpt-5.5 | pending | pending |
|
||||
|
||||
Logged automatically by the swarm asset-gen lane.
|
||||
BIN
public/assets/hermesworld/v2/wave-a-source/A03-A08-rerolls.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
BIN
public/assets/hermesworld/video/hero-720p.mp4
Normal file
BIN
public/assets/hermesworld/video/hero-poster.jpg
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
public/assets/hermesworld/video/world-demo-720p.mp4
Normal file
BIN
public/assets/hermesworld/video/world-demo-poster.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/assets/hermesworld/zones/cityscape.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/assets/hermesworld/zones/hero.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
public/assets/hermesworld/zones/zone-1.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
public/assets/hermesworld/zones/zone-2.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
public/assets/hermesworld/zones/zone-3.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
public/assets/hermesworld/zones/zone-4.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
public/assets/hermesworld/zones/zone-5.jpg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
public/assets/hermesworld/zones/zone-6.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
@@ -225,7 +225,7 @@ export function PlaygroundDialog({
|
||||
{/* Speech body / chat history */}
|
||||
{!showChat ? (
|
||||
<div className="px-4 py-4">
|
||||
<SpeechBubble variant="npc" tail="left" accent={npc.color} name={npc.name}>
|
||||
<SpeechBubble variant="npc" tail="left" accent={npc.color} name={npc.name} portraitSrc={npc.portraitSrc} portraitAlt={npc.portraitAlt}>
|
||||
{reply ?? npc.opening}
|
||||
</SpeechBubble>
|
||||
</div>
|
||||
@@ -236,7 +236,7 @@ export function PlaygroundDialog({
|
||||
>
|
||||
{/* Show opening line as an initial assistant turn for context */}
|
||||
<div className="mb-3">
|
||||
<SpeechBubble variant="npc" tail="left" accent={npc.color} name={npc.name} compact>
|
||||
<SpeechBubble variant="npc" tail="left" accent={npc.color} name={npc.name} portraitSrc={npc.portraitSrc} portraitAlt={npc.portraitAlt} compact>
|
||||
{reply ?? npc.opening}
|
||||
</SpeechBubble>
|
||||
</div>
|
||||
@@ -249,7 +249,7 @@ export function PlaygroundDialog({
|
||||
</SpeechBubble>
|
||||
</div>
|
||||
) : (
|
||||
<SpeechBubble variant={t.fallback ? 'system' : 'npc'} tail="left" accent={npc.color} name={npc.name} compact>
|
||||
<SpeechBubble variant={t.fallback ? 'system' : 'npc'} tail="left" accent={npc.color} name={npc.name} portraitSrc={npc.portraitSrc} portraitAlt={npc.portraitAlt} compact>
|
||||
{t.content}
|
||||
{t.fallback && (
|
||||
<span className="ml-2 rounded bg-amber-800/15 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-[0.18em] text-amber-900/75">
|
||||
|
||||
@@ -162,6 +162,14 @@ const WORLDS_3D: Record<PlaygroundWorldId, WorldDef> = {
|
||||
},
|
||||
}
|
||||
|
||||
const ZONE_FALLBACK_BACKGROUNDS: Partial<Record<PlaygroundWorldId, string>> = {
|
||||
training: '/assets/hermesworld/zones/zone-1.jpg',
|
||||
forge: '/assets/hermesworld/zones/zone-2.jpg',
|
||||
grove: '/assets/hermesworld/zones/zone-3.jpg',
|
||||
oracle: '/assets/hermesworld/zones/zone-4.jpg',
|
||||
arena: '/assets/hermesworld/zones/zone-5.jpg',
|
||||
}
|
||||
|
||||
/* ── Ground ── */
|
||||
/** Procedural stone-tile plaza overlay (canvas texture). Used as a circular */
|
||||
/** floor under the central HermesStatue in Training Grounds + Agora. */
|
||||
@@ -3102,6 +3110,7 @@ export function PlaygroundWorld3D({
|
||||
const playerYaw = useRef(0)
|
||||
const [settings] = useHermesWorldSettings()
|
||||
const photosensitiveMode = settings.accessibility.photosensitiveMode
|
||||
const fallbackBackground = ZONE_FALLBACK_BACKGROUNDS[worldId]
|
||||
const positionForMp = useRef<{ x: number; y: number; z: number } | null>({ x: 0, y: 0, z: 6 })
|
||||
// Sync simple position object for multiplayer hook (it doesn't use THREE).
|
||||
// Also expose to window so the HUD objective arrow can compute heading.
|
||||
@@ -3159,9 +3168,22 @@ export function PlaygroundWorld3D({
|
||||
inset: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: '#0b1720',
|
||||
background: fallbackBackground
|
||||
? `linear-gradient(180deg, rgba(5,11,18,.22), rgba(5,11,18,.6)), url(${fallbackBackground}) center / cover no-repeat, #0b1720`
|
||||
: '#0b1720',
|
||||
}}
|
||||
>
|
||||
{fallbackBackground ? (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
background: 'radial-gradient(circle at 50% 45%, transparent 0%, rgba(5,11,18,.34) 68%, rgba(5,11,18,.78) 100%)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<style>{`
|
||||
@keyframes hermes-target-arrow {
|
||||
0%, 100% { transform: translateY(0); opacity: 0.78; }
|
||||
|
||||
@@ -14,6 +14,8 @@ type SpeechBubbleProps = {
|
||||
tail?: SpeechBubbleTail
|
||||
accent?: string
|
||||
name?: string
|
||||
portraitSrc?: string
|
||||
portraitAlt?: string
|
||||
className?: string
|
||||
style?: CSSProperties
|
||||
compact?: boolean
|
||||
@@ -82,6 +84,8 @@ export function SpeechBubble({
|
||||
tail = 'bottom',
|
||||
accent,
|
||||
name,
|
||||
portraitSrc,
|
||||
portraitAlt,
|
||||
className = '',
|
||||
style,
|
||||
compact = false,
|
||||
@@ -113,21 +117,46 @@ export function SpeechBubble({
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{name ? (
|
||||
<div
|
||||
style={{
|
||||
color: accent || tokens.label,
|
||||
fontSize: compact ? 9 : 10,
|
||||
fontWeight: 900,
|
||||
letterSpacing: '.16em',
|
||||
textTransform: 'uppercase',
|
||||
marginBottom: compact ? 2 : 5,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<div style={{ display: portraitSrc ? 'flex' : 'block', gap: compact ? 8 : 12, alignItems: 'flex-start' }}>
|
||||
{portraitSrc ? (
|
||||
<img
|
||||
src={portraitSrc}
|
||||
alt={portraitAlt || name || 'NPC portrait'}
|
||||
loading="lazy"
|
||||
style={{
|
||||
width: compact ? 42 : 64,
|
||||
height: compact ? 42 : 64,
|
||||
flex: '0 0 auto',
|
||||
borderRadius: compact ? 12 : 16,
|
||||
border: `2px solid ${border}`,
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
background: 'rgba(0,0,0,.18)',
|
||||
boxShadow: `0 0 14px ${tokens.glow}`,
|
||||
}}
|
||||
onError={(event) => {
|
||||
;(event.currentTarget as HTMLImageElement).style.display = 'none'
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<div>
|
||||
{name ? (
|
||||
<div
|
||||
style={{
|
||||
color: accent || tokens.label,
|
||||
fontSize: compact ? 9 : 10,
|
||||
fontWeight: 900,
|
||||
letterSpacing: '.16em',
|
||||
textTransform: 'uppercase',
|
||||
marginBottom: compact ? 2 : 5,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
) : null}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -34,6 +34,9 @@ export type NpcDialogTree = {
|
||||
name: string
|
||||
title: string
|
||||
color: string
|
||||
/** Optional runtime portrait used by the shared SpeechBubble component. */
|
||||
portraitSrc?: string
|
||||
portraitAlt?: string
|
||||
/** Opening line shown when dialog starts */
|
||||
opening: string
|
||||
/** Lore line shown if player keeps talking */
|
||||
@@ -321,10 +324,12 @@ export const NPC_DIALOG: Record<string, NpcDialogTree> = {
|
||||
shopkeeper: {
|
||||
id: 'shopkeeper',
|
||||
name: 'Dorian',
|
||||
title: 'Quartermaster of the Market',
|
||||
color: '#38bdf8',
|
||||
title: 'Quartermaster of the Starter Kit',
|
||||
color: '#fbbf24',
|
||||
portraitSrc: '/assets/hermesworld/v2/wave-a-source/A03-A08-rerolls.png',
|
||||
portraitAlt: 'Midjourney quartermaster portrait reference for Dorian',
|
||||
opening:
|
||||
'Welcome to the Agora market. Every real MMO hub needs a place where players understand value. Your starter kit teaches inventory, gear, and progression in the same motion.',
|
||||
'You look under-equipped. I am Dorian, quartermaster of the Training Grounds. Builders do better with a blade, a cloak, and a sigil.',
|
||||
lore: [
|
||||
'The market will eventually trade cosmetics, generated relics, guild banners, and agent-made artifacts. For now, your starter kit teaches inventory, gear, progression, and rewards.',
|
||||
'A good product hub has economy, even before money. Reputation, tokens, badges, access, trust — those are currencies too.',
|
||||
|
||||