Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdacbf5e78 | |||
| 60c3838c2b | |||
| 9251ffc4b5 |
83
bin/validate_config.py
Normal file
83
bin/validate_config.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Config Validator -- pre-deploy YAML validation for timmy-config sidecar.
|
||||||
|
|
||||||
|
Validates YAML syntax, required keys (model.default, model.provider,
|
||||||
|
toolsets), and provider names before deploy.sh writes to ~/.hermes/.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 bin/validate_config.py [path/to/config.yaml]
|
||||||
|
python3 bin/validate_config.py --strict (fail on warnings too)
|
||||||
|
"""
|
||||||
|
import json, os, sys, yaml
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REQUIRED = {
|
||||||
|
"model": {"type": dict, "keys": {"default": str, "provider": str}},
|
||||||
|
"toolsets": {"type": list},
|
||||||
|
}
|
||||||
|
ALLOWED_PROVIDERS = [
|
||||||
|
"anthropic", "openai", "nous", "ollama", "openrouter", "openai-codex"
|
||||||
|
]
|
||||||
|
|
||||||
|
def validate(path):
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
with open(path) as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
except Exception as e:
|
||||||
|
return [f"YAML parse error: {e}"]
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return [f"Expected mapping, got {type(data).__name__}"]
|
||||||
|
|
||||||
|
for key, spec in REQUIRED.items():
|
||||||
|
if key not in data:
|
||||||
|
errors.append(f"Required key missing: {key}")
|
||||||
|
continue
|
||||||
|
if spec["type"] == dict and not isinstance(data[key], dict):
|
||||||
|
errors.append(f"{key}: expected dict")
|
||||||
|
continue
|
||||||
|
if spec["type"] == list and not isinstance(data[key], list):
|
||||||
|
errors.append(f"{key}: expected list")
|
||||||
|
continue
|
||||||
|
if "keys" in spec:
|
||||||
|
for sub, sub_type in spec["keys"].items():
|
||||||
|
if sub not in data[key]:
|
||||||
|
errors.append(f"{key}.{sub}: required")
|
||||||
|
elif not isinstance(data[key][sub], sub_type):
|
||||||
|
errors.append(f"{key}.{sub}: expected {sub_type.__name__}")
|
||||||
|
|
||||||
|
provider = data.get("model", {}).get("provider")
|
||||||
|
if provider and provider not in ALLOWED_PROVIDERS:
|
||||||
|
errors.append(f"model.provider: unknown provider '{provider}'")
|
||||||
|
|
||||||
|
# Check JSON files
|
||||||
|
for jf in ["channel_directory.json"]:
|
||||||
|
jp = Path(path).parent / jf
|
||||||
|
if jp.exists():
|
||||||
|
try:
|
||||||
|
json.loads(jp.read_text())
|
||||||
|
except Exception as e:
|
||||||
|
errors.append(f"{jf}: invalid JSON: {e}")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
def main():
|
||||||
|
strict = "--strict" in sys.argv
|
||||||
|
args = [a for a in sys.argv[1:] if not a.startswith("--")]
|
||||||
|
path = args[0] if args else str(Path(__file__).parent.parent / "config.yaml")
|
||||||
|
|
||||||
|
if not os.path.exists(path):
|
||||||
|
print(f"ERROR: {path} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
errs = validate(path)
|
||||||
|
if errs:
|
||||||
|
for e in errs:
|
||||||
|
print(f"ERROR: {e}")
|
||||||
|
print(f"Validation FAILED: {len(errs)} issue(s)")
|
||||||
|
sys.exit(1)
|
||||||
|
print(f"OK: {path} is valid")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
207
scripts/validate-sidecar-config.py
Normal file
207
scripts/validate-sidecar-config.py
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
validate-sidecar-config.py — Pre-deploy validation for timmy-config sidecar.
|
||||||
|
|
||||||
|
Validates YAML syntax, required keys, value types before deploy.
|
||||||
|
Rejects bad config with clear errors.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 scripts/validate-sidecar-config.py ~/.timmy/config.yaml
|
||||||
|
python3 scripts/validate-sidecar-config.py --all # Validate all config files
|
||||||
|
python3 scripts/validate-sidecar-config.py --schema # Print expected schema
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
HAS_YAML = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_YAML = False
|
||||||
|
|
||||||
|
# Expected schema: field -> type
|
||||||
|
REQUIRED_SCHEMA = {
|
||||||
|
"model": str,
|
||||||
|
"provider": str,
|
||||||
|
}
|
||||||
|
|
||||||
|
OPTIONAL_SCHEMA = {
|
||||||
|
"api_base": str,
|
||||||
|
"max_tokens": int,
|
||||||
|
"temperature": (int, float),
|
||||||
|
"system_prompt": str,
|
||||||
|
"tools": list,
|
||||||
|
"memory_enabled": bool,
|
||||||
|
"session_timeout": int,
|
||||||
|
"log_level": str,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_DIRS = [
|
||||||
|
Path.home() / ".timmy",
|
||||||
|
Path.home() / ".hermes",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def validate_yaml_syntax(filepath: Path) -> list[str]:
|
||||||
|
"""Validate YAML can be parsed."""
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
content = filepath.read_text(errors="ignore")
|
||||||
|
if HAS_YAML:
|
||||||
|
yaml.safe_load(content)
|
||||||
|
else:
|
||||||
|
# Fallback: check for basic JSON-in-YAML
|
||||||
|
json.loads(content)
|
||||||
|
except (yaml.YAMLError if HAS_YAML else Exception, json.JSONDecodeError) as e:
|
||||||
|
errors.append(f"YAML syntax error: {e}")
|
||||||
|
except OSError as e:
|
||||||
|
errors.append(f"Cannot read file: {e}")
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_schema(filepath: Path) -> list[str]:
|
||||||
|
"""Validate config against expected schema."""
|
||||||
|
errors = []
|
||||||
|
try:
|
||||||
|
content = filepath.read_text(errors="ignore")
|
||||||
|
if HAS_YAML:
|
||||||
|
config = yaml.safe_load(content) or {}
|
||||||
|
else:
|
||||||
|
config = json.loads(content)
|
||||||
|
except Exception as e:
|
||||||
|
return [f"Cannot parse: {e}"]
|
||||||
|
|
||||||
|
if not isinstance(config, dict):
|
||||||
|
return ["Config must be a YAML/JSON object (dict)"]
|
||||||
|
|
||||||
|
# Check required keys
|
||||||
|
for key, expected_type in REQUIRED_SCHEMA.items():
|
||||||
|
if key not in config:
|
||||||
|
errors.append(f"Missing required key: '{key}' (expected {expected_type.__name__})")
|
||||||
|
elif not isinstance(config[key], expected_type):
|
||||||
|
errors.append(f"Wrong type for '{key}': expected {expected_type.__name__}, got {type(config[key]).__name__}")
|
||||||
|
|
||||||
|
# Check optional keys types
|
||||||
|
for key, expected_type in OPTIONAL_SCHEMA.items():
|
||||||
|
if key in config:
|
||||||
|
if isinstance(expected_type, tuple):
|
||||||
|
if not isinstance(config[key], expected_type):
|
||||||
|
type_names = " or ".join(t.__name__ for t in expected_type)
|
||||||
|
errors.append(f"Wrong type for '{key}': expected {type_names}, got {type(config[key]).__name__}")
|
||||||
|
else:
|
||||||
|
if not isinstance(config[key], expected_type):
|
||||||
|
errors.append(f"Wrong type for '{key}': expected {expected_type.__name__}, got {type(config[key]).__name__}")
|
||||||
|
|
||||||
|
# Check for common mistakes
|
||||||
|
if "model" in config and isinstance(config["model"], str):
|
||||||
|
if config["model"].startswith("http"):
|
||||||
|
errors.append("'model' looks like a URL — did you mean 'api_base'?")
|
||||||
|
|
||||||
|
if "api_base" in config and isinstance(config["api_base"], str):
|
||||||
|
if not config["api_base"].startswith("http"):
|
||||||
|
errors.append("'api_base' should start with http:// or https://")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_file(filepath: Path) -> tuple[bool, list[str]]:
|
||||||
|
"""Full validation of a config file. Returns (valid, errors)."""
|
||||||
|
errors = []
|
||||||
|
errors.extend(validate_yaml_syntax(filepath))
|
||||||
|
if not errors:
|
||||||
|
errors.extend(validate_schema(filepath))
|
||||||
|
return len(errors) == 0, errors
|
||||||
|
|
||||||
|
|
||||||
|
def find_config_files() -> list[Path]:
|
||||||
|
"""Find config files in standard locations."""
|
||||||
|
configs = []
|
||||||
|
for d in CONFIG_DIRS:
|
||||||
|
if not d.exists():
|
||||||
|
continue
|
||||||
|
for f in d.rglob("*.yaml"):
|
||||||
|
if f.name in ("config.yaml", "settings.yaml", "env.yaml", "config.yml"):
|
||||||
|
configs.append(f)
|
||||||
|
for f in d.rglob("*.yml"):
|
||||||
|
if "config" in f.name.lower():
|
||||||
|
configs.append(f)
|
||||||
|
for f in d.rglob("*.json"):
|
||||||
|
if f.name in ("config.json", "settings.json"):
|
||||||
|
configs.append(f)
|
||||||
|
return sorted(set(configs))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_validate(filepath: str) -> bool:
|
||||||
|
path = Path(filepath)
|
||||||
|
if not path.exists():
|
||||||
|
print(f"ERROR: {path} not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
valid, errors = validate_file(path)
|
||||||
|
if valid:
|
||||||
|
print(f"OK: {path}")
|
||||||
|
else:
|
||||||
|
print(f"FAIL: {path}")
|
||||||
|
for e in errors:
|
||||||
|
print(f" - {e}")
|
||||||
|
return valid
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_validate_all() -> bool:
|
||||||
|
configs = find_config_files()
|
||||||
|
if not configs:
|
||||||
|
print("No config files found in standard locations.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
all_valid = True
|
||||||
|
for config in configs:
|
||||||
|
valid, errors = validate_file(config)
|
||||||
|
if valid:
|
||||||
|
print(f"OK: {config}")
|
||||||
|
else:
|
||||||
|
all_valid = False
|
||||||
|
print(f"FAIL: {config}")
|
||||||
|
for e in errors:
|
||||||
|
print(f" - {e}")
|
||||||
|
|
||||||
|
print(f"\n{'All configs valid.' if all_valid else 'Validation failures found.'}")
|
||||||
|
return all_valid
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_schema():
|
||||||
|
print("Required keys:")
|
||||||
|
for key, typ in REQUIRED_SCHEMA.items():
|
||||||
|
print(f" {key}: {typ.__name__}")
|
||||||
|
print("\nOptional keys:")
|
||||||
|
for key, typ in OPTIONAL_SCHEMA.items():
|
||||||
|
if isinstance(typ, tuple):
|
||||||
|
print(f" {key}: {'|'.join(t.__name__ for t in typ)}")
|
||||||
|
else:
|
||||||
|
print(f" {key}: {typ.__name__}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Validate sidecar config files")
|
||||||
|
parser.add_argument("file", nargs="?", help="Config file to validate")
|
||||||
|
parser.add_argument("--all", action="store_true", help="Validate all config files")
|
||||||
|
parser.add_argument("--schema", action="store_true", help="Print expected schema")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.schema:
|
||||||
|
cmd_schema()
|
||||||
|
elif args.all:
|
||||||
|
ok = cmd_validate_all()
|
||||||
|
sys.exit(0 if ok else 1)
|
||||||
|
elif args.file:
|
||||||
|
ok = cmd_validate(args.file)
|
||||||
|
sys.exit(0 if ok else 1)
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{"song": "Dirt Road Home", "beat": 1, "lyric_line": "Gravel crunches under the tires slow", "scene": {"mood": "warmth", "colors": ["navy", "silver", "white"], "composition": "close-up", "camera": "slow pan", "description": "A warmth scene: 'Gravel crunches under the tires slow'. close-up with navy, silver, white. Camera: slow pan."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 2, "lyric_line": "The oak tree still leans toward the road", "scene": {"mood": "memory", "colors": ["dusty rose", "gold", "brown"], "composition": "wide shot", "camera": "steady", "description": "A memory scene: 'The oak tree still leans toward the road'. wide shot with dusty rose, gold, brown. Camera: steady."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 3, "lyric_line": "Mama's porch light through the fog", "scene": {"mood": "bittersweet", "colors": ["orange", "red", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A bittersweet scene: 'Mama's porch light through the fog'. medium shot with orange, red, brown. Camera: handheld."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 4, "lyric_line": "Daddy's truck rusting by the barn", "scene": {"mood": "tender", "colors": ["navy", "silver", "white"], "composition": "low angle", "camera": "slow zoom", "description": "A tender scene: 'Daddy's truck rusting by the barn'. low angle with navy, silver, white. Camera: slow zoom."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 5, "lyric_line": "The creek remembers my bare feet", "scene": {"mood": "fading", "colors": ["amber", "brown", "cream"], "composition": "high angle", "camera": "tracking", "description": "A fading scene: 'The creek remembers my bare feet'. high angle with amber, brown, cream. Camera: tracking."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 6, "lyric_line": "Fireflies spell out summer's name", "scene": {"mood": "warmth", "colors": ["green", "olive", "tan"], "composition": "over-the-shoulder", "camera": "static", "description": "A warmth scene: 'Fireflies spell out summer's name'. over-the-shoulder with green, olive, tan. Camera: static."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 7, "lyric_line": "The church bell rings for no one new", "scene": {"mood": "memory", "colors": ["dusty rose", "gold", "brown"], "composition": "profile", "camera": "crane up", "description": "A memory scene: 'The church bell rings for no one new'. profile with dusty rose, gold, brown. Camera: crane up."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 8, "lyric_line": "Honeysuckle climbs the fence again", "scene": {"mood": "bittersweet", "colors": ["navy", "silver", "white"], "composition": "bird's eye", "camera": "dolly in", "description": "A bittersweet scene: 'Honeysuckle climbs the fence again'. bird's eye with navy, silver, white. Camera: dolly in."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 9, "lyric_line": "The field where we learned to drive", "scene": {"mood": "tender", "colors": ["warm yellow", "barn red", "cream"], "composition": "tracking shot", "camera": "gentle drift", "description": "A tender scene: 'The field where we learned to drive'. tracking shot with warm yellow, barn red, cream. Camera: gentle drift."}}
|
|
||||||
{"song": "Dirt Road Home", "beat": 10, "lyric_line": "Some roads only go one way home", "scene": {"mood": "fading", "colors": ["forest green", "brown", "gold"], "composition": "establishing", "camera": "locked-off", "description": "A fading scene: 'Some roads only go one way home'. establishing with forest green, brown, gold. Camera: locked-off."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 1, "lyric_line": "Neon beer sign flickers twice", "scene": {"mood": "regret", "colors": ["warm yellow", "barn red", "cream"], "composition": "close-up", "camera": "slow pan", "description": "A regret scene: 'Neon beer sign flickers twice'. close-up with warm yellow, barn red, cream. Camera: slow pan."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 2, "lyric_line": "The jukebox plays what we used to be", "scene": {"mood": "fondness", "colors": ["copper", "dust", "gold"], "composition": "wide shot", "camera": "steady", "description": "A fondness scene: 'The jukebox plays what we used to be'. wide shot with copper, dust, gold. Camera: steady."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 3, "lyric_line": "Boots scuff the dance floor marks", "scene": {"mood": "aging", "colors": ["sunset orange", "purple", "pink"], "composition": "medium shot", "camera": "handheld", "description": "A aging scene: 'Boots scuff the dance floor marks'. medium shot with sunset orange, purple, pink. Camera: handheld."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 4, "lyric_line": "She orders water for the drive", "scene": {"mood": "memory", "colors": ["grey", "mud brown", "green"], "composition": "low angle", "camera": "slow zoom", "description": "A memory scene: 'She orders water for the drive'. low angle with grey, mud brown, green. Camera: slow zoom."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 5, "lyric_line": "The bartender knows both our names", "scene": {"mood": "music", "colors": ["orange", "red", "brown"], "composition": "high angle", "camera": "tracking", "description": "A music scene: 'The bartender knows both our names'. high angle with orange, red, brown. Camera: tracking."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 6, "lyric_line": "Two-step where the floor dips low", "scene": {"mood": "regret", "colors": ["navy", "silver", "white"], "composition": "over-the-shoulder", "camera": "static", "description": "A regret scene: 'Two-step where the floor dips low'. over-the-shoulder with navy, silver, white. Camera: static."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 7, "lyric_line": "Closing time writes the last song", "scene": {"mood": "fondness", "colors": ["sky blue", "wheat", "brown"], "composition": "profile", "camera": "crane up", "description": "A fondness scene: 'Closing time writes the last song'. profile with sky blue, wheat, brown. Camera: crane up."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 8, "lyric_line": "We leave our shadows at the bar", "scene": {"mood": "aging", "colors": ["green", "olive", "tan"], "composition": "bird's eye", "camera": "dolly in", "description": "A aging scene: 'We leave our shadows at the bar'. bird's eye with green, olive, tan. Camera: dolly in."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 9, "lyric_line": "The parking lot smells like rain", "scene": {"mood": "memory", "colors": ["dusty rose", "gold", "brown"], "composition": "tracking shot", "camera": "gentle drift", "description": "A memory scene: 'The parking lot smells like rain'. tracking shot with dusty rose, gold, brown. Camera: gentle drift."}}
|
|
||||||
{"song": "Last Call Honky-Tonk", "beat": 10, "lyric_line": "Some nights end before the music", "scene": {"mood": "music", "colors": ["navy", "silver", "white"], "composition": "establishing", "camera": "locked-off", "description": "A music scene: 'Some nights end before the music'. establishing with navy, silver, white. Camera: locked-off."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 1, "lyric_line": "White steeple catches the morning sun", "scene": {"mood": "sacred", "colors": ["forest green", "brown", "gold"], "composition": "close-up", "camera": "slow pan", "description": "A sacred scene: 'White steeple catches the morning sun'. close-up with forest green, brown, gold. Camera: slow pan."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 2, "lyric_line": "Hymnal pages turn like falling leaves", "scene": {"mood": "quiet", "colors": ["grey", "mud brown", "green"], "composition": "wide shot", "camera": "steady", "description": "A quiet scene: 'Hymnal pages turn like falling leaves'. wide shot with grey, mud brown, green. Camera: steady."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 3, "lyric_line": "The organ hums beneath the prayers", "scene": {"mood": "devotion", "colors": ["orange", "red", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A devotion scene: 'The organ hums beneath the prayers'. medium shot with orange, red, brown. Camera: handheld."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 4, "lyric_line": "Grandma's hat blocks the stained glass light", "scene": {"mood": "stillness", "colors": ["warm yellow", "barn red", "cream"], "composition": "low angle", "camera": "slow zoom", "description": "A stillness scene: 'Grandma's hat blocks the stained glass light'. low angle with warm yellow, barn red, cream. Camera: slow zoom."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 5, "lyric_line": "We kneel on cushions worn by years", "scene": {"mood": "awe", "colors": ["navy", "silver", "white"], "composition": "high angle", "camera": "tracking", "description": "A awe scene: 'We kneel on cushions worn by years'. high angle with navy, silver, white. Camera: tracking."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 6, "lyric_line": "The preacher's voice fills the gaps", "scene": {"mood": "sacred", "colors": ["sky blue", "wheat", "brown"], "composition": "over-the-shoulder", "camera": "static", "description": "A sacred scene: 'The preacher's voice fills the gaps'. over-the-shoulder with sky blue, wheat, brown. Camera: static."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 7, "lyric_line": "Offering plate circles like a prayer", "scene": {"mood": "quiet", "colors": ["white", "blue", "brown"], "composition": "profile", "camera": "crane up", "description": "A quiet scene: 'Offering plate circles like a prayer'. profile with white, blue, brown. Camera: crane up."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 8, "lyric_line": "Amen echoes off the wooden beams", "scene": {"mood": "devotion", "colors": ["dusty rose", "gold", "brown"], "composition": "bird's eye", "camera": "dolly in", "description": "A devotion scene: 'Amen echoes off the wooden beams'. bird's eye with dusty rose, gold, brown. Camera: dolly in."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 9, "lyric_line": "Children wiggle through the sermon", "scene": {"mood": "stillness", "colors": ["white", "blue", "brown"], "composition": "tracking shot", "camera": "gentle drift", "description": "A stillness scene: 'Children wiggle through the sermon'. tracking shot with white, blue, brown. Camera: gentle drift."}}
|
|
||||||
{"song": "Church on Sunday", "beat": 10, "lyric_line": "Faith smells like old wood and coffee", "scene": {"mood": "awe", "colors": ["sunset orange", "purple", "pink"], "composition": "establishing", "camera": "locked-off", "description": "A awe scene: 'Faith smells like old wood and coffee'. establishing with sunset orange, purple, pink. Camera: locked-off."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 1, "lyric_line": "Headlights cut the fog at five", "scene": {"mood": "resolve", "colors": ["dusty rose", "gold", "brown"], "composition": "close-up", "camera": "slow pan", "description": "A resolve scene: 'Headlights cut the fog at five'. close-up with dusty rose, gold, brown. Camera: slow pan."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 2, "lyric_line": "The diesel coughs to life like faith", "scene": {"mood": "effort", "colors": ["dusty rose", "gold", "brown"], "composition": "wide shot", "camera": "steady", "description": "A effort scene: 'The diesel coughs to life like faith'. wide shot with dusty rose, gold, brown. Camera: steady."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 3, "lyric_line": "Rows stretch past the tree line", "scene": {"mood": "strength", "colors": ["dusty rose", "gold", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A strength scene: 'Rows stretch past the tree line'. medium shot with dusty rose, gold, brown. Camera: handheld."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 4, "lyric_line": "Dust follows the disc like a ghost", "scene": {"mood": "persistence", "colors": ["warm yellow", "barn red", "cream"], "composition": "low angle", "camera": "slow zoom", "description": "A persistence scene: 'Dust follows the disc like a ghost'. low angle with warm yellow, barn red, cream. Camera: slow zoom."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 5, "lyric_line": "Hands grip leather worn to skin", "scene": {"mood": "focus", "colors": ["amber", "brown", "cream"], "composition": "high angle", "camera": "tracking", "description": "A focus scene: 'Hands grip leather worn to skin'. high angle with amber, brown, cream. Camera: tracking."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 6, "lyric_line": "The sun rises behind the work", "scene": {"mood": "resolve", "colors": ["forest green", "brown", "gold"], "composition": "over-the-shoulder", "camera": "static", "description": "A resolve scene: 'The sun rises behind the work'. over-the-shoulder with forest green, brown, gold. Camera: static."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 7, "lyric_line": "Crows circle what the plow reveals", "scene": {"mood": "effort", "colors": ["amber", "brown", "cream"], "composition": "profile", "camera": "crane up", "description": "A effort scene: 'Crows circle what the plow reveals'. profile with amber, brown, cream. Camera: crane up."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 8, "lyric_line": "Sweat salts the steering wheel", "scene": {"mood": "strength", "colors": ["grey", "mud brown", "green"], "composition": "bird's eye", "camera": "dolly in", "description": "A strength scene: 'Sweat salts the steering wheel'. bird's eye with grey, mud brown, green. Camera: dolly in."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 9, "lyric_line": "Planting season has no snooze", "scene": {"mood": "persistence", "colors": ["green", "olive", "tan"], "composition": "tracking shot", "camera": "gentle drift", "description": "A persistence scene: 'Planting season has no snooze'. tracking shot with green, olive, tan. Camera: gentle drift."}}
|
|
||||||
{"song": "Tractor at Dawn", "beat": 10, "lyric_line": "Every seed is a prayer for rain", "scene": {"mood": "focus", "colors": ["dusty rose", "gold", "brown"], "composition": "establishing", "camera": "locked-off", "description": "A focus scene: 'Every seed is a prayer for rain'. establishing with dusty rose, gold, brown. Camera: locked-off."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 1, "lyric_line": "Her handwriting shakes on the envelope", "scene": {"mood": "love", "colors": ["sky blue", "wheat", "brown"], "composition": "close-up", "camera": "slow pan", "description": "A love scene: 'Her handwriting shakes on the envelope'. close-up with sky blue, wheat, brown. Camera: slow pan."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 2, "lyric_line": "The postmark is two weeks old", "scene": {"mood": "vulnerability", "colors": ["green", "olive", "tan"], "composition": "wide shot", "camera": "steady", "description": "A vulnerability scene: 'The postmark is two weeks old'. wide shot with green, olive, tan. Camera: steady."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 3, "lyric_line": "He reads it sitting on his bunk", "scene": {"mood": "distance", "colors": ["sky blue", "wheat", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A distance scene: 'He reads it sitting on his bunk'. medium shot with sky blue, wheat, brown. Camera: handheld."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 4, "lyric_line": "She describes the dog getting bigger", "scene": {"mood": "hope", "colors": ["white", "blue", "brown"], "composition": "low angle", "camera": "slow zoom", "description": "A hope scene: 'She describes the dog getting bigger'. low angle with white, blue, brown. Camera: slow zoom."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 5, "lyric_line": "Censored words leave blank stares", "scene": {"mood": "longing", "colors": ["sunset orange", "purple", "pink"], "composition": "high angle", "camera": "tracking", "description": "A longing scene: 'Censored words leave blank stares'. high angle with sunset orange, purple, pink. Camera: tracking."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 6, "lyric_line": "The stamp is peeling at the corner", "scene": {"mood": "love", "colors": ["white", "blue", "brown"], "composition": "over-the-shoulder", "camera": "static", "description": "A love scene: 'The stamp is peeling at the corner'. over-the-shoulder with white, blue, brown. Camera: static."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 7, "lyric_line": "He folds it back exactly right", "scene": {"mood": "vulnerability", "colors": ["forest green", "brown", "gold"], "composition": "profile", "camera": "crane up", "description": "A vulnerability scene: 'He folds it back exactly right'. profile with forest green, brown, gold. Camera: crane up."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 8, "lyric_line": "Pictures curl at the edges now", "scene": {"mood": "distance", "colors": ["forest green", "brown", "gold"], "composition": "bird's eye", "camera": "dolly in", "description": "A distance scene: 'Pictures curl at the edges now'. bird's eye with forest green, brown, gold. Camera: dolly in."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 9, "lyric_line": "Her voice lives between the lines", "scene": {"mood": "hope", "colors": ["orange", "red", "brown"], "composition": "tracking shot", "camera": "gentle drift", "description": "A hope scene: 'Her voice lives between the lines'. tracking shot with orange, red, brown. Camera: gentle drift."}}
|
|
||||||
{"song": "Letters from Boot Camp", "beat": 10, "lyric_line": "Some letters carry more than words", "scene": {"mood": "longing", "colors": ["sunset orange", "purple", "pink"], "composition": "establishing", "camera": "locked-off", "description": "A longing scene: 'Some letters carry more than words'. establishing with sunset orange, purple, pink. Camera: locked-off."}}
|
|
||||||
{"song": "Flood Stage", "beat": 1, "lyric_line": "The river rose past the marker", "scene": {"mood": "loss", "colors": ["white", "blue", "brown"], "composition": "close-up", "camera": "slow pan", "description": "A loss scene: 'The river rose past the marker'. close-up with white, blue, brown. Camera: slow pan."}}
|
|
||||||
{"song": "Flood Stage", "beat": 2, "lyric_line": "Sandbags line the church basement door", "scene": {"mood": "resilience", "colors": ["green", "olive", "tan"], "composition": "wide shot", "camera": "steady", "description": "A resilience scene: 'Sandbags line the church basement door'. wide shot with green, olive, tan. Camera: steady."}}
|
|
||||||
{"song": "Flood Stage", "beat": 3, "lyric_line": "Photo albums float in the living room", "scene": {"mood": "community", "colors": ["white", "blue", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A community scene: 'Photo albums float in the living room'. medium shot with white, blue, brown. Camera: handheld."}}
|
|
||||||
{"song": "Flood Stage", "beat": 4, "lyric_line": "The bridge went out Tuesday night", "scene": {"mood": "grief", "colors": ["navy", "silver", "white"], "composition": "low angle", "camera": "slow zoom", "description": "A grief scene: 'The bridge went out Tuesday night'. low angle with navy, silver, white. Camera: slow zoom."}}
|
|
||||||
{"song": "Flood Stage", "beat": 5, "lyric_line": "Neighbors carry what they can hold", "scene": {"mood": "rebuilding", "colors": ["green", "olive", "tan"], "composition": "high angle", "camera": "tracking", "description": "A rebuilding scene: 'Neighbors carry what they can hold'. high angle with green, olive, tan. Camera: tracking."}}
|
|
||||||
{"song": "Flood Stage", "beat": 6, "lyric_line": "Water stains reach the second step", "scene": {"mood": "loss", "colors": ["amber", "brown", "cream"], "composition": "over-the-shoulder", "camera": "static", "description": "A loss scene: 'Water stains reach the second step'. over-the-shoulder with amber, brown, cream. Camera: static."}}
|
|
||||||
{"song": "Flood Stage", "beat": 7, "lyric_line": "The well is tasting like the river", "scene": {"mood": "resilience", "colors": ["forest green", "brown", "gold"], "composition": "profile", "camera": "crane up", "description": "A resilience scene: 'The well is tasting like the river'. profile with forest green, brown, gold. Camera: crane up."}}
|
|
||||||
{"song": "Flood Stage", "beat": 8, "lyric_line": "Mud lines mark where hope used to sit", "scene": {"mood": "community", "colors": ["warm yellow", "barn red", "cream"], "composition": "bird's eye", "camera": "dolly in", "description": "A community scene: 'Mud lines mark where hope used to sit'. bird's eye with warm yellow, barn red, cream. Camera: dolly in."}}
|
|
||||||
{"song": "Flood Stage", "beat": 9, "lyric_line": "We rebuild on the same ground", "scene": {"mood": "grief", "colors": ["sunset orange", "purple", "pink"], "composition": "tracking shot", "camera": "gentle drift", "description": "A grief scene: 'We rebuild on the same ground'. tracking shot with sunset orange, purple, pink. Camera: gentle drift."}}
|
|
||||||
{"song": "Flood Stage", "beat": 10, "lyric_line": "Some floods are just the land remembering", "scene": {"mood": "rebuilding", "colors": ["dusty rose", "gold", "brown"], "composition": "establishing", "camera": "locked-off", "description": "A rebuilding scene: 'Some floods are just the land remembering'. establishing with dusty rose, gold, brown. Camera: locked-off."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 1, "lyric_line": "The fence line needs mending again", "scene": {"mood": "endurance", "colors": ["orange", "red", "brown"], "composition": "close-up", "camera": "slow pan", "description": "A endurance scene: 'The fence line needs mending again'. close-up with orange, red, brown. Camera: slow pan."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 2, "lyric_line": "Wire cuts through leather gloves", "scene": {"mood": "patience", "colors": ["amber", "brown", "cream"], "composition": "wide shot", "camera": "steady", "description": "A patience scene: 'Wire cuts through leather gloves'. wide shot with amber, brown, cream. Camera: steady."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 3, "lyric_line": "Posts lean like tired old men", "scene": {"mood": "repair", "colors": ["grey", "mud brown", "green"], "composition": "medium shot", "camera": "handheld", "description": "A repair scene: 'Posts lean like tired old men'. medium shot with grey, mud brown, green. Camera: handheld."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 4, "lyric_line": "The cattle watch from the far hill", "scene": {"mood": "land", "colors": ["warm yellow", "barn red", "cream"], "composition": "low angle", "camera": "slow zoom", "description": "A land scene: 'The cattle watch from the far hill'. low angle with warm yellow, barn red, cream. Camera: slow zoom."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 5, "lyric_line": "We stretch and twist and tie", "scene": {"mood": "duty", "colors": ["amber", "brown", "cream"], "composition": "high angle", "camera": "tracking", "description": "A duty scene: 'We stretch and twist and tie'. high angle with amber, brown, cream. Camera: tracking."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 6, "lyric_line": "Sunburn writes on the back of necks", "scene": {"mood": "endurance", "colors": ["sunset orange", "purple", "pink"], "composition": "over-the-shoulder", "camera": "static", "description": "A endurance scene: 'Sunburn writes on the back of necks'. over-the-shoulder with sunset orange, purple, pink. Camera: static."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 7, "lyric_line": "The wind carries fence wire songs", "scene": {"mood": "patience", "colors": ["dusty rose", "gold", "brown"], "composition": "profile", "camera": "crane up", "description": "A patience scene: 'The wind carries fence wire songs'. profile with dusty rose, gold, brown. Camera: crane up."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 8, "lyric_line": "We repair what the storm broke", "scene": {"mood": "repair", "colors": ["white", "blue", "brown"], "composition": "bird's eye", "camera": "dolly in", "description": "A repair scene: 'We repair what the storm broke'. bird's eye with white, blue, brown. Camera: dolly in."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 9, "lyric_line": "Patience wears like good boots", "scene": {"mood": "land", "colors": ["copper", "dust", "gold"], "composition": "tracking shot", "camera": "gentle drift", "description": "A land scene: 'Patience wears like good boots'. tracking shot with copper, dust, gold. Camera: gentle drift."}}
|
|
||||||
{"song": "Barbed Wire Waltz", "beat": 10, "lyric_line": "Some fences are promises to the land", "scene": {"mood": "duty", "colors": ["amber", "brown", "cream"], "composition": "establishing", "camera": "locked-off", "description": "A duty scene: 'Some fences are promises to the land'. establishing with amber, brown, cream. Camera: locked-off."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 1, "lyric_line": "The truck bed holds two lawn chairs", "scene": {"mood": "calm", "colors": ["grey", "mud brown", "green"], "composition": "close-up", "camera": "slow pan", "description": "A calm scene: 'The truck bed holds two lawn chairs'. close-up with grey, mud brown, green. Camera: slow pan."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 2, "lyric_line": "Cooler rattles with ice and hope", "scene": {"mood": "companionship", "colors": ["orange", "red", "brown"], "composition": "wide shot", "camera": "steady", "description": "A companionship scene: 'Cooler rattles with ice and hope'. wide shot with orange, red, brown. Camera: steady."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 3, "lyric_line": "Crickets start before the stars", "scene": {"mood": "simplicity", "colors": ["sky blue", "wheat", "brown"], "composition": "medium shot", "camera": "handheld", "description": "A simplicity scene: 'Crickets start before the stars'. medium shot with sky blue, wheat, brown. Camera: handheld."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 4, "lyric_line": "The highway hums its evening song", "scene": {"mood": "nature", "colors": ["copper", "dust", "gold"], "composition": "low angle", "camera": "slow zoom", "description": "A nature scene: 'The highway hums its evening song'. low angle with copper, dust, gold. Camera: slow zoom."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 5, "lyric_line": "We share a blanket past dark", "scene": {"mood": "contentment", "colors": ["forest green", "brown", "gold"], "composition": "high angle", "camera": "tracking", "description": "A contentment scene: 'We share a blanket past dark'. high angle with forest green, brown, gold. Camera: tracking."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 6, "lyric_line": "Fireflies answer the sunset", "scene": {"mood": "calm", "colors": ["green", "olive", "tan"], "composition": "over-the-shoulder", "camera": "static", "description": "A calm scene: 'Fireflies answer the sunset'. over-the-shoulder with green, olive, tan. Camera: static."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 7, "lyric_line": "Country station plays the old ones", "scene": {"mood": "companionship", "colors": ["navy", "silver", "white"], "composition": "profile", "camera": "crane up", "description": "A companionship scene: 'Country station plays the old ones'. profile with navy, silver, white. Camera: crane up."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 8, "lyric_line": "The tailgate is our table now", "scene": {"mood": "simplicity", "colors": ["sunset orange", "purple", "pink"], "composition": "bird's eye", "camera": "dolly in", "description": "A simplicity scene: 'The tailgate is our table now'. bird's eye with sunset orange, purple, pink. Camera: dolly in."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 9, "lyric_line": "Silence sits between the songs", "scene": {"mood": "nature", "colors": ["sky blue", "wheat", "brown"], "composition": "tracking shot", "camera": "gentle drift", "description": "A nature scene: 'Silence sits between the songs'. tracking shot with sky blue, wheat, brown. Camera: gentle drift."}}
|
|
||||||
{"song": "Tailgate Sunset", "beat": 10, "lyric_line": "Some nights are church without walls", "scene": {"mood": "contentment", "colors": ["sunset orange", "purple", "pink"], "composition": "establishing", "camera": "locked-off", "description": "A contentment scene: 'Some nights are church without walls'. establishing with sunset orange, purple, pink. Camera: locked-off."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 1, "lyric_line": "Bone handle smooth from his pocket", "scene": {"mood": "sacred", "colors": ["forest green", "brown", "gold"], "composition": "close-up", "camera": "slow pan", "description": "A sacred scene: 'Bone handle smooth from his pocket'. close-up with forest green, brown, gold. Camera: slow pan."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 2, "lyric_line": "Three blades none of them new", "scene": {"mood": "quiet", "colors": ["green", "olive", "tan"], "composition": "wide shot", "camera": "steady", "description": "A quiet scene: 'Three blades none of them new'. wide shot with green, olive, tan. Camera: steady."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 3, "lyric_line": "He carved initials in the oak", "scene": {"mood": "devotion", "colors": ["warm yellow", "barn red", "cream"], "composition": "medium shot", "camera": "handheld", "description": "A devotion scene: 'He carved initials in the oak'. medium shot with warm yellow, barn red, cream. Camera: handheld."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 4, "lyric_line": "The steel remembers every cut", "scene": {"mood": "stillness", "colors": ["warm yellow", "barn red", "cream"], "composition": "low angle", "camera": "slow zoom", "description": "A stillness scene: 'The steel remembers every cut'. low angle with warm yellow, barn red, cream. Camera: slow zoom."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 5, "lyric_line": "I open it the way he taught", "scene": {"mood": "awe", "colors": ["sunset orange", "purple", "pink"], "composition": "high angle", "camera": "tracking", "description": "A awe scene: 'I open it the way he taught'. high angle with sunset orange, purple, pink. Camera: tracking."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 6, "lyric_line": "The smallest blade is for detail", "scene": {"mood": "sacred", "colors": ["green", "olive", "tan"], "composition": "over-the-shoulder", "camera": "static", "description": "A sacred scene: 'The smallest blade is for detail'. over-the-shoulder with green, olive, tan. Camera: static."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 7, "lyric_line": "Whittling shavings catch the light", "scene": {"mood": "quiet", "colors": ["amber", "brown", "cream"], "composition": "profile", "camera": "crane up", "description": "A quiet scene: 'Whittling shavings catch the light'. profile with amber, brown, cream. Camera: crane up."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 8, "lyric_line": "He said a knife is a promise", "scene": {"mood": "devotion", "colors": ["sunset orange", "purple", "pink"], "composition": "bird's eye", "camera": "dolly in", "description": "A devotion scene: 'He said a knife is a promise'. bird's eye with sunset orange, purple, pink. Camera: dolly in."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 9, "lyric_line": "I carry it in my front pocket", "scene": {"mood": "stillness", "colors": ["forest green", "brown", "gold"], "composition": "tracking shot", "camera": "gentle drift", "description": "A stillness scene: 'I carry it in my front pocket'. tracking shot with forest green, brown, gold. Camera: gentle drift."}}
|
|
||||||
{"song": "Granddad's Pocket Knife", "beat": 10, "lyric_line": "Some tools are heirlooms of skill", "scene": {"mood": "awe", "colors": ["orange", "red", "brown"], "composition": "establishing", "camera": "locked-off", "description": "A awe scene: 'Some tools are heirlooms of skill'. establishing with orange, red, brown. Camera: locked-off."}}
|
|
||||||
{"song": "County Fair", "beat": 1, "lyric_line": "Ferris wheel lights the harvest sky", "scene": {"mood": "celebration", "colors": ["green", "olive", "tan"], "composition": "close-up", "camera": "slow pan", "description": "A celebration scene: 'Ferris wheel lights the harvest sky'. close-up with green, olive, tan. Camera: slow pan."}}
|
|
||||||
{"song": "County Fair", "beat": 2, "lyric_line": "Corn dogs and lemon shake-ups", "scene": {"mood": "community", "colors": ["orange", "red", "brown"], "composition": "wide shot", "camera": "steady", "description": "A community scene: 'Corn dogs and lemon shake-ups'. wide shot with orange, red, brown. Camera: steady."}}
|
|
||||||
{"song": "County Fair", "beat": 3, "lyric_line": "The livestock barn smells like home", "scene": {"mood": "youth", "colors": ["sunset orange", "purple", "pink"], "composition": "medium shot", "camera": "handheld", "description": "A youth scene: 'The livestock barn smells like home'. medium shot with sunset orange, purple, pink. Camera: handheld."}}
|
|
||||||
{"song": "County Fair", "beat": 4, "lyric_line": "Blue ribbons pinned to quilt squares", "scene": {"mood": "harvest", "colors": ["dusty rose", "gold", "brown"], "composition": "low angle", "camera": "slow zoom", "description": "A harvest scene: 'Blue ribbons pinned to quilt squares'. low angle with dusty rose, gold, brown. Camera: slow zoom."}}
|
|
||||||
{"song": "County Fair", "beat": 5, "lyric_line": "Kids scream on the zipper ride", "scene": {"mood": "fun", "colors": ["grey", "mud brown", "green"], "composition": "high angle", "camera": "tracking", "description": "A fun scene: 'Kids scream on the zipper ride'. high angle with grey, mud brown, green. Camera: tracking."}}
|
|
||||||
{"song": "County Fair", "beat": 6, "lyric_line": "Band plays covers by the stage", "scene": {"mood": "celebration", "colors": ["navy", "silver", "white"], "composition": "over-the-shoulder", "camera": "static", "description": "A celebration scene: 'Band plays covers by the stage'. over-the-shoulder with navy, silver, white. Camera: static."}}
|
|
||||||
{"song": "County Fair", "beat": 7, "lyric_line": "Hay bales line the midway path", "scene": {"mood": "community", "colors": ["sky blue", "wheat", "brown"], "composition": "profile", "camera": "crane up", "description": "A community scene: 'Hay bales line the midway path'. profile with sky blue, wheat, brown. Camera: crane up."}}
|
|
||||||
{"song": "County Fair", "beat": 8, "lyric_line": "We split the funnel cake in half", "scene": {"mood": "youth", "colors": ["copper", "dust", "gold"], "composition": "bird's eye", "camera": "dolly in", "description": "A youth scene: 'We split the funnel cake in half'. bird's eye with copper, dust, gold. Camera: dolly in."}}
|
|
||||||
{"song": "County Fair", "beat": 9, "lyric_line": "The demolition derby is last", "scene": {"mood": "harvest", "colors": ["sunset orange", "purple", "pink"], "composition": "tracking shot", "camera": "gentle drift", "description": "A harvest scene: 'The demolition derby is last'. tracking shot with sunset orange, purple, pink. Camera: gentle drift."}}
|
|
||||||
{"song": "County Fair", "beat": 10, "lyric_line": "Some summers live in a single night", "scene": {"mood": "fun", "colors": ["warm yellow", "barn red", "cream"], "composition": "establishing", "camera": "locked-off", "description": "A fun scene: 'Some summers live in a single night'. establishing with warm yellow, barn red, cream. Camera: locked-off."}}
|
|
||||||
Reference in New Issue
Block a user