Skip to content

Commit 7ae90e4

Browse files
committed
tweaks, comments, cleanup
1 parent 8ba5d3e commit 7ae90e4

2 files changed

Lines changed: 99 additions & 57 deletions

File tree

src/pages/index.astro

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,27 @@ import { Image } from "astro:assets";
2121
class="pl-[6vw] pt-[8vh] inset-0 bg-[radial-gradient(circle_at_top_right,_rgba(139,92,246,0.25),_transparent_70%)]"
2222
>
2323
<div class="flex md:flex-row flex-col items-start">
24-
<h1 class="text-7xl glow-anim font-[SUSE] font-thin">
25-
Aaron Zandt
26-
</h1>
27-
<div class="flex justify-center mt-0 flex-row gap-2 md:flex-col md:ml-4">
28-
<a class="" href="https://github.com/lith-x">
24+
<h1 class="text-7xl glow-anim font-[SUSE] font-thin">Aaron Zandt</h1>
25+
<div
26+
class="flex justify-center mt-0 flex-row gap-2 md:flex-col md:ml-4"
27+
>
28+
<a
29+
target="_blank"
30+
rel="noopener noreferrer"
31+
class=""
32+
href="https://github.com/lith-x"
33+
>
2934
<Image
3035
src={githubLogo}
3136
alt="GitHub Profile"
3237
class="glow-anim w-7 h-7"
3338
/>
3439
</a>
35-
<a href="https://github.com/lith-x">
40+
<a
41+
target="_blank"
42+
rel="noopener noreferrer"
43+
href="https://github.com/lith-x"
44+
>
3645
<Image
3746
src={linkedinLogo}
3847
alt="LinkedIn Profile"
@@ -62,9 +71,13 @@ import { Image } from "astro:assets";
6271

6372
<li class="pb-3.5">
6473
I draw inspiration from projects like <a
74+
target="_blank"
75+
rel="noopener noreferrer"
6576
href="https://www.youtube.com/playlist?list=PLnuhp3Xd9PYTt6svyQPyRO_AAuMWGxPzU"
6677
>Handmade Hero</a
6778
> and communities like <a
79+
target="_blank"
80+
rel="noopener noreferrer"
6881
href="https://www.youtube.com/@TsodingDaily">Tsoding Daily</a
6982
>, which have shaped my philosophy of writing code that is
7083
intentional, efficient, and built from the ground up with clarity in
@@ -75,13 +88,17 @@ import { Image } from "astro:assets";
7588
<ul class="w-[80%] list-[square] list-outside pl-3.5 pb-7">
7689
<li class="pb-3.5">
7790
<a
91+
target="_blank"
92+
rel="noopener noreferrer"
7893
class="font-bold italic [font-variant:small-caps]"
7994
href="https://github.com/lith-x/Capstone-project"
8095
>Capstone Project — Northrop Grumman</a
8196
>
8297
— Collaborated with a team to develop a plugin for the Android application
83-
<a href="https://tak.gov/">ATAK</a>, enabling geolocation of devices
84-
outside the network via Bluetooth signaling.
98+
<a target="_blank" rel="noopener noreferrer" href="https://tak.gov/"
99+
>ATAK</a
100+
>, enabling geolocation of devices outside the network via Bluetooth
101+
signaling.
85102

86103
<ul class="ml-4 list-[square]">
87104
<li>Tech: Java, Android SDK, Bluetooth APIs</li>
@@ -93,6 +110,8 @@ import { Image } from "astro:assets";
93110
</li>
94111
<li class="pb-3.5">
95112
<a
113+
target="_blank"
114+
rel="noopener noreferrer"
96115
class="font-bold italic [font-variant:small-caps]"
97116
href="https://github.com/lith-x/leetcode">LeetCode Repository</a
98117
>
@@ -108,26 +127,35 @@ import { Image } from "astro:assets";
108127
</li>
109128
<li class="pb-3.5">
110129
<a
130+
target="_blank"
131+
rel="noopener noreferrer"
111132
class="font-bold italic [font-variant:small-caps]"
112133
href="https://github.com/lith-x/storyboard-web"
113134
>Storyboard Web App</a
114-
> — A WIP all-in-one <a href="https://osu.ppy.sh/">osu!</a> storyboarding
115-
platform.
135+
> — A WIP all-in-one <a
136+
target="_blank"
137+
rel="noopener noreferrer"
138+
href="https://osu.ppy.sh/">osu!</a
139+
> storyboarding platform.
116140
<ul class="ml-4 list-[square]">
117141
<li>Tech: Svelte, Tailwind, Typescript, PixiJS</li>
118142
<li>
119143
Focus: Designing an elegant, feature-complete, and
120144
platform-independent application that will enable a niche group
121145
of creative spirits to more effectively develop <a
146+
target="_blank"
147+
rel="noopener noreferrer"
122148
href="https://osu.ppy.sh/wiki/en/Storyboard">storyboards</a
123149
>.
124150
</li>
125151
</ul>
126152
</li>
127153
<li class="pb-45">
128-
<span class="font-bold italic [font-variant:small-caps]"
129-
>This Site</span
130-
> — Source available, see link at the bottom left.
154+
<a
155+
rel="noopener noreferrer"
156+
href="https://github.com/lith-x/lith-x.github.io/"
157+
class="font-bold italic [font-variant:small-caps]">This Site</a
158+
>
131159
<ul class="ml-4 list-[square]">
132160
<li>Tech: Astro, Tailwind, Typescript, WebGL</li>
133161
<li>
@@ -137,9 +165,11 @@ import { Image } from "astro:assets";
137165
</ul>
138166
</li>
139167
</ul>
140-
<div class="fixed bottom-1 left-1 text-[1em] text-violet-300 italic">
141-
made by me! <a href="https://github.com/lith-x/lith-x.github.io/"
142-
>source</a
168+
<div class="fixed bottom-1 left-1 text-[1em] text-violet-300 italic opacity-50">
169+
made by me! <a
170+
target="_blank"
171+
rel="noopener noreferrer"
172+
href="https://github.com/lith-x/lith-x.github.io/">source</a
143173
>
144174
</div>
145175
<script>

src/ts/bg-webgl.ts

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const CUBES_Y = 24;
4545
const CUBES_Z = 24;
4646
const CUBES_COUNT = (CUBES_X * CUBES_Y * CUBES_Z);
4747

48-
const getGridLength = (x: number) => (Cube.INTERVAL * (x) - Cube.PADDING);
48+
const getGridLength = (x: number) => (Cube.INTERVAL * x - Cube.PADDING);
4949
const SIZE_X = getGridLength(CUBES_X);
5050
const SIZE_Y = getGridLength(CUBES_Y);
5151
const SIZE_Z = getGridLength(CUBES_Z);
@@ -65,13 +65,15 @@ const POINT_COUNT = 10;
6565

6666
const cubeIdx = (x: number, y: number, z: number) => CUBES_X * CUBES_Y * z + CUBES_X * y + x;
6767

68-
const v3scratch: [x: number, y: number, z: number] = [0, 0, 0];
68+
// benchmarked various methods of doing this function, it made little difference
69+
// turns out it makes a copy anyways regardless of const, oh well.
70+
const v3Scratch: [x: number, y: number, z: number] = [0,0,0];
6971
const getVec3Idx = (idx: number) => {
7072
const base = idx * 3;
71-
v3scratch[0] = base;
72-
v3scratch[1] = base + 1;
73-
v3scratch[2] = base + 2;
74-
return v3scratch;
73+
v3Scratch[0] = base;
74+
v3Scratch[1] = base + 1;
75+
v3Scratch[2] = base + 2;
76+
return v3Scratch;
7577
};
7678

7779
// -------------------- main --------------------
@@ -129,7 +131,7 @@ export const main = async () => {
129131
}
130132
};
131133

132-
const gridPositions = new Float32Array(CUBES_COUNT * 3);
134+
const gridPositions = new Float32Array(CUBES_COUNT * 3); // float vec3
133135
const refPos = twgl.v3.create(X_MIN_CUBE_CENTER, Y_MIN_CUBE_CENTER, Z_MIN_CUBE_CENTER);
134136
for (let z = 0; z < CUBES_Z; z++) {
135137
refPos[1] = Y_MIN_CUBE_CENTER;
@@ -157,7 +159,7 @@ export const main = async () => {
157159
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
158160
gl.disable(gl.DEPTH_TEST);
159161
twgl.setUniforms(progInfo, {
160-
u_view: twgl.m4.inverse(twgl.m4.lookAt([0, 0, maxGridSize * fieldOfView], [0, 0, 0], [0, 1, 0]))
162+
u_view: twgl.m4.inverse(twgl.m4.lookAt([0, 0, maxGridSize * fieldOfView], CENTER, [0, 1, 0]))
161163
});
162164

163165
let dt: number;
@@ -166,6 +168,7 @@ export const main = async () => {
166168
const points = new PointsArray(POINT_COUNT);
167169
let spawnTimer = PRNG.nextRange(Spawn.TIME.MIN, Spawn.TIME.MAX);
168170
const render = (time: number) => {
171+
// --- update ---
169172
dt = (time - lastTime) / 1000;
170173
lastTime = time;
171174
cubeInstanceArray.reset();
@@ -190,14 +193,17 @@ export const main = async () => {
190193
for (let z = bbox.min.z; z < bbox.max.z; z++) {
191194
for (let y = bbox.min.y; y < bbox.max.y; y++) {
192195
for (let x = bbox.min.x; x < bbox.max.x; x++) {
193-
const [cx, cy, cz] = getVec3Idx(cubeIdx(x, y, z));
196+
// inlined: getVec3Idx(cubeIdx(x, y, z))
197+
const cx = (CUBES_X * CUBES_Y * z + CUBES_X * y + x) * 3;
198+
const cy = cx + 1;
199+
const cz = cy + 1;
194200
const dx = Math.abs((points.positions[px] - gridPositions[cx]) / points.scales[px]);
195201
const dy = Math.abs((points.positions[py] - gridPositions[cy]) / points.scales[py]);
196202
const dz = Math.abs((points.positions[pz] - gridPositions[cz]) / points.scales[pz]);
197203
const d = dx + dy + dz;
198204

199205
// octahedral shape with a linear falloff
200-
const sideLen = Math.max(0, Cube.SIZE * (1 - d));
206+
const sideLen = Cube.SIZE * (1 - d);
201207
if (sideLen <= EPSILON)
202208
continue;
203209

@@ -211,6 +217,7 @@ export const main = async () => {
211217
}
212218
}
213219

220+
// --- render ---
214221
resized = twgl.resizeCanvasToDisplaySize(gl.canvas as HTMLCanvasElement);
215222
if (resized) {
216223
twgl.setUniforms(progInfo, {
@@ -289,23 +296,33 @@ class CubeInstanceArray {
289296
}
290297

291298
public setPointData(x: number, y: number, z: number, r: number, g: number, b: number, size: number) {
292-
// indexing directly to avoid constructing an array in hot loop.
293-
const [ix, iy, iz] = getVec3Idx(this.count);
299+
// This is in the hottest loop in the program, must be as fast as possible.
300+
const ix = this.count * 3;
301+
const iy = ix + 1;
302+
const iz = iy + 1;
294303
this.instanceCenters[ix] = x;
295304
this.instanceCenters[iy] = y;
296305
this.instanceCenters[iz] = z;
297306

298-
const [ir, ig, ib] = getVec3Idx(this.count);
299-
this.instanceColors[ir] = r;
300-
this.instanceColors[ig] = g;
301-
this.instanceColors[ib] = b;
307+
this.instanceColors[ix] = r;
308+
this.instanceColors[iy] = g;
309+
this.instanceColors[iz] = b;
302310
this.instanceSizes[this.count] = size;
303311
this.count++;
304312
}
305313

306314
public reset() { this.count = 0; }
307315
}
308316

317+
// constants used for freelist, internal to PointsArray
318+
// hoisted out for readability
319+
const FL = Object.freeze({
320+
HEAD: 0,
321+
TAIL: 1,
322+
END: -1,
323+
SPAWNED: -2
324+
});
325+
309326
class PointsArray {
310327
private data: ArrayBuffer;
311328
public readonly count: number;
@@ -318,12 +335,7 @@ class PointsArray {
318335
public activeIdx: Int32Array; // int32
319336
public directions: Int8Array; // char
320337

321-
// freelist constants, if name collisions become an issue wrap these in a frozen object
322-
private static readonly HEAD_IDX = 0;
323-
private static readonly TAIL_IDX = 1;
324-
private static readonly LIST_END = -1;
325-
private static readonly IS_SPAWNED = -2;
326-
private freelist = new Int32Array([PointsArray.LIST_END, PointsArray.LIST_END]);
338+
private freelist = new Int32Array([FL.END, FL.END]);
327339

328340
constructor(poolSize: number) {
329341
this.count = poolSize;
@@ -356,22 +368,22 @@ class PointsArray {
356368
// initialize freelist
357369
for (let i = 0; i < poolSize - 1; i++)
358370
this.nextFreeOrSpawned[i] = i + 1;
359-
this.nextFreeOrSpawned[poolSize - 1] = PointsArray.LIST_END;
360-
this.freelist[PointsArray.HEAD_IDX] = 0;
361-
this.freelist[1] = POINT_COUNT - 1;
371+
this.nextFreeOrSpawned[poolSize - 1] = FL.END;
372+
this.freelist[FL.HEAD] = 0;
373+
this.freelist[FL.TAIL] = POINT_COUNT - 1;
362374
}
363375

364376
public spawn() {
365377
// pop from freelist, return if none available
366-
if (this.freelist[PointsArray.HEAD_IDX] == PointsArray.LIST_END)
367-
return PointsArray.LIST_END;
368-
369-
const idx = this.freelist[PointsArray.HEAD_IDX];
370-
371-
this.freelist[PointsArray.HEAD_IDX] = this.nextFreeOrSpawned[idx];
372-
if (this.freelist[PointsArray.HEAD_IDX] == PointsArray.LIST_END)
373-
this.freelist[1] = PointsArray.LIST_END;
374-
this.nextFreeOrSpawned[idx] = PointsArray.IS_SPAWNED;
378+
if (this.freelist[FL.HEAD] == FL.END)
379+
return FL.END;
380+
381+
const idx = this.freelist[FL.HEAD];
382+
383+
this.freelist[FL.HEAD] = this.nextFreeOrSpawned[idx];
384+
if (this.freelist[FL.HEAD] == FL.END)
385+
this.freelist[FL.TAIL] = FL.END;
386+
this.nextFreeOrSpawned[idx] = FL.SPAWNED;
375387

376388
// got the next available point, initialize
377389
const lerpVal = PRNG.nextRange(0, 1);
@@ -405,15 +417,15 @@ class PointsArray {
405417

406418
public free(idx: number) {
407419
const [vx, vy, vz] = getVec3Idx(idx);
408-
this.positions[vx] = Number.MAX_VALUE;
420+
this.positions[vx] = Number.MAX_VALUE; // prevent small chance of flickering upon ege of free/respawn
409421
this.positions[vy] = Number.MAX_VALUE;
410422
this.positions[vz] = Number.MAX_VALUE;
411-
this.nextFreeOrSpawned[idx] = PointsArray.LIST_END;
412-
if (this.freelist[PointsArray.TAIL_IDX] != PointsArray.LIST_END)
413-
this.nextFreeOrSpawned[this.freelist[PointsArray.TAIL_IDX]] = idx;
423+
this.nextFreeOrSpawned[idx] = FL.END;
424+
if (this.freelist[FL.TAIL] != FL.END)
425+
this.nextFreeOrSpawned[this.freelist[FL.TAIL]] = idx;
414426
else
415-
this.freelist[PointsArray.HEAD_IDX] = idx;
416-
this.freelist[PointsArray.TAIL_IDX] = idx;
427+
this.freelist[FL.HEAD] = idx;
428+
this.freelist[FL.TAIL] = idx;
417429
}
418430

419431
public getBoundingBox(idx: number) {
@@ -453,7 +465,7 @@ class PointsArray {
453465
}
454466

455467
public isNotSpawned(idx: number) {
456-
return this.nextFreeOrSpawned[idx] != PointsArray.IS_SPAWNED;
468+
return this.nextFreeOrSpawned[idx] != FL.SPAWNED;
457469
}
458470

459471
private getStartPos(idx: number) {

0 commit comments

Comments
 (0)