Files
motif/index.html
T
b1rdmania f437bba281 Move MIDI preview playback into results table.
Adds per-row Play/Stop buttons and replaces the standalone preview box with compact preview volume/stop controls.
2025-12-26 18:42:31 +00:00

1036 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Motif - Procedural Music Synthesis</title>
<!-- OpenGraph / Social Media Preview -->
<meta property="og:title" content="MOTIF">
<meta property="og:description" content="Procedural Music Synthesis from MIDI">
<meta property="og:image" content="/chiptune_blog_piece_1000x.webp">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:type" content="website">
<meta property="og:url" content="https://motif-self.vercel.app">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="MOTIF">
<meta name="twitter:description" content="Procedural Music Synthesis from MIDI">
<meta name="twitter:image" content="/chiptune_blog_piece_1000x.webp">
<!-- General Meta -->
<meta name="description" content="Transform MIDI files into retro synthesized variations. Search for songs, preview them, and generate new procedural versions with retro game console vibes.">
<style>
/* Design System: Synthwave - 8px grid, consistent neon accents */
:root {
--color-bg: #0a0a0a;
--color-surface: #141414;
--color-surface-elevated: #1a1a1a;
--color-border: #2a2a2a;
--color-text: #e8e8e8;
--color-text-dim: #999;
--color-accent-primary: #00ff88;
--color-accent-secondary: #ffaa44;
--spacing-unit: 8px;
--radius: 8px;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.5);
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.6);
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.7);
--glow-primary: 0 0 20px rgba(0, 255, 136, 0.3);
--glow-secondary: 0 0 20px rgba(255, 170, 68, 0.3);
}
* {
box-sizing: border-box;
}
body {
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
background:
radial-gradient(1000px 600px at 50% -150px, rgba(0, 255, 136, 0.12), transparent 60%),
radial-gradient(800px 600px at 110% 20%, rgba(255, 170, 68, 0.08), transparent 55%),
var(--color-bg);
color: var(--color-text);
margin: 0;
padding: calc(var(--spacing-unit) * 3);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
.container {
max-width: 960px;
margin: 0 auto;
}
h1 {
color: var(--color-accent-primary);
text-align: center;
margin: 0 0 calc(var(--spacing-unit) * 4) 0;
font-size: 2em;
font-weight: 700;
letter-spacing: 0.05em;
text-shadow: var(--glow-primary);
}
.topbar {
display: flex;
align-items: center;
justify-content: center;
gap: calc(var(--spacing-unit) * 2);
margin-bottom: calc(var(--spacing-unit) * 2);
}
.topbar h1 {
margin: 0;
}
.faq-link {
margin-left: auto;
background: transparent;
border: 1px solid rgba(255,255,255,0.14);
color: rgba(255,255,255,0.85);
padding: 8px 10px;
border-radius: var(--radius);
box-shadow: none;
font-size: 13px;
}
.faq-link:hover:not(:disabled) {
box-shadow: var(--shadow-sm);
border-color: rgba(255,255,255,0.22);
}
/* FAQ modal */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.65);
display: none;
align-items: center;
justify-content: center;
padding: 20px;
z-index: 1000;
}
.modal-backdrop.open { display: flex; }
.modal {
width: min(720px, 100%);
background: rgba(20,20,20,0.98);
border: 1px solid rgba(255,255,255,0.12);
border-radius: 12px;
box-shadow: 0 30px 120px rgba(0,0,0,0.75);
overflow: hidden;
}
.modal header {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-bottom: 1px solid rgba(255,255,255,0.08);
}
.modal header h3 {
margin: 0;
font-size: 14px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: rgba(255,255,255,0.9);
}
.modal header .faq-header-links {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.modal header .faq-header-links a {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,0.12);
background: rgba(0,0,0,0.18);
color: rgba(255,255,255,0.82);
text-decoration: none;
font-size: 12px;
line-height: 1;
box-shadow: none;
transition: border-color 120ms ease, box-shadow 120ms ease, background 120ms ease;
}
.modal header .faq-header-links a:hover {
border-color: rgba(255,255,255,0.22);
box-shadow: 0 10px 30px rgba(0,0,0,0.45);
background: rgba(0,0,0,0.28);
}
.modal header .faq-header-links a:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(0,255,136,0.25), 0 12px 34px rgba(0,0,0,0.55);
border-color: rgba(0,255,136,0.45);
}
.modal header .faq-header-links .dot {
width: 6px;
height: 6px;
border-radius: 999px;
background: rgba(0,255,136,0.85);
box-shadow: 0 0 14px rgba(0,255,136,0.22);
flex: 0 0 auto;
}
.modal header .faq-header-links .label {
display: inline-flex;
align-items: baseline;
gap: 6px;
white-space: nowrap;
}
.modal header .faq-header-links .handle {
color: rgba(0,255,136,0.9);
font-weight: 600;
}
@media (max-width: 480px) {
.modal header {
gap: 10px;
padding: 12px 12px;
}
.modal header .faq-header-links a {
padding: 6px 9px;
font-size: 12px;
}
}
.modal header .spacer { margin-left: auto; }
.modal header button {
padding: 8px 10px;
border-radius: 10px;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.12);
box-shadow: none;
}
.modal main {
padding: 14px 16px 16px 16px;
}
.faq-grid {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
.faq-item {
border: 1px solid rgba(255,255,255,0.08);
border-radius: 12px;
padding: 12px 12px;
background: rgba(0,0,0,0.18);
}
.faq-item h4 {
margin: 0 0 6px 0;
font-size: 13px;
color: rgba(0,255,136,0.9);
}
.faq-item p {
margin: 0;
color: rgba(255,255,255,0.75);
font-size: 13px;
line-height: 1.45;
}
.faq-item code {
font-size: 12px;
color: rgba(255,255,255,0.85);
}
.controls {
margin: calc(var(--spacing-unit) * 3) 0;
text-align: center;
}
button {
background: var(--color-surface);
color: var(--color-text);
border: 1px solid var(--color-border);
padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 3);
border-radius: var(--radius);
cursor: pointer;
font-family: inherit;
font-size: 14px;
font-weight: 500;
transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--shadow-sm);
}
button:hover:not(:disabled) {
background: var(--color-surface-elevated);
transform: translateY(-1px);
border-color: #444;
box-shadow: var(--shadow-md);
}
button:active:not(:disabled) {
transform: translateY(0);
box-shadow: var(--shadow-sm);
}
button:disabled {
opacity: 0.4;
cursor: not-allowed;
}
button.primary {
background: var(--color-accent-primary);
color: #000;
border-color: var(--color-accent-primary);
font-weight: 600;
}
button.primary:hover:not(:disabled) {
background: #00dd77;
box-shadow: var(--glow-primary), var(--shadow-md);
}
#status {
margin: calc(var(--spacing-unit) * 3) 0;
padding: calc(var(--spacing-unit) * 2);
background: var(--color-surface);
border-left: 3px solid var(--color-accent-primary);
border-radius: var(--radius);
box-shadow: var(--shadow-md);
font-size: 14px;
min-height: 24px;
}
input[type="text"] {
background: var(--color-surface);
color: var(--color-text);
border: 1px solid var(--color-border);
padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 2);
border-radius: var(--radius);
font-family: inherit;
font-size: 16px;
transition: border-color 150ms ease, box-shadow 150ms ease;
}
input[type="text"]:focus {
outline: none;
border-color: var(--color-accent-primary);
box-shadow: 0 0 0 3px rgba(0, 255, 136, 0.1);
}
.results-section {
margin: 30px 0;
display: none;
}
.results-section.visible {
display: block;
}
.results-table {
width: 100%;
border-collapse: collapse;
margin: calc(var(--spacing-unit) * 2) 0;
background: var(--color-surface);
border-radius: var(--radius);
overflow: hidden;
box-shadow: var(--shadow-md);
}
.results-table th,
.results-table td {
padding: calc(var(--spacing-unit) * 2);
text-align: left;
border-bottom: 1px solid var(--color-border);
}
.results-table th {
background: var(--color-surface-elevated);
color: var(--color-accent-primary);
font-weight: 600;
font-size: 12px;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.results-table .source-col {
width: 100px;
text-align: center;
}
.results-table .duration-col {
width: 80px;
text-align: center;
}
.results-table .preview-col {
width: 110px;
text-align: center;
}
.results-table tbody tr {
cursor: pointer;
transition: background 150ms ease;
}
.results-table tbody tr:hover {
background: rgba(255, 255, 255, 0.05);
}
.results-table tbody tr:last-child td {
border-bottom: none;
}
.results-table tr.selected {
background: rgba(0, 255, 136, 0.12);
}
.results-table tr.selected td:first-child {
border-left: 4px solid var(--color-accent-primary);
padding-left: calc(var(--spacing-unit) * 2 - 4px);
}
@media (max-width: 640px) {
.results-table th,
.results-table td {
padding: calc(var(--spacing-unit) * 1.5);
font-size: 14px;
}
.results-table th {
font-size: 11px;
}
.results-table .source-col {
display: none;
}
.results-table .duration-col {
width: 60px;
}
.results-table .preview-col {
width: 84px;
}
}
.results-controls {
display: flex;
gap: calc(var(--spacing-unit) * 1.5);
align-items: center;
flex-wrap: wrap;
padding: calc(var(--spacing-unit) * 2);
background: var(--color-surface);
border-radius: var(--radius);
border: 1px solid var(--color-border);
box-shadow: var(--shadow-sm);
margin-top: calc(var(--spacing-unit) * 2);
}
.results-controls .volume-control {
flex: 1;
min-width: 220px;
margin-top: 0;
}
.results-controls .actions {
margin-left: auto;
display: inline-flex;
gap: calc(var(--spacing-unit) * 1.25);
align-items: center;
flex-wrap: wrap;
}
@media (max-width: 768px) {
.results-controls {
flex-direction: column;
align-items: stretch;
}
.results-controls .actions {
margin-left: 0;
width: 100%;
display: flex;
flex-direction: column;
}
}
.confidence-bar {
width: 60px;
height: 4px;
background: #333;
border-radius: 2px;
overflow: hidden;
}
.confidence-fill {
height: 100%;
background: linear-gradient(90deg, #ff4444, #ffaa44, #00ff88);
transition: width 0.2s;
}
.player-section {
margin: 30px 0;
display: none;
}
.player-section.visible {
display: block;
}
.player-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 20px 0;
}
.player-box {
background: var(--color-surface);
padding: calc(var(--spacing-unit) * 3);
border: 1px solid var(--color-border);
border-radius: var(--radius);
box-shadow: var(--shadow-md);
transition: transform 150ms ease, box-shadow 150ms ease;
}
.player-box:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.player-box h4 {
margin: 0 0 calc(var(--spacing-unit)) 0;
color: var(--color-accent-primary);
font-size: 15px;
font-weight: 600;
}
.player-box p {
font-size: 13px;
color: var(--color-text-dim);
margin: 0 0 calc(var(--spacing-unit) * 2) 0;
}
.player-box button {
width: 100%;
margin: calc(var(--spacing-unit)) 0 0 0;
}
.player-box button:first-of-type {
margin-top: 0;
}
.player-info {
background: var(--color-surface);
padding: calc(var(--spacing-unit) * 3);
margin: calc(var(--spacing-unit) * 3) 0;
border-left: 3px solid var(--color-accent-primary);
border-radius: var(--radius);
box-shadow: var(--shadow-md);
}
.player-info h4 {
margin: 0 0 calc(var(--spacing-unit)) 0;
color: var(--color-text);
font-size: 16px;
}
.player-info p {
margin: 0;
font-size: 13px;
color: var(--color-text-dim);
}
.section {
margin-top: calc(var(--spacing-unit) * 5);
}
.section-header {
margin: 0 0 calc(var(--spacing-unit) * 2) 0;
}
.section-title {
margin: 0;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--color-text);
}
.section-subtitle {
margin: calc(var(--spacing-unit) / 2) 0 0 0;
font-size: 13px;
color: var(--color-text-dim);
}
.divider {
height: 1px;
margin: 0 0 calc(var(--spacing-unit) * 3) 0;
background: linear-gradient(90deg, transparent, var(--color-border), transparent);
}
.preview-controls {
display: flex;
gap: calc(var(--spacing-unit) * 1.5);
align-items: center;
flex-wrap: wrap;
padding: calc(var(--spacing-unit) * 3);
background: var(--color-surface);
border-radius: var(--radius);
border: 1px solid var(--color-border);
box-shadow: var(--shadow-sm);
}
.preview-controls button.preview-play {
flex: 1;
min-width: 160px;
}
.preview-controls button.next-result {
margin-left: 0;
}
.preview-controls .preview-actions {
margin-left: auto;
display: inline-flex;
gap: calc(var(--spacing-unit) * 1.25);
align-items: center;
}
.preview-controls .volume-control {
flex: 1;
min-width: 200px;
margin-top: 0;
}
@media (max-width: 768px) {
.preview-controls {
flex-direction: column;
align-items: stretch;
}
.preview-controls .preview-actions {
margin-left: 0;
width: 100%;
display: flex;
flex-direction: column;
}
}
.motif-stage {
background: var(--color-surface-elevated);
padding: calc(var(--spacing-unit) * 3);
border-radius: var(--radius);
border: 1px solid rgba(255, 170, 68, 0.2);
box-shadow: var(--shadow-lg), var(--glow-secondary);
}
.motif-grid {
display: flex;
flex-direction: column;
gap: 16px;
}
.motif-header {
margin-bottom: 6px;
}
.motif-controls {
display: flex;
gap: 12px;
align-items: center;
flex-wrap: wrap;
}
.motif-controls button {
flex-shrink: 0;
}
.motif-controls button.primary {
flex: 1;
min-width: 180px;
padding: 12px 16px;
font-weight: 700;
}
.motif-controls button.primary:hover {
box-shadow: 0 16px 60px rgba(255, 170, 68, 0.15);
border-color: rgba(255, 170, 68, 0.55);
}
.motif-controls .volume-control {
flex: 1;
min-width: 200px;
margin-top: 0;
}
.motif-controls .volume-control label {
font-size: 0.85em;
min-width: 55px;
}
/* iOS audio unlock (Motif) */
.ios-audio-banner {
margin-top: calc(var(--spacing-unit) * 2);
padding: calc(var(--spacing-unit) * 2);
border-radius: var(--radius);
border: 1px solid rgba(255, 170, 68, 0.22);
background: rgba(0, 0, 0, 0.25);
box-shadow: var(--shadow-sm);
display: none; /* toggled by JS */
}
.ios-audio-banner .row {
display: flex;
gap: calc(var(--spacing-unit) * 1.5);
align-items: center;
flex-wrap: wrap;
}
.ios-audio-banner .copy {
font-size: 12px;
color: var(--color-text-dim);
line-height: 1.35;
flex: 1;
min-width: 220px;
}
.ios-audio-banner .copy strong {
color: var(--color-text);
font-weight: 600;
}
.ios-audio-banner .state {
margin-top: calc(var(--spacing-unit) * 1);
font-size: 12px;
color: rgba(255, 170, 68, 0.85);
display: none;
}
.ios-audio-banner button {
padding: calc(var(--spacing-unit) * 1.25) calc(var(--spacing-unit) * 2);
border-radius: var(--radius);
border: 1px solid rgba(255, 170, 68, 0.35);
background: rgba(255, 170, 68, 0.12);
color: var(--color-text);
box-shadow: var(--shadow-sm);
font-weight: 600;
}
.ios-audio-banner button:hover:not(:disabled) {
border-color: rgba(255, 170, 68, 0.55);
box-shadow: var(--glow-secondary), var(--shadow-md);
}
.motif-kicker {
font-size: 0.85em;
color: #b6b6b6;
margin: 0 0 10px 0;
max-width: 70ch;
}
.try-next {
margin-top: 14px;
width: 100%;
}
.try-next button {
width: 100%;
}
.volume-control {
margin-top: 10px;
display: flex;
align-items: center;
gap: 10px;
position: relative;
}
.volume-control label {
font-size: 0.9em;
color: #aaa;
}
.volume-control input[type="range"] {
flex: 1;
margin: 0;
}
.motif-progress-container {
margin-top: 8px;
padding-top: 16px;
border-top: 1px solid rgba(255, 170, 68, 0.15);
}
.progress-time {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 0.85em;
color: #8f8f8f;
}
.progress-bar-wrapper {
position: relative;
height: 44px;
display: flex;
align-items: center;
padding: calc(var(--spacing-unit) * 2) 0;
}
.progress-bar {
width: 100%;
height: 6px;
-webkit-appearance: none;
appearance: none;
background: transparent;
border-radius: 3px;
outline: none;
cursor: pointer;
position: relative;
z-index: 2;
}
.progress-bar::-webkit-slider-runnable-track {
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
.progress-bar::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--color-accent-secondary);
cursor: pointer;
box-shadow: 0 0 8px rgba(255, 170, 68, 0.6), var(--shadow-sm);
margin-top: -7px;
transition: transform 100ms ease;
}
.progress-bar:active::-webkit-slider-thumb {
transform: scale(1.15);
}
.progress-bar::-moz-range-track {
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
.progress-bar::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--color-accent-secondary);
cursor: pointer;
border: none;
box-shadow: 0 0 8px rgba(255, 170, 68, 0.6), var(--shadow-sm);
}
.progress-fill {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 6px;
background: linear-gradient(90deg, var(--color-accent-secondary), rgba(255, 170, 68, 0.5));
border-radius: 3px;
pointer-events: none;
z-index: 1;
width: 0%;
transition: width 0.1s linear;
}
/* Use on your website */
.embed-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius);
padding: calc(var(--spacing-unit) * 3);
box-shadow: var(--shadow-md);
}
.embed-row {
display: flex;
gap: calc(var(--spacing-unit) * 1.5);
align-items: flex-start;
flex-wrap: wrap;
}
.embed-row button {
flex-shrink: 0;
}
.codeblock {
flex: 1;
min-width: 260px;
margin: 0;
padding: calc(var(--spacing-unit) * 2);
border-radius: calc(var(--radius) + 2px);
background: rgba(0,0,0,0.35);
border: 1px solid rgba(255,255,255,0.08);
overflow: auto;
box-shadow: var(--shadow-sm);
}
.codeblock code {
font-size: 12px;
color: rgba(255,255,255,0.85);
white-space: pre;
}
.embed-hint {
margin-top: calc(var(--spacing-unit) * 1.5);
color: var(--color-text-dim);
font-size: 12px;
}
.embed-hint strong {
color: var(--color-text);
font-weight: 600;
}
.copy-toast {
margin-left: auto;
font-size: 12px;
color: rgba(0,255,136,0.85);
display: none;
}
.engine-selector {
margin-top: 10px;
font-size: 0.9em;
}
.engine-selector label {
color: #aaa;
display: block;
margin-bottom: 5px;
}
.engine-selector select {
background: #333;
color: #e0e0e0;
border: 1px solid #555;
padding: 5px 10px;
font-family: inherit;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="topbar">
<h1>🎵 MOTIF</h1>
<button id="faqBtn" class="faq-link" type="button">FAQ</button>
</div>
<p>Procedural Music Synthesis from MIDI Structure</p>
<div class="controls">
<input type="text" id="songInput" placeholder="Enter song name..." />
<button id="searchBtn">Search</button>
</div>
<div id="status">Ready. Enter a song name to search for MIDI files.</div>
<div id="resultsSection" class="results-section">
<h3>Search Results</h3>
<table id="resultsTable" class="results-table">
<thead>
<tr>
<th>Title</th>
<th class="source-col">Source</th>
<th class="duration-col">Duration</th>
<th class="preview-col">Preview</th>
</tr>
</thead>
<tbody id="resultsBody">
</tbody>
</table>
<div class="results-controls" aria-label="Preview controls">
<div class="volume-control">
<label for="soundfontVolume">Preview volume</label>
<input type="range" id="soundfontVolume" min="0" max="1" step="0.01" value="0.7" />
</div>
<div class="actions">
<button id="soundfontStopBtn" disabled>Stop preview</button>
<button id="nextResultBtn" class="next-result" disabled>Try Next Result</button>
</div>
</div>
</div>
<div id="playerSection" class="player-section">
<div id="selectedInfo" class="player-info">
<h4 id="selectedTitle">No MIDI selected</h4>
<p id="selectedMeta">Select a MIDI file from search results to enable playback</p>
</div>
<div class="section">
<div class="section-header">
<h3 class="section-title">Synthesis Engine</h3>
<p class="section-subtitle">Run it through the Gameboy emulator.</p>
</div>
<div class="divider"></div>
<div class="motif-stage">
<div class="motif-grid">
<div class="motif-header">
<h4 style="margin:0; color:#ffaa44; text-shadow: 0 0 18px rgba(255,170,68,0.15);">Run the engine</h4>
<p class="motif-kicker">Gameboy MIDI synthesis. Triangle, square, and sawtooth waveforms. Polyphonic 8-bit chiptune generation.</p>
</div>
<div class="motif-controls">
<button id="motifBtn" class="primary" disabled>Generate & Play</button>
<button id="motifStopBtn" disabled>Stop</button>
<button id="copyLinkBtn" type="button" disabled>Copy link</button>
<div class="volume-control">
<label for="motifVolume">Volume</label>
<input type="range" id="motifVolume" min="0" max="1" step="0.01" value="0.7" />
</div>
</div>
<div id="iosAudioBanner" class="ios-audio-banner" aria-live="polite">
<div class="row">
<div class="copy">
<strong>iOS Safari:</strong> tap once to enable audio, then press <strong>Generate &amp; Play</strong>.
</div>
<button id="enableAudioBtn" type="button">Enable Audio</button>
</div>
<div id="iosAudioState" class="state">Audio: …</div>
</div>
<div class="motif-progress-container" id="motifProgressContainer" style="display: none;">
<div class="progress-time">
<span id="motifCurrentTime">0:00</span>
<span id="motifDuration">0:00</span>
</div>
<div class="progress-bar-wrapper">
<input type="range" id="motifProgressBar" class="progress-bar" min="0" max="100" value="0" step="0.1" />
<div class="progress-fill" id="motifProgressFill"></div>
</div>
</div>
</div>
</div>
</div>
<div class="section" id="embedSection" data-not-live="true" style="display:none;">
<div class="section-header">
<h3 class="section-title">Use on your website <span style="color: rgba(255,255,255,0.5); font-weight: 500;">(Coming soon)</span></h3>
<p class="section-subtitle">Embeddable widget + multiple synth engines.</p>
</div>
<div class="divider"></div>
<div class="embed-card" style="opacity:0.55; filter: grayscale(20%); position:relative;">
<div style="position:absolute; inset:0; background: linear-gradient(90deg, rgba(0,0,0,0.35), rgba(0,0,0,0)); pointer-events:none;"></div>
<div class="embed-row">
<pre class="codeblock"><code id="embedCode">&lt;iframe src=&quot;...&quot;&gt;&lt;/iframe&gt;</code></pre>
<div style="display:flex; flex-direction:column; gap: calc(var(--spacing-unit) * 1.5);">
<button id="copyEmbedBtn" class="primary" type="button" disabled>Copy embed</button>
<span id="copyToast" class="copy-toast">Copied</span>
</div>
</div>
<div class="embed-hint">
<strong>Note:</strong> This is not live yet. Well ship a dedicated <code>/embed</code> widget + style presets next.
</div>
</div>
</div>
</div>
</div>
<div id="faqModalBackdrop" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="faqTitle">
<div class="modal" role="document">
<header>
<h3 id="faqTitle">FAQ</h3>
<nav class="faq-header-links" aria-label="FAQ links">
<a href="https://x.com/b1rdmania" target="_blank" rel="noopener noreferrer" aria-label="Open @b1rdmania on X">
<span class="dot" aria-hidden="true"></span>
<span class="label"><span class="handle">@b1rdmania</span><span aria-hidden="true">X</span></span>
</a>
<a href="https://github.com/b1rdmania/motif" target="_blank" rel="noopener noreferrer" aria-label="Open the MOTIF GitHub repository">
<span class="dot" aria-hidden="true"></span>
<span class="label">GitHub</span>
</a>
</nav>
<div class="spacer"></div>
<button id="faqCloseBtn" type="button">Close</button>
</header>
<main>
<div class="faq-grid">
<div class="faq-item">
<h4>What is MOTIF?</h4>
<p>Turn any song into retro <strong>Gameboy-style</strong> synth. Search a track, preview the MIDI, hit Generate.</p>
</div>
<div class="faq-item">
<h4>How does it work?</h4>
<p>We scrape MIDI files from the web, analyse the structure (melody, bass, chords), then resynthesise with an emulation engine. Light touch and runs in any browser through <strong>Web Audio</strong>.</p>
</div>
<div class="faq-item">
<h4>Why "Enable Audio" on iPhone?</h4>
<p>Apple blocks sound until you tap something. Just hit the button once — you're good. Still silent? Check your ringer switch isn't on mute.</p>
</div>
<div class="faq-item">
<h4>Ps. I love Claude Code.</h4>
<img src="/wario.png" alt="Wario moment" style="margin-top: 8px; border-radius: 8px; max-width: 100%; opacity: 0.85;" />
</div>
</div>
</main>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>