@johnfmorton/some-shade 0.1.2-beta → 0.1.4-beta

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.
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("lit"),l=require("lit/decorators.js");function k(t){return t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}function E(t,o,r){const i=t.createShader(o);if(!i)throw new Error("Failed to create shader");if(t.shaderSource(i,r),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS)){const e=t.getShaderInfoLog(i);throw t.deleteShader(i),new Error(`Shader compile error: ${e}`)}return i}function L(t,o,r){const i=E(t,t.VERTEX_SHADER,o),e=E(t,t.FRAGMENT_SHADER,r),n=t.createProgram();if(!n)throw new Error("Failed to create program");if(t.attachShader(n,i),t.attachShader(n,e),t.linkProgram(n),!t.getProgramParameter(n,t.LINK_STATUS)){const c=t.getProgramInfoLog(n);throw t.deleteProgram(n),new Error(`Program link error: ${c}`)}t.deleteShader(i),t.deleteShader(e);const d=new Map,h=t.getProgramParameter(n,t.ACTIVE_ATTRIBUTES);for(let c=0;c<h;c++){const f=t.getActiveAttrib(n,c);f&&d.set(f.name,t.getAttribLocation(n,f.name))}const s=new Map,g=t.getProgramParameter(n,t.ACTIVE_UNIFORMS);for(let c=0;c<g;c++){const f=t.getActiveUniform(n,c);if(f){const m=t.getUniformLocation(n,f.name);m&&s.set(f.name,m)}}return{program:n,attribLocations:d,uniformLocations:s}}function D(t,o,r){for(const[i,e]of Object.entries(r)){const n=o.uniformLocations.get(i);if(n){if(typeof e=="number")t.uniform1f(n,e);else if(Array.isArray(e))switch(e.length){case 2:t.uniform2fv(n,e);break;case 3:t.uniform3fv(n,e);break;case 4:t.uniform4fv(n,e);break}}}}function z(t,o){const r=t.createTexture();if(!r)throw new Error("Failed to create texture");return t.bindTexture(t.TEXTURE_2D,r),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,o),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),{texture:r,width:o.naturalWidth,height:o.naturalHeight}}function P(t,o){const r=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=t.createBuffer();if(!i)throw new Error("Failed to create buffer");t.bindBuffer(t.ARRAY_BUFFER,i),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW);const e=4*Float32Array.BYTES_PER_ELEMENT,n=o.attribLocations.get("a_position");n!==void 0&&n!==-1&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,e,0));const d=o.attribLocations.get("a_texCoord");return d!==void 0&&d!==-1&&(t.enableVertexAttribArray(d),t.vertexAttribPointer(d,2,t.FLOAT,!1,e,2*Float32Array.BYTES_PER_ELEMENT)),i}function O(t){t.drawArrays(t.TRIANGLE_STRIP,0,4)}const I=`precision mediump float;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("lit"),l=require("lit/decorators.js");function k(t){return t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}function E(t,o,r){const i=t.createShader(o);if(!i)throw new Error("Failed to create shader");if(t.shaderSource(i,r),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS)){const e=t.getShaderInfoLog(i);throw t.deleteShader(i),new Error(`Shader compile error: ${e}`)}return i}function D(t,o,r){const i=E(t,t.VERTEX_SHADER,o),e=E(t,t.FRAGMENT_SHADER,r),n=t.createProgram();if(!n)throw new Error("Failed to create program");if(t.attachShader(n,i),t.attachShader(n,e),t.linkProgram(n),!t.getProgramParameter(n,t.LINK_STATUS)){const d=t.getProgramInfoLog(n);throw t.deleteProgram(n),new Error(`Program link error: ${d}`)}t.deleteShader(i),t.deleteShader(e);const c=new Map,h=t.getProgramParameter(n,t.ACTIVE_ATTRIBUTES);for(let d=0;d<h;d++){const f=t.getActiveAttrib(n,d);f&&c.set(f.name,t.getAttribLocation(n,f.name))}const s=new Map,g=t.getProgramParameter(n,t.ACTIVE_UNIFORMS);for(let d=0;d<g;d++){const f=t.getActiveUniform(n,d);if(f){const m=t.getUniformLocation(n,f.name);m&&s.set(f.name,m)}}return{program:n,attribLocations:c,uniformLocations:s}}function L(t,o,r){for(const[i,e]of Object.entries(r)){const n=o.uniformLocations.get(i);if(n){if(typeof e=="number")t.uniform1f(n,e);else if(Array.isArray(e))switch(e.length){case 2:t.uniform2fv(n,e);break;case 3:t.uniform3fv(n,e);break;case 4:t.uniform4fv(n,e);break}}}}function z(t,o){const r=t.createTexture();if(!r)throw new Error("Failed to create texture");return t.bindTexture(t.TEXTURE_2D,r),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,o),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),{texture:r,width:o.naturalWidth,height:o.naturalHeight}}function M(t,o){const r=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=t.createBuffer();if(!i)throw new Error("Failed to create buffer");t.bindBuffer(t.ARRAY_BUFFER,i),t.bufferData(t.ARRAY_BUFFER,r,t.STATIC_DRAW);const e=4*Float32Array.BYTES_PER_ELEMENT,n=o.attribLocations.get("a_position");n!==void 0&&n!==-1&&(t.enableVertexAttribArray(n),t.vertexAttribPointer(n,2,t.FLOAT,!1,e,0));const c=o.attribLocations.get("a_texCoord");return c!==void 0&&c!==-1&&(t.enableVertexAttribArray(c),t.vertexAttribPointer(c,2,t.FLOAT,!1,e,2*Float32Array.BYTES_PER_ELEMENT)),i}function P(t){t.drawArrays(t.TRIANGLE_STRIP,0,4)}const O=`precision mediump float;
2
2
 
3
3
  varying vec2 v_texCoord;
4
4
 
@@ -92,7 +92,7 @@ void main() {
92
92
  gl_Position = vec4(a_position, 0.0, 1.0);
93
93
  v_texCoord = a_texCoord;
94
94
  }
95
- `,M={name:"halftone-cmyk",fragmentShader:I,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleC",type:"float",default:15,attribute:"angle-c"},{name:"u_angleM",type:"float",default:75,attribute:"angle-m"},{name:"u_angleY",type:"float",default:0,attribute:"angle-y"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showC",type:"float",default:1,attribute:"show-c"},{name:"u_showM",type:"float",default:1,attribute:"show-m"},{name:"u_showY",type:"float",default:1,attribute:"show-y"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},V=`precision mediump float;
95
+ `,I={name:"halftone-cmyk",fragmentShader:O,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleC",type:"float",default:15,attribute:"angle-c"},{name:"u_angleM",type:"float",default:75,attribute:"angle-m"},{name:"u_angleY",type:"float",default:0,attribute:"angle-y"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showC",type:"float",default:1,attribute:"show-c"},{name:"u_showM",type:"float",default:1,attribute:"show-m"},{name:"u_showY",type:"float",default:1,attribute:"show-y"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},V=`precision mediump float;
96
96
 
97
97
  varying vec2 v_texCoord;
98
98
 
@@ -134,7 +134,7 @@ void main() {
134
134
 
135
135
  gl_FragColor = vec4(result, color.a);
136
136
  }
137
- `,N={name:"halftone-duotone",fragmentShader:V,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_duotoneColor",type:"vec3",default:[0,.6,.8],attribute:"duotone-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},W=`precision mediump float;
137
+ `,W={name:"halftone-duotone",fragmentShader:V,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_duotoneColor",type:"vec3",default:[0,.6,.8],attribute:"duotone-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},N=`precision mediump float;
138
138
 
139
139
  varying vec2 v_texCoord;
140
140
 
@@ -190,7 +190,7 @@ void main() {
190
190
 
191
191
  gl_FragColor = vec4(result, 1.0);
192
192
  }
193
- `,F={name:"dot-grid",fragmentShader:W,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_dotOffset",type:"vec2",default:[.5,.5],attribute:"dot-offset"},{name:"u_bgColor",type:"vec3",default:[1,1,1],attribute:"bg-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},Y=`precision mediump float;
193
+ `,F={name:"dot-grid",fragmentShader:N,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_dotOffset",type:"vec2",default:[.5,.5],attribute:"dot-offset"},{name:"u_bgColor",type:"vec3",default:[1,1,1],attribute:"bg-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},B=`precision mediump float;
194
194
 
195
195
  varying vec2 v_texCoord;
196
196
 
@@ -206,6 +206,8 @@ uniform float u_showCool;
206
206
  uniform float u_showK;
207
207
  uniform vec3 u_warmColor;
208
208
  uniform vec3 u_coolColor;
209
+ uniform float u_blendMode;
210
+ uniform float u_intensityK;
209
211
 
210
212
  float halftone(vec2 uv, float angle, float channelValue, float gridSize, float dotRadius) {
211
213
  float rad = radians(angle);
@@ -232,28 +234,53 @@ void main() {
232
234
 
233
235
  // Black channel: derived from overall darkness
234
236
  float k = 1.0 - max(warmSep, coolSep);
237
+ k = clamp(k * u_intensityK, 0.0, 1.0);
235
238
 
236
239
  // Halftone dots for each channel
237
240
  float warmDot = halftone(uv, u_angleWarm, warmSep, u_gridSize, u_dotRadius) * u_showWarm;
238
241
  float coolDot = halftone(uv, u_angleCool, coolSep, u_gridSize, u_dotRadius) * u_showCool;
239
242
  float kDot = halftone(uv, u_angleK, k, u_gridSize, u_dotRadius) * u_showK;
240
243
 
241
- // Subtractive mixing: start with white paper, subtract dye layers
242
- vec3 paper = vec3(1.0);
243
- paper -= warmDot * (vec3(1.0) - u_warmColor);
244
- paper -= coolDot * (vec3(1.0) - u_coolColor);
245
- paper *= (1.0 - kDot);
244
+ // Blend modes affect how warm and cool dots combine where they overlap.
245
+ // All modes use white paper; individual dots look the same.
246
+ // Only the overlap regions differ between modes.
247
+ vec3 overlap;
248
+ if (u_blendMode < 0.5) {
249
+ // Subtractive: dye overlap absorbs more light (darker)
250
+ overlap = u_warmColor + u_coolColor - vec3(1.0);
251
+ } else if (u_blendMode < 1.5) {
252
+ // Additive: light overlap adds up (brighter)
253
+ overlap = u_warmColor + u_coolColor;
254
+ } else {
255
+ // Screen: soft additive overlap with natural clamping
256
+ overlap = vec3(1.0) - (vec3(1.0) - u_warmColor) * (vec3(1.0) - u_coolColor);
257
+ }
258
+
259
+ // Decompose into four halftone regions
260
+ float onlyWarm = warmDot * (1.0 - coolDot);
261
+ float onlyCool = coolDot * (1.0 - warmDot);
262
+ float both = warmDot * coolDot;
263
+ float neither = (1.0 - warmDot) * (1.0 - coolDot);
264
+
265
+ // Composite: white paper base, colored dots, blend-mode-dependent overlap
266
+ vec3 result = neither * vec3(1.0)
267
+ + onlyWarm * u_warmColor
268
+ + onlyCool * u_coolColor
269
+ + both * overlap;
270
+
271
+ // K channel darkening with intensity control
272
+ result *= (1.0 - kDot);
246
273
 
247
- gl_FragColor = vec4(clamp(paper, 0.0, 1.0), color.a);
274
+ gl_FragColor = vec4(clamp(result, 0.0, 1.0), color.a);
248
275
  }
249
- `,B={name:"technicolor-2strip",fragmentShader:Y,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleWarm",type:"float",default:15,attribute:"angle-warm"},{name:"u_angleCool",type:"float",default:75,attribute:"angle-cool"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showWarm",type:"float",default:1,attribute:"show-warm"},{name:"u_showCool",type:"float",default:1,attribute:"show-cool"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_warmColor",type:"vec3",default:[.85,.25,.06],attribute:"warm-color"},{name:"u_coolColor",type:"vec3",default:[.05,.65,.6],attribute:"cool-color"}]},w=new Map;function p(t){w.set(t.name,t)}function U(t){return w.get(t)}function X(){return Array.from(w.keys())}p(M);p(N);p(F);p(B);var $=Object.defineProperty,u=(t,o,r,i)=>{for(var e=void 0,n=t.length-1,d;n>=0;n--)(d=t[n])&&(e=d(o,r,e)||e);return e&&$(o,r,e),e};const G=2;let T=Promise.resolve();function A(t){const o=T.then(t,t);return T=o,o}const H=new Set(["effect","dotRadius","gridSize","angleC","angleM","angleY","angleK","showC","showM","showY","showK","intensityK","duotoneColor","angle","dotOffsetX","dotOffsetY","bgColor","angleWarm","angleCool","showWarm","showCool","warmColor","coolColor"]),C=class C extends _.LitElement{constructor(){super(...arguments),this.src="",this.effect="halftone-cmyk",this.dotRadius=4,this.gridSize=8,this.angleC=15,this.angleM=75,this.angleY=0,this.angleK=45,this.showC=1,this.showM=1,this.showY=1,this.showK=1,this.intensityK=1,this.duotoneColor="#0099cc",this.angle=0,this.dotOffsetX=.5,this.dotOffsetY=.5,this.bgColor="#ffffff",this.angleWarm=15,this.angleCool=75,this.showWarm=1,this.showCool=1,this.warmColor="#d94010",this.coolColor="#0da699",this.loadingBlur=0,this._webglAvailable=!0,this._snapshotUrl="",this._snapshotLoaded=!1,this._image=null,this._observer=null,this._resizeObserver=null,this._lastClientWidth=0,this._visible=!1,this._needsRender=!1}render(){if(!this._webglAvailable)return _.html`<img src=${this.src} alt="" />`;const o=this.loadingBlur>0?`filter: blur(${this.loadingBlur}px)`:"";return _.html`
276
+ `,Y={name:"technicolor-2strip",fragmentShader:B,vertexShader:y,uniforms:[{name:"u_dotRadius",type:"float",default:7,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:10,attribute:"grid-size"},{name:"u_angleWarm",type:"float",default:15,attribute:"angle-warm"},{name:"u_angleCool",type:"float",default:75,attribute:"angle-cool"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showWarm",type:"float",default:1,attribute:"show-warm"},{name:"u_showCool",type:"float",default:1,attribute:"show-cool"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_warmColor",type:"vec3",default:[.85,.25,.06],attribute:"warm-color"},{name:"u_coolColor",type:"vec3",default:[.05,.65,.6],attribute:"cool-color"},{name:"u_blendMode",type:"float",default:1,attribute:"blend-mode"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},w=new Map;function p(t){w.set(t.name,t)}function U(t){return w.get(t)}function X(){return Array.from(w.keys())}p(I);p(W);p(F);p(Y);var $=Object.defineProperty,u=(t,o,r,i)=>{for(var e=void 0,n=t.length-1,c;n>=0;n--)(c=t[n])&&(e=c(o,r,e)||e);return e&&$(o,r,e),e};const G=2;let T=Promise.resolve();function A(t){const o=T.then(t,t);return T=o,o}const H=new Set(["effect","dotRadius","gridSize","angleC","angleM","angleY","angleK","showC","showM","showY","showK","intensityK","duotoneColor","angle","dotOffsetX","dotOffsetY","bgColor","angleWarm","angleCool","showWarm","showCool","warmColor","coolColor","blendMode"]),C=class C extends _.LitElement{constructor(){super(...arguments),this.src="",this.effect="halftone-cmyk",this.dotRadius=4,this.gridSize=8,this.angleC=15,this.angleM=75,this.angleY=0,this.angleK=45,this.showC=1,this.showM=1,this.showY=1,this.showK=1,this.intensityK=1,this.duotoneColor="#0099cc",this.angle=0,this.dotOffsetX=.5,this.dotOffsetY=.5,this.bgColor="#ffffff",this.angleWarm=15,this.angleCool=75,this.showWarm=1,this.showCool=1,this.warmColor="#d94010",this.coolColor="#0da699",this.blendMode=1,this.loadingBlur=0,this._webglAvailable=!0,this._snapshotUrl="",this._snapshotLoaded=!1,this._image=null,this._observer=null,this._resizeObserver=null,this._lastClientWidth=0,this._visible=!1,this._needsRender=!1}render(){if(!this._webglAvailable)return _.html`<img src=${this.src} alt="" />`;const o=this.loadingBlur>0?`filter: blur(${this.loadingBlur}px)`:"";return _.html`
250
277
  <img src=${this.src} alt="" style=${o} />
251
278
  ${this._snapshotUrl?_.html`<img
252
279
  class="snapshot${this._snapshotLoaded?" loaded":""}"
253
280
  src=${this._snapshotUrl}
254
281
  @load=${this._onSnapshotLoad}
255
282
  alt="" />`:""}
256
- `}connectedCallback(){super.connectedCallback(),this._observer=new IntersectionObserver(o=>{var i;const r=this._visible;this._visible=((i=o[0])==null?void 0:i.isIntersecting)??!1,this._visible&&!r&&this._needsRender&&(this._needsRender=!1,A(()=>this._renderEffect()))},{rootMargin:"200px"}),this._observer.observe(this),this._resizeObserver=new ResizeObserver(()=>{if(!this._image)return;const o=this.clientWidth;o>0&&o!==this._lastClientWidth&&(this._lastClientWidth=o,this._scheduleRender())}),this._resizeObserver.observe(this)}updated(o){if(o.has("src")&&this.src){this._loadImage(this.src);return}if(!this._image)return;[...o.keys()].some(i=>H.has(i))&&this._scheduleRender()}disconnectedCallback(){var o,r;super.disconnectedCallback(),(o=this._observer)==null||o.disconnect(),(r=this._resizeObserver)==null||r.disconnect(),this._revokeSnapshot()}_loadImage(o){const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this._image=r,this._scheduleRender()},r.onerror=()=>{console.warn(`[some-shade] Failed to load image: ${o}`)},r.src=o}_scheduleRender(){this._visible?A(()=>this._renderEffect()):this._needsRender=!0}async _renderEffect(){var g;if(!this._image)return;const o=U(this.effect);if(!o){console.warn(`[some-shade] Unknown effect: ${this.effect}`);return}const r=Math.min(window.devicePixelRatio||1,G),i=this._image.naturalWidth,e=this._image.naturalHeight,n=this.clientWidth||i,d=Math.max(1,i/n);this._lastClientWidth=this.clientWidth;const h=document.createElement("canvas");h.width=i*r,h.height=e*r;const s=k(h);if(!s){this._webglAvailable=!1;return}try{const c=L(s,o.vertexShader,o.fragmentShader);s.useProgram(c.program);const f=z(s,this._image),m=P(s,c);s.viewport(0,0,h.width,h.height),s.clearColor(0,0,0,0),s.clear(s.COLOR_BUFFER_BIT),s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D,f.texture);const R=c.uniformLocations.get("u_image");R&&s.uniform1i(R,0),D(s,c,this._getUniformValues(f,r,d)),s.bindBuffer(s.ARRAY_BUFFER,m);const S=4*Float32Array.BYTES_PER_ELEMENT,b=c.attribLocations.get("a_position");b!==void 0&&b!==-1&&(s.enableVertexAttribArray(b),s.vertexAttribPointer(b,2,s.FLOAT,!1,S,0));const v=c.attribLocations.get("a_texCoord");v!==void 0&&v!==-1&&(s.enableVertexAttribArray(v),s.vertexAttribPointer(v,2,s.FLOAT,!1,S,2*Float32Array.BYTES_PER_ELEMENT)),O(s);const x=await new Promise(K=>h.toBlob(K));s.deleteTexture(f.texture),s.deleteProgram(c.program),s.deleteBuffer(m),x&&(this._snapshotLoaded=!1,this._revokeSnapshot(),this._snapshotUrl=URL.createObjectURL(x))}finally{(g=s.getExtension("WEBGL_lose_context"))==null||g.loseContext()}}_onSnapshotLoad(){this._snapshotLoaded=!0}replayTransition(o=500){this._snapshotUrl&&(this._snapshotLoaded=!1,this.updateComplete.then(()=>{setTimeout(()=>{this._snapshotLoaded=!0},o)}))}_revokeSnapshot(){this._snapshotUrl&&(URL.revokeObjectURL(this._snapshotUrl),this._snapshotUrl="")}_getUniformValues(o,r,i){const e={};return e.u_resolution=[o.width*r,o.height*r],e.u_dotRadius=this.dotRadius*i,e.u_gridSize=this.gridSize*i,this.effect==="halftone-cmyk"?(e.u_angleC=this.angleC,e.u_angleM=this.angleM,e.u_angleY=this.angleY,e.u_angleK=this.angleK,e.u_showC=this.showC,e.u_showM=this.showM,e.u_showY=this.showY,e.u_showK=this.showK,e.u_intensityK=this.intensityK):this.effect==="halftone-duotone"?(e.u_duotoneColor=this._parseHexColor(this.duotoneColor),e.u_angle=this.angle):this.effect==="dot-grid"?(e.u_dotOffset=[this.dotOffsetX,this.dotOffsetY],e.u_bgColor=this._parseHexColor(this.bgColor),e.u_angle=this.angle):this.effect==="technicolor-2strip"&&(e.u_angleWarm=this.angleWarm,e.u_angleCool=this.angleCool,e.u_angleK=this.angleK,e.u_showWarm=this.showWarm,e.u_showCool=this.showCool,e.u_showK=this.showK,e.u_warmColor=this._parseHexColor(this.warmColor),e.u_coolColor=this._parseHexColor(this.coolColor)),e}_parseHexColor(o){const r=o.replace("#",""),i=parseInt(r.substring(0,2),16)/255,e=parseInt(r.substring(2,4),16)/255,n=parseInt(r.substring(4,6),16)/255;return[i,e,n]}};C.styles=_.css`
283
+ `}connectedCallback(){super.connectedCallback(),this._observer=new IntersectionObserver(o=>{var i;const r=this._visible;this._visible=((i=o[0])==null?void 0:i.isIntersecting)??!1,this._visible&&!r&&this._needsRender&&(this._needsRender=!1,A(()=>this._renderEffect()))},{rootMargin:"200px"}),this._observer.observe(this),this._resizeObserver=new ResizeObserver(()=>{if(!this._image)return;const o=this.clientWidth;o>0&&o!==this._lastClientWidth&&(this._lastClientWidth=o,this._scheduleRender())}),this._resizeObserver.observe(this)}updated(o){if(o.has("src")&&this.src){this._loadImage(this.src);return}if(!this._image)return;[...o.keys()].some(i=>H.has(i))&&this._scheduleRender()}disconnectedCallback(){var o,r;super.disconnectedCallback(),(o=this._observer)==null||o.disconnect(),(r=this._resizeObserver)==null||r.disconnect(),this._revokeSnapshot()}_loadImage(o){const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{this._image=r,this._scheduleRender()},r.onerror=()=>{console.warn(`[some-shade] Failed to load image: ${o}`)},r.src=o}_scheduleRender(){this._visible?A(()=>this._renderEffect()):this._needsRender=!0}async _renderEffect(){var g;if(!this._image)return;const o=U(this.effect);if(!o){console.warn(`[some-shade] Unknown effect: ${this.effect}`);return}const r=Math.min(window.devicePixelRatio||1,G),i=this._image.naturalWidth,e=this._image.naturalHeight,n=this.clientWidth||i,c=Math.max(1,i/n);this._lastClientWidth=this.clientWidth;const h=document.createElement("canvas");h.width=i*r,h.height=e*r;const s=k(h);if(!s){this._webglAvailable=!1;return}try{const d=D(s,o.vertexShader,o.fragmentShader);s.useProgram(d.program);const f=z(s,this._image),m=M(s,d);s.viewport(0,0,h.width,h.height),s.clearColor(0,0,0,0),s.clear(s.COLOR_BUFFER_BIT),s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D,f.texture);const R=d.uniformLocations.get("u_image");R&&s.uniform1i(R,0),L(s,d,this._getUniformValues(f,r,c)),s.bindBuffer(s.ARRAY_BUFFER,m);const S=4*Float32Array.BYTES_PER_ELEMENT,b=d.attribLocations.get("a_position");b!==void 0&&b!==-1&&(s.enableVertexAttribArray(b),s.vertexAttribPointer(b,2,s.FLOAT,!1,S,0));const v=d.attribLocations.get("a_texCoord");v!==void 0&&v!==-1&&(s.enableVertexAttribArray(v),s.vertexAttribPointer(v,2,s.FLOAT,!1,S,2*Float32Array.BYTES_PER_ELEMENT)),P(s);const x=await new Promise(K=>h.toBlob(K));s.deleteTexture(f.texture),s.deleteProgram(d.program),s.deleteBuffer(m),x&&(this._snapshotLoaded=!1,this._revokeSnapshot(),this._snapshotUrl=URL.createObjectURL(x))}finally{(g=s.getExtension("WEBGL_lose_context"))==null||g.loseContext()}}_onSnapshotLoad(){this._snapshotLoaded=!0}replayTransition(o=500){this._snapshotUrl&&(this._snapshotLoaded=!1,this.updateComplete.then(()=>{setTimeout(()=>{this._snapshotLoaded=!0},o)}))}_revokeSnapshot(){this._snapshotUrl&&(URL.revokeObjectURL(this._snapshotUrl),this._snapshotUrl="")}_getUniformValues(o,r,i){const e={};return e.u_resolution=[o.width*r,o.height*r],e.u_dotRadius=this.dotRadius*i,e.u_gridSize=this.gridSize*i,this.effect==="halftone-cmyk"?(e.u_angleC=this.angleC,e.u_angleM=this.angleM,e.u_angleY=this.angleY,e.u_angleK=this.angleK,e.u_showC=this.showC,e.u_showM=this.showM,e.u_showY=this.showY,e.u_showK=this.showK,e.u_intensityK=this.intensityK):this.effect==="halftone-duotone"?(e.u_duotoneColor=this._parseHexColor(this.duotoneColor),e.u_angle=this.angle):this.effect==="dot-grid"?(e.u_dotOffset=[this.dotOffsetX,this.dotOffsetY],e.u_bgColor=this._parseHexColor(this.bgColor),e.u_angle=this.angle):this.effect==="technicolor-2strip"&&(e.u_angleWarm=this.angleWarm,e.u_angleCool=this.angleCool,e.u_angleK=this.angleK,e.u_showWarm=this.showWarm,e.u_showCool=this.showCool,e.u_showK=this.showK,e.u_warmColor=this._parseHexColor(this.warmColor),e.u_coolColor=this._parseHexColor(this.coolColor),e.u_blendMode=this.blendMode,e.u_intensityK=this.intensityK),e}_parseHexColor(o){const r=o.replace("#",""),i=parseInt(r.substring(0,2),16)/255,e=parseInt(r.substring(2,4),16)/255,n=parseInt(r.substring(4,6),16)/255;return[i,e,n]}};C.styles=_.css`
257
284
  :host {
258
285
  display: block;
259
286
  position: relative;
@@ -276,4 +303,4 @@ void main() {
276
303
  img.snapshot.loaded {
277
304
  opacity: 1;
278
305
  }
279
- `;let a=C;u([l.property()],a.prototype,"src");u([l.property()],a.prototype,"effect");u([l.property({type:Number,attribute:"dot-radius"})],a.prototype,"dotRadius");u([l.property({type:Number,attribute:"grid-size"})],a.prototype,"gridSize");u([l.property({type:Number,attribute:"angle-c"})],a.prototype,"angleC");u([l.property({type:Number,attribute:"angle-m"})],a.prototype,"angleM");u([l.property({type:Number,attribute:"angle-y"})],a.prototype,"angleY");u([l.property({type:Number,attribute:"angle-k"})],a.prototype,"angleK");u([l.property({type:Number,attribute:"show-c"})],a.prototype,"showC");u([l.property({type:Number,attribute:"show-m"})],a.prototype,"showM");u([l.property({type:Number,attribute:"show-y"})],a.prototype,"showY");u([l.property({type:Number,attribute:"show-k"})],a.prototype,"showK");u([l.property({type:Number,attribute:"intensity-k"})],a.prototype,"intensityK");u([l.property({attribute:"duotone-color"})],a.prototype,"duotoneColor");u([l.property({type:Number})],a.prototype,"angle");u([l.property({type:Number,attribute:"dot-offset-x"})],a.prototype,"dotOffsetX");u([l.property({type:Number,attribute:"dot-offset-y"})],a.prototype,"dotOffsetY");u([l.property({attribute:"bg-color"})],a.prototype,"bgColor");u([l.property({type:Number,attribute:"angle-warm"})],a.prototype,"angleWarm");u([l.property({type:Number,attribute:"angle-cool"})],a.prototype,"angleCool");u([l.property({type:Number,attribute:"show-warm"})],a.prototype,"showWarm");u([l.property({type:Number,attribute:"show-cool"})],a.prototype,"showCool");u([l.property({attribute:"warm-color"})],a.prototype,"warmColor");u([l.property({attribute:"cool-color"})],a.prototype,"coolColor");u([l.property({type:Number,attribute:"loading-blur"})],a.prototype,"loadingBlur");u([l.state()],a.prototype,"_webglAvailable");u([l.state()],a.prototype,"_snapshotUrl");u([l.state()],a.prototype,"_snapshotLoaded");customElements.get("some-shade-image")||customElements.define("some-shade-image",a);exports.SomeShadeImage=a;exports.get=U;exports.list=X;exports.register=p;
306
+ `;let a=C;u([l.property()],a.prototype,"src");u([l.property()],a.prototype,"effect");u([l.property({type:Number,attribute:"dot-radius"})],a.prototype,"dotRadius");u([l.property({type:Number,attribute:"grid-size"})],a.prototype,"gridSize");u([l.property({type:Number,attribute:"angle-c"})],a.prototype,"angleC");u([l.property({type:Number,attribute:"angle-m"})],a.prototype,"angleM");u([l.property({type:Number,attribute:"angle-y"})],a.prototype,"angleY");u([l.property({type:Number,attribute:"angle-k"})],a.prototype,"angleK");u([l.property({type:Number,attribute:"show-c"})],a.prototype,"showC");u([l.property({type:Number,attribute:"show-m"})],a.prototype,"showM");u([l.property({type:Number,attribute:"show-y"})],a.prototype,"showY");u([l.property({type:Number,attribute:"show-k"})],a.prototype,"showK");u([l.property({type:Number,attribute:"intensity-k"})],a.prototype,"intensityK");u([l.property({attribute:"duotone-color"})],a.prototype,"duotoneColor");u([l.property({type:Number})],a.prototype,"angle");u([l.property({type:Number,attribute:"dot-offset-x"})],a.prototype,"dotOffsetX");u([l.property({type:Number,attribute:"dot-offset-y"})],a.prototype,"dotOffsetY");u([l.property({attribute:"bg-color"})],a.prototype,"bgColor");u([l.property({type:Number,attribute:"angle-warm"})],a.prototype,"angleWarm");u([l.property({type:Number,attribute:"angle-cool"})],a.prototype,"angleCool");u([l.property({type:Number,attribute:"show-warm"})],a.prototype,"showWarm");u([l.property({type:Number,attribute:"show-cool"})],a.prototype,"showCool");u([l.property({attribute:"warm-color"})],a.prototype,"warmColor");u([l.property({attribute:"cool-color"})],a.prototype,"coolColor");u([l.property({type:Number,attribute:"blend-mode"})],a.prototype,"blendMode");u([l.property({type:Number,attribute:"loading-blur"})],a.prototype,"loadingBlur");u([l.state()],a.prototype,"_webglAvailable");u([l.state()],a.prototype,"_snapshotUrl");u([l.state()],a.prototype,"_snapshotLoaded");customElements.get("some-shade-image")||customElements.define("some-shade-image",a);exports.SomeShadeImage=a;exports.get=U;exports.list=X;exports.register=p;
@@ -1,72 +1,72 @@
1
- import { LitElement as k, css as L, html as y } from "lit";
1
+ import { LitElement as k, css as D, html as y } from "lit";
2
2
  import { property as u, state as w } from "lit/decorators.js";
3
- function D(t) {
3
+ function L(t) {
4
4
  return t.getContext("webgl", {
5
5
  alpha: !0,
6
6
  premultipliedAlpha: !1,
7
7
  preserveDrawingBuffer: !0
8
8
  });
9
9
  }
10
- function T(t, o, r) {
11
- const a = t.createShader(o);
12
- if (!a) throw new Error("Failed to create shader");
13
- if (t.shaderSource(a, r), t.compileShader(a), !t.getShaderParameter(a, t.COMPILE_STATUS)) {
14
- const e = t.getShaderInfoLog(a);
15
- throw t.deleteShader(a), new Error(`Shader compile error: ${e}`);
10
+ function T(t, o, n) {
11
+ const i = t.createShader(o);
12
+ if (!i) throw new Error("Failed to create shader");
13
+ if (t.shaderSource(i, n), t.compileShader(i), !t.getShaderParameter(i, t.COMPILE_STATUS)) {
14
+ const e = t.getShaderInfoLog(i);
15
+ throw t.deleteShader(i), new Error(`Shader compile error: ${e}`);
16
16
  }
17
- return a;
17
+ return i;
18
18
  }
19
- function z(t, o, r) {
20
- const a = T(t, t.VERTEX_SHADER, o), e = T(t, t.FRAGMENT_SHADER, r), n = t.createProgram();
21
- if (!n) throw new Error("Failed to create program");
22
- if (t.attachShader(n, a), t.attachShader(n, e), t.linkProgram(n), !t.getProgramParameter(n, t.LINK_STATUS)) {
23
- const d = t.getProgramInfoLog(n);
24
- throw t.deleteProgram(n), new Error(`Program link error: ${d}`);
19
+ function z(t, o, n) {
20
+ const i = T(t, t.VERTEX_SHADER, o), e = T(t, t.FRAGMENT_SHADER, n), r = t.createProgram();
21
+ if (!r) throw new Error("Failed to create program");
22
+ if (t.attachShader(r, i), t.attachShader(r, e), t.linkProgram(r), !t.getProgramParameter(r, t.LINK_STATUS)) {
23
+ const d = t.getProgramInfoLog(r);
24
+ throw t.deleteProgram(r), new Error(`Program link error: ${d}`);
25
25
  }
26
- t.deleteShader(a), t.deleteShader(e);
27
- const c = /* @__PURE__ */ new Map(), h = t.getProgramParameter(n, t.ACTIVE_ATTRIBUTES);
26
+ t.deleteShader(i), t.deleteShader(e);
27
+ const c = /* @__PURE__ */ new Map(), h = t.getProgramParameter(r, t.ACTIVE_ATTRIBUTES);
28
28
  for (let d = 0; d < h; d++) {
29
- const f = t.getActiveAttrib(n, d);
30
- f && c.set(f.name, t.getAttribLocation(n, f.name));
29
+ const f = t.getActiveAttrib(r, d);
30
+ f && c.set(f.name, t.getAttribLocation(r, f.name));
31
31
  }
32
- const i = /* @__PURE__ */ new Map(), _ = t.getProgramParameter(n, t.ACTIVE_UNIFORMS);
32
+ const s = /* @__PURE__ */ new Map(), _ = t.getProgramParameter(r, t.ACTIVE_UNIFORMS);
33
33
  for (let d = 0; d < _; d++) {
34
- const f = t.getActiveUniform(n, d);
34
+ const f = t.getActiveUniform(r, d);
35
35
  if (f) {
36
- const m = t.getUniformLocation(n, f.name);
37
- m && i.set(f.name, m);
36
+ const m = t.getUniformLocation(r, f.name);
37
+ m && s.set(f.name, m);
38
38
  }
39
39
  }
40
- return { program: n, attribLocations: c, uniformLocations: i };
40
+ return { program: r, attribLocations: c, uniformLocations: s };
41
41
  }
42
- function P(t, o, r) {
43
- for (const [a, e] of Object.entries(r)) {
44
- const n = o.uniformLocations.get(a);
45
- if (n) {
42
+ function M(t, o, n) {
43
+ for (const [i, e] of Object.entries(n)) {
44
+ const r = o.uniformLocations.get(i);
45
+ if (r) {
46
46
  if (typeof e == "number")
47
- t.uniform1f(n, e);
47
+ t.uniform1f(r, e);
48
48
  else if (Array.isArray(e))
49
49
  switch (e.length) {
50
50
  case 2:
51
- t.uniform2fv(n, e);
51
+ t.uniform2fv(r, e);
52
52
  break;
53
53
  case 3:
54
- t.uniform3fv(n, e);
54
+ t.uniform3fv(r, e);
55
55
  break;
56
56
  case 4:
57
- t.uniform4fv(n, e);
57
+ t.uniform4fv(r, e);
58
58
  break;
59
59
  }
60
60
  }
61
61
  }
62
62
  }
63
- function O(t, o) {
64
- const r = t.createTexture();
65
- if (!r) throw new Error("Failed to create texture");
66
- return t.bindTexture(t.TEXTURE_2D, r), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, o), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR), { texture: r, width: o.naturalWidth, height: o.naturalHeight };
63
+ function P(t, o) {
64
+ const n = t.createTexture();
65
+ if (!n) throw new Error("Failed to create texture");
66
+ return t.bindTexture(t.TEXTURE_2D, n), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, o), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR), { texture: n, width: o.naturalWidth, height: o.naturalHeight };
67
67
  }
68
- function I(t, o) {
69
- const r = new Float32Array([
68
+ function O(t, o) {
69
+ const n = new Float32Array([
70
70
  // pos.x pos.y tex.s tex.t
71
71
  -1,
72
72
  -1,
@@ -84,15 +84,15 @@ function I(t, o) {
84
84
  1,
85
85
  1,
86
86
  0
87
- ]), a = t.createBuffer();
88
- if (!a) throw new Error("Failed to create buffer");
89
- t.bindBuffer(t.ARRAY_BUFFER, a), t.bufferData(t.ARRAY_BUFFER, r, t.STATIC_DRAW);
90
- const e = 4 * Float32Array.BYTES_PER_ELEMENT, n = o.attribLocations.get("a_position");
91
- n !== void 0 && n !== -1 && (t.enableVertexAttribArray(n), t.vertexAttribPointer(n, 2, t.FLOAT, !1, e, 0));
87
+ ]), i = t.createBuffer();
88
+ if (!i) throw new Error("Failed to create buffer");
89
+ t.bindBuffer(t.ARRAY_BUFFER, i), t.bufferData(t.ARRAY_BUFFER, n, t.STATIC_DRAW);
90
+ const e = 4 * Float32Array.BYTES_PER_ELEMENT, r = o.attribLocations.get("a_position");
91
+ r !== void 0 && r !== -1 && (t.enableVertexAttribArray(r), t.vertexAttribPointer(r, 2, t.FLOAT, !1, e, 0));
92
92
  const c = o.attribLocations.get("a_texCoord");
93
- return c !== void 0 && c !== -1 && (t.enableVertexAttribArray(c), t.vertexAttribPointer(c, 2, t.FLOAT, !1, e, 2 * Float32Array.BYTES_PER_ELEMENT)), a;
93
+ return c !== void 0 && c !== -1 && (t.enableVertexAttribArray(c), t.vertexAttribPointer(c, 2, t.FLOAT, !1, e, 2 * Float32Array.BYTES_PER_ELEMENT)), i;
94
94
  }
95
- function M(t) {
95
+ function I(t) {
96
96
  t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
97
97
  }
98
98
  const V = `precision mediump float;
@@ -181,7 +181,7 @@ void main() {
181
181
 
182
182
  gl_FragColor = vec4(outR, outG, outB, texture2D(u_image, v_texCoord).a);
183
183
  }
184
- `, v = `attribute vec2 a_position;
184
+ `, b = `attribute vec2 a_position;
185
185
  attribute vec2 a_texCoord;
186
186
  varying vec2 v_texCoord;
187
187
 
@@ -189,10 +189,10 @@ void main() {
189
189
  gl_Position = vec4(a_position, 0.0, 1.0);
190
190
  v_texCoord = a_texCoord;
191
191
  }
192
- `, N = {
192
+ `, W = {
193
193
  name: "halftone-cmyk",
194
194
  fragmentShader: V,
195
- vertexShader: v,
195
+ vertexShader: b,
196
196
  uniforms: [
197
197
  { name: "u_dotRadius", type: "float", default: 4, attribute: "dot-radius" },
198
198
  { name: "u_gridSize", type: "float", default: 8, attribute: "grid-size" },
@@ -206,7 +206,7 @@ void main() {
206
206
  { name: "u_showK", type: "float", default: 1, attribute: "show-k" },
207
207
  { name: "u_intensityK", type: "float", default: 1, attribute: "intensity-k" }
208
208
  ]
209
- }, W = `precision mediump float;
209
+ }, N = `precision mediump float;
210
210
 
211
211
  varying vec2 v_texCoord;
212
212
 
@@ -250,15 +250,15 @@ void main() {
250
250
  }
251
251
  `, F = {
252
252
  name: "halftone-duotone",
253
- fragmentShader: W,
254
- vertexShader: v,
253
+ fragmentShader: N,
254
+ vertexShader: b,
255
255
  uniforms: [
256
256
  { name: "u_dotRadius", type: "float", default: 4, attribute: "dot-radius" },
257
257
  { name: "u_gridSize", type: "float", default: 8, attribute: "grid-size" },
258
258
  { name: "u_duotoneColor", type: "vec3", default: [0, 0.6, 0.8], attribute: "duotone-color" },
259
259
  { name: "u_angle", type: "float", default: 0, attribute: "angle" }
260
260
  ]
261
- }, Y = `precision mediump float;
261
+ }, B = `precision mediump float;
262
262
 
263
263
  varying vec2 v_texCoord;
264
264
 
@@ -314,10 +314,10 @@ void main() {
314
314
 
315
315
  gl_FragColor = vec4(result, 1.0);
316
316
  }
317
- `, B = {
317
+ `, Y = {
318
318
  name: "dot-grid",
319
- fragmentShader: Y,
320
- vertexShader: v,
319
+ fragmentShader: B,
320
+ vertexShader: b,
321
321
  uniforms: [
322
322
  { name: "u_dotRadius", type: "float", default: 4, attribute: "dot-radius" },
323
323
  { name: "u_gridSize", type: "float", default: 8, attribute: "grid-size" },
@@ -341,6 +341,8 @@ uniform float u_showCool;
341
341
  uniform float u_showK;
342
342
  uniform vec3 u_warmColor;
343
343
  uniform vec3 u_coolColor;
344
+ uniform float u_blendMode;
345
+ uniform float u_intensityK;
344
346
 
345
347
  float halftone(vec2 uv, float angle, float channelValue, float gridSize, float dotRadius) {
346
348
  float rad = radians(angle);
@@ -367,27 +369,52 @@ void main() {
367
369
 
368
370
  // Black channel: derived from overall darkness
369
371
  float k = 1.0 - max(warmSep, coolSep);
372
+ k = clamp(k * u_intensityK, 0.0, 1.0);
370
373
 
371
374
  // Halftone dots for each channel
372
375
  float warmDot = halftone(uv, u_angleWarm, warmSep, u_gridSize, u_dotRadius) * u_showWarm;
373
376
  float coolDot = halftone(uv, u_angleCool, coolSep, u_gridSize, u_dotRadius) * u_showCool;
374
377
  float kDot = halftone(uv, u_angleK, k, u_gridSize, u_dotRadius) * u_showK;
375
378
 
376
- // Subtractive mixing: start with white paper, subtract dye layers
377
- vec3 paper = vec3(1.0);
378
- paper -= warmDot * (vec3(1.0) - u_warmColor);
379
- paper -= coolDot * (vec3(1.0) - u_coolColor);
380
- paper *= (1.0 - kDot);
379
+ // Blend modes affect how warm and cool dots combine where they overlap.
380
+ // All modes use white paper; individual dots look the same.
381
+ // Only the overlap regions differ between modes.
382
+ vec3 overlap;
383
+ if (u_blendMode < 0.5) {
384
+ // Subtractive: dye overlap absorbs more light (darker)
385
+ overlap = u_warmColor + u_coolColor - vec3(1.0);
386
+ } else if (u_blendMode < 1.5) {
387
+ // Additive: light overlap adds up (brighter)
388
+ overlap = u_warmColor + u_coolColor;
389
+ } else {
390
+ // Screen: soft additive overlap with natural clamping
391
+ overlap = vec3(1.0) - (vec3(1.0) - u_warmColor) * (vec3(1.0) - u_coolColor);
392
+ }
393
+
394
+ // Decompose into four halftone regions
395
+ float onlyWarm = warmDot * (1.0 - coolDot);
396
+ float onlyCool = coolDot * (1.0 - warmDot);
397
+ float both = warmDot * coolDot;
398
+ float neither = (1.0 - warmDot) * (1.0 - coolDot);
381
399
 
382
- gl_FragColor = vec4(clamp(paper, 0.0, 1.0), color.a);
400
+ // Composite: white paper base, colored dots, blend-mode-dependent overlap
401
+ vec3 result = neither * vec3(1.0)
402
+ + onlyWarm * u_warmColor
403
+ + onlyCool * u_coolColor
404
+ + both * overlap;
405
+
406
+ // K channel darkening with intensity control
407
+ result *= (1.0 - kDot);
408
+
409
+ gl_FragColor = vec4(clamp(result, 0.0, 1.0), color.a);
383
410
  }
384
411
  `, $ = {
385
412
  name: "technicolor-2strip",
386
413
  fragmentShader: X,
387
- vertexShader: v,
414
+ vertexShader: b,
388
415
  uniforms: [
389
- { name: "u_dotRadius", type: "float", default: 4, attribute: "dot-radius" },
390
- { name: "u_gridSize", type: "float", default: 8, attribute: "grid-size" },
416
+ { name: "u_dotRadius", type: "float", default: 7, attribute: "dot-radius" },
417
+ { name: "u_gridSize", type: "float", default: 10, attribute: "grid-size" },
391
418
  { name: "u_angleWarm", type: "float", default: 15, attribute: "angle-warm" },
392
419
  { name: "u_angleCool", type: "float", default: 75, attribute: "angle-cool" },
393
420
  { name: "u_angleK", type: "float", default: 45, attribute: "angle-k" },
@@ -395,10 +422,12 @@ void main() {
395
422
  { name: "u_showCool", type: "float", default: 1, attribute: "show-cool" },
396
423
  { name: "u_showK", type: "float", default: 1, attribute: "show-k" },
397
424
  { name: "u_warmColor", type: "vec3", default: [0.85, 0.25, 0.06], attribute: "warm-color" },
398
- { name: "u_coolColor", type: "vec3", default: [0.05, 0.65, 0.6], attribute: "cool-color" }
425
+ { name: "u_coolColor", type: "vec3", default: [0.05, 0.65, 0.6], attribute: "cool-color" },
426
+ { name: "u_blendMode", type: "float", default: 1, attribute: "blend-mode" },
427
+ { name: "u_intensityK", type: "float", default: 1, attribute: "intensity-k" }
399
428
  ]
400
429
  }, C = /* @__PURE__ */ new Map();
401
- function b(t) {
430
+ function v(t) {
402
431
  C.set(t.name, t);
403
432
  }
404
433
  function G(t) {
@@ -407,14 +436,14 @@ function G(t) {
407
436
  function Z() {
408
437
  return Array.from(C.keys());
409
438
  }
410
- b(N);
411
- b(F);
412
- b(B);
413
- b($);
414
- var H = Object.defineProperty, l = (t, o, r, a) => {
415
- for (var e = void 0, n = t.length - 1, c; n >= 0; n--)
416
- (c = t[n]) && (e = c(o, r, e) || e);
417
- return e && H(o, r, e), e;
439
+ v(W);
440
+ v(F);
441
+ v(Y);
442
+ v($);
443
+ var H = Object.defineProperty, l = (t, o, n, i) => {
444
+ for (var e = void 0, r = t.length - 1, c; r >= 0; r--)
445
+ (c = t[r]) && (e = c(o, n, e) || e);
446
+ return e && H(o, n, e), e;
418
447
  };
419
448
  const q = 2;
420
449
  let A = Promise.resolve();
@@ -445,10 +474,11 @@ const j = /* @__PURE__ */ new Set([
445
474
  "showWarm",
446
475
  "showCool",
447
476
  "warmColor",
448
- "coolColor"
477
+ "coolColor",
478
+ "blendMode"
449
479
  ]), R = class R extends k {
450
480
  constructor() {
451
- super(...arguments), this.src = "", this.effect = "halftone-cmyk", this.dotRadius = 4, this.gridSize = 8, this.angleC = 15, this.angleM = 75, this.angleY = 0, this.angleK = 45, this.showC = 1, this.showM = 1, this.showY = 1, this.showK = 1, this.intensityK = 1, this.duotoneColor = "#0099cc", this.angle = 0, this.dotOffsetX = 0.5, this.dotOffsetY = 0.5, this.bgColor = "#ffffff", this.angleWarm = 15, this.angleCool = 75, this.showWarm = 1, this.showCool = 1, this.warmColor = "#d94010", this.coolColor = "#0da699", this.loadingBlur = 0, this._webglAvailable = !0, this._snapshotUrl = "", this._snapshotLoaded = !1, this._image = null, this._observer = null, this._resizeObserver = null, this._lastClientWidth = 0, this._visible = !1, this._needsRender = !1;
481
+ super(...arguments), this.src = "", this.effect = "halftone-cmyk", this.dotRadius = 4, this.gridSize = 8, this.angleC = 15, this.angleM = 75, this.angleY = 0, this.angleK = 45, this.showC = 1, this.showM = 1, this.showY = 1, this.showK = 1, this.intensityK = 1, this.duotoneColor = "#0099cc", this.angle = 0, this.dotOffsetX = 0.5, this.dotOffsetY = 0.5, this.bgColor = "#ffffff", this.angleWarm = 15, this.angleCool = 75, this.showWarm = 1, this.showCool = 1, this.warmColor = "#d94010", this.coolColor = "#0da699", this.blendMode = 1, this.loadingBlur = 0, this._webglAvailable = !0, this._snapshotUrl = "", this._snapshotLoaded = !1, this._image = null, this._observer = null, this._resizeObserver = null, this._lastClientWidth = 0, this._visible = !1, this._needsRender = !1;
452
482
  }
453
483
  render() {
454
484
  if (!this._webglAvailable)
@@ -466,9 +496,9 @@ const j = /* @__PURE__ */ new Set([
466
496
  connectedCallback() {
467
497
  super.connectedCallback(), this._observer = new IntersectionObserver(
468
498
  (o) => {
469
- var a;
470
- const r = this._visible;
471
- this._visible = ((a = o[0]) == null ? void 0 : a.isIntersecting) ?? !1, this._visible && !r && this._needsRender && (this._needsRender = !1, U(() => this._renderEffect()));
499
+ var i;
500
+ const n = this._visible;
501
+ this._visible = ((i = o[0]) == null ? void 0 : i.isIntersecting) ?? !1, this._visible && !n && this._needsRender && (this._needsRender = !1, U(() => this._renderEffect()));
472
502
  },
473
503
  // Start rendering slightly before the element scrolls into view.
474
504
  { rootMargin: "200px" }
@@ -485,23 +515,23 @@ const j = /* @__PURE__ */ new Set([
485
515
  }
486
516
  if (!this._image) return;
487
517
  [...o.keys()].some(
488
- (a) => j.has(a)
518
+ (i) => j.has(i)
489
519
  ) && this._scheduleRender();
490
520
  }
491
521
  disconnectedCallback() {
492
- var o, r;
493
- super.disconnectedCallback(), (o = this._observer) == null || o.disconnect(), (r = this._resizeObserver) == null || r.disconnect(), this._revokeSnapshot();
522
+ var o, n;
523
+ super.disconnectedCallback(), (o = this._observer) == null || o.disconnect(), (n = this._resizeObserver) == null || n.disconnect(), this._revokeSnapshot();
494
524
  }
495
525
  // ---------------------------------------------------------------------------
496
526
  // Image loading
497
527
  // ---------------------------------------------------------------------------
498
528
  _loadImage(o) {
499
- const r = new Image();
500
- r.crossOrigin = "anonymous", r.onload = () => {
501
- this._image = r, this._scheduleRender();
502
- }, r.onerror = () => {
529
+ const n = new Image();
530
+ n.crossOrigin = "anonymous", n.onload = () => {
531
+ this._image = n, this._scheduleRender();
532
+ }, n.onerror = () => {
503
533
  console.warn(`[some-shade] Failed to load image: ${o}`);
504
- }, r.src = o;
534
+ }, n.src = o;
505
535
  }
506
536
  // ---------------------------------------------------------------------------
507
537
  // Render scheduling
@@ -520,47 +550,47 @@ const j = /* @__PURE__ */ new Set([
520
550
  console.warn(`[some-shade] Unknown effect: ${this.effect}`);
521
551
  return;
522
552
  }
523
- const r = Math.min(window.devicePixelRatio || 1, q), a = this._image.naturalWidth, e = this._image.naturalHeight, n = this.clientWidth || a, c = Math.max(1, a / n);
553
+ const n = Math.min(window.devicePixelRatio || 1, q), i = this._image.naturalWidth, e = this._image.naturalHeight, r = this.clientWidth || i, c = Math.max(1, i / r);
524
554
  this._lastClientWidth = this.clientWidth;
525
555
  const h = document.createElement("canvas");
526
- h.width = a * r, h.height = e * r;
527
- const i = D(h);
528
- if (!i) {
556
+ h.width = i * n, h.height = e * n;
557
+ const s = L(h);
558
+ if (!s) {
529
559
  this._webglAvailable = !1;
530
560
  return;
531
561
  }
532
562
  try {
533
563
  const d = z(
534
- i,
564
+ s,
535
565
  o.vertexShader,
536
566
  o.fragmentShader
537
567
  );
538
- i.useProgram(d.program);
539
- const f = O(i, this._image), m = I(i, d);
540
- i.viewport(0, 0, h.width, h.height), i.clearColor(0, 0, 0, 0), i.clear(i.COLOR_BUFFER_BIT), i.activeTexture(i.TEXTURE0), i.bindTexture(i.TEXTURE_2D, f.texture);
568
+ s.useProgram(d.program);
569
+ const f = P(s, this._image), m = O(s, d);
570
+ s.viewport(0, 0, h.width, h.height), s.clearColor(0, 0, 0, 0), s.clear(s.COLOR_BUFFER_BIT), s.activeTexture(s.TEXTURE0), s.bindTexture(s.TEXTURE_2D, f.texture);
541
571
  const S = d.uniformLocations.get("u_image");
542
- S && i.uniform1i(S, 0), P(
543
- i,
572
+ S && s.uniform1i(S, 0), M(
573
+ s,
544
574
  d,
545
- this._getUniformValues(f, r, c)
546
- ), i.bindBuffer(i.ARRAY_BUFFER, m);
575
+ this._getUniformValues(f, n, c)
576
+ ), s.bindBuffer(s.ARRAY_BUFFER, m);
547
577
  const x = 4 * Float32Array.BYTES_PER_ELEMENT, g = d.attribLocations.get("a_position");
548
- g !== void 0 && g !== -1 && (i.enableVertexAttribArray(g), i.vertexAttribPointer(g, 2, i.FLOAT, !1, x, 0));
578
+ g !== void 0 && g !== -1 && (s.enableVertexAttribArray(g), s.vertexAttribPointer(g, 2, s.FLOAT, !1, x, 0));
549
579
  const p = d.attribLocations.get("a_texCoord");
550
- p !== void 0 && p !== -1 && (i.enableVertexAttribArray(p), i.vertexAttribPointer(
580
+ p !== void 0 && p !== -1 && (s.enableVertexAttribArray(p), s.vertexAttribPointer(
551
581
  p,
552
582
  2,
553
- i.FLOAT,
583
+ s.FLOAT,
554
584
  !1,
555
585
  x,
556
586
  2 * Float32Array.BYTES_PER_ELEMENT
557
- )), M(i);
587
+ )), I(s);
558
588
  const E = await new Promise(
559
589
  (K) => h.toBlob(K)
560
590
  );
561
- i.deleteTexture(f.texture), i.deleteProgram(d.program), i.deleteBuffer(m), E && (this._snapshotLoaded = !1, this._revokeSnapshot(), this._snapshotUrl = URL.createObjectURL(E));
591
+ s.deleteTexture(f.texture), s.deleteProgram(d.program), s.deleteBuffer(m), E && (this._snapshotLoaded = !1, this._revokeSnapshot(), this._snapshotUrl = URL.createObjectURL(E));
562
592
  } finally {
563
- (_ = i.getExtension("WEBGL_lose_context")) == null || _.loseContext();
593
+ (_ = s.getExtension("WEBGL_lose_context")) == null || _.loseContext();
564
594
  }
565
595
  }
566
596
  // ---------------------------------------------------------------------------
@@ -581,19 +611,19 @@ const j = /* @__PURE__ */ new Set([
581
611
  _revokeSnapshot() {
582
612
  this._snapshotUrl && (URL.revokeObjectURL(this._snapshotUrl), this._snapshotUrl = "");
583
613
  }
584
- _getUniformValues(o, r, a) {
614
+ _getUniformValues(o, n, i) {
585
615
  const e = {};
586
616
  return e.u_resolution = [
587
- o.width * r,
588
- o.height * r
589
- ], e.u_dotRadius = this.dotRadius * a, e.u_gridSize = this.gridSize * a, this.effect === "halftone-cmyk" ? (e.u_angleC = this.angleC, e.u_angleM = this.angleM, e.u_angleY = this.angleY, e.u_angleK = this.angleK, e.u_showC = this.showC, e.u_showM = this.showM, e.u_showY = this.showY, e.u_showK = this.showK, e.u_intensityK = this.intensityK) : this.effect === "halftone-duotone" ? (e.u_duotoneColor = this._parseHexColor(this.duotoneColor), e.u_angle = this.angle) : this.effect === "dot-grid" ? (e.u_dotOffset = [this.dotOffsetX, this.dotOffsetY], e.u_bgColor = this._parseHexColor(this.bgColor), e.u_angle = this.angle) : this.effect === "technicolor-2strip" && (e.u_angleWarm = this.angleWarm, e.u_angleCool = this.angleCool, e.u_angleK = this.angleK, e.u_showWarm = this.showWarm, e.u_showCool = this.showCool, e.u_showK = this.showK, e.u_warmColor = this._parseHexColor(this.warmColor), e.u_coolColor = this._parseHexColor(this.coolColor)), e;
617
+ o.width * n,
618
+ o.height * n
619
+ ], e.u_dotRadius = this.dotRadius * i, e.u_gridSize = this.gridSize * i, this.effect === "halftone-cmyk" ? (e.u_angleC = this.angleC, e.u_angleM = this.angleM, e.u_angleY = this.angleY, e.u_angleK = this.angleK, e.u_showC = this.showC, e.u_showM = this.showM, e.u_showY = this.showY, e.u_showK = this.showK, e.u_intensityK = this.intensityK) : this.effect === "halftone-duotone" ? (e.u_duotoneColor = this._parseHexColor(this.duotoneColor), e.u_angle = this.angle) : this.effect === "dot-grid" ? (e.u_dotOffset = [this.dotOffsetX, this.dotOffsetY], e.u_bgColor = this._parseHexColor(this.bgColor), e.u_angle = this.angle) : this.effect === "technicolor-2strip" && (e.u_angleWarm = this.angleWarm, e.u_angleCool = this.angleCool, e.u_angleK = this.angleK, e.u_showWarm = this.showWarm, e.u_showCool = this.showCool, e.u_showK = this.showK, e.u_warmColor = this._parseHexColor(this.warmColor), e.u_coolColor = this._parseHexColor(this.coolColor), e.u_blendMode = this.blendMode, e.u_intensityK = this.intensityK), e;
590
620
  }
591
621
  _parseHexColor(o) {
592
- const r = o.replace("#", ""), a = parseInt(r.substring(0, 2), 16) / 255, e = parseInt(r.substring(2, 4), 16) / 255, n = parseInt(r.substring(4, 6), 16) / 255;
593
- return [a, e, n];
622
+ const n = o.replace("#", ""), i = parseInt(n.substring(0, 2), 16) / 255, e = parseInt(n.substring(2, 4), 16) / 255, r = parseInt(n.substring(4, 6), 16) / 255;
623
+ return [i, e, r];
594
624
  }
595
625
  };
596
- R.styles = L`
626
+ R.styles = D`
597
627
  :host {
598
628
  display: block;
599
629
  position: relative;
@@ -617,95 +647,98 @@ R.styles = L`
617
647
  opacity: 1;
618
648
  }
619
649
  `;
620
- let s = R;
650
+ let a = R;
621
651
  l([
622
652
  u()
623
- ], s.prototype, "src");
653
+ ], a.prototype, "src");
624
654
  l([
625
655
  u()
626
- ], s.prototype, "effect");
656
+ ], a.prototype, "effect");
627
657
  l([
628
658
  u({ type: Number, attribute: "dot-radius" })
629
- ], s.prototype, "dotRadius");
659
+ ], a.prototype, "dotRadius");
630
660
  l([
631
661
  u({ type: Number, attribute: "grid-size" })
632
- ], s.prototype, "gridSize");
662
+ ], a.prototype, "gridSize");
633
663
  l([
634
664
  u({ type: Number, attribute: "angle-c" })
635
- ], s.prototype, "angleC");
665
+ ], a.prototype, "angleC");
636
666
  l([
637
667
  u({ type: Number, attribute: "angle-m" })
638
- ], s.prototype, "angleM");
668
+ ], a.prototype, "angleM");
639
669
  l([
640
670
  u({ type: Number, attribute: "angle-y" })
641
- ], s.prototype, "angleY");
671
+ ], a.prototype, "angleY");
642
672
  l([
643
673
  u({ type: Number, attribute: "angle-k" })
644
- ], s.prototype, "angleK");
674
+ ], a.prototype, "angleK");
645
675
  l([
646
676
  u({ type: Number, attribute: "show-c" })
647
- ], s.prototype, "showC");
677
+ ], a.prototype, "showC");
648
678
  l([
649
679
  u({ type: Number, attribute: "show-m" })
650
- ], s.prototype, "showM");
680
+ ], a.prototype, "showM");
651
681
  l([
652
682
  u({ type: Number, attribute: "show-y" })
653
- ], s.prototype, "showY");
683
+ ], a.prototype, "showY");
654
684
  l([
655
685
  u({ type: Number, attribute: "show-k" })
656
- ], s.prototype, "showK");
686
+ ], a.prototype, "showK");
657
687
  l([
658
688
  u({ type: Number, attribute: "intensity-k" })
659
- ], s.prototype, "intensityK");
689
+ ], a.prototype, "intensityK");
660
690
  l([
661
691
  u({ attribute: "duotone-color" })
662
- ], s.prototype, "duotoneColor");
692
+ ], a.prototype, "duotoneColor");
663
693
  l([
664
694
  u({ type: Number })
665
- ], s.prototype, "angle");
695
+ ], a.prototype, "angle");
666
696
  l([
667
697
  u({ type: Number, attribute: "dot-offset-x" })
668
- ], s.prototype, "dotOffsetX");
698
+ ], a.prototype, "dotOffsetX");
669
699
  l([
670
700
  u({ type: Number, attribute: "dot-offset-y" })
671
- ], s.prototype, "dotOffsetY");
701
+ ], a.prototype, "dotOffsetY");
672
702
  l([
673
703
  u({ attribute: "bg-color" })
674
- ], s.prototype, "bgColor");
704
+ ], a.prototype, "bgColor");
675
705
  l([
676
706
  u({ type: Number, attribute: "angle-warm" })
677
- ], s.prototype, "angleWarm");
707
+ ], a.prototype, "angleWarm");
678
708
  l([
679
709
  u({ type: Number, attribute: "angle-cool" })
680
- ], s.prototype, "angleCool");
710
+ ], a.prototype, "angleCool");
681
711
  l([
682
712
  u({ type: Number, attribute: "show-warm" })
683
- ], s.prototype, "showWarm");
713
+ ], a.prototype, "showWarm");
684
714
  l([
685
715
  u({ type: Number, attribute: "show-cool" })
686
- ], s.prototype, "showCool");
716
+ ], a.prototype, "showCool");
687
717
  l([
688
718
  u({ attribute: "warm-color" })
689
- ], s.prototype, "warmColor");
719
+ ], a.prototype, "warmColor");
690
720
  l([
691
721
  u({ attribute: "cool-color" })
692
- ], s.prototype, "coolColor");
722
+ ], a.prototype, "coolColor");
723
+ l([
724
+ u({ type: Number, attribute: "blend-mode" })
725
+ ], a.prototype, "blendMode");
693
726
  l([
694
727
  u({ type: Number, attribute: "loading-blur" })
695
- ], s.prototype, "loadingBlur");
728
+ ], a.prototype, "loadingBlur");
696
729
  l([
697
730
  w()
698
- ], s.prototype, "_webglAvailable");
731
+ ], a.prototype, "_webglAvailable");
699
732
  l([
700
733
  w()
701
- ], s.prototype, "_snapshotUrl");
734
+ ], a.prototype, "_snapshotUrl");
702
735
  l([
703
736
  w()
704
- ], s.prototype, "_snapshotLoaded");
705
- customElements.get("some-shade-image") || customElements.define("some-shade-image", s);
737
+ ], a.prototype, "_snapshotLoaded");
738
+ customElements.get("some-shade-image") || customElements.define("some-shade-image", a);
706
739
  export {
707
- s as SomeShadeImage,
740
+ a as SomeShadeImage,
708
741
  G as get,
709
742
  Z as list,
710
- b as register
743
+ v as register
711
744
  };
@@ -1,4 +1,4 @@
1
- (function(c,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("lit"),require("lit/decorators.js")):typeof define=="function"&&define.amd?define(["exports","lit","lit/decorators.js"],m):(c=typeof globalThis<"u"?globalThis:c||self,m(c.SomeShade={},c.Lit,c.LitDecorators))})(this,(function(c,m,l){"use strict";function k(t){return t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}function S(t,o,n){const i=t.createShader(o);if(!i)throw new Error("Failed to create shader");if(t.shaderSource(i,n),t.compileShader(i),!t.getShaderParameter(i,t.COMPILE_STATUS)){const e=t.getShaderInfoLog(i);throw t.deleteShader(i),new Error(`Shader compile error: ${e}`)}return i}function L(t,o,n){const i=S(t,t.VERTEX_SHADER,o),e=S(t,t.FRAGMENT_SHADER,n),r=t.createProgram();if(!r)throw new Error("Failed to create program");if(t.attachShader(r,i),t.attachShader(r,e),t.linkProgram(r),!t.getProgramParameter(r,t.LINK_STATUS)){const f=t.getProgramInfoLog(r);throw t.deleteProgram(r),new Error(`Program link error: ${f}`)}t.deleteShader(i),t.deleteShader(e);const d=new Map,p=t.getProgramParameter(r,t.ACTIVE_ATTRIBUTES);for(let f=0;f<p;f++){const h=t.getActiveAttrib(r,f);h&&d.set(h.name,t.getAttribLocation(r,h.name))}const s=new Map,b=t.getProgramParameter(r,t.ACTIVE_UNIFORMS);for(let f=0;f<b;f++){const h=t.getActiveUniform(r,f);if(h){const _=t.getUniformLocation(r,h.name);_&&s.set(h.name,_)}}return{program:r,attribLocations:d,uniformLocations:s}}function D(t,o,n){for(const[i,e]of Object.entries(n)){const r=o.uniformLocations.get(i);if(r){if(typeof e=="number")t.uniform1f(r,e);else if(Array.isArray(e))switch(e.length){case 2:t.uniform2fv(r,e);break;case 3:t.uniform3fv(r,e);break;case 4:t.uniform4fv(r,e);break}}}}function z(t,o){const n=t.createTexture();if(!n)throw new Error("Failed to create texture");return t.bindTexture(t.TEXTURE_2D,n),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,o),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),{texture:n,width:o.naturalWidth,height:o.naturalHeight}}function P(t,o){const n=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=t.createBuffer();if(!i)throw new Error("Failed to create buffer");t.bindBuffer(t.ARRAY_BUFFER,i),t.bufferData(t.ARRAY_BUFFER,n,t.STATIC_DRAW);const e=4*Float32Array.BYTES_PER_ELEMENT,r=o.attribLocations.get("a_position");r!==void 0&&r!==-1&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,e,0));const d=o.attribLocations.get("a_texCoord");return d!==void 0&&d!==-1&&(t.enableVertexAttribArray(d),t.vertexAttribPointer(d,2,t.FLOAT,!1,e,2*Float32Array.BYTES_PER_ELEMENT)),i}function O(t){t.drawArrays(t.TRIANGLE_STRIP,0,4)}const I=`precision mediump float;
1
+ (function(c,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("lit"),require("lit/decorators.js")):typeof define=="function"&&define.amd?define(["exports","lit","lit/decorators.js"],m):(c=typeof globalThis<"u"?globalThis:c||self,m(c.SomeShade={},c.Lit,c.LitDecorators))})(this,(function(c,m,l){"use strict";function k(e){return e.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!0})}function S(e,o,n){const i=e.createShader(o);if(!i)throw new Error("Failed to create shader");if(e.shaderSource(i,n),e.compileShader(i),!e.getShaderParameter(i,e.COMPILE_STATUS)){const t=e.getShaderInfoLog(i);throw e.deleteShader(i),new Error(`Shader compile error: ${t}`)}return i}function D(e,o,n){const i=S(e,e.VERTEX_SHADER,o),t=S(e,e.FRAGMENT_SHADER,n),a=e.createProgram();if(!a)throw new Error("Failed to create program");if(e.attachShader(a,i),e.attachShader(a,t),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS)){const d=e.getProgramInfoLog(a);throw e.deleteProgram(a),new Error(`Program link error: ${d}`)}e.deleteShader(i),e.deleteShader(t);const f=new Map,p=e.getProgramParameter(a,e.ACTIVE_ATTRIBUTES);for(let d=0;d<p;d++){const h=e.getActiveAttrib(a,d);h&&f.set(h.name,e.getAttribLocation(a,h.name))}const s=new Map,v=e.getProgramParameter(a,e.ACTIVE_UNIFORMS);for(let d=0;d<v;d++){const h=e.getActiveUniform(a,d);if(h){const g=e.getUniformLocation(a,h.name);g&&s.set(h.name,g)}}return{program:a,attribLocations:f,uniformLocations:s}}function L(e,o,n){for(const[i,t]of Object.entries(n)){const a=o.uniformLocations.get(i);if(a){if(typeof t=="number")e.uniform1f(a,t);else if(Array.isArray(t))switch(t.length){case 2:e.uniform2fv(a,t);break;case 3:e.uniform3fv(a,t);break;case 4:e.uniform4fv(a,t);break}}}}function z(e,o){const n=e.createTexture();if(!n)throw new Error("Failed to create texture");return e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,o),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),{texture:n,width:o.naturalWidth,height:o.naturalHeight}}function M(e,o){const n=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=e.createBuffer();if(!i)throw new Error("Failed to create buffer");e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,n,e.STATIC_DRAW);const t=4*Float32Array.BYTES_PER_ELEMENT,a=o.attribLocations.get("a_position");a!==void 0&&a!==-1&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,2,e.FLOAT,!1,t,0));const f=o.attribLocations.get("a_texCoord");return f!==void 0&&f!==-1&&(e.enableVertexAttribArray(f),e.vertexAttribPointer(f,2,e.FLOAT,!1,t,2*Float32Array.BYTES_PER_ELEMENT)),i}function P(e){e.drawArrays(e.TRIANGLE_STRIP,0,4)}const O=`precision mediump float;
2
2
 
3
3
  varying vec2 v_texCoord;
4
4
 
@@ -84,7 +84,7 @@ void main() {
84
84
 
85
85
  gl_FragColor = vec4(outR, outG, outB, texture2D(u_image, v_texCoord).a);
86
86
  }
87
- `,v=`attribute vec2 a_position;
87
+ `,b=`attribute vec2 a_position;
88
88
  attribute vec2 a_texCoord;
89
89
  varying vec2 v_texCoord;
90
90
 
@@ -92,7 +92,7 @@ void main() {
92
92
  gl_Position = vec4(a_position, 0.0, 1.0);
93
93
  v_texCoord = a_texCoord;
94
94
  }
95
- `,M={name:"halftone-cmyk",fragmentShader:I,vertexShader:v,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleC",type:"float",default:15,attribute:"angle-c"},{name:"u_angleM",type:"float",default:75,attribute:"angle-m"},{name:"u_angleY",type:"float",default:0,attribute:"angle-y"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showC",type:"float",default:1,attribute:"show-c"},{name:"u_showM",type:"float",default:1,attribute:"show-m"},{name:"u_showY",type:"float",default:1,attribute:"show-y"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},V={name:"halftone-duotone",fragmentShader:`precision mediump float;
95
+ `,I={name:"halftone-cmyk",fragmentShader:O,vertexShader:b,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleC",type:"float",default:15,attribute:"angle-c"},{name:"u_angleM",type:"float",default:75,attribute:"angle-m"},{name:"u_angleY",type:"float",default:0,attribute:"angle-y"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showC",type:"float",default:1,attribute:"show-c"},{name:"u_showM",type:"float",default:1,attribute:"show-m"},{name:"u_showY",type:"float",default:1,attribute:"show-y"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},V={name:"halftone-duotone",fragmentShader:`precision mediump float;
96
96
 
97
97
  varying vec2 v_texCoord;
98
98
 
@@ -134,7 +134,7 @@ void main() {
134
134
 
135
135
  gl_FragColor = vec4(result, color.a);
136
136
  }
137
- `,vertexShader:v,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_duotoneColor",type:"vec3",default:[0,.6,.8],attribute:"duotone-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},N={name:"dot-grid",fragmentShader:`precision mediump float;
137
+ `,vertexShader:b,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_duotoneColor",type:"vec3",default:[0,.6,.8],attribute:"duotone-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},W={name:"dot-grid",fragmentShader:`precision mediump float;
138
138
 
139
139
  varying vec2 v_texCoord;
140
140
 
@@ -190,7 +190,7 @@ void main() {
190
190
 
191
191
  gl_FragColor = vec4(result, 1.0);
192
192
  }
193
- `,vertexShader:v,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_dotOffset",type:"vec2",default:[.5,.5],attribute:"dot-offset"},{name:"u_bgColor",type:"vec3",default:[1,1,1],attribute:"bg-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},W={name:"technicolor-2strip",fragmentShader:`precision mediump float;
193
+ `,vertexShader:b,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_dotOffset",type:"vec2",default:[.5,.5],attribute:"dot-offset"},{name:"u_bgColor",type:"vec3",default:[1,1,1],attribute:"bg-color"},{name:"u_angle",type:"float",default:0,attribute:"angle"}]},N={name:"technicolor-2strip",fragmentShader:`precision mediump float;
194
194
 
195
195
  varying vec2 v_texCoord;
196
196
 
@@ -206,6 +206,8 @@ uniform float u_showCool;
206
206
  uniform float u_showK;
207
207
  uniform vec3 u_warmColor;
208
208
  uniform vec3 u_coolColor;
209
+ uniform float u_blendMode;
210
+ uniform float u_intensityK;
209
211
 
210
212
  float halftone(vec2 uv, float angle, float channelValue, float gridSize, float dotRadius) {
211
213
  float rad = radians(angle);
@@ -232,28 +234,53 @@ void main() {
232
234
 
233
235
  // Black channel: derived from overall darkness
234
236
  float k = 1.0 - max(warmSep, coolSep);
237
+ k = clamp(k * u_intensityK, 0.0, 1.0);
235
238
 
236
239
  // Halftone dots for each channel
237
240
  float warmDot = halftone(uv, u_angleWarm, warmSep, u_gridSize, u_dotRadius) * u_showWarm;
238
241
  float coolDot = halftone(uv, u_angleCool, coolSep, u_gridSize, u_dotRadius) * u_showCool;
239
242
  float kDot = halftone(uv, u_angleK, k, u_gridSize, u_dotRadius) * u_showK;
240
243
 
241
- // Subtractive mixing: start with white paper, subtract dye layers
242
- vec3 paper = vec3(1.0);
243
- paper -= warmDot * (vec3(1.0) - u_warmColor);
244
- paper -= coolDot * (vec3(1.0) - u_coolColor);
245
- paper *= (1.0 - kDot);
244
+ // Blend modes affect how warm and cool dots combine where they overlap.
245
+ // All modes use white paper; individual dots look the same.
246
+ // Only the overlap regions differ between modes.
247
+ vec3 overlap;
248
+ if (u_blendMode < 0.5) {
249
+ // Subtractive: dye overlap absorbs more light (darker)
250
+ overlap = u_warmColor + u_coolColor - vec3(1.0);
251
+ } else if (u_blendMode < 1.5) {
252
+ // Additive: light overlap adds up (brighter)
253
+ overlap = u_warmColor + u_coolColor;
254
+ } else {
255
+ // Screen: soft additive overlap with natural clamping
256
+ overlap = vec3(1.0) - (vec3(1.0) - u_warmColor) * (vec3(1.0) - u_coolColor);
257
+ }
258
+
259
+ // Decompose into four halftone regions
260
+ float onlyWarm = warmDot * (1.0 - coolDot);
261
+ float onlyCool = coolDot * (1.0 - warmDot);
262
+ float both = warmDot * coolDot;
263
+ float neither = (1.0 - warmDot) * (1.0 - coolDot);
264
+
265
+ // Composite: white paper base, colored dots, blend-mode-dependent overlap
266
+ vec3 result = neither * vec3(1.0)
267
+ + onlyWarm * u_warmColor
268
+ + onlyCool * u_coolColor
269
+ + both * overlap;
270
+
271
+ // K channel darkening with intensity control
272
+ result *= (1.0 - kDot);
246
273
 
247
- gl_FragColor = vec4(clamp(paper, 0.0, 1.0), color.a);
274
+ gl_FragColor = vec4(clamp(result, 0.0, 1.0), color.a);
248
275
  }
249
- `,vertexShader:v,uniforms:[{name:"u_dotRadius",type:"float",default:4,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:8,attribute:"grid-size"},{name:"u_angleWarm",type:"float",default:15,attribute:"angle-warm"},{name:"u_angleCool",type:"float",default:75,attribute:"angle-cool"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showWarm",type:"float",default:1,attribute:"show-warm"},{name:"u_showCool",type:"float",default:1,attribute:"show-cool"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_warmColor",type:"vec3",default:[.85,.25,.06],attribute:"warm-color"},{name:"u_coolColor",type:"vec3",default:[.05,.65,.6],attribute:"cool-color"}]},C=new Map;function g(t){C.set(t.name,t)}function x(t){return C.get(t)}function F(){return Array.from(C.keys())}g(M),g(V),g(N),g(W);var Y=Object.defineProperty,u=(t,o,n,i)=>{for(var e=void 0,r=t.length-1,d;r>=0;r--)(d=t[r])&&(e=d(o,n,e)||e);return e&&Y(o,n,e),e};const B=2;let E=Promise.resolve();function T(t){const o=E.then(t,t);return E=o,o}const X=new Set(["effect","dotRadius","gridSize","angleC","angleM","angleY","angleK","showC","showM","showY","showK","intensityK","duotoneColor","angle","dotOffsetX","dotOffsetY","bgColor","angleWarm","angleCool","showWarm","showCool","warmColor","coolColor"]),R=class R extends m.LitElement{constructor(){super(...arguments),this.src="",this.effect="halftone-cmyk",this.dotRadius=4,this.gridSize=8,this.angleC=15,this.angleM=75,this.angleY=0,this.angleK=45,this.showC=1,this.showM=1,this.showY=1,this.showK=1,this.intensityK=1,this.duotoneColor="#0099cc",this.angle=0,this.dotOffsetX=.5,this.dotOffsetY=.5,this.bgColor="#ffffff",this.angleWarm=15,this.angleCool=75,this.showWarm=1,this.showCool=1,this.warmColor="#d94010",this.coolColor="#0da699",this.loadingBlur=0,this._webglAvailable=!0,this._snapshotUrl="",this._snapshotLoaded=!1,this._image=null,this._observer=null,this._resizeObserver=null,this._lastClientWidth=0,this._visible=!1,this._needsRender=!1}render(){if(!this._webglAvailable)return m.html`<img src=${this.src} alt="" />`;const o=this.loadingBlur>0?`filter: blur(${this.loadingBlur}px)`:"";return m.html`
276
+ `,vertexShader:b,uniforms:[{name:"u_dotRadius",type:"float",default:7,attribute:"dot-radius"},{name:"u_gridSize",type:"float",default:10,attribute:"grid-size"},{name:"u_angleWarm",type:"float",default:15,attribute:"angle-warm"},{name:"u_angleCool",type:"float",default:75,attribute:"angle-cool"},{name:"u_angleK",type:"float",default:45,attribute:"angle-k"},{name:"u_showWarm",type:"float",default:1,attribute:"show-warm"},{name:"u_showCool",type:"float",default:1,attribute:"show-cool"},{name:"u_showK",type:"float",default:1,attribute:"show-k"},{name:"u_warmColor",type:"vec3",default:[.85,.25,.06],attribute:"warm-color"},{name:"u_coolColor",type:"vec3",default:[.05,.65,.6],attribute:"cool-color"},{name:"u_blendMode",type:"float",default:1,attribute:"blend-mode"},{name:"u_intensityK",type:"float",default:1,attribute:"intensity-k"}]},C=new Map;function _(e){C.set(e.name,e)}function x(e){return C.get(e)}function F(){return Array.from(C.keys())}_(I),_(V),_(W),_(N);var B=Object.defineProperty,u=(e,o,n,i)=>{for(var t=void 0,a=e.length-1,f;a>=0;a--)(f=e[a])&&(t=f(o,n,t)||t);return t&&B(o,n,t),t};const Y=2;let E=Promise.resolve();function T(e){const o=E.then(e,e);return E=o,o}const X=new Set(["effect","dotRadius","gridSize","angleC","angleM","angleY","angleK","showC","showM","showY","showK","intensityK","duotoneColor","angle","dotOffsetX","dotOffsetY","bgColor","angleWarm","angleCool","showWarm","showCool","warmColor","coolColor","blendMode"]),R=class R extends m.LitElement{constructor(){super(...arguments),this.src="",this.effect="halftone-cmyk",this.dotRadius=4,this.gridSize=8,this.angleC=15,this.angleM=75,this.angleY=0,this.angleK=45,this.showC=1,this.showM=1,this.showY=1,this.showK=1,this.intensityK=1,this.duotoneColor="#0099cc",this.angle=0,this.dotOffsetX=.5,this.dotOffsetY=.5,this.bgColor="#ffffff",this.angleWarm=15,this.angleCool=75,this.showWarm=1,this.showCool=1,this.warmColor="#d94010",this.coolColor="#0da699",this.blendMode=1,this.loadingBlur=0,this._webglAvailable=!0,this._snapshotUrl="",this._snapshotLoaded=!1,this._image=null,this._observer=null,this._resizeObserver=null,this._lastClientWidth=0,this._visible=!1,this._needsRender=!1}render(){if(!this._webglAvailable)return m.html`<img src=${this.src} alt="" />`;const o=this.loadingBlur>0?`filter: blur(${this.loadingBlur}px)`:"";return m.html`
250
277
  <img src=${this.src} alt="" style=${o} />
251
278
  ${this._snapshotUrl?m.html`<img
252
279
  class="snapshot${this._snapshotLoaded?" loaded":""}"
253
280
  src=${this._snapshotUrl}
254
281
  @load=${this._onSnapshotLoad}
255
282
  alt="" />`:""}
256
- `}connectedCallback(){super.connectedCallback(),this._observer=new IntersectionObserver(o=>{var i;const n=this._visible;this._visible=((i=o[0])==null?void 0:i.isIntersecting)??!1,this._visible&&!n&&this._needsRender&&(this._needsRender=!1,T(()=>this._renderEffect()))},{rootMargin:"200px"}),this._observer.observe(this),this._resizeObserver=new ResizeObserver(()=>{if(!this._image)return;const o=this.clientWidth;o>0&&o!==this._lastClientWidth&&(this._lastClientWidth=o,this._scheduleRender())}),this._resizeObserver.observe(this)}updated(o){if(o.has("src")&&this.src){this._loadImage(this.src);return}if(!this._image)return;[...o.keys()].some(i=>X.has(i))&&this._scheduleRender()}disconnectedCallback(){var o,n;super.disconnectedCallback(),(o=this._observer)==null||o.disconnect(),(n=this._resizeObserver)==null||n.disconnect(),this._revokeSnapshot()}_loadImage(o){const n=new Image;n.crossOrigin="anonymous",n.onload=()=>{this._image=n,this._scheduleRender()},n.onerror=()=>{console.warn(`[some-shade] Failed to load image: ${o}`)},n.src=o}_scheduleRender(){this._visible?T(()=>this._renderEffect()):this._needsRender=!0}async _renderEffect(){var b;if(!this._image)return;const o=x(this.effect);if(!o){console.warn(`[some-shade] Unknown effect: ${this.effect}`);return}const n=Math.min(window.devicePixelRatio||1,B),i=this._image.naturalWidth,e=this._image.naturalHeight,r=this.clientWidth||i,d=Math.max(1,i/r);this._lastClientWidth=this.clientWidth;const p=document.createElement("canvas");p.width=i*n,p.height=e*n;const s=k(p);if(!s){this._webglAvailable=!1;return}try{const f=L(s,o.vertexShader,o.fragmentShader);s.useProgram(f.program);const h=z(s,this._image),_=P(s,f);s.viewport(0,0,p.width,p.height),s.clearColor(0,0,0,0),s.clear(s.COLOR_BUFFER_BIT),s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D,h.texture);const A=f.uniformLocations.get("u_image");A&&s.uniform1i(A,0),D(s,f,this._getUniformValues(h,n,d)),s.bindBuffer(s.ARRAY_BUFFER,_);const U=4*Float32Array.BYTES_PER_ELEMENT,y=f.attribLocations.get("a_position");y!==void 0&&y!==-1&&(s.enableVertexAttribArray(y),s.vertexAttribPointer(y,2,s.FLOAT,!1,U,0));const w=f.attribLocations.get("a_texCoord");w!==void 0&&w!==-1&&(s.enableVertexAttribArray(w),s.vertexAttribPointer(w,2,s.FLOAT,!1,U,2*Float32Array.BYTES_PER_ELEMENT)),O(s);const K=await new Promise($=>p.toBlob($));s.deleteTexture(h.texture),s.deleteProgram(f.program),s.deleteBuffer(_),K&&(this._snapshotLoaded=!1,this._revokeSnapshot(),this._snapshotUrl=URL.createObjectURL(K))}finally{(b=s.getExtension("WEBGL_lose_context"))==null||b.loseContext()}}_onSnapshotLoad(){this._snapshotLoaded=!0}replayTransition(o=500){this._snapshotUrl&&(this._snapshotLoaded=!1,this.updateComplete.then(()=>{setTimeout(()=>{this._snapshotLoaded=!0},o)}))}_revokeSnapshot(){this._snapshotUrl&&(URL.revokeObjectURL(this._snapshotUrl),this._snapshotUrl="")}_getUniformValues(o,n,i){const e={};return e.u_resolution=[o.width*n,o.height*n],e.u_dotRadius=this.dotRadius*i,e.u_gridSize=this.gridSize*i,this.effect==="halftone-cmyk"?(e.u_angleC=this.angleC,e.u_angleM=this.angleM,e.u_angleY=this.angleY,e.u_angleK=this.angleK,e.u_showC=this.showC,e.u_showM=this.showM,e.u_showY=this.showY,e.u_showK=this.showK,e.u_intensityK=this.intensityK):this.effect==="halftone-duotone"?(e.u_duotoneColor=this._parseHexColor(this.duotoneColor),e.u_angle=this.angle):this.effect==="dot-grid"?(e.u_dotOffset=[this.dotOffsetX,this.dotOffsetY],e.u_bgColor=this._parseHexColor(this.bgColor),e.u_angle=this.angle):this.effect==="technicolor-2strip"&&(e.u_angleWarm=this.angleWarm,e.u_angleCool=this.angleCool,e.u_angleK=this.angleK,e.u_showWarm=this.showWarm,e.u_showCool=this.showCool,e.u_showK=this.showK,e.u_warmColor=this._parseHexColor(this.warmColor),e.u_coolColor=this._parseHexColor(this.coolColor)),e}_parseHexColor(o){const n=o.replace("#",""),i=parseInt(n.substring(0,2),16)/255,e=parseInt(n.substring(2,4),16)/255,r=parseInt(n.substring(4,6),16)/255;return[i,e,r]}};R.styles=m.css`
283
+ `}connectedCallback(){super.connectedCallback(),this._observer=new IntersectionObserver(o=>{var i;const n=this._visible;this._visible=((i=o[0])==null?void 0:i.isIntersecting)??!1,this._visible&&!n&&this._needsRender&&(this._needsRender=!1,T(()=>this._renderEffect()))},{rootMargin:"200px"}),this._observer.observe(this),this._resizeObserver=new ResizeObserver(()=>{if(!this._image)return;const o=this.clientWidth;o>0&&o!==this._lastClientWidth&&(this._lastClientWidth=o,this._scheduleRender())}),this._resizeObserver.observe(this)}updated(o){if(o.has("src")&&this.src){this._loadImage(this.src);return}if(!this._image)return;[...o.keys()].some(i=>X.has(i))&&this._scheduleRender()}disconnectedCallback(){var o,n;super.disconnectedCallback(),(o=this._observer)==null||o.disconnect(),(n=this._resizeObserver)==null||n.disconnect(),this._revokeSnapshot()}_loadImage(o){const n=new Image;n.crossOrigin="anonymous",n.onload=()=>{this._image=n,this._scheduleRender()},n.onerror=()=>{console.warn(`[some-shade] Failed to load image: ${o}`)},n.src=o}_scheduleRender(){this._visible?T(()=>this._renderEffect()):this._needsRender=!0}async _renderEffect(){var v;if(!this._image)return;const o=x(this.effect);if(!o){console.warn(`[some-shade] Unknown effect: ${this.effect}`);return}const n=Math.min(window.devicePixelRatio||1,Y),i=this._image.naturalWidth,t=this._image.naturalHeight,a=this.clientWidth||i,f=Math.max(1,i/a);this._lastClientWidth=this.clientWidth;const p=document.createElement("canvas");p.width=i*n,p.height=t*n;const s=k(p);if(!s){this._webglAvailable=!1;return}try{const d=D(s,o.vertexShader,o.fragmentShader);s.useProgram(d.program);const h=z(s,this._image),g=M(s,d);s.viewport(0,0,p.width,p.height),s.clearColor(0,0,0,0),s.clear(s.COLOR_BUFFER_BIT),s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D,h.texture);const A=d.uniformLocations.get("u_image");A&&s.uniform1i(A,0),L(s,d,this._getUniformValues(h,n,f)),s.bindBuffer(s.ARRAY_BUFFER,g);const U=4*Float32Array.BYTES_PER_ELEMENT,y=d.attribLocations.get("a_position");y!==void 0&&y!==-1&&(s.enableVertexAttribArray(y),s.vertexAttribPointer(y,2,s.FLOAT,!1,U,0));const w=d.attribLocations.get("a_texCoord");w!==void 0&&w!==-1&&(s.enableVertexAttribArray(w),s.vertexAttribPointer(w,2,s.FLOAT,!1,U,2*Float32Array.BYTES_PER_ELEMENT)),P(s);const K=await new Promise($=>p.toBlob($));s.deleteTexture(h.texture),s.deleteProgram(d.program),s.deleteBuffer(g),K&&(this._snapshotLoaded=!1,this._revokeSnapshot(),this._snapshotUrl=URL.createObjectURL(K))}finally{(v=s.getExtension("WEBGL_lose_context"))==null||v.loseContext()}}_onSnapshotLoad(){this._snapshotLoaded=!0}replayTransition(o=500){this._snapshotUrl&&(this._snapshotLoaded=!1,this.updateComplete.then(()=>{setTimeout(()=>{this._snapshotLoaded=!0},o)}))}_revokeSnapshot(){this._snapshotUrl&&(URL.revokeObjectURL(this._snapshotUrl),this._snapshotUrl="")}_getUniformValues(o,n,i){const t={};return t.u_resolution=[o.width*n,o.height*n],t.u_dotRadius=this.dotRadius*i,t.u_gridSize=this.gridSize*i,this.effect==="halftone-cmyk"?(t.u_angleC=this.angleC,t.u_angleM=this.angleM,t.u_angleY=this.angleY,t.u_angleK=this.angleK,t.u_showC=this.showC,t.u_showM=this.showM,t.u_showY=this.showY,t.u_showK=this.showK,t.u_intensityK=this.intensityK):this.effect==="halftone-duotone"?(t.u_duotoneColor=this._parseHexColor(this.duotoneColor),t.u_angle=this.angle):this.effect==="dot-grid"?(t.u_dotOffset=[this.dotOffsetX,this.dotOffsetY],t.u_bgColor=this._parseHexColor(this.bgColor),t.u_angle=this.angle):this.effect==="technicolor-2strip"&&(t.u_angleWarm=this.angleWarm,t.u_angleCool=this.angleCool,t.u_angleK=this.angleK,t.u_showWarm=this.showWarm,t.u_showCool=this.showCool,t.u_showK=this.showK,t.u_warmColor=this._parseHexColor(this.warmColor),t.u_coolColor=this._parseHexColor(this.coolColor),t.u_blendMode=this.blendMode,t.u_intensityK=this.intensityK),t}_parseHexColor(o){const n=o.replace("#",""),i=parseInt(n.substring(0,2),16)/255,t=parseInt(n.substring(2,4),16)/255,a=parseInt(n.substring(4,6),16)/255;return[i,t,a]}};R.styles=m.css`
257
284
  :host {
258
285
  display: block;
259
286
  position: relative;
@@ -276,4 +303,4 @@ void main() {
276
303
  img.snapshot.loaded {
277
304
  opacity: 1;
278
305
  }
279
- `;let a=R;u([l.property()],a.prototype,"src"),u([l.property()],a.prototype,"effect"),u([l.property({type:Number,attribute:"dot-radius"})],a.prototype,"dotRadius"),u([l.property({type:Number,attribute:"grid-size"})],a.prototype,"gridSize"),u([l.property({type:Number,attribute:"angle-c"})],a.prototype,"angleC"),u([l.property({type:Number,attribute:"angle-m"})],a.prototype,"angleM"),u([l.property({type:Number,attribute:"angle-y"})],a.prototype,"angleY"),u([l.property({type:Number,attribute:"angle-k"})],a.prototype,"angleK"),u([l.property({type:Number,attribute:"show-c"})],a.prototype,"showC"),u([l.property({type:Number,attribute:"show-m"})],a.prototype,"showM"),u([l.property({type:Number,attribute:"show-y"})],a.prototype,"showY"),u([l.property({type:Number,attribute:"show-k"})],a.prototype,"showK"),u([l.property({type:Number,attribute:"intensity-k"})],a.prototype,"intensityK"),u([l.property({attribute:"duotone-color"})],a.prototype,"duotoneColor"),u([l.property({type:Number})],a.prototype,"angle"),u([l.property({type:Number,attribute:"dot-offset-x"})],a.prototype,"dotOffsetX"),u([l.property({type:Number,attribute:"dot-offset-y"})],a.prototype,"dotOffsetY"),u([l.property({attribute:"bg-color"})],a.prototype,"bgColor"),u([l.property({type:Number,attribute:"angle-warm"})],a.prototype,"angleWarm"),u([l.property({type:Number,attribute:"angle-cool"})],a.prototype,"angleCool"),u([l.property({type:Number,attribute:"show-warm"})],a.prototype,"showWarm"),u([l.property({type:Number,attribute:"show-cool"})],a.prototype,"showCool"),u([l.property({attribute:"warm-color"})],a.prototype,"warmColor"),u([l.property({attribute:"cool-color"})],a.prototype,"coolColor"),u([l.property({type:Number,attribute:"loading-blur"})],a.prototype,"loadingBlur"),u([l.state()],a.prototype,"_webglAvailable"),u([l.state()],a.prototype,"_snapshotUrl"),u([l.state()],a.prototype,"_snapshotLoaded"),customElements.get("some-shade-image")||customElements.define("some-shade-image",a),c.SomeShadeImage=a,c.get=x,c.list=F,c.register=g,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
306
+ `;let r=R;u([l.property()],r.prototype,"src"),u([l.property()],r.prototype,"effect"),u([l.property({type:Number,attribute:"dot-radius"})],r.prototype,"dotRadius"),u([l.property({type:Number,attribute:"grid-size"})],r.prototype,"gridSize"),u([l.property({type:Number,attribute:"angle-c"})],r.prototype,"angleC"),u([l.property({type:Number,attribute:"angle-m"})],r.prototype,"angleM"),u([l.property({type:Number,attribute:"angle-y"})],r.prototype,"angleY"),u([l.property({type:Number,attribute:"angle-k"})],r.prototype,"angleK"),u([l.property({type:Number,attribute:"show-c"})],r.prototype,"showC"),u([l.property({type:Number,attribute:"show-m"})],r.prototype,"showM"),u([l.property({type:Number,attribute:"show-y"})],r.prototype,"showY"),u([l.property({type:Number,attribute:"show-k"})],r.prototype,"showK"),u([l.property({type:Number,attribute:"intensity-k"})],r.prototype,"intensityK"),u([l.property({attribute:"duotone-color"})],r.prototype,"duotoneColor"),u([l.property({type:Number})],r.prototype,"angle"),u([l.property({type:Number,attribute:"dot-offset-x"})],r.prototype,"dotOffsetX"),u([l.property({type:Number,attribute:"dot-offset-y"})],r.prototype,"dotOffsetY"),u([l.property({attribute:"bg-color"})],r.prototype,"bgColor"),u([l.property({type:Number,attribute:"angle-warm"})],r.prototype,"angleWarm"),u([l.property({type:Number,attribute:"angle-cool"})],r.prototype,"angleCool"),u([l.property({type:Number,attribute:"show-warm"})],r.prototype,"showWarm"),u([l.property({type:Number,attribute:"show-cool"})],r.prototype,"showCool"),u([l.property({attribute:"warm-color"})],r.prototype,"warmColor"),u([l.property({attribute:"cool-color"})],r.prototype,"coolColor"),u([l.property({type:Number,attribute:"blend-mode"})],r.prototype,"blendMode"),u([l.property({type:Number,attribute:"loading-blur"})],r.prototype,"loadingBlur"),u([l.state()],r.prototype,"_webglAvailable"),u([l.state()],r.prototype,"_snapshotUrl"),u([l.state()],r.prototype,"_snapshotLoaded"),customElements.get("some-shade-image")||customElements.define("some-shade-image",r),c.SomeShadeImage=r,c.get=x,c.list=F,c.register=_,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnfmorton/some-shade",
3
- "version": "0.1.2-beta",
3
+ "version": "0.1.4-beta",
4
4
  "license": "ISC",
5
5
  "homepage": "https://johnfmorton.github.io/some-shade-web-component/",
6
6
  "repository": {
package/dist/index.d.ts DELETED
@@ -1,78 +0,0 @@
1
- import { CSSResult } from 'lit';
2
- import { LitElement } from 'lit';
3
- import { PropertyValues } from 'lit';
4
- import { TemplateResult } from 'lit';
5
-
6
- export declare interface EffectDefinition {
7
- name: string;
8
- fragmentShader: string;
9
- vertexShader: string;
10
- uniforms: UniformDefinition[];
11
- }
12
-
13
- export declare function get(name: string): EffectDefinition | undefined;
14
-
15
- export declare function list(): string[];
16
-
17
- export declare function register(effect: EffectDefinition): void;
18
-
19
- export declare class SomeShadeImage extends LitElement {
20
- static styles: CSSResult;
21
- src: string;
22
- effect: string;
23
- dotRadius: number;
24
- gridSize: number;
25
- angleC: number;
26
- angleM: number;
27
- angleY: number;
28
- angleK: number;
29
- showC: number;
30
- showM: number;
31
- showY: number;
32
- showK: number;
33
- intensityK: number;
34
- duotoneColor: string;
35
- angle: number;
36
- dotOffsetX: number;
37
- dotOffsetY: number;
38
- bgColor: string;
39
- angleWarm: number;
40
- angleCool: number;
41
- showWarm: number;
42
- showCool: number;
43
- warmColor: string;
44
- coolColor: string;
45
- loadingBlur: number;
46
- private _webglAvailable;
47
- private _snapshotUrl;
48
- private _snapshotLoaded;
49
- private _image;
50
- private _observer;
51
- private _resizeObserver;
52
- private _lastClientWidth;
53
- private _visible;
54
- private _needsRender;
55
- render(): TemplateResult<1>;
56
- connectedCallback(): void;
57
- updated(changed: PropertyValues): void;
58
- disconnectedCallback(): void;
59
- private _loadImage;
60
- private _scheduleRender;
61
- private _renderEffect;
62
- private _onSnapshotLoad;
63
- /** Hide the rendered snapshot momentarily, then fade it back in.
64
- * Useful for previewing the loading-blur transition. */
65
- replayTransition(delay?: number): void;
66
- private _revokeSnapshot;
67
- private _getUniformValues;
68
- private _parseHexColor;
69
- }
70
-
71
- export declare interface UniformDefinition {
72
- name: string;
73
- type: 'float' | 'vec2' | 'vec3' | 'vec4';
74
- default: number | number[];
75
- attribute?: string;
76
- }
77
-
78
- export { }