tangled
alpha
login
or
join now
goose.art
/
blentoo
forked from
flo-bit.dev/blento
0
fork
atom
your personal website on atproto - mirror
0
fork
atom
overview
issues
pulls
pipelines
refactor pt6
Florian
1 month ago
d529a5d5
a028e39d
+122
-132
4 changed files
expand all
collapse all
unified
split
src
lib
cards
BlueskyMediaCard
CreateBlueskyMediaCardModal.svelte
FluidTextCard
FluidTextCard.svelte
LDR_LLL1_0.png
components
post
embeds
External.svelte
+8
-5
src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte
···
9
9
10
10
let did = getDidContext();
11
11
12
12
-
let mediaList: { fullsize: string; isVideo?: boolean; playlist?: string }[] = $state([]);
12
12
+
let mediaList: { fullsize: string; isVideo?: boolean; playlist?: string, thumbnail?: string }[] = $state([]);
13
13
14
14
let isLoading = $state(true);
15
15
···
17
17
const authorFeed = await getAuthorFeed({ did });
18
18
19
19
for (let post of authorFeed?.feed ?? []) {
20
20
-
for (let image of post.post.embed?.images ?? []) {
20
20
+
let images = post.post.embed?.$type === 'app.bsky.embed.images#view' ? post.post.embed : undefined
21
21
+
22
22
+
for (let image of images?.images ?? []) {
21
23
mediaList.push(image);
22
24
}
23
25
24
24
-
if (post.post.embed.thumbnail && post.post.embed.playlist) {
26
26
+
if (post.post.embed?.$type === 'app.bsky.embed.video#view' && post.post.embed.thumbnail && post.post.embed.playlist) {
25
27
mediaList.push({
26
28
...post.post.embed,
27
27
-
isVideo: true
29
29
+
isVideo: true,
30
30
+
fullsize: ''
28
31
});
29
32
}
30
33
}
···
64
67
class="relative cursor-pointer"
65
68
>
66
69
<img
67
67
-
src={media.fullsize ?? media.thumbnail}
70
70
+
src={media.fullsize || media.thumbnail}
68
71
alt=""
69
72
class={[
70
73
'h-32 w-full rounded-xl object-cover',
+111
-125
src/lib/cards/FluidTextCard/FluidTextCard.svelte
···
1
1
<script lang="ts">
2
2
import type { ContentComponentProps } from '../types';
3
3
import { onMount, onDestroy, tick } from 'svelte';
4
4
-
import ditheringTextureUrl from './LDR_LLL1_0.png';
5
5
-
6
4
let { item }: ContentComponentProps = $props();
7
5
8
6
let container: HTMLDivElement;
···
15
13
let isInitialized = $state(false);
16
14
let resizeObserver: ResizeObserver | null = null;
17
15
16
16
+
// Pure hash function for shader keyword caching
17
17
+
function hashCode(s: string) {
18
18
+
if (s.length === 0) return 0;
19
19
+
let hash = 0;
20
20
+
for (let i = 0; i < s.length; i++) {
21
21
+
hash = (hash << 5) - hash + s.charCodeAt(i);
22
22
+
hash |= 0;
23
23
+
}
24
24
+
return hash;
25
25
+
}
26
26
+
27
27
+
// WebGL helper types
28
28
+
type CompileShaderFn = (type: number, source: string, keywords?: string[]) => WebGLShader;
29
29
+
type CreateProgramFn = (vs: WebGLShader, fs: WebGLShader) => WebGLProgram;
30
30
+
type GetUniformsFn = (program: WebGLProgram) => Record<string, WebGLUniformLocation | null>;
31
31
+
32
32
+
// Material class for shader programs with keyword variants
33
33
+
class Material {
34
34
+
private gl: WebGL2RenderingContext;
35
35
+
private compileShader: CompileShaderFn;
36
36
+
private createProgramFn: CreateProgramFn;
37
37
+
private getUniformsFn: GetUniformsFn;
38
38
+
vertexShader: WebGLShader;
39
39
+
fragmentShaderSource: string;
40
40
+
programs: Record<number, WebGLProgram> = {};
41
41
+
activeProgram: WebGLProgram | null = null;
42
42
+
uniforms: Record<string, WebGLUniformLocation | null> = {};
43
43
+
44
44
+
constructor(
45
45
+
gl: WebGL2RenderingContext,
46
46
+
vertexShader: WebGLShader,
47
47
+
fragmentShaderSource: string,
48
48
+
compileShader: CompileShaderFn,
49
49
+
createProgramFn: CreateProgramFn,
50
50
+
getUniformsFn: GetUniformsFn
51
51
+
) {
52
52
+
this.gl = gl;
53
53
+
this.compileShader = compileShader;
54
54
+
this.createProgramFn = createProgramFn;
55
55
+
this.getUniformsFn = getUniformsFn;
56
56
+
this.vertexShader = vertexShader;
57
57
+
this.fragmentShaderSource = fragmentShaderSource;
58
58
+
}
59
59
+
60
60
+
setKeywords(keywords: string[]) {
61
61
+
let hash = 0;
62
62
+
for (let i = 0; i < keywords.length; i++) hash += hashCode(keywords[i]);
63
63
+
64
64
+
let program = this.programs[hash];
65
65
+
if (!program) {
66
66
+
const fragmentShader = this.compileShader(
67
67
+
this.gl.FRAGMENT_SHADER,
68
68
+
this.fragmentShaderSource,
69
69
+
keywords
70
70
+
);
71
71
+
program = this.createProgramFn(this.vertexShader, fragmentShader);
72
72
+
this.programs[hash] = program;
73
73
+
}
74
74
+
75
75
+
if (program === this.activeProgram) return;
76
76
+
77
77
+
this.uniforms = this.getUniformsFn(program);
78
78
+
this.activeProgram = program;
79
79
+
}
80
80
+
81
81
+
bind() {
82
82
+
this.gl.useProgram(this.activeProgram);
83
83
+
}
84
84
+
}
85
85
+
86
86
+
// Program class for simple shader programs
87
87
+
class Program {
88
88
+
private gl: WebGL2RenderingContext;
89
89
+
uniforms: Record<string, WebGLUniformLocation | null> = {};
90
90
+
program: WebGLProgram;
91
91
+
92
92
+
constructor(
93
93
+
gl: WebGL2RenderingContext,
94
94
+
vertexShader: WebGLShader,
95
95
+
fragmentShader: WebGLShader,
96
96
+
createProgramFn: CreateProgramFn,
97
97
+
getUniformsFn: GetUniformsFn
98
98
+
) {
99
99
+
this.gl = gl;
100
100
+
this.program = createProgramFn(vertexShader, fragmentShader);
101
101
+
this.uniforms = getUniformsFn(this.program);
102
102
+
}
103
103
+
104
104
+
bind() {
105
105
+
this.gl.useProgram(this.program);
106
106
+
}
107
107
+
}
108
108
+
18
109
// Get text from card data
19
110
const text = $derived((item.cardData?.text as string) || 'hello');
20
111
const fontWeight = '900';
···
180
271
let pointers: Pointer[] = [PointerPrototype()];
181
272
let splatStack: number[] = [];
182
273
183
183
-
const { gl, ext } = getWebGLContext(fluidCanvas);
184
184
-
if (!gl) return;
274
274
+
const { gl: glMaybeNull, ext } = getWebGLContext(fluidCanvas);
275
275
+
if (!glMaybeNull) return;
276
276
+
const gl = glMaybeNull;
185
277
186
278
if (isMobile()) {
187
279
config.DYE_RESOLUTION = 512;
···
316
408
return /Mobi|Android/i.test(navigator.userAgent);
317
409
}
318
410
319
319
-
class Material {
320
320
-
vertexShader: WebGLShader;
321
321
-
fragmentShaderSource: string;
322
322
-
programs: Record<number, WebGLProgram> = {};
323
323
-
activeProgram: WebGLProgram | null = null;
324
324
-
uniforms: Record<string, WebGLUniformLocation | null> = {};
325
325
-
326
326
-
constructor(vertexShader: WebGLShader, fragmentShaderSource: string) {
327
327
-
this.vertexShader = vertexShader;
328
328
-
this.fragmentShaderSource = fragmentShaderSource;
329
329
-
}
330
330
-
331
331
-
setKeywords(keywords: string[]) {
332
332
-
let hash = 0;
333
333
-
for (let i = 0; i < keywords.length; i++) hash += hashCode(keywords[i]);
334
334
-
335
335
-
let program = this.programs[hash];
336
336
-
if (!program) {
337
337
-
const fragmentShader = compileShader(
338
338
-
gl.FRAGMENT_SHADER,
339
339
-
this.fragmentShaderSource,
340
340
-
keywords
341
341
-
);
342
342
-
program = createProgram(this.vertexShader, fragmentShader);
343
343
-
this.programs[hash] = program;
344
344
-
}
345
345
-
346
346
-
if (program === this.activeProgram) return;
347
347
-
348
348
-
this.uniforms = getUniforms(program);
349
349
-
this.activeProgram = program;
350
350
-
}
351
351
-
352
352
-
bind() {
353
353
-
gl.useProgram(this.activeProgram);
354
354
-
}
355
355
-
}
356
356
-
357
357
-
class Program {
358
358
-
uniforms: Record<string, WebGLUniformLocation | null> = {};
359
359
-
program: WebGLProgram;
360
360
-
361
361
-
constructor(vertexShader: WebGLShader, fragmentShader: WebGLShader) {
362
362
-
this.program = createProgram(vertexShader, fragmentShader);
363
363
-
this.uniforms = getUniforms(this.program);
364
364
-
}
365
365
-
366
366
-
bind() {
367
367
-
gl.useProgram(this.program);
368
368
-
}
369
369
-
}
370
370
-
371
371
-
function createProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader) {
411
411
+
function createWebGLProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader) {
372
412
const program = gl.createProgram()!;
373
413
gl.attachShader(program, vertexShader);
374
414
gl.attachShader(program, fragmentShader);
···
848
888
let sunrays: FBO;
849
889
let sunraysTemp: FBO;
850
890
851
851
-
const ditheringTexture = createTextureAsync(ditheringTextureUrl);
852
852
-
853
853
-
const blurProgram = new Program(blurVertexShader, blurShader);
854
854
-
const copyProgram = new Program(baseVertexShader, copyShader);
855
855
-
const clearProgram = new Program(baseVertexShader, clearShader);
856
856
-
const colorProgram = new Program(baseVertexShader, colorShader);
857
857
-
const splatProgram = new Program(baseVertexShader, splatShader);
858
858
-
const advectionProgram = new Program(baseVertexShader, advectionShader);
859
859
-
const divergenceProgram = new Program(baseVertexShader, divergenceShader);
860
860
-
const curlProgram = new Program(baseVertexShader, curlShader);
861
861
-
const vorticityProgram = new Program(baseVertexShader, vorticityShader);
862
862
-
const pressureProgram = new Program(baseVertexShader, pressureShader);
863
863
-
const gradienSubtractProgram = new Program(baseVertexShader, gradientSubtractShader);
864
864
-
const sunraysMaskProgram = new Program(baseVertexShader, sunraysMaskShader);
865
865
-
const sunraysProgram = new Program(baseVertexShader, sunraysShader);
891
891
+
const blurProgram = new Program(gl, blurVertexShader, blurShader, createWebGLProgram, getUniforms);
892
892
+
const copyProgram = new Program(gl, baseVertexShader, copyShader, createWebGLProgram, getUniforms);
893
893
+
const clearProgram = new Program(gl, baseVertexShader, clearShader, createWebGLProgram, getUniforms);
894
894
+
const colorProgram = new Program(gl, baseVertexShader, colorShader, createWebGLProgram, getUniforms);
895
895
+
const splatProgram = new Program(gl, baseVertexShader, splatShader, createWebGLProgram, getUniforms);
896
896
+
const advectionProgram = new Program(gl, baseVertexShader, advectionShader, createWebGLProgram, getUniforms);
897
897
+
const divergenceProgram = new Program(gl, baseVertexShader, divergenceShader, createWebGLProgram, getUniforms);
898
898
+
const curlProgram = new Program(gl, baseVertexShader, curlShader, createWebGLProgram, getUniforms);
899
899
+
const vorticityProgram = new Program(gl, baseVertexShader, vorticityShader, createWebGLProgram, getUniforms);
900
900
+
const pressureProgram = new Program(gl, baseVertexShader, pressureShader, createWebGLProgram, getUniforms);
901
901
+
const gradienSubtractProgram = new Program(gl, baseVertexShader, gradientSubtractShader, createWebGLProgram, getUniforms);
902
902
+
const sunraysMaskProgram = new Program(gl, baseVertexShader, sunraysMaskShader, createWebGLProgram, getUniforms);
903
903
+
const sunraysProgram = new Program(gl, baseVertexShader, sunraysShader, createWebGLProgram, getUniforms);
866
904
867
867
-
const displayMaterial = new Material(baseVertexShader, displayShaderSource);
905
905
+
const displayMaterial = new Material(gl, baseVertexShader, displayShaderSource, compileShader, createWebGLProgram, getUniforms);
868
906
869
907
function getResolution(resolution: number) {
870
908
let aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight;
···
985
1023
target.texelSizeX = 1.0 / w;
986
1024
target.texelSizeY = 1.0 / h;
987
1025
return target;
988
988
-
}
989
989
-
990
990
-
function createTextureAsync(url: string) {
991
991
-
const texture = gl.createTexture()!;
992
992
-
gl.bindTexture(gl.TEXTURE_2D, texture);
993
993
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
994
994
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
995
995
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
996
996
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
997
997
-
gl.texImage2D(
998
998
-
gl.TEXTURE_2D,
999
999
-
0,
1000
1000
-
gl.RGB,
1001
1001
-
1,
1002
1002
-
1,
1003
1003
-
0,
1004
1004
-
gl.RGB,
1005
1005
-
gl.UNSIGNED_BYTE,
1006
1006
-
new Uint8Array([255, 255, 255])
1007
1007
-
);
1008
1008
-
1009
1009
-
const obj = {
1010
1010
-
texture,
1011
1011
-
width: 1,
1012
1012
-
height: 1,
1013
1013
-
attach(id: number) {
1014
1014
-
gl.activeTexture(gl.TEXTURE0 + id);
1015
1015
-
gl.bindTexture(gl.TEXTURE_2D, texture);
1016
1016
-
return id;
1017
1017
-
}
1018
1018
-
};
1019
1019
-
1020
1020
-
const image = new Image();
1021
1021
-
image.onload = () => {
1022
1022
-
obj.width = image.width;
1023
1023
-
obj.height = image.height;
1024
1024
-
gl.bindTexture(gl.TEXTURE_2D, texture);
1025
1025
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
1026
1026
-
};
1027
1027
-
image.src = url;
1028
1028
-
1029
1029
-
return obj;
1030
1026
}
1031
1027
1032
1028
function initFramebuffers() {
···
1450
1446
if (!config.PAUSED) step(dt);
1451
1447
render(null);
1452
1448
animationId = requestAnimationFrame(update);
1453
1453
-
}
1454
1454
-
1455
1455
-
function hashCode(s: string) {
1456
1456
-
if (s.length === 0) return 0;
1457
1457
-
let hash = 0;
1458
1458
-
for (let i = 0; i < s.length; i++) {
1459
1459
-
hash = (hash << 5) - hash + s.charCodeAt(i);
1460
1460
-
hash |= 0;
1461
1461
-
}
1462
1462
-
return hash;
1463
1449
}
1464
1450
1465
1451
function correctDeltaX(delta: number) {
src/lib/cards/FluidTextCard/LDR_LLL1_0.png
This is a binary file and will not be displayed.
+3
-2
src/lib/components/post/embeds/External.svelte
···
3
3
4
4
const { data }: { data: PostEmbedExternal } = $props();
5
5
6
6
+
// svelte-ignore state_referenced_locally
6
7
const domain = new URL(data.external.href).hostname.replace('www.', '');
7
8
</script>
8
9
9
10
<article
10
11
class={[
11
12
'group dark:bg-base-900 bg-base-200 border-base-300 dark:border-base-600/30 relative isolate flex max-w-md flex-col justify-end overflow-hidden rounded-2xl border p-4',
12
12
-
data.external.thumb ? 'aspect-[16/9]' : ''
13
13
+
data.external.thumb ? 'aspect-video' : ''
13
14
]}
14
15
>
15
16
{#if data.external.thumb}
···
20
21
/>
21
22
{/if}
22
23
<div
23
23
-
class="dark:from-base-950/90 dark:via-base-950/40 from-base-50/90 via-base-50/40 absolute inset-0 -z-10 bg-gradient-to-t"
24
24
+
class="dark:from-base-950/90 dark:via-base-950/40 from-base-50/90 via-base-50/40 absolute inset-0 -z-10 bg-linear-to-t"
24
25
></div>
25
26
26
27
<div