@@ -8,6 +8,7 @@ import axios from '@web/src/lib/axios';
8
8
export const SongCanvas = ( { song } : { song : SongViewDtoType } ) => {
9
9
const canvasContainerRef = useRef < HTMLDivElement > ( null ) ;
10
10
const wasmModuleRef = useRef < any > ( null ) ;
11
+ let scriptTag : HTMLScriptElement | null = null ;
11
12
12
13
useEffect ( ( ) => {
13
14
if ( ! canvasContainerRef . current ) return ;
@@ -23,107 +24,79 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
23
24
24
25
window . addEventListener ( 'keydown' , handleKeyDown ) ;
25
26
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 ;
40
29
41
30
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 ) ,
45
34
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' ,
53
42
} ,
54
43
} ;
55
44
56
- const scriptTag = document . createElement ( ' script' ) ;
57
-
45
+ // Create and append script dynamically
46
+ scriptTag = document . createElement ( 'script' ) ;
58
47
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 ;
66
49
67
50
window . Module = {
68
- canvas : canvas ,
51
+ canvas,
69
52
arguments : [ JSON . stringify ( argumentsData ) ] ,
70
53
noInitialRun : true ,
54
+ onAbort : ( ) => console . log ( 'WASM Module Aborted' ) ,
71
55
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 ) ;
98
80
}
99
81
} ,
100
82
} ;
101
- //};
102
83
103
- // Append the script tag to the body
104
84
element . appendChild ( scriptTag ) ;
105
85
106
86
return ( ) => {
107
87
window . removeEventListener ( 'keydown' , handleKeyDown ) ;
108
88
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
118
89
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 ) ;
121
97
}
122
-
123
- wasmModuleRef . current = null ;
124
98
}
125
99
126
- // Clear global Module reference
127
100
if ( window . Module ) {
128
101
delete window . Module ;
129
102
}
@@ -132,8 +105,15 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
132
105
window . wasmInstance . delete ( ) ;
133
106
}
134
107
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
+ }
137
117
} ;
138
118
} , [ song . publicId ] ) ;
139
119
@@ -148,11 +128,7 @@ export const SongCanvas = ({ song }: { song: SongViewDtoType }) => {
148
128
width = { 1280 }
149
129
height = { 720 }
150
130
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' } }
156
132
/>
157
133
</ div >
158
134
) ;
0 commit comments