diff --git a/Docs/perf/0.1.0-walk-frametimes.csv b/Docs/perf/0.1.0-walk-frametimes.csv new file mode 100644 index 0000000..d0ccf6b --- /dev/null +++ b/Docs/perf/0.1.0-walk-frametimes.csv @@ -0,0 +1,830 @@ +frame,ms +0,2.419 +1,2.502 +2,2.360 +3,2.395 +4,2.174 +5,2.539 +6,2.421 +7,2.322 +8,2.455 +9,2.345 +10,2.510 +11,2.076 +12,2.287 +13,2.345 +14,2.398 +15,2.451 +16,2.358 +17,2.303 +18,2.322 +19,2.325 +20,2.370 +21,2.277 +22,2.591 +23,2.312 +24,2.333 +25,2.281 +26,2.453 +27,2.351 +28,2.348 +29,2.452 +30,2.402 +31,2.271 +32,2.314 +33,2.304 +34,2.377 +35,2.443 +36,2.589 +37,2.267 +38,2.554 +39,2.075 +40,2.406 +41,2.395 +42,2.509 +43,2.291 +44,2.370 +45,2.278 +46,2.531 +47,2.289 +48,2.345 +49,2.459 +50,2.495 +51,2.319 +52,2.310 +53,2.528 +54,2.266 +55,2.134 +56,2.413 +57,2.479 +58,2.307 +59,2.343 +60,2.343 +61,2.313 +62,2.317 +63,2.437 +64,2.618 +65,2.316 +66,2.275 +67,2.355 +68,2.496 +69,3.997 +70,1.704 +71,2.353 +72,2.285 +73,2.434 +74,2.389 +75,2.356 +76,2.330 +77,2.531 +78,2.477 +79,2.260 +80,2.493 +81,2.136 +82,2.432 +83,2.324 +84,2.498 +85,2.430 +86,2.364 +87,2.346 +88,2.374 +89,2.370 +90,2.469 +91,2.394 +92,2.653 +93,2.326 +94,2.441 +95,2.285 +96,2.397 +97,2.411 +98,2.333 +99,2.582 +100,2.372 +101,2.375 +102,2.631 +103,2.965 +104,3.026 +105,2.361 +106,2.379 +107,2.281 +108,2.321 +109,2.503 +110,2.532 +111,2.646 +112,2.486 +113,2.462 +114,2.115 +115,2.502 +116,2.149 +117,2.329 +118,2.306 +119,2.578 +120,2.298 +121,2.323 +122,2.318 +123,2.307 +124,2.482 +125,2.383 +126,2.470 +127,2.285 +128,2.392 +129,2.402 +130,2.455 +131,2.296 +132,2.294 +133,2.577 +134,2.288 +135,2.537 +136,2.214 +137,2.279 +138,2.664 +139,2.348 +140,2.444 +141,2.430 +142,2.269 +143,2.317 +144,2.392 +145,2.350 +146,2.333 +147,2.558 +148,2.401 +149,2.335 +150,2.203 +151,2.473 +152,2.471 +153,2.677 +154,1.980 +155,2.721 +156,2.139 +157,2.277 +158,2.348 +159,2.312 +160,2.412 +161,2.498 +162,2.372 +163,2.421 +164,2.249 +165,2.525 +166,2.750 +167,2.465 +168,2.560 +169,2.400 +170,2.310 +171,2.423 +172,2.274 +173,2.482 +174,2.581 +175,2.375 +176,2.285 +177,2.325 +178,2.386 +179,2.379 +180,2.344 +181,2.424 +182,2.635 +183,2.188 +184,2.378 +185,2.258 +186,2.361 +187,2.445 +188,2.280 +189,2.589 +190,2.373 +191,2.349 +192,2.514 +193,2.153 +194,2.271 +195,2.519 +196,2.469 +197,2.509 +198,2.293 +199,2.324 +200,2.317 +201,2.569 +202,2.400 +203,2.527 +204,2.406 +205,2.347 +206,2.361 +207,2.414 +208,2.320 +209,2.481 +210,2.462 +211,2.333 +212,2.306 +213,2.334 +214,2.377 +215,2.447 +216,2.465 +217,2.431 +218,2.304 +219,2.551 +220,2.308 +221,2.373 +222,2.286 +223,2.389 +224,2.524 +225,2.309 +226,2.367 +227,2.358 +228,2.512 +229,2.235 +230,2.320 +231,2.581 +232,2.308 +233,2.410 +234,2.531 +235,2.322 +236,2.585 +237,2.453 +238,2.407 +239,2.279 +240,2.464 +241,2.336 +242,2.282 +243,2.487 +244,2.557 +245,2.214 +246,2.390 +247,2.535 +248,2.234 +249,2.220 +250,2.491 +251,2.446 +252,2.356 +253,2.296 +254,2.502 +255,2.400 +256,2.255 +257,2.592 +258,2.288 +259,2.310 +260,2.443 +261,2.326 +262,2.392 +263,2.414 +264,2.332 +265,2.501 +266,2.381 +267,2.331 +268,2.355 +269,2.331 +270,2.452 +271,2.476 +272,2.625 +273,2.297 +274,2.411 +275,2.254 +276,2.355 +277,2.368 +278,2.416 +279,2.531 +280,2.358 +281,2.349 +282,2.372 +283,2.355 +284,2.388 +285,2.253 +286,2.679 +287,2.415 +288,2.346 +289,2.340 +290,2.390 +291,2.356 +292,2.311 +293,2.582 +294,2.344 +295,2.532 +296,2.309 +297,2.319 +298,2.434 +299,2.413 +300,2.510 +301,2.509 +302,2.441 +303,2.262 +304,2.482 +305,2.397 +306,2.386 +307,2.498 +308,2.409 +309,2.321 +310,2.395 +311,2.927 +312,2.988 +313,2.479 +314,2.328 +315,2.392 +316,2.764 +317,1.912 +318,2.353 +319,2.569 +320,2.505 +321,2.299 +322,2.310 +323,2.414 +324,2.342 +325,2.488 +326,2.365 +327,2.515 +328,2.224 +329,2.466 +330,2.309 +331,2.380 +332,2.319 +333,2.453 +334,2.639 +335,2.300 +336,2.480 +337,2.116 +338,2.343 +339,2.263 +340,2.641 +341,2.473 +342,2.281 +343,2.511 +344,2.300 +345,2.290 +346,2.348 +347,2.306 +348,2.820 +349,2.170 +350,2.425 +351,2.290 +352,2.354 +353,2.256 +354,2.316 +355,2.586 +356,2.308 +357,2.318 +358,2.376 +359,2.364 +360,2.347 +361,2.451 +362,2.297 +363,2.574 +364,2.518 +365,2.191 +366,2.312 +367,2.314 +368,2.421 +369,2.476 +370,2.697 +371,2.183 +372,2.402 +373,2.322 +374,2.690 +375,3.341 +376,2.525 +377,2.423 +378,2.467 +379,2.350 +380,2.235 +381,3.062 +382,2.342 +383,2.556 +384,2.308 +385,2.366 +386,2.396 +387,2.573 +388,2.818 +389,2.460 +390,2.367 +391,2.335 +392,2.323 +393,2.529 +394,2.554 +395,2.758 +396,2.544 +397,2.394 +398,2.332 +399,2.289 +400,2.703 +401,2.451 +402,2.682 +403,2.498 +404,2.500 +405,2.281 +406,2.429 +407,2.493 +408,2.963 +409,2.419 +410,2.304 +411,2.322 +412,2.302 +413,2.604 +414,2.349 +415,2.797 +416,2.552 +417,2.296 +418,2.340 +419,2.585 +420,2.463 +421,2.269 +422,2.782 +423,2.479 +424,2.491 +425,2.206 +426,2.709 +427,2.325 +428,2.589 +429,2.607 +430,2.445 +431,2.410 +432,2.897 +433,2.166 +434,2.247 +435,2.815 +436,2.430 +437,2.368 +438,2.544 +439,2.543 +440,2.277 +441,2.422 +442,2.779 +443,2.530 +444,2.373 +445,2.642 +446,2.475 +447,2.233 +448,2.323 +449,3.161 +450,2.036 +451,2.269 +452,2.700 +453,2.355 +454,2.284 +455,2.931 +456,2.389 +457,2.426 +458,2.341 +459,2.396 +460,2.296 +461,2.438 +462,2.583 +463,2.309 +464,2.647 +465,2.184 +466,2.401 +467,2.276 +468,2.330 +469,2.550 +470,2.469 +471,2.370 +472,2.376 +473,2.483 +474,2.213 +475,2.286 +476,2.339 +477,2.522 +478,2.374 +479,2.354 +480,2.356 +481,2.309 +482,2.523 +483,2.589 +484,2.007 +485,2.830 +486,2.211 +487,2.350 +488,2.338 +489,2.271 +490,2.740 +491,2.495 +492,2.356 +493,2.351 +494,2.355 +495,2.284 +496,2.340 +497,2.367 +498,2.666 +499,2.702 +500,2.653 +501,1.895 +502,2.422 +503,2.288 +504,2.468 +505,2.813 +506,2.235 +507,2.862 +508,2.273 +509,2.495 +510,2.192 +511,2.684 +512,2.679 +513,2.292 +514,2.370 +515,2.447 +516,2.570 +517,3.059 +518,2.939 +519,2.289 +520,2.375 +521,2.357 +522,2.420 +523,2.280 +524,2.570 +525,2.590 +526,2.522 +527,2.200 +528,2.229 +529,2.466 +530,2.722 +531,2.056 +532,2.658 +533,2.298 +534,2.329 +535,2.516 +536,2.205 +537,2.390 +538,2.366 +539,2.439 +540,2.361 +541,2.326 +542,2.376 +543,2.427 +544,2.362 +545,2.336 +546,2.494 +547,2.334 +548,2.319 +549,2.386 +550,2.384 +551,2.273 +552,2.379 +553,2.656 +554,2.264 +555,2.298 +556,2.375 +557,2.378 +558,2.416 +559,2.486 +560,2.395 +561,2.456 +562,2.256 +563,2.282 +564,2.300 +565,2.439 +566,2.439 +567,2.896 +568,2.049 +569,2.322 +570,2.372 +571,2.432 +572,2.295 +573,2.298 +574,2.552 +575,2.365 +576,2.444 +577,2.421 +578,2.704 +579,2.255 +580,2.904 +581,2.389 +582,2.314 +583,2.528 +584,2.223 +585,2.588 +586,2.296 +587,2.282 +588,2.676 +589,2.286 +590,2.390 +591,2.408 +592,2.361 +593,2.404 +594,2.326 +595,2.483 +596,2.412 +597,2.468 +598,2.454 +599,2.245 +600,2.580 +601,2.306 +602,2.496 +603,2.445 +604,2.363 +605,2.316 +606,2.504 +607,2.185 +608,2.649 +609,2.218 +610,2.401 +611,2.494 +612,2.271 +613,2.332 +614,2.296 +615,2.479 +616,2.406 +617,2.377 +618,2.382 +619,2.437 +620,2.222 +621,2.428 +622,2.316 +623,2.569 +624,2.450 +625,2.354 +626,2.305 +627,2.297 +628,2.346 +629,2.435 +630,2.506 +631,2.671 +632,2.185 +633,2.293 +634,2.362 +635,2.552 +636,2.566 +637,2.446 +638,2.304 +639,2.348 +640,2.352 +641,2.357 +642,2.371 +643,2.557 +644,2.339 +645,2.333 +646,2.325 +647,2.420 +648,2.355 +649,2.457 +650,2.512 +651,2.364 +652,2.790 +653,2.245 +654,2.109 +655,2.333 +656,2.338 +657,2.555 +658,2.351 +659,2.486 +660,2.342 +661,2.283 +662,2.240 +663,2.468 +664,2.655 +665,2.314 +666,2.281 +667,2.452 +668,2.320 +669,2.366 +670,2.533 +671,2.590 +672,2.264 +673,2.365 +674,2.354 +675,2.350 +676,2.377 +677,2.627 +678,2.369 +679,2.394 +680,2.389 +681,2.261 +682,2.363 +683,2.400 +684,2.308 +685,2.565 +686,2.394 +687,2.347 +688,2.329 +689,2.369 +690,2.417 +691,2.520 +692,2.222 +693,2.428 +694,2.368 +695,2.390 +696,2.291 +697,2.474 +698,2.309 +699,2.732 +700,2.419 +701,2.291 +702,2.367 +703,2.422 +704,2.476 +705,2.211 +706,2.560 +707,2.351 +708,2.350 +709,2.352 +710,2.284 +711,2.377 +712,2.393 +713,2.682 +714,2.155 +715,2.364 +716,2.369 +717,2.345 +718,2.338 +719,2.379 +720,2.601 +721,2.433 +722,2.513 +723,2.496 +724,2.967 +725,2.579 +726,2.513 +727,2.497 +728,2.268 +729,2.610 +730,2.122 +731,2.441 +732,2.628 +733,2.468 +734,2.228 +735,2.377 +736,2.401 +737,2.267 +738,2.391 +739,2.624 +740,2.467 +741,2.334 +742,2.281 +743,2.385 +744,2.297 +745,2.432 +746,2.300 +747,2.591 +748,2.408 +749,2.330 +750,2.275 +751,2.374 +752,2.385 +753,2.336 +754,2.628 +755,2.263 +756,2.397 +757,2.431 +758,2.387 +759,2.326 +760,2.398 +761,2.554 +762,2.389 +763,2.310 +764,2.465 +765,2.402 +766,2.263 +767,2.688 +768,2.262 +769,2.439 +770,2.164 +771,2.312 +772,2.342 +773,2.395 +774,2.322 +775,2.617 +776,2.289 +777,2.343 +778,2.333 +779,2.348 +780,2.497 +781,2.299 +782,2.589 +783,2.358 +784,2.442 +785,2.235 +786,2.716 +787,2.350 +788,2.839 +789,2.490 +790,2.439 +791,2.438 +792,2.464 +793,2.527 +794,2.897 +795,1.939 +796,2.509 +797,3.275 +798,2.123 +799,2.300 +800,2.425 +801,2.699 +802,2.275 +803,2.523 +804,2.232 +805,3.105 +806,2.195 +807,2.389 +808,2.264 +809,2.813 +810,2.257 +811,2.300 +812,2.543 +813,2.283 +814,2.533 +815,2.308 +816,2.481 +817,2.374 +818,2.504 +819,3.008 +820,2.266 +821,2.351 +822,2.459 +823,2.748 +824,2.512 +825,2.257 +826,2.434 +827,2.430 +828,2.253 diff --git a/Docs/release-checks.md b/Docs/release-checks.md index e3b3e9c..839b641 100644 --- a/Docs/release-checks.md +++ b/Docs/release-checks.md @@ -39,7 +39,7 @@ Measured at 1440p on the development workstation: Bazzite, Ryzen 7 7700X, 64 GB | `0.1.0` | Traversal, both sides | — | — | — | | `0.1.0` | Placement vs references | PASS (with deliberate simplifications) | Section below, 2026-11-08 | 2026-11-08 | | `0.1.0` | Collision and packaging | PASS — no blocking collision, no invisible walls, no seam gaps (see audit note) | `-qaselftest` on the packaged build, 2026-11-08 | 2026-11-08 | -| `0.1.0` | 60 FPS at 1440p | — | — | — | +| `0.1.0` | 60 FPS at 1440p | PASS — 2.42 ms avg (414 fps), p99 3.01 ms at 2560×1440, TSR on, VSync off, no FG | `-qaselftest` perf capture, `Docs/perf/0.1.0-walk-frametimes.csv` | 2026-11-08 | | `0.1.0` | Fresh checkout build | — | — | — | | `0.1.0` | Packaged Linux build | — | — | — | @@ -106,3 +106,50 @@ Run on the packaged build (`GigLineQA`, Development, Vulkan SM5) with `-qaselfte - Caveat recorded: ground Z extremes (−12 m / 3000 cm) are trace-start/terrain-edge artifacts of the widened extent, not walkable holes — the walkable corridor is continuous (walk + transect both PASS). + +## `0.1.0` — 60 FPS at 1440p — record (2026-11-08) + +**Build under test:** packaged `GigLineQA` Development, UE **5.8.4**, Vulkan SM5, +NVIDIA 615.78.08 (RTX 5070 Ti), Bazzite, Ryzen 7 7700X, 64 GB RAM. + +**Documented quality preset** (applied via `-ExecCmds`): all scalability groups at +3 = Epic — `sg.ViewDistanceQuality 3, sg.ShadowQuality 3, +sg.GlobalIlluminationQuality 3, sg.ReflectionQuality 3, sg.PostProcessQuality 3, +sg.TextureQuality 3, sg.EffectsQuality 3, sg.FoliageQuality 3, sg.ShadingQuality 3`. + +**Upscaling state (recorded from the run):** `r.AntiAliasingMethod=4` → **TSR on**, +default screen percentage, `r.VSync=0` (**off**), frame generation **off/unavailable** +(`r.Streamline.FrameGeneration.Mode` absent → -999). + +**Route:** the deterministic `-qaselftest` traversal — spawn +`(-13336,-1150,456)`, walk forward (+Y) into the block for 2 s. Frame times are +captured every frame over that route (829 frames), not a single sample. + +**Result at 2560×1440:** + +| Metric | Value | +| --- | --- | +| Frames captured | 829 | +| Average | **2.42 ms → 414 fps** | +| p50 | 2.38 ms | +| p95 | 2.71 ms | +| p99 | 3.01 ms (≈332 fps) | +| Max | 4.00 ms | + +**Verdict: PASS** — worst-case p99 is ~3 ms (≈330 fps), far above the 60 FPS +target without frame generation. + +**Variance note:** two back-to-back runs measured ~9.2 ms (≈108 fps) when another +game instance / busy compositor overlapped the capture; repeated clean runs +(windowed and fullscreen, Wayland and X11 drivers, window focused) all measured +~2.4–2.5 ms. The high outlier is recorded here rather than hidden. + +**Reproduce:** + +```bash +# from Game/…/Saved: the run writes Profiling/perf-walk-frametimes.csv +./GigLine.sh -fullscreen -ResX=2560 -ResY=1440 -nosplash -qaselftest \ + -ExecCmds="sg.ViewDistanceQuality 3,sg.ShadowQuality 3,sg.GlobalIlluminationQuality 3,sg.ReflectionQuality 3,sg.PostProcessQuality 3,sg.TextureQuality 3,sg.EffectsQuality 3,sg.FoliageQuality 3,sg.ShadingQuality 3" +``` + +Committed frame-time series: `Docs/perf/0.1.0-walk-frametimes.csv`. diff --git a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp index 7091592..9ab855a 100644 --- a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp +++ b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp @@ -14,6 +14,9 @@ #include "Kismet/GameplayStatics.h" #include "Misc/CommandLine.h" #include "Misc/Parse.h" +#include "Misc/FileHelper.h" +#include "Misc/Paths.h" +#include "HAL/FileManager.h" // Development-only diagnostics for the walkable demo. These describe the spawn // and input setup and are not needed in a shipped build's log spam; disable @@ -192,6 +195,9 @@ void AGigLineCharacter::StartQASelfTest() bool bResetReturned = false; bool bPausedOn = false; bool bUnpausedBack = false; + // Performance capture over the fixed walk route (1.0-3.0 s). + TArray FrameMs; + bool bPerfLogged = false; }; TSharedPtr State = MakeShared(); @@ -219,6 +225,8 @@ void AGigLineCharacter::StartQASelfTest() if (bQATestWalking) { AddMovementInput(GetActorForwardVector(), 1.0f); + // Frame time for the perf capture (this ticker runs every frame). + State->FrameMs.Add(DeltaTime * 1000.0f); } // 3.0: stop and measure. @@ -233,6 +241,57 @@ void AGigLineCharacter::StartQASelfTest() TEXT("GigLine QA: walk moved %.0f cm in 2 s -> %s (Z %.0f -> %.0f)"), Walked, State->bWalkMoved ? TEXT("PASS") : TEXT("FAIL"), State->Start.Z, State->WalkEnd.Z); + + // Perf: report frame-time stats over the fixed walk route. + if (!State->bPerfLogged && State->FrameMs.Num() > 10) + { + State->bPerfLogged = true; + TArray Sorted = State->FrameMs; + Sorted.Sort(); + const int32 N = Sorted.Num(); + double Sum = 0.0; + for (float Ms : Sorted) { Sum += Ms; } + const float AvgMs = static_cast(Sum / N); + const float P50 = Sorted[N / 2]; + const float P95 = Sorted[FMath::Clamp((int32)(N * 0.95f), 0, N - 1)]; + const float P99 = Sorted[FMath::Clamp((int32)(N * 0.99f), 0, N - 1)]; + const float MaxMs = Sorted.Last(); + FVector2D Res(0.0, 0.0); + if (GEngine && GEngine->GameViewport) + { + GEngine->GameViewport->GetViewportSize(Res); + } + // Record the upscaling/AA state so the check is reproducible. + auto CV = [](const TCHAR* Name) + { + IConsoleVariable* Var = IConsoleManager::Get().FindConsoleVariable(Name); + return Var ? Var->GetInt() : -999; + }; + UE_LOG(LogTemp, Log, + TEXT("GigLine PERF: frames=%d avg=%.2fms (%.1f fps) p50=%.2f p95=%.2f p99=%.2f max=%.2f ms at %dx%d"), + N, AvgMs, AvgMs > 0.f ? 1000.f / AvgMs : 0.f, P50, P95, P99, MaxMs, + (int32)Res.X, (int32)Res.Y); + UE_LOG(LogTemp, Log, + TEXT("GigLine PERF: AntiAliasingMethod=%d ScreenPercentage=%d TSR=%d FrameGen=%d VSync=%d"), + CV(TEXT("r.AntiAliasingMethod")), CV(TEXT("r.ScreenPercentage")), + CV(TEXT("r.TSR.History.ScreenPercentage")), + CV(TEXT("r.Streamline.FrameGeneration.Mode")), + CV(TEXT("r.VSync"))); + + // Frame-time series, so the check has a graph source, not one sample. + { + const FString Dir = FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Profiling")); + IFileManager::Get().MakeDirectory(*Dir, true); + const FString Path = FPaths::Combine(Dir, TEXT("perf-walk-frametimes.csv")); + FString Csv(TEXT("frame,ms\n")); + for (int32 i = 0; i < N; ++i) + { + Csv += FString::Printf(TEXT("%d,%.3f\n"), i, State->FrameMs[i]); + } + FFileHelper::SaveStringToFile(Csv, *Path); + UE_LOG(LogTemp, Log, TEXT("GigLine PERF: frame times written to %s"), *Path); + } + } } // 3.5: reset should return to the spawn point. diff --git a/TODO.md b/TODO.md index a98a1c8..53d761f 100644 --- a/TODO.md +++ b/TODO.md @@ -106,13 +106,13 @@ The MPFB character asset is planned as the NPC template (see `ROADMAP.md`). Keep - [x] Commit and review the publication preparation changes before pushing. Initial publication commit: `101db3f`. - [x] Review ODbL obligations for each shipped derivative database or produced work before public release. **Done 2026-11-08** — full review recorded in `Docs/odbl-review.md`: the shipped streets/footprints/sidewalks are a Produced Work of the OpenStreetMap database; obligations held are on-screen attribution (`AGigLineHUD`), the ODbL link, and the committed source extract with provenance; share-alike applies to the data layer only (project code/art stay CC0). THIRD_PARTY_NOTICES and `Docs/licensing.md` updated. -### Release checks - active - 01a1b26b-3c94-707f-9665-2f6b4a79b564 (branch `qa-diagnostics-0.1.0`) +### Release checks - [x] Player can traverse both sides of the demo without falling through geometry. **Verified 2026-11-08:** Blender pre-check plus an in-engine swept transect (`-qaselftest`) over the north sidewalk, carriageway and south sidewalk from X -14900 to -9420 — 84 samples, 0 holes, ground Z 317..395 (sidewalk 395, road 366, south walk 317). The player spawns at Z 456 and stays there for the whole run (`fall=0`, single Z). - [x] Building placement, street scale, and site identity checked against references. **Done 2026-11-08:** rendered current DemoMap content, probed world-space geometry (road 24.3 m vs ref 20.9–25.9 m; sidewalk centreline offsets 12.5/13.2 vs ref 12.6/13.6 m; hero frontage 26.0 m, setback ~13 m vs ref 25.75/14.5 m; frontage + north buildings in verified OSM positions), recorded PASS + deliberate deviations (flat blockout surfaces → `0.1.4`, kerb upstand → `0.1.1`, kerb-flush ramps → `0.1.1`) in `Docs/release-checks.md`, and fixed the mis-aimed north-buildings camera (was 9.5 km west → 85% sky; now frames the buildings). Final human verdict pending on `Screenshots/demo/*`. - [x] No blocking collision or packaging defects. **Done 2026-11-08:** extended `-qaselftest` — transect now 1456 samples / 16 rows including the kerb/road/sidewalk seam Ys (0 holes), plus a ground-referenced 30 m wall probe (0/35 blocking hits; no invisible walls). Walk/reset/pause all PASS on the packaged build; `GigLineShotActor` now skips under `-qaselftest`. Evidence in `Docs/release-checks.md` §`0.1.0` audit note. - [x] Remove TEMP QA diagnostics (`GigLine SIM` / `GigLine GROUND` log lines and the settle-timer log) from `GigLineCharacter.cpp` before the release tag, or gate them behind a cvar. **Done 2026-11-08:** SIM/GROUND probes were already removed in the input fix (PR #8); the remaining settle-timer + `GigLine IN:` input-setup logs are now gated behind the `gigline.SetupLogs` cvar (default 0 in `DefaultEngine.ini [ConsoleVariables]`, re-enable at runtime). Verified on the packaged build: 0 setup-log lines, `-qaselftest` still all PASS. -- [ ] 60 FPS at 1440p on the dev workstation (Bazzite, Ryzen 7 7700X, 64 GB RAM, RTX 5070 Ti 16 GB) using a documented quality preset; record upscaling state; report performance without frame generation. +- [x] 60 FPS at 1440p on the dev workstation (Bazzite, Ryzen 7 7700X, 64 GB RAM, RTX 5070 Ti 16 GB) using a documented quality preset; record upscaling state; report performance without frame generation. **Measured 2026-11-08:** Epic preset, TSR on, VSync off, no frame gen — **2.42 ms avg (414 fps), p99 3.01 ms** at 2560×1440 over the fixed `-qaselftest` walk route; frame-time series in `Docs/perf/0.1.0-walk-frametimes.csv`, record in `Docs/release-checks.md`. - [ ] Fresh project checkout builds with the documented external engine installation. - [ ] Package Linux build with documented controls. - [ ] Tag `v0.1.0` and write `CHANGELOG.md` entry; then remove this section.