Skip to content

Commit 3c4b68a

Browse files
committed
feat: add MusicalNote component for interactive note display
1 parent e5c6301 commit 3c4b68a

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

web/next.config.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ const nextConfig = {
3434
hostname: 'cdn.discordapp.com',
3535
port: '',
3636
},
37+
// localhost
38+
{
39+
protocol: 'http',
40+
hostname: 'localhost',
41+
port: '9000',
42+
},
3743
],
3844
},
3945
};

web/public/notes_sprites.png

1.51 KB
Loading
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use client';
2+
import { useCallback, useState } from 'react';
3+
4+
const notesSpritesSheet = '/notes_sprites.png';
5+
6+
const spritesSheetSize = {
7+
width: 120,
8+
height: 8,
9+
};
10+
11+
const gridDimensions = {
12+
x: 24, // 24 columns
13+
y: 1, // 1 row
14+
};
15+
16+
const singleNoteSize = {
17+
width: spritesSheetSize.width / gridDimensions.x,
18+
height: spritesSheetSize.height / gridDimensions.y,
19+
};
20+
21+
const totalNotes = gridDimensions.x * gridDimensions.y;
22+
23+
interface MusicalNoteProps {
24+
size?: number;
25+
}
26+
27+
export const MusicalNote = ({ size = 8 }: MusicalNoteProps) => {
28+
const [currentNote, setCurrentNote] = useState(0);
29+
30+
const noteToCell = useCallback(() => {
31+
return {
32+
x: currentNote % gridDimensions.x,
33+
y: Math.floor(currentNote / gridDimensions.x),
34+
};
35+
}, [currentNote]);
36+
37+
const nextNote = () => {
38+
setCurrentNote((currentNote + 1) % totalNotes);
39+
};
40+
41+
const onNoteClick = () => {
42+
nextNote();
43+
};
44+
45+
const cell = noteToCell();
46+
47+
return (
48+
<div
49+
style={{
50+
width: singleNoteSize.width * size, // Scale display size
51+
height: singleNoteSize.height * size, // Scale display size
52+
53+
backgroundImage: `url(${notesSpritesSheet})`,
54+
backgroundPosition: `-${cell.x * singleNoteSize.width * size}px -${
55+
cell.y * singleNoteSize.height * size
56+
}px`,
57+
backgroundSize: `${spritesSheetSize.width * size}px ${
58+
spritesSheetSize.height * size
59+
}px`, // Scale background
60+
61+
imageRendering: 'pixelated',
62+
cursor: 'pointer',
63+
}}
64+
onClick={onNoteClick}
65+
/>
66+
);
67+
};

0 commit comments

Comments
 (0)