YTPMV Scan - Ultimate Audio Visual Sequencer
About this app
Create chaotic and rhythmic YouTube Poop Music Videos with this interactive scanline sequencer. Upload samples, adjust BPM, and remix live!
YTPMV Scan - Ultimate Audio Visual Sequencer YTPMV SCAN Tap anywhere to initialize Poop Engine... START SCAN CLEAR GRID TEMPO: 130 BPM RANDOMIZE GLITCH UI LOAD BG Add Poop Visuals Instructions: Click/Tap cells to toggle a sound trigger. Each row corresponds to a different classic poop sound. Upload your own image to act as the "source" for your YTPMV. Adjust the tempo for hyper-fast or slow-motion Poops. © 2024 YTPMV Scanner Visual Sequencer - Created for the WebPoopers.
Put this on your site
Source
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>YTPMV Scan - Ultimate Audio Visual Sequencer</title>
<meta name="description" content="Create chaotic and rhythmic YouTube Poop Music Videos with this interactive scanline sequencer. Upload samples, adjust BPM, and remix live!">
<meta name="keywords" content="YTPMV, sequencer, music maker, web audio, scanline, rhythm game, visualizer, audio visual">
<!-- Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" crossorigin="anonymous">
<script type="text/javascript">
try {
// Core Audio Engine
let audioCtx;
let samples = {};
let grid = [];
const ROWS = 8;
const COLS = 16;
let bpm = 130;
let isPlaying = false;
let currentStep = 0;
let nextTickTime = 0;
let lookAhead = 25.0; // ms
let scheduleAheadTime = 0.1; // seconds
let timerID;
// Visual Constants
const COLORS = [
'#ff00ff', '#00ffff', '#ffff00', '#ff0000',
'#00ff00', '#ff8800', '#8800ff', '#ffffff'
];
// Default Sound Links (Creative Commons / Placeholder friendly)
const DEFAULT_SOUNDS = [
{ id: 'bass', url: 'https://actions.google.com/sounds/v1/science_fiction/low_vibrating_hum.ogg' },
{ id: 'snare', url: 'https://actions.google.com/sounds/v1/drums/snare_drum.ogg' },
{ id: 'kick', url: 'https://actions.google.com/sounds/v1/drums/conga_hit.ogg' },
{ id: 'clap', url: 'https://actions.google.com/sounds/v1/foley/beating_on_books.ogg' },
{ id: 'ping', url: 'https://actions.google.com/sounds/v1/alarms/digital_watch_alarm_long.ogg' },
{ id: 'laser', url: 'https://actions.google.com/sounds/v1/science_fiction/sci_fi_door.ogg' },
{ id: 'glitch', url: 'https://actions.google.com/sounds/v1/foley/plastic_crumple.ogg' },
{ id: 'vox', url: 'https://actions.google.com/sounds/v1/cartoon/cartoon_boing.ogg' }
];
async function loadSample(id, url) {
try {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
samples[id] = audioBuffer;
return true;
} catch (e) {
console.error("Failed to load sample:", id, e);
return false;
}
}
function playSample(id, time) {
if (!samples[id]) return;
const source = audioCtx.createBufferSource();
source.buffer = samples[id];
const gainNode = audioCtx.createGain();
gainNode.gain.setValueAtTime(0.7, time);
gainNode.gain.exponentialRampToValueAtTime(0.01, time + 0.5);
source.connect(gainNode);
gainNode.connect(audioCtx.destination);
source.start(time);
}
function initGrid() {
grid = [];
for (let r = 0; r < ROWS; r++) {
grid[r] = new Array(COLS).fill(false);
}
}
function nextStep() {
const secondsPerBeat = 60.0 / bpm / 4; // 16th notes
nextTickTime += secondsPerBeat;
currentStep = (currentStep + 1) % COLS;
}
function scheduler() {
while (nextTickTime < audioCtx.currentTime + scheduleAheadTime) {
scheduleStep(currentStep, nextTickTime);
nextStep();
}
timerID = setTimeout(scheduler, lookAhead);
}
function scheduleStep(step, time) {
for (let r = 0; r < ROWS; r++) {
if (grid[r][step]) {
playSample(`s${r}`, time);
// Visual feedback triggers handled via step class update
}
}
// UI sync
requestAnimationFrame(() => {
$('.cell').removeClass('active-col');
$(`.cell[data-col="${step}"]`).addClass('active-col');
if (grid.some((row, rIdx) => grid[rIdx][step])) {
$(`.cell[data-col="${step}"]`).addClass('impact');
setTimeout(() => {
$(`.cell[data-col="${step}"]`).removeClass('impact');
}, 100);
}
});
}
function togglePlay() {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
initDefaultSamples();
}
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}
isPlaying = !isPlaying;
if (isPlaying) {
nextTickTime = audioCtx.currentTime;
scheduler();
$('#play-btn').html('<i class="fas fa-pause"></i> PAUSE').addClass('btn-danger').removeClass('btn-success');
} else {
clearTimeout(timerID);
$('#play-btn').html('<i class="fas fa-play"></i> START SCAN').addClass('btn-success').removeClass('btn-danger');
$('.cell').removeClass('active-col');
}
}
async function initDefaultSamples() {
$('#status').text("Loading Core Audio Samples...");
for (let i = 0; i < ROWS; i++) {
await loadSample(`s${i}`, DEFAULT_SOUNDS[i % DEFAULT_SOUNDS.length].url);
}
$('#status').text("Ready to Poop! Tap cells to sequence.");
setTimeout(() => $('#status').fadeOut(), 3000);
}
function renderGrid() {
const container = $('#grid-container');
container.empty();
for (let r = 0; r < ROWS; r++) {
const rowDiv = $('<div class="grid-row"></div>');
for (let c = 0; c < COLS; c++) {
const cell = $(`<div class="cell" data-row="${r}" data-col="${c}"></div>`);
cell.css('--cell-color', COLORS[r]);
if (grid[r][c]) cell.addClass('selected');
cell.on('click touchstart', function(e) {
e.preventDefault();
grid[r][c] = !grid[r][c];
$(this).toggleClass('selected');
if (grid[r][c] && audioCtx) playSample(`s${r}`, audioCtx.currentTime);
});
rowDiv.append(cell);
}
container.append(rowDiv);
}
}
document.addEventListener("DOMContentLoaded", function() {
initGrid();
renderGrid();
$('#play-btn').on('click', togglePlay);
$('#bpm-slider').on('input', function() {
bpm = $(this).val();
$('#bpm-val').text(bpm);
});
$('#clear-btn').on('click', function() {
initGrid();
$('.cell').removeClass('selected');
});
$('#random-btn').on('click', function() {
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
grid[r][c] = Math.random() > 0.85;
}
}
renderGrid();
});
$('#glitch-btn').on('click', function() {
$('body').addClass('glitch-effect');
setTimeout(() => $('body').removeClass('glitch-effect'), 500);
});
// Add image background feature
$('#img-upload').on('change', function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
$('#grid-container').css('background-image', `url(${event.target.result})`);
$('#grid-container').css('background-size', 'cover');
$('#grid-container').css('background-position', 'center');
};
reader.readAsDataURL(file);
}
});
});
} catch (error) {
console.error("YTPMV Global Error:", error);
throw error;
}
</script>
<style>
:root {
--bg-color: #0d0221;
--accent-color: #00ffcc;
--panel-color: #1a0b3c;
--text-color: #ffffff;
--neon-pink: #ff00ff;
--neon-blue: #00ffff;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-image:
linear-gradient(rgba(13, 2, 33, 0.8), rgba(13, 2, 33, 0.8)),
url('https://www.transparenttextures.com/patterns/carbon-fibre.png');
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
overflow-x: hidden;
}
#main-container {
width: 100%;
max-width: 900px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
margin-top: env(safe-area-inset-top);
}
header {
text-align: center;
margin-bottom: 10px;
}
h1 {
font-size: 2.5rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 5px;
margin: 0;
background: linear-gradient(to right, var(--neon-pink), var(--neon-blue), var(--accent-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 20px rgba(0, 255, 204, 0.3);
}
#status {
color: var(--accent-color);
font-size: 0.9rem;
margin-top: 5px;
min-height: 1.5em;
}
/* The Sequencer Grid */
#grid-container {
position: relative;
width: 100%;
aspect-ratio: 16 / 8;
background-color: rgba(0,0,0,0.5);
border: 4px solid var(--panel-color);
box-shadow: 0 0 30px rgba(0,0,0,0.5), inset 0 0 100px rgba(255,0,255,0.1);
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.grid-row {
display: flex;
flex: 1;
width: 100%;
}
.cell {
flex: 1;
border: 1px solid rgba(255,255,255,0.05);
cursor: pointer;
transition: all 0.1s ease;
position: relative;
background-clip: content-box;
}
.cell.selected {
background-color: var(--cell-color);
box-shadow: inset 0 0 15px rgba(255,255,255,0.6);
animation: flicker 2s infinite;
}
.cell.active-col {
border-left: 2px solid #fff;
border-right: 2px solid #fff;
z-index: 10;
background-color: rgba(255,255,255,0.1);
}
.cell.active-col.impact {
animation: scanImpact 0.1s ease-out;
}
@keyframes scanImpact {
0% { background-color: rgba(255,255,255,0.5); transform: scale(1.1); }
100% { background-color: transparent; transform: scale(1); }
}
@keyframes flicker {
0%, 100% { opacity: 1; }
50% { opacity: 0.8; }
}
/* Controls Panel */
.controls-panel {
background: var(--panel-color);
padding: 20px;
border-radius: 15px;
box-shadow: 0 10px 20px rgba(0,0,0,0.3);
display: flex;
flex-wrap: wrap;
gap: 15px;
justify-content: space-around;
align-items: center;
border: 2px solid rgba(255,255,255,0.1);
}
.control-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.btn-cyber {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-weight: bold;
text-transform: uppercase;
transition: all 0.2s;
min-width: 120px;
box-shadow: 0 4px 0 rgba(0,0,0,0.4);
}
.btn-cyber:active {
transform: translateY(3px);
box-shadow: 0 1px 0 rgba(0,0,0,0.4);
}
input[type=range] {
-webkit-appearance: none;
width: 150px;
height: 10px;
background: rgba(0,0,0,0.5);
border-radius: 5px;
outline: none;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 25px;
height: 25px;
background: var(--accent-color);
cursor: pointer;
border-radius: 50%;
border: 3px solid #fff;
}
.footer-info {
font-size: 0.8rem;
opacity: 0.6;
text-align: center;
margin-top: 20px;
}
/* Effects */
.glitch-effect {
animation: shake 0.2s cubic-bezier(.36,.07,.19,.97) both;
transform: translate3d(0, 0, 0);
}
@keyframes shake {
10%, 90% { transform: translate3d(-2px, 0, 0); filter: hue-rotate(90deg) contrast(150%); }
20%, 80% { transform: translate3d(4px, 0, 0); }
30%, 50%, 70% { transform: translate3d(-8px, 0, 0); }
40%, 60% { transform: translate3d(8px, 0, 0); }
}
/* Mobile tweaks */
@media (max-width: 600px) {
h1 { font-size: 1.5rem; letter-spacing: 2px; }
.controls-panel { padding: 10px; }
.btn-cyber { width: 100%; min-width: unset; }
#grid-container { border-width: 2px; }
}
</style>
</head>
<body>
<div id="main-container">
<header>
<h1><i class="fas fa-barcode"></i> YTPMV SCAN</h1>
<div id="status">Tap anywhere to initialize Poop Engine...</div>
</header>
<div id="grid-container">
<!-- Grid Cells Generated by JS -->
</div>
<div class="controls-panel">
<div class="control-group">
<button id="play-btn" class="btn btn-success btn-lg btn-cyber">
<i class="fas fa-play"></i> START SCAN
</button>
<button id="clear-btn" class="btn btn-outline-light btn-sm mt-1">
CLEAR GRID
</button>
</div>
<div class="control-group">
<label>TEMPO: <span id="bpm-val">130</span> BPM</label>
<input type="range" id="bpm-slider" min="60" max="220" value="130">
</div>
<div class="control-group">
<button id="random-btn" class="btn btn-primary btn-cyber">
RANDOMIZE
</button>
<button id="glitch-btn" class="btn btn-warning btn-cyber mt-2">
GLITCH UI
</button>
</div>
<div class="control-group">
<label for="img-upload" class="btn btn-info btn-cyber">
<i class="fas fa-image"></i> LOAD BG
</label>
<input type="file" id="img-upload" hidden accept="image/*">
<p class="mb-0 small opacity-50">Add Poop Visuals</p>
</div>
</div>
<div class="card bg-dark text-light border-secondary mt-3">
<div class="card-body py-2 px-3">
<h6 class="card-title mb-1"><i class="fas fa-info-circle"></i> Instructions:</h6>
<ul class="mb-0 small" style="padding-left: 20px;">
<li>Click/Tap cells to toggle a sound trigger.</li>
<li>Each row corresponds to a different classic poop sound.</li>
<li>Upload your own image to act as the "source" for your YTPMV.</li>
<li>Adjust the tempo for hyper-fast or slow-motion Poops.</li>
</ul>
</div>
</div>
<div class="footer-info">
© 2024 YTPMV Scanner Visual Sequencer - Created for the WebPoopers.
</div>
</div>
<script>
// Audio context start guard
$('body').on('click touchstart', function() {
if (audioCtx && audioCtx.state === 'suspended') {
audioCtx.resume();
}
});
</script>
</body>
</html>
NEW APPS
These are apps made by the community!