@mtph9/heehee.js 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +15 -0
- package/README.md +54 -0
- package/grunts/grunt-1.mp3 +0 -0
- package/grunts/grunt-10.mp3 +0 -0
- package/grunts/grunt-11.mp3 +0 -0
- package/grunts/grunt-12.mp3 +0 -0
- package/grunts/grunt-13.mp3 +0 -0
- package/grunts/grunt-14.mp3 +0 -0
- package/grunts/grunt-15.mp3 +0 -0
- package/grunts/grunt-16.mp3 +0 -0
- package/grunts/grunt-17.mp3 +0 -0
- package/grunts/grunt-18.mp3 +0 -0
- package/grunts/grunt-19.mp3 +0 -0
- package/grunts/grunt-2.mp3 +0 -0
- package/grunts/grunt-20.mp3 +0 -0
- package/grunts/grunt-21.mp3 +0 -0
- package/grunts/grunt-22.mp3 +0 -0
- package/grunts/grunt-23.mp3 +0 -0
- package/grunts/grunt-24.mp3 +0 -0
- package/grunts/grunt-25.mp3 +0 -0
- package/grunts/grunt-26.mp3 +0 -0
- package/grunts/grunt-27.mp3 +0 -0
- package/grunts/grunt-28.mp3 +0 -0
- package/grunts/grunt-29.mp3 +0 -0
- package/grunts/grunt-3.mp3 +0 -0
- package/grunts/grunt-30.mp3 +0 -0
- package/grunts/grunt-31.mp3 +0 -0
- package/grunts/grunt-4.mp3 +0 -0
- package/grunts/grunt-5.mp3 +0 -0
- package/grunts/grunt-6.mp3 +0 -0
- package/grunts/grunt-7.mp3 +0 -0
- package/grunts/grunt-8.mp3 +0 -0
- package/grunts/grunt-9.mp3 +0 -0
- package/heehee.css +44 -0
- package/heehee.js +83 -0
- package/package.json +21 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2026] [mtph9]
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# heehee.js
|
|
2
|
+
|
|
3
|
+
A lightweight JavaScript library that adds Michael Jackson's iconic "grunts" and sounds to your web elements when they are hovered over.
|
|
4
|
+
|
|
5
|
+
[**Demo / GitHub Pages**](https://merlin-1d.github.io/heehee.js/)
|
|
6
|
+
|
|
7
|
+
`heehee.js` provides a fun and simple way to add sound effects to your website. It listens for `mouseover` events on specified elements and plays one of the 31 available Michael Jackson grunts. By default, it targets elements with the class `.heehee` or the attribute `data-heehee`.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **31 unique sounds**: A wide variety of iconic Michael Jackson grunts.
|
|
12
|
+
- **Random or Specific sounds**: Hovering over a default element plays a random sound, but you can specify which sound to play using the `data-heehee` attribute (e.g., `data-heehee="5"` for grunt 6, as it's 0-indexed).
|
|
13
|
+
- **Simple implementation**: Import and call `initHeeHee()`.
|
|
14
|
+
|
|
15
|
+
## Setup & Run
|
|
16
|
+
|
|
17
|
+
### 1. Install
|
|
18
|
+
```bash
|
|
19
|
+
npm install heehee.js
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Usage
|
|
23
|
+
Add `heehee` class or `data-heehee` attribute to your HTML elements:
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<div class="heehee">Hover over me!</div>
|
|
27
|
+
<div data-heehee="7">Play specific sound (grunt-7.mp3)</div>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Initialize in your JS:
|
|
31
|
+
```javascript
|
|
32
|
+
import { initHeeHee } from '@mtph9/heehee.js';
|
|
33
|
+
initHeeHee();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration Options
|
|
37
|
+
|
|
38
|
+
You can pass an options object to `initHeeHee()`:
|
|
39
|
+
|
|
40
|
+
- `selector`: (String) CSS selector for elements (default: `.heehee, [data-heehee]`)
|
|
41
|
+
- `basePath`: (String) Custom path to the grunts directory (must end with `/`)
|
|
42
|
+
- `showUnlockButton`: (Boolean) Whether to show the "unlock sound" button if audio playback is blocked by the browser (default: `true`)
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
```javascript
|
|
46
|
+
initHeeHee({
|
|
47
|
+
selector: '.my-custom-class',
|
|
48
|
+
basePath: 'https://unpkg.com/heehee.js/grunts/'
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
This project is licensed under the **ISC License**. See the `LICENSE.txt` file for more details.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/heehee.css
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
@keyframes heehee-scroll-in {
|
|
2
|
+
0% { transform: translateY(100px) scale(0); opacity: 0; }
|
|
3
|
+
60% { transform: translateY(-10px) scale(1.1); opacity: 1; }
|
|
4
|
+
100% { transform: translateY(0) scale(1); opacity: 1; }
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@keyframes heehee-shake {
|
|
8
|
+
0%, 100% { transform: scale(1) rotate(0); }
|
|
9
|
+
10%, 30%, 50%, 70%, 90% { transform: scale(1.1) rotate(-5deg); }
|
|
10
|
+
20%, 40%, 60%, 80% { transform: scale(1.1) rotate(5deg); }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.heehee-unlock-icon {
|
|
14
|
+
position: fixed;
|
|
15
|
+
bottom: 20px;
|
|
16
|
+
right: 20px;
|
|
17
|
+
width: 48px;
|
|
18
|
+
height: 48px;
|
|
19
|
+
background-color: #ff0055;
|
|
20
|
+
color: white;
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
27
|
+
z-index: 9999;
|
|
28
|
+
transition: transform 0.2s, background-color 0.2s;
|
|
29
|
+
animation: heehee-scroll-in 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards,
|
|
30
|
+
heehee-shake 2s ease-in-out infinite 2s;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.heehee-unlock-icon:hover {
|
|
34
|
+
animation-play-state: paused;
|
|
35
|
+
transform: scale(1.2) !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@media (prefers-reduced-motion: reduce) {
|
|
39
|
+
.heehee-unlock-icon {
|
|
40
|
+
animation: none !important;
|
|
41
|
+
opacity: 1;
|
|
42
|
+
transform: none;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/heehee.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
let soundsBasePath = new URL('./grunts/', import.meta.url).href;
|
|
2
|
+
let unlockIcon = null;
|
|
3
|
+
let showUnlockButtonEnabled = true;
|
|
4
|
+
|
|
5
|
+
const sounds = Array.from({ length: 31 }, (_, i) => `grunt-${i + 1}.mp3`);
|
|
6
|
+
|
|
7
|
+
function showUnlockIcon() {
|
|
8
|
+
if (unlockIcon) return;
|
|
9
|
+
|
|
10
|
+
unlockIcon = document.createElement('div');
|
|
11
|
+
unlockIcon.className = 'heehee-unlock-icon';
|
|
12
|
+
unlockIcon.innerHTML = `
|
|
13
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
14
|
+
<path d="M11 5L6 9H2v6h4l5 4V5z"></path>
|
|
15
|
+
<line x1="23" y1="9" x2="17" y2="15"></line>
|
|
16
|
+
<line x1="17" y1="9" x2="23" y2="15"></line>
|
|
17
|
+
</svg>
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
unlockIcon.addEventListener('click', () => {
|
|
21
|
+
const audio = new Audio(new URL(`./grunts/${sounds[0]}`, import.meta.url).href);
|
|
22
|
+
audio.play().then(() => {
|
|
23
|
+
unlockIcon.remove();
|
|
24
|
+
unlockIcon = null;
|
|
25
|
+
}).catch(err => {
|
|
26
|
+
console.debug('HeeHee: Still blocked.', err);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
document.body.appendChild(unlockIcon);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function playSound(index, options = {}) {
|
|
34
|
+
const parsedIndex = parseInt(index);
|
|
35
|
+
const soundIndex = (!isNaN(parsedIndex) && parsedIndex >= 1 && parsedIndex <= sounds.length)
|
|
36
|
+
? parsedIndex - 1
|
|
37
|
+
: Math.floor(Math.random() * sounds.length);
|
|
38
|
+
|
|
39
|
+
const audioUrl = options.basePath
|
|
40
|
+
? new URL(sounds[soundIndex], soundsBasePath).href
|
|
41
|
+
: new URL(`./grunts/${sounds[soundIndex]}`, import.meta.url).href;
|
|
42
|
+
|
|
43
|
+
new Audio(audioUrl).play().then(() => {
|
|
44
|
+
if (unlockIcon) {
|
|
45
|
+
unlockIcon.remove();
|
|
46
|
+
unlockIcon = null;
|
|
47
|
+
}
|
|
48
|
+
}).catch(err => {
|
|
49
|
+
if (err.name === 'NotAllowedError' && showUnlockButtonEnabled) {
|
|
50
|
+
showUnlockIcon();
|
|
51
|
+
}
|
|
52
|
+
console.debug('HeeHee: Audio playback failed.', err);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function initHeeHee(options = {}) {
|
|
57
|
+
const selector = typeof options === 'string' ? options : (options.selector || '.heehee, [data-heehee]');
|
|
58
|
+
|
|
59
|
+
if (options.basePath) {
|
|
60
|
+
soundsBasePath = options.basePath.endsWith('/') ? options.basePath : options.basePath + '/';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (options.showUnlockButton !== undefined) {
|
|
64
|
+
showUnlockButtonEnabled = !!options.showUnlockButton;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
document.addEventListener('mouseover', (event) => {
|
|
68
|
+
const target = event.target.closest(selector);
|
|
69
|
+
|
|
70
|
+
if (target && !target.dataset.heeheeActive) {
|
|
71
|
+
target.dataset.heeheeActive = 'true';
|
|
72
|
+
|
|
73
|
+
const soundAttr = target.getAttribute('data-heehee');
|
|
74
|
+
playSound(soundAttr, options);
|
|
75
|
+
|
|
76
|
+
const onMouseLeave = () => {
|
|
77
|
+
delete target.dataset.heeheeActive;
|
|
78
|
+
target.removeEventListener('mouseleave', onMouseLeave);
|
|
79
|
+
};
|
|
80
|
+
target.addEventListener('mouseleave', onMouseLeave);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mtph9/heehee.js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "heehee.js",
|
|
6
|
+
"repository": "https://github.com/mtph9/heehee.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"heehee.js",
|
|
9
|
+
"heehee.css",
|
|
10
|
+
"grunts/"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./heehee.js",
|
|
14
|
+
"./heehee.css": "./heehee.css",
|
|
15
|
+
"./grunts/*": "./grunts/*"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "mtph9 <mtph9.dev@gmail.com>",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"type": "module"
|
|
21
|
+
}
|