Skip to content

Commit 4d130ce

Browse files
committed
feat: enhance SongCanvas with improved WASM initialization and cleanup
1 parent 0f1576e commit 4d130ce

File tree

1 file changed

+59
-83
lines changed

1 file changed

+59
-83
lines changed

web/src/modules/song/components/client/SongCanvas.tsx

Lines changed: 59 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import axios from '@web/src/lib/axios';
88
export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
99
const canvasContainerRef = useRef<HTMLDivElement>(null);
1010
const wasmModuleRef = useRef<any>(null);
11+
let scriptTag: HTMLScriptElement | null = null;
1112

1213
useEffect(() => {
1314
if (!canvasContainerRef.current) return;
@@ -23,107 +24,79 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
2324

2425
window.addEventListener('keydown', handleKeyDown);
2526

26-
// Calculate window dimensions
27-
let fullscreen_window_width = window.screen.width;
28-
let fullscreen_window_height = window.screen.height;
29-
30-
if (fullscreen_window_width < fullscreen_window_height) {
31-
[fullscreen_window_width, fullscreen_window_height] = [
32-
fullscreen_window_height,
33-
fullscreen_window_width,
34-
];
35-
}
36-
37-
// 720p resolution
38-
//const window_width = 1280;
39-
//const window_height = 720;
27+
const fullscreen_window_width = window.screen.width;
28+
const fullscreen_window_height = window.screen.height;
4029

4130
const argumentsData = {
42-
font_id: 1, // Math.floor(Math.random() * 6),
43-
window_width: Number((fullscreen_window_width / 2).toFixed(0)),
44-
window_height: Number((fullscreen_window_height / 2).toFixed(0)),
31+
font_id: 1,
32+
window_width: Math.floor(fullscreen_window_width / 2),
33+
window_height: Math.floor(fullscreen_window_height / 2),
4534
theme: {
46-
background_color: '#18181B', // Grass-like green
47-
accent_color: '#002FA3', // Orange (like Minecraft's iconic dirt/wood)
48-
text_color: '#F0F0F0', // Light gray
49-
white_key_color: '#F0F0F0', // Beige (like sand)
50-
black_key_color: '#1A1A1A', // Dark brown (like wood)
51-
white_text_key_color: '#1A1A1A', // Dark gray
52-
black_text_key_color: '#F0F0F0', // Light gray
35+
background_color: '#18181B',
36+
accent_color: '#002FA3',
37+
text_color: '#F0F0F0',
38+
white_key_color: '#F0F0F0',
39+
black_key_color: '#1A1A1A',
40+
white_text_key_color: '#1A1A1A',
41+
black_text_key_color: '#F0F0F0',
5342
},
5443
};
5544

56-
const scriptTag = document.createElement('script');
57-
45+
// Create and append script dynamically
46+
scriptTag = document.createElement('script');
5847
scriptTag.src = '/nbs-player-rs.js';
59-
60-
scriptTag.async = true; // Load the script asynchronously
61-
62-
//scriptTag.onload = () => {
63-
//if (!window.Module) return;
64-
65-
wasmModuleRef.current = window.Module; // Store for cleanup
48+
scriptTag.async = true;
6649

6750
window.Module = {
68-
canvas: canvas,
51+
canvas,
6952
arguments: [JSON.stringify(argumentsData)],
7053
noInitialRun: true,
54+
onAbort: () => console.log('WASM Module Aborted'),
7155
preInit: async function () {
72-
// wait 2 seconds before starting
73-
await new Promise((resolve) => setTimeout(resolve, 200));
74-
75-
const response_url = await axios.get(`/song/${song.publicId}/open`, {
76-
headers: {
77-
src: 'downloadButton',
78-
},
79-
});
80-
81-
const song_url = response_url.data;
82-
console.log('Song URL:', song_url);
83-
84-
const response = await fetch(song_url);
85-
const arrayBuffer = await response.arrayBuffer();
86-
const byteArray = new Uint8Array(arrayBuffer);
87-
88-
if (window.FS) {
89-
window.FS.writeFile('/song.nbsx', byteArray);
90-
} else {
91-
console.error('FS is not defined');
92-
}
93-
94-
if (window.callMain) {
95-
window.callMain([JSON.stringify(argumentsData)]);
96-
} else {
97-
console.error('callMain is not defined');
56+
try {
57+
const response = await axios.get(`/song/${song.publicId}/open`, {
58+
headers: { src: 'downloadButton' },
59+
});
60+
61+
const song_url = response.data;
62+
console.log('Song URL:', song_url);
63+
64+
const responseData = await fetch(song_url);
65+
const byteArray = new Uint8Array(await responseData.arrayBuffer());
66+
67+
if (window.FS) {
68+
window.FS.writeFile('/song.nbsx', byteArray);
69+
} else {
70+
console.error('FS is not defined');
71+
}
72+
73+
if (window.callMain) {
74+
window.callMain([JSON.stringify(argumentsData)]);
75+
} else {
76+
console.error('callMain is not defined');
77+
}
78+
} catch (error) {
79+
console.error('Error initializing WASM:', error);
9880
}
9981
},
10082
};
101-
//};
10283

103-
// Append the script tag to the body
10484
element.appendChild(scriptTag);
10585

10686
return () => {
10787
window.removeEventListener('keydown', handleKeyDown);
10888

109-
if (canvas) {
110-
canvas.removeEventListener('keydown', () => undefined);
111-
}
112-
113-
// Remove script tag
114-
const script = element.querySelector('script[src="/nbs-player-rs.js"]');
115-
if (script) script.remove();
116-
117-
// Properly destroy WASM module
11889
if (wasmModuleRef.current) {
119-
if (wasmModuleRef.current.destroy) {
120-
wasmModuleRef.current.destroy();
90+
try {
91+
wasmModuleRef.current._free?.(); // Free memory if `_free()` is available
92+
wasmModuleRef.current.quit?.(); // Call `quit()` if it exists
93+
wasmModuleRef.current.destroy?.(); // Call `destroy()` if it exists
94+
wasmModuleRef.current = null;
95+
} catch (error) {
96+
console.error('Error cleaning up WASM:', error);
12197
}
122-
123-
wasmModuleRef.current = null;
12498
}
12599

126-
// Clear global Module reference
127100
if (window.Module) {
128101
delete window.Module;
129102
}
@@ -132,8 +105,15 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
132105
window.wasmInstance.delete();
133106
}
134107

135-
// Force garbage collection
136-
if (window.gc) window.gc();
108+
// Remove the script tag
109+
if (scriptTag && scriptTag.parentNode) {
110+
scriptTag.parentNode.removeChild(scriptTag);
111+
}
112+
113+
// Force garbage collection if available
114+
if (window.gc) {
115+
window.gc();
116+
}
137117
};
138118
}, [song.publicId]);
139119

@@ -148,11 +128,7 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
148128
width={1280}
149129
height={720}
150130
className='w-full h-full rounded-xl'
151-
style={{
152-
// no filter
153-
filter: 'none',
154-
imageRendering: 'pixelated',
155-
}}
131+
style={{ filter: 'none', imageRendering: 'pixelated' }}
156132
/>
157133
</div>
158134
);

0 commit comments

Comments
 (0)