7.5 KiB
TrapMap Managed PNG Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Remove TrapMap's platform-specific drawing dependency and produce the same bounded 300 DPI PNG with a managed encoder that runs inside Clumsy.
Architecture: Keep TrapMapImageExporter.ExportIfEnabled and its file-reservation/publication behavior. Replace only the renderer with an internal RGBA raster surface, primitive drawing functions, a compact embedded bitmap font, and StbImageWriteSharp for PNG encoding; insert the 300 DPI pHYs chunk after encoding.
Tech Stack: C# 10, .NET Standard 2.0, StbImageWriteSharp 1.16.7, PowerShell contract/PNG parsing tests.
Global Constraints
- Do not inspect or modify
TrajPlanner. - Do not commit or stage any file.
- Do not change grid construction, Painter behavior, movement behavior, switches, output location, naming, 300 DPI, 4 pixels per cell, 4000-pixel edge limit, or 50 MiB limit.
- The only new image package is
StbImageWriteSharpversion 1.16.7; do not add native assets or another graphics package. TrapMapImageExportermust have no runtime reference toSystem.Drawing.CommonorSystem.Drawing.- Preserve collision-safe temporary-file reservation, encoded-size validation, atomic publication, and contained export failures.
Task 1: Replace System.Drawing rendering with a managed Stb PNG encoder
Files:
- Modify:
ClumsyPilot/ClumsyPilot.csproj - Modify:
ClumsyPilot/TrapMapImageExporter.cs - Modify:
ClumsyPilot/tests/verify_trapmap_image.ps1 - Modify:
docs/superpowers/specs/2026-07-22-trap-map-image-and-console-design.md - Modify:
docs/superpowers/plans/2026-07-22-trap-map-image-and-console.md
Interfaces:
-
Preserve:
TrapMapImageExporter.ExportIfEnabled(bool, TrapMapImageExportRequest)and all public request/result properties and constants. -
Add only private implementation units:
RgbaSurface, integer drawing helpers, bitmap-font helpers, andPngWriter. -
RenderToTemporaryPngcontinues to consume the existing request/dimensions and write to the already exclusively reserved stream. -
Step 1: Add dependency-removal and PNG-structure assertions
Update verify_trapmap_image.ps1 before production code. Require that:
if ($project.PackageReference.Include -contains 'System.Drawing.Common') {
throw 'TrapMap must not depend on System.Drawing.Common.'
}
if ($project.Target.Name -contains 'DeployFrameworkDrawingRuntime') {
throw 'Legacy drawing-runtime deployment target remains.'
}
if (-not ($project.PackageReference | Where-Object {
$_.Include -eq 'StbImageWriteSharp' -and $_.Version -eq '1.16.7'
})) { throw 'Exact managed PNG package is missing.' }
if ($exporterSource -match 'System\.Drawing|\bBitmap\b|\bGraphics\b|ImageFormat') {
throw 'Exporter still uses the external drawing API.'
}
Parse the generated PNG without loading a drawing assembly. Verify signature, one IHDR, one pHYs, one or more IDAT, and IEND; verify every chunk CRC. Assert IHDR width/height and RGBA8 fields and pHYs values 11811,11811,1. Decode representative pixels with a test-only PNG decoder or the Stb package and reuse the existing color/Y-inversion assertions.
Add a clean-output assertion after build:
$drawingDll = Join-Path (Split-Path -Parent $AssemblyPath) 'System.Drawing.Common.dll'
if (Test-Path -LiteralPath $drawingDll) {
throw 'System.Drawing.Common.dll must not be deployed for TrapMap.'
}
- Step 2: Run RED verification
dotnet build ClumsyPilot\ClumsyPilot.csproj --no-restore -v:minimal
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_image.ps1
Expected: the image test fails because the package, deployment target, using System.Drawing, and renderer still exist.
- Step 3: Remove the drawing package and deployment target
Delete the System.Drawing.Common PackageReference and the entire DeployFrameworkDrawingRuntime target. Add <PackageReference Include="StbImageWriteSharp" Version="1.16.7" />. Do not change the target framework or other references. Ensure a clean build cannot retain the old DLL: the verification command must remove only ClumsyPilot/bin/Debug/netstandard2.0/System.Drawing.Common.dll before rebuilding, after resolving and validating that exact path is under the project output directory.
- Step 4: Implement the RGBA raster surface
Replace drawing types with a private surface backed by byte[] in RGBA order. Required primitives and semantics:
SetPixel(int x, int y, byte r, byte g, byte b, byte a = 255);
FillRectangle(int x, int y, int width, int height, Color32 color);
DrawLine(int x0, int y0, int x1, int y1, Color32 color, int thickness);
DrawRectangle(int x, int y, int width, int height, Color32 color, int thickness);
DrawCircle(int centerX, int centerY, int radius, Color32 color, int thickness);
FillCircle(int centerX, int centerY, int radius, Color32 color);
FillPolygon(PointD[] points, Color32 color);
Clip every primitive to the surface. Use pre-clipped Bresenham lines, scale-normalized scanline polygon filling, and a canvas-clipped bounded circle scan whose work is proportional to visible rows/columns rather than radius. Preserve exact white, red, LightGray (211,211,211), black, blue, and LimeGreen (0,255,0) colors. Convert vehicle/workstation world positions using the existing discrete-grid-aligned transform.
- Step 5: Implement deterministic bitmap text
Embed a private 5×7 ASCII glyph table for code points 32–126. Draw scaled glyphs using integer pixels; unsupported characters render as ?. Use a 2× scale for header text and 1× scale for the workstation label. Keep all five header baselines inside HeaderHeightPixels=140 with fixed non-overlapping line boxes. Continue building the same five metadata lines, including occupancy rate; sanitize only the exported header text, not logs.
- Step 6: Encode PNG and add 300 DPI metadata
Use StbImageWriteSharp.ImageWriter.WritePng to encode the RGBA buffer. Then insert:
pHYs: X=11811, Y=11811, unit=1
Encode into a temporary MemoryStream, validate the PNG signature and first IHDR chunk, then copy the signature+IHDR, append the 13-byte pHYs chunk, and copy the remaining encoded chunks. Use big-endian integers and standard CRC-32 over pHYs+data. Do not close the caller-owned reserved stream before the existing file-size/atomic-move flow finishes.
- Step 7: Update documentation and run GREEN verification
Remove all claims that TrapMap deploys or requires System.Drawing.Common; document the pure C# encoder and BCL-only runtime.
Run from a clean output state:
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_inputs.ps1
dotnet build ClumsyPilot\ClumsyPilot.csproj --no-restore -v:minimal
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_grid.ps1
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_lifecycle.ps1
powershell -ExecutionPolicy Bypass -File ClumsyPilot\tests\verify_trapmap_image.ps1
git diff --check
$staged = git diff --cached --name-only; if ($staged) { throw "Unexpected staged files: $staged" }
Expected: build succeeds without a drawing DLL in output; all tests pass; PNG parser reports correct dimensions, CRCs, 300 DPI metadata, RGBA pixels, unique filenames, file size at or below 50 MiB, and no temporary files.