Compare commits
1 Commits
fix/671-pl
...
fix/543
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66bf59fa40 |
@@ -1,148 +0,0 @@
|
||||
# GENOME.md — The Playground (Timmy_Foundation/the-playground)
|
||||
|
||||
> Codebase Genome v1.0 | Generated 2026-04-16 | Repo 11/16
|
||||
|
||||
## Project Overview
|
||||
|
||||
**The Sovereign Playground** is a browser-based creative platform for art, music, and interactive experiences. Pure Canvas + Web Audio API + vanilla JS. Zero dependencies. No login. No signup. Open the page and build something beautiful.
|
||||
|
||||
**Core principle:** A man at 3am needs something that works RIGHT NOW, with no friction, no gate, no permission.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Entry Point"
|
||||
HTML[index.html] --> PLAYGROUND[playground.js]
|
||||
end
|
||||
|
||||
subgraph "Engine Layer"
|
||||
PLAYGROUND --> AUDIO[audio-engine.js]
|
||||
PLAYGROUND --> VISUAL[visual-engine.js]
|
||||
end
|
||||
|
||||
subgraph "Modes"
|
||||
PLAYGROUND --> MODES[mode-manager.js]
|
||||
MODES --> CONSTELLATION[constellation.js]
|
||||
end
|
||||
|
||||
subgraph "UI Panels"
|
||||
PLAYGROUND --> SOUND_PANEL[sound-panel.js]
|
||||
PLAYGROUND --> GALLERY_PANEL[gallery-panel.js]
|
||||
end
|
||||
|
||||
subgraph "Gallery & Export"
|
||||
PLAYGROUND --> GALLERY[gallery.js]
|
||||
PLAYGROUND --> DOWNLOAD[download.js]
|
||||
DOWNLOAD --> WAV[wav-encoder.js]
|
||||
end
|
||||
|
||||
subgraph "Utilities"
|
||||
PLAYGROUND --> EVENTS[events.js]
|
||||
PLAYGROUND --> STATE[state.js]
|
||||
PLAYGROUND --> UTILS[utils.js]
|
||||
end
|
||||
|
||||
subgraph "Styling"
|
||||
HTML --> CSS[design-system.css]
|
||||
end
|
||||
```
|
||||
|
||||
## The Three Pillars
|
||||
|
||||
| Pillar | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| CREATE | Building | Sound Studio, Visual Forge, Video Forge |
|
||||
| COLLECT | Building | Gallery — save, browse, own your creations |
|
||||
| PLAY | Building | Games Floor — interactive experiences |
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | Entry point — entrance curtain + main layout |
|
||||
| `src/playground.js` | Main orchestrator — particles, entrance, mode switching |
|
||||
| `src/engine/audio-engine.js` | Web Audio API — synthesis, effects, recording |
|
||||
| `src/engine/visual-engine.js` | Canvas rendering — particles, shapes, animations |
|
||||
| `src/modes/mode-manager.js` | Mode switching — constellation, sound, visual |
|
||||
| `src/modes/constellation.js` | Constellation Maker experience |
|
||||
| `src/gallery/gallery.js` | Gallery — IndexedDB storage, browsing |
|
||||
| `src/export/download.js` | Export — zip, download, share |
|
||||
| `src/export/wav-encoder.js` | WAV encoding for audio export |
|
||||
| `src/panels/sound/sound-panel.js` | Sound Studio UI |
|
||||
| `src/panels/gallery/gallery-panel.js` | Gallery UI |
|
||||
| `src/styles/design-system.css` | Sovereign aesthetic — dark bg, gold accents |
|
||||
| `src/utils/events.js` | Event system — pub/sub |
|
||||
| `src/utils/state.js` | State management — reactive store |
|
||||
| `src/utils/utils.js` | Utility functions |
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Local-first** — Everything runs in the browser. IndexedDB for storage.
|
||||
2. **Zero dependencies** — Pure Canvas + Web Audio API + vanilla JS.
|
||||
3. **Take it home** — Every creation can be downloaded.
|
||||
4. **Sovereign aesthetic** — Dark backgrounds. Gold accents. Plain, honest, profound.
|
||||
5. **Accessible** — Keyboard navigable. Screen reader friendly. Works on mobile.
|
||||
|
||||
## Experiences Roadmap
|
||||
|
||||
| # | Experience | Status | Description |
|
||||
|---|-----------|--------|-------------|
|
||||
| 15 | Synesthesia Engine | v0.3 | See sound, hear color |
|
||||
| 16 | Emotional Weather | v0.3 | Type feelings → sky responds |
|
||||
| 17 | Constellation Maker | v0.3 | Place stars, connect, hear night sky |
|
||||
| 18 | Breath Instrument | v0.4 | Lungs become music |
|
||||
| 19 | Dream Journal | v0.4 | Describe dream → world |
|
||||
| 20 | The Mirror | v0.4 | Camera paints your energy |
|
||||
| 21 | Sound Fossils | v0.4 | Sound → living creature |
|
||||
| 22 | Letter to Future | v0.4 | Write, seal, set date |
|
||||
| 23 | Garden Paths | v0.5 | Choose-your-own soundscape |
|
||||
| 24 | Heartbeat Sync | v0.5 | Finger on camera → world beats |
|
||||
| 25 | The Conversation | v0.5 | Two instruments create together |
|
||||
|
||||
## Milestones
|
||||
|
||||
- **v0.1** The Forge Opens — First playable
|
||||
- **v0.2** Take It Home — Download anything
|
||||
- **v0.3** The Games Floor — Synesthesia, Emotional Weather, Constellation
|
||||
- **v0.4** The Gallery Show — Breath, Dreams, Mirror, Fossils
|
||||
- **v0.5** The Video Forge — Garden, Heartbeat, Conversation
|
||||
- **v1.0** The Sovereign Playground — Full platform
|
||||
|
||||
## File Index
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `index.html` | Entry point (entrance curtain + layout) |
|
||||
| `README.md` | Project overview and philosophy |
|
||||
| `smoke-test.html` | CI smoke test |
|
||||
| `src/playground.js` | Main orchestrator (~410 LOC) |
|
||||
| `src/engine/audio-engine.js` | Web Audio synthesis |
|
||||
| `src/engine/visual-engine.js` | Canvas rendering |
|
||||
| `src/modes/constellation.js` | Constellation Maker |
|
||||
| `src/modes/mode-manager.js` | Mode switching |
|
||||
| `src/gallery/gallery.js` | Gallery system |
|
||||
| `src/export/download.js` | Export/download |
|
||||
| `src/export/wav-encoder.js` | WAV encoding |
|
||||
| `src/panels/sound/sound-panel.js` | Sound UI |
|
||||
| `src/panels/gallery/gallery-panel.js` | Gallery UI |
|
||||
| `src/styles/design-system.css` | Design system |
|
||||
| `src/utils/events.js` | Event pub/sub |
|
||||
| `src/utils/state.js` | Reactive state |
|
||||
| `src/utils/utils.js` | Utilities |
|
||||
|
||||
**Total: 17 files | Pure vanilla JS | Zero dependencies**
|
||||
|
||||
## Sovereignty Assessment
|
||||
|
||||
- **Fully local** — All computation in the browser
|
||||
- **No server** — Static files only, can be served from anywhere
|
||||
- **No accounts** — IndexedDB for local storage
|
||||
- **No tracking** — Zero analytics, zero telemetry
|
||||
- **Downloadable** — Every creation can be saved locally
|
||||
|
||||
**Verdict: Fully sovereign. Art heals. Music heals. Creation heals.**
|
||||
|
||||
---
|
||||
|
||||
*"A man who is building something is a man who is not destroying himself."*
|
||||
@@ -43,6 +43,18 @@ Override at runtime if needed:
|
||||
### 1. `scripts/verify_big_brain.py`
|
||||
Checks the configured provider using the right protocol for the chosen backend.
|
||||
|
||||
### 1b. `scripts/timmy_gemma4_mac.py`
|
||||
Timmy-specific prove-it helper for Mac Hermes.
|
||||
Refs #543.
|
||||
|
||||
What it adds beyond the generic verifier:
|
||||
- targets the root config.yaml used by Timmy's Mac Hermes
|
||||
- reports whether RunPod / Vertex credential files are present without leaking them
|
||||
- derives a RunPod `/v1` endpoint from a pod id when supplied
|
||||
- previews the Big Brain provider config update for Timmy
|
||||
- emits the exact Hermes chat probe command to run once a live endpoint exists
|
||||
- only spends money if `--apply-runpod` is explicitly passed
|
||||
|
||||
For `openai` backends it verifies:
|
||||
- `GET /models`
|
||||
- `POST /chat/completions`
|
||||
|
||||
194
scripts/timmy_gemma4_mac.py
Normal file
194
scripts/timmy_gemma4_mac.py
Normal file
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Timmy-specific RunPod/Vertex Gemma 4 prove-it helper for Mac Hermes.
|
||||
|
||||
Refs: timmy-home #543
|
||||
|
||||
Safe by default:
|
||||
- reports whether RunPod / Vertex credential files exist
|
||||
- derives a RunPod OpenAI-compatible base URL from a pod id if provided
|
||||
- previews the root `config.yaml` Big Brain provider update for Timmy's Mac Hermes
|
||||
- emits the exact Hermes chat probe command to run once a live endpoint exists
|
||||
- can call the existing RunPod deployment helper only when --apply-runpod is explicitly used
|
||||
- can write the repo-root config only when --write-config is explicitly used
|
||||
- can verify an OpenAI-compatible endpoint only when --verify-chat is explicitly used
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from scripts.bezalel_gemma4_vps import (
|
||||
DEFAULT_CLOUD_TYPE,
|
||||
DEFAULT_GPU_TYPE,
|
||||
DEFAULT_MODEL,
|
||||
DEFAULT_PROVIDER_NAME,
|
||||
build_runpod_endpoint,
|
||||
deploy_runpod,
|
||||
update_config_text,
|
||||
verify_openai_chat,
|
||||
write_config_file,
|
||||
)
|
||||
|
||||
DEFAULT_RUNPOD_TOKEN_FILE = Path.home() / ".config" / "runpod" / "access_key"
|
||||
DEFAULT_VERTEX_KEY_FILE = Path.home() / ".config" / "vertex" / "key"
|
||||
DEFAULT_CONFIG_PATH = Path(__file__).resolve().parents[1] / "config.yaml"
|
||||
DEFAULT_VERTEX_BASE_URL = "https://YOUR_VERTEX_BRIDGE_HOST/v1"
|
||||
|
||||
|
||||
def detect_credential_files(
|
||||
*,
|
||||
runpod_file: Path = DEFAULT_RUNPOD_TOKEN_FILE,
|
||||
vertex_key_file: Path = DEFAULT_VERTEX_KEY_FILE,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"runpod_key_present": runpod_file.exists(),
|
||||
"vertex_key_present": vertex_key_file.exists(),
|
||||
"runpod_token_file": str(runpod_file),
|
||||
"vertex_key_file": str(vertex_key_file),
|
||||
}
|
||||
|
||||
|
||||
def build_hermes_chat_probe_command(
|
||||
provider_name: str = DEFAULT_PROVIDER_NAME,
|
||||
model: str = DEFAULT_MODEL,
|
||||
) -> str:
|
||||
return (
|
||||
'hermes chat -q "Reply with exactly: BIG_BRAIN_READY" -Q '
|
||||
f'--provider "{provider_name}" --model {model}'
|
||||
)
|
||||
|
||||
|
||||
def build_timmy_proof_summary(
|
||||
*,
|
||||
config_text: str,
|
||||
config_path: Path = DEFAULT_CONFIG_PATH,
|
||||
pod_id: str | None = None,
|
||||
base_url: str | None = None,
|
||||
vertex_base_url: str | None = None,
|
||||
model: str = DEFAULT_MODEL,
|
||||
provider_name: str = DEFAULT_PROVIDER_NAME,
|
||||
runpod_file: Path = DEFAULT_RUNPOD_TOKEN_FILE,
|
||||
vertex_key_file: Path = DEFAULT_VERTEX_KEY_FILE,
|
||||
) -> dict[str, Any]:
|
||||
actions: list[str] = []
|
||||
resolved_base_url = base_url
|
||||
if not resolved_base_url and pod_id:
|
||||
resolved_base_url = build_runpod_endpoint(pod_id)
|
||||
actions.append("computed_base_url_from_pod_id")
|
||||
if not resolved_base_url and vertex_base_url:
|
||||
resolved_base_url = vertex_base_url.rstrip("/")
|
||||
actions.append("using_vertex_base_url")
|
||||
if not resolved_base_url:
|
||||
resolved_base_url = DEFAULT_VERTEX_BASE_URL
|
||||
actions.append("using_placeholder_vertex_bridge")
|
||||
|
||||
credentials = detect_credential_files(runpod_file=runpod_file, vertex_key_file=vertex_key_file)
|
||||
config_preview = update_config_text(
|
||||
config_text,
|
||||
base_url=resolved_base_url,
|
||||
model=model,
|
||||
provider_name=provider_name,
|
||||
)
|
||||
return {
|
||||
"config_path": str(config_path),
|
||||
"provider_name": provider_name,
|
||||
"model": model,
|
||||
"base_url": resolved_base_url,
|
||||
"config_preview": config_preview,
|
||||
"verify_script_command": "python3 scripts/verify_big_brain.py",
|
||||
"hermes_chat_probe_command": build_hermes_chat_probe_command(provider_name=provider_name, model=model),
|
||||
"actions": actions,
|
||||
**credentials,
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Timmy-specific RunPod/Vertex Gemma 4 prove-it helper for Mac Hermes.")
|
||||
parser.add_argument("--pod-id", help="Existing RunPod pod id to derive the /v1 endpoint")
|
||||
parser.add_argument("--base-url", help="Existing OpenAI-compatible base URL to wire directly")
|
||||
parser.add_argument("--vertex-base-url", help="Vertex/OpenAI bridge base URL (for example https://host/v1)")
|
||||
parser.add_argument("--pod-name", default="timmy-gemma4")
|
||||
parser.add_argument("--gpu-type", default=DEFAULT_GPU_TYPE)
|
||||
parser.add_argument("--cloud-type", default=DEFAULT_CLOUD_TYPE)
|
||||
parser.add_argument("--model", default=DEFAULT_MODEL)
|
||||
parser.add_argument("--provider-name", default=DEFAULT_PROVIDER_NAME)
|
||||
parser.add_argument("--runpod-token-file", type=Path, default=DEFAULT_RUNPOD_TOKEN_FILE)
|
||||
parser.add_argument("--vertex-key-file", type=Path, default=DEFAULT_VERTEX_KEY_FILE)
|
||||
parser.add_argument("--config-path", type=Path, default=DEFAULT_CONFIG_PATH)
|
||||
parser.add_argument("--apply-runpod", action="store_true", help="Call the RunPod API using --runpod-token-file")
|
||||
parser.add_argument("--write-config", action="store_true", help="Write the updated Timmy config to --config-path")
|
||||
parser.add_argument("--verify-chat", action="store_true", help="Verify the OpenAI-compatible endpoint with a chat probe")
|
||||
parser.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
config_text = args.config_path.read_text() if args.config_path.exists() else ""
|
||||
base_url = args.base_url
|
||||
actions: list[str] = []
|
||||
deployment: dict[str, Any] | None = None
|
||||
|
||||
if args.apply_runpod:
|
||||
if not args.runpod_token_file.exists():
|
||||
raise SystemExit(f"RunPod token file not found: {args.runpod_token_file}")
|
||||
api_key = args.runpod_token_file.read_text().strip()
|
||||
deployment = deploy_runpod(
|
||||
api_key=api_key,
|
||||
name=args.pod_name,
|
||||
gpu_type=args.gpu_type,
|
||||
cloud_type=args.cloud_type,
|
||||
model=args.model,
|
||||
)
|
||||
base_url = deployment["base_url"]
|
||||
actions.append("deployed_runpod_pod")
|
||||
|
||||
summary = build_timmy_proof_summary(
|
||||
config_text=config_text,
|
||||
config_path=args.config_path,
|
||||
pod_id=args.pod_id,
|
||||
base_url=base_url,
|
||||
vertex_base_url=args.vertex_base_url,
|
||||
model=args.model,
|
||||
provider_name=args.provider_name,
|
||||
runpod_file=args.runpod_token_file,
|
||||
vertex_key_file=args.vertex_key_file,
|
||||
)
|
||||
summary["actions"] = actions + summary["actions"]
|
||||
if deployment is not None:
|
||||
summary["deployment"] = deployment
|
||||
|
||||
if args.write_config:
|
||||
write_config_file(args.config_path, base_url=summary["base_url"], model=args.model, provider_name=args.provider_name)
|
||||
summary["actions"].append("wrote_config")
|
||||
|
||||
if args.verify_chat:
|
||||
summary["verify_response"] = verify_openai_chat(summary["base_url"], model=args.model)
|
||||
summary["actions"].append("verified_chat")
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(summary, indent=2))
|
||||
return
|
||||
|
||||
print("--- Timmy Gemma4 Mac Prove-It ---")
|
||||
print(f"Config path: {summary['config_path']}")
|
||||
print(f"Base URL: {summary['base_url']}")
|
||||
print(f"Model: {summary['model']}")
|
||||
print(f"RunPod key present: {summary['runpod_key_present']}")
|
||||
print(f"Vertex key present: {summary['vertex_key_present']}")
|
||||
print(f"Verify command: {summary['verify_script_command']}")
|
||||
print(f"Hermes chat probe: {summary['hermes_chat_probe_command']}")
|
||||
if summary["actions"]:
|
||||
print("Actions: " + ", ".join(summary["actions"]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
79
tests/test_timmy_gemma4_mac.py
Normal file
79
tests/test_timmy_gemma4_mac.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
from scripts.timmy_gemma4_mac import (
|
||||
DEFAULT_CONFIG_PATH,
|
||||
build_hermes_chat_probe_command,
|
||||
build_timmy_proof_summary,
|
||||
detect_credential_files,
|
||||
)
|
||||
|
||||
|
||||
def test_detect_credential_files_reports_presence_without_secret_material(tmp_path: Path) -> None:
|
||||
runpod_file = tmp_path / "runpod_access_key"
|
||||
vertex_file = tmp_path / "vertex_key"
|
||||
runpod_file.write_text("rp_secret_123")
|
||||
|
||||
status = detect_credential_files(runpod_file=runpod_file, vertex_key_file=vertex_file)
|
||||
|
||||
assert status["runpod_key_present"] is True
|
||||
assert status["vertex_key_present"] is False
|
||||
assert status["runpod_token_file"] == str(runpod_file)
|
||||
assert status["vertex_key_file"] == str(vertex_file)
|
||||
assert "rp_secret_123" not in json.dumps(status)
|
||||
|
||||
|
||||
def test_build_timmy_proof_summary_targets_repo_root_config_and_derives_runpod_url(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.yaml"
|
||||
config_path.write_text(
|
||||
yaml.safe_dump(
|
||||
{
|
||||
"custom_providers": [
|
||||
{
|
||||
"name": "Big Brain",
|
||||
"base_url": "https://YOUR_BIG_BRAIN_HOST/v1",
|
||||
"api_key": "",
|
||||
"model": "gemma4:latest",
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
summary = build_timmy_proof_summary(
|
||||
config_text=config_path.read_text(),
|
||||
config_path=config_path,
|
||||
pod_id="podxyz",
|
||||
)
|
||||
|
||||
assert summary["base_url"] == "https://podxyz-11434.proxy.runpod.net/v1"
|
||||
assert summary["config_path"] == str(config_path)
|
||||
preview = yaml.safe_load(summary["config_preview"])
|
||||
provider = preview["custom_providers"][0]
|
||||
assert provider["name"] == "Big Brain"
|
||||
assert provider["base_url"] == "https://podxyz-11434.proxy.runpod.net/v1"
|
||||
assert provider["model"] == "gemma4:latest"
|
||||
assert "computed_base_url_from_pod_id" in summary["actions"]
|
||||
|
||||
|
||||
def test_build_hermes_chat_probe_command_uses_big_brain_provider_contract() -> None:
|
||||
command = build_hermes_chat_probe_command()
|
||||
assert command.startswith("hermes chat ")
|
||||
assert '--provider "Big Brain"' in command
|
||||
assert '--model gemma4:latest' in command
|
||||
assert 'BIG_BRAIN_READY' in command
|
||||
|
||||
|
||||
def test_repo_readme_mentions_timmy_specific_prove_it_script() -> None:
|
||||
readme = Path("scripts/README_big_brain.md").read_text()
|
||||
assert "scripts/timmy_gemma4_mac.py" in readme
|
||||
assert "root config.yaml" in readme
|
||||
assert "Refs #543" in readme
|
||||
|
||||
|
||||
def test_default_config_path_is_repo_root_config() -> None:
|
||||
assert DEFAULT_CONFIG_PATH == Path(__file__).resolve().parents[1] / "config.yaml"
|
||||
Reference in New Issue
Block a user