From 8e6e4380f43c9e9eda620b07a2f1629d1516809d Mon Sep 17 00:00:00 2001 From: Orion Reed Date: Sun, 22 Dec 2024 23:30:24 -0500 Subject: [PATCH] website update --- labs/folk-sand.glsl.ts | 3 +- labs/folk-sand.ts | 41 +++- vite.config.ts | 63 +++--- .../chains-of-thought.json | 0 .../index.html | 0 .../main.ts | 0 website/canvas/index.html | 195 ++++++++++++++++-- website/canvas/{ => morph}/projector.html | 0 .../spreadsheet-shape-projection.html | 0 .../audio-beats-with-event-propagators.html | 0 ...event-propagators-with-device-gravity.html | 0 .../event-propagators-with-weather.html | 0 .../{ => propagators}/event-propagators.html | 0 ...d-communication-and-event-propagators.html | 0 .../spreadsheet-map-propagator.html | 0 .../distance-field.html} | 0 .../falling-sand.html} | 0 website/canvas/{ => space}/radial-space.html | 0 website/canvas/{ => space}/space-morph.html | 0 .../canvas/{ => space}/space-transform.html | 0 .../distance-field.html} | 0 .../many-shapes.html} | 0 .../{[tests]rope.html => tests/rope.html} | 0 23 files changed, 247 insertions(+), 55 deletions(-) rename website/canvas/{chains-of-thought => _chains-of-thought}/chains-of-thought.json (100%) rename website/canvas/{chains-of-thought => _chains-of-thought}/index.html (100%) rename website/canvas/{chains-of-thought => _chains-of-thought}/main.ts (100%) rename website/canvas/{ => morph}/projector.html (100%) rename website/canvas/{ => morph}/spreadsheet-shape-projection.html (100%) rename website/canvas/{ => propagators}/audio-beats-with-event-propagators.html (100%) rename website/canvas/{ => propagators}/event-propagators-with-device-gravity.html (100%) rename website/canvas/{ => propagators}/event-propagators-with-weather.html (100%) rename website/canvas/{ => propagators}/event-propagators.html (100%) rename website/canvas/{ => propagators}/proximity-based-communication-and-event-propagators.html (100%) rename website/canvas/{ => propagators}/spreadsheet-map-propagator.html (100%) rename website/canvas/{[shaders]distance-field.html => shaders/distance-field.html} (100%) rename website/canvas/{[shaders]falling-sand.html => shaders/falling-sand.html} (100%) rename website/canvas/{ => space}/radial-space.html (100%) rename website/canvas/{ => space}/space-morph.html (100%) rename website/canvas/{ => space}/space-transform.html (100%) rename website/canvas/{[tests]distance-field.html => tests/distance-field.html} (100%) rename website/canvas/{[tests]many-shapes.html => tests/many-shapes.html} (100%) rename website/canvas/{[tests]rope.html => tests/rope.html} (100%) diff --git a/labs/folk-sand.glsl.ts b/labs/folk-sand.glsl.ts index f700467..97ac88c 100644 --- a/labs/folk-sand.glsl.ts +++ b/labs/folk-sand.glsl.ts @@ -97,6 +97,7 @@ uniform int materialType; uniform float brushRadius; uniform sampler2D tex; uniform sampler2D u_collisionTex; +uniform float initialSand; in vec2 outUv; @@ -196,7 +197,7 @@ void main() { if (frame == 0) { float r = hash12(gl_FragCoord.xy); float id = AIR; - if (r < 0.15) + if (r < initialSand) { id = SAND; } diff --git a/labs/folk-sand.ts b/labs/folk-sand.ts index c9d48ed..4ae872c 100644 --- a/labs/folk-sand.ts +++ b/labs/folk-sand.ts @@ -25,6 +25,12 @@ export class FolkSand extends FolkBaseSet { `, ]; + static properties = { + initialSand: { type: Number, attribute: 'initial-sand' }, + }; + + initialSand = 0.15; + #canvas = document.createElement('canvas'); #gl!: WebGL2RenderingContext; @@ -152,7 +158,17 @@ export class FolkSand extends FolkBaseSet { // Create collision texture this.#collisionTex = gl.createTexture()!; gl.bindTexture(gl.TEXTURE_2D, this.#collisionTex); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, this.#bufferWidth, this.#bufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA8, + this.#bufferWidth, + this.#bufferHeight, + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + null, + ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); @@ -425,6 +441,9 @@ export class FolkSand extends FolkBaseSet { gl.bindTexture(gl.TEXTURE_2D, this.#collisionTex); } + const initialSandLoc = gl.getUniformLocation(this.#program, 'initialSand'); + gl.uniform1f(initialSandLoc, this.initialSand); + let mx = (this.#pointer.x / gl.canvas.width) * this.#bufferWidth; let my = (1.0 - this.#pointer.y / gl.canvas.height) * this.#bufferHeight; let mpx = (this.#pointer.prevX / gl.canvas.width) * this.#bufferWidth; @@ -543,7 +562,17 @@ export class FolkSand extends FolkBaseSet { // Update collision texture size gl.bindTexture(gl.TEXTURE_2D, this.#collisionTex); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, this.#bufferWidth, this.#bufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA8, + this.#bufferWidth, + this.#bufferHeight, + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + null, + ); // Re-render collision data after resize this.#handleShapeTransform(); @@ -587,13 +616,7 @@ export class FolkSand extends FolkBaseSet { } } - #createProgramFromStrings({ - vertex, - fragment, - }: { - vertex: string; - fragment: string; - }): WebGLProgram | undefined { + #createProgramFromStrings({ vertex, fragment }: { vertex: string; fragment: string }): WebGLProgram | undefined { const vertexShader = WebGLUtils.createShader(this.#gl, this.#gl.VERTEX_SHADER, vertex); const fragmentShader = WebGLUtils.createShader(this.#gl, this.#gl.FRAGMENT_SHADER, fragment); diff --git a/vite.config.ts b/vite.config.ts index 5861837..827deb3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,7 +6,27 @@ import mkcert from 'vite-plugin-mkcert'; const canvasWebsiteDir = resolve(__dirname, './website/canvas'); function getCanvasFiles() { - return readdirSync(canvasWebsiteDir).filter((file) => file.endsWith('.html')); + const files: { path: string; name: string }[] = []; + + // Helper function to read directory recursively + const readDir = (dir: string, base = '') => { + readdirSync(dir, { withFileTypes: true }).forEach((dirent) => { + // Skip directories that start with underscore + if (dirent.name.startsWith('_')) return; + + if (dirent.isDirectory()) { + readDir(resolve(dir, dirent.name), `${base}${dirent.name}/`); + } else if (dirent.name.endsWith('.html')) { + files.push({ + path: `${base}${dirent.name}`, + name: dirent.name, + }); + } + }); + }; + + readDir(canvasWebsiteDir); + return files; } const linkGenerator = (): Plugin => { @@ -15,46 +35,41 @@ const linkGenerator = (): Plugin => { transformIndexHtml(html: string, ctx: IndexHtmlTransformContext) { if (!ctx.filename.endsWith('canvas/index.html')) return; const files = getCanvasFiles(); - // First, handle ungrouped files - const ungroupedFiles = files.filter( - (file) => !file.includes('index') && !file.startsWith('_') && !file.match(/^\[([^\]]+)\]/), - ); - // Then handle grouped files + // Handle ungrouped files (in root canvas directory) + const ungroupedFiles = files.filter((file) => !file.path.includes('/') && !file.name.includes('index')); + + // Handle grouped files (in subdirectories) const groups = files - .filter((file) => !file.includes('index') && file.match(/^\[([^\]]+)\]/)) + .filter((file) => file.path.includes('/')) .reduce( (acc, file) => { - const match = file.match(/^\[([^\]]+)\](.+)\.html$/); - const group = match![1]; + const group = file.path.split('/')[0]; if (!acc[group]) acc[group] = []; acc[group].push(file); return acc; }, - {} as Record, + {} as Record, ); - // Generate ungrouped HTML first + // Generate ungrouped HTML const ungroupedHtml = ungroupedFiles - .sort() - .map((file) => { - const title = file.replace('.html', '').replaceAll('-', ' '); - return `
  • ${title}
  • `; + .sort((a, b) => a.name.localeCompare(b.name)) + .map(({ path, name }) => { + const title = name.replace('.html', '').replaceAll('-', ' '); + return `
  • ${title}
  • `; }) .join('\n'); - // Then generate grouped HTML + // Generate grouped HTML const groupedHtml = Object.entries(groups) .sort(([a], [b]) => a.localeCompare(b)) .map(([group, groupFiles]) => { const groupHtml = groupFiles - .sort() - .map((file) => { - const title = file - .replace(/^\[[^\]]+\]/, '') - .replace('.html', '') - .replaceAll('-', ' '); - return `
  • ${title}
  • `; + .sort((a, b) => a.name.localeCompare(b.name)) + .map(({ path, name }) => { + const title = name.replace('.html', '').replaceAll('-', ' '); + return `
  • ${title}
  • `; }) .join('\n'); @@ -84,7 +99,7 @@ export default defineConfig({ index: resolve(__dirname, './website/index.html'), ...getCanvasFiles().reduce( (acc, file) => { - acc[`canvas/${file.replace('.html', '')}`] = resolve(canvasWebsiteDir, file); + acc[`canvas/${file.name.replace('.html', '')}`] = resolve(canvasWebsiteDir, file.name); return acc; }, {} as Record, diff --git a/website/canvas/chains-of-thought/chains-of-thought.json b/website/canvas/_chains-of-thought/chains-of-thought.json similarity index 100% rename from website/canvas/chains-of-thought/chains-of-thought.json rename to website/canvas/_chains-of-thought/chains-of-thought.json diff --git a/website/canvas/chains-of-thought/index.html b/website/canvas/_chains-of-thought/index.html similarity index 100% rename from website/canvas/chains-of-thought/index.html rename to website/canvas/_chains-of-thought/index.html diff --git a/website/canvas/chains-of-thought/main.ts b/website/canvas/_chains-of-thought/main.ts similarity index 100% rename from website/canvas/chains-of-thought/main.ts rename to website/canvas/_chains-of-thought/main.ts diff --git a/website/canvas/index.html b/website/canvas/index.html index 2793b5b..5afb8f8 100644 --- a/website/canvas/index.html +++ b/website/canvas/index.html @@ -1,4 +1,4 @@ - + @@ -6,7 +6,7 @@ Folk Canvas @@ -16,27 +16,50 @@ background: #f5f5f5; } + body { + margin: 0; + min-height: 100%; + } + + folk-sand { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + main { - font-family: 'Courier Prime', Courier, monospace; + position: relative; + font-family: 'Recursive', Courier, monospace; + font-variation-settings: + 'slnt' 0, + 'wght' 400, + 'CASL' 1, + 'CRSV' 0, + 'MONO' 0; max-width: 800px; margin: 20px auto; padding: 20px; border-radius: 2px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); - background: #fff; + background: rgba(255, 255, 255, 0.9); } h1 { - color: #2c3e50; margin: 0; margin-bottom: 1em; text-align: center; + font-variation-settings: + 'CASL' 0, + 'MONO' 1; } h2 { - color: #2c3e50; font-size: 1.2em; + font-weight: 800; margin: 1em 0 0; + font-variation-settings: 'wght' 800; } ul { @@ -46,14 +69,24 @@ margin: 0; } + li { + display: grid; + grid-template-columns: 2em 1fr; + padding-left: 0; + text-indent: 0; + } + li::before { - content: '>'; - color: #666; - margin-right: 1em; + content: '➔'; + justify-self: center; + } + + #questions li::before { + content: attr(data-symbol); } a { - color: #34495e; + color: #22282f; text-decoration: none; } @@ -63,12 +96,8 @@ #questions { font-size: 0.9rem; - font-style: italic; + font-variation-settings: 'slnt' 1; margin-bottom: 2rem; - - li::before { - content: '-'; - } } #disclaimer { @@ -76,13 +105,134 @@ font-style: italic; } + +
    -

    - Folk Canvas - (Github) -

    +

    Folk Canvas [Github]

    • How do we make the web feel more alive and less rigid and closed off?
    • How can we more easily compose web pages and their data together?
    • @@ -99,8 +249,11 @@ >
    -

    Demos

    -

    (Make sure to checkout the dev tools, all of the you see are just authored in HTML!)

    +

    Experiments from the lab

    +

    + These experiments (like this page) are very raw, intended to poke at new primitives and ideas. Make sure to + checkout the dev tools, all of the you see are just authored in HTML! +