@@ -17,6 +17,7 @@ export class ShaderLayer extends LitElement {
1717 private animationFrame ?: number ;
1818 private startTime = performance . now ( ) ;
1919 private vertexShader ?: WebGLShader ;
20+ private errorMessage : string | null = null ;
2021
2122 static override styles = css `
2223 :host {
@@ -37,38 +38,83 @@ export class ShaderLayer extends LitElement {
3738 left: 0;
3839 mix-blend-mode: var(--blend-mode, default);
3940 }
41+ .error {
42+ color: red;
43+ padding: 20px;
44+ position: absolute;
45+ top: 0;
46+ left: 0;
47+ background: rgba(0,0,0,0.8);
48+ }
4049 ` ;
4150
51+ private cleanup ( ) {
52+ if ( this . animationFrame ) {
53+ cancelAnimationFrame ( this . animationFrame ) ;
54+ this . animationFrame = undefined ;
55+ }
56+
57+ if ( this . gl ) {
58+ if ( this . program ) {
59+ this . gl . deleteProgram ( this . program ) ;
60+ this . program = undefined ;
61+ }
62+ if ( this . vertexShader ) {
63+ this . gl . deleteShader ( this . vertexShader ) ;
64+ this . vertexShader = undefined ;
65+ }
66+ this . gl = undefined ;
67+ }
68+
69+ this . timeLocation = undefined ;
70+ this . resolutionLocation = undefined ;
71+ this . errorMessage = null ;
72+ }
73+
4274 private setupWebGL ( ) {
75+ this . cleanup ( ) ;
76+
4377 const canvas = this . canvasRef . value ;
4478 if ( ! canvas ) return ;
4579
4680 canvas . width = this . width ;
4781 canvas . height = this . height ;
4882 canvas . style . setProperty ( '--blend-mode' , this . blendMode ) ;
4983
50- this . gl = canvas . getContext ( 'webgl' , {
84+ const gl = canvas . getContext ( 'webgl' , {
5185 alpha : true ,
5286 premultipliedAlpha : false
53- } ) ! ;
54- if ( ! this . gl ) return ;
87+ } ) ;
88+ if ( ! gl ) {
89+ this . errorMessage = "WebGL not supported" ;
90+ return ;
91+ }
92+ this . gl = gl ;
5593
56- // Enable blending for transparency
57- this . gl . enable ( this . gl . BLEND ) ;
58- this . gl . blendFunc ( this . gl . SRC_ALPHA , this . gl . ONE_MINUS_SRC_ALPHA ) ;
94+ gl . enable ( gl . BLEND ) ;
95+ gl . blendFunc ( gl . SRC_ALPHA , gl . ONE_MINUS_SRC_ALPHA ) ;
5996
60- this . vertexShader = this . gl . createShader ( this . gl . VERTEX_SHADER ) ;
61- if ( ! this . vertexShader ) return ;
97+ const vertexShader = gl . createShader ( gl . VERTEX_SHADER ) ;
98+ if ( ! vertexShader ) {
99+ this . errorMessage = "Failed to create vertex shader" ;
100+ return ;
101+ }
102+ this . vertexShader = vertexShader ;
62103
63- this . gl . shaderSource ( this . vertexShader , `
104+ gl . shaderSource ( vertexShader , `
64105 attribute vec2 position;
65106 varying vec2 v_texCoord;
66107 void main() {
67108 v_texCoord = (position + 1.0) * 0.5;
68109 gl_Position = vec4(position, 0.0, 1.0);
69110 }
70111 ` ) ;
71- this . gl . compileShader ( this . vertexShader ) ;
112+ gl . compileShader ( vertexShader ) ;
113+
114+ if ( ! gl . getShaderParameter ( vertexShader , gl . COMPILE_STATUS ) ) {
115+ this . errorMessage = `Vertex shader error: ${ gl . getShaderInfoLog ( vertexShader ) } ` ;
116+ return ;
117+ }
72118
73119 const positions = new Float32Array ( [
74120 - 1 , - 1 ,
@@ -78,53 +124,62 @@ export class ShaderLayer extends LitElement {
78124 1 , - 1 ,
79125 1 , 1
80126 ] ) ;
81- const positionBuffer = this . gl . createBuffer ( ) ;
82- this . gl . bindBuffer ( this . gl . ARRAY_BUFFER , positionBuffer ) ;
83- this . gl . bufferData ( this . gl . ARRAY_BUFFER , positions , this . gl . STATIC_DRAW ) ;
127+ const positionBuffer = gl . createBuffer ( ) ;
128+ gl . bindBuffer ( gl . ARRAY_BUFFER , positionBuffer ) ;
129+ gl . bufferData ( gl . ARRAY_BUFFER , positions , gl . STATIC_DRAW ) ;
84130
85131 this . initShaderProgram ( ) ;
86132 }
87133
88134 private initShaderProgram ( ) {
89135 if ( ! this . gl || ! this . vertexShader || ! this . shader ) return ;
136+ const gl = this . gl ;
90137
91- // Clean up existing program
92- if ( this . program ) {
93- this . gl . deleteProgram ( this . program ) ;
138+ const program = gl . createProgram ( ) ;
139+ if ( ! program ) {
140+ this . errorMessage = "Failed to create program" ;
141+ return ;
94142 }
95143
96- this . program = this . gl . createProgram ( ) ;
97- if ( ! this . program ) return ;
98-
99- const fragmentShader = this . gl . createShader ( this . gl . FRAGMENT_SHADER ) ;
100- if ( ! fragmentShader ) return ;
144+ const fragmentShader = gl . createShader ( gl . FRAGMENT_SHADER ) ;
145+ if ( ! fragmentShader ) {
146+ this . errorMessage = "Failed to create fragment shader" ;
147+ return ;
148+ }
101149
102- this . gl . shaderSource ( fragmentShader , this . shader ) ;
103- this . gl . compileShader ( fragmentShader ) ;
150+ gl . shaderSource ( fragmentShader , this . shader ) ;
151+ gl . compileShader ( fragmentShader ) ;
104152
105- if ( ! this . gl . getShaderParameter ( fragmentShader , this . gl . COMPILE_STATUS ) ) {
106- console . error ( 'Fragment shader compilation error:' , this . gl . getShaderInfoLog ( fragmentShader ) ) ;
153+ if ( ! gl . getShaderParameter ( fragmentShader , gl . COMPILE_STATUS ) ) {
154+ this . errorMessage = `Fragment shader error: ${ gl . getShaderInfoLog ( fragmentShader ) } ` ;
155+ gl . deleteShader ( fragmentShader ) ;
107156 return ;
108157 }
109158
110- this . gl . attachShader ( this . program , this . vertexShader ) ;
111- this . gl . attachShader ( this . program , fragmentShader ) ;
112- this . gl . linkProgram ( this . program ) ;
159+ gl . attachShader ( program , this . vertexShader ) ;
160+ gl . attachShader ( program , fragmentShader ) ;
161+ gl . linkProgram ( program ) ;
113162
114- if ( ! this . gl . getProgramParameter ( this . program , this . gl . LINK_STATUS ) ) {
115- console . error ( 'Program linking error:' , this . gl . getProgramInfoLog ( this . program ) ) ;
163+ if ( ! gl . getProgramParameter ( program , gl . LINK_STATUS ) ) {
164+ this . errorMessage = `Program linking error: ${ gl . getProgramInfoLog ( program ) } ` ;
165+ gl . deleteShader ( fragmentShader ) ;
166+ gl . deleteProgram ( program ) ;
116167 return ;
117168 }
118169
119- const positionLocation = this . gl . getAttribLocation ( this . program , "position" ) ;
120- this . gl . enableVertexAttribArray ( positionLocation ) ;
121- this . gl . vertexAttribPointer ( positionLocation , 2 , this . gl . FLOAT , false , 0 , 0 ) ;
170+ this . program = program ;
171+
172+ const positionLocation = gl . getAttribLocation ( program , "position" ) ;
173+ gl . enableVertexAttribArray ( positionLocation ) ;
174+ gl . vertexAttribPointer ( positionLocation , 2 , gl . FLOAT , false , 0 , 0 ) ;
122175
123- this . timeLocation = this . gl . getUniformLocation ( this . program , "iTime" ) ;
124- this . resolutionLocation = this . gl . getUniformLocation ( this . program , "iResolution" ) ;
176+ this . timeLocation = gl . getUniformLocation ( program , "iTime" ) ;
177+ this . resolutionLocation = gl . getUniformLocation ( program , "iResolution" ) ;
125178
126- // Clean up fragment shader
127- this . gl . deleteShader ( fragmentShader ) ;
179+ gl . deleteShader ( fragmentShader ) ;
180+
181+ this . startTime = performance . now ( ) ;
182+ this . renderGl ( ) ;
128183 }
129184
130185 private renderGl ( ) {
@@ -149,32 +204,27 @@ export class ShaderLayer extends LitElement {
149204 }
150205
151206 override updated ( changedProperties : Map < string , any > ) {
152- if ( changedProperties . has ( 'shader' ) ) {
153- this . initShaderProgram ( ) ;
207+ if ( changedProperties . has ( 'shader' ) ||
208+ changedProperties . has ( 'width' ) ||
209+ changedProperties . has ( 'height' ) ||
210+ changedProperties . has ( 'blendMode' ) ) {
211+ this . setupWebGL ( ) ;
154212 }
155213 }
156214
157215 override firstUpdated ( ) {
158216 this . setupWebGL ( ) ;
159- this . renderGl ( ) ;
160217 }
161218
162219 override disconnectedCallback ( ) {
163220 super . disconnectedCallback ( ) ;
164- if ( this . animationFrame ) {
165- cancelAnimationFrame ( this . animationFrame ) ;
166- }
167- if ( this . gl && this . program ) {
168- this . gl . deleteProgram ( this . program ) ;
169- }
170- if ( this . gl && this . vertexShader ) {
171- this . gl . deleteShader ( this . vertexShader ) ;
172- }
221+ this . cleanup ( ) ;
173222 }
174223
175224 override render ( ) {
176225 return html `
177226 < canvas ${ ref ( this . canvasRef ) } > </ canvas >
227+ ${ this . errorMessage ? html `< div class ="error "> ${ this . errorMessage } </ div > ` : null }
178228 ` ;
179229 }
180230}
0 commit comments