feat: draw a red square

This commit is contained in:
Florian Sylvain
2025-04-05 23:37:22 +02:00
parent 95fa10f306
commit 10f67b8a11
9 changed files with 632 additions and 716 deletions
+3 -3
View File
@@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/webgpu.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
<title>Whatever WebGPU</title>
</head>
<body>
<div id="app"></div>
<canvas id="canvas"></canvas>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+4
View File
@@ -12,5 +12,9 @@
"prettier": "3.5.3",
"typescript": "~5.7.2",
"vite": "^6.2.0"
},
"dependencies": {
"@webgpu/types": "^0.1.60",
"webgpu": "^0.2.11"
}
}
+475 -621
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

+45
View File
@@ -0,0 +1,45 @@
<svg id="Logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="768" height="768" viewBox="0 0 768 768">
<defs>
<style>
.cls-1, .cls-2, .cls-3, .cls-4, .cls-5 {
fill-rule: evenodd;
stroke-linejoin: round;
}
.cls-6 {
fill-rule: evenodd;
}
.cls-1 {
fill: #005a9c;
stroke: #005a9c;
}
.cls-2 {
fill: #0066b0;
stroke: #0066b0;
}
.cls-3 {
fill: #0076cc;
stroke: #0076cc;
}
.cls-4 {
fill: #0086e8;
stroke: #0086e8;
}
.cls-5 {
fill: #0093ff;
stroke: #0093ff;
}
</style>
</defs>
<path id="Triangle_4" data-name="Triangle 4" class="cls-4" d="m626.63 295.5-60.189-104.25h120.55z"/>
<path id="Triangle_5" data-name="Triangle 5" class="cls-5" d="m626.63 87.001-60.189 104.25h120.55z"/>
<path id="Triangle_3" data-name="Triangle 3" class="cls-3" d="m506.26 504-120.38-208.5 240.76-2e-3z"/>
<path id="Triangle_2" data-name="Triangle 2" class="cls-2" d="m506.26 87-120.38 208.5 240.76-2e-3z"/>
<path id="Triangle_1" data-name="Triangle 1" class="cls-1" d="m265.5 504-240.76-417h481.51z"/>
<path id="WebGPU" class="cls-6" d="M168.627,547.469l-25.7,98.943-26.877-98.943H98.913L70.692,646.748,45.158,547.469H28.864L61.621,664.722l16.966-.168,28.221-94.239,27.214,94.239h17.134l33.933-117.085H168.627ZM285.879,615a46.371,46.371,0,0,0-5.459-22.594A39.572,39.572,0,0,0,264.881,576.7a46.213,46.213,0,0,0-23.181-5.711,47.756,47.756,0,0,0-23.77,5.8,40.093,40.093,0,0,0-16.043,16.547q-5.712,10.752-5.711,25.029t5.879,25.114a41.6,41.6,0,0,0,16.211,16.714,46.506,46.506,0,0,0,23.434,5.88q16.461,0,27.549-8.315a39.581,39.581,0,0,0,14.783-21.586H267.569a24.459,24.459,0,0,1-9.323,12.347q-6.637,4.621-16.546,4.619a29.643,29.643,0,0,1-20.579-7.643q-8.484-7.643-9.323-21.25h73.578a90.2,90.2,0,0,0,.5-9.239h0Zm-15.79-3.192H211.966q1.174-13.1,9.323-20.494a28.334,28.334,0,0,1,19.739-7.391,32.747,32.747,0,0,1,14.7,3.275,25.141,25.141,0,0,1,10.5,9.575,28.211,28.211,0,0,1,3.864,15.035h0Zm51.234-22.174V540.246H306.037V664.554h15.286V647.588a35.4,35.4,0,0,0,13.523,13.27,40.944,40.944,0,0,0,20.914,5.208,41.878,41.878,0,0,0,37.965-23.014,52.85,52.85,0,0,0,5.711-24.862q0-14.111-5.711-24.777A41.656,41.656,0,0,0,378.1,576.866a42.963,42.963,0,0,0-22.342-5.879,40.769,40.769,0,0,0-20.662,5.207,36.153,36.153,0,0,0-13.775,13.439h0Zm62.491,28.557a38.312,38.312,0,0,1-4.2,18.395,29.538,29.538,0,0,1-11.339,11.927,30.881,30.881,0,0,1-15.707,4.115,30.554,30.554,0,0,1-15.538-4.115,30.081,30.081,0,0,1-11.423-11.927,40.557,40.557,0,0,1,0-36.285,30.1,30.1,0,0,1,11.423-11.927,30.574,30.574,0,0,1,15.538-4.115,31.392,31.392,0,0,1,15.707,4.031,29.1,29.1,0,0,1,11.339,11.759,37.449,37.449,0,0,1,4.2,18.142h0ZM526.6,581.4a52.873,52.873,0,0,0-20.914-26.038q-14.363-9.236-33.008-9.239a59.1,59.1,0,0,0-29.734,7.643,55.966,55.966,0,0,0-21.25,21.334,64.565,64.565,0,0,0,0,61.567,56.107,56.107,0,0,0,21.25,21.25,59.068,59.068,0,0,0,29.734,7.643,56.956,56.956,0,0,0,28.053-6.971,56.039,56.039,0,0,0,20.326-18.983,58.146,58.146,0,0,0,9.071-26.457V601.392H467.133v12.431h46.7Q511.982,631.3,500.9,641.54t-28.221,10.247a43.637,43.637,0,0,1-22.091-5.627,39.867,39.867,0,0,1-15.454-16.043q-5.629-10.413-5.627-24.189t5.627-24.274a39.775,39.775,0,0,1,15.454-16.127,43.657,43.657,0,0,1,22.091-5.627,40.519,40.519,0,0,1,21.5,5.627A36.439,36.439,0,0,1,508.289,581.4H526.6Zm101.967,0.336q0-15.119-10.331-24.694t-30.153-9.575h-37.8V664.554h15.287V615.671h22.51q20.493,0,30.489-9.659t10-24.274h0Zm-40.484,21.334h-22.51v-43h22.51q24.858,0,24.861,21.67,0,10.248-6.047,15.79t-18.814,5.544h0Zm59.129-55.6v73.913q0,14.615,5.8,24.61a36.383,36.383,0,0,0,15.79,14.866,54.05,54.05,0,0,0,44.852,0,36.913,36.913,0,0,0,15.875-14.866Q735.4,636,735.4,621.382V547.469H720.117V621.55q0,15.623-7.644,23.182t-21.082,7.559q-13.606,0-21.25-7.559T662.5,621.55V547.469H647.211Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+85
View File
@@ -1 +1,86 @@
import "./style.css"
async function init() {
const canvas = document.querySelector<HTMLCanvasElement>("#canvas")
if (!canvas) {
throw new Error("Canvas element not found")
}
if (!navigator.gpu) {
throw new Error("WebGPU not supported on this browser.")
}
const adapter = await navigator.gpu.requestAdapter()
if (!adapter) {
throw new Error("No appropriate GPUAdapter found.")
}
const context = canvas.getContext("webgpu")
if (!context) {
throw new Error("Failed to get WebGPU context.")
}
const device = await adapter.requestDevice()
const canvasFormat = navigator.gpu.getPreferredCanvasFormat()
context.configure({ device, format: canvasFormat })
const encoder = device.createCommandEncoder()
const vertexBufferLayout = {
arrayStride: 8,
attributes: [
{
format: "float32x2" as GPUVertexFormat,
offset: 0,
shaderLocation: 0,
},
],
}
const cellShaderModule = device.createShaderModule({
label: "Cell shader",
code: (await import("./shaders/cell.wgsl?raw")).default,
})
const cellPipeline = device.createRenderPipeline({
label: "Cell pipeline",
layout: "auto",
vertex: {
module: cellShaderModule,
entryPoint: "vertexMain",
buffers: [vertexBufferLayout],
},
fragment: {
module: cellShaderModule,
entryPoint: "fragmentMain",
targets: [{ format: canvasFormat }],
},
})
const vertices = new Float32Array([
-0.8, -0.8, 0.8, -0.8, 0.8, 0.8, -0.8, -0.8, 0.8, 0.8, -0.8, 0.8,
])
const vertexBuffer = device.createBuffer({
label: "Cell vertices",
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
})
device.queue.writeBuffer(vertexBuffer, 0, vertices)
const pass = encoder.beginRenderPass({
colorAttachments: [
{
view: context.getCurrentTexture().createView(),
loadOp: "clear",
clearValue: [0.0, 0.0, 0.4, 1.0],
storeOp: "store",
},
],
})
pass.setPipeline(cellPipeline)
pass.setVertexBuffer(0, vertexBuffer)
pass.draw(vertices.length / 2)
pass.end()
device.queue.submit([encoder.finish()])
}
init().catch((error) => {
console.error("Failed to initialize the application:", error)
})
+9
View File
@@ -0,0 +1,9 @@
@vertex
fn vertexMain(@location(0) pos: vec2f) -> @builtin(position) vec4f {
return vec4f(pos, 0, 1);
}
@fragment
fn fragmentMain() -> @location(0) vec4f {
return vec4f(1, 0, 0, 1);
}
+9 -90
View File
@@ -1,96 +1,15 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
padding: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vanilla:hover {
filter: drop-shadow(0 0 2em #3178c6aa);
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
canvas {
width: 512px;
height: 512px;
display: block;
}
+2 -1
View File
@@ -18,7 +18,8 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
"noUncheckedSideEffectImports": true,
"types": ["@webgpu/types"]
},
"include": ["src"]
}