Pixel Knights

A garrisoned pixel island in your sidebar - a keep, a village, and the knights
who hold them - wired up as a readout of your error diagnostics. Break the build
and raiders land on the shore. Fix the errors and the garrison cuts them down.
The whole thing is one canvas in a webview - no accounts, no telemetry, nothing
leaves your machine.

Features
- A terraced island drawn from the Tiny Swords tileset - keep on top, barracks and watchtower below, village on the ground floor
- Grass stairs cut into each cliff, on opposite sides, so the levels read as a switchback
- Raids driven by your errors - one red raider per error, capped at three, fought off by the knight, the lancer and the tower archers
- Layout is computed from the pane, so the scene re-composes when you resize the sidebar instead of clipping
- Two faction colours, swapped live from settings - knight, garrison and buildings all change together
- Status bar entry opens the view, and
Pixel Knights: Focus Companion View does the same from the command palette
Install
Search Pixel Knights in the Extensions view, or:
code --install-extension nauqh.pixel-knights
How the island reacts
The host publishes one thing to the renderer: the current count of error
diagnostics. Everything below is the renderer's reading of that number, so the
island responds to whatever produces your errors - a language server, a linter,
a compile task - and not to any particular editor event.
| Error count |
What happens |
| Rises above zero |
A raider wades in from the right shore for each error, capped at three, and forms a beachhead |
| Stays above zero |
The knight marches to meet them and cycles two swings and a guard; the lancer walks the switchback down from the keep and thrusts from the second rank; the tower archers put arrows on the beach; the villagers clear out |
| Falls |
The raider nearest the fight dies in a puff of dust |
| Reaches zero |
The raid ends and the lancer walks back up to his post |
Diagnostics are debounced by 300ms, and an unchanged count is dropped rather
than posted, so a busy language server does not wake the render loop.
How much of the garrison turns out depends on the pane. The lancer needs a keep
terrace wide enough to hold a sentry post, and a narrow sidebar gets a watchtower
on the high ground instead of the castle, so at the smallest widths the knight
meets the beachhead alone.
Nothing is remembered between sessions yet - see plan.md.
The island
Tiny Swords is authored at 1x on a 64px world grid, which is far too big for a
sidebar, so the scene is not just CSS-scaled down. Two rules hold the pixels
straight:
- One resample, ever. Each sheet is drawn once into an offscreen canvas at
half size with smoothing off. Every runtime blit then reads from that cache
1:1. When the pane is wide enough to earn it, the whole viewport is upscaled
by an integer factor - never a fraction.
- Integer destinations. No sprite ever lands on a half pixel, so nothing
shimmers as it moves.
Units are not normalised to a common body height - they are stood on the ground
contact point baked into each sprite's own shadow, which is why the Lancer
(mostly spear) comes out the right size next to the Warrior. Draw order is a
painter's sort on that same contact point.
The terrain is assembled from the pack's tilemap rather than pre-cut images: a
nine-slice for the shoreline, another for each plateau, and a stone wall row
that stands on grass. The stairs are the pack's diagonal grass ramp, two tiles
tall, and each level's edge steps down a row where the ramp meets it - without
that step the ramp reads as a mound rather than a descent.
Configuration
| Setting |
Default |
Does |
pixelKnight.colour |
colour1 |
Faction palette. colour1 is blue, colour2 black. Applies to the knight, the garrison and every building at once. Raiders stay red either way |
Colour changes are pushed to the open view immediately - no reload.
Development
npm install
npm run build
Then press F5. That launches an Extension Development Host with Pixel Knights
loaded; open it from the activity bar or from the status bar. npm run package
builds a .vsix you can install locally with code --install-extension.
src/extension.ts activation, diagnostics hook, webview host, asset manifest
media/companion.js the entire renderer: layout, tilemap, animation, sprites
media/tiny-swords/ the vendored asset pack
docs/plan.md where this is going
npm run watch rebuilds src/ on save. The renderer is plain browser
JavaScript with no build step of its own, so editing media/companion.js only
needs a reload of the Extension Development Host.
One thing has to agree across the boundary: the sprite keys in COLOUR_FILES
and SCENE_FILES in src/extension.ts, which build the URI manifest, must
match the keys the renderer looks up in the SPR and NATIVE tables in
media/companion.js. Adding a sprite means touching both.
Adding a sprite from an excluded part of the pack also means loosening
.vscodeignore, which trims the unreferenced factions out of the .vsix.
Credits
All artwork is from the
Tiny Swords pack by
Pixel Frog, used under its license
terms. The code is MIT; the artwork is not - see LICENSE and
THIRD_PARTY_NOTICES.md. Purchase
the pack from Pixel Frog.