From f0e664235718e7eb381b310760dc2a9bba519eed Mon Sep 17 00:00:00 2001 From: Vaclav Vancura Date: Mon, 18 May 2026 17:02:46 +0200 Subject: [PATCH] chore(docs): normalize em and en dashes to ascii hyphens Replace em dashes, en dashes, and spaced double hyphens with ASCII hyphens across docs, JSDoc, comments, error messages, and project guides for consistent plain-text style. Signed-off-by: Vaclav Vancura --- .claude/rules/bt-api-getters.md | 4 +-- .claude/skills/perf/SKILL.md | 2 +- .claude/skills/spellcheck/SKILL.md | 4 +-- CLAUDE.md | 4 +-- README.md | 8 ++--- docs/api-assets.md | 14 ++++----- docs/api-core.md | 34 ++++++++++---------- docs/api-palette.md | 10 +++--- docs/api-rendering.md | 26 +++++++-------- docs/bitmap-fonts.md | 4 +-- docs/developer-experience-guide.md | 2 +- docs/input.md | 8 ++--- docs/post-process-effects.md | 42 ++++++++++++------------- docs/testing.md | 6 ++-- docs/tooling.md | 6 ++-- docs/voice.md | 12 +++---- src/BlitTech.ts | 14 ++++----- src/__test__/webgpu-mock.ts | 2 +- src/assets/BitmapFont.ts | 4 +-- src/assets/Palette.test.ts | 2 +- src/assets/Palette.ts | 16 +++++----- src/assets/SpriteSheet.test.ts | 8 ++--- src/assets/SpriteSheet.ts | 12 +++---- src/assets/SystemFont.ts | 2 +- src/core/BTAPI.test.ts | 2 +- src/core/BTAPI.ts | 4 +-- src/core/GameLoop.test.ts | 4 +-- src/core/IBlitTechDemo.ts | 4 +-- src/core/WebGPUContext.test.ts | 2 +- src/core/WebGPUContext.ts | 2 +- src/input/KeyboardInput.ts | 2 +- src/render/PrimitivePipeline.ts | 2 +- src/render/SoftwareRenderer.ts | 10 +++--- src/render/SpritePipeline.ts | 8 ++--- src/render/UpscalePass.ts | 2 +- src/render/WebGpuRenderer.test.ts | 14 ++++----- src/render/WebGpuRenderer.ts | 8 ++--- src/render/effects/FullscreenEffect.ts | 2 +- src/render/effects/display/Flicker.ts | 2 +- src/render/effects/presets/amber.ts | 2 +- src/render/effects/presets/green.ts | 2 +- src/utils/Bootstrap.test.ts | 2 +- src/utils/Color32.ts | 18 +++++------ src/utils/FrameCapture.test.ts | 2 +- src/utils/Vector2i.ts | 4 +-- src/utils/errorMessages.ts | 8 ++--- tests/visual/fixtures/post-process.html | 2 +- 47 files changed, 177 insertions(+), 177 deletions(-) diff --git a/.claude/rules/bt-api-getters.md b/.claude/rules/bt-api-getters.md index cdfaa23..110c8a6 100644 --- a/.claude/rules/bt-api-getters.md +++ b/.claude/rules/bt-api-getters.md @@ -11,7 +11,7 @@ Quick rules when changing `src/BlitTech.ts` or demos: ## Getter list | Category | Members | -| --- | --- | +| - | - | | Configure-time (mirror `HardwareSettings` names) | `displaySize`, `canvasDisplaySize`, `targetFPS`, `outputSize` | | Loop timing | `deltaSeconds`, `timeSeconds`, `ticks` | | Runtime state | `activeBackend`, `camera`, `palette` | @@ -19,7 +19,7 @@ Quick rules when changing `src/BlitTech.ts` or demos: `outputSize` = effective buffer (`canvasDisplaySize ?? displaySize`). `Vector2i` getters return a clone per read. `activeBackend` is what actually started after fallback, not `configure().renderer`. -`palette` is a live reference — mutating slots affects rendering on the next frame. +`palette` is a live reference - mutating slots affects rendering on the next frame. ## Naming when adding getters diff --git a/.claude/skills/perf/SKILL.md b/.claude/skills/perf/SKILL.md index 8109b72..67eccfb 100644 --- a/.claude/skills/perf/SKILL.md +++ b/.claude/skills/perf/SKILL.md @@ -10,7 +10,7 @@ Use this skill when the task involves: - benchmarking a new hot method or allocation pattern - working on benchmark CI behavior -For visual correctness verification (not performance), use `pnpm test:visual` — see the Visual Regression Tests section +For visual correctness verification (not performance), use `pnpm test:visual` - see the Visual Regression Tests section in CLAUDE.md. ## CPU Benchmarks diff --git a/.claude/skills/spellcheck/SKILL.md b/.claude/skills/spellcheck/SKILL.md index 15909b8..f579f83 100644 --- a/.claude/skills/spellcheck/SKILL.md +++ b/.claude/skills/spellcheck/SKILL.md @@ -19,8 +19,8 @@ Run the project-wide spellcheck, then fix all reported errors. - Capture the full error output 2. **Analyze each error** For every word flagged by cspell, determine if it is: - - **A typo** – a misspelled word in source code, comments, strings, or content - - **A legitimate term** – a technical term, brand name, abbreviation, or proper noun that cspell doesn’t know + - **A typo** - a misspelled word in source code, comments, strings, or content + - **A legitimate term** - a technical term, brand name, abbreviation, or proper noun that cspell doesn’t know 3. **Fix typos in source files** - Open the file and fix the misspelled word in place diff --git a/CLAUDE.md b/CLAUDE.md index f3c1736..c6fa1ec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -241,7 +241,7 @@ pnpm bench:json # Run benchmarks and write benchmark-results.json ### Visual Regression Tests `pnpm test:visual` runs Playwright with Chromium + WebGPU and captures PNG snapshots of actual rendered frames. This is -the primary tool for verifying that visual output is correct — not performance, but pixel-level correctness. +the primary tool for verifying that visual output is correct - not performance, but pixel-level correctness. Use it when implementing or changing: @@ -276,7 +276,7 @@ Use the benchmark system when the user asks about performance, throughput, regre coverage. - Use **CPU benchmarks** for isolated methods, helpers, caches, and allocation patterns -- For rendering correctness, use visual regression tests (`pnpm test:visual`) — they produce PNG snapshots +- For rendering correctness, use visual regression tests (`pnpm test:visual`) - they produce PNG snapshots Recommended commands: diff --git a/README.md b/README.md index 66dac37..2773161 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ with palette indices, animate with palette cycling and fades, and ship authentic ## Inspiration Blit-Tech draws heavy inspiration from [RetroBlit](https://www.badcastle.com/retroblit/docs/doc/index.html) by Martin -Cietwierkowski ([@daafu](https://github.com/daafu)) — a retro pixel demo framework for Unity that replaces the editor +Cietwierkowski ([@daafu](https://github.com/daafu)) - a retro pixel demo framework for Unity that replaces the editor with a clean, low-level demo loop. Blit-Tech brings the same philosophy to the web using WebGPU: no scene graphs, no complex frameworks, just sprites, primitives, and fonts. @@ -26,7 +26,7 @@ complex frameworks, just sprites, primitives, and fonts. - **Palette offset variants**: recolor one sprite sheet into team colors, states, or themes without duplicate textures - **Performance-first data model**: tiny palette uploads (4 KB), smaller sprite textures, and compact primitive vertices - **WebGPU rendering** with dual-pipeline architecture (primitives + sprites); automatic Canvas 2D software fallback -- **Post-process effects**: two-tier system — pixel tier on the `r8uint` index framebuffer; display tier on upscaled +- **Post-process effects**: two-tier system - pixel tier on the `r8uint` index framebuffer; display tier on upscaled RGBA; bundled CRT presets - **Primitive drawing**: pixels, lines, rectangles (outline and filled) - **Sprite system**: palette-indexed textures, palette offset, automatic texture batching @@ -56,7 +56,7 @@ complex frameworks, just sprites, primitives, and fonts. - A **WebGPU-compatible browser** (the engine falls back to Canvas 2D software rendering when WebGPU is unavailable): - Chrome/Edge 113+ (Windows, macOS, Linux, Android) - Firefox 141+ on Windows; 145+/147+ on macOS; Nightly on Linux and Android - - Safari 26+ (macOS Tahoe / iOS 26); or Safari 18–25 with WebGPU enabled via Feature Flags + - Safari 26+ (macOS Tahoe / iOS 26); or Safari 18-25 with WebGPU enabled via Feature Flags **App toolchain** @@ -176,7 +176,7 @@ WebGPU support varies by browser: | ----------- | -------------- | ---------------------------------------------------------------- | | Chrome/Edge | 113+ | Enabled by default | | Firefox | 141+ (Windows) | Enabled by default; 145+/147+ on macOS; Nightly on Linux/Android | -| Safari | 26+ | Enabled by default; Safari 18–25 available via Feature Flags | +| Safari | 26+ | Enabled by default; Safari 18-25 available via Feature Flags | When WebGPU is unavailable the engine falls back to the Canvas 2D software renderer automatically. A dismissible in-canvas "SOFTWARE RENDERER" banner appears to confirm the fallback is active. Use `BT.activeBackend` to detect which diff --git a/docs/api-assets.md b/docs/api-assets.md index 6b3d477..bd11ba0 100644 --- a/docs/api-assets.md +++ b/docs/api-assets.md @@ -47,7 +47,7 @@ if (AssetLoader.isLoaded('sprites.png')) { --- -## Sprite Setup — Preferred Path +## Sprite Setup - Preferred Path Use `SpriteSheet.loadIndexed()` for all standard sprite setup. It combines color registration, image loading, and palette indexization in one call. @@ -60,7 +60,7 @@ const palette = new Palette(256); const indexed = await SpriteSheet.loadIndexed( 'sprites/hero.png', // URL palette, // palette to populate - 10, // startSlot — first palette slot to write colors into + 10, // startSlot - first palette slot to write colors into { sort: 'luminance' }, // optional: color order in palette ('luminance' | 'none') ); @@ -69,16 +69,16 @@ BT.paletteSet(palette); // activate AFTER loadIndexed returns // Draw using the returned sheet and source rectangle: BT.drawSprite(indexed.sheet, indexed.srcRect, new Vector2i(20, 20)); -// indexed.colors — list of Color32 values registered into the palette -// indexed.srcRect — Rect2i spanning the full image +// indexed.colors - list of Color32 values registered into the palette +// indexed.srcRect - Rect2i spanning the full image ``` Colors are sorted by perceived luminance (darkest-first) by default. Pass `{ sort: 'none' }` to preserve row-major scan -order. Slot 0 is never touched — transparent pixels in the image map to slot 0 at draw time. +order. Slot 0 is never touched - transparent pixels in the image map to slot 0 at draw time. --- -## Sprite Setup — Manual Path +## Sprite Setup - Manual Path Use this only when you need fine-grained control over the palette layout or want to load several sheets into the same palette sequentially. @@ -138,7 +138,7 @@ See [Bitmap Fonts Guide](bitmap-fonts.md) for the `.btfont` format specification ## System Font -A built-in 6×14 monospace font covering printable ASCII (characters 32–126). No load step needed. +A built-in 6×14 monospace font covering printable ASCII (characters 32-126). No load step needed. ```ts BT.systemPrint(new Vector2i(10, 10), paletteIndex, 'Score: 100'); diff --git a/docs/api-core.md b/docs/api-core.md index f7b5657..927a6c6 100644 --- a/docs/api-core.md +++ b/docs/api-core.md @@ -12,7 +12,7 @@ The `bootstrap()` function is the recommended entry point. It handles DOM ready, ```ts import { bootstrap, type BootstrapOptions } from 'blit-tech'; -// One-liner — canvas id defaults to 'blit-tech-canvas', container to 'canvas-container' +// One-liner - canvas id defaults to 'blit-tech-canvas', container to 'canvas-container' bootstrap(MyDemo); // With options @@ -31,8 +31,8 @@ bootstrap(MyDemo, { | ----------------- | ------------------------ | -------------------- | ------------------------------ | | `canvasId` | `string` | `'blit-tech-canvas'` | Canvas element id | | `containerId` | `string` | `'canvas-container'` | Container id for error display | -| `onSuccess` | `() => void` | — | Called after successful init | -| `onError` | `(error: Error) => void` | — | Called on any init failure | +| `onSuccess` | `() => void` | - | Called after successful init | +| `onError` | `(error: Error) => void` | - | Called on any init failure | | `waitForDOMReady` | `boolean` | `true` | Wait for `DOMContentLoaded` | **Manual utilities** (for custom initialization flows): @@ -50,10 +50,10 @@ displayError('Init Failed', 'WebGPU unavailable.', 'my-container'); ```ts const ok = await BT.init(demo, canvas); // low-level init; prefer bootstrap() -BT.displaySize; // Vector2i — configured logical resolution (clone per read) -BT.canvasDisplaySize; // Vector2i | null — output buffer when set in configure() -BT.outputSize; // Vector2i — effective drawing-buffer size (clone per read) -BT.targetFPS; // number — target updates per second +BT.displaySize; // Vector2i - configured logical resolution (clone per read) +BT.canvasDisplaySize; // Vector2i | null - output buffer when set in configure() +BT.outputSize; // Vector2i - effective drawing-buffer size (clone per read) +BT.targetFPS; // number - target updates per second BT.activeBackend; // 'webgpu' | 'software' | null ``` @@ -118,11 +118,11 @@ specific snapshot; the default is the engine tick counter. ## Camera -The camera applies a global pixel offset to all subsequent draw calls. Integer only — pass `Vector2i`, never floats. +The camera applies a global pixel offset to all subsequent draw calls. Integer only - pass `Vector2i`, never floats. ```ts BT.cameraSet(new Vector2i(scrollX, scrollY)); // apply offset -BT.camera; // Vector2i — current offset +BT.camera; // Vector2i - current offset BT.cameraReset(); // set back to (0, 0) // Clamp a camera origin so the viewport stays within a world: @@ -147,8 +147,8 @@ v.width; v.height; // aliases for x / y (useful when treating the vector as a size) // Static factories -Vector2i.zero(); // (0, 0) — cached frozen singleton -Vector2i.one(); // (1, 1) — cached frozen singleton +Vector2i.zero(); // (0, 0) - cached frozen singleton +Vector2i.one(); // (1, 1) - cached frozen singleton Vector2i.up(); // (0, -1) Vector2i.down(); // (0, 1) Vector2i.left(); // (-1, 0) @@ -174,16 +174,16 @@ Integer rectangle with `x, y, width, height` fields. const r = new Rect2i(x, y, width, height); // Static factories -Rect2i.zero(); // (0,0,0,0) — cached frozen singleton +Rect2i.zero(); // (0,0,0,0) - cached frozen singleton Rect2i.fromMinMax(min, max); // from corner vectors Rect2i.fromMinMaxXY(minX, minY, maxX, maxY); // zero-allocation variant Rect2i.fromCenterSize(center, size); // centered rectangle Rect2i.fromCenterSizeXY(cx, cy, w, h); // zero-allocation variant // Instance methods -r.contains(point); // boolean — point inside rect -r.intersects(other); // boolean — rects overlap -r.intersection(other); // Rect2i | null — overlap area +r.contains(point); // boolean - point inside rect +r.intersects(other); // boolean - rects overlap +r.intersection(other); // Rect2i | null - overlap area r.center; // Vector2i getter r.min; // Vector2i getter (top-left) r.max; // Vector2i getter (bottom-right) @@ -191,7 +191,7 @@ r.max; // Vector2i getter (bottom-right) ### Color32 -32-bit RGBA color (channels 0–255). +32-bit RGBA color (channels 0-255). ```ts const c = new Color32(r, g, b, a); @@ -200,7 +200,7 @@ const c = new Color32(r, g, b, a); Color32.white Color32.black Color32.transparent Color32.red Color32.green Color32.blue Color32.yellow Color32.cyan Color32.magenta -Color32.gray(value) // grayscale, value 0–255 +Color32.gray(value) // grayscale, value 0-255 // Hex parsing Color32.fromHex('#ff8800') // returns Color32 diff --git a/docs/api-palette.md b/docs/api-palette.md index 82fd82b..938ffe3 100644 --- a/docs/api-palette.md +++ b/docs/api-palette.md @@ -17,7 +17,7 @@ const palette = BT.paletteCreate(256); // equivalent BT-namespace shorthand // Set and get colors palette.set(1, new Color32(255, 0, 0, 255)); // red at slot 1 palette.get(1); // → Color32 (defensive copy) -palette.getRef(1); // → Color32 (live reference — do not store) +palette.getRef(1); // → Color32 (live reference - do not store) // Activate for rendering BT.paletteSet(palette); @@ -46,8 +46,8 @@ Palette.nes(); // NES 64-color Fills six consecutive UI-purpose slots into an existing palette and registers `hud_*` name aliases. ```ts -palette.applyHUD(); // fills slots 1–6 (default startSlot = 1) -palette.applyHUD(10); // fills slots 10–15 +palette.applyHUD(); // fills slots 1-6 (default startSlot = 1) +palette.applyHUD(10); // fills slots 10-15 BT.paletteSet(palette); ``` @@ -109,7 +109,7 @@ const slot = palette.findColor(color); // → index, or -1 if not found Animated effects run automatically each frame in the engine's end-of-frame pass (after `demo.render()`, before the GPU upload). Multiple effects can run simultaneously on different palette ranges and will not conflict. Effects process via -the `dirty` flag — no polling needed. +the `dirty` flag - no polling needed. ```ts // Cycle a range of slots (water, fire, plasma) @@ -152,7 +152,7 @@ Used by `paletteFade` and `paletteFadeRange`. Type: `EasingFunction`. ## Timing Note Effects are applied after `demo.render()` but before the GPU palette upload in `Renderer.endFrame()`. This means user -draw calls and palette effects see the same consistent snapshot within a frame — they never interleave mid-frame. +draw calls and palette effects see the same consistent snapshot within a frame - they never interleave mid-frame. Effects that auto-remove (fade, flash) clean up when their duration elapses. `paletteCycle` runs indefinitely until `paletteClearEffects()` is called. diff --git a/docs/api-rendering.md b/docs/api-rendering.md index d3d799f..1705815 100644 --- a/docs/api-rendering.md +++ b/docs/api-rendering.md @@ -3,7 +3,7 @@ Primitives, sprites, text, post-process effects, and frame capture. All draw calls require a palette to be active (`BT.paletteSet(palette)` before the first `BT.drawSprite`, -`BT.drawRectFill`, etc.). All coordinates are integer pixels — use `Vector2i` and `Rect2i`, never floats. +`BT.drawRectFill`, etc.). All coordinates are integer pixels - use `Vector2i` and `Rect2i`, never floats. --- @@ -21,7 +21,7 @@ BT.drawRect(rect, paletteIndex); // outline only BT.drawRectFill(rect, paletteIndex); // filled ``` -All primitives write palette indices, not RGBA — the active palette resolves colors at frame end. +All primitives write palette indices, not RGBA - the active palette resolves colors at frame end. --- @@ -34,10 +34,10 @@ BT.drawSprite(sheet, srcRect, destPos); BT.drawSprite(sheet, srcRect, destPos, paletteOffset); ``` -- `sheet` — an indexed `SpriteSheet` (must have been prepared via `loadIndexed` or `indexize`). -- `srcRect` — source region within the sheet in pixels. -- `destPos` — top-left destination in display coordinates. -- `paletteOffset` — shift added to every stored pixel index before palette lookup (default `0`). +- `sheet` - an indexed `SpriteSheet` (must have been prepared via `loadIndexed` or `indexize`). +- `srcRect` - source region within the sheet in pixels. +- `destPos` - top-left destination in display coordinates. +- `paletteOffset` - shift added to every stored pixel index before palette lookup (default `0`). **Palette offset semantics:** Stored sprite indices start at `1` (index `0` is always transparent and discarded). With `paletteOffset = N`, a pixel stored at index `1` renders as `palette[1 + N]`, a pixel at index `2` renders as @@ -70,7 +70,7 @@ BT.paletteSet(newLayoutPalette); BT.spritesRefresh(); // re-maps all tracked sheets to the new slot positions ``` -Call `spritesRefresh()` only after a **palette-layout swap** — when the same colors have moved to different slot +Call `spritesRefresh()` only after a **palette-layout swap** - when the same colors have moved to different slot indices. Do NOT call it after a palette-value swap (when you changed what color a slot holds). In the value-swap case the fragment shader picks up the new color automatically; calling `spritesRefresh()` is wasteful and will fail reindexing if original RGBA values are gone. @@ -81,7 +81,7 @@ reindexing if original RGBA values are gone. ### System font -Built-in 6×14 monospace font covering printable ASCII (characters 32–126). +Built-in 6×14 monospace font covering printable ASCII (characters 32-126). ```ts BT.systemPrint(pos, paletteIndex, text); // draw text at pos @@ -106,18 +106,18 @@ See [Bitmap Fonts Guide](bitmap-fonts.md) for the `.btfont` format spec and BMFo Two-tier fullscreen pipeline running between scene render and swap-chain present: -1. **Pixel tier** — operates on the logical `r8uint` framebuffer (one palette index per pixel). Effects here stay +1. **Pixel tier** - operates on the logical `r8uint` framebuffer (one palette index per pixel). Effects here stay palette-native (chunky glitch, mosaic). -2. **Palette resolve + upscale** — `PaletteResolveUpscalePass` converts indices to RGBA through the active palette LUT +2. **Palette resolve + upscale** - `PaletteResolveUpscalePass` converts indices to RGBA through the active palette LUT and upscales to `canvasDisplaySize`. -3. **Display tier** — operates on the RGBA output image. Hosts CRT scanlines, barrel distortion, bloom, etc. Requires +3. **Display tier** - operates on the RGBA output image. Hosts CRT scanlines, barrel distortion, bloom, etc. Requires `canvasDisplaySize` in hardware settings. -Both chains add zero cost when empty. Post-process is unsupported by the Canvas 2D software backend — calling +Both chains add zero cost when empty. Post-process is unsupported by the Canvas 2D software backend - calling `effectAdd` in software mode throws a clear error. ```ts -// Add effect — routed to pixel or display chain by Effect.tier automatically +// Add effect - routed to pixel or display chain by Effect.tier automatically BT.effectAdd(new BarrelDistortion()); BT.effectAdd(new Scanlines()); BT.effectAdd(new Bloom()); diff --git a/docs/bitmap-fonts.md b/docs/bitmap-fonts.md index 38f6894..a3eb26d 100644 --- a/docs/bitmap-fonts.md +++ b/docs/bitmap-fonts.md @@ -229,9 +229,9 @@ If you prefer to convert manually: 3. **Export with padding** between characters to prevent bleeding artifacts. -4. **Use white glyphs** on a transparent background – colors are applied at render time via tinting. +4. **Use white glyphs** on a transparent background - colors are applied at render time via tinting. -5. **Include common symbols** beyond ASCII: `×`, `÷`, `·`, `—`, `…`, etc. +5. **Include common symbols** beyond ASCII: `×`, `÷`, `·`, `-`, `…`, etc. ## API Reference diff --git a/docs/developer-experience-guide.md b/docs/developer-experience-guide.md index 2c3cf57..e794edd 100644 --- a/docs/developer-experience-guide.md +++ b/docs/developer-experience-guide.md @@ -143,7 +143,7 @@ AI-assisted commits add a trailer: `Co-Authored-By: Claude `) -vs RGBA paths — see [Writing a custom effect](#writing-a-custom-effect) below. +vs RGBA paths - see [Writing a custom effect](#writing-a-custom-effect) below. ### `HardwareSettings` @@ -160,7 +160,7 @@ custom `configure()` that omits output sizing. ## Pixel-tier effects -### `PixelGlitch` — chunky band shift +### `PixelGlitch` - chunky band shift Per-row horizontal glitch: every Nth row of source **palette indices** gets a random horizontal shift in index space (integer texel steps), so output stays on valid palette slots without RGB remapping. @@ -171,7 +171,7 @@ Per-row horizontal glitch: every Nth row of source **palette indices** gets a ra | `bandHeight` | `4` | Height of each glitch band in source pixels | | `seed` | `0` | Per-glitch seed; change between bursts to vary the band noise | -### `PixelMosaic` — block down-quantize +### `PixelMosaic` - block down-quantize Replaces each `blockSize x blockSize` group of source pixels with a single sample. Useful for transitions, dream sequences, and "low-res mode" effects. @@ -184,16 +184,16 @@ sequences, and "low-res mode" effects. ## Display-tier effects -### `BarrelDistortion` — pincushion curve +### `BarrelDistortion` - pincushion curve `warp(uv) = uv + delta * d2 * curvature`. Operates at output resolution so the curve has enough pixels to express -smoothly — no stepping artifacts on diagonals. +smoothly - no stepping artifacts on diagonals. | Field | Default | Purpose | | ----------- | ------- | ------------------------------------------------------------------- | | `curvature` | `0.05` | Curve strength. `0.02` flat panel, `0.05` desktop, `0.10` pocket TV | -### `Scanlines` — bright/dark horizontal bands +### `Scanlines` - bright/dark horizontal bands Gaussian-weighted scanline pattern matched to source pixel rows. @@ -203,7 +203,7 @@ Gaussian-weighted scanline pattern matched to source pixel rows. | `strength` | `-8` | Negative gaussian falloff; more negative = sharper bands | | `density` | `240` | Cycles per view (set to your logical vertical resolution) | -### `RGBMask` — CRT shadow mask +### `RGBMask` - CRT shadow mask R/G/B vertical-stripe pattern with darkened cell borders, simulating an aperture-grille CRT. @@ -213,7 +213,7 @@ R/G/B vertical-stripe pattern with darkened cell borders, simulating an aperture | `size` | `6` | Mask cell pitch in source pixels | | `border` | `0.5` | Border darkening within each cell | -### `Vignette` — edge darkening +### `Vignette` - edge darkening Smooth radial fade. `pow(edge.x * edge.y, amount)`. @@ -221,7 +221,7 @@ Smooth radial fade. `pow(edge.x * edge.y, amount)`. | -------- | ------- | ----------------------------------------------- | | `amount` | `0.35` | Darkening exponent. Higher = stronger / sharper | -### `ChromaticAberration` — RGB channel offset +### `ChromaticAberration` - RGB channel offset Red samples left of the fragment, blue samples right. Cheap CRT optics produce a tiny version of this naturally. @@ -229,7 +229,7 @@ Red samples left of the fragment, blue samples right. Cheap CRT optics produce a | ------------ | ------- | ------------------------------- | | `aberration` | `1.0` | Channel offset in source pixels | -### `Flicker` — brightness multiplier +### `Flicker` - brightness multiplier The simplest CRT animation knob. `color *= amount`. Demo drives it per-frame. @@ -237,7 +237,7 @@ The simplest CRT animation knob. `color *= amount`. Demo drives it per-frame. | -------- | ------- | ------------------------------------ | | `amount` | `1.0` | Brightness multiplier. 1 unmodulated | -### `RollLine` — scrolling interference band +### `RollLine` - scrolling interference band A horizontal bright stripe slowly scrolls down the screen. @@ -247,7 +247,7 @@ A horizontal bright stripe slowly scrolls down the screen. | `speed` | `1.0` | Scroll velocity multiplier | | `time` | `0` | Wall-clock seconds; demos drive this each frame | -### `Interference` — per-row analog jitter +### `Interference` - per-row analog jitter Each row gets a random horizontal offset reseeded each frame. @@ -256,7 +256,7 @@ Each row gets a random horizontal offset reseeded each frame. | `amount` | `0.06` | Maximum offset as a UV fraction | | `time` | `0` | Wall-clock seconds; reseeds each frame | -### `Noise` — additive pseudo-random noise +### `Noise` - additive pseudo-random noise Per-pixel film grain. Reseeds each frame from `time`. @@ -265,7 +265,7 @@ Per-pixel film grain. Reseeds each frame from `time`. | `amount` | `0.025` | Noise amplitude as `[-amount, +amount]` perturbation | | `time` | `0` | Wall-clock seconds | -### `Bloom` — soft phosphor glow +### `Bloom` - soft phosphor glow Single-pass 5x5 box blur (25 taps) mixed with the original color. @@ -292,7 +292,7 @@ Demos that want the full kitchen-sink effect should use this. ### `BT.preset.amber()` -Amber monochrome PC monitor (think IBM 5151 / Hercules). Currently ships as a parameter-only set — the actual amber tint +Amber monochrome PC monitor (think IBM 5151 / Hercules). Currently ships as a parameter-only set - the actual amber tint quantization will land with [VV-479](https://linear.app/vancura/issue/VV-479/monochrome-re-quantization-display-effect). ### `BT.preset.green()` @@ -358,9 +358,9 @@ Extend `FullscreenPixelEffect` for logical `r8uint` chains. Provide **both** `fr format is ever passed to `init`; keep it minimal). Implement `writeUniforms` like display-tier effects. - Integer clears use index `0`; treat palette slot `0` as transparent where appropriate. -- For data-dependent control flow that calls `textureSample`, switch to `textureSampleLevel(..., 0.0)` — WGSL forbids +- For data-dependent control flow that calls `textureSample`, switch to `textureSampleLevel(..., 0.0)` - WGSL forbids `textureSample` outside uniform control flow because of mip derivative requirements. -- Reuse the inherited `uniformData` `Float32Array` — never allocate per frame. +- Reuse the inherited `uniformData` `Float32Array` - never allocate per frame. --- @@ -396,7 +396,7 @@ codebase derive from the same shader. The glitch / flicker / roll-line / chromatic-aberration extensions and the uniform set the pre-decomposition `PipBoyEffect` replicated come from a community PipBoy fork written for p5.js's `createFilterShader`. The fork's source -URL and author are **unknown** to us at the time of writing, and **no license has been confirmed** — the only header it +URL and author are **unknown** to us at the time of writing, and **no license has been confirmed** - the only header it carried was a Fallout-themed "RobCo Industries (Unlicensed Wasteland Fork)" comment, which is character flavour rather than a license grant. Treat the upstream provenance as unverified; do not assume permissive rights for the borrowed extensions until the upstream source and license have been identified. diff --git a/docs/testing.md b/docs/testing.md index 844ee55..588cc9b 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -64,12 +64,12 @@ documented in [Performance Testing](performance-testing.md). Public types are rolled up during `pnpm build` via `vite-plugin-dts` and API Extractor. The workspace pins TypeScript to the same version API Extractor bundles (see `docs/developer-experience-guide.md`). -- **`pnpm test:declarations`** — Node test runner for `scripts/check-declaration-tooling.mjs` (drift patterns and +- **`pnpm test:declarations`** - Node test runner for `scripts/check-declaration-tooling.mjs` (drift patterns and alignment log parsing). Included in `pnpm preflight`. -- **CI** — after `pnpm build`, `node scripts/check-declaration-tooling.mjs build.log` runs in both +- **CI** - after `pnpm build`, `node scripts/check-declaration-tooling.mjs build.log` runs in both `.github/workflows/ci.yml` (build-library job) and `.github/workflows/pr-checks.yml` (bundle-size job) to fail on drift warnings and version mismatch. -- **Manual** — `pnpm build 2>&1 | tee build.log && node scripts/check-declaration-tooling.mjs build.log` +- **Manual** - `pnpm build 2>&1 | tee build.log && node scripts/check-declaration-tooling.mjs build.log` ## Commands diff --git a/docs/tooling.md b/docs/tooling.md index 511b6df..2decd71 100644 --- a/docs/tooling.md +++ b/docs/tooling.md @@ -23,7 +23,7 @@ CI details. CI runs the checker after `pnpm build` in: -- `.github/workflows/ci.yml` — `build-library` job -- `.github/workflows/pr-checks.yml` — `bundle-size` job +- `.github/workflows/ci.yml` - `build-library` job +- `.github/workflows/pr-checks.yml` - `bundle-size` job -More context: [Testing — Declaration tooling checks](testing.md#declaration-tooling-checks). +More context: [Testing - Declaration tooling checks](testing.md#declaration-tooling-checks). diff --git a/docs/voice.md b/docs/voice.md index 354ba4e..fed3888 100644 --- a/docs/voice.md +++ b/docs/voice.md @@ -12,7 +12,7 @@ read the relevant section below. ## Two Audience Tiers -### Tier 1 — User-facing (canvas-visible or public API errors) +### Tier 1 - User-facing (canvas-visible or public API errors) Audience: demo authors using the `BT` namespace, beginners who may not know TypeScript internals. @@ -30,14 +30,14 @@ Where it appears: `showBeginnerRuntimeError()`, `displayError()`, canvas banners API path (anything reachable from demo code via `BT.*` or a public constructor). All such messages must live in `src/utils/errorMessages.ts`. -### Tier 2 — Internal invariants (developer-only) +### Tier 2 - Internal invariants (developer-only) Audience: engine contributors reading a stack trace. Rules: - Terse. Include the relevant values. -- No need to explain next steps — the reader can read the source. +- No need to explain next steps - the reader can read the source. - Still no emoji. Where it appears: `throw new Error()` inside private engine methods, guard checks inside `src/core/`, `src/render/`, and @@ -68,7 +68,7 @@ non-public `src/assets/` paths. - Use `console.error` for failures, `console.warn` for degraded-but-continuing states. - Never use `console.log` in production code paths (benchmarks and debug utilities excepted). - Canvas-visible errors (`displayError`) and console output must say the same thing. Do not show a terse console message - and a friendly canvas message — they must match. + and a friendly canvas message - they must match. --- @@ -87,7 +87,7 @@ Steps when adding a new Tier 1 message: 2. Import and call it at the throw or display site. 3. Do not inline the string at the call site. -Tier 2 strings (internal invariants) may be inlined — they are never user-visible and do not need the same stability +Tier 2 strings (internal invariants) may be inlined - they are never user-visible and do not need the same stability guarantees. --- @@ -97,7 +97,7 @@ guarantees. 1. **Plain English?** Could a junior developer understand it without reading engine source? 2. **Next action?** Does it tell the reader what to do, not just what failed? 3. **No trailing period?** Thrown strings land mid-sentence in stack traces. -4. **No emoji?** Nowhere in the engine — not in throws, not in banners, not in console output. +4. **No emoji?** Nowhere in the engine - not in throws, not in banners, not in console output. 5. **Sentence case?** "Slot 0 is always transparent" not "Slot 0 Is Always Transparent". 6. **Centralized?** Is the string in `errorMessages.ts`, or must it go there? 7. **Tier correct?** Is this reachable from demo code? If yes, it must be Tier 1. diff --git a/src/BlitTech.ts b/src/BlitTech.ts index de24f12..2eef7dd 100644 --- a/src/BlitTech.ts +++ b/src/BlitTech.ts @@ -186,7 +186,7 @@ function executeDrawCall(methodName: string, callback: () => void): void { /** * Returns runtime keyboard `KeyboardEvent.code` list for a face button and player, - * or `null` when there is no keyboard fallback (e.g. players 2–3 for face buttons). + * or `null` when there is no keyboard fallback (e.g. players 2-3 for face buttons). * * @param button - Face button constant (`BT.BTN_UP` … `BT.BTN_SELECT`). * @param player - Zero-based player index. @@ -503,7 +503,7 @@ export const BT = { * Renderer backend that is currently active. * * `'webgpu'` or `'software'` after successful init; `null` before init or on failure. - * Useful when adjusting demo behavior — for example, skipping post-process effects + * Useful when adjusting demo behavior - for example, skipping post-process effects * that only work under WebGPU. * * @returns `'webgpu'` or `'software'` after successful init; `null` before init or on failure. @@ -531,7 +531,7 @@ export const BT = { * * **Palette-value swap (change what a slot looks like):** mutate the current * palette with `palette.set(slot, newColor)` and then call `paletteSet()`. The - * sprite sheets' stored indices are unchanged — no {@link BT.spritesRefresh} + * sprite sheets' stored indices are unchanged - no {@link BT.spritesRefresh} * needed. * * **Palette-layout swap (same colors, different slot positions):** build a new @@ -554,7 +554,7 @@ export const BT = { }, /** - * Active engine palette (live reference — not a copy). + * Active engine palette (live reference - not a copy). * * Mutating slots updates colors on the next frame without {@link BT.paletteSet}. * @@ -1428,7 +1428,7 @@ export const BT = { * **Out-of-range behavior:** No CPU-side validation is performed. `paletteOffset` is passed to * the GPU as a `u32`. If `storedIndex + paletteOffset` exceeds the last palette index, WebGPU's * robust buffer access returns 0 for every component; because the fragment shader forces alpha - * to 1.0, the affected pixels render as opaque black. Negative values are forbidden — a negative + * to 1.0, the affected pixels render as opaque black. Negative values are forbidden - a negative * JS number written into a `u32` vertex attribute wraps to a large unsigned integer, which also * produces out-of-bounds black pixels. * @@ -1455,7 +1455,7 @@ export const BT = { /** * Re-indexizes all tracked sprite sheets against the current active palette. * - * Only call this after a **palette-layout swap** — when the same colors have + * Only call this after a **palette-layout swap** - when the same colors have * moved to different slot positions and existing sprite indices now point to * the wrong slots. Each sheet re-runs exact RGBA-to-index matching against the * active palette via `SpriteSheet.reindexize()`. If any opaque pixel's original @@ -1465,7 +1465,7 @@ export const BT = { * * **Do not call this after a palette-value swap.** If you changed what color a * slot holds (e.g. palette animation, theme tinting), the stored indices are - * still correct — the fragment shader picks up the new color automatically. + * still correct - the fragment shader picks up the new color automatically. * Calling `spritesRefresh()` in that case is wasteful at best; at worst, if the * original RGBA values are gone from the palette, sheets with missing colors * will fail reindexing and be removed from the registry. diff --git a/src/__test__/webgpu-mock.ts b/src/__test__/webgpu-mock.ts index f109ac9..26a854d 100644 --- a/src/__test__/webgpu-mock.ts +++ b/src/__test__/webgpu-mock.ts @@ -140,7 +140,7 @@ export function createMockGPUCanvasContext(): GPUCanvasContext { /** * Creates a mock GPUBuffer matching the real 4096-byte palette uniform layout. - * Returns a plain object — does not call device.createBuffer. + * Returns a plain object - does not call device.createBuffer. * * @returns Mock GPUBuffer stub. */ diff --git a/src/assets/BitmapFont.ts b/src/assets/BitmapFont.ts index 36fa1bb..3474a4d 100644 --- a/src/assets/BitmapFont.ts +++ b/src/assets/BitmapFont.ts @@ -264,7 +264,7 @@ export class BitmapFont { const { data, glyphEntries } = BitmapFont.parseBtfontFile(url, await response.text()); - // Load texture – embedded `data:` URIs and relative PNG paths are both allowed. + // Load texture - embedded `data:` URIs and relative PNG paths are both allowed. const image = await BitmapFont.loadTexture(data.texture, url); const spriteSheet = new SpriteSheet(image); const atlasWidth = spriteSheet.width; @@ -648,7 +648,7 @@ export class BitmapFont { // eslint-disable-next-line security/detect-object-injection -- Index is bounds-checked above glyph = this.asciiGlyphs[code] ?? null; } else { - // Unicode fallback – index is guaranteed valid within loop bounds. + // Unicode fallback - index is guaranteed valid within loop bounds. // eslint-disable-next-line security/detect-object-injection -- Index is within loop bounds const char = text[i]; diff --git a/src/assets/Palette.test.ts b/src/assets/Palette.test.ts index eb1448c..0c5cdc1 100644 --- a/src/assets/Palette.test.ts +++ b/src/assets/Palette.test.ts @@ -59,7 +59,7 @@ describe('Palette', () => { expect(() => palette.set(-1, color)).toThrow('0 or higher'); }); - it('get() returns a defensive copy — mutating the result does not change the stored entry', () => { + it('get() returns a defensive copy - mutating the result does not change the stored entry', () => { const palette = new Palette(16); palette.set(3, new Color32(10, 20, 30, 255)); diff --git a/src/assets/Palette.ts b/src/assets/Palette.ts index 79f680c..a721bea 100644 --- a/src/assets/Palette.ts +++ b/src/assets/Palette.ts @@ -150,7 +150,7 @@ export class Palette { * * Set by {@link set} and {@link copyFrom}. Cleared by {@link clearDirty} after * the renderer has uploaded the updated palette uniform buffer. Not set by the - * constructor — initial upload is always triggered by {@link Renderer.setPalette}. + * constructor - initial upload is always triggered by {@link Renderer.setPalette}. */ private _dirty: boolean = false; @@ -312,12 +312,12 @@ export class Palette { * without hardcoding numbers. * * Default colors (matching common demo usage): - * - `hud_white` — `#ffffff` pure white - * - `hud_bg` — `#1e1428` dark purple background - * - `hud_label` — `#c8c8c8` medium gray labels - * - `hud_header` — `#ffdc64` golden header text - * - `hud_dim` — `#646464` dim gray (FPS, secondary info) - * - `hud_code` — `#6496c8` slate blue code snippets + * - `hud_white` - `#ffffff` pure white + * - `hud_bg` - `#1e1428` dark purple background + * - `hud_label` - `#c8c8c8` medium gray labels + * - `hud_header` - `#ffdc64` golden header text + * - `hud_dim` - `#646464` dim gray (FPS, secondary info) + * - `hud_code` - `#6496c8` slate blue code snippets * * @param startSlot - First palette index to write. Must be a positive integer >= 1 * and leave room for all six entries within the palette size. Defaults to `1`. @@ -507,7 +507,7 @@ export class Palette { * * The renderer checks this flag each frame and re-uploads the palette uniform * buffer when it is set, then calls {@link clearDirty} to reset it. Palette - * animation works automatically — no per-frame {@link BT.paletteSet} required. + * animation works automatically - no per-frame {@link BT.paletteSet} required. * * @returns `true` if any color has been written via {@link set} or {@link copyFrom} * since the last call to {@link clearDirty}. diff --git a/src/assets/SpriteSheet.test.ts b/src/assets/SpriteSheet.test.ts index 88af14d..b1f8ea7 100644 --- a/src/assets/SpriteSheet.test.ts +++ b/src/assets/SpriteSheet.test.ts @@ -198,7 +198,7 @@ describe('SpriteSheet', () => { }); it('maps transparent pixels (alpha=0) to palette index 0', () => { - // All pixels fully transparent — expect no throws and all indices to be 0. + // All pixels fully transparent - expect no throws and all indices to be 0. const palette = new Palette(16); const sheet = new SpriteSheet({ width: 2, height: 2 } as HTMLImageElement); @@ -226,7 +226,7 @@ describe('SpriteSheet', () => { it('throws when an opaque pixel color is not in the palette', () => { const w = 1; const h = 1; - // Solid red pixel — not in an empty palette. + // Solid red pixel - not in an empty palette. const pixels = new Uint8ClampedArray([200, 100, 50, 255]); vi.stubGlobal('OffscreenCanvas', makeOffscreenCanvasMock(pixels, w, h)); @@ -260,7 +260,7 @@ describe('SpriteSheet', () => { sheet.indexize(palette); const first = sheet.getTexture(device); - // Call indexize again — should destroy the existing texture. + // Call indexize again - should destroy the existing texture. sheet.indexize(palette); const second = sheet.getTexture(device); @@ -488,7 +488,7 @@ describe('SpriteSheet', () => { }); it('forces alpha to 255 even when source alpha is partial', async () => { - // Source has alpha=128 — should be stored as 255 to match indexize() lookup. + // Source has alpha=128 - should be stored as 255 to match indexize() lookup. const pixels = new Uint8ClampedArray([200, 100, 50, 128]); stubLoad(pixels, 1, 1); diff --git a/src/assets/SpriteSheet.ts b/src/assets/SpriteSheet.ts index ed2fb54..ce1a108 100644 --- a/src/assets/SpriteSheet.ts +++ b/src/assets/SpriteSheet.ts @@ -157,7 +157,7 @@ export class SpriteSheet { * Walks a PNG's pixels and registers every unique opaque color into the * supplied palette starting at `startSlot`. * - * Pixels with alpha 0 are skipped — they map to the engine's transparent + * Pixels with alpha 0 are skipped - they map to the engine's transparent * sentinel slot 0 at draw time. Opaque pixels are deduplicated on RGB and * stored with alpha forced to 255, matching the lookup performed by * `indexize()` so a subsequent `sheet.indexize(palette)` call resolves @@ -266,7 +266,7 @@ export class SpriteSheet { /** * Creates a sprite sheet from pre-computed palette-indexed pixel data. * - * The resulting sheet is immediately indexized -- its `getTexture()` call + * The resulting sheet is immediately indexized - its `getTexture()` call * will produce an `r8uint` GPU texture without needing `indexize()`. This * is used for embedded assets like the built-in system font where the pixel * data is already expressed as palette indices. @@ -332,7 +332,7 @@ export class SpriteSheet { const a = rgba[base + 3]; if (a === 0) { - // Index 0 is the transparent sentinel — the shader discards any pixel with rawIndex == 0. + // Index 0 is the transparent sentinel - the shader discards any pixel with rawIndex == 0. // eslint-disable-next-line security/detect-object-injection indexed[i] = 0; continue; @@ -373,14 +373,14 @@ export class SpriteSheet { /** * Re-converts retained RGBA pixels to palette indices using a new palette. * - * Use this only when the **slot layout** of the palette has changed — that is, + * Use this only when the **slot layout** of the palette has changed - that is, * when the same colors now live at different index positions. It works by * replaying the original RGBA data through `palette.findColor()` and assigning * each opaque pixel the index of its matching color in the new palette. * * **Do not call this to change what color a slot displays.** If you only want * to swap the visible color at a slot (e.g. animate a fire effect), mutate the - * palette entry directly — the stored indices remain valid and the fragment + * palette entry directly - the stored indices remain valid and the fragment * shader picks up the new color automatically on the next frame: * * ```ts @@ -430,7 +430,7 @@ export class SpriteSheet { const a = rgba[base + 3]; if (a === 0) { - // Index 0 is the transparent sentinel — the shader discards any pixel with rawIndex == 0. + // Index 0 is the transparent sentinel - the shader discards any pixel with rawIndex == 0. // eslint-disable-next-line security/detect-object-injection indexed[i] = 0; continue; diff --git a/src/assets/SystemFont.ts b/src/assets/SystemFont.ts index 87a1d3a..0389ec8 100644 --- a/src/assets/SystemFont.ts +++ b/src/assets/SystemFont.ts @@ -3,7 +3,7 @@ * * Expands the embedded glyph bitmaps from {@link systemFontData} into a * palette-indexed texture atlas and wraps the result in a {@link BitmapFont}. - * The font is fully synchronous to create -- no `fetch()`, no image decode. + * The font is fully synchronous to create - no `fetch()`, no image decode. * * The glyph data lives in `src/assets/fonts/systemFontData.ts`. To edit it * visually, export the current bitmaps to a PNG, redraw in a pixel editor, diff --git a/src/core/BTAPI.test.ts b/src/core/BTAPI.test.ts index e41e4bb..13ad988 100644 --- a/src/core/BTAPI.test.ts +++ b/src/core/BTAPI.test.ts @@ -36,7 +36,7 @@ import type { IBlitTechDemo } from './IBlitTechDemo'; // #region Helpers function resetSingleton(): void { - // BTAPI._instance is private; the cast is intentional — there is no public + // BTAPI._instance is private; the cast is intentional - there is no public // reset API, and this is the least-invasive way to isolate singleton state // between tests without modifying production code. (BTAPI as unknown as { _instance: BTAPI | null })._instance = null; diff --git a/src/core/BTAPI.ts b/src/core/BTAPI.ts index e95f0ca..924b05c 100644 --- a/src/core/BTAPI.ts +++ b/src/core/BTAPI.ts @@ -552,7 +552,7 @@ export class BTAPI { public drawSystemText(pos: Vector2i, paletteIndex: number, text: string): void { this.assertPaletteIndex(paletteIndex); - // Palette index 0 is transparent -- nothing to draw. + // Palette index 0 is transparent - nothing to draw. if (paletteIndex === 0) { return; } @@ -855,7 +855,7 @@ export class BTAPI { // #endregion - // #region Private — Initialization Helpers + // #region Private - Initialization Helpers /** * Constructs and initializes the renderer for the active hardware settings. diff --git a/src/core/GameLoop.test.ts b/src/core/GameLoop.test.ts index 9a3a5eb..9090cb1 100644 --- a/src/core/GameLoop.test.ts +++ b/src/core/GameLoop.test.ts @@ -144,7 +144,7 @@ describe('GameLoop', () => { // Execute outer RAF callback. rafCallbacks[0]?.(); - // Execute inner RAF callback — sets lastUpdateTime and schedules first tick. + // Execute inner RAF callback - sets lastUpdateTime and schedules first tick. rafCallbacks[1]?.(); expect(p.lastUpdateTime).toBeGreaterThan(0); @@ -204,7 +204,7 @@ describe('GameLoop', () => { p.isRunning = true; p.lastUpdateTime = 0; - p.tick(10000); // huge pause — MAX_STEPS = 8 caps at 8 updates + p.tick(10000); // huge pause - MAX_STEPS = 8 caps at 8 updates expect(onUpdate).toHaveBeenCalledTimes(8); }); diff --git a/src/core/IBlitTechDemo.ts b/src/core/IBlitTechDemo.ts index 0ac4889..c00ab60 100644 --- a/src/core/IBlitTechDemo.ts +++ b/src/core/IBlitTechDemo.ts @@ -88,8 +88,8 @@ export interface HardwareSettings { * stutters during development. Defaults to `false`. * * Detection runs in `GameLoop.detectFrameDrop()` and uses an - * auto-calibrated baseline -- the shortest `requestAnimationFrame` delta - * observed in a rolling window of recent frames -- rather than a fixed + * auto-calibrated baseline - the shortest `requestAnimationFrame` delta + * observed in a rolling window of recent frames - rather than a fixed * `1.5 / targetFPS` threshold. A frame is reported as dropped when its * rAF delta exceeds 1.5x that baseline, which makes detection work on * any display refresh rate (60 / 120 / 144 Hz, etc.) and on browsers diff --git a/src/core/WebGPUContext.test.ts b/src/core/WebGPUContext.test.ts index 1358c78..e76d8aa 100644 --- a/src/core/WebGPUContext.test.ts +++ b/src/core/WebGPUContext.test.ts @@ -45,7 +45,7 @@ describe('initWebGPU', () => { // #region No WebGPU support it('should return null when navigator.gpu is absent', async () => { - // Use Object.defineProperty to install a navigator without .gpu — direct + // Use Object.defineProperty to install a navigator without .gpu - direct // property deletion throws in Node.js when navigator is null/non-writable. Object.defineProperty(globalThis, 'navigator', { value: { userAgent: 'test' }, diff --git a/src/core/WebGPUContext.ts b/src/core/WebGPUContext.ts index 616ffcd..6c486e4 100644 --- a/src/core/WebGPUContext.ts +++ b/src/core/WebGPUContext.ts @@ -28,7 +28,7 @@ export interface WebGPUContextResult { * The WebGPU drawing buffer is sized to `canvasDisplaySize` when provided so * the engine can run display-tier post-processing (CRT scanlines, barrel * distortion, etc.) at output resolution. The CSS size of the canvas matches - * the drawing-buffer size — when the demo wants different on-screen and + * the drawing-buffer size - when the demo wants different on-screen and * GPU-internal sizes it must apply CSS itself after init. * * When `canvasDisplaySize` is omitted, the drawing buffer matches the logical diff --git a/src/input/KeyboardInput.ts b/src/input/KeyboardInput.ts index da03db9..2cb315d 100644 --- a/src/input/KeyboardInput.ts +++ b/src/input/KeyboardInput.ts @@ -347,7 +347,7 @@ export class KeyboardInput { for (let i = 0; i < data.length; i++) { const cp = data.charCodeAt(i); - // Printable ASCII 32–127, plus Tab (9) and ESC (27) when present as text. + // Printable ASCII 32-127, plus Tab (9) and ESC (27) when present as text. if ((cp >= 32 && cp <= 127) || cp === 9 || cp === 27) { this.inputBuffer += String.fromCharCode(cp); } diff --git a/src/render/PrimitivePipeline.ts b/src/render/PrimitivePipeline.ts index 582db04..4b5530c 100644 --- a/src/render/PrimitivePipeline.ts +++ b/src/render/PrimitivePipeline.ts @@ -580,7 +580,7 @@ export class PrimitivePipeline { /** * Records the current vertex batch and resets the vertex count. * Used for early flush when the buffer is full mid-frame. - * Does not write to GPU -- encodePass() uploads all batches at once. + * Does not write to GPU - encodePass() uploads all batches at once. */ private earlyFlush(): void { if (this.vertexCount === 0) { diff --git a/src/render/SoftwareRenderer.ts b/src/render/SoftwareRenderer.ts index 3175f5d..7987877 100644 --- a/src/render/SoftwareRenderer.ts +++ b/src/render/SoftwareRenderer.ts @@ -408,7 +408,7 @@ export class SoftwareRenderer implements IRenderer { // #region Effects /** - * Not supported — always throws. + * Not supported - always throws. * * @param _effect - Ignored. */ @@ -417,7 +417,7 @@ export class SoftwareRenderer implements IRenderer { } /** - * Not supported — always throws. + * Not supported - always throws. * * @param _effect - Ignored. */ @@ -425,7 +425,7 @@ export class SoftwareRenderer implements IRenderer { throw new Error(SoftwareRenderer.EFFECTS_UNSUPPORTED_MESSAGE); } - /** Not supported — always throws. */ + /** Not supported - always throws. */ clearEffects(): void { throw new Error(SoftwareRenderer.EFFECTS_UNSUPPORTED_MESSAGE); } @@ -797,7 +797,7 @@ export class SoftwareRenderer implements IRenderer { if (typeof this.canvas.toBlob !== 'function') { this.pendingCapture.reject( new Error( - "Can't save this frame — your browser doesn't support canvas image export. Try Chrome or Edge.", + "Can't save this frame - your browser doesn't support canvas image export. Try Chrome or Edge.", ), ); this.pendingCapture = null; @@ -810,7 +810,7 @@ export class SoftwareRenderer implements IRenderer { if (!blob) { request.reject( new Error( - "Can't save this frame — something went wrong exporting the canvas image. Try again on the next frame.", + "Can't save this frame - something went wrong exporting the canvas image. Try again on the next frame.", ), ); return; diff --git a/src/render/SpritePipeline.ts b/src/render/SpritePipeline.ts index 03d3e05..9e43c6c 100644 --- a/src/render/SpritePipeline.ts +++ b/src/render/SpritePipeline.ts @@ -58,10 +58,10 @@ export class SpritePipeline { /** Backing buffer for all vertex data. */ private readonly vertexArrayBuffer: ArrayBuffer; - /** Float32 view over vertexArrayBuffer — for x, y, u, v (indices i*5+0..+3). */ + /** Float32 view over vertexArrayBuffer - for x, y, u, v (indices i*5+0..+3). */ private readonly vertexFloats: Float32Array; - /** Uint32 view over vertexArrayBuffer — for paletteOffset (index i*5+4). */ + /** Uint32 view over vertexArrayBuffer - for paletteOffset (index i*5+4). */ private readonly vertexUints: Uint32Array; /** Number of vertices in the current (unflushed) batch. */ @@ -368,7 +368,7 @@ export class SpritePipeline { usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, }); - // Shared bind group (group 0): uniforms + palette — created once and reused for all textures. + // Shared bind group (group 0): uniforms + palette - created once and reused for all textures. this.sharedBindGroup = device.createBindGroup({ label: 'Sprite Shared Bind Group', layout: (this.pipeline as GPURenderPipeline).getBindGroupLayout(0), @@ -424,7 +424,7 @@ export class SpritePipeline { this.flushCurrentBatch(); } - // Check again after flush — if still no space, the buffer is full for this frame. + // Check again after flush - if still no space, the buffer is full for this frame. if (!this.hasSpaceForQuad()) { console.warn('[SpritePipeline] Sprite buffer capacity exceeded for this frame, quad dropped'); diff --git a/src/render/UpscalePass.ts b/src/render/UpscalePass.ts index 1f11a4d..1e02e89 100644 --- a/src/render/UpscalePass.ts +++ b/src/render/UpscalePass.ts @@ -153,7 +153,7 @@ export class UpscalePass { // #endregion - // #region Helpers — texture allocation + // #region Helpers - texture allocation /** * Allocates a texture for the upscale pass output at the supplied size and diff --git a/src/render/WebGpuRenderer.test.ts b/src/render/WebGpuRenderer.test.ts index 476cf4b..53f0f9b 100644 --- a/src/render/WebGpuRenderer.test.ts +++ b/src/render/WebGpuRenderer.test.ts @@ -407,7 +407,7 @@ describe('with initialized renderer', () => { it('drawBitmapText delegates without throwing', () => { renderer.beginFrame(); - // Empty text — loop does not execute so glyph methods are never called. + // Empty text - loop does not execute so glyph methods are never called. const mockFont = { getSpriteSheet: () => ({}), getGlyphByCode: () => null, @@ -433,7 +433,7 @@ describe('resolveClearColor fallbacks', () => { await r.init(); - // No setPalette() call — endFrame() resolves clear color to black via fallback. + // No setPalette() call - endFrame() resolves clear color to black via fallback. expect(() => r.endFrame()).not.toThrow(); uninstallMockNavigatorGPU(); @@ -742,7 +742,7 @@ describe('palette dirty-flag auto-propagation', () => { renderer.setPalette(palette); - // Mutate the original after setPalette — the renderer must see the change. + // Mutate the original after setPalette - the renderer must see the change. palette.set(1, new Color32(99, 99, 99, 255)); // getPalette() returns a clone, so compare by value rather than reference. @@ -805,7 +805,7 @@ describe('palette dirty-flag auto-propagation', () => { renderer.setPalette(palette); - // First frame — initial upload due to paletteDirty. + // First frame - initial upload due to paletteDirty. renderer.beginFrame(); renderer.endFrame(); @@ -814,7 +814,7 @@ describe('palette dirty-flag auto-propagation', () => { // Mutate palette without calling BT.paletteSet() again. palette.set(1, new Color32(255, 0, 128, 255)); - // Second frame — must re-upload because palette.dirty is true. + // Second frame - must re-upload because palette.dirty is true. renderer.beginFrame(); renderer.endFrame(); @@ -839,13 +839,13 @@ describe('palette dirty-flag auto-propagation', () => { renderer.setPalette(palette); - // First frame — initial upload. + // First frame - initial upload. renderer.beginFrame(); renderer.endFrame(); const callsAfterFirstFrame = writeBufferSpy.mock.calls.length; - // No mutation — second frame should NOT upload. + // No mutation - second frame should NOT upload. renderer.beginFrame(); renderer.endFrame(); diff --git a/src/render/WebGpuRenderer.ts b/src/render/WebGpuRenderer.ts index 6f75627..432f8f3 100644 --- a/src/render/WebGpuRenderer.ts +++ b/src/render/WebGpuRenderer.ts @@ -247,7 +247,7 @@ export class WebGpuRenderer implements IRenderer { /** * Sets the active palette used for rendering. * - * Stores a reference to the supplied palette — no clone is made. Subsequent + * Stores a reference to the supplied palette - no clone is made. Subsequent * calls to {@link Palette.set} or {@link Palette.copyFrom} on the same object * will be detected via {@link Palette.dirty} and uploaded automatically at the * start of the next frame. {@link paletteDirty} is set to guarantee the initial @@ -272,7 +272,7 @@ export class WebGpuRenderer implements IRenderer { * Returns a clone to prevent callers from accidentally mutating the active * palette through the returned reference in ways that may be surprising. * To intentionally update palette colors, mutate the original palette object - * that was passed to {@link setPalette} — changes will auto-propagate via the + * that was passed to {@link setPalette} - changes will auto-propagate via the * dirty flag on the next frame. * * @returns Clone of the active palette instance, or null. @@ -547,7 +547,7 @@ export class WebGpuRenderer implements IRenderer { // #endregion - // #region Private — frame encoding + // #region Private - frame encoding /** * Tries to acquire the swap-chain texture and validate its dimensions. @@ -746,7 +746,7 @@ export class WebGpuRenderer implements IRenderer { // #endregion - // #region Private — drawing + // #region Private - drawing /** * Fast-path pixel draw using raw integer coordinates. diff --git a/src/render/effects/FullscreenEffect.ts b/src/render/effects/FullscreenEffect.ts index b6b642a..62f7752 100644 --- a/src/render/effects/FullscreenEffect.ts +++ b/src/render/effects/FullscreenEffect.ts @@ -34,7 +34,7 @@ export abstract class FullscreenEffect implements Effect { abstract readonly tier: EffectTier; /** - * Sampler filter mode. Defaults to `'linear'` (smooth — appropriate for + * Sampler filter mode. Defaults to `'linear'` (smooth - appropriate for * display-tier effects). Pixel-tier effects can override to `'nearest'` to * preserve palette colors during sampling. */ diff --git a/src/render/effects/display/Flicker.ts b/src/render/effects/display/Flicker.ts index 21f6a14..394ee90 100644 --- a/src/render/effects/display/Flicker.ts +++ b/src/render/effects/display/Flicker.ts @@ -2,7 +2,7 @@ import type { Vector2i } from '../../../utils/Vector2i'; import { FullscreenEffect } from '../FullscreenEffect'; /** - * Brightness multiplier — the simplest CRT animation knob. + * Brightness multiplier - the simplest CRT animation knob. * * Demos drive {@link amount} per frame to simulate flicker (e.g. with * `0.95 + sin(t) * 0.05`). The effect is intentionally trivial so the demo diff --git a/src/render/effects/presets/amber.ts b/src/render/effects/presets/amber.ts index 8a72961..83df677 100644 --- a/src/render/effects/presets/amber.ts +++ b/src/render/effects/presets/amber.ts @@ -9,7 +9,7 @@ import type { Effect } from '../Effect'; /** * Amber monochrome PC monitor look (think IBM 5151 / Hercules). * - * Ships as a parameter-only set — the underlying colors stay full-RGB until + * Ships as a parameter-only set - the underlying colors stay full-RGB until * the {@link MonochromeQuantize} effect lands (tracked in * [VV-479](https://linear.app/vancura/issue/VV-479/monochrome-re-quantization-display-effect)). * For now this preset gives you the *feel* (CRT curvature + scanlines + diff --git a/src/render/effects/presets/green.ts b/src/render/effects/presets/green.ts index 8f1ecd2..9d2df30 100644 --- a/src/render/effects/presets/green.ts +++ b/src/render/effects/presets/green.ts @@ -9,7 +9,7 @@ import type { Effect } from '../Effect'; /** * Green monochrome PC monitor look (think original IBM monochrome / VT100). * - * Ships as a parameter-only set — see the {@link amber} preset for the + * Ships as a parameter-only set - see the {@link amber} preset for the * caveat about re-quantization (VV-479). Same effect stack as `amber()`, * tuned slightly toward a cooler / more flickery aesthetic. * diff --git a/src/utils/Bootstrap.test.ts b/src/utils/Bootstrap.test.ts index 2935afe..fd7077f 100644 --- a/src/utils/Bootstrap.test.ts +++ b/src/utils/Bootstrap.test.ts @@ -133,7 +133,7 @@ describe('bootstrap', () => { describe('canvas validation', () => { it('should return false and call onError when canvas is not found', async () => { - // No canvas in DOM — only the container. + // No canvas in DOM - only the container. const container = document.createElement('div'); container.id = DEFAULT_CONTAINER_ID; diff --git a/src/utils/Color32.ts b/src/utils/Color32.ts index d67f185..e4dc769 100644 --- a/src/utils/Color32.ts +++ b/src/utils/Color32.ts @@ -101,7 +101,7 @@ export class Color32 { /** * Pure white color (255, 255, 255, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared white Color32 instance. */ static get white(): Color32 { @@ -110,7 +110,7 @@ export class Color32 { /** * Pure black color (0, 0, 0, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared black Color32 instance. */ static get black(): Color32 { @@ -119,7 +119,7 @@ export class Color32 { /** * Fully transparent color (0, 0, 0, 0). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared transparent Color32 instance. */ static get transparent(): Color32 { @@ -128,7 +128,7 @@ export class Color32 { /** * Pure red color (255, 0, 0, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared red Color32 instance. */ static get red(): Color32 { @@ -137,7 +137,7 @@ export class Color32 { /** * Pure green color (0, 255, 0, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared green Color32 instance. */ static get green(): Color32 { @@ -146,7 +146,7 @@ export class Color32 { /** * Pure blue color (0, 0, 255, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared blue Color32 instance. */ static get blue(): Color32 { @@ -155,7 +155,7 @@ export class Color32 { /** * Yellow color (255, 255, 0, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared yellow Color32 instance. */ static get yellow(): Color32 { @@ -164,7 +164,7 @@ export class Color32 { /** * Cyan color (0, 255, 255, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared cyan Color32 instance. */ static get cyan(): Color32 { @@ -173,7 +173,7 @@ export class Color32 { /** * Magenta color (255, 0, 255, 255). - * Cached frozen singleton — do not modify. + * Cached frozen singleton - do not modify. * @returns The shared magenta Color32 instance. */ static get magenta(): Color32 { diff --git a/src/utils/FrameCapture.test.ts b/src/utils/FrameCapture.test.ts index 722c366..6858eb6 100644 --- a/src/utils/FrameCapture.test.ts +++ b/src/utils/FrameCapture.test.ts @@ -153,7 +153,7 @@ describe('FrameCapture', () => { it('should set a pending flag after requestCapture', () => { const capture = new FrameCapture(); - // Don't await -- just queue the request. + // Don't await - just queue the request. void capture.requestCapture(); expect(capture.hasPendingCapture()).toBe(true); diff --git a/src/utils/Vector2i.ts b/src/utils/Vector2i.ts index 41bc8f3..4904b43 100644 --- a/src/utils/Vector2i.ts +++ b/src/utils/Vector2i.ts @@ -112,7 +112,7 @@ export class Vector2i { } /** - * Returns an up direction vector (0, –1). + * Returns an up direction vector (0, -1). * In screen coordinates, Y increases downward, so up is negative. * Returns a cached frozen singleton - do not modify. * @@ -173,7 +173,7 @@ export class Vector2i { * Creates an integer vector from floating-point coordinates. * Both values are truncated to integers using |0. * - * Note: |0 truncates toward zero (e.g., –1.7 becomes –1, not –2). + * Note: |0 truncates toward zero (e.g., -1.7 becomes -1, not -2). * * @param x - Floating-point x coordinate. * @param y - Floating-point y coordinate. diff --git a/src/utils/errorMessages.ts b/src/utils/errorMessages.ts index fd9ed4a..7eb441d 100644 --- a/src/utils/errorMessages.ts +++ b/src/utils/errorMessages.ts @@ -44,7 +44,7 @@ export const WEBGPU_ADAPTER_MESSAGE = export const WEBGPU_DEVICE_MESSAGE = "Couldn't connect to the graphics card. Try closing other tabs or restarting the browser."; -// #region Runtime — Render configuration +// #region Runtime - Render configuration /** * Returns the error message for a render dimension that is not a positive whole-number pixel size. @@ -104,7 +104,7 @@ export function renderDimensionGpuLimitError(field: string, size: string, maxTex // #endregion -// #region Runtime — Assets +// #region Runtime - Assets /** * Returns the error message for an asset whose width or height is not a positive whole number. @@ -370,7 +370,7 @@ export function btfontGlyphAreaTooLargeError(charLabel: string): string { // #endregion -// #region Runtime — Palette +// #region Runtime - Palette /** * Returns the "no active palette" error message used whenever a palette must @@ -431,7 +431,7 @@ export function hudRangeError(startSlot: number, count: number, size: number): s // #endregion -// #region Runtime — Sprites +// #region Runtime - Sprites /** * Returns the error message for a sprite pixel whose color is absent from the diff --git a/tests/visual/fixtures/post-process.html b/tests/visual/fixtures/post-process.html index a80ae51..585c805 100644 --- a/tests/visual/fixtures/post-process.html +++ b/tests/visual/fixtures/post-process.html @@ -37,7 +37,7 @@ // many snapshot variants. const mode = (window.location.hash || '#baseline').replace('#', ''); - // Modes that need a display-tier output buffer — anything testing a + // Modes that need a display-tier output buffer - anything testing a // display effect or the upscale pass needs canvasDisplaySize set. const NEEDS_DISPLAY = new Set([ 'barrel', -- 2.51.2