sleepgennnnn / index.html
Wavetype's picture
Update index.html
6fad337 verified
<!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>Baarons Beats | Bubble Drum Pad</title>
<style>
:root {
--ios-white: #fbfbfd;
--ios-glass: rgba(255, 255, 255, 0.7);
--ios-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
--accent-blue: #007aff;
--accent-red: #ff3b30;
}
body {
margin: 0;
padding: 0;
background-color: #f2f2f7;
background-image: radial-gradient(circle at top right, #ffffff, #e5e5e5);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
color: #1d1d1f;
min-height: 100vh;
overflow-x: hidden;
}
/* Splash / App Launcher Overlay */
#appLauncher {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
z-index: 1000;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: opacity 0.5s ease, visibility 0.5s;
}
.app-icon-large {
width: 120px;
height: 120px;
background: linear-gradient(145deg, #007aff, #0056b3);
border-radius: 28px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 20px 40px rgba(0,122,255,0.3);
margin-bottom: 24px;
}
.app-icon-large span {
color: white;
font-size: 40px;
font-weight: bold;
}
.launch-btn {
background: var(--accent-blue);
color: white;
border: none;
padding: 16px 32px;
border-radius: 18px;
font-size: 18px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0,122,255,0.2);
}
/* Main Container */
.app-container {
max-width: 1000px;
margin: 20px auto;
padding: 20px;
background: var(--ios-glass);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 40px;
border: 1px solid rgba(255, 255, 255, 0.8);
box-shadow: var(--ios-shadow);
position: relative;
display: none; /* Hidden until "Open" */
}
.logo-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 180px;
height: 180px;
background: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-shadow: 0 10px 25px rgba(0,0,0,0.05);
z-index: 10;
border: 1px solid rgba(0,0,0,0.03);
pointer-events: none;
}
.logo-text {
font-weight: 700;
text-transform: lowercase;
font-size: 1.2rem;
letter-spacing: -0.5px;
color: #333;
}
header h1 {
text-align: center;
font-weight: 600;
font-size: 2rem;
margin: 10px 0 20px 0;
letter-spacing: -1px;
}
.canvas-area {
position: relative;
width: 100%;
height: 500px;
margin-bottom: 30px;
background: rgba(255, 255, 255, 0.4);
border-radius: 30px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.5);
touch-action: none;
}
.bubble {
position: absolute;
width: 28px;
height: 28px;
border-radius: 50%;
background: rgba(0, 122, 255, 0.15);
border: 1.5px solid rgba(0, 122, 255, 0.3);
cursor: pointer;
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
.bubble.active {
animation: flash 0.3s ease-out;
background: var(--accent-blue) !important;
box-shadow: 0 0 20px rgba(0, 122, 255, 0.6);
}
@keyframes flash {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.6); opacity: 0.7; }
100% { transform: scale(1); opacity: 1; }
}
.controls-bar {
position: absolute;
bottom: 20px;
left: 5%;
width: 90%;
display: flex;
gap: 8px;
background: rgba(255, 255, 255, 0.85);
padding: 12px;
border-radius: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
backdrop-filter: blur(10px);
z-index: 20;
overflow-x: auto;
scrollbar-width: none;
}
.control-btn {
background: #e9e9eb;
color: #1d1d1f;
border: none;
padding: 10px 16px;
border-radius: 12px;
font-weight: 500;
font-size: 13px;
cursor: pointer;
white-space: nowrap;
}
.control-btn.active {
background: var(--accent-red);
color: white;
}
.upload-section {
background: white;
border-radius: 24px;
padding: 20px;
margin-top: 20px;
}
.file-input-label {
background: var(--accent-blue);
color: white;
padding: 10px 20px;
border-radius: 14px;
cursor: pointer;
display: inline-block;
font-weight: 500;
}
#mp3UploadInput { display: none; }
.song-item {
background: #f2f2f7;
padding: 6px 12px;
border-radius: 10px;
font-size: 11px;
display: inline-flex;
align-items: center;
margin: 4px;
}
.song-color { width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
footer { text-align: center; margin: 20px 0; opacity: 0.4; font-size: 11px; }
@media (max-width: 600px) {
.app-container { margin: 0; border-radius: 0; min-height: 100vh; }
.canvas-area { height: 60vh; }
.logo-circle { width: 120px; height: 120px; font-size: 0.8rem; }
}
</style>
</head>
<body>
<div id="appLauncher">
<div class="app-icon-large"><span>BB</span></div>
<h2 style="margin-bottom: 30px; font-weight: 600;">Baarons Beats</h2>
<button class="launch-btn" onclick="openInApp()">Open in App</button>
</div>
<div class="app-container" id="mainApp">
<header>
<h1>baarons beats</h1>
</header>
<section class="canvas-area">
<div class="logo-circle">
<div class="logo-text">baarons<br>beats</div>
</div>
<div id="bubblesCtn" style="position:absolute; top:0; left:0; width:100%; height:100%;"></div>
<div class="controls-bar">
<button id="playBtn" class="control-btn">Play</button>
<button id="recordBtn" class="control-btn">Record</button>
<button id="stopBtn" class="control-btn">Stop</button>
<button id="loopBtn" class="control-btn">Loop</button>
<button id="structureBtn" class="control-btn">Layout</button>
<select id="patternSelect" style="border-radius:10px; border:none; background:#e9e9eb; padding:5px 10px;">
<option value="">Pattern</option>
<option value="rock">Rock</option>
<option value="hiphop">Hip-Hop</option>
<option value="house">House</option>
</select>
<div style="display:flex; align-items:center; gap:8px; font-size:12px; padding-left: 10px;">
<input type="range" id="tempoSlider" min="60" max="240" value="120" style="width: 80px;">
<span id="tempoValue">120</span>
</div>
</div>
</section>
<section class="upload-section">
<h3 style="margin-top:0; font-size: 16px;">Sound Engine</h3>
<label for="mp3UploadInput" class="file-input-label">Upload Samples</label>
<input type="file" id="mp3UploadInput" multiple accept="audio/mp3">
<button id="resetBubblesBtn" class="control-btn" style="float:right">Reset</button>
<div id="uploadedSongsCtn" style="margin-top:15px;"></div>
</section>
<footer>
© 2026 Baarons Beats
</footer>
</div>
<script>
const drumSounds = ["Kick", "Snare", "Hi-Hat", "Crash", "Tom", "Clap", "Ride", "Cowbell", "Bass", "Perc", "Shaker", "Tamb", "Cymbal", "Conga", "Bongo", "Triangle", "Wood", "Metal", "Glass", "Water", "Wind", "Thunder", "Fire", "Ice", "Electric", "Acoustic", "Synth", "Analog", "Digital", "Vintage", "Modern", "Futuristic", "Soft", "Hard", "Sharp", "Mellow", "Bright", "Dark", "Warm", "Cool", "Short", "Long", "Fast", "Slow", "High", "Low", "Mid", "Full", "Punchy", "Smooth", "Rough", "Clean", "Dirty", "Wet", "Dry", "Echo", "Reverb", "Delay", "Flange", "Phaser", "Chorus", "Distort", "Boost", "Cut", "Beat", "Rhythm", "Tempo", "Groove", "Swing", "Sync", "Pulse", "Vibe", "Hit", "Strike", "Tap", "Slap", "Bang", "Crack", "Pop", "Snap", "Boom", "Bap", "Tss", "Chk", "Clack", "Click", "Clunk", "Thud", "Zap", "Zing", "Zip", "Zoom", "Whiz", "Wham", "Pow", "Bam", "Whack", "Smash", "Clash", "Bash", "Ting", "Ping", "Pong", "Ding", "Dong", "Bing", "Bong", "Ring", "Tock", "Tick", "Tack", "Tuk", "Tok", "Tak", "Tek", "Tik", "Drum", "Pad", "Machine", "Beatbox", "Sampler", "Sequencer", "Mixer", "Console", "Audio", "Sound", "Wave", "Tone", "Pitch", "Volume", "Pan", "Effect", "Loop", "Pattern", "Sequence", "Track", "Channel", "Bus", "Send", "Return", "Input", "Output", "Mono", "Stereo", "Surround", "Spatial", "3D", "Ambient"];
let audioContext = null;
let isRecording = false;
let isPlaying = false;
let isLooping = false;
let recordedEvents = [];
let recordStartTime = 0;
let playbackTimeout = null;
let currentTempo = 120;
let bubbles = [];
let currentLayout = 'circle';
let uploadedSongs = [];
let bubbleSnippets = [];
function openInApp() {
// Initialize Audio Context on User Gesture
audioContext = new (window.AudioContext || window.webkitAudioContext)();
document.getElementById('appLauncher').style.opacity = '0';
setTimeout(() => {
document.getElementById('appLauncher').style.visibility = 'hidden';
document.getElementById('mainApp').style.display = 'block';
initBubbles();
}, 500);
}
function initBubbles() {
const container = document.getElementById('bubblesCtn');
const centerX = container.offsetWidth / 2;
const centerY = container.offsetHeight / 2;
const maxRadius = Math.min(centerX, centerY) - 40;
const rings = 7;
const bubblesPerRing = Math.ceil(drumSounds.length / rings);
container.innerHTML = '';
bubbles = [];
bubbleSnippets = [];
for (let i = 0; i < drumSounds.length; i++) {
const ring = Math.floor(i / bubblesPerRing);
const posInRing = i % bubblesPerRing;
const radius = (ring + 1) * (maxRadius / rings);
const angle = (posInRing / bubblesPerRing) * Math.PI * 2;
const x = centerX + radius * Math.cos(angle);
const y = centerY + radius * Math.sin(angle);
const bubble = document.createElement('div');
bubble.className = 'bubble';
bubble.style.left = `${x - 14}px`;
bubble.style.top = `${y - 14}px`;
bubble.dataset.index = i;
bubble.dataset.frequency = 80 + Math.random() * 800;
bubble.dataset.duration = 0.1 + Math.random() * 0.4;
bubble.dataset.waveform = ['sine', 'triangle'][Math.floor(Math.random()*2)];
const triggerSound = () => {
playBubbleSound(bubble);
if (isRecording) {
const timeSinceStart = audioContext.currentTime - recordStartTime;
recordedEvents.push({ time: timeSinceStart, bubbleIndex: i });
}
};
bubble.onmousedown = triggerSound;
bubble.ontouchstart = (e) => {
e.preventDefault();
triggerSound();
};
container.appendChild(bubble);
bubbles.push(bubble);
bubbleSnippets.push(null);
}
}
function playBubbleSound(bubble, scheduledTime = null) {
const index = parseInt(bubble.dataset.index);
bubble.classList.add('active');
setTimeout(() => bubble.classList.remove('active'), 300);
if (audioContext.state === 'suspended') audioContext.resume();
if (bubbleSnippets[index]) {
const snippet = bubbleSnippets[index];
const source = audioContext.createBufferSource();
source.buffer = snippet.audioBuffer;
const gain = audioContext.createGain();
gain.gain.value = 0.7;
source.connect(gain);
gain.connect(audioContext.destination);
source.start(scheduledTime || audioContext.currentTime, snippet.startTime, snippet.duration);
return;
}
const osc = audioContext.createOscillator();
const gain = audioContext.createGain();
osc.type = bubble.dataset.waveform;
osc.frequency.setValueAtTime(bubble.dataset.frequency, audioContext.currentTime);
gain.gain.setValueAtTime(0.3, audioContext.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + parseFloat(bubble.dataset.duration));
osc.connect(gain);
gain.connect(audioContext.destination);
const start = scheduledTime || audioContext.currentTime;
osc.start(start);
osc.stop(start + parseFloat(bubble.dataset.duration));
}
function playRecordedSequence() {
if (recordedEvents.length === 0) return;
isPlaying = true;
document.getElementById('playBtn').textContent = "Playing...";
const tempoFactor = 120 / currentTempo;
const sequenceDuration = recordedEvents.reduce((max, e) => Math.max(max, e.time), 0) * tempoFactor + 0.5;
recordedEvents.forEach(event => {
const scheduledTime = audioContext.currentTime + (event.time * tempoFactor);
if (bubbles[event.bubbleIndex]) {
setTimeout(() => {
if(isPlaying) playBubbleSound(bubbles[event.bubbleIndex]);
}, event.time * tempoFactor * 1000);
}
});
if (isLooping) {
playbackTimeout = setTimeout(playRecordedSequence, sequenceDuration * 1000);
} else {
playbackTimeout = setTimeout(stopPlayback, sequenceDuration * 1000);
}
}
function stopPlayback() {
isPlaying = false;
if (playbackTimeout) clearTimeout(playbackTimeout);
document.getElementById('playBtn').textContent = "Play";
}
document.getElementById('playBtn').onclick = () => { if (!isPlaying) playRecordedSequence(); };
document.getElementById('stopBtn').onclick = stopPlayback;
document.getElementById('loopBtn').onclick = function() {
isLooping = !isLooping;
this.classList.toggle('active', isLooping);
};
document.getElementById('recordBtn').onclick = function() {
isRecording = !isRecording;
if (isRecording) {
recordedEvents = [];
recordStartTime = audioContext.currentTime;
this.classList.add('active');
this.textContent = "REC...";
} else {
this.classList.remove('active');
this.textContent = "Record";
}
};
document.getElementById('structureBtn').onclick = function() {
const container = document.getElementById('bubblesCtn');
if (currentLayout === 'circle') {
const cols = 12;
bubbles.forEach((b, i) => {
b.style.left = `${(i % cols) * 35 + 20}px`;
b.style.top = `${Math.floor(i / cols) * 35 + 20}px`;
});
currentLayout = 'grid';
} else {
initBubbles();
currentLayout = 'circle';
}
};
document.getElementById('tempoSlider').oninput = function() {
currentTempo = this.value;
document.getElementById('tempoValue').textContent = this.value;
};
document.getElementById('mp3UploadInput').onchange = function(e) {
const files = e.target.files;
for (let file of files) {
const reader = new FileReader();
reader.onload = (ev) => {
audioContext.decodeAudioData(ev.target.result, (buffer) => {
const song = { audioBuffer: buffer, color: `hsl(${Math.random()*360}, 70%, 60%)`, name: file.name };
uploadedSongs.push(song);
const item = document.createElement('div');
item.className = 'song-item';
item.innerHTML = `<div class="song-color" style="background:${song.color}"></div>${song.name.substring(0,8)}`;
document.getElementById('uploadedSongsCtn').appendChild(item);
assignSnippets();
});
};
reader.readAsArrayBuffer(file);
}
};
function assignSnippets() {
for (let i = 0; i < 15; i++) {
const idx = Math.floor(Math.random() * bubbles.length);
const song = uploadedSongs[Math.floor(Math.random() * uploadedSongs.length)];
bubbleSnippets[idx] = {
audioBuffer: song.audioBuffer,
startTime: Math.random() * (song.audioBuffer.duration - 1),
duration: 0.2 + Math.random() * 0.5
};
bubbles[idx].style.background = song.color;
bubbles[idx].style.borderColor = "white";
}
}
document.getElementById('resetBubblesBtn').onclick = () => { location.reload(); };
</script>
</body>
</html>