71762c07f8
- Flip from dark to light authentic Game Boy LCD palette - Update both main app (index.html) and share page (play.html) - Light background (#C8D8B0) with dark text (#1D2A1D) - Keep results interactive after selecting a song - Remove search locking so users can always search or pick different results 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1183 lines
38 KiB
HTML
1183 lines
38 KiB
HTML
<!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>WARIO SYNTH - Retro Game Console Music</title>
|
||
|
||
<!-- OpenGraph / Social Media Preview -->
|
||
<meta property="og:title" content="WARIO SYNTH">
|
||
<meta property="og:description" content="Turn any song into retro game console music">
|
||
<meta property="og:image" content="/wario.png">
|
||
<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="WARIO SYNTH">
|
||
<meta name="twitter:description" content="Turn any song into retro game console music">
|
||
<meta name="twitter:image" content="/wario.png">
|
||
|
||
<!-- General Meta -->
|
||
<meta name="description" content="WARIO SYNTH - Transform any song into retro Gameboy-style game console music. Search, preview MIDI, and generate chiptune versions.">
|
||
|
||
<!-- Pixel Font -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
|
||
|
||
<style>
|
||
/* Design System: Game Boy DMG - Authentic light LCD look */
|
||
:root {
|
||
/* Game Boy palette - light mode (authentic LCD) */
|
||
--gb-lightest: #E0E8C8; /* Screen background */
|
||
--gb-light: #A8B89A; /* Surface/cards */
|
||
--gb-medium: #6B7B5A; /* Dim text, borders */
|
||
--gb-dark: #3A4A2A; /* Text */
|
||
--gb-darkest: #1D2A1D; /* Darkest accents */
|
||
|
||
/* Console shell colors */
|
||
--gb-shell: #C4CFA1;
|
||
--gb-shell-dark: #8B956D;
|
||
|
||
/* Semantic mapping - LIGHT background, DARK text */
|
||
--color-bg: #C8D8B0;
|
||
--color-surface: #A8B89A;
|
||
--color-surface-elevated: #B8C8A8;
|
||
--color-border: var(--gb-dark);
|
||
--color-text: var(--gb-darkest);
|
||
--color-text-dim: var(--gb-medium);
|
||
--color-accent-primary: var(--gb-dark);
|
||
--color-accent-secondary: var(--gb-medium);
|
||
|
||
--spacing-unit: 8px;
|
||
--radius: 0px; /* Pixel-perfect, no rounding */
|
||
--pixel-border: 4px;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
image-rendering: pixelated;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Press Start 2P', monospace;
|
||
background: var(--color-bg);
|
||
color: var(--color-text);
|
||
margin: 0;
|
||
padding: calc(var(--spacing-unit) * 3);
|
||
line-height: 2;
|
||
font-size: 10px;
|
||
-webkit-font-smoothing: none;
|
||
-moz-osx-font-smoothing: unset;
|
||
}
|
||
|
||
/* LCD Screen Effect - subtle on light bg */
|
||
body::before {
|
||
content: '';
|
||
position: fixed;
|
||
inset: 0;
|
||
background: repeating-linear-gradient(
|
||
0deg,
|
||
rgba(0, 0, 0, 0.03) 0px,
|
||
rgba(0, 0, 0, 0.03) 2px,
|
||
transparent 2px,
|
||
transparent 4px
|
||
);
|
||
pointer-events: none;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.container {
|
||
max-width: 960px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.hero {
|
||
text-align: center;
|
||
margin: 0 0 calc(var(--spacing-unit) * 4) 0;
|
||
position: relative;
|
||
padding: calc(var(--spacing-unit) * 2);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
background: var(--color-surface);
|
||
}
|
||
.hero h1 {
|
||
color: var(--gb-darkest);
|
||
margin: 0;
|
||
font-size: 20px;
|
||
font-weight: normal;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
.hero .tagline {
|
||
margin: calc(var(--spacing-unit) * 2) 0 0 0;
|
||
color: var(--gb-dark);
|
||
font-size: 8px;
|
||
}
|
||
.faq-link {
|
||
background: var(--gb-lightest);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
color: var(--gb-darkest);
|
||
padding: 8px 12px;
|
||
border-radius: 0;
|
||
box-shadow:
|
||
inset -3px -3px 0 var(--gb-medium),
|
||
inset 3px 3px 0 #fff;
|
||
font-size: 8px;
|
||
}
|
||
.faq-link:hover:not(:disabled) {
|
||
background: #fff;
|
||
color: var(--gb-darkest);
|
||
}
|
||
.faq-top {
|
||
position: absolute;
|
||
top: calc(var(--spacing-unit) * 2);
|
||
right: calc(var(--spacing-unit) * 2);
|
||
}
|
||
|
||
/* 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) auto calc(var(--spacing-unit) * 2) auto;
|
||
display: flex;
|
||
gap: calc(var(--spacing-unit) * 1.5);
|
||
align-items: stretch;
|
||
justify-content: center;
|
||
max-width: 720px;
|
||
}
|
||
.controls.locked {
|
||
opacity: 0.35;
|
||
}
|
||
|
||
/* Chunky 8-bit buttons */
|
||
button {
|
||
background: var(--color-surface);
|
||
color: var(--color-text);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
padding: 12px 16px;
|
||
border-radius: 0;
|
||
cursor: pointer;
|
||
font-family: 'Press Start 2P', monospace;
|
||
font-size: 8px;
|
||
text-transform: uppercase;
|
||
box-shadow:
|
||
inset -3px -3px 0 var(--gb-medium),
|
||
inset 3px 3px 0 var(--gb-lightest);
|
||
transition: none;
|
||
}
|
||
|
||
button:hover:not(:disabled) {
|
||
background: var(--gb-lightest);
|
||
color: var(--gb-darkest);
|
||
}
|
||
|
||
button:active:not(:disabled) {
|
||
box-shadow:
|
||
inset 3px 3px 0 var(--gb-medium);
|
||
}
|
||
|
||
button:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
button.primary {
|
||
background: var(--gb-dark);
|
||
color: var(--gb-lightest);
|
||
border-color: var(--gb-darkest);
|
||
box-shadow:
|
||
inset -3px -3px 0 var(--gb-darkest),
|
||
inset 3px 3px 0 var(--gb-medium);
|
||
}
|
||
|
||
button.primary:hover:not(:disabled) {
|
||
background: var(--gb-darkest);
|
||
color: var(--gb-lightest);
|
||
}
|
||
|
||
/* Search button */
|
||
#searchBtn {
|
||
padding: 14px 20px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
/* Status bar - like a Game Boy dialog box */
|
||
#status {
|
||
margin: calc(var(--spacing-unit) * 3) 0;
|
||
padding: calc(var(--spacing-unit) * 2);
|
||
background: var(--gb-lightest);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
color: var(--gb-darkest);
|
||
font-size: 8px;
|
||
min-height: 24px;
|
||
}
|
||
|
||
/* Text input - Game Boy style */
|
||
input[type="text"] {
|
||
flex: 1;
|
||
background: var(--gb-lightest);
|
||
color: var(--gb-darkest);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
padding: 12px 14px;
|
||
border-radius: 0;
|
||
font-family: 'Press Start 2P', monospace;
|
||
font-size: 10px;
|
||
box-shadow: inset 3px 3px 0 var(--gb-medium);
|
||
}
|
||
|
||
input[type="text"]:focus {
|
||
outline: none;
|
||
border-color: var(--gb-darkest);
|
||
background: #fff;
|
||
}
|
||
|
||
input[type="text"]::placeholder {
|
||
color: var(--gb-medium);
|
||
}
|
||
|
||
.results-section {
|
||
margin: 30px 0;
|
||
display: none;
|
||
}
|
||
.results-section.visible {
|
||
display: block;
|
||
}
|
||
.results-section.collapsed {
|
||
opacity: 0.55;
|
||
transition: opacity 160ms ease;
|
||
}
|
||
.results-section.collapsed:hover {
|
||
opacity: 1;
|
||
}
|
||
|
||
.chooser-helper {
|
||
margin-top: calc(var(--spacing-unit) * 2);
|
||
padding: calc(var(--spacing-unit) * 2);
|
||
background: var(--color-surface);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
}
|
||
.chooser-helper h4 {
|
||
margin: 0 0 8px 0;
|
||
font-size: 8px;
|
||
text-transform: uppercase;
|
||
color: var(--gb-darkest);
|
||
}
|
||
.chooser-helper p {
|
||
margin: 0;
|
||
font-size: 8px;
|
||
color: var(--gb-dark);
|
||
line-height: 2;
|
||
}
|
||
|
||
/* Results table - Game Boy menu style */
|
||
.results-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: calc(var(--spacing-unit) * 2) 0;
|
||
background: var(--color-surface);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
}
|
||
|
||
.results-table th,
|
||
.results-table td {
|
||
padding: 12px 16px;
|
||
text-align: left;
|
||
border-bottom: 2px solid var(--gb-medium);
|
||
font-size: 8px;
|
||
color: var(--gb-darkest);
|
||
}
|
||
|
||
.results-table th {
|
||
background: var(--gb-dark);
|
||
color: var(--gb-lightest);
|
||
font-weight: normal;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.results-table .source-col {
|
||
width: 100px;
|
||
text-align: center;
|
||
}
|
||
|
||
.results-table .duration-col {
|
||
width: 80px;
|
||
text-align: right;
|
||
}
|
||
.results-table .action-col {
|
||
width: 120px;
|
||
text-align: right;
|
||
}
|
||
|
||
.results-table tbody tr {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.results-table tbody tr:hover {
|
||
background: var(--gb-lightest);
|
||
}
|
||
|
||
.results-table tbody tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.results-table tr.selected {
|
||
background: var(--gb-dark);
|
||
color: var(--gb-lightest);
|
||
}
|
||
|
||
.results-table tr.selected td {
|
||
color: var(--gb-lightest);
|
||
}
|
||
|
||
.results-table tr.selected td:first-child {
|
||
padding-left: 12px;
|
||
}
|
||
|
||
/* Selection arrow indicator */
|
||
.results-table tr.selected td:first-child::before {
|
||
content: '▶ ';
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.results-table th,
|
||
.results-table td {
|
||
padding: 10px 12px;
|
||
font-size: 7px;
|
||
}
|
||
|
||
.results-table .source-col {
|
||
display: none;
|
||
}
|
||
|
||
.results-table .duration-col {
|
||
width: 60px;
|
||
}
|
||
|
||
.results-table .action-col {
|
||
width: 90px;
|
||
}
|
||
}
|
||
|
||
.results-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: calc(var(--spacing-unit) * 2);
|
||
flex-wrap: wrap;
|
||
margin: 0 0 calc(var(--spacing-unit) * 2) 0;
|
||
}
|
||
.results-header h3 { margin: 0; }
|
||
|
||
.confidence-bar {
|
||
width: 60px;
|
||
height: 4px;
|
||
background: var(--gb-darkest);
|
||
overflow: hidden;
|
||
}
|
||
.confidence-fill {
|
||
height: 100%;
|
||
background: var(--gb-lightest);
|
||
}
|
||
|
||
/* Selected source card - Game Boy cartridge style */
|
||
.selected-card {
|
||
margin-top: calc(var(--spacing-unit) * 3);
|
||
padding: calc(var(--spacing-unit) * 3);
|
||
background: var(--gb-dark);
|
||
border: var(--pixel-border) solid var(--gb-light);
|
||
}
|
||
.selected-title {
|
||
margin: 0;
|
||
font-size: 12px;
|
||
line-height: 2;
|
||
font-weight: normal;
|
||
color: var(--gb-lightest);
|
||
}
|
||
.selected-meta {
|
||
margin: 12px 0 0 0;
|
||
font-size: 8px;
|
||
color: var(--gb-light);
|
||
}
|
||
.selected-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
margin-top: 16px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.selected-actions .primary {
|
||
flex: 1;
|
||
min-width: 160px;
|
||
padding: 14px 16px;
|
||
}
|
||
.selected-actions button:not(.primary) {
|
||
flex: 1;
|
||
min-width: 140px;
|
||
}
|
||
.selected-support {
|
||
display: flex;
|
||
gap: 16px;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
margin-top: 16px;
|
||
}
|
||
.selected-support .linklike {
|
||
background: transparent;
|
||
border: none;
|
||
padding: 0;
|
||
box-shadow: none;
|
||
color: var(--gb-lightest);
|
||
cursor: pointer;
|
||
font-size: 8px;
|
||
text-decoration: underline;
|
||
}
|
||
.selected-support .linklike:hover {
|
||
color: var(--gb-light);
|
||
}
|
||
.preview-inline {
|
||
display: inline-flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
.preview-state {
|
||
font-size: 8px;
|
||
color: var(--gb-light);
|
||
display: none;
|
||
}
|
||
|
||
/* Copy link button */
|
||
#copyLinkBtn {
|
||
padding: 12px 16px;
|
||
}
|
||
#copyLinkBtn:hover:not(:disabled) {
|
||
background: var(--gb-light);
|
||
color: var(--gb-darkest);
|
||
}
|
||
.engine-line {
|
||
margin-top: 14px;
|
||
color: var(--gb-light);
|
||
font-size: 8px;
|
||
}
|
||
details.details-toggle {
|
||
margin-top: 12px;
|
||
}
|
||
details.details-toggle summary {
|
||
cursor: pointer;
|
||
color: var(--gb-light);
|
||
font-size: 8px;
|
||
list-style: none;
|
||
}
|
||
details.details-toggle summary::-webkit-details-marker { display: none; }
|
||
.selected-details {
|
||
margin-top: 8px;
|
||
font-size: 8px;
|
||
color: var(--gb-light);
|
||
}
|
||
|
||
.footer {
|
||
margin-top: calc(var(--spacing-unit) * 6);
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: calc(var(--spacing-unit) * 1.5);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.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: var(--pixel-border) solid var(--gb-dark);
|
||
border-radius: 0;
|
||
}
|
||
|
||
.player-box:hover {
|
||
background: var(--gb-lightest);
|
||
}
|
||
|
||
.player-box h4 {
|
||
margin: 0 0 calc(var(--spacing-unit)) 0;
|
||
color: var(--gb-darkest);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.player-box p {
|
||
font-size: 13px;
|
||
color: var(--gb-dark);
|
||
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: var(--pixel-border) solid var(--gb-dark);
|
||
}
|
||
.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 {
|
||
background: var(--gb-darkest);
|
||
}
|
||
.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: var(--pixel-border) solid var(--gb-dark);
|
||
background: var(--gb-lightest);
|
||
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: 8px;
|
||
color: var(--gb-dark);
|
||
line-height: 2;
|
||
flex: 1;
|
||
min-width: 220px;
|
||
}
|
||
.ios-audio-banner .copy strong {
|
||
color: var(--gb-darkest);
|
||
}
|
||
.ios-audio-banner .state {
|
||
margin-top: calc(var(--spacing-unit) * 1);
|
||
font-size: 8px;
|
||
color: var(--gb-dark);
|
||
display: none;
|
||
}
|
||
.motif-kicker {
|
||
font-size: 8px;
|
||
color: var(--gb-dark);
|
||
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: 8px;
|
||
color: var(--gb-dark);
|
||
}
|
||
.volume-control input[type="range"] {
|
||
flex: 1;
|
||
margin: 0;
|
||
}
|
||
|
||
.motif-progress-container {
|
||
margin-top: 8px;
|
||
padding-top: 16px;
|
||
border-top: 2px solid var(--gb-light);
|
||
}
|
||
.progress-time {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
font-size: 8px;
|
||
color: var(--gb-light);
|
||
}
|
||
.progress-bar-wrapper {
|
||
position: relative;
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: calc(var(--spacing-unit) * 2) 0;
|
||
}
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 8px;
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
background: transparent;
|
||
border-radius: 0;
|
||
outline: none;
|
||
cursor: pointer;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.progress-bar::-webkit-slider-runnable-track {
|
||
height: 8px;
|
||
background: var(--gb-darkest);
|
||
border-radius: 0;
|
||
}
|
||
|
||
.progress-bar::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 0;
|
||
background: var(--gb-lightest);
|
||
border: 2px solid var(--gb-light);
|
||
cursor: pointer;
|
||
margin-top: -4px;
|
||
}
|
||
|
||
.progress-bar:active::-webkit-slider-thumb {
|
||
background: #fff;
|
||
}
|
||
|
||
.progress-bar::-moz-range-track {
|
||
height: 8px;
|
||
background: var(--gb-darkest);
|
||
border-radius: 0;
|
||
}
|
||
|
||
.progress-bar::-moz-range-thumb {
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 0;
|
||
background: var(--gb-lightest);
|
||
border: 2px solid var(--gb-light);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.progress-fill {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
height: 8px;
|
||
background: var(--gb-light);
|
||
border-radius: 0;
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
width: 0%;
|
||
transition: width 0.1s linear;
|
||
}
|
||
|
||
/* Use on your website */
|
||
.embed-card {
|
||
background: var(--color-surface);
|
||
border: var(--pixel-border) solid var(--gb-dark);
|
||
padding: calc(var(--spacing-unit) * 3);
|
||
}
|
||
.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);
|
||
background: var(--gb-lightest);
|
||
border: 2px solid var(--gb-medium);
|
||
overflow: auto;
|
||
}
|
||
.codeblock code {
|
||
font-size: 8px;
|
||
color: var(--gb-darkest);
|
||
white-space: pre;
|
||
}
|
||
.embed-hint {
|
||
margin-top: calc(var(--spacing-unit) * 1.5);
|
||
color: var(--gb-dark);
|
||
font-size: 8px;
|
||
}
|
||
.embed-hint strong {
|
||
color: var(--gb-darkest);
|
||
}
|
||
.copy-toast {
|
||
margin-left: auto;
|
||
font-size: 8px;
|
||
color: var(--gb-darkest);
|
||
display: none;
|
||
}
|
||
|
||
.engine-selector {
|
||
margin-top: 10px;
|
||
font-size: 8px;
|
||
}
|
||
.engine-selector label {
|
||
color: var(--gb-dark);
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
}
|
||
.engine-selector select {
|
||
background: var(--gb-lightest);
|
||
color: var(--gb-darkest);
|
||
border: 2px solid var(--gb-dark);
|
||
padding: 8px 12px;
|
||
font-family: 'Press Start 2P', monospace;
|
||
font-size: 8px;
|
||
width: 100%;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="hero">
|
||
<button id="faqBtn" class="faq-link faq-top" type="button">FAQ</button>
|
||
<h1>WARIO SYNTH</h1>
|
||
<p class="tagline"><strong>Turn any song into retro game console music</strong></p>
|
||
</div>
|
||
|
||
<div class="controls">
|
||
<input type="text" id="songInput" placeholder="Search for a song…" />
|
||
<button id="searchBtn" class="primary">Search</button>
|
||
</div>
|
||
|
||
<div id="status">Ready. Enter a song name to search for MIDI files.</div>
|
||
|
||
<div id="resultsSection" class="results-section">
|
||
<div id="chooseHelper" class="chooser-helper" style="display:none;">
|
||
<h4>Choosing a MIDI source</h4>
|
||
<p>
|
||
Different MIDI files capture songs differently. Some will produce better results than others.<br />
|
||
Pick a source, generate, and if it sounds off, try another.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="results-header">
|
||
<h3>Search Results</h3>
|
||
</div>
|
||
<table id="resultsTable" class="results-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Song</th>
|
||
<th class="source-col">Source</th>
|
||
<th class="duration-col">Length</th>
|
||
<th class="action-col">Action</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="resultsBody">
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="playerSection" class="player-section">
|
||
<div id="selectedCard" class="selected-card">
|
||
<h2 id="selectedTitle" class="selected-title">No source selected</h2>
|
||
<div id="selectedMeta" class="selected-meta">Search for a song, then choose a source to use.</div>
|
||
|
||
<!-- selected_pre_generate only -->
|
||
<div id="selectedExpectation" class="selected-meta" style="margin-top: 8px;">
|
||
Some MIDI files work better than others. If the result sounds off, try another source.
|
||
</div>
|
||
|
||
<div class="selected-actions" id="preGenActions">
|
||
<button id="motifBtn" class="primary" disabled>Generate music</button>
|
||
</div>
|
||
|
||
<div class="selected-support" id="preGenSupport">
|
||
<div class="preview-inline">
|
||
<button id="previewBtn" type="button" class="linklike" disabled>Preview original MIDI</button>
|
||
<span id="previewState" class="preview-state">Previewing…</span>
|
||
<button id="previewStopBtn" type="button" class="linklike" style="display:none;">Stop preview</button>
|
||
</div>
|
||
<button id="chooseDifferentBtn" type="button" class="linklike">Choose a different source</button>
|
||
</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 music</strong>.
|
||
</div>
|
||
<button id="enableAudioBtn" type="button">Enable Audio</button>
|
||
</div>
|
||
<div id="iosAudioState" class="state">Audio: …</div>
|
||
</div>
|
||
|
||
<!-- generated only: artifact playback + sharing -->
|
||
<div id="generatedBlock" style="display:none;">
|
||
<div style="display:flex; justify-content:center; margin-top: 14px; margin-bottom: 14px;">
|
||
<button id="playPauseBtn" class="primary" type="button">Play</button>
|
||
</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 style="margin-top: 14px;">
|
||
<button id="copyLinkBtn" type="button" disabled>Copy link</button>
|
||
</div>
|
||
</div>
|
||
|
||
<details class="details-toggle" id="detailsToggle">
|
||
<summary>Details</summary>
|
||
<div id="selectedDetails" class="selected-details"></div>
|
||
</details>
|
||
</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"><iframe src="..."></iframe></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. We’ll ship a dedicated <code>/embed</code> widget + style presets next.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
<button id="faqBtnFooter" class="faq-link" type="button">FAQ</button>
|
||
<button id="newSearchBtn" class="faq-link" type="button">New search</button>
|
||
</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 WARIO SYNTH 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 WARIO SYNTH?</h4>
|
||
<p>Turn any song into retro <strong>Gameboy-style</strong> synth using the Wario Synthesis Engine. 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 the <strong>Wario Synthesis Engine</strong>. 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> |