From d529a5d509fcc5e7d9f989b0a21e30764e66ac6f Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Fri, 23 Jan 2026 11:19:31 +0000 Subject: [PATCH] refactor pt6 --- src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte | 13 ++++++++----- src/lib/cards/FluidTextCard/FluidTextCard.svelte | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------------------------------- src/lib/cards/FluidTextCard/LDR_LLL1_0.png | 0 src/lib/components/post/embeds/External.svelte | 5 +++-- 4 file(s) changed, 122 insertion(s)(+), 132 deletion(s)(-) diff --git a/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte b/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte --- a/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte +++ b/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte @@ -9,7 +9,7 @@ let did = getDidContext(); - let mediaList: { fullsize: string; isVideo?: boolean; playlist?: string }[] = $state([]); + let mediaList: { fullsize: string; isVideo?: boolean; playlist?: string, thumbnail?: string }[] = $state([]); let isLoading = $state(true); @@ -17,14 +17,17 @@ const authorFeed = await getAuthorFeed({ did }); for (let post of authorFeed?.feed ?? []) { - for (let image of post.post.embed?.images ?? []) { + let images = post.post.embed?.$type === 'app.bsky.embed.images#view' ? post.post.embed : undefined + + for (let image of images?.images ?? []) { mediaList.push(image); } - if (post.post.embed.thumbnail && post.post.embed.playlist) { + if (post.post.embed?.$type === 'app.bsky.embed.video#view' && post.post.embed.thumbnail && post.post.embed.playlist) { mediaList.push({ ...post.post.embed, - isVideo: true + isVideo: true, + fullsize: '' }); } } @@ -64,7 +67,7 @@ class="relative cursor-pointer" > import type { ContentComponentProps } from '../types'; import { onMount, onDestroy, tick } from 'svelte'; - import ditheringTextureUrl from './LDR_LLL1_0.png'; - let { item }: ContentComponentProps = $props(); let container: HTMLDivElement; @@ -14,6 +12,99 @@ let maskReady = false; let isInitialized = $state(false); let resizeObserver: ResizeObserver | null = null; + + // Pure hash function for shader keyword caching + function hashCode(s: string) { + if (s.length === 0) return 0; + let hash = 0; + for (let i = 0; i < s.length; i++) { + hash = (hash << 5) - hash + s.charCodeAt(i); + hash |= 0; + } + return hash; + } + + // WebGL helper types + type CompileShaderFn = (type: number, source: string, keywords?: string[]) => WebGLShader; + type CreateProgramFn = (vs: WebGLShader, fs: WebGLShader) => WebGLProgram; + type GetUniformsFn = (program: WebGLProgram) => Record; + + // Material class for shader programs with keyword variants + class Material { + private gl: WebGL2RenderingContext; + private compileShader: CompileShaderFn; + private createProgramFn: CreateProgramFn; + private getUniformsFn: GetUniformsFn; + vertexShader: WebGLShader; + fragmentShaderSource: string; + programs: Record = {}; + activeProgram: WebGLProgram | null = null; + uniforms: Record = {}; + + constructor( + gl: WebGL2RenderingContext, + vertexShader: WebGLShader, + fragmentShaderSource: string, + compileShader: CompileShaderFn, + createProgramFn: CreateProgramFn, + getUniformsFn: GetUniformsFn + ) { + this.gl = gl; + this.compileShader = compileShader; + this.createProgramFn = createProgramFn; + this.getUniformsFn = getUniformsFn; + this.vertexShader = vertexShader; + this.fragmentShaderSource = fragmentShaderSource; + } + + setKeywords(keywords: string[]) { + let hash = 0; + for (let i = 0; i < keywords.length; i++) hash += hashCode(keywords[i]); + + let program = this.programs[hash]; + if (!program) { + const fragmentShader = this.compileShader( + this.gl.FRAGMENT_SHADER, + this.fragmentShaderSource, + keywords + ); + program = this.createProgramFn(this.vertexShader, fragmentShader); + this.programs[hash] = program; + } + + if (program === this.activeProgram) return; + + this.uniforms = this.getUniformsFn(program); + this.activeProgram = program; + } + + bind() { + this.gl.useProgram(this.activeProgram); + } + } + + // Program class for simple shader programs + class Program { + private gl: WebGL2RenderingContext; + uniforms: Record = {}; + program: WebGLProgram; + + constructor( + gl: WebGL2RenderingContext, + vertexShader: WebGLShader, + fragmentShader: WebGLShader, + createProgramFn: CreateProgramFn, + getUniformsFn: GetUniformsFn + ) { + this.gl = gl; + this.program = createProgramFn(vertexShader, fragmentShader); + this.uniforms = getUniformsFn(this.program); + } + + bind() { + this.gl.useProgram(this.program); + } + } // Get text from card data const text = $derived((item.cardData?.text as string) || 'hello'); @@ -180,8 +271,9 @@ let pointers: Pointer[] = [PointerPrototype()]; let splatStack: number[] = []; - const { gl, ext } = getWebGLContext(fluidCanvas); - if (!gl) return; + const { gl: glMaybeNull, ext } = getWebGLContext(fluidCanvas); + if (!glMaybeNull) return; + const gl = glMaybeNull; if (isMobile()) { config.DYE_RESOLUTION = 512; @@ -316,59 +408,7 @@ return /Mobi|Android/i.test(navigator.userAgent); } - class Material { - vertexShader: WebGLShader; - fragmentShaderSource: string; - programs: Record = {}; - activeProgram: WebGLProgram | null = null; - uniforms: Record = {}; - - constructor(vertexShader: WebGLShader, fragmentShaderSource: string) { - this.vertexShader = vertexShader; - this.fragmentShaderSource = fragmentShaderSource; - } - - setKeywords(keywords: string[]) { - let hash = 0; - for (let i = 0; i < keywords.length; i++) hash += hashCode(keywords[i]); - - let program = this.programs[hash]; - if (!program) { - const fragmentShader = compileShader( - gl.FRAGMENT_SHADER, - this.fragmentShaderSource, - keywords - ); - program = createProgram(this.vertexShader, fragmentShader); - this.programs[hash] = program; - } - - if (program === this.activeProgram) return; - - this.uniforms = getUniforms(program); - this.activeProgram = program; - } - - bind() { - gl.useProgram(this.activeProgram); - } - } - - class Program { - uniforms: Record = {}; - program: WebGLProgram; - - constructor(vertexShader: WebGLShader, fragmentShader: WebGLShader) { - this.program = createProgram(vertexShader, fragmentShader); - this.uniforms = getUniforms(this.program); - } - - bind() { - gl.useProgram(this.program); - } - } - - function createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader) { + function createWebGLProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader) { const program = gl.createProgram()!; gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); @@ -848,23 +888,21 @@ let sunrays: FBO; let sunraysTemp: FBO; - const ditheringTexture = createTextureAsync(ditheringTextureUrl); + const blurProgram = new Program(gl, blurVertexShader, blurShader, createWebGLProgram, getUniforms); + const copyProgram = new Program(gl, baseVertexShader, copyShader, createWebGLProgram, getUniforms); + const clearProgram = new Program(gl, baseVertexShader, clearShader, createWebGLProgram, getUniforms); + const colorProgram = new Program(gl, baseVertexShader, colorShader, createWebGLProgram, getUniforms); + const splatProgram = new Program(gl, baseVertexShader, splatShader, createWebGLProgram, getUniforms); + const advectionProgram = new Program(gl, baseVertexShader, advectionShader, createWebGLProgram, getUniforms); + const divergenceProgram = new Program(gl, baseVertexShader, divergenceShader, createWebGLProgram, getUniforms); + const curlProgram = new Program(gl, baseVertexShader, curlShader, createWebGLProgram, getUniforms); + const vorticityProgram = new Program(gl, baseVertexShader, vorticityShader, createWebGLProgram, getUniforms); + const pressureProgram = new Program(gl, baseVertexShader, pressureShader, createWebGLProgram, getUniforms); + const gradienSubtractProgram = new Program(gl, baseVertexShader, gradientSubtractShader, createWebGLProgram, getUniforms); + const sunraysMaskProgram = new Program(gl, baseVertexShader, sunraysMaskShader, createWebGLProgram, getUniforms); + const sunraysProgram = new Program(gl, baseVertexShader, sunraysShader, createWebGLProgram, getUniforms); - const blurProgram = new Program(blurVertexShader, blurShader); - const copyProgram = new Program(baseVertexShader, copyShader); - const clearProgram = new Program(baseVertexShader, clearShader); - const colorProgram = new Program(baseVertexShader, colorShader); - const splatProgram = new Program(baseVertexShader, splatShader); - const advectionProgram = new Program(baseVertexShader, advectionShader); - const divergenceProgram = new Program(baseVertexShader, divergenceShader); - const curlProgram = new Program(baseVertexShader, curlShader); - const vorticityProgram = new Program(baseVertexShader, vorticityShader); - const pressureProgram = new Program(baseVertexShader, pressureShader); - const gradienSubtractProgram = new Program(baseVertexShader, gradientSubtractShader); - const sunraysMaskProgram = new Program(baseVertexShader, sunraysMaskShader); - const sunraysProgram = new Program(baseVertexShader, sunraysShader); - - const displayMaterial = new Material(baseVertexShader, displayShaderSource); + const displayMaterial = new Material(gl, baseVertexShader, displayShaderSource, compileShader, createWebGLProgram, getUniforms); function getResolution(resolution: number) { let aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight; @@ -985,48 +1023,6 @@ target.texelSizeX = 1.0 / w; target.texelSizeY = 1.0 / h; return target; - } - - function createTextureAsync(url: string) { - const texture = gl.createTexture()!; - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - gl.texImage2D( - gl.TEXTURE_2D, - 0, - gl.RGB, - 1, - 1, - 0, - gl.RGB, - gl.UNSIGNED_BYTE, - new Uint8Array([255, 255, 255]) - ); - - const obj = { - texture, - width: 1, - height: 1, - attach(id: number) { - gl.activeTexture(gl.TEXTURE0 + id); - gl.bindTexture(gl.TEXTURE_2D, texture); - return id; - } - }; - - const image = new Image(); - image.onload = () => { - obj.width = image.width; - obj.height = image.height; - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); - }; - image.src = url; - - return obj; } function initFramebuffers() { @@ -1450,16 +1446,6 @@ if (!config.PAUSED) step(dt); render(null); animationId = requestAnimationFrame(update); - } - - function hashCode(s: string) { - if (s.length === 0) return 0; - let hash = 0; - for (let i = 0; i < s.length; i++) { - hash = (hash << 5) - hash + s.charCodeAt(i); - hash |= 0; - } - return hash; } function correctDeltaX(delta: number) { diff --git a/src/lib/cards/FluidTextCard/LDR_LLL1_0.png b/src/lib/cards/FluidTextCard/LDR_LLL1_0.png deleted file mode 100644 --- a/src/lib/cards/FluidTextCard/LDR_LLL1_0.png +++ /dev/null diff --git a/src/lib/components/post/embeds/External.svelte b/src/lib/components/post/embeds/External.svelte --- a/src/lib/components/post/embeds/External.svelte +++ b/src/lib/components/post/embeds/External.svelte @@ -3,13 +3,14 @@ const { data }: { data: PostEmbedExternal } = $props(); + // svelte-ignore state_referenced_locally const domain = new URL(data.external.href).hostname.replace('www.', '');
{#if data.external.thumb} @@ -20,7 +21,7 @@ /> {/if}