feat(app): dots background for node interface

This commit is contained in:
2026-02-09 16:53:57 +01:00
parent e89a46e146
commit 23a48572f3
7 changed files with 72 additions and 39 deletions

View File

@@ -11,6 +11,7 @@ uniform vec3 camPos;
uniform vec2 zoomLimits; uniform vec2 zoomLimits;
uniform vec3 backgroundColor; uniform vec3 backgroundColor;
uniform vec3 lineColor; uniform vec3 lineColor;
uniform int gridType; // 0 = grid lines, 1 = dots
// Anti-aliased step: threshold in the same units as `value` // Anti-aliased step: threshold in the same units as `value`
float aaStep(float threshold, float value, float deriv) { float aaStep(float threshold, float value, float deriv) {
@@ -78,6 +79,7 @@ void main(void) {
float ux = (vUv.x - 0.5) * width + cx * cz; float ux = (vUv.x - 0.5) * width + cx * cz;
float uy = (vUv.y - 0.5) * height - cy * cz; float uy = (vUv.y - 0.5) * height - cy * cz;
if(gridType == 0) {
// extra small grid // extra small grid
float m1 = grid(ux, uy, divisions * 4.0, thickness * 4.0) * 0.9; float m1 = grid(ux, uy, divisions * 4.0, thickness * 4.0) * 0.9;
float m2 = grid(ux, uy, divisions * 16.0, thickness * 16.0) * 0.5; float m2 = grid(ux, uy, divisions * 16.0, thickness * 16.0) * 0.5;
@@ -107,6 +109,21 @@ void main(void) {
vec3 color = mix(backgroundColor, lineColor, c); vec3 color = mix(backgroundColor, lineColor, c);
gl_FragColor = vec4(color, 1.0);
} else {
float large = circle_grid(ux, uy, cz * 20.0, 1.0) * 0.4;
float medium = circle_grid(ux, uy, cz * 10.0, 1.0) * 0.6;
float small = circle_grid(ux, uy, cz * 2.5, 1.0) * 0.8;
float c = mix(large, medium, min(nz * 2.0 + 0.05, 1.0));
c = mix(c, small, clamp((nz - 0.3) / 0.7, 0.0, 1.0));
vec3 color = mix(backgroundColor, lineColor, c);
gl_FragColor = vec4(color, 1.0); gl_FragColor = vec4(color, 1.0);
} }
}

View File

@@ -6,11 +6,12 @@
import BackgroundVert from './Background.vert'; import BackgroundVert from './Background.vert';
type Props = { type Props = {
minZoom: number; minZoom?: number;
maxZoom: number; maxZoom?: number;
cameraPosition: [number, number, number]; cameraPosition?: [number, number, number];
width: number; width?: number;
height: number; height?: number;
type?: 'grid' | 'dots' | 'none';
}; };
let { let {
@@ -18,9 +19,18 @@
maxZoom = 150, maxZoom = 150,
cameraPosition = [0, 1, 0], cameraPosition = [0, 1, 0],
width = globalThis?.innerWidth || 100, width = globalThis?.innerWidth || 100,
height = globalThis?.innerHeight || 100 height = globalThis?.innerHeight || 100,
type = 'grid'
}: Props = $props(); }: Props = $props();
const typeMap = new Map([
['grid', 0],
['dots', 1],
['none', 2]
]);
const gridType = $derived(typeMap.get(type) || 0);
let bw = $derived(width / cameraPosition[2]); let bw = $derived(width / cameraPosition[2]);
let bh = $derived(height / cameraPosition[2]); let bh = $derived(height / cameraPosition[2]);
</script> </script>
@@ -51,6 +61,9 @@
}, },
dimensions: { dimensions: {
value: [100, 100] value: [100, 100]
},
gridType: {
value: 0
} }
}} }}
uniforms.camPos.value={cameraPosition} uniforms.camPos.value={cameraPosition}
@@ -59,6 +72,7 @@
uniforms.lineColor.value={appSettings.value.theme && colors['outline']} uniforms.lineColor.value={appSettings.value.theme && colors['outline']}
uniforms.zoomLimits.value={[minZoom, maxZoom]} uniforms.zoomLimits.value={[minZoom, maxZoom]}
uniforms.dimensions.value={[width, height]} uniforms.dimensions.value={[width, height]}
uniforms.gridType.value={gridType}
/> />
</T.Mesh> </T.Mesh>
</T.Group> </T.Group>

View File

@@ -83,7 +83,7 @@ export class GraphState {
addMenuPosition = $state<[number, number] | null>(null); addMenuPosition = $state<[number, number] | null>(null);
snapToGrid = $state(false); snapToGrid = $state(false);
showGrid = $state(true); backgroundType = $state<'grid' | 'dots' | 'none'>('grid');
showHelp = $state(false); showHelp = $state(false);
cameraDown = [0, 0]; cameraDown = [0, 0];

View File

@@ -132,8 +132,9 @@
position={graphState.cameraPosition} position={graphState.cameraPosition}
/> />
{#if graphState.showGrid !== false} {#if graphState.backgroundType !== 'none'}
<Background <Background
type={graphState.backgroundType}
cameraPosition={graphState.cameraPosition} cameraPosition={graphState.cameraPosition}
{maxZoom} {maxZoom}
{minZoom} {minZoom}

View File

@@ -13,7 +13,7 @@
settings?: Record<string, unknown>; settings?: Record<string, unknown>;
activeNode?: NodeInstance; activeNode?: NodeInstance;
showGrid?: boolean; backgroundType?: 'grid' | 'dots' | 'none';
snapToGrid?: boolean; snapToGrid?: boolean;
showHelp?: boolean; showHelp?: boolean;
settingTypes?: Record<string, unknown>; settingTypes?: Record<string, unknown>;
@@ -27,7 +27,7 @@
registry, registry,
settings = $bindable(), settings = $bindable(),
activeNode = $bindable(), activeNode = $bindable(),
showGrid = $bindable(true), backgroundType = $bindable('grid'),
snapToGrid = $bindable(true), snapToGrid = $bindable(true),
showHelp = $bindable(false), showHelp = $bindable(false),
settingTypes = $bindable(), settingTypes = $bindable(),
@@ -43,7 +43,7 @@
const graphState = new GraphState(manager); const graphState = new GraphState(manager);
$effect(() => { $effect(() => {
graphState.showGrid = showGrid; graphState.backgroundType = backgroundType;
graphState.snapToGrid = snapToGrid; graphState.snapToGrid = snapToGrid;
graphState.showHelp = showHelp; graphState.showHelp = showHelp;
}); });

View File

@@ -30,10 +30,11 @@ export const AppSettingTypes = {
}, },
nodeInterface: { nodeInterface: {
title: 'Node Interface', title: 'Node Interface',
showNodeGrid: { backgroundType: {
type: 'boolean', type: 'select',
label: 'Show Grid', label: 'Background',
value: true options: ['grid', 'dots', 'none'],
value: 'grid'
}, },
snapToGrid: { snapToGrid: {
type: 'boolean', type: 'boolean',

View File

@@ -171,7 +171,7 @@
graph={pm.graph} graph={pm.graph}
bind:this={graphInterface} bind:this={graphInterface}
registry={nodeRegistry} registry={nodeRegistry}
showGrid={appSettings.value.nodeInterface.showNodeGrid} backgroundType={appSettings.value.nodeInterface.backgroundType}
snapToGrid={appSettings.value.nodeInterface.snapToGrid} snapToGrid={appSettings.value.nodeInterface.snapToGrid}
bind:activeNode bind:activeNode
bind:showHelp={appSettings.value.nodeInterface.showHelp} bind:showHelp={appSettings.value.nodeInterface.showHelp}