wip
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.idea
|
||||
+36
@@ -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">
|
||||
<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>
|
||||
@@ -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.
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user