Create a new Ghost Signal audio theme from images, visual references, text descriptions, or concept prompts. Use this skill when users want to create a new sound theme from an image, photo, screenshot, or artwork. Also triggers on: "new theme", "create theme", "sound theme", "audio theme", "sound palette", "analyze this image", "theme from image", or any request to turn a visual into browser sounds.
التثبيت
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Create a new Ghost Signal audio theme from images, visual references, text descriptions, or concept prompts. Use this skill when users want to create a new sound theme from an image, photo, screenshot, or artwork. Also triggers on: "new theme", "create theme", "sound theme", "audio theme", "sound palette", "analyze this image", "theme from image", or any request to turn a visual into browser sounds.
version
2.0.0
Create Sound Theme
This skill provides a complete workflow for creating Ghost Signal audio themes —
browser sound palettes built entirely with the Web Audio API. The primary use
case is analyzing an image and translating its visual qualities into a
cohesive sound palette.
Critical Rules (Read First!)
Every theme has exactly 4 files: <theme-name>.md (spec), sounds.js (ES module), index.html (thin redirect), and cover.png (cover image)
Every theme has exactly 16 sounds — no more, no fewer
Web Audio API only — no sample files, no <audio> elements, no fetch
Sound logic goes in sounds.js — the shared demo.html handles all UI
Do NOT modify demo.html — it loads themes dynamically via ?theme=<name>
Use TEMPLATE.md and TEMPLATE.js as the structural base — read them first
No build step — themes are ES modules loaded by the browser natively
Workflow: Image → Sound Theme
When the user provides an image, follow this complete pipeline:
Image provided
│
├─► 1. ANALYZE the image (see Image Analysis below)
│
├─► 2. DERIVE theme identity — name, mood, colors, sonic family
│
├─► 3. MAP visible objects → sonic metaphors for all 16 sounds
│
├─► 4. GENERATE cover image (see Cover Image Generation below)
│
├─► 5. WRITE spec file (<theme-name>.md)
│
├─► 6. WRITE sounds.js ES module with meta + createSounds factory
│
└─► 7. WRITE thin index.html redirect
Image Analysis Procedure
Examine the image systematically across these 6 dimensions:
A. Era & Setting
Identify the time period and location. This determines the overall sonic
character:
Era
Sonic Character
Oscillator Preference
Filter Style
Retro / vintage / analog
Warm, rounded, lo-fi
triangle, sine
Heavy low-pass, roll off > 4 kHz
Modern / minimal / clean
Crisp, precise, digital
sine, square
Light filtering, wider bandwidth
Futuristic / sci-fi / cyber
Sharp, metallic, electric
sawtooth, square
Bandpass sweeps, high resonance
Natural / organic / earthy
Soft, diffuse, breathy
sine + heavy noise
Wide bandpass, low Q
B. Visible Objects → Sound Sources
This is the most important step. Scan the image for physical objects and map
each to a sound ID. Every object that could make a sound is a candidate:
Object Type
Maps To
Sonic Metaphor
Buttons, knobs, switches
CLICK, SWITCH_TOGGLE
The material they're made of (plastic, metal, wood)
Screens, displays, monitors
HOVER, HOVER_UP
The technology type (CRT hum, LCD whisper, LED ping)
Mechanical devices
IMPORTANT_CLICK
The action of their mechanism (lever, spring, gear)
If the image lacks enough distinct objects, derive sounds from the materials
and atmosphere instead (wood resonance, metal clang, glass tink, fabric
muffle, water drip, etc.).
C. Material Palette → Tonal Qualities
Identify the dominant materials in the scene and translate to synthesis parameters:
Material
Frequency Range
Oscillator
Filter
Gain Envelope
Wood
200-800 Hz
triangle
Low-pass < 2.5 kHz, Q = 3-5
Medium attack, warm release
Metal
1-4 kHz
square, sawtooth
Bandpass, high Q (8-12)
Sharp attack, resonant decay
Plastic
500-2 kHz
triangle
Low-pass < 4 kHz, Q = 2-3
Fast attack, short release
Glass
2-6 kHz
sine
High-pass > 1 kHz
Instant attack, long ringing release
Fabric / soft
200-1.5 kHz
noise-only
Bandpass, low Q (1-2)
Soft attack, muffled
Electronics
60-8 kHz (wide)
sine + sawtooth
Sweeping low-pass
Depends on power state
Water / liquid
300-3 kHz
noise + sine
Bandpass, moderate Q
Bubbly, irregular
D. Color Palette → CSS Variables
Extract 9 colors from the image:
Find the 2 most vibrant/saturated colors → --accent and --accent2
Find the most alarming/warm saturated color → --danger
Find the darkest background tone → --bg
Create 2 progressively lighter shades from --bg → --surface, --surface2
Find a mid-tone separator color → --border
Find the lightest readable color → --text
Desaturate --text and reduce brightness → --text-dim
Use kebab-case for the directory: chill-city-fm, ghost-signal, neon-arcade
Cover Image Generation
Every theme needs a cover.png — a visual identity image that captures the
theme's mood, atmosphere, and color palette. Generate it using NotebookLM
infographic generation after the theme identity and color palette have been
derived.
Method — NotebookLM infographic pipeline:
Create a notebook: notebook_create with title "<Theme Name> Cover Art"
Add a text source: source_add with source_type="text" containing a
vivid description of the desired cover image (see prompt guidelines below).
Set wait=true to ensure the source is processed before generating.
Generate infographic: studio_create with artifact_type="infographic",
orientation="landscape", detail_level="detailed". Include a focus_prompt
describing the visual scene. Set confirm=true.
Poll for completion: studio_status until the artifact status is
"completed" (typically 60-90 seconds).
Download: download_artifact with artifact_type="infographic" and
output_path="<theme-name>/cover.png".
Cleanup (optional): notebook_delete the temporary notebook with
confirm=true.
Text source content guidelines:
Write a rich visual description (150-300 words) covering:
Subject — A scene or composition that embodies the theme's mood and setting
(e.g. "rain-slick neon alley at night" for a cyberpunk theme, "high-altitude
space gantry above cloud layer" for a space theme)
Materials & textures — Reference the dominant materials from the Material
Palette analysis (metal, wood, glass, fabric, etc.)
Color direction — Specify the accent colors with hex values and overall
palette derived in step D (Color Palette → CSS Variables)
Atmosphere — Match the lighting and atmosphere from step E
Style — Painterly, cinematic, or illustrative — avoid photorealism and
text/lettering
Aspect ratio — Landscape (16:9 or similar)
Focus prompt example:
Create a cinematic cover art image: a lone coder silhouetted against a massive
holographic code display floating in deep space. Cyan and green glowing text,
midnight navy void with distant stars. Painterly, atmospheric, no text or
lettering. Wide landscape.
Save the generated image as <theme-name>/cover.png. The concept file
(<theme-name>.md) references it via .
Step 1: Derive Theme Identity
Extract these from the source material:
Field
What to determine
Name
2-3 words, kebab-case for directory, Title Case for display
HOVER / HOVER_UP — mirror pair (ascending vs descending sweep)
CLICK / IMPORTANT_CLICK — same transient, IMPORTANT adds body + sub-bass
FEATURE_SWITCH ON / OFF — inverse envelopes
LIMITER ON / OFF — related to FEATURE_SWITCH but narrower, more constrained
TAB_INSERT / TAB_CLOSE — inverse blip sequences
TYPING keys — same tonal family, different weight per key
Step 3: Create Files
3a. Create directory
mkdir <theme-name>
3b. Write <theme-name>.md
Follow TEMPLATE.md structure exactly. For each of the 16 sounds, specify:
Duration (ms), Base Freq (Hz), Variants count
Concept — sonic metaphor paragraph
Synthesis — exact Web Audio recipe (oscillator types, frequencies, filter
specs, gain envelopes, noise layers — specific enough to implement without guessing)
3c. Write sounds.js
Follow TEMPLATE.js structure. The module exports { meta, createSounds }:
Section
What to fill in
meta.name
Theme display name
meta.subtitle
Short description
meta.colors
All 9 color hex values (accent, accent2, danger, bg, surface, surface2, border, text, textDim)
meta.placeholder
Mood-appropriate textarea placeholder text
meta.sounds
Object with 16 entries, each having { label, meta, desc }
createSounds() body
16 sound function implementations using Web Audio API
The createSounds(ctx, noiseBuffer) factory receives an AudioContext and
noiseBuffer(duration) helper. It returns an object of 16 sound functions.
3d. Generate cover.png
Generate a cover image via NotebookLM (see Cover Image Generation above):
notebook_create — temporary notebook for cover generation
source_add — text source with vivid visual description of the scene
studio_create — infographic, landscape orientation, detailed, with focus prompt
studio_status — poll until completed
download_artifact — save as <theme-name>/cover.png
notebook_delete — clean up the temporary notebook (optional)
Do NOT modify demo.html — it handles all shared UI (audio engine, toggle
switches, tab bar, keyboard input, sound grid rendering) automatically.
Web Audio Synthesis Reference
Sound Function Structure
Every sound function must follow this pattern:
sounds.SOUND_NAME = function() {
const now = ctx.currentTime;
// 1. Create oscillator(s) / buffer source(s)// 2. Create filter(s) — bandpass, lowpass, highpass// 3. Create gain node(s) with envelope automation// 4. Connect chain: source → filter → gain → ctx.destination// 5. Schedule .start(now + offset) and .stop(now + offset)
};
Gain Envelopes
// Attack-release
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(0.2, now + 0.005); // attack
gain.gain.exponentialRampToValueAtTime(0.001, now + dur); // release// Sustain-release
gain.gain.setValueAtTime(0, now);
gain.gain.linearRampToValueAtTime(0.2, now + 0.003); // attack
gain.gain.setValueAtTime(0.2, now + 0.05); // sustain hold
gain.gain.exponentialRampToValueAtTime(0.001, now + 0.12); // release
exponentialRampToValueAtTime cannot target 0 — always use 0.001.
Frequency Sweeps
osc.frequency.setValueAtTime(startHz, now);
osc.frequency.linearRampToValueAtTime(endHz, now + dur); // linear
osc.frequency.exponentialRampToValueAtTime(endHz, now + dur); // natural curve