website update

This commit is contained in:
Orion Reed 2024-12-22 23:30:24 -05:00
parent e69f60b59f
commit 8e6e4380f4
23 changed files with 247 additions and 55 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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<string, string[]>,
{} as Record<string, typeof files>,
);
// Generate ungrouped HTML first
// Generate ungrouped HTML
const ungroupedHtml = ungroupedFiles
.sort()
.map((file) => {
const title = file.replace('.html', '').replaceAll('-', ' ');
return `<li><a href="${file}">${title}</a></li>`;
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ path, name }) => {
const title = name.replace('.html', '').replaceAll('-', ' ');
return `<li><a href="${path}">${title}</a></li>`;
})
.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 `<li><a href="${file}">${title}</a></li>`;
.sort((a, b) => a.name.localeCompare(b.name))
.map(({ path, name }) => {
const title = name.replace('.html', '').replaceAll('-', ' ');
return `<li><a href="${path}">${title}</a></li>`;
})
.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<string, string>,

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@ -6,7 +6,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Pixelify+Sans&display=swap"
href="https://fonts.googleapis.com/css2?family=Recursive:slnt,wght,CASL,CRSV,MONO@-15..0,300..1000,0..1,0..1,0..1&display=swap"
rel="stylesheet"
/>
<title>Folk Canvas</title>
@ -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;
}
</style>
<script type="module">
import '@labs/standalone/folk-sand.ts';
const alchemicalSymbols = [
'🜁',
'🜂',
'🜃',
'🜄',
'🜅',
'🜆',
'🜇',
'🜈',
'🜉',
'🜊',
'🜋',
'🜌',
'🜍',
'🜎',
'🜏',
'🜐',
'🜑',
'🜒',
'🜓',
'🜔',
'🜕',
'🜖',
'🜗',
'🜘',
'🜙',
'🜚',
'🜛',
'🜜',
'🜝',
'🜞',
'🜟',
'🜠',
'🜡',
'🜢',
'🜣',
'🜤',
'🜥',
'🜦',
'🜧',
'🜨',
'🜩',
'🜪',
'🜫',
'🜬',
'🜭',
'🜮',
'🜯',
'🜰',
'🜱',
'🜲',
'🜳',
'🜴',
'🜵',
'🜶',
'🜸',
'🜹',
'🜺',
'🜻',
'🜼',
'🜾',
'🜿',
'🝀',
'🝁',
'🝂',
'🝃',
'🝄',
'🝅',
'🝆',
'🝈',
'🝉',
'🝊',
'🝋',
'🝌',
'🝍',
'🝎',
'🝏',
'🝐',
'🝑',
'🝒',
'🝓',
'🝔',
'🝕',
'🝖',
'🝗',
'🝘',
'🝙',
'🝚',
'🝛',
'🝜',
'🝝',
'🝞',
'🝟',
'🝠',
'🝡',
'🝢',
'🝣',
'🝤',
'🝥',
'🝦',
'🝧',
'🝩',
'🝪',
'🝬',
'🝭',
'🝮',
'🝯',
'🝰',
'🝲',
'🝳',
];
document.addEventListener('DOMContentLoaded', () => {
const questionItems = document.querySelectorAll('#questions li');
questionItems.forEach((li) => {
const randomSymbol = alchemicalSymbols[Math.floor(Math.random() * alchemicalSymbols.length)];
li.setAttribute('data-symbol', randomSymbol);
});
});
</script>
</head>
<body>
<folk-sand initial-sand="0"></folk-sand>
<main>
<h1>
Folk Canvas
<a href="https://github.com/folk-canvas/folk-canvas">(Github)</a>
</h1>
<h1> Folk Canvas [<a href="https://github.com/folk-canvas/folk-canvas">Github</a>] </h1>
<ul id="questions">
<li>How do we make the web feel more alive and less rigid and closed off?</li>
<li>How can we more easily compose web pages and their data together?</li>
@ -99,8 +249,11 @@
>
</ul>
<h2>Demos</h2>
<p id="disclaimer">(Make sure to checkout the dev tools, all of the you see are just authored in HTML!)</p>
<h2>Experiments from the lab</h2>
<p id="disclaimer">
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!
</p>
<ul id="links">
{{ LINKS }}