Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
521 changes: 99 additions & 422 deletions app/assets/css/main.css

Large diffs are not rendered by default.

405 changes: 0 additions & 405 deletions app/components/NoiseField.client.vue

This file was deleted.

515 changes: 104 additions & 411 deletions app/pages/index.vue

Large diffs are not rendered by default.

50 changes: 0 additions & 50 deletions app/utils/webgl-context.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,3 @@
const requiredWebGL2Methods = [
'attachShader',
'bindVertexArray',
'blendFunc',
'clear',
'clearColor',
'compileShader',
'createProgram',
'createShader',
'createVertexArray',
'deleteProgram',
'deleteShader',
'deleteVertexArray',
'drawArrays',
'enable',
'getExtension',
'getProgramInfoLog',
'getProgramParameter',
'getShaderInfoLog',
'getShaderParameter',
'getUniformLocation',
'linkProgram',
'shaderSource',
'uniform1f',
'uniform2f',
'useProgram',
'viewport',
] as const

const requiredWebGL2Constants = [
'BLEND',
'COLOR_BUFFER_BIT',
'COMPILE_STATUS',
'FRAGMENT_SHADER',
'LINK_STATUS',
'ONE_MINUS_SRC_ALPHA',
'SRC_ALPHA',
'TRIANGLES',
'VERTEX_SHADER',
] as const

export function isUsableWebGL2Context(value: unknown): value is WebGL2RenderingContext {
if (typeof value !== 'object' || value === null)
return false

const candidate = value as Record<string, unknown>
return requiredWebGL2Methods.every(name => typeof candidate[name] === 'function')
&& requiredWebGL2Constants.every(name => typeof candidate[name] === 'number')
}

/**
* Renderers that run WebGL on the CPU: Chrome's SwiftShader fallback, Mesa's
* llvmpipe and softpipe, and Windows without a GPU driver. On these, every
Expand Down
2 changes: 1 addition & 1 deletion scripts/lib/production-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const ASSET_COHERENCE_PATH = '/skills/trending'
export const PRODUCTION_SMOKE_EXPECTATIONS: SmokeExpectation[] = [
// The hero words are asserted, not just an h1: the error branch renders an
// h1 too, so a homepage that lost its data would otherwise pass.
{ path: '/', status: 200, bodyContains: ['<h1', 'Taste-tested'] },
{ path: '/', status: 200, bodyContains: ['<h1', 'Hyped agent skills'] },
{ path: '/alt', status: 301, location: '/' },
{ path: '/skills', status: 200, bodyContains: ['<h1'] },
{ path: '/community', status: 200, bodyContains: ['<h1'] },
Expand Down
1 change: 0 additions & 1 deletion test/a11y.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,6 @@ describe('accessibility: component coverage', () => {
const SKIPPED_COMPONENTS = [
'OutcomeClusterGrid', // Content section (fetches /api/clusters), tested at page level
'KeyboardShortcutsModal.client', // Client-only modal requires full app context
'NoiseField.client', // Decorative client-only canvas
'TextureBrailleNames.client', // Decorative client-only canvas, hidden from screen readers
'TextureConverge.client', // Client-only canvas; its loading state is one role="status" with a text label
'TextureFileMinimap.client', // Decorative client-only canvas, hidden from screen readers
Expand Down
2 changes: 1 addition & 1 deletion test/unit/production-smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('production smoke contract', () => {
expect(PRODUCTION_SMOKE_EXPECTATIONS).toEqual(expect.arrayContaining([
// The homepage asserts its own hero words, because the page's error
// branch renders an h1 too.
{ path: '/', status: 200, bodyContains: ['<h1', 'Taste-tested'] },
{ path: '/', status: 200, bodyContains: ['<h1', 'Hyped agent skills'] },
{ path: '/alt', status: 301, location: '/' },
{ path: '/skills', status: 200, bodyContains: ['<h1'] },
{ path: '/community', status: 200, bodyContains: ['<h1'] },
Expand Down
61 changes: 2 additions & 59 deletions test/unit/webgl-context.test.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,5 @@
import { describe, expect, it, vi } from 'vitest'
import { isSoftwareRenderer, isUsableWebGL2Context } from '../../app/utils/webgl-context'

const requiredMethodNames = [
'attachShader',
'bindVertexArray',
'blendFunc',
'clear',
'clearColor',
'compileShader',
'createProgram',
'createShader',
'createVertexArray',
'deleteProgram',
'deleteShader',
'deleteVertexArray',
'drawArrays',
'enable',
'getExtension',
'getProgramInfoLog',
'getProgramParameter',
'getShaderInfoLog',
'getShaderParameter',
'getUniformLocation',
'linkProgram',
'shaderSource',
'uniform1f',
'uniform2f',
'useProgram',
'viewport',
] as const

function contextStub(): Record<string, unknown> {
return {
...Object.fromEntries(requiredMethodNames.map(name => [name, vi.fn()])),
BLEND: 1,
COLOR_BUFFER_BIT: 2,
COMPILE_STATUS: 3,
FRAGMENT_SHADER: 4,
LINK_STATUS: 5,
ONE_MINUS_SRC_ALPHA: 6,
SRC_ALPHA: 7,
TRIANGLES: 8,
VERTEX_SHADER: 9,
}
}

describe('isUsableWebGL2Context', () => {
it('rejects a partial context missing getShaderParameter', () => {
const context = contextStub()
delete context.getShaderParameter

expect(isUsableWebGL2Context(context)).toBe(false)
})

it('accepts a context that exposes every operation used by NoiseField', () => {
expect(isUsableWebGL2Context(contextStub())).toBe(true)
})
})
import { describe, expect, it } from 'vitest'
import { isSoftwareRenderer } from '../../app/utils/webgl-context'

describe('isSoftwareRenderer', () => {
it.each([
Expand Down