This commit is contained in:
Klemek
2024-10-16 11:41:39 +02:00
commit 866e2aaa28
30 changed files with 334 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.idea
+36
View File
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Startle Machine</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript" src="main.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- card related -->
<meta property="og:title" content="Startle Machine">
<meta property="og:description" content="Generates silence occasionally broken up by random sound effects">
<meta property="org:url" content="https://prank.klemek.fr">
<!--
<meta property="og:image" content="https://.../preview_640x320.jpg">
-->
</head>
<body>
<main id="app" style="display:none">
<h1>Startle Machine</h1>
<br>
<button @click="start">Start</button>
<button @click="selectAll">Select all</button>
<button @click="deselectAll">Deselect all</button>
<br>
<div style="display:flex;flex-flow: row wrap;">
<div style="width: 33%; padding: .5em;" v-for="sound in sounds">
<input v-bind:id="`active-${sound.id}`" type="checkbox" v-model="sound.active">&nbsp;
<label v-bind:for="`active-${sound.id}`">{{ sound.name }}</label>
</div>
</div>
<br>
<small><a href="https://github.com/klemek" target="_blank">@klemek</a> - <a href="https://github.com/klemek/startle-machine" target="_blank">Github Repository</a> - 2024</small>
</main>
</body>
</html>
+126
View File
@@ -0,0 +1,126 @@
/* exported app */
const SOUNDS = [
{ id: 'baba_booey', name: 'Baba Booey' },
{ id: 'bonk', name: 'Doge Bonk' },
{ id: 'boo_womp', name: 'Boo-womp (Spongebob)' },
{ id: 'bruh', name: 'Bruh' },
{ id: 'cash_register', name: 'Cash Register (Kaching)' },
{ id: 'censor_beep', name: 'Censor Beep' },
{ id: 'confetti', name: 'Confetti' },
{ id: 'fart_reverb', name: 'Fart with reverb' },
{ id: 'fart_wet', name: 'Wet Fart' },
{ id: 'gnome', name: 'Gnome' },
{ id: 'huh', name: 'Huh ?' },
{ id: 'mario_coin', name: 'Mario Coin' },
{ id: 'mario_jump', name: 'Mario Jump' },
{ id: 'metal_gear', name: 'Metal Gear Solid' },
{ id: 'microsoft_error', name: 'Windows XP Error' },
{ id: 'minecraft_cave', name: 'Minecraft Cave Ambiance' },
{ id: 'minecraft_door', name: 'Minecraft Door' },
{ id: 'minecraft_eating', name: 'Minecraft Eating' },
{ id: 'minecraft_glass', name: 'Minecraft Glass Break' },
{ id: 'minecraft_hurt', name: 'Minecraft Hurt' },
{ id: 'nope', name: 'Nope' },
{ id: 'quack', name: 'Quack' },
{ id: 'roblox_death', name: 'Roblox Death' },
{ id: 'wilhelm_scream', name: 'The Wilhelm Scream' },
{ id: 'wow', name: 'WOW' },
{ id: 'wrong_buzzer', name: 'Wrong Buzzer' },
];
const random = {
element: function (array) {
if (array.length == 0) {
return null;
}
return array[Math.floor(Math.random() * array.length)];
},
int: function (min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
float: function (min, max) {
return (Math.random() * (max - min)) + min;
}
};
let app = {
data() {
return {
sounds: [],
};
},
computed: {
currentYear() {
return new Date().getFullYear();
},
},
methods: {
showApp() {
document.getElementById("app").setAttribute("style", "");
},
onBlur() {
// TODO document.getElementById("app").setAttribute("style", "display:none");
// TODO
},
onFocus() {
// TODO
},
loadSounds() {
this.sounds = SOUNDS.map(sound => {
sound.audio = new Audio(`./sounds/${sound.id}.wav`);
sound.audio.preservesPitch = false;
sound.active = true;
return sound;
});
},
start() {
const audioCtx = new AudioContext();
this.sounds.forEach(sound => {
const source = audioCtx.createMediaElementSource(sound.audio);
source.connect(audioCtx.destination);
});
this.trigger();
},
trigger() {
const time = random.int(30, 300);
console.log(`Next in ${time} seconds`);
setTimeout(this.playRandomSound, time * 1000);
},
selectAll() {
this.sounds.forEach(sound => {
sound.active = true;
});
},
deselectAll() {
this.sounds.forEach(sound => {
sound.active = false;
});
},
playRandomSound() {
const sound = random.element(this.sounds.filter(sound => sound.active));
if (sound !== null) {
console.log(`Playing ${sound.id}`);
sound.audio.playbackRate = random.float(0.8, 1.2);
sound.audio.play();
}
this.trigger();
},
},
mounted: function () {
const self = this;
setTimeout(this.showApp);
this.loadSounds();
document.addEventListener("visibilitychange", function () {
if (document.hidden) {
self.onBlur();
} else {
self.onFocus();
}
});
},
};
window.onload = () => {
app = Vue.createApp(app);
app.mount("#app");
};
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+171
View File
@@ -0,0 +1,171 @@
/*
=================================================
https://www.joshwcomeau.com/css/custom-css-reset/
=================================================
*/
/*
1. Use a more-intuitive box-sizing model.
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
/*
2. Remove default margin
*/
* {
margin: 0;
}
/*
3. Allow percentage-based heights in the application
*/
html,
body {
height: 100%;
}
/*
Typographic tweaks!
4. Add accessible line-height
5. Improve text rendering
*/
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/*
6. Improve media defaults
*/
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
/*
7. Remove built-in form typography styles
*/
input,
button,
textarea,
select {
font: inherit;
}
/*
8. Avoid text overflows
*/
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
/*
9. Create a root stacking context
*/
#root,
#__next {
isolation: isolate;
}
/*
=================================================
CUSTOM STYLE
=================================================
*/
@import url("https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
:root {
/* https://materialui.co/colors/ */
--hue-primary: 65.52;
--sat-primary: 20%;
--background: hsl(var(--hue-primary), var(--sat-primary), 96.08%);
--background-primary: hsl(var(--hue-primary), var(--sat-primary), 93.33%);
--background-secondary: hsl(var(--hue-primary), var(--sat-primary), 90%);
--color-primary: hsl(var(--hue-primary), var(--sat-primary), 50%);
--text-primary: hsl(var(--hue-primary), var(--sat-primary), 25%);
--text-secondary: hsl(var(--hue-primary), var(--sat-primary), 30%);
}
/*
=================================================
https://blog.koley.in/2019/339-bytes-of-responsive-css
https://www.swyx.io/css-100-bytes
https://gist.github.com/JoeyBurzynski/617fb6201335779f8424ad9528b72c41
=================================================
*/
html,
body {
padding: 0;
max-width: 100%;
color: var(--text-primary);
font-family: "Roboto", Verdana, serif;
}
body {
background-color: var(--background);
}
main {
padding: 1.5rem;
margin: auto;
background-color: var(--background-primary);
min-height: 100%;
}
table {
border-collapse: collapse;
width: 100%;
font-size: 0.9em;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 1em 0 0.5em;
}
p,
ul,
ol {
margin-bottom: 2em;
color: var(--text-secondary);
}
textarea,
input,
select,
.mono {
font-family: "Roboto Mono", monospace;
}
textarea {
width: 100%;
min-width: 100%;
max-width: 100%;
}
a {
color: inherit;
}
@media only screen and (min-width: 768px) {
main {
max-width: 42rem;
}
table {
font-size: inherit;
}
}