B-Side Audio and Vision

Sound.
Code.
Vision.

Musikproduktion · Mixing & Mastering · IT-Lösungen

Über mich

Hey, ich bin Ben.

20 Jahre alt. Musikproduzent, Mixing & Mastering Engineer, IT-Developer — und Gründer von B-Side Audio and Vision.

Seit knapp 3 Jahren produziere ich Musik und verfeinere Sounds bis ins kleinste Detail. Parallel studiere ich Informatik und baue Websites, Skripte und individuelle Software-Lösungen.

B-Side steht für die andere Seite — die, die oft mehr Charakter hat als die A-Seite.

Musik

Meine Beats

Track auswählen — Nadel drauf.

● Jetzt läuft
Track auswählen
B-Side Audio and Vision
— BPM
0:00
0:00
IT-Lösungen

Digitale Lösungen

src/components/VinylPlayer.astroCode aus dieser Seite
---export interface Track {  title: string;  meta: string;  bpm: number;  duration: number;  color: string;  src?: string; }export interface Props {  tracks: Track[];}const { tracks } = Astro.props;---Zeile 17–484: Markup & CSS<script define:vars={{ tracks }}>  const ARM_PARKED = -30;  const ARM_START  = -25;  const ARM_END    = 10;  let currentTrack = null;  let isPlaying    = false;  let progress     = 0;  let ticker       = null;  let bpmTicker    = null;  let waveHeights  = [];  let audio        = null;  const vinyl        = document.getElementById('vinyl');  const tonearm      = document.getElementById('tonearm');  const platterRing  = document.getElementById('platterRing');  const playBtn      = document.getElementById('playBtn');  const playIcon     = document.getElementById('playIcon');  const volIconBtn   = document.getElementById('volIconBtn');  const volIcon      = document.getElementById('volIcon');  const trackTitle   = document.getElementById('trackTitle');  const trackMeta    = document.getElementById('trackMeta');  const bpmLabel     = document.getElementById('bpmLabel');  const bpmDot       = document.getElementById('bpmDot');  const nowPlaying   = document.getElementById('nowPlayingLabel');  const progressFill = document.getElementById('progressFill');  const timeElapsed  = document.getElementById('timeElapsed');  const timeTotal    = document.getElementById('timeTotal');  const waveformEl   = document.getElementById('waveform');  let lastVolume = 0.8;  function fmt(s) {    return Math.floor(s/60) + ':' + String(Math.floor(s%60)).padStart(2,'0');  }  function pctToAngle(pct) {    return ARM_START + (ARM_END - ARM_START) * (pct / 100);  }  function setArm(deg) {    tonearm.style.transform = 'rotate(' + deg + 'deg)';  }  function genWave() {    waveHeights = Array.from({length: 48}, () => 8 + Math.random() * 36);    waveformEl.innerHTML = '';    waveHeights.forEach(h => {      const b = document.createElement('div');      b.style.cssText = `flex:1;height:${h}px;min-height:4px;border-radius:2px;background:var(--wave-unplayed,rgba(255,255,255,0.18));transition:background 0.15s;`;      waveformEl.appendChild(b);    });  }  function drawWave(pct) {    const bars = waveformEl.children;    const played = Math.floor((pct / 100) * waveHeights.length);    for (let i = 0; i < bars.length; i++) {      bars[i].style.background = i < played ? 'var(--accent)'        : i === played && isPlaying ? 'var(--accent)'        : 'var(--wave-unplayed, rgba(255,255,255,0.18))';    }  }  //reduced motion keeps only the fade  const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');  function revealTrackInfo() {    const frames = reduceMotion.matches      ? [{ opacity: 0 }, { opacity: 1 }]      : [{ opacity: 0, transform: 'translateY(6px)' }, { opacity: 1, transform: 'none' }];    [trackTitle, trackMeta].forEach((el, i) => el.animate(frames, {      duration: 240,      delay: i * 40,      easing: 'cubic-bezier(0.23, 1, 0.32, 1)',      fill: 'backwards',    }));  }  function hexRgba(hex, a) {    const r = parseInt(hex.slice(1,3),16);    const g = parseInt(hex.slice(3,5),16);    const b = parseInt(hex.slice(5,7),16);    return 'rgba('+r+','+g+','+b+','+a+')';  }  function selectTrack(i) {    if (currentTrack === i && isPlaying) { pause(); return; }    currentTrack = i;    progress = 0;    const t = tracks[i];    document.querySelectorAll('.track-btn').forEach((b,j) =>      b.classList.toggle('active', j === i));    trackTitle.textContent = t.title;    trackMeta.textContent  = t.meta;    revealTrackInfo();    bpmLabel.textContent   = t.bpm + ' BPM';    timeTotal.textContent  = fmt(t.duration);    nowPlaying.classList.add('visible');    document.documentElement.style.setProperty('--accent', t.color);    document.documentElement.style.setProperty('--accent-dim', hexRgba(t.color, 0.1));    vinyl.style.setProperty('--glow-color', hexRgba(t.color, 0.20));    vinyl.style.setProperty('--glow-color-soft', hexRgba(t.color, 0.08));    //audio support    if (audio) { audio.pause(); audio = null; }    if (t.src) {      audio = new Audio(t.src);      audio.volume = document.getElementById('volSlider').value / 100;    }    genWave();    drawWave(0);    play();  }  function play() {    isPlaying = true;    vinyl.classList.add('playing');    vinyl.style.animationPlayState = 'running';    platterRing.classList.add('active');    playIcon.innerHTML = '<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>';    setArm(pctToAngle(progress));    if (audio) audio.play().catch(() => {});    // bpm pulse    clearInterval(bpmTicker);    bpmTicker = setInterval(() => {      bpmDot.style.transform = 'scale(1.5)';      const c = tracks[currentTrack].color;      vinyl.style.boxShadow = `0 0 0 2px #222, 0 0 40px rgba(0,0,0,0.8), 0 0 70px ${hexRgba(c,0.20)}, 0 0 110px ${hexRgba(c,0.07)}`;      const beatMs = (60 / tracks[currentTrack].bpm) * 1000 * 0.5;      setTimeout(() => {        bpmDot.style.transform = '';        vinyl.style.boxShadow = '';      }, beatMs);    }, (60 / tracks[currentTrack].bpm) * 1000);    // progress tick    clearInterval(ticker);    const t = tracks[currentTrack];    if (audio) {      // sync with audio      ticker = setInterval(() => {        if (!audio) return;        progress = (audio.currentTime / audio.duration) * 100 || 0;        progressFill.style.width = progress + '%';        timeElapsed.textContent  = fmt(audio.currentTime);        drawWave(progress);        setArm(pctToAngle(progress));        if (audio.ended) {          clearInterval(ticker);          clearInterval(bpmTicker);          nextTrack();        }      }, 100);    } else {      // simulated progress      const stepPerTick = (100 / t.duration) * 0.1;      ticker = setInterval(() => {        progress = Math.min(progress + stepPerTick, 100);        progressFill.style.width = progress + '%';        timeElapsed.textContent  = fmt((progress / 100) * t.duration);        drawWave(progress);        setArm(pctToAngle(progress));        if (progress >= 100) {          clearInterval(ticker);          clearInterval(bpmTicker);          nextTrack();        }      }, 100);    }  }  function pause() {    isPlaying = false;    vinyl.style.animationPlayState = 'paused';    platterRing.classList.remove('active');    clearInterval(ticker);    clearInterval(bpmTicker);    playIcon.innerHTML = '<path d="M8 5v14l11-7z"/>';    if (audio) audio.pause();  }  function nextTrack() {    setArm(ARM_PARKED);    const next = currentTrack + 1;    if (next >= tracks.length) {      setTimeout(() => {        isPlaying = false;        vinyl.classList.remove('playing');        vinyl.style.animationPlayState = '';        platterRing.classList.remove('active');        playIcon.innerHTML = '<path d="M8 5v14l11-7z"/>';        progress = 0;        progressFill.style.width = '0%';        timeElapsed.textContent = fmt(0);        drawWave(0);      }, 600);    } else {      setTimeout(() => selectTrack(next), 600);    }  }  function prevTrack() {    setArm(ARM_PARKED);    setTimeout(() => selectTrack((currentTrack - 1 + tracks.length) % tracks.length), 600);  }  // events  playBtn.onclick = () => {    if (currentTrack === null) { selectTrack(0); return; }    if (isPlaying) pause(); else play();  };  document.getElementById('nextBtn').onclick = nextTrack;  document.getElementById('prevBtn').onclick = prevTrack;  document.getElementById('progressBar').onclick = (e) => {    if (currentTrack === null) return;    const rect = e.currentTarget.getBoundingClientRect();    progress = Math.max(0, Math.min(100, ((e.clientX - rect.left) / rect.width) * 100));    progressFill.style.width = progress + '%';    timeElapsed.textContent = fmt((progress/100) * tracks[currentTrack].duration);    if (audio) audio.currentTime = (progress / 100) * audio.duration;    drawWave(progress);    setArm(pctToAngle(progress));  };  waveformEl.onclick = (e) => {    if (currentTrack === null) return;    const rect = waveformEl.getBoundingClientRect();    progress = Math.max(0, Math.min(100, ((e.clientX - rect.left) / rect.width) * 100));    progressFill.style.width = progress + '%';    timeElapsed.textContent = fmt((progress / 100) * tracks[currentTrack].duration);    if (audio) audio.currentTime = (progress / 100) * audio.duration;    drawWave(progress);    setArm(pctToAngle(progress));  };  document.getElementById('volSlider').oninput = (e) => {    const v = Number(e.target.value);    if (audio) audio.volume = v / 100;    volIcon.textContent = v === 0 ? '🔇' : '🔈';    if (v > 0) lastVolume = v / 100;  };  volIconBtn.addEventListener('click', () => {    const slider = document.getElementById('volSlider');    const currentVolume = Number(slider.value);    if (currentVolume !== 0) {      lastVolume = currentVolume / 100;      slider.value = '0';      if (audio) audio.volume = 0;      volIcon.textContent = '🔇';    } else {      slider.value = String(Math.round(lastVolume * 100));      if (audio) audio.volume = lastVolume;      volIcon.textContent = '🔈';    }  });  document.querySelectorAll('.track-btn').forEach((btn, i) => {    btn.onclick = () => selectTrack(i);  });  // init  setArm(ARM_PARKED);  genWave();  drawWave(0);</script>

Webentwicklung

Moderne, schnelle Websites & Web-Apps — von der Landing Page bis zum kompletten Auftritt.

Skripte & Automatisierung

Wiederkehrende Aufgaben automatisieren, APIs anbinden, Workflows optimieren.

Software & Tools

Individuelle Programme und Tools die genau das machen was du brauchst — nicht mehr, nicht weniger.

Visual

Bild & Video

Video ist für mich kein Add-on — es ist ein eigenes Handwerk. Musikvideos, cineastische Kurzfilme, Content für Artists und Brands. Daran habe ich großes Interesse und Lust auf echte Projekte.

In Arbeit — bald mehr
  • 01Musikvideos
  • 02Kurzfilme & Content
  • 03Skripte & Ideen
  • 04Schnitt & Color Grading
Kontakt

Lass uns zusammenarbeiten

Egal ob Musikprojekt, Website oder IT-Lösung — schreib mir einfach.

oder