website update
This commit is contained in:
parent
e69f60b59f
commit
8e6e4380f4
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
Loading…
Reference in New Issue