Add additional marketplace options on launch

This commit is contained in:
2026-01-13 13:12:44 +01:00
parent 94d0787b75
commit ea986059ba
21 changed files with 252 additions and 5 deletions

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"name": "Checkerboard test",
"description": "Animated checkerboard pattern with a moving offset to spot scaling artifacts."
}

View File

@@ -0,0 +1,30 @@
function init() {}
function tick(context, state) {
const { ctx, width, height, deltaMs } = context;
if (!ctx) {
return;
}
const speed = 0.02;
const offset = ((state.offset || 0) + (deltaMs || 0) * speed) % 40;
state.offset = offset;
const squareSize = 40;
ctx.clearRect(0, 0, width, height);
for (let y = -squareSize; y < height + squareSize; y += squareSize) {
for (let x = -squareSize; x < width + squareSize; x += squareSize) {
const isDark = ((x + y) / squareSize) % 2 === 0;
ctx.fillStyle = isDark ? "#101828" : "#e2e8f0";
ctx.fillRect(x + offset, y + offset, squareSize, squareSize);
}
}
ctx.strokeStyle = "#ef4444";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(width / 2, 0);
ctx.lineTo(width / 2, height);
ctx.moveTo(0, height / 2);
ctx.lineTo(width, height / 2);
ctx.stroke();
}

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"name": "Circle grid",
"description": "Concentric circles and calibration marks to test geometry and focus."
}

View File

@@ -0,0 +1,42 @@
function init() {}
function tick(context, state) {
const { ctx, width, height, deltaMs } = context;
if (!ctx) {
return;
}
ctx.clearRect(0, 0, width, height);
const centerX = width / 2;
const centerY = height / 2;
const maxRadius = Math.min(width, height) * 0.45;
const pulse = 0.02 * (deltaMs || 0);
state.phase = (state.phase || 0) + pulse;
ctx.strokeStyle = "#38bdf8";
ctx.lineWidth = 2;
for (let radius = maxRadius; radius > 0; radius -= maxRadius / 6) {
ctx.globalAlpha = 0.2 + (radius / maxRadius) * 0.6;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.stroke();
}
ctx.globalAlpha = 1;
ctx.strokeStyle = "#22c55e";
ctx.lineWidth = 3;
const sweep = (Math.sin(state.phase) + 1) / 2;
const sweepRadius = maxRadius * (0.3 + sweep * 0.7);
ctx.beginPath();
ctx.arc(centerX, centerY, sweepRadius, 0, Math.PI * 2);
ctx.stroke();
ctx.strokeStyle = "#f8fafc";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(centerX, 0);
ctx.lineTo(centerX, height);
ctx.moveTo(0, centerY);
ctx.lineTo(width, centerY);
ctx.stroke();
}

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"name": "Color bars",
"description": "Classic SMPTE-style color bars test pattern for verifying color reproduction."
}

View File

@@ -0,0 +1,38 @@
function init() {}
function tick(context) {
const { ctx, width, height } = context;
if (!ctx) {
return;
}
ctx.clearRect(0, 0, width, height);
const topHeight = height * 0.7;
const barWidth = width / 7;
const colors = [
"#ffffff",
"#ffff00",
"#00ffff",
"#00ff00",
"#ff00ff",
"#ff0000",
"#0000ff",
];
colors.forEach((color, index) => {
ctx.fillStyle = color;
ctx.fillRect(index * barWidth, 0, barWidth, topHeight);
});
const middleHeight = height * 0.15;
const middleColors = ["#0000ff", "#000000", "#ff00ff", "#000000", "#00ffff", "#000000", "#ffffff"];
middleColors.forEach((color, index) => {
ctx.fillStyle = color;
ctx.fillRect(index * barWidth, topHeight, barWidth, middleHeight);
});
const bottomHeight = height - topHeight - middleHeight;
const bottomColors = ["#2b2b2b", "#ffffff", "#2b2b2b", "#00ffff", "#2b2b2b", "#ff00ff", "#2b2b2b"];
bottomColors.forEach((color, index) => {
ctx.fillStyle = color;
ctx.fillRect(index * barWidth, topHeight + middleHeight, barWidth, bottomHeight);
});
}

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"name": "Rotating Möbius strip",
"description": "Procedural Möbius strip rendering with rotation for geometry inspection."
}

View File

@@ -0,0 +1,72 @@
function init() {}
function tick(context, state) {
const { ctx, width, height, deltaMs } = context;
if (!ctx) {
return;
}
const dt = (deltaMs || 16) * 0.001;
state.angle = (state.angle || 0) + dt * 0.6;
ctx.clearRect(0, 0, width, height);
const centerX = width / 2;
const centerY = height / 2;
const scale = Math.min(width, height) * 0.32;
const points = [];
const segments = 140;
const halfWidth = 0.35;
for (let i = 0; i <= segments; i += 1) {
const t = (i / segments) * Math.PI * 2;
const cosT = Math.cos(t);
const sinT = Math.sin(t);
for (const side of [-halfWidth, halfWidth]) {
const cosHalf = Math.cos(t / 2);
const sinHalf = Math.sin(t / 2);
const radius = 1 + (side * cosHalf) / 2;
const x = radius * cosT;
const y = radius * sinT;
const z = (side * sinHalf) / 2;
const y1 = y * Math.cos(state.angle) - z * Math.sin(state.angle);
const z1 = y * Math.sin(state.angle) + z * Math.cos(state.angle);
const x2 = x * Math.cos(state.angle * 0.7) - z1 * Math.sin(state.angle * 0.7);
const z2 = x * Math.sin(state.angle * 0.7) + z1 * Math.cos(state.angle * 0.7);
const depth = 2.6;
const perspective = depth / (depth - z2);
const screenX = centerX + x2 * scale * perspective;
const screenY = centerY + y1 * scale * perspective;
points.push({ screenX, screenY, depth: z2 });
}
}
ctx.lineWidth = 2;
for (let i = 0; i < points.length - 2; i += 2) {
const a = points[i];
const b = points[i + 1];
const brightness = Math.max(0.25, (a.depth + 1.5) / 3);
ctx.strokeStyle = `rgba(56, 189, 248, ${brightness})`;
ctx.beginPath();
ctx.moveTo(a.screenX, a.screenY);
ctx.lineTo(b.screenX, b.screenY);
ctx.stroke();
}
ctx.strokeStyle = "rgba(248, 250, 252, 0.7)";
ctx.lineWidth = 1;
ctx.beginPath();
for (let i = 0; i < points.length; i += 2) {
const p = points[i];
if (i === 0) {
ctx.moveTo(p.screenX, p.screenY);
} else {
ctx.lineTo(p.screenX, p.screenY);
}
}
ctx.closePath();
ctx.stroke();
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"name": "Rotating logo",
"description": "Renders the Imgfloat logo and rotates it every tick."
}

View File

@@ -0,0 +1,33 @@
async function init(context, state) {
const asset = Array.isArray(context.assets) ? context.assets[0] : null;
if (!asset?.blob) {
return;
}
state.rotation = 0;
state.imageReady = false;
try {
state.image = await createImageBitmap(asset.blob);
state.imageReady = true;
} catch (error) {
state.imageError = error;
}
}
function tick(context, state) {
const { ctx, width, height, deltaMs } = context;
if (!ctx) {
return;
}
ctx.clearRect(0, 0, width, height);
const image = state?.image;
if (!image || !state.imageReady) {
return;
}
const size = Math.min(width, height) * 0.35;
state.rotation = (state.rotation + (deltaMs || 0) * 0.002) % (Math.PI * 2);
ctx.save();
ctx.translate(width / 2, height / 2);
ctx.rotate(state.rotation);
ctx.drawImage(image, -size / 2, -size / 2, size, size);
ctx.restore();
}