DramaticShapeVoxelMod archival mirror · read-only
CHANGELOG.md

CHANGELOG.md

CHANGELOG.md225.9 KB100644c9a9a0b8a9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879
# Changelog

## Unreleased

### Added

- **SHINY POKEMON.** On by default, with no row to switch it off:
  shininess is a property of a Pokemon, not a display mode, and one that
  differed between two players' saves would be a setting rather than a
  Pokemon.

  **It was always there.** Gen 1 has no shininess of its own, but it has
  the four DVs Gen 2 later reads to decide it, and the engine already
  ships that reading (`src/pokemon/Stats.lua`, `isShiny` -- its own
  comment calls it "the RBY virtual shiny"). So nothing new is stored on
  a Pokemon and nothing migrates: every save ever made already contains
  the answer, and this release starts drawing it. A mon is shiny when
  Defense, Speed and Special are all exactly 10 and Attack is one of
  2/3/6/7/10/11/14/15 -- which random DVs land on 1 time in 8192, the
  classic rate, and the default the odds dial ships at. Deriving rather
  than storing is what makes it survive a save, a box, a trade and an
  evolution without a second copy of the truth to drift out of step; a
  shiny Bulbasaur is a shiny Venusaur without being told. `mon.shiny` is
  maintained as a cache beside it, written from the DVs and never read
  as the source.

  The roll happens in `Pokemon.new`, which is where every wild, gift,
  starter and traded mon is built -- before the battle bakes its sprite,
  which `battle.started` is already too late for. It draws from the mod's
  OWN random stream rather than the game's, so installing this does not
  shift the sequence every damage roll and encounter slot comes out of.
  Trainers' Pokemon come out ordinary by themselves, because the engine
  pins their DVs to a fixed set -- which is also what the real games do.

  **The models are genuinely recoloured**, not tinted. The recolour runs
  as part of the Stadium extraction: each species' textures are decoded
  once, packed as usual, then recoloured and packed again beside it as
  `NNNs.dsm`. The colours are Stadium's own -- it slides a model in HSL
  rather than shipping second textures, a hue rotation in degrees plus
  saturation and lightness on a quantized -8..+8 scale at 12.5% a step --
  and all 151 sets of values are shipped in `data/shiny_colors.lua`.
  Five species get an explicit colour table instead, because Stadium
  gives THEM a real alternate texture and no single slide can reproduce
  it: Clefairy, Clefable, Jigglypuff, Wigglytuff and Gyarados, whose
  bodies must stay put while a small region rotates a long way.
  Generated effect frames -- flames, beams, sparks -- are excluded, so a
  shiny Charizard has a shiny hide and an ordinary fire.

  Doing this at extraction rather than at load is what makes that
  exclusion exact: `StadiumFx` marks its generated frames and the packer
  drops the marker, so extraction is the last moment a flame is
  distinguishable from a hide. The normal packs come out byte-identical
  either way -- the shiny pass runs after they are written -- so
  `tests/stadium_extract_test.lua` still diffs all 151 against the Python
  oracle unchanged, and the format did not move. The install marker's REV
  goes to 3 so an existing cache rebuilds rather than quietly showing
  every shiny in its ordinary colours.

  **Flat art is tinted** rather than recoloured, because the engine bakes
  a species palette into an image cache that has no idea which individual
  is being drawn. The tint is derived from that species' own shiny slide,
  so a shiny Golbat leans green and a shiny Charizard goes dusky. On the
  3D path each side is tinted separately, which is the only place the two
  sides can differ. A multiply can only darken, so species whose shiny is
  LIGHTER than their normal read quieter on the flat art than on the
  model.

  **A sparkle** on arrival: a ring of additive stars that springs from
  the mon's chest and fades over three quarters of a second, armed on the
  frame a side's occupant changes -- which covers a send-out, a switch
  and a wild foe alike. A wild Pokemon never grows out of a ball, so the
  grow was the wrong edge to hang it on.

  **A star on the status page**, beside the level on page 1, drawn in the
  engine's own pixel grid so it is palette-processed like every other
  pixel rather than floating over the finished frame. Page 1 only: page 2
  clears that block itself.

  **SHINY ODDS**, on the DRAMATIC SHAPE menu itself rather than in one of
  its four categories -- those are the diorama, the fights, what the look
  costs and the headset, and an encounter rate is none of them. The row
  reads `1:8192` and halves down to `1:1`, so every rung is exactly twice
  as often as the one above it, and `1:8192` is both the default and the
  fallback for an unreadable options file: the mod's default is the games'
  own rate, not a buff. The number is the truth rather than an
  approximation of it, because a missed roll also clears a mon that landed
  on the pattern by luck -- without that, every setting would be itself
  and 1/8192 in parallel, and no setting could ever be rarer than 8192.

- **DOORS ON A GATE HOUSE'S OTHER SIDES.** A route gate is walked
  through, so it opens on two opposite faces -- and the overworld drawing
  can only show one. The sprite is a facade seen face-on under a roof
  seen from above, so a SOUTH entrance is drawn (a doorway block in the
  facade's last rows, which `Structures` folds up into the front face)
  and a north, east or west one is drawn as nothing at all: the warp
  sits on the ground cell outside, the art beside it is plain wall.
  Top-down that reads fine, because the wall is never seen. In 3D you
  walked into a blank slab -- 33 of them, on eleven gates.

  Each is now a real doorway, one cell of the tileset's own door art
  standing on the ground of the face you walk into, hung by the SAME
  rule the drawn facade hangs its own door by: the black frame stays
  flush with the wall and what it seals sinks a voxel behind it, so a
  side door and a front door are the same opening at the same depth, and
  the jambs the recess exposes fall out of the mesher wearing the
  frame's own texels. The art's outer ring is left alone -- a doorway
  cell is a cell OF a facade, its border is the wall beside and above
  the frame, and painting all 16x16 would stamp a one-pixel strip of
  front-wall art around every door. The same flood the facade tells wall
  from pane with, bounded to the cell, tells them apart here.

  **Nothing is authored but the art.** `data/voxel_heights.lua` names
  one door cell per tileset and no coordinates: where the doors go is
  read off the map, from the warps that land in a gate house and the
  building standing against them. A warp is an entrance when it leads
  into a GATE-tileset map, is not already ON a door tile (a drawn south
  door would be fought over), and stands on a WALKABLE cell -- the ROM
  gives several gates an unreachable twin warp on the fence or tree
  beside the real opening, and a door behind a fence is a door into
  nothing. What is left is the entrance, and the two cells side by side
  that most gates do have come out as the double door they always were.
  So no hand list to drift out of step with a map edit, and every other
  building in the game is untouched: exactly the eleven gate placements
  get doors.

  Doors belong to the PLACEMENT, not the drawing -- the same 6x4 block
  is the gate on four routes and the warps sit at different rows of it
  on each -- so the model cache is keyed by the openings as well, and
  only placements that agree share a model. It costs about 290 quads a
  door (a flank quad carries one texel, so the art cannot merge into
  strips the way a facade's does) and no voxels: the recess removes as
  many faces as it exposes.

### Fixed

- **The Pokemon Center's steps climb.** The Cable Club stairs, cut into
  the back wall of all eleven Centers, were built as a stairwell sunk
  into the floor -- they lead UP to the Center's second floor. The
  head-on stair reading was right and stays: a drawn ROW is a step and
  drawn row is depth row, 1:1 into the opening, the drawing's own band
  table landing exactly on four steps and its black edge columns walling
  the opening. Only the sign of the rise was wrong, and two things follow
  from it. The risers turn around -- a flight descending away from you
  closes its steps from below and shows you their backs, one climbing
  away shows you their fronts -- and the black edge columns become the
  walls of the opening the flight climbs into, running from each tread up
  to the top of the wall band rather than down from the floor to it. The
  top step lands level with that band, in the dark rows the artist drew
  there, so the flight fills the opening it leaves by. The descending
  class (`stair_down_n`) is unchanged and still available; the Centers
  now pin `stair_n`.

- **Nothing is hung on the TOP of an interior wall.** A wall band is 16px
  of art folded upright over a run two drawn rows deep, so it folds
  entirely onto its south face and has no drawn row left to lay flat on
  top -- and the top then repeated the face. The town house's town-map
  poster (cell (3,0)) and its window ((5,0)), and the Pokemon Center's
  pokeball poster ((3,0) and (4,0)), each came out lying across the top
  of the wall as well as hanging on it: a picture you look DOWN on.

  What is really up there is the wall's own capping course, which is
  exactly the plain panel the decorated column's neighbours draw --
  `wall_top` in `data/voxel_heights.lua` names it per tileset (HOUSE caps
  with the blank course, POKECENTER with the striped panel cell (9,0)
  draws). Per tileset rather than per tile because one room caps with one
  course, and because "plain" is a fact about the drawing that no
  measurement of the geometry can recover. Only the top face is
  redirected; the poster still faces the room.

  Five rooms take it. `HOUSE`, `POKECENTER`, `REDS_HOUSE_1` and
  `REDS_HOUSE_2` name one course for every wall in the atlas -- each of
  those dresses one kind of room, and a list keyed by the decorated tiles
  would need extending every time a map hung something new on the same
  wall. `LOBBY` names the tiles instead (`{ [40] = 93, [56] = 93 }`): the
  Rocket lift's car doors cap with the cabin frame, and the department
  store, the Game Corner, Silph's floors and the roof -- all on that one
  atlas -- keep exactly the tops they had. The doors are also the reason
  the cap is applied in the mesher's DETECTED-run branch as well as its
  pinned one; Structures finds them rather than a pin naming them.

- **Lance's room is furnished with the badge gyms' bird statue.** It is
  the gyms' statue tile for tile on the DOJO atlas -- one cell of figure
  ($02/$38/$12/$13) over one cell of plinth ($22/$23/$32/$33) -- and left
  derived the pair merged into one 32px volume wearing the statue folded
  onto its face. The extruded picture, the same failure the gyms' statues
  and the Plateau's avenue had, and it takes the same answer: the plinth a
  solid 16px block, the bird a per-pixel cutout 5 voxels deep riding its
  top face. Every placement of those eight tiles in the game is a statue
  -- 18 in LANCES_ROOM and 2 in FIGHTING_DOJO -- and Oak's Lab, the third
  map on the atlas, places none of them.

- **A wall cut into a terrace inherits terrace, never the statue standing
  on it.** `bookcase_backfill = "above"` hands a collapsed rank's vacated
  rows the cell above the run, so the League's gate walls have more
  hillside behind them rather than a trench. Indigo Plateau's avenue
  statues stand directly on the pilasters that collapse that way, so what
  every one of them inherited was the BIRD: the figure's shape and art
  copied onto two more rows down the shaft, and each statue came out two
  deep behind itself. Only bodies backfill now -- flat, top and upright.
  A per-pixel standee above (a statue, a sign, a bush) is an object
  standing ON the terrace rather than terrace, so the row has nothing to
  inherit and takes the default synthesized ground.

- **...and a statue on a collapsed pilaster stands ON it.** The duplicate
  above was masking a second fault. A standee finds its support by reading
  the cell below its own drawing, and the bookcase collapse MOVES the box
  it finds: the whole four-row pilaster walks onto its southmost cell,
  which on the Plateau is a full cell south of where the test looked. So
  the bird was lifted to the right HEIGHT and left standing over open
  ground with its pillar behind it -- invisible while the vacated rows
  were being filled with copies of the bird itself, obvious the moment
  they were not. Every row of a collapsed rank now records the row its box
  actually stands on (`S.bookcaseBox`), and a standee supported by one is
  placed there instead of at its drawn position. Supports that do not move
  -- the gyms' plinths, furniture, `building` claims -- are unaffected.
  The plinth keeps its elevation and the statue extends exactly one cell
  above it.

## 1.8.0

### Added

- **LET'S GO: Pokemon GO-style catching, staged in the 3D battle.** A new
  three-rung row. CATCH ONLY changes nothing about the game except the
  throw: picking a Poke/Great/Ultra/Master Ball in a wild battle (or the
  BALL row of the safari menu) opens capture mode instead of the automatic
  toss. FULL makes wild encounters the real Let's Go article: the
  encounter IS the catch -- it opens in throwing mode and stays there,
  the foe never takes a turn, your own Pokemon is never sent out or
  shown (no back pic, no model, no HUD), and B runs, which from a catch
  encounter always works. Poke/Great/Ultra Balls are half price at every
  mart, and EXPERIENCE works the way that game's does: every healthy
  party member gains from every catch AND every trainer knockout, each
  one measured against its OWN level through the Gen VII scaled formula
  -- which is why Let's Go ships no EXP.ALL, and why a level 5 party
  member takes several times what a level 45 one does from the very same
  fight. A catch adds the throw stack on top: grade, first ball of the
  encounter, new species, and a persistent catch combo. CATCH ONLY
  leaves experience exactly as the original game had it.

  **The throw.** The camera locks HEAD ON with the wild Pokemon -- its
  own seat on the arena's axis, no drift, no steer -- and a real 3D Poke
  Ball (modelled and animated for this: hinged lid, capture beam,
  squash-click, decaying wobble, caught stars, breakout burst; GREAT
  blue, ULTRA's yellow band, MASTER purple, SAFARI olive) hangs at the
  bottom of the frame. The ball rides UNDER the finger -- mouse, touch,
  or the right stick -- and releasing throws it with the swipe's own
  velocity: forward from how hard, height from its rise, side from its
  slant, gravity and collision deciding the rest, with a bearing-and-
  range assist trimming honest errors. Circling the ball WINDS it -- the
  spin visibly builds with the gesture to a cap and bleeds off when the
  hand pauses -- and only a ball at the cap flies with the late-biting
  curve. Contact is against the creature's own GEOMETRY: a pic foe is
  its sprite's opaque pixels (a ball through the gap under a wing flies
  on), a STADIUM foe its model's measured height, girth and hover. The
  timing ring pulses on the creature, coloured by the Gen 1 odds, and is
  judged AT the moment of contact: inside earns NICE / GREAT /
  EXCELLENT, which multiplies the engine's own Gen 1 catch roll; the
  shakes the roll answers are the rocks the ball plays on the ground.

  **Running out, and staying out of the way.** Under FULL an empty bag
  does not hand the fight back to the classic menu -- there is no fight to
  hand back, since a Let's Go wild has no Pokemon of yours in it and a foe
  that never takes a turn, so that menu would offer a FIGHT that cannot
  happen. The encounter keeps its own screen: the seat holds, the Pokemon
  stands there, the readout says NO BALLS LEFT, and RUN is the way out.
  Throwing your last ball lands in the same place rather than ending the
  session. And the scripted catch tutorials -- the VIRIDIAN CITY old man,
  and Yellow's PROF.OAK catching the PIKACHU -- are left alone at every
  rung: they are cutscenes wearing a battle's clothes, where the cursor,
  the bag and the throw are all scripted and nobody keeps the Pokemon, so
  they play exactly as the original does with no capture screen, no held
  camera and no experience.

  **What it stands on.** The outcome is exactly a Gen 1 ball throw: same
  catch math (status, HP and ball factors intact), same outcome texts,
  same caught flow -- dex page, nickname, box overflow -- and a missed
  ball is a spent ball. Outside FULL, a failed throw still costs the
  turn it always did. Needs the staged 3D battle standing (3D-BTL on, a
  depth-capable driver, no headset); anywhere it cannot stand, balls
  quietly take the engine's classic toss.

- **SHADOWS: a row that stands the sun's pass down.** Cast shadows are the
  most expensive thing the mode draws after the geometry -- the whole world
  rendered a second time from the light, every time the view or anybody in
  it moves -- and on a phone or an old laptop that is the difference between
  the diorama running and the diorama stuttering. ON by default, because a
  world where a building throws nothing reads as flat however many voxels it
  is made of. OFF means off rather than "fall back": the flat decal drop
  shadows are the stand-in for a machine that WANTED shadows and could not
  have them, so they stay down too, and the forest's light shafts go with
  them (the beams are lit by the sun's own map). FULL neither sets the row
  nor takes it away, on the same reasoning as AA -- what the look costs is
  the player's question, not a preset's.

### Added

- **SELECT on any row of the mod's menus explains what it does.** Every
  setting here has carried a paragraph of help since it was written -- it is
  handed to the mod manager with the rest of the schema -- and nothing in the
  engine has ever drawn one. It could not: a row is a label and a value, and
  no options row anywhere has room for a third thing. So a row says what it
  IS on one line and what it is SET TO on the next, and SELECT says what that
  MEANS, which is the question RENDER DIST or 2D-3D B cannot answer in
  eighteen characters however the label is worded.

  It opens the game's own dialogue box -- drawn with the ROM's own border
  glyphs, anchored to the bottom of the screen where this game has always put
  text, and only as tall as the sentence it holds, so the row being asked
  about is still visible above it. A, B, START and SELECT all close it, SELECT
  included: it is the button somebody who just pressed it will reach for. The
  bottom line of every one of the mod's menus now reads `B BACK  SEL HELP`,
  because a binding nobody knows about is worth nothing.

  Every description is ONE SENTENCE, and the whole of it is on screen at once.
  The long paragraphs these grew from were written for a reader that never
  existed, and they read as documentation rather than as an answer; a box you
  have to scroll is a worse reply to "what does this do" than a shorter
  sentence is. Both properties are tested rather than trusted -- a description
  that gains a second sentence, or that outgrows its box, fails the suite.
  VOXEL, T-SHIFT and STADIUM ROM got sentences of their own to go with the
  thirteen settings: the first two are the engine's row descriptors with
  nowhere to keep one, and the third is an action rather than a setting.

  The suite also checks every character of every description against the ROM's
  real charmap, because Font.encode answers a glyph it does not have with a
  SPACE and a one-time console warning -- so a curly quote pasted in from
  somewhere would blank a word on screen and say nothing about it.

### Changed

- **The settings live on menus of their own now, behind one red row at the
  top of OPTIONS.** This mod had grown to fourteen rows on the engine's
  list, spliced in as one block. OPTIONS shows four boxes at a time, so that
  was four screens of scrolling inside a list that already carried twenty
  engine rows, and finding SHADOWS meant knowing it was in there somewhere
  past the wireframe and the horizon bend.

  What is on OPTIONS now is `DRAMATIC SHAPE..`, and it leads the list --
  a mod that replaces the look of the whole game should not make the player
  scroll to find out where its settings went, least of all past the engine
  rows it has quietly taken away. It opens VOXEL and T-SHIFT, which came off
  the engine's list with it, and four categories: **3D WORLD** (V-GRID,
  V-CURVE, RENDER DIST, WATER, DAYTIME), **BATTLES** (3D-BTL, BACK SPRITES,
  LET'S GO), **PERFORMANCE** (FOREST FX, SHADOWS, AA) and **VR** (VR,
  SMOOTH TURN). STADIUM ROM stays on that top-level menu, last: it is
  one-time setup rather than a setting, and somebody who has been told to
  import a cartridge should find the row where the mod begins, not two
  levels down a category they have no reason to open until it has worked.

  The split is not a new opinion: it is the `full` flag each row already
  carried. `full` marks a row the FULL preset does not take away, and the
  reason written beside each one was always the same -- this is a question
  about the HARDWARE, or about the GAME, not a knob on the diorama FULL is a
  preset for. So 3D WORLD is exactly the rows FULL owns, and needs no rule
  to disappear under it: every child filters itself out and an empty category
  is not offered. Under FULL the menu is four rows on one screen with no
  scroll arrow. The same rule retires VR where there is no VR to have.

  **Nothing you had set has moved.** Every setting keeps its stored key, its
  ladder and its row id, so `options.lua` is byte-identical across the
  upgrade for a player who changes nothing -- and the hotkeys are untouched,
  which is what makes the nesting affordable: 3, 5, 6, 7, 8 and 9 still put
  every buried row one keypress away. The mod manager's own page still lists
  all thirteen settings flat, now in category order.

  The row is drawn in red, which is a palette zone rather than a color:
  `setColor` cannot tint this text, because the glyph atlas is black ink and
  LOVE tints multiplicatively, and because the palette shader keys on the red
  channel alone and would send a red pixel to the lightest slot. What the
  zone changes is which color the shade the text was drawn in comes out as.
  It is MEWMON -- the palette the OPTIONS menu already wears -- copied with
  only the ink slot replaced, so the paper under the row is the same white as
  the row above it in all three ROMs, and the band covers the two text lines
  alone rather than the cursor and the box borders beside them. SGB INV
  reverses a palette, so there the red starts in the other slot and still
  lands on the ink; OG, OG INV and CLASSIC substitute their own tables
  outright, and the row simply draws monochrome, which is what asking for a
  screen with no colors in it should get.

### Fixed

- **A setting that pins another one now pins it from wherever it was
  changed.** 3D-BTL holds BATTLE LAYOUT at OG while a fight can be staged on
  the map, and FULL holds DAYTIME at SYNC while it owns that row. Both pins
  used to be a side effect of the options-rows hook, which every step on the
  OPTIONS menu happened to rerun -- so they fired whether or not the step was
  the one that mattered, and nothing had to name them. A step made on the
  mod's own menus reruns no hook, so the pinning is a function now, and the
  hook, the menus and the mod manager's page all ask for it.

- **An open OPTIONS menu notices a change made on a menu pushed over it.**
  The rebuild that keeps the row list honest compared the voxel level and the
  two battle switches across one call of `update`. The stack ticks its top
  state only, so a step taken on one of the mod's own menus happens while
  OPTIONS is suspended: both halves of that comparison were read after the
  fact and always agreed, and OPTIONS came back still showing a BATTLE LAYOUT
  row that no longer belonged there. The signature is held on the menu and
  stamped where the rows are built, which is the thing it is a signature of.

- **A building's back no longer wears its own front door.** Every voxelized
  building is its drawing extruded straight through the footprint, so the
  far wall is the facade again -- and read from behind, the facade mirrored:
  a door on the back of every house, a POKe sign readable backwards on
  every Center, MART on every mart and GYM painted across the back of every
  gym. Those tiles are now named per tileset (`frontOnly` in
  `data/voxel_heights.lua` -- the doorways, the hanging shop signs and the
  gyms' lettering) and every cell wearing one takes the art of the nearest
  ordinary cell beside it in the same tile row instead. The donor is picked
  per RUN, so a two-tile doorway comes out as two tiles of the same wall
  rather than borrowing left from one side and right from the other, and
  between the two neighbours the one that row uses more often wins -- which
  is what reaches past a gable's sloped corner for the wall behind it. At
  the base course the donor lifts one row with the model, because the
  drawing's last row is the black threshold a door stands on and the wall
  beside it does not paint; without that the doorway kept its own foot and
  the back's bottom course had a notch in it. Windows are deliberately left
  alone: a back wall with windows is right. The generic volume path folds
  the same drawing up all four sides and had the same bug on its back AND
  its flanks, so it takes the same substitution -- only the south face,
  which IS the drawing, keeps every tile of it.

- **B now actually runs from capture mode -- and A throws, and L/R switch
  balls.** The capture session read its button presses on the RENDER clock,
  along with everything else it does per frame. Button edges do not survive
  there: the engine rebuilds the edge table once per fixed logic step and
  runs all of a frame's steps BEFORE the render-clock hooks, so any frame
  carrying more than one step had already thrown the press away before
  anything looked at it. That is not a rare race -- it is every press below
  60fps, which is exactly where a 3D battle lives, so these buttons were
  reliably dead on the machines that most needed them and fine on a 144Hz
  one. They are read on the logic step now, through the engine's own
  input.step seam, and taken rather than peeked so a press the capture used
  does not also page the message it just queued.

- **No more grass smeared across the top of a LET'S GO throw.** The capture
  seat handed BattleScene its pitch as the DEPRESSION below level, and the
  one thing that reads it -- the camera-ward pull the grass and flowers are
  drawn with -- measures angles off STRAIGHT DOWN, the complement. So a seat
  looking nearly level read as the top-down end of the ladder, where the pull
  is longest: 46 world pixels of bias, handed to a camera standing 46 world
  pixels behind the player. The pull is a shove along each vertex's own eye
  ray -- a pure depth bias while it is shorter than the range, and past that
  it carries geometry THROUGH the lens, where the projection turns inside out
  and a single tuft at the eye lands smeared across the frame. That was the
  greenery hanging over the top of a capture shot on any route or street with
  grass rows beside it. The seat now speaks the same convention the battle's
  own rig does, and the vertex stage clamps the pull to half the range to the
  eye besides -- so no camera standing this close can be smeared by a bias
  again, in a capture, a fight, or first person.

- **The grass moves during a staged battle.** The wind is switched on around
  the free-roam pass's grass draws and off again after them, and the battle
  pass -- which draws the same tufts, on the same map, from its own camera --
  never switched it on: the uniform sat at the per-frame default, which means
  no wind, so a field that was moving one frame before the encounter went dead
  still for the whole fight and started again when it ended. A fight is staged
  on the MAP, in that place's own weather and light; a frozen field was the one
  thing reading as a photograph of it rather than the place. No walker-contact
  push comes with it -- that is somebody stepping through the grass, and the
  two mons stand still on their own tiles.

- **The bottom of the frame no longer bites a row out of the scenery.**
  RENDER DIST cut the world to where the frame's rays land on the GROUND,
  and the ground is not what the picture is made of: a tree at the bottom of
  the screen has its feet south of the row its top is seen on, because the
  bottom edge's ray is still coming down as it passes them. The cut is by
  column -- deliberately, so it never takes the tops off trees -- so a tree
  whose base fell one pixel outside lost its whole height at once, and the
  last row of forest along the bottom of the frame was cut through with the
  ground behind it showing. The south edge is now walked back down that same
  ray by the tallest thing that can stand on it (about a tile and a half at
  35 degrees, four tiles at 50, eleven at 75), plus a tile of slack so a hard
  edge is never decided by a rounding. FIT carries it too: it is a correction
  to the honest answer, not margin around it.

## 1.7.1

### Added

- **RENDER DIST: stop drawing the map you cannot see.** The orbit rungs now
  cut the world to the ground the camera actually frames, so a connected
  map that falls entirely outside it is skipped before it is drawn --
  terrain, water, grass, flowers and its whole shadow pass. At the high
  rungs, where the camera is nearly overhead, that is most of the frame's
  geometry never submitted.

  **The footprint is not the window.** Tilt the camera and the ground it
  frames stops being the flat game's own rectangle and becomes a
  trapezoid: reaching much further north, flaring much wider out there,
  and pulling in at the near edge. At 35 degrees a 320x288 view reaches
  270 world pixels north where the window reaches 144, and 246 to each
  side where the window reaches 160 -- so a window-sized cut takes a bite
  out of a world plainly on screen, with sky showing through the top and
  both sides. It is derived from the orbit's own basis rather than guessed
  -- the frame's corner rays dropped on the ground plane, in closed form,
  cross-checked against a ray cast in the suite -- and the stored
  rectangle sits north of the view centre, because the trapezoid does.

  **The row is a real render distance at 75.** Past about 63 degrees
  (exactly `atan(2*FOCAL)`) the horizon is inside the frame and "all the
  ground on screen" is an infinite answer, so something has to name a
  distance. FIT is the closest of the four, WIDE through WIDEST push the
  world's edge out, OFF stops cutting. Below that pitch the honest
  footprint is already inside the reach and the row does nothing to the
  picture at all.

  The cut reaches the shader as the same box the headset's DIORAMA uses --
  rectangular now, with two half-extents, and the diorama passes the same
  number twice. Under V-CURVE the rim dissolves rather than cutting,
  because a bent world has no straight sides. The sun and the eye ask the
  same question about the same maps, so the light can never record a map
  the camera did not draw.

  Not on 1ST or 3RD -- the player is standing in the world there -- and
  the box opens out and away over the rung tween rather than vanishing on
  the frame the rung changed. FULL sets it to FIT.

## 1.7.0

### Added

- **The DIORAMA modes: Kanto as a model you can pick up.** The VR row is a
  ladder now -- OFF / STANDARD / DIORAMA / DIORAMA-MR. STANDARD is what the
  mod already did (the headset follows the VOXEL ladder, orbit rungs a
  tabletop and 1ST life size). DIORAMA is one presentation instead of a
  ladder: the world is always the model on the table, and the model is a
  thing in the room.

  Everything outside an invisible **box** centred on the view is simply
  not drawn -- the Final Fantasy Tactics read, a square slab of the world
  sitting in the air rather than a map running off to a horizon, cut with
  a hard edge because a flat world is a thing with sides. The cut reaches
  every pass the world is made of -- terrain, characters, grass, water and
  the forest's beams and motes.

  **V-CURVE changes its shape.** With the bend on the world is not flat any
  more -- it is a little globe curling away over its own horizon -- and a
  square cut through that is a lie about what is being looked at. So the
  box becomes a **ball**, and its edge becomes a **gradient** dissolving
  into the sky (the same sky the flat screen has). One click of the left
  stick throws the row and swaps the whole reading of the model.

  **A staged fight** ignores both shapes and cuts a vertical **pillar**
  about the arena, always dissolved at the rim, framing the model to it:
  the fight lifted out of the map as a floating disc.

  **The grips** take hold of the whole thing: one hand carries the model
  anywhere in the room, both hands turn it and open the viewport out to
  whatever you spread your hands to. The **left stick's click** throws
  V-CURVE to its top rung and back rather than stepping views -- there is
  no 2D diorama and no first-person one, so the ladder is held on an orbit
  rung for as long as the mode runs, and the Pokedex stays away.

  **DIORAMA-MR** is the same mode with the background keyed pure green --
  no bands, no sun, no haze, because every one of those is a colour a
  keyer would have to survive -- for a mixed-reality capture that
  composites the model into the player's own room.

  A save that stored the old VR toggle as `true` comes back on STANDARD
  rather than falling to OFF. The viewport is compiled into the scene
  shader as its own variant, so a flat frame -- and a phone above all --
  builds and binds exactly what it always did.

## 1.6.2

### Added

- **The air of Viridian Forest: volumetric god rays, ground fog, and a
  FOREST FX row.** An invisible jungle canopy now hangs above the forest's
  real trees, and light comes down through it as true volumetric beams: a
  per-pixel march reads the frame's own depth buffer and the sun's own
  shadow map, so shafts stand exactly where light really breaks between
  the tree hulls, trunks and passing characters carve dark columns
  through them, and a wind-blown leaf field at the canopy plane opens and
  closes the beams like foliage moving overhead. The beams are alpha zero
  at the canopy and fade in as they descend -- light below the leaves,
  never a lid above them -- and a forward-scattering term blooms them for
  a camera looking up into the light, first person especially.

  The scene shader gains a height-and-distance fog every surface sinks
  into, and the rays are that fog lit: one shared ramp off the day/night
  clock colours both, gold spears of sun by day, silver moon rays after
  dark, dying back through the twilights as one hands over to the other.
  Pollen drifts through the day's beams and fireflies blink low over the
  floor at night, all shader-animated and deterministic. A fight staged
  on the forest floor sits in the same haze at half density.

  The direction never moves: a canopy map's light is pinned to noon (see
  DayNight.CANOPY), so the beams always agree with the shadows on the
  floor. Everything is authored per map in `data/map_atmosphere.lua` --
  a map with no entry spends nothing -- and the **FOREST FX** row (FULL /
  LOW / OFF, FULL by default) governs the cost: LOW halves the march and
  stands the particles down. On Android the row offers LOW / OFF only --
  no mobile driver grants the readable depth the march needs -- so the
  forest keeps its haze there and loses the beams.

## 1.6.1

### Fixed

- **Exeggutor, Tangela and Magmar stand as models in STADIUM battles, and
  Pidgeot and Dodrio stop animating garbled.** Five species animate with
  hermite keyframes rather than packed per-frame streams, and the extractor
  read the animation flags byte from the wrong half of its u16 -- the half
  that is always zero -- so it decoded their keyframe tables as streams.
  For Exeggutor, Tangela and Magmar the result exploded so hard the packer
  declined them to flat battle pics; Pidgeot and Dodrio stayed models but
  played the garbage. All five now decode the way the game's own sampler
  (src/17300.c) does, and no species is held off the field any more.

  Model packs built by an older version of the mod are detected by a
  revision stamp in the install marker and rebuilt from the ROM on the next
  launch (or shadowed by a checkout's freshly packed set) rather than
  trusted.

## 1.6.0

### Added

- **STADIUM battles, and a disc stage: three new rungs on the 3D-BTL row.**
  The row that used to read ON / OFF now reads **2D-3D A / 2D-3D B /
  STADIUM A / STADIUM B / OFF**, which is two independent choices laid out
  as one ladder -- WHAT is standing there, and WHERE:

  |            | on the MAP  | on two DISCS |
  | ---------- | ----------- | ------------ |
  | **pics**   | 2D-3D A     | 2D-3D B      |
  | **models** | STADIUM A   | STADIUM B    |

  2D-3D A is what ON always was -- the fight staged on the map with the Game
  Boy's own pics stood up on their tiles as quads. The STADIUM rungs keep
  the whole staging and replace those quads with the **Pokemon Stadium
  battle models**: all 151 species, skinned, lit and animated, playing the
  animation the move being used actually calls for.

  **A** stands the fight on the map, in the world's own light and weather.
  **B** stands it on two discs against the sky and draws no map at all --
  the Game Boy's own framing, staged rather than found.

  All four combinations are reachable rather than only the diagonal. The
  discs do not know what is on them -- they are two platforms at two cells,
  drawn off the arena alone -- so **2D-3D B** costs one value on the ladder
  and gives the disc framing to a player who has no Pokemon Stadium ROM and
  would rather not go and find one. It needs nothing the base game did not
  ship: the stage is generated in Lua and the Pokemon on it are the game's
  own art.

  B exists because the map does not always cooperate. Half of Kanto's
  interiors are furniture, a cave floor can be nothing but two-cell
  corridors, and some maps have nowhere a fight can be SEEN from a low
  camera and are declined outright -- which drops the player back to the
  flat battle screen with no warning. A carried stage has none of those
  problems: it works on every map, at every step, and the framing is the
  same every time. What it gives up is the thing A is for, which is
  fighting somewhere real.

  It is abstracted from the GROUND, not from the world. The sky behind the
  discs is the hour's own -- gold at dusk, navy at midnight -- and a fight
  in a cave or a shop is under that place's void and its own flat light, so
  walking into Mt. Moon at night and starting a battle looks like Mt. Moon
  at night.

  The discs themselves are flat: one quad apiece, wearing a painted circle
  that fades out at its rim, sized to the Pokemon standing on it. The fade
  is an ordered dither baked into the texture's alpha rather than a smooth
  ramp -- the scene shader discards under half alpha outright, so a ramp
  would come out as a hard-edged circle -- which is the same trick the sky's
  own bands use and reads as intended on a mode built out of visible texels.

  Nothing else about the fight moves. The arena is picked the same way, the
  camera is solved the same way, and the HUDs, the frosted text box, the
  move animations and the depth of field are all exactly what 2D-3D draws
  -- because every one of those is hung off the arena's CELLS rather than
  off the pics. Swapping what stands on a cell changes nothing about where
  the cell projects to, which is why this is a rung on the mode rather than
  a second mode.

  The animations are driven from the fight itself: a move plays the animation
  that species' own battle table names for that move (the Stadium ROM's
  per-species move table, packed into the assets, keyed by the same Gen 1
  move id the engine's move defs already carry -- so DIG really does put
  Diglett into the ground), fainting plays the faint and holds on its last
  frame, and a send-out grows the Pokemon out of the ball as it opens and
  plays the entrance with it. Between all of that, the standby loop. The eyes blink and go
  dizzy on their own counter, which is a texture animation glTF has no
  channel for and the pack carries anyway. Charmander's tail flame and
  Weezing's gas are there too, drawn additively over the body.

  The models go through the mod's OWN vertex format and shader rather than
  a path of their own, which is what earns them everything the rest of the
  diorama has: the depth buffer decides what is in front of what, the sun
  pass throws a shadow of the actual pose, the hour's tint lands on them,
  the hit flash flattens them and the tilt-shift and depth of field see
  them as part of the picture. Skinning is done on the CPU -- these are
  674-vertex models and exactly two are ever on screen -- and once per
  frame, so the sun, the camera and both VR eyes draw the same posed mesh.

  It declines per POKEMON rather than per battle: a species whose pack is
  missing, a substitute doll, or the trainer's own pic before the send-out
  all fall back to the flat card, on that side alone, with the other side
  keeping its model.

  Stored as new values on the same key, with 2D-3D A still first -- so a
  save written before this update reads back as exactly the mode it was
  written for.

- **The models are built on your machine, from your own cartridge.** The
  mod ships no Pokemon Stadium data and cannot: it is that game's. What it
  ships is the READER.

  **Press STADIUM ROM on the OPTIONS menu and pick the file.** The row opens
  the host's own file dialog -- osascript on macOS, PowerShell's
  OpenFileDialog on Windows, zenity then kdialog on Linux, which are the same
  four the engine's own Game Boy importer uses -- and the models are built
  from whatever comes back. `.z64`, `.n64` and `.v64` all work; the byte
  order is detected. The row reads IMPORT before and READY after, and
  pressing it again imports a different cartridge.

  The ROM is **not kept**: it is read, built from, and forgotten. A Stadium
  cartridge is 32 MB and the models built out of it are 34, so keeping both
  would double the cost of the feature for a file with no further use -- the
  marker still records its md5, so a swapped cartridge is noticed.

  The wrong file is refused with a reason on the loading screen rather than
  half-built, and refused BEFORE anything is written -- which matters more
  than it sounds, because the marker is the only thing that makes 151 files
  on disk count as installed, so a refusal that wrote one anyway would
  uninstall a working set.

  The original route still works everywhere, and is the answer on the
  platforms with no dialog (Android; a Linux install with neither zenity nor
  kdialog): drop a Pokemon Stadium (US) ROM into a `baseroms/` folder beside
  the game, straight in it rather than in a revision subfolder under it, and
  the first time it runs
  the 151 battle models are built out of it on a loading screen, in about ten
  seconds, one species a frame. The screen says what it is doing in those
  words -- **ONE-TIME EXTRACTION OF STADIUM ASSETS** -- carries a progress bar
  filled by species written rather than by elapsed time, and names the
  Pokemon it is on, which is the difference between a bar that is trusted and
  one that is suspected of having hung. After that they sit in
  the save directory and are read like any other asset. Until then the two
  STADIUM rungs simply are not on the row: they are skipped rather than
  shown and refused, because a setting that can be selected and then does
  nothing is indistinguishable from a broken mod.

  This is the same arrangement the engine already has for the Game Boy ROM
  it is a recompilation of, and it is why nothing ROM-derived is in this
  repository.

  Doing it needed the whole extraction pipeline in Lua: the archive and its
  Yay0 streams (`StadiumRom`), a geo-layout walk and an F3DEX2 interpreter
  with six texture codecs and a bit-packed animation sampler
  (`StadiumFragment`), the generated flame and gas stand-ins (`StadiumFx`),
  and the bind-pose measurement and packer (`StadiumBuild`).

  **Pure Lua, and deliberately so: it runs anywhere LOVE does, phones
  included.** No FFI, no native helper, no second process, nothing outside
  the standard library and stock LOVE calls. On desktop it is about seven
  seconds and peaks at 68 MB of Lua heap, 32 MB of which is the cartridge
  itself; the working set does not grow across the run.
  `tests/stadium_budget_test.lua` measures both and fails if either stops
  being bounded, because a transient peak a desktop shrugs off is what gets
  a process killed on a phone. On Android the save directory is the app's
  external-files folder, so `baseroms/` there is reachable over USB or a
  file manager without root.

- **Acknowledgement for [pret/pokestadium](https://github.com/pret/pokestadium)**,
  in README.md, model_extract/README.md and mod.card. The STADIUM extractor is
  original code, but the decompilation is what it was written against -- the
  bone matrix chain and the fact that scale is kept out of it, the rotation
  basis, the animation and texture-animation samplers, the battle context
  slots and the move-id constants all came from reading that project. None of
  its code or data is vendored here or needed to run this, and the credit says
  so as plainly as it says what was owed.

- `tools/stadium_pack.py` now reads the ROM directly rather than a
  pre-extracted tree, which makes it the ORACLE the Lua port is verified
  against: `tests/stadium_extract_test.lua` runs both over the same
  cartridge and requires all 151 packed files to come out **byte for byte
  identical**. That is the only honest test of a port of that much numeric
  code -- every rounding mode, iteration order and off-by-one shows up as a
  differing byte, and there are thirty-four megabytes of them.

- `ModSetting:setValue`, which sets a setting by its stored value rather
  than by its place on the ladder, and `ModSetting:setGate`, which lets a
  rung exist only when there is something behind it. 3D-BTL grew two rungs
  in the middle of itself, and every caller that had counted to two would
  otherwise have quietly meant something else afterwards.

- `tests/stadium_shots.lua`, a shot driver for both rungs, with a control
  mode and a pinned clock so two runs of it can be compared.

- **`tests/stadium_anim_qa.lua`: every Pokemon, every animation, every
  frame.** A battle asks a species for one of its animations and then poses,
  skins, re-textures and draws it sixty times a second, and nothing exercised
  that chain -- the pack probe reads the format and walks a bind pose, the
  shot drivers show one species in one animation at a time. So the failures
  only some species have had no way of being found except by a player calling
  that Pokemon out, which is exactly how the eviction crash above was found.

  This is that sweep, headless: the real StadiumPack, StadiumRig and
  StadiumMon over stubs for the three things a graphics context provides, and
  the stubs are not lenient -- a released object throws with LOVE's own
  message, because a stub that quietly accepted one would hide the class of
  bug the sweep exists to find. 151 species, 403,716 posed frames, 25
  seconds. It also drives the state machine over all 165 move slots and
  reproduces the cache eviction directly, which no amount of playing one
  species' animations can reach.

  What it found, and what happened to each:

  | finding | count | outcome |
  | --- | --- | --- |
  | pack cache evicted a model still on the field | 2 | **fixed** -- see above |
  | animation walks the Pokemon off its tile | 65 entrances, 36 hits, 35 faints | **fixed** -- see above |
  | part has no texture | 104,728 | **not a defect.** 39 primitives across 37 species, 1.6% of the set's vertices, every one with all-zero UVs: they are flat-shaded geometry in the original. The pack stores texture indices one-based, so the packer's `0xFFFF` "untextured" sentinel arrives as 65,536 and resolves to nothing, which is correct. Counted rather than reported now |
  | pose flies apart | 250 | **understood, left alone.** Two species in one animation each: Farfetch'd's entrance at 6.0x its bind height and Dewgong's at 6.1x, both just over the threshold, and both because the measurement is a bounding box that includes an authored trail -- Farfetch'd's is a dedicated 30-vertex primitive on a five-bone chain. The bodies are intact and, since the anchor, in frame |
  | NaN or infinite vertex, rig would not build, loopStart out of range, missing aux animation, track indexed off its end, move slot with no animation | 0 | none |

  The three species the packer already declines (Exeggutor, Tangela, Magmar)
  are skipped rather than swept: they are never posed in a game, and sweeping
  them anyway produced 356 of the 362 original "flies apart" findings.

### Fixed

- **Idle animations snapped, and then ran at half the frame rate.** Two
  bugs with the same cause, fixed in opposite directions.

  The animation streams are not keyframes: they carry one value per frame at
  30 Hz and the game steps them. Blended naively against a 60 Hz camera
  that produced the reported glitch -- Rattata's idle snapping almost upside
  down for a frame, Charmander's arms turning inside out for a few --
  because rotations here are **Euler triples**, and two triples can describe
  nearly the same orientation while being nowhere near each other component
  by component. `(0, 20976, 32736)` and `(0, -19936, -5904)` are a real
  consecutive pair out of the set. Walking from one to the other passes
  through orientations that are nothing like either end.

  Dropping the blend fixed that and cost the smoothness: every pose then
  held for two frames, and a set of models moving at half the rate of
  everything around them reads as a stutter. So the blend is back, and the
  snaps are **detected** rather than smoothed. A bone whose rotation moves
  more than a quarter turn inside one 30 Hz frame is not being animated, it
  is being re-expressed, and it holds its frame instead of blending -- all
  three components together, because they are one rotation. The same guard
  covers a translation that teleports more than half the Pokemon's own
  height in a frame. Angles blend the short way round the +-pi seam, and
  texture animations still step whole frames, because an eye is open or shut
  and there is no halfway swap to draw.

  Measured, not eyeballed: walking every species' standby loop in quarter
  frames and differencing each bone's world origin against itself, the
  number of species that jump more than a quarter of their own height in a
  quarter frame goes **42 -> 11 -> 3**: naive blend, stepped, guarded blend.
  The three that remain (Pidgeot, Dodrio, Grimer) have erratic rotation data
  at source and are held rather than smoothed, which is exactly the guard
  doing its job.

- **Exeggutor, Tangela and Magmar are drawn as battle sprites instead of
  models.** Those three come out of the ROM with standby loops that throw
  bones hundreds of units off the body -- the game's own index arithmetic
  evidently reads their channel streams differently from the way this does.
  They used to stand still in their **bind pose** instead, on the reasoning
  that a Pokemon looking like itself beats one coming apart.

  It does, but only just: a bind pose is a rigging pose, not a portrait, and
  three species holding a T-pose among a hundred and forty-eight that
  breathe read as broken rather than as still. So they now decline the model
  outright and the Game Boy's own battle pic stands on the tile instead --
  the same per-Pokemon fallback a species with no pack at all already took,
  in the same arena, under the same light.

  Keyed on the packer's own measurement rather than on a list of dex
  numbers, so a re-extraction that fixes those streams -- or breaks a fourth
  species -- moves this with it.

- **The eyes blinked several times a second.** A texture animation was
  running on a clock of its own and wrapping on its own stream's length.
  Rattata's standby loop is forty frames and its blink is five -- `6 8 7 8
  6`, open through shut and back -- so that played it six times a second,
  and every species with a short blink twitched the same way.

  Two things were wrong, and the data says so plainly: 507 of the 691
  animation/texture-animation pairs in the set are exactly the same length
  as each other, which is what one shared frame counter looks like from the
  outside. So the texture animation now rides the SKELETAL animation's own
  frame, and it HOLDS its last entry past the end of its stream rather than
  looping -- which is what the game's own sampler does (`func_80017540`).
  Rattata now blinks once at the top of each idle loop and keeps its eyes
  open for the other thirty-five frames.

  The frame is not recomputed for the textures; `pose` stashes the one it
  resolved and `textures` reads it, so the two cannot drift apart.

- **The faint animation no longer plays while the HP bar is still
  draining.** `onFaint` runs the instant HP reaches zero, but the engine
  queues the visible collapse behind the move animation and the bar drain
  -- and that drain takes real time, some two and a half seconds on a
  full-health Pokemon. The model was therefore lying down while its own
  health went on emptying above it.

  The request is now recorded when HP hits zero and played when the bar
  reaches zero, off the engine's own `shownHP` -- the same number the bar is
  drawn from, so the two cannot drift. A faint that stops being owed in the
  meantime (a revive, a battler replaced under us) is dropped rather than
  fired late at whoever is standing there. Measured rather than eyeballed:
  the shot driver's `DS_FAINT` case prints the frame the bar empties against
  the frame the animation starts, and they are the same frame.

- **Being hit played the ATTACK animation.** The context slot the mod called
  `hit` is not a damage reaction: read against the move table, Bulbasaur's is a
  95-frame animation that 66 of its moves play, and Pidgey's is 138 frames --
  four and a half seconds -- shared by 111 of its moves. That is the species'
  DEFAULT ATTACK, which is why taking damage looked exactly like swinging: it
  was the swing. Slots 173, 178, 179, 180 and 181 all point at the same one.

  Nor is a reaction hiding elsewhere. Exactly one animation per species is
  claimed by no slot and no move, and it is the same length as that species'
  idle for essentially all of them -- 48/48, 56/56, 60/60, 84/84 -- so it is a
  second standby loop, not a recoil. **This set has no damage reaction in it.**

  So damage now plays nothing and the Pokemon carries on with what it was
  doing, which is what the engine already communicates through its own screen
  flash, pic blink and HP drain. The slot is renamed `attack_default`
  throughout (a label on a position -- the file format is the ORDER, so no
  bytes changed), and the generic swing a move with no table entry falls back
  to now uses it rather than resolving to the standby loop.

- **The battle menu no longer changes colour with the scenery.** There was a
  pass that measured each frosted panel's average brightness and flipped the
  glyphs to white over a dark one, with hysteresis so a drifting camera could
  not strobe them. It worked, and it was still wrong: the battle menu is the
  part of the frame the player reads constantly, and having its colour depend
  on where the camera happens to point makes it unreliable furniture. Gen 1's
  battle ink is black, so it is black -- on a cave floor as much as on a
  meadow -- and the panel's tint, which always pushes toward white, is what
  earns it its contrast. Removing it also took out a one-pixel GPU readback
  that ran several times a second to answer a question nothing asks any more.

- **The required ROM is now named everywhere: Pokemon Stadium (US) 1.0.** It
  always was the only one that works -- every offset in the reader was
  measured against that cartridge -- but the docs and the file picker just
  said "Pokemon Stadium (US)", which is three different ROMs. The picker's
  title, the OPTIONS help, the README, mod.card and the manifest all name the
  revision now, the README carries the reference md5
  (`ed1378bc12115f71209a77844965ba50`) so a player can check their own file,
  and a build from anything else says so on the loading screen as well as the
  console rather than quietly producing wrong models.

- **The extraction screen just says STADIUM EXTRACTION now**, with the
  progress bar and the species name under it; the "this runs once" line is
  gone.

- **Pokemon now grow out of the ball, instead of appearing beside it.**
  Measured, the send-out is: the ball is thrown, the POOF animation runs for
  27 frames, and `startGrowIn` fires on the frame AFTER it ends. So the model
  did not begin to exist until the ball had finished opening -- the ball came
  apart, and then a Pokemon was switched on next to it.

  The engine's own ramp is the Game Boy's three steps (0, 3/7, 5/7, full)
  across the twelve frames after that, which on a 56-pixel sprite is a chunky
  pop and on a smooth 3D model is just a pop.

  The model now runs its own ramp, started when the POOF BEGINS and
  continuous: it grows out of nothing while the ball is coming apart and
  reaches full size exactly as the engine's own grow finishes -- 39 frames
  end to end, which is the poof's 27 plus the engine's 12. Smoothstep rather
  than linear or ease-out, because the ball is still opening through the first
  half and a curve that was already near full size by then would have the
  Pokemon standing about waiting for it. The entrance animation starts with
  the grow, so the arrival is one performance rather than a grow followed by
  a flourish.

  Its own ramp OWNS the arrival once it starts: falling back to the engine's
  afterwards shrank the Pokemon from 0.96 back to 0.71 and then snapped it to
  full, because the two finish a few frames apart -- a visible hitch at the
  end of the one animation that exists to not have one.

- **The first Pokemon of a battle arrived, left, and arrived again.** Every
  guard deciding whether the player's Pokemon is on the field is a field the
  engine sets once the battle is RUNNING, and during the opening none of them
  is set yet: `showPlayerBack` is still nil (BattleState assigns it further
  in), `playerBackPic` is nil with it, and `sendingOut` does not go true until
  the ball is thrown. So the whole intro read as "this Pokemon is standing on
  the field" -- two and a half seconds of it, on its tile, playing its standby
  loop, before the trainer sprite it is meant to be hiding behind had even
  appeared. It then vanished when that sprite arrived and came back with its
  entrance when the ball opened. A switch has no intro, which is why a switch
  always looked right and was the thing worth comparing against. The player's
  side is now simply not on the field during the intro phase.

- **The anchor made birds shake, and the shake read as fast flapping.** The
  body estimate it corrects toward was the MEDIAN bone origin -- robust to a
  few bones flung out, which is what it was chosen for, and wrong in a way
  that only shows on a flapping model: a median is a RANK, and on a bird most
  of the skeleton is wing, so which bone sits at the middle of the sorted list
  swaps between the up cluster and the down one every beat. Measured, the
  estimate moved a tenth of a body-height between adjacent half-frames on
  Pidgey and three whole body-heights on Pidgeot, and the anchor turned that
  into a translation of the entire Pokemon -- the body counter-shaking against
  its own wings, which reads as flapping at twice the real speed.

  The centre is now the bone origins averaged and **weighted by how many
  vertices each bone moves**. The weights are a property of the mesh, computed
  once, so there is no rank to flip -- and a bone with little geometry barely
  counts, which is the robustness the median was for in the first place
  (Farfetch'd's trail is 30 vertices on five bones). On top of that the
  correction is low-passed, so what survives is where the Pokemon has drifted
  to and never how it is shaking on the way. Pidgey's shake goes from 0.24 to
  **0.10 pixels a frame** on a fourteen-pixel model, and travel correction
  improved with it.

  Two species -- Pidgeot and Dodrio -- have standby loops with genuinely junk
  rotation frames, which move the estimate three and two body-heights in a
  single frame against a fifth of a body-height for the fastest real motion in
  the set. No filter separates those: rate-limiting the correction bounded the
  shake but put 33 of the 148 entrances back outside the frame, and
  rate-limiting the measurement could not tell a spike from an excursion
  because they are only a factor of fifteen apart. So each species' own
  standby loop is walked once, at rig construction, and one whose estimate is
  that unsteady is **not anchored at all**: it travels as far as its animation
  says and does not vibrate, which is exactly how it behaved before the anchor
  existed. One species trading a framing problem for no problem beats 147
  trading a solved framing problem for a shake.

- **A Pokemon calling out a fifth species killed every model in the fight.**
  Reported as `Cannot use object after it has been released` out of
  `Voxel3D.draw`, after which nothing 3D drew for the rest of the battle.

  The pack cache holds four models and evicts the least recently *loaded* --
  and `load` only runs when a side's species CHANGES, so a Pokemon that has
  been standing there for a few turns is the oldest entry in the cache. Send
  out a fifth species and it was evicted mid-fight and **its textures
  released**, while it was still being drawn sixty times a second.

  Two things were wrong. The eviction released each texture but left the dead
  object in its slot -- and a released Image is still a truthy value, so the
  next `image()` handed the corpse straight back out to `mesh:setTexture`.
  Slots are now cleared, so an evicted model simply decodes its textures
  again. And the mode now says, every frame, which two species are actually
  standing there (`StadiumPack.keep`), so the two in use are always the two
  most recent and cannot reach the front of the queue at all.

- **And a model that does fail now fails gracefully.** Both draws were a bare
  loop inside the caller's single pcall, so a throw on the first side skipped
  the second -- one broken Pokemon took its opponent off the screen with it
  -- and nothing recorded that it had happened, so the same throw came back
  every frame forever. Each side is now drawn, cast and posed inside its own
  guard, and a side that throws is RETIRED: its rig is released and
  OverworldBattle renders its flat battle pic from the next frame on, which
  is the fallback a species with no pack has always had. The fight carries on
  with a flat Pokemon instead of a missing one, and its opponent is
  untouched.

- **Half the set's animations walked the Pokemon out of the shot.** Found by
  the sweep below, not by a bug report, and it is the biggest of them: 65 of
  the 148 send-out entrances carry the body more than its own height off the
  spot it started on -- Dewgong's reaches seven and a half, and its faint
  nearly ten. Every one returns to exactly where it began, because Pokemon
  Stadium framed each Pokemon with a camera of its OWN that followed the
  performance around a stage. This mode has one camera, solved to hold two
  fixed map cells, so a Pokemon that travels seven body-heights is simply
  gone: sending out a Farfetch'd left an empty tile for three and a half
  seconds while its animation played somewhere off to the left of the frame.

  `StadiumRig.anchor` now takes the excess back out -- the pose is measured
  against where the bind pose put the body, and whatever has carried it
  further than `StadiumMon.TRAVEL` (three quarters of a body-height, which is
  what the frame holds) is subtracted from every bone. The EXCESS only: the
  83 species that never reach the limit are bit-for-bit what they were, and a
  lunge, a hop or a collapse still reads as big and still comes back to the
  tile it left. The centre is the median bone origin rather than the mean or
  the root, so Farfetch'd's five-bone trail streaking three thousand units
  out cannot drag the bird with it.

- **FLY and DIG now take the model off the field.** The charging turn of a
  two-turn move puts the Pokemon out of reach, and the engine says so through
  `picFx[battler].hidden` -- FLY runs `SE_SLIDE_MON_OFF` and DIG
  `SE_SLIDE_MON_DOWN`, each a 19-24 frame slide that ends by setting that
  flag, and the release turn puts the pic back. The model was reading
  `fxHidden`, which is the damage BLINK and nothing else, so it stood on its
  tile while the game insisted it was underground -- and insisted in the
  strongest way it has, by making every attack aimed at it miss.

  It now reads the same field the pic does, which also covers every other
  vanishing act on that seam: the user of Explosion, a Pokemon Teleported
  away. Read as the engine's own answer rather than as a list of move ids,
  so a mod that adds a third two-turn move gets it for free.

  It is deliberately NOT held to the end of its own animation the way a
  collapse is. The Stadium animations are authored as the WHOLE move --
  Charizard's DIG is 3.83 seconds of burrow, emerge and strike, because
  Stadium plays it in one turn -- so cutting at the engine's own hide shows
  the burrowing and holds the strike back for the turn it actually lands on.
  Verified as a timeline (`DS_FLY`, and `DS_MOVE=DIG`): the pic hid at frame
  67, the model went with it, and both came back at 264.

- **And the faint animation now gets to finish.** A fainted Pokemon left the
  field when its PIC did, and the engine's pic slide is fourteen frames of a
  60 Hz clock -- `SlideDownFaintedMonPic`, seven rows two frames apart, under
  a quarter of a second. The Stadium faint animations are nothing like that
  short: the briefest in the set is 49 frames of a 30 Hz clock, the median is
  110 and the longest 230. Every model was therefore cut off inside the first
  fifth of its own collapse -- the Pokemon began to fall and then vanished
  mid-fall, which is worse than not animating at all.

  A model that is collapsing now stays until it has finished collapsing, and
  the two timings are simply not tied to each other any more: how long a flat
  pic takes to slide off the bottom of a 160x144 frame has nothing to say
  about how long it takes a Gyarados to fall over. Bounded at both ends --
  it ends when the animation does, so nothing is left lying on the field for
  the rest of the fight, and the side is reset outright the moment a
  different battler stands in that slot, which is what stops the next
  Pokemon out of the ball arriving face down (that one bites when a trainer
  leads with two of the same species, where the dex number never changes and
  nothing downstream would otherwise notice the swap).

  `DS_FAINT` now prints the span as well as the moment: 127 frames against
  the pic's 14.

- Two ordering bugs in the extraction pipeline that made its output
  **non-reproducible**. The generated flame nodes were deduplicated through
  a Python `set` of tuples containing strings, so their order moved with
  `PYTHONHASHSEED` and Ponyta, Rapidash and Moltres got differently-seeded
  flames on different runs of the same build; and texture registration
  order came from iterating a `set` of ints, which is stable across runs
  but is a CPython implementation detail rather than a fact about the data.
  Both now go in order of appearance, which is the game's own order and the
  one a Lua port can reproduce.

### Changed

- The packed format is now **DSM3**: textures are stored as raw RGBA rather
  than PNG. An ImageData over those bytes costs nothing where a PNG costs a
  decode on the frame a battle starts -- but the reason it was done is that
  PNG means zlib, and Python's deflate and LOVE's need not agree byte for
  byte, which would have made the extractor impossible to check against the
  packer. Uncompressed pixels are the same pixels whoever wrote them. The
  set is 34 MB rather than 24 MB, and it is generated locally rather than
  shipped, so that is a trade worth making.

### Known

- Three species -- Exeggutor, Tangela and Magmar -- have standby loops that
  are corrupt in the source extraction, and fall back to their battle
  sprites on the STADIUM rungs (see above). 148 of the 151 have models.

- Pidgeot, Dodrio and Grimer have a handful of erratic rotation frames in
  their standby loops -- a few frames of junk at the top of the loop rather
  than a corrupt stream. The blend guard holds those frames rather than
  smoothing through them, so they step where the source steps, and Pidgeot
  and Dodrio are additionally left unanchored because those frames move the
  body estimate too far to measure against (see above). Not chased
  further: the extraction is byte-identical to a reference pipeline whose
  sampling was validated against the decompilation's own arithmetic, and
  guessing at the format to fix three species risks the other 145.

## 1.5.5

### Added

- **A third-person camera: the 3RD rung.** The VOXEL ladder's eighth rung
  (`3` / SELECT walk onto it after 1ST, and it is on the OPTIONS row)
  stands the camera on a boom behind the player's shoulder. It is the
  first-person rig with one number added, so everything 1ST already did
  it does: the look steers on a mouse, the right stick or a touch drag,
  and the grid walk is replaced by continuous camera-relative movement --
  push in any direction and you go there, at any angle, with collision,
  warps, ledges, encounters and scripts still running through the
  engine's own machinery.

  The boom **collides**: it marches back through the terrain height field
  and the map's own walkability, so backing into a wall walks the camera
  in to your shoulders instead of through it, and rounding a corner eases
  it back out rather than snapping. Squeezed all the way into the head it
  simply draws as 1ST until you step clear. It also carries a small
  over-the-shoulder rail offset, which fades out as the boom shortens.

  Every sprite in the world **turns to face it** -- yours, the NPCs', the
  figures drawn into the furniture -- and shows the frame it would look
  like from where the camera actually stands, so walking behind someone
  shows you their back. Your own character is drawn (with the
  through-the-wall silhouette 1ST had no use for) and **turns to face
  where they are walking** rather than where the camera looks, so a strafe
  reads as one; standing still they come back round to the camera's
  bearing, which is the one A talks along.

  Your card's frame is chosen from your body's **continuous** bearing
  rather than from the compass direction the grid game stores. An NPC's
  facing really is one of four directions, but yours is the angle the
  camera itself is hung off, and quantising it before measuring it against
  the eye leaves no margin for the shoulder rail's few degrees of offset:
  in a band just short of each 45-degree boundary the pair read as 135
  degrees apart and picked the mirrored PROFILE frame. Standing still.
  Spinning the camera swept four of those bands a revolution, which showed
  up as the character flicking sideways for a split second.

  In VR the boom is declined outright and 3RD presents as 1ST does: a
  headset that seats its wearer three cells behind their own body is a
  well-known way to make people ill. The rung still changes the walk and
  the sprites the same way.

- **Every camera zooms, on whatever the machine has.** The mouse wheel,
  `Q`/`E`, a two-finger pinch and the pad's two stick clicks all reach
  whichever camera is actually in front of you -- the third-person boom,
  the staged battle's lens, or the engine's own survey zoom on an orbit
  rung. One module (`lib/CamControl.lua`) answers "which camera is this
  aimed at" so the four cameras never race each other for an event, and
  forwards everything it does not claim. 1ST claims nothing: the eye is in
  the player's head, and a pinch there would only wind the survey zoom for
  whenever they stepped back out.

- **The battle camera is yours to steer.** The right stick, a drag across
  the screen or the mouse walks the staged shot around the arena and raises
  the seat; the wheel, `Q`/`E`, a pinch or a stick click work the lens.

  Both axes stop where the composition does. LEFT stops at the shot the rig
  was solved for, because there is nothing to the left of it. RIGHT ends
  SIDE-ON -- the eye square to the arena's axis, both Pokemon at the same
  distance instead of one behind the other -- computed from each rig's own
  stance rather than written down. DOWN stops at the rig's low stance and
  UP is 45 degrees above it, raised about the focus at a constant radius so
  climbing never doubles as zooming. Input accumulates into a goal the eye
  eases after, so a flick reads as the camera being pushed rather than
  dragged.

  The lens **opens by exactly the amount the pair spreads**: the solved
  shot looks along the arena's axis at a shallow angle, which foreshortens
  the gap between the two mons to less than half its length, and swinging
  round or climbing un-foreshortens it. Left alone that threw both Pokemon
  off the edges of the frame at the far end of either range, which made the
  whole far end unusable.

  Where you leave the camera is where the next battle opens. An angle and a
  lens you chose are how you want to watch battles, not a fact about one
  encounter.

- **Move animations track the camera.** They already slid to follow the
  pair's midpoint; now they follow its SEPARATION too. Both mons are
  geometry standing on the map, so the camera sizes them -- and an effects
  layer that kept the authored 106-pixel spacing through a zoom and a
  60-degree swing fired its beams into the air beside the Pokemon they were
  aimed at.

- **BACK SPRITES locks the battle camera.** That setting pins your own mon
  to the GB's slot on the menu while the foe stands out on the map, and no
  angle holds a composition that is half frame and half world. The steer,
  the climb and the lens all stand down -- in the rig as well as at the
  inputs, so an angle stored from before the row was switched on cannot
  leave it steered anyway. The slow drift stays: it was always there under
  BACK SPRITES and two degrees is not a composition problem.

- **BATTLE BG is pinned to WHITE and its row comes off the menu.** The row
  picks what fills the screen AROUND the battle, and this mode fills the
  window with the map the fight is standing on -- there are no voids left
  for it to be about. WORLD was actively wrong under it: it makes the
  battle non-opaque so the engine draws a second, dimmed copy of the
  overworld beneath the arena pass's own. Pinned rather than merely hidden,
  so a save written before the mod was installed cannot carry a value the
  menu can no longer reach. Uninstall and the row is back.

### Fixed

- **Grass and flowers are closed off at the sides.** Both stand as
  per-pixel slabs built from runs of lit pixels, and only the front, the
  back and a lid were ever emitted -- so from any angle off square you
  looked straight in through the open end of every run and out the far
  side. At the low cameras this release adds, that is most of the time.
  Each run now wears end walls in the colour of the pixel they close off.

  Flowers needed more than that, because a flower SWAYS: the mesh spans the
  union of every animation frame and each frame is cut back out in texture
  space, so a pixel that drops out of a frame takes the union's wall with
  it and leaves an interior boundary that never had one. The first cut of
  this looked solid on the base frame and still had gaps on every other.
  Every pixel of a flower now carries a cap on all four of its remaining
  faces: enclosed and invisible while its neighbour is there, and already
  in place the moment the animation takes that neighbour away.

- **No more machine-gun bonking in 1ST and 3RD.** The grid walk's collision
  sound marks a discrete event -- a direction pressed, a step refused. A
  free walk has no such moment: the body slides along every wall it grazes,
  continuously, so a corridor taken at a slight angle rang the bonk twice a
  second from end to end. The wall stopping you is the feedback.

## 1.5.2

### Added

- **The Pokédex in hand is a quarter larger.** Its voxel pitch went from
  1.1 cm to 1.375 cm (the body from about 10x15 cm to about 12x19 cm),
  because the screen carries every menu in first person and was
  squint-small at the old size. The attachment -- flush along the left
  controller -- is unchanged.

- **Left stick click steps the VOXEL ladder.** In VR the click now makes
  exactly the step the "3" key (and the pad's SELECT) makes -- the same
  function, handed across, so the ladder walk, the FULL step-over and
  the TILT/GBC FX clearing can never drift from the key's. It used to
  toggle first/third person against a remembered return rung.

- **The floating panel shows the same picture at every window size.**
  The GB-frame region used to be copied into the headset's panel
  pixel-for-pixel, and the panel's swapchain image has a fixed size --
  so a window scaled past it (fullscreen above all) ran the frame off
  the copy's edge and cut the START menu out of the panel. The region
  is now blitted OUT of the window and SCALED into the swapchain image
  at the frame's own aspect: identical picture, identical near-square
  ratio, whatever size or shape the window takes.

- **Menus stay inside the GB frame while a headset is live.** The
  engine's new zoom-aware anchoring docks the START menu to the
  WINDOW's edge -- and both VR screens (the floating panel and the
  Pokédex) crop the window to the near-square GB frame, so a docked
  menu was cropped away with the border it hugged. While a headset is
  live the mod answers the engine's own "hold the anchors" predicate
  with yes, and every menu blits where it was drawn: the START menu's
  classic slot, flush with the frame's right edge, which is the right
  edge of everything the headset shows.

- **The sky's dither is glued to the sky.** The gradient's bands were
  already read by true elevation, but the GBC checker between them kept
  SCREEN-cell parity -- so a head's pitch or roll slid the world-fixed
  band edges over a screen-fixed checkerboard and the whole gradient
  shimmered as the pattern recomputed. The ray path is now a computed
  SKYBOX: each pixel's ray lands in a cell of the sky's own angular
  grid (azimuth columns, elevation rows, sized to match the diorama's
  pixel grid on screen), and the band, the checker's parity and the
  twilight glow -- now measured by the angle to the sun's own direction
  -- are all answered from that cell's centre. The screen grid
  quantises nothing, so the picture behaves exactly like a
  nearest-filtered texture on a dome: its cells slide smoothly with the
  world, no motion of the head recomputes the pattern, and only the
  clock moves the sky.

- **VR works from an installed release.** The OpenXR loader used to be
  looked for only against the working directory and the game's source --
  right for the dev tree, wrong for a release install, where importing
  the mod lands it in the game's SAVE DIRECTORY (or keeps it zipped) and
  the VR row silently failed to start. The search now also asks the
  mount that actually holds the mod and the save directory itself; and
  if nothing on disk answers -- the mod imported as an archive -- the
  DLL is copied once out of the mod into the save directory and loaded
  from there, so every install shape reaches the headset.

- **SELECT walks the VOXEL ladder.** In free roam, the pad's SELECT
  button makes exactly the step hotkey 3 makes -- OFF through the angle
  rungs to 1ST and round, stepping over FULL, clearing TILT and GBC FX
  on every press like the key does. For the machines with no number row:
  the phone's touch pad and a controller. SELECT has no overworld job in
  Gen 1 -- its work is all in-menu, and menus keep it untouched.

- **PCVR, in-process, through OpenXR -- with no change to the parent
  app.** A new **VR** row (OFF / ON, off by default; on the OPTIONS menu
  and the mod manager's page). The whole stack rides LuaJIT's FFI from
  inside the mod: the Khronos OpenXR loader ships in `assets/vr/` (with
  its Apache-2.0 license alongside), the session binds to LOVE's own
  OpenGL context, each eye is rendered by the mod's existing scene pass
  under a placed camera built from the tracked pose, and the finished
  canvases are blitted straight into the runtime's swapchain images.
  Works with any Windows OpenXR runtime (SteamVR, Oculus, WMR).

  - **What you see mirrors the VOXEL ladder.** On the orbit rungs the
    world is a TABLETOP DIORAMA hung at the RUNG'S own viewing angle and
    at the scale that reproduces the flat screen's framing -- step onto
    35 and the model presents at 35 degrees, onto 75 and it rises toward
    eye level, easing between rungs; lean in and the town grows, walk
    around the table and honest occlusion shows you the far side of the
    buildings. On **1ST** you stand inside the world at life size (a
    tile is a stride), the headset steers the same yaw and pitch the
    flat screen's mouse does, and FreeMove walks where you look.

  - **VR controllers.** One OpenXR action set, suggested onto Touch,
    Index and WMR (plus the khr/simple fallback), rebindable in the
    runtime's own UI. In both modes: **left stick** moves (through the
    engine's own stick path, so it grid-walks the diorama and free-walks
    1ST), **A/B** are A/B, **either trigger** is START, and **clicking
    the left stick** steps the VOXEL angle ladder exactly as the "3"
    key does. In the diorama: **right stick up/down** zooms the
    model, and **squeezing a grip** while moving that hand up or down
    drags the whole table with it. No controller button leaves VR --
    both directions belong to the VR row alone, so no mid-fight click
    can eject you from the headset.

  - **Battles happen ON the world -- from the flat game's own seat.**
    When a staged fight starts, the headset fades to black and comes
    back seated in the flat battle's over-the-shoulder shot: on the same
    camera line (your mon near-left, the foe far-right), pulled in to
    the wide rig's standing distance at life scale, turned to face the
    arena -- and fades back to wherever you were when the fight ends.
    Both mons stand on their arena cells in the VR eyes' own view, yawed
    per eye, casting real shadows, wearing the hit flash -- and the MOVE
    ANIMATIONS play out there with them: the engine's own effects layer,
    caught on a canvas and stood on a billboard that faces the eye the
    way the mon cards do (effects are 2D drawings, and a drawing must
    face the eye that is looking), with the classic layout's two slot
    marks pinned where each arena cell lands on that plane along the
    eye's own ray -- so a burst authored at a slot sits exactly over the
    mon standing in for it, per eye, and a projectile crossing the frame
    crosses the arena. (The flat screen keeps its
    composed battle shot, untouched.) And the battle camera's parallax
    drift holds still while a headset is watching: the sway is a flat
    screen's depth cue, and inside VR it read as the world lurching.

  - **A voxel POKEDEX along your left controller.** A hand-authored
    voxel model of the series' own field guide -- red slab, lens, LEDs,
    hinge, d-pad, dark screen bezel -- laid flush along the left
    controller's grip pose (a full quarter turn forward, so holding the
    controller is holding the device) through the same XR-to-world
    mapping as the eyes, at its real hand size wherever the camera is.
    It rides in FIRST PERSON and in the BATTLE seat; the diorama does
    without it -- a hand-sized device hovering over a tabletop town is
    clutter, and the floating panel serves there. In first person its
    screen carries EVERYTHING the flat screen shows -- menus, dialogs,
    shops, wipes -- and the floating billboard is retired outright:
    raise your hand to read, lower it to play. In a staged fight the
    screen is the 2D battle -- text, menus, HP bars, and any party or
    bag screen opened over it -- and there too the floating billboard is
    gone entirely: the fight owns the view, the reading is in the hand.
    (No tracked left controller still gets the floating panel -- the UI
    must be readable somewhere.) Drawn by the scene's own pass with real
    depth, per eye; dark when nothing is showing.

  - **The floating panel wears the GB frame.** The quad used to show
    the whole window -- monitor-wide, mostly mirror -- and now crops to
    the 160x144 letterbox where everything the flat screen has to say
    actually lives, so the panel presents near-square (10:9) at 1:1
    pixel aspect. To keep a battle's HUDs inside that frame, the HUD
    blocks stay in their classic GB slots for as long as a headset is
    live instead of snapping out to the window's edges.

  - **The sky is anchored in space.** On the flat screen the band
    gradient hangs off the frame; inside a headset that meant the sky
    (and the sun and moon with it) rode the player's head. The VR eyes
    now hang the gradient over a fixed slice of elevation above the
    world's real horizon and drop the fixed-slice fallback entirely, so
    tilting your head slides the frame across a sky that stays put --
    and the discs, already projected through each eye's true camera,
    stand still over their own azimuth. The gradient is a true SKYBOX:
    each eye hands the sky shader its own ray fan (head rotation plus
    frustum tangents), and every pixel takes its band -- and its GBC
    checker dither -- from the TRUE elevation of its own view ray, so
    no motion of the head, pitch, yaw or roll, in the diorama or in
    first person, moves a band by a pixel; only the clock recolours
    them. The FLAT screen's first person gets the very same treatment:
    the placed rig builds its own ray fan from the basis its view is
    made of, so mouse-look pitch slides the frame over a sky that
    stays put there too, dither and all -- while the orbit rungs keep
    their classic frame-hung painting. And the SUN AND MOON are no
    longer painted on the frame at all (in first person on the flat
    screen included): the cell art is baked to a texture once per
    palette and hung on a quad IN THE WORLD, projected through the
    camera like any geometry -- no per-frame cell snapping (the
    jitter), no pattern squared to the canvas (the face that turned
    with the head).

  - **The VR row exists only where VR can.** Off Windows -- the Android
    build above all -- the row is absent from the OPTIONS menu and the
    mod manager's page both (the loader and the GL interop are Win32),
    and a stored vr=true that migrated over in a save is ignored instead
    of read, so a phone never tries to start a session or force the
    battle rows.

  - **VR owns the battle rows.** While the VR row is ON, staged battles
    are REQUIRED (3D-BTL answers ON whatever it was set to) and BACK
    SPRITES is held OFF -- the battle seat, the pokedex screen and the
    effects plane all assume both mons standing on the world -- and both
    rows leave the OPTIONS menu for the duration, because a switch that
    decides nothing reads as broken. Both come back, at their stored
    values, the moment VR goes off.

  - **First person snap-turns.** Flicking the right stick left or right
    steps the view 45 degrees, once per flick (it re-arms at centre) --
    a snap rather than a smooth spin, because smooth software yaw is
    the classic VR comfort mistake. The turn steps the XR-to-world
    mapping itself, so the eyes, the walk direction and the pokedex in
    your hand all agree about which way the world now faces.

  - **The cast holds one pose for the headset.** Sprite cards lean back
    by the camera pitch on the flat screen; a head that roams the table
    has no one pitch to match, so every VR frame leans the cards at the
    top rung's near-upright 75 degrees instead -- whatever orbit rung
    the ladder is on -- and the flat screen keeps leaning with the rung.

  - **Menus, dialogs, battles and wipes float on a panel** (an OpenXR
    quad layer fed from the window), so everything the flat screen can
    show, the headset can read. The window itself becomes the VR mirror
    -- the left eye, fitted to the window -- and every existing
    keyboard, mouse and pad input keeps working alongside the XR
    controllers.

  - The two eyes share one shadow map, one pose capture and one glint
    step per frame (VoxelScene.render's `eyes` path), so they can never
    disagree about anything but their viewpoint. xrWaitFrame paces the
    app at headset rate while FixedStep keeps game logic at its own 60
    Hz; vsync is handed off while the session runs and put back after.

  - Failure is a status, never a crash: no runtime, no headset, no GL
    interop, or a session lost mid-play all land back on the flat screen
    with the reason printed (`XR_ERROR_FORM_FACTOR_UNAVAILABLE` means
    "plug the headset in, then toggle the row"). Needs the mod running
    from a real folder (the FFI cannot load a DLL out of an archive).

## 1.5.0

### Added

- **1ST: a first-person camera, played like a modern one.** A seventh
  rung on the VOXEL ladder (hotkey 3 walks it; the OPTIONS row carries
  it). Stepping onto it dives the camera from wherever the orbit was
  into the player's own head over half a second, and stepping off flies
  it back out. The rig rides the same placed-camera seam the staged
  battle proved out, so the sky's bands meet the horizon, the sun and
  moon hang where their shadows say, and the water reflects at eye
  level -- all through math that was already there.

  - **Free look.** Relative mouse motion (the cursor is captured while
    the rung is on; left click is A, right click is B), the right
    stick at a rate with a squared response curve, or a touch dragged
    across any open screen -- the overlay's d-pad and buttons still
    work, and a second finger can drag the view while the first
    walks. Pitch clamps short of straight up and straight down.

  - **Free movement.** While 1ST drives, the grid walk is replaced by
    a continuous, camera-relative one: push forward and you go where
    you look, at any angle, sliding along whatever you graze. The left
    stick's raw deflection, the touch d-pad's true vector, or the held
    keys (forward / backpedal / strafe) all steer it. The grid is
    still the game: the walk asks the engine's own collision the same
    per-cell questions a grid step asks, the logical cell tracks the
    body, and every cell crossed runs the engine's own landing
    pipeline -- warps, encounters, spinners, gates, poison, repel, the
    step counters. Walking off the map edge, into a ledge or into a
    boulder hands the push to the engine's own handlers, so
    connections cross, ledges hop and boulders shove exactly as
    themselves. Speed is the grid walker's own (bike included), so
    distance per second and encounters per tile are unchanged.

  - **Billboards seen from inside the world.** Character cards stop
    leaning and start turning: upright, yawed about their feet to face
    the eye, wearing the frame their pose shows *this* viewer -- walk
    behind an NPC and you see their back, circle to a flank and you
    get the profile, exactly the four frames Gen 1 drew. The authored
    figures (the couch sitters) turn the same way, about their own
    middle. The sun pass swaps frames in step, so a card never reads
    its own shadow through a mirror-flipped record of itself. The
    player's own card is left out of the camera draw -- the eye stands
    in it -- but still casts its shadow on the ground ahead.

  - The shadow map's box follows the look (the orbit's fit reaches far
    north and barely south, which is wrong for a head facing south);
    the world curve is declined outright while the head owns the
    camera; and the whole rung falls back to the 75-degree orbit on
    hardware without the 3D pass.

## 1.4.3

### Added

- **The furniture of the whole game goes through the building
  pipeline.** 1.4.1 put four drawings through it; this is the rest of
  the rooms. Every one of them is the same read -- the drawing's own
  bands say what is a top seen from above, what is a face seen head-on,
  and where the thing ends on the floor -- and every one of them
  replaces a pinned box that wore its drawing as a decal. The pins all
  stay as the degradation path, neutralized wherever a template stamps.

  - **The bookcase, the commonest piece of furniture in the game** --
    58 placements across two drawings on the town-house atlas (books
    and a bowl on each shelf at the west end of eighteen homes, books
    on both at the east), plus Red's and the Copycat's pair. Pinned
    `desk` it was a 24px box with the books painted on its flat front.
    Modelled it is 23 voxels of cabinet with its top seen from above,
    and every book, bowl and door panel sunk a voxel behind the frame
    the drawing seals it in.
  - **Celadon's display cabinets** -- the tall one with the trophy
    behind its glass and the short one beside it, band for band the
    same object as the town house's on another atlas, which is what
    makes the pair read as one line of furniture: 23 voxels and 15,
    exactly the 8 rows of drawing between them.
  - **The dining table, everywhere it is drawn** -- the generic town
    house's at 18 placements, Red's and the Copycat's, and the chief's
    long table at four cells wide. All of them the lab table's read at
    a different width, all of them 6 voxels, all of them standing on
    the ground line their legs are drawn stopping at rather than on
    the grid's floor.
  - **The stool at every one of those tables** -- 94 placements on the
    house atlas alone, ten more in Red's and the Copycat's, and the Fan
    Club's four members' chairs, a different drawing that is
    pixel-identical from the seat down. The first template with no base
    piece at all: a stool is drawn mid-cell over its own floor, so it
    is a desk-set of exactly one part, seat lid over legs with the
    floor showing between them.
  - **The Pokemon Center's healing machine** -- two variants, 24
    placements, plus the Indigo Plateau lobby's pair. A wall-height
    cabinet with its monitor perched on the front of its top face,
    drawn across two map rows because it towers over the 16px band
    behind it, which the volume path could only read as more wall. The
    hoses leaving its side are modelled as hoses, at the elevation and
    the depth the two stacked motifs put them; the west machine's
    keyboard is a shelf at counter height wearing its own top-view art.
  - **Bill's desk, and the Silph president's** -- the same drawing in
    both rooms. Its terminal is drawn in 2:1 isometric, turned 45
    degrees to the map, and builds as a cube rather than the slab a 2:1
    reading gives; the kinked dark run between keyboard and computer is
    raised to the keyboard's height and reads as the cable it is. The
    desk stops at its own two cells because the artist drew its apron
    into the walkable cell in front, sharing tiles with the chair
    pushed up to it -- so the chair is modelled as a part of the desk.
  - **The Bike Shop's open toolbox.** The drawing looks down INTO the
    tray, which is why every solid treatment failed it -- as a
    `billboard` the whole cell went up as one 10-voxel slab wearing the
    drawing as a decal. `tray` builds four walls, a floor and air
    between them, with the lid standing open on its hinge.

  What the template language grew to carry them: `tray`; a `desk` band
  that lays its top face flat as a lid; the `box`, `flat` and `iso`
  part kinds; `stretch` for a band mapped over a deeper plot than it
  was drawn on; `inset` for a pane sunk by hand; `panes = false` where
  the global recess pass has the polarity backwards; a `wall` element
  so a template can keep the band behind it solid; `plane` for a height
  the drawing states elsewhere; and `scrub`/`keep`/`support`, which let
  a template model a surface while leaving an object standing on it to
  its own standee -- Red's potted plant on the dining table.

- **Round bins: the `can` class.** Vermilion Gym's switch puzzle stands
  fifteen galvanised trash cans in a row, and the S.S. Anne redraws the
  same object pixel for pixel as its galley barrels. Left to the thin
  standee pool they were flat discs on edge -- fifteen coins standing
  in a row; pinned a plain `cylinder` the drawing's base arc revolves
  too and they came out as barrels balanced on a three-voxel stem.
  `can` is the round hull cut at both ends, hollowed and tapered: the
  drawn mouth ellipse projects across the top and down the well so you
  look into the bin, the drawn base ellipse is ground contact rather
  than body, and the plan narrows toward the floor. The two ellipses
  are measured off the pixels; the height, the well and the taper are
  authored, and the entry says why.

- **The rock gyms' boulders are round.** 87 placements over Pewter's
  walls and maze and Bruno's clusters, and every one of them was a
  square bar wearing a boulder texture in relief -- the repeat-aware
  scenery path extruding the whole drawing as one course. Each cell is
  now a hull whose plan is its own drawn width profile turned in depth:
  a dome full-width from the drawn shoulder down, tapering over the top
  five rows exactly where the art tapers, with the floor's corner
  diamonds opening between them the way the drawing has them. Still
  16px, so nothing standing on or beside a rock moves.

- **The potted plant stands as a plant.** The most repeated interior
  prop in the game -- 78 placements over 13 maps, six per Pokemon
  Center -- and its urn was rendering as a hollow black frame, because
  the drawing's foot lies flush on the block's bottom edge and the
  background vote took the plant's own darks away with the floor. Named
  outright as light and white instead, it stands as one organic
  silhouette 32px tall over its two stacked cells, crown overhanging
  the stem. `planter` carries the same reading for a round drawing
  stacked two cells high on one cell of plot.

- **Bicycles, in both places the Bike Shop draws them.** The six on the
  showroom floor get their own pool at two voxels rather than the thin
  pool's five: a bike is a line drawing, and at five voxels every
  stroke closes the gap to its neighbour with its own side faces, so
  from any angle but dead-on the air inside the frames filled in and
  the six came out as one dark lump. And the two against the north wall
  get `mounted`, a new authored-mask escape for a thing drawn INTO a
  wall band: it holds the wall's plane as a thin per-pixel slab instead
  of standing up as a sprite card, and it keeps its drawn elevation, so
  a bicycle hung clear of the floor stays hung. Its mask is measured
  rather than hand-drawn -- the plain panel tile composited across the
  same grid and the background flooded in through the pixels that still
  match it, which separates bicycle from stripe exactly.

- **The Marts' cash register is a machine, not a decal.** An authored
  figure may now state a `depth`, which makes it an object rather than
  a person: a per-pixel solid standing on the counter instead of the
  flat card that turned edge-on with the camera. And the drawing is not
  a box -- its black linework packs two facings, an L of base and arm
  around a keypad that is the machine's deck seen from above. `flat`
  lays that rect horizontal in the notch of the L, and `thin` gives the
  receipt curl a paper's thickness where the body's would have made it
  a wedge.

- **Shelf fronts have relief.** Everything the `bookcase` collapse is
  used for is a shelf, a rack or a display case, and all of them seal
  their contents behind the drawing's own black frame -- so those
  regions now sink a voxel, the same rule a facade's window panes are
  recessed by, and the books stand in the shelf instead of being
  painted on it. A tileset that borrows the collapse for something that
  is not a shelf says `bookcase_relief = false`: the League's masonry
  and pilasters, whose courses are the wall itself, and Bill's
  transporter drums, whose light regions are a lit barrel.

### Changed

- **Class heights now follow the models under them.** A tileset's
  `heights` gets stools at 5 and tables at 6 in the houses, Bill's desk
  at 8, and cans at 9 -- each of them the drawn elevation the new
  template or hull stands at, so whoever sits on a stool sits on the
  seat, and whatever object sprite stands on a table lands on the
  modelled top rather than three voxels over it or under it.
- The healing machines' two flanks leave the `wall` pin for the thin
  standee pool. They are equipment standing beside the console -- a
  pair of pipes and a keyboard -- and as wall each was boxed into a
  solid 16px half-cell wearing its drawing in relief.

### Fixed

- **Water no longer hides behind water.** The reflective pass writes no
  depth -- the depth canvas is detached for the length of it so the
  shader can read it -- so nothing put a lake in the buffer and no lake
  could occlude another; the sheets were simply painted in mesh order.
  Flat water never showed it, one plane, a farther sheet always landing
  farther down the screen. The world curve ends that: it drops the far
  side of the map into the near field of view, and a sea a hundred and
  fifty tiles away came out rasterised on top of the pond at the
  player's feet, tall grass and all -- water and terrain "from the
  other side of the map", not reflected but there. The water meshes now
  go down flat first, through the ordinary scene shader with depth
  writes on, and the reflective pass draws over what survived. The
  buffer holds the surface, so the pass's own test throws the far sheet
  away; the reflection copy holds it too, so a ray grazing another part
  of the lake reads water rather than the void behind it; and a frame
  that cannot run the pass at all is unchanged, because the flat draw
  is the fallback that was already there.
- **Reflections under the world curve.** The bend tips the world away
  and the things standing on it do not lean with it -- and a lake is
  one of those things. Reflected off the bowl the bend makes, the far
  half of a pond was a mirror tilted twenty degrees: it threw the ray
  past the vertical, where the sky ramp's own measure swings from one
  end to the other across a single column, and hard-edged patches of
  the wrong sky stamped into the water; the same tilt sent the
  screen-space march grazing along the bank rather than over it, which
  is what smeared the dock and the roofs across the harbour. What the
  water reflects is now worked out in the flat world, exactly as it
  would be with the curve off, and every marched sample is bent on its
  way to the screen by the vertex stage's own displacement -- so the
  ray is straight where it should be and lands where the geometry did.
  The wave columns are read on the flat sheet too: the relief walk is
  built on an even slab over a level plane, and in the curved world
  that slab is a bowl, which handed back a column a pixel or three off
  per fragment -- a patch of noise in the middle of a pond.
- **Merged runs tore open under the curve.** A quad's interior is the
  chord of a parabola its neighbours draw the arc of, so a long run
  hangs below the short quads butted against it. Nothing bounded a
  run's length, and the ones that ran away were those wearing a
  constant texel -- a roof's black eave outline, its fascia, its shaded
  underside -- because a flat run has no art to break it. At 102px
  across a gym the eave tore off the roof and the slot showed the
  building's dark interior through it. Runs now stop at the next 8px
  lattice line, which is the lattice buildings are stamped on and the
  one every other quad in the scene already ends on, so every join is
  vertex-for-vertex and the bend carries them together. It costs quads
  whether the curve is on or not -- Cerulean's object stream goes from
  35.7k to 41.6k -- and that is deliberate: the mesh is cached per map
  and built over seconds, so meshing for the curve's sake only when the
  curve is on would mean rebuilding every live map on a keypress.

## 1.4.1

### Added

- **Furniture through the building pipeline.** The band-table voxelizer
  that models whole buildings from their own drawings (lib/Buildings.lua)
  now reads interior furniture too, and the first four drawings are in:

  - **F01, the starter-ball table in Oak's lab** -- the tabletop's 16
    drawn rows lay flat over a 16px plot (1:1, the first template that
    never cycles), the black/#555/black edge band folds into the slab's
    own rim, and the base extrudes with its corner feet. Six voxels
    tall, exactly the drawn elevation.
  - **F03, the empty north table beside it** -- the same band table on a
    grid two tiles narrower.
  - **F02, the lab's computer desk** -- the first DESK-SET template: the
    drawing segments into PARTS, each classified by the surface it
    depicts. The monitor and the computer tower stand upright on the
    desk wearing their own drawn tops as lids; the keyboards and the
    mouse lie flat in front of them; the sheet of paper on the right
    lies flat across the desk. Flat parts keep the drawing's own rule --
    drawn row IS depth row, the same 1:1 the tabletop is drawn with --
    so an object's height on the drawing is its position on the desk.
    The Hall of Fame's recording machine is this drawing tile for tile
    on the GYM atlas, and models identically for free.
  - **F04, the Center PC** -- the desk-set read again: a Mac-style unit
    with its screen and drive slot in relief, standing at the back of a
    low white-topped desk with its keyboard lying at the front edge.
    Eleven Pokemon Centers, plus the Indigo Plateau lobby, whose MART
    tileset shares the atlas.

  Two measurements had to stop being assumptions for furniture to fit
  the pipeline: the GROUND LINE is now read off the drawing (a building
  ends on the black threshold row it stands on; a table's legs stop two
  rows short of theirs, and extruding against the grid floated them in
  the air), and a template may name its PLOT (`depth`) when the matched
  grid runs past it onto the walkable floor the legs merely stand on.
  Both are identities for every existing building.

- **The Center couch has a backrest.** The couch is drawn from above --
  back-and-arm strip down the west side, cushions and seams on the east
  -- and rendered as one seat-high box. The new `backrest` class raises
  the drawn back strip to 12px over the 8px seat, in every Center and
  the Celadon Hotel. The man sitting on it keeps his seat: the figure
  anchor now scans under his card for the tallest authored upright (his
  cushion) instead of reading the corner tile, which is the backrest
  now.

### Changed

- **Sprites ride at the height the art actually stands.** Class heights
  can now be overridden per tileset (a tileset entry's `heights`), and
  DOJO's lab tables use it: they are drawn 6px tall, not the default
  table's 12, so the starter balls sit exactly on the modelled tabletop
  -- and the volume-built north tables drop to the same height, keeping
  every table in the room level.
- The Center PC's old rendering -- a 12px table box with the unit as a
  flat standee on it -- retires wherever the F04 template stamps; the
  pins stay only as the degradation path when the shape profile is
  absent.

## 1.4.0

### Added

- **WATER, a new row on hotkey 9: water reflects the world, the sky, the sun
  and the moon.** Every lake, sea and pond in Kanto was a flat animated
  texture lying in a hole in the ground. It is now a surface, and it is
  reflective.

  What it reflects, in the order the shader resolves them:

  - **The sky.** The reflected direction goes through the very matrix the
    frame is drawn with, as a point at infinity, and the canvas row that
    lands on is looked up on Sky's own band ramp -- the identical texture,
    the identical checkerboard dither, the identical display-mode transform.
    So the sky in the lake is the sky over it, and the two meet at the
    waterline with no seam at any pitch, field of view, window shape or zoom.
    Blue at noon, gold at dusk, navy under the moon; GRAY gets a grey lake
    and CLASSIC a green one, for nothing.

  - **The sun and the moon**, hung by ANGLE rather than by screen position,
    because a reflected body is usually off the top of the frame entirely
    and a projected point stops meaning anything out there. The angular
    radius is the painted disc's own radius run back through the camera's
    field of view, so the two are the same size -- craters, dithered rim,
    the sunset's loom and all, off one shared list. This is also the
    specular: a low sun lays a broken gold path across the water on its own,
    out of the reflection rather than out of a highlight term nailed on
    beside it.

  - **The world, in screen space.** The reflected ray is walked forward in
    world space, each step projected through the same matrix, looking for
    where it passes behind what the depth buffer holds -- then binary-refined
    onto the contact and read out of a copy of the frame as it stood before
    the water went down. Shore trees, buildings, ledges and cliffs land in
    the water because they are on screen; where the ray leaves the frame or
    finds nothing, the sky above answers instead, which is what makes the far
    half of a lake sky and the near half scenery with no seam between them.

  Fresnel decides how much of it shows: almost nothing looked straight down
  at, almost everything looked along -- so the 15-degree rung is a pond and
  the 75-degree rung is a mirror, off the same surface.

  Every rung gets one, though, which took a lean. A reflection off flat water
  points as far above the horizon as the eye is above the water: 15 degrees
  at the top rung -- grazing the sky's pale end, sweeping the sun's own path,
  travelling far enough across the screen for the march to find the shoreline
  -- and 75 degrees, straight up, at the steepest. Up there the bands are at
  their darkest, the sun and moon sit at about 6 degrees of squashed
  elevation and are nowhere near it, and the screen-space ray leaves the top
  of the frame in two steps. All three are correct, and together they are a
  lake with nothing in it.

  So the reflection now LEANS toward the elevation the top rung reflects at,
  by however far the camera is from having a horizon in frame -- **zero** at
  the rung where the horizon IS in frame, so the one place the join can be
  seen, the waterline, is still the exact reflection it was. Toward an
  elevation rather than by a weight, because the ray it starts from differs
  at every rung and a fixed fraction lands them all somewhere different: the
  middle rungs came out further from the sun than the steepest one. And it
  leans the LEVEL reflection with each column's own deflection added back on
  top -- leaning the perturbed ray sets its elevation outright, which at full
  lean gave every column on the lake the same one, flattened the sky to a
  single band and removed the moon entirely.

  Three rungs rather than a toggle. FULL is the whole thing; SKY drops the
  ray march and keeps the sky, sun and moon, which is most of the look for a
  handful of instructions; OFF is the flat water this mode always drew. The
  FULL preset sets it to FULL.

- **The water surface is a field of pixel-tall columns, and they are real.**
  Not a normal map: a heightfield of one-world-pixel bars -- the same unit
  every other voxel in this mode is built from, and exactly one texel of the
  water tile -- each standing a WHOLE number of pixels high and rising and
  falling on its own.

  Three travelling wave trains, and one of them dominates: a wave has a
  DIRECTION, and its crest is a line running across it for as far as the
  water goes. Three trains of equal weight cancel and reinforce in patches
  instead, and the surface comes out as round islands of raised pixels with
  no travel to them -- blobs rather than waves. The dominant train's
  wavelength is about forty world pixels, five tiles, so a crest is a long
  run of columns at one height with a step down either side.

  Drawn with no extra geometry at all: the mesh is still one flat quad per
  tile, and the columns are found by walking the view ray down through the
  slab in the pixel shader. That is what makes them read as solid -- a tall
  bar hides the shorter ones behind it, you see the SIDE of the ones facing
  you (wearing the mesh's own direction shading, so a crest is lit like every
  other voxel in the world), and the whole field parallaxes against the plane
  as the camera moves. The water's art is read at the column the ray landed
  on rather than at the flat quad underneath, so the pixels travel with the
  bars they are made of.

  The columns are what you SEE; the normal they reflect with is read off the
  smooth surface they are a quantisation of. That distinction is the whole
  difference between a moon on the water and confetti: whole-pixel heights
  have whole-pixel differences, so a normal built from them can only point in
  about five directions, and a sun or moon barely two degrees across falls
  between them. Still one normal per column, so the surface stays
  pixel-quantised in space while the value it reflects with is continuous.

  Crests stand up to five world pixels, well past the 2px recess water sits
  in -- deliberately, because the columns are relief drawn inside the water
  quad's own footprint, so a bar that reaches above the bank is clipped at
  the water's edge rather than spilling over it. What it buys is a surface
  with real swell in it instead of a two-rung terrace.

  And it moves in STEPS, at **15 a second** -- the cadence hand-drawn pixel
  art is animated at. A surface built out of whole pixels that crawls
  smoothly between them gives away that the quantisation is only skin deep.
  Each step advances the dominant wave by exactly one world pixel, derived
  from that train's own wavelength rather than tuned beside it, so nothing
  ever lands half-way between two pixels and changing a wavelength moves the
  speed with it.

- **AA, a new options row: OFF / 2X / 4X.** Everything else in this game is
  flat art blitted at whole pixels. This mode's world is real geometry seen
  through a perspective camera, and a polygon edge that lands at an angle
  across the pixel grid is the one place where a hard stair-step is not a
  stylistic choice -- a roof ridge, a ledge lip, a tree's silhouette against
  the sky, the leaning card of a character. At the shallow rungs, where the
  diorama reads most like a photograph of a model, they crawl as the camera
  drifts.

  The row is SUPERSAMPLING: the whole pass renders into a canvas larger than
  the window and is folded back down at the end. The ladder is samples per
  display pixel, so 2X is a canvas root-two wider and taller and 4X one
  exactly twice the size -- an honest 2x2 box.

  Two alternatives were tried against what this pass already is, and both
  lost:

  - **MSAA** would have taken the water with it. The reflections read the
    frame's own depth buffer as a texture, and a multisampled depth
    attachment is not something a fragment shader in this dialect can sample.
    The row would have quietly switched the WATER row off.

  - **An edge filter** (FXAA and its relatives) works from the finished
    colour alone, so it would be guessing where the edges are out of one
    sample per pixel -- inventing detail it never rendered, and unable to
    tell a geometry edge from the boundary between two texels of a tileset.

  Rendering larger has neither problem, and nothing in the frame had to be
  taught about it: every pass already measures itself in the canvas it was
  handed, so the sky's dither, the water's ray march, the shadow lookups and
  the camera itself come out the same picture at a higher sample rate. It
  antialiases the geometry, the alpha-cut outline of a sprite card, the
  wireframe and the reflections at once, because none of them know it is
  happening.

  And it softens the ARTWORK with them, which is worth saying plainly. A
  tileset texel out here is not a screen pixel, it is a quad in a perspective
  view, and its boundary crosses the pixel grid at the same arbitrary angle a
  roof ridge does -- so the fold averages across it exactly as it averages
  across the ridge. That is what an honest extra sample says about that
  pixel, and it is also the trade the row is: the diorama comes out smoother,
  not sharper. Which is why it is a row and not something that is simply on.

  Two things are quoted in DISPLAY pixels rather than canvas ones and are
  multiplied up to match: the voxel wireframe's line width -- left alone it
  would fold down to half a line, so turning the smoothing up would appear to
  fade the grid out -- and the scale the overworld's FX closures draw at.

  The fold is a shader rather than a scaled draw, because the void this pass
  renders into is a transparent BLACK: averaging a straight-alpha edge against
  it drags the colour toward black as well as toward transparent, and the
  engine's composite then multiplies by that alpha a second time. Every
  silhouette against the sky would have come out ringed with a dark fringe --
  the exact artefact the row exists to remove. So the taps are premultiplied
  before they are averaged and divided back out after.

  The staged battle gets it too, on its own canvas: the arena is folded back
  to the window's pixel size before the depth-of-field pass and the HUDs go
  on, so the world is smoothed and the pics, panels and text box stay the
  chunky GB art they are.

  OFF by default, and **FULL neither sets it nor takes the row away** -- it
  is the one row that is not a knob on the look but on what the look COSTS,
  and only the player knows what their machine can carry. No hotkey, for the
  same reason: it is set once, not flicked while walking.


### Changed

- **The water surface is its own mesh, and its own pass.** A mirror cannot be
  drawn until what it reflects exists, so water is lifted out of the terrain
  mesh at build time and drawn between the world and the characters. The
  shoreline faces around it are untouched -- they belong to the GROUND that
  exposes them -- and the sun still sees the surface, so a tree at the water's
  edge still throws its shadow onto the lake.

- **The scene's depth buffer is a readable canvas.** It was an internal buffer
  that could be written and tested and never sampled; it is now the same
  buffer with a texture handle on it, at the same cost. Drivers that will not
  make one fall straight back to the old buffer and lose the reflections and
  nothing else.

- **The cast is reflected too -- by being drawn twice.** Gen 1 draws people
  over the world and water is world, so a surfing player has to composite
  OVER the water they are sitting on, which puts them after it; and a
  reflection can only hold what came before it. So the walkers, the NPCs and
  the authored figures are painted into the reflection COPY alone, where they
  are in the picture the water reflects and not yet in the picture the water
  is drawn into. Both draws go through one function, so they cannot come out
  different. The staged battle does the same with its two Pokemon.

  The ray march finds them the honest way round: a sprite is not in the depth
  buffer at that point, so a ray aimed at one passes through to the terrain
  standing behind it and reads the copy there -- where the sprite is already
  painted. The reflection lands a hair off the sprite's own depth and exactly
  on its colour, which at a lake's worth of wave is the same picture.

### Changed

- **The waves arrive in sets now, and a little slower.** Three fixed trains
  are an exactly periodic field -- every forty-odd pixels of sea wore the
  same crest at the same height, which reads as wallpaper the moment a lake
  is bigger than the repeat. Two long-wavelength fields now ride the
  dominant train, four to five carrier wavelengths apiece so neither reads
  as a wave itself: a SWELL that breathes its amplitude, so a few tall
  crests march through and hand over to a lull that is itself moving, and a
  BEND that bows its phase, so a crest line curves across the surface
  instead of ruling itself over all of it. The two lesser trains stay
  plain: they are texture rather than structure, and a third modulator is
  the soup the train weights exist to avoid. The step beat comes down from
  15 to 12 a second -- the crests were hurrying, and a big wave is slower
  than a walk cycle -- still a clean divisor of the engine's 60, and still
  exactly one world pixel of dominant-crest travel per step.

- **Staged battles draw their water plain, whatever the WATER row says.**
  The reflective pass is tuned for the overworld's ladder of cameras; a
  battle's camera is PLACED -- low, tilted, framed like a picture -- and
  under it the pass read wrong: Fresnel opened all the way up, the leaned
  sky landed on bands the framing never shows, and a lake-sized arena came
  out as murk wearing the tile art. The battle is a stage set, and stage
  water is painted: the flat animated tiles the mode always drew, with the
  mons compositing over them like everything else on the set.

### Fixed

- **On Android the water stayed flat, as if the row were off -- and once it
  did draw, it came up in blocks with the haze showing through the holes.**
  Three separate faults, every one of them invisible on desktop GL, run down
  on a Galaxy Z Fold 7 with the driver's own compiler errors in logcat:

  **The shader would not build.** Fragment floats default to **mediump** on
  GLSL ES while the vertex stage's default is highp, and the water shader is
  the mod's first to declare the same uniform -- the frame's `vp` matrix --
  in BOTH stages, one on each default; GLSL ES refuses to link that, and the
  pass fell back, quietly and by design, to the flat water the mode always
  drew. The pixel stage now lifts its float default to highp (guarded, so a
  GPU without fragment highp still compiles and falls back flat), which
  settles the link and is also simply needed: the march works in world
  coordinates that run to a few thousand, where fp16 has no fraction left.
  The world-position varying is qualified highp for the same reason the
  wireframe's always was, and the depth sampler too -- samplers default to
  **lowp** whatever the floats are set to, and eight bits of depth is a
  march with nothing to land on. One wrinkle inside the fix: LOVE's header
  forward-declares `effect()` under ITS default, and Samsung's Xclipse
  compiler treats a definition whose parameter precisions have drifted from
  the prototype's as an illegal overload -- so effect()'s own float
  parameters stay pinned to mediump, matching the declaration, and the
  maths above them runs highp regardless.

  **The depth test read the wrong texels.** The shader's own depth test
  normalised LOVE's pixel coordinate by the `screen` uniform, which counts
  canvas UNITS -- and on a highdpi phone (Android's density here is 2.625)
  a canvas holds that many PIXELS per unit, so the lookup ran to 2.6,
  clamped, and read edge texels across two thirds of the frame. Water
  discarded itself in blocks wherever the mis-read depth landed in front,
  and the haze backdrop showed through the holes. The coordinate is now
  normalised by `love_ScreenSize.xy` -- the bound canvas's own pixel size,
  measured in the same units on every display.

  **And the readable depth canvas** -- the one hardware requirement the
  rest of the mode does not already have -- now tries four formats before
  giving up: depth24, depth24 riding a stencil (a pairing some mobile
  drivers will texture when they refuse the bare format), depth32f, and
  depth16 as the floor every GLES3 device can read. Refused all four, the
  reflections are lost and nothing else, exactly as before.

- **Under BACK SPRITES some of your own Pokemon were see-through -- Pikachu,
  Seel, Dewgong, Chansey, Jigglypuff -- with the arena showing through the
  middle of them.** Those back pics are drawn as OUTLINES: everything inside
  the ink is the lightest shade, the decoder keys that shade to nothing, and
  on hardware it did not matter because the field behind them was white too.

  BattlePics already put that paper back by flooding the background inward and
  filling whatever it could not reach, and along the bottom of a figure it told
  a narrow opening (a belly the drawing ran out of, sealed) from a wide one (a
  stride, left open for the world to show through). Right for a mon standing
  on the map -- but the pinned back pic is not on the map, it is on the text
  box with its feet on row 96, and there is white box under its lowest row
  rather than arena. Every one of those mons leaks out through an opening far
  too wide to read as a drain, so the flood walked straight up inside them.

  A pic on the box is now told so, and its bottom edge seals: nothing reaches
  it from below at any width, and the rule stops being a heuristic -- paper is
  whatever the background cannot walk to from the left, the right or the top.
  Twelve of the game's 151 back pics turn on this; the other 139 come back
  byte-identical, and no front pic is touched at all.

  **And a hole is filled with the pic's own paper rather than with white.**
  Shade 0 is only white while the pic is still grays, and pics arrive here
  after the bake -- a species SGB colour, a BGP fade mid-animation, PAL_BLACK
  across the whole screen while the blackout text is up. A hardcoded white
  belly would have been the one lit thing on a blacked-out mon. The lightest
  shade still standing in the pic is that colour, and every one of the game's
  battler pics keeps at least one such pixel -- an eye, a highlight down a
  cheek -- so what goes back is the baked shade itself.

### Known

- Screen-space reflections can only reflect what is in the frame. A tree just
  off the top edge is not in the water below it, and a reflection whose ray
  runs off the side of the screen fades into the sky rather than ending on a
  hard line.

## 1.3.1

### Fixed

- **A staged battle on a phone stood some Pokémon three times the size of the
  square they were on.** A Pidgey towered over the arena while the mon beside
  it was the right size, which reads as a bug in one species and is not one.

  Putting the paper back inside a battle pic (BattlePics, 1.3.0) needs the
  pic's pixels, and a LOVE Image does not hand them back -- so the pic is drawn
  into a canvas of its own size and the canvas is read. `newCanvas` takes the
  SURFACE's dpi scale when it is not told otherwise, `conf.lua` turns highdpi
  on for Android and iOS, and Android's display density is routinely 2.75. So
  `newCanvas(56, 56)` allocated a 154x154 texture there, the pic was magnified
  into it, and the readback came back at the magnified size. The rebuilt pic
  was 2.75x the artwork, the engine's pics layer drew it 1:1 because it trusts
  `getWidth()`, and the mon stood on its tile nearly three times too big.

  Only a pic with an enclosed hole in it is rebuilt at all -- the rest are
  handed straight back untouched -- which is why it hit some species and not
  others, and why it never showed on desktop, where the dpi scale is already 1.
  The readback now asks for one texel per pic pixel, the way the engine's own
  `PixelCanvas` does for the same reason. The animated-tile atlas readback took
  the same fix: on a phone it would have come back magnified too, and every
  tile coordinate in it counts in eights from the top-left.

## 1.3.0

### Added

- **BACK SPRITES, a new row under 3D-BTL: your own Pokémon stays on the battle menu.**
  The staged shot stands both mons on the map, which is the mode's whole claim
  -- and it costs the framing Gen 1 is most recognisable by: your own Pokémon,
  seen from behind, sitting on top of the battle menu with its feet on the box.

  With BACK SPRITES on the foe is still geometry standing on its own tile at the far
  end of the arena, and the player's side goes back to being the GB's own flat
  back pic in the GB's own slot: same art, same 2x, same feet on row 96. It is
  the engine's own pics layer that draws it, through the `onlySide` argument
  that layer already takes, so every pic effect -- the grow-out-of-the-ball,
  the faint slide, the damage blink, the send-out trainer pic -- comes along
  unchanged and none of it is reimplemented.

  Nothing else about the shot moves. The arena, the camera and the drift are
  solved exactly as they were, so the foe stands where it always stood and the
  player's cell is simply empty ground in the foreground. Two things follow the
  setting: the `pokemon.sprite` hook stops asking for the front pic on the
  player's side (it is a back view again, and the front art would be that mon
  turned round to face the player it belongs to), and the move-animation offset
  drops that side's contribution, because a pic that has not moved cannot have
  moved the pair's centre.

  OFF by default -- what the mode advertises is the two of them out there --
  and only on the OPTIONS menu while 3D-BTL is on, since with staged battles
  off the engine already draws exactly this.

### Fixed

- **Battle pics were see-through, and it took a back sprite on a tiled floor
  to make it obvious.** Gen 1 pics are two-bit art whose lightest shade is
  white, and the decoded PNGs key that shade to alpha 0 -- which cost nothing
  when the field behind them was white too. Over a route, every belly, every
  eye white and every highlight is a hole with the world showing through, and
  the mon reads as a stencil.

  `BattlePics` exists to put that paper back and, as written, put none of it
  back. It flood-filled the outside from the border and filled what the flood
  could not reach, which is exact and, on this game's art, empty: a Gen 1
  figure is an open drawing, and its belly walks out to the border through the
  gap between its legs. Read across all 305 of the game's battle pics, that
  rule finds an enclosed hole in exactly none of them.

  The fix is to start the flood somewhere else: at the edges of the ARTWORK'S
  OWN BOUNDING BOX, and at three of them -- left, right and top. The bottom is
  closed, because it is not a side the background is behind, it is where the
  drawing was CUT. A pic is bottom-aligned in its slot with all the margin at
  the top, so a mon's lowest row is the last row it was given and everything
  below the belly simply stops. Treat that cut as open and the background
  pours up inside the figure, which is the channel of world that used to show
  through a Clefairy.

  That is exact rather than a heuristic: nothing is filled because of what
  surrounds it, only because the background provably cannot reach it. Which is
  why it needs no idea whether it is holding a front pic or a back one -- the
  sky between a pair of ears reaches the top edge and stays sky, the gap
  between a body and a raised tail reaches the side and stays gap, the belly
  reaches neither and is paper. The silhouette is untouched, so the mon still
  cuts cleanly against the world.

  It replaces the border flood outright rather than sitting beside it, since
  anything the border could not reach the box edges cannot reach either.

  The bottom edge needs one more distinction, because two different things
  meet the underside of a figure. A DRAIN is where the drawing ran out -- a
  belly whose white carries on down until the artist stopped, leaking out
  through the inch between a body and a leg -- and is sealed. A MOUTH is the
  space between two legs, background that happens to be enclosed on three
  sides, and is left open so the world shows through a trainer's stride.

  Width tells them apart, and on this game's art it is not a close call.
  Measured along the bottom of every battle pic, the drains run 3 and 4 pixels
  (Clefairy's back, Wartortle's back, Red's back) and the mouths run 10, 12, 14
  and 17 (a Rattata's underbelly, Blue's stride, Brock's, a Pikachu's back).
  Nothing lands between 4 and 10, so the cut is taken at 6 with room either
  side rather than tuned to one sprite. Apart from that number the rule stays
  exact.

  Front pics come back untouched, and not by being special-cased: they are
  near-solid silhouettes with almost nothing inside them to fill, so their own
  shape is what says so.

  Both mons were affected -- the cards in the arena as much as anything -- so
  this lands wherever a battle pic is drawn over the world, not just under
  BACK SPRITES.

- **The pinned back pic was lit at noon while the world behind it was not.**
  Everything standing in the arena goes through the voxel shader, and that
  shader multiplies by the hour's tint, so at dusk the diorama warms and at
  night it goes blue -- the two mons' cards included, because they are drawn
  in the same pass as the ground they stand on. A back pic pinned to the menu
  is not in that pass; it is a flat blit over the finished shot, and it stayed
  bright over a midnight route.

  The same tint is now applied to that one draw, by multiplying every colour
  the pics layer sets on its way past -- so the alpha, the faint slide's fade
  and the damage blink all compose with it instead of being overwritten. What
  it does not get is the sun: the cards are shadow-mapped and a pic pinned to
  the menu has no position in the scene to be shadowed at, so it carries the
  hour and not the weather.

### Added

- **The hour reaches the FLAT world too, not just the diorama.** DAYTIME drove
  the 3D pass through the voxel shader's own tint uniform -- a uniform the 2D
  tile path never runs -- so with VOXEL off, the same evening that fell on the
  diorama left the flat world at permanent noon. One clock, two worlds, one of
  them ignoring it. Outdoor maps now get the same multiply, painted as one
  rectangle over the composited world.

  The whole difficulty is WHERE, and it is worth writing down. Not on the world
  canvas: in a colorized mode that canvas is grayscale art and the blit that
  puts it on screen runs it through the palette shader, which classifies each
  pixel into a shade BY ITS RED CHANNEL -- multiply a night blue over it first
  and every pixel lands in the wrong bucket, so the world does not darken, it
  changes colour. Not over the finished frame either, or the dialog boxes and
  menus darken along with the world they are held up in front of, which is the
  same reason the tilt-shift blur is a `worldPresent` and not a `present`.

  Which leaves the instant between the world blit and the UI blit, and the
  engine has no seam there -- `worldPresent` only runs when a PIPELINE produced
  the world, which in flat mode is precisely what did not happen. So
  `Renderer:endFrame` is wrapped and the UI canvas's own draw is watched for:
  `blit` passes the canvas it is compositing as the first argument, so the
  first draw of `Renderer.canvas` IS the boundary, by identity rather than by
  counting. The shader and scissor that call arrives under belong to the UI
  blit already in progress, so both are put aside for the rectangle and handed
  straight back.

  Skipped entirely when a pipeline drew the frame (it tinted itself, and twice
  is wrong), indoors (a room has no sky to take its light from), and at midday
  (a multiply by white) -- so a game with the clock at DAY issues not one extra
  call.

### Changed

- **FULL no longer takes the two battle rows off the menu.** It still owns the
  rows that describe the LOOK -- the wireframe, the horizon bend, the blur, the
  hour -- because it is a preset for the diorama and a row that no longer
  decides anything is worse than no row. 3D-BTL and BACK SPRITES are not that:
  one decides what a fight is drawn OVER and the other how it is framed.
  FULL still SETS both on arrival; it does not hold them, and leaving them
  reachable is the difference between a preset and a lock.

  This makes `stagedBattles()` honest as a side effect. It used to answer yes
  under FULL as well, on the grounds that FULL owned the 3D-BTL row and
  switched it on -- safe only while the row was hidden. With the row reachable
  from inside FULL, that clause would have claimed staged battles for a preset
  the player had just switched them off inside, pinning BATTLE LAYOUT to OG for
  a fight that never gets staged. The row is the only thing that decides now,
  which is what `OverworldBattle.begin` and `wantsFront` already believed.

- **TILT and GBC FX are off the OPTIONS menu entirely while this mod is
  installed.** Both fight the diorama and both were already half-taken: the
  mode's own key forces them off on every press, and the registry switches
  TILT off whenever a world pipeline takes the pass. What was left was two
  rows a player could set and watch get reverted -- TILT being the flat fake
  of what this mode does for real, and GBC FX a full-screen present pass over
  the top of the whole thing.

  Dropped AND held at zero, which is the part that matters: hiding a live
  setting is a trap, because a save written before the mod was installed can
  carry TILT 3 and a row that is not there cannot turn it back off. Pinned
  wherever the value could arrive from -- the menu opening, a save being
  loaded or begun -- so there is no route by which either is on and
  unreachable. Uninstalling the mod puts both rows back, at whatever they were
  last set to.

- **The battle's text box and menus are frosted glass, like the HUDs.** The
  HUD blocks got panels because black glyphs on grass are not readable. The box
  at the bottom had the opposite problem and the same cause: it is drawn as an
  opaque white slab with a black border, which was the field's own colour back
  when the field was white and is a sheet of paper laid over the bottom third
  of the diorama now that it is not.

  It gets exactly what the HUDs get -- the world behind it, blurred to frosted
  glass and laid back down translucent, at the same frost and the same tint --
  and it is measured into the same brightness verdict, so the ink over the menu
  flips white with the ink over the HUDs rather than against it. Only the FILL
  is taken away: the border, the text, the cursor and the down arrow are the
  engine's own glyphs in their own places. The move menu's TYPE/PP box and
  Mimic's copy menu get their own panels, trimmed to the rows above the box
  below them so no pixel is frosted twice.

## 1.2.1

### Fixed

- **On Android the sky went black below its first couple of bands.** A hard-edged
  band of black ran from partway down the gradient to the horizon point, with the
  moon still hanging correctly inside it. Desktop was unaffected.

  What gave it away is that the same colour reached the screen by two routes and
  only one of them was wrong. The haze filling the void UNDER the horizon is the
  sky's palest band, and it is delivered by `love.graphics.clear` -- it landed
  correctly. The bottom of the sky above it is that same band delivered by the
  shader, and it was black. So the palette was not reaching the fragment shader,
  and nothing was wrong with the palette, the layout or the camera.

  The bands went in as `uniform vec3 bands[8]`, filled from Lua and read through
  a loop counter, and on Android's GLSL ES the tail of that array arrived as
  zero -- which is black. The likeliest reason is the fragment uniform budget:
  ES 2.0 only guarantees sixteen uniform VECTORS, and eight band slots plus the
  twilight glow plus LOVE's own built-ins is over it. A driver that truncates a
  partly-filled array, or one that reflects `bands[0]` and nothing after it,
  fails identically -- so the fix removes the whole class rather than the one
  cause.

  The bands are a one-texel-per-band TEXTURE now, sampled nearest, with the
  band index clamped against the ramp's width. One texture unit replaces eight
  uniform vectors, there is no array to index and no budget to overrun, and a
  sample past the last band lands on the last band instead of on nothing. It is
  still a palette and not a picture -- one texel per band on a single row -- so
  the sky is still computed per pixel at the size it is displayed at, with
  nothing resampled and nothing baked.

  Also gone with it: `clamp(x, 0.0, 0.999999)`, which rounds its bound to 1.0 at
  mediump -- the fragment default on GLSL ES -- and would have indexed one past
  the last band on the sky's bottom row for the same black result.

## 1.1.1

### Fixed

- A move that shakes the screen no longer whites out the frame. The zone pass
  fills each zone with its blank colour before drawing the shifted copy -- the
  hardware showing empty BG in the strip the shake vacated -- and a shake
  program alternates offset and no-offset frames, so over the map that read as
  the whole battle screen, menu box included, flashing white a few times a
  second. The fill is dropped while a battle is staged on the map; the shake
  itself still moves the HUD.

## 1.2.0

### Added

- **A gradient sky behind the diorama, on every `VOXEL` rung.** The void behind
  the world used to be a black plate at every rung but the top, where it became
  one flat blue -- enough while that void was a sliver, and a wall of paint once
  the horizon came into frame.

  It is the 8-bit skybox recipe now: four blues painted as flat horizontal bands,
  deepest overhead and palest at the bottom, with a CHECKERBOARD of the next band
  dithered into the bottom 40% of each one. Alternating two colours on a pixel
  grid is how a machine with four to a palette got a fifth, sixth and seventh out
  of them, and it is what keeps four bands reading as a gradient rather than as
  four stripes. Every channel of the palette is a multiple of 8 -- where a
  five-bit GBC channel lands -- so no colour in it is one the hardware could not
  have shown. No clouds, nothing moving.

  Where the bands END is the camera's own answer. At `75` the ground plane's
  vanishing line is genuinely in frame -- projected through the same matrix the
  geometry is drawn with -- and the pale end meets it. At the steeper rungs that
  line is above the top edge, and what shows up there is the ground running OUT
  past the map edge instead, so the bands take a fixed slice of the frame and the
  haze fills the rest. One sky across the whole ladder either way.

  **Nothing is resampled**, which is why it is drawn the way it is: no baked
  160x144 image scaled up to the window, no downsized buffer blown back up, no
  texture at all. One rectangle through a shader answers every pixel from its own
  canvas coordinate, so a pixel of sky is computed at the size it is displayed
  at and there is nothing for a filter to soften. The band edges and the dither
  cells are measured in the pass's own pixels-per-world-pixel, handed in fresh
  every frame -- so a `ZOOM` keypress is reflected in the frame that follows it,
  with nothing cached at the old scale, and the sky's grid is the same grid the
  world's own texels sit on.

  The palette goes through the display-mode transform like every other palette in
  this mod, so GRAY gets four greys and CLASSIC four greens. Below the bands the
  void is filled with the palest of them -- which is also what the bottom band
  ends on -- so the join has no seam, and a driver that cannot compile the shader
  gets flat bands and a logged line rather than a wrong sky.

  The overworld only. A battle is a staged shot whose placed camera has the
  horizon above the frame, so the arena keeps exactly the flat sky it had.

- **A day/night cycle**, on a new **DAYTIME** options row: `DAY`, `NIGHT`,
  `DUSK`, `DAWN`, `SYNC`, `CYCLE`. One twenty-minute clock underneath all of
  them -- ten minutes of sun, ten of moon -- where the four named settings
  are PINS on that dial (noon, mid-night, sunset, sunrise), `CYCLE` lets it
  run, picking up from whichever pin or SYNC sky the player was just looking
  at, and `SYNC` -- the DEFAULT -- lays the machine's own clock onto the
  dial: local noon is the DAY pin, midnight is NIGHT, six and eighteen the
  twilights, an hour of the real day is fifty seconds of dial. Everything is
  a pure function of the clock, so the pinned DUSK is exactly the running
  cycle stopped at sunset. While **VOXEL** sits on `FULL` the DAYTIME row is
  HELD at `SYNC` and taken off the menu with the other rows the preset owns
  (DayNight.forceSync, enforced from the preset, the rows hook and the
  manager's options_changed -- the same three places BATTLE LAYOUT's pin
  lives): the full diorama runs on the real sky.

  **The sun and the moon are in the sky**, and their positions are honest:
  the disc is the light's own direction projected through the same matrix the
  geometry is drawn with, so it stands over the point on the horizon its
  shadows point away from, at every pitch, window shape and zoom. The sun's
  noon is this mod's existing sun to the digit -- southeast, 45 degrees up,
  overhead behind the north-facing camera and correctly out of frame -- and
  its arc swings north at both ends, so the disc stands IN frame through dawn
  and dusk, rising half-set on the horizon. The moon arcs the northern sky
  all night, due north (screen centre) at mid-night, with scaled crater
  cells. Both are cell art on the sky's own dither grid, sized by the frame
  (a celestial body's apparent size is an angle, so zooming the ground does
  not swell it), and both are SCISSORED to the sky's region: the horizon
  point is where a setting body disappears -- it never hangs under the map.

  **The sky follows the clock.** Phase palettes -- the daytime blues,
  gold-to-violet dawn, a hotter gold-to-indigo dusk, moonlit navy -- six
  bands each now, blended along the dial and re-quantised onto the 5-bit
  lattice, so every mixed frame is still a colour the hardware could show.
  The blends bend through designed WAYPOINTS rather than straight across --
  a golden hour on the way into dusk, a violet civil twilight either side of
  the night -- because day's blue and dusk's gold are near-complements, and
  a straight lerp between complements bottoms out in dishwater grey. Through the twilights a posterised, checker-dithered GLOW
  warms the bands around the low sun -- painted light, not an airbrush. The
  blends are 75 seconds wide either side of each twilight and the pins land
  on their phase palette unmixed.

  **The shadows follow the sun and the moon.** The shear every shadow is
  thrown by (direction opposite the body's bearing, length its elevation's
  cotangent, clamped at twice the caster's height) comes off the clock, the
  shadow map's signature carries it, and the light's press fades out over the
  last twelve degrees before the horizon -- so sunset hands off to moonrise
  through a soft shadowless gap, and moonlight presses at about two-thirds
  the sun's weight. The scene shader also multiplies every surface by the
  hour's tint: neutral at noon, warm at the twilights, dim blue at night.

  **Outdoors only**, by the same `Map.isOutdoor` test the sky already rests
  on: indoors keeps the noon rig, the neutral tint and no sky -- a cave at
  midnight is exactly as dark as a cave at noon. Viridian Forest is the case
  between, a CANOPY map (DayNight.CANOPY): there is no sky to paint and no
  sun to see, so the shadow rig stays the mod's fixed noon light -- all that
  ever filtered through the leaves -- but night still FALLS in a forest, so
  of everything the clock does, exactly one thing reaches it: the hour's
  tint, in free-roam and staged battles alike. A battle staged on an
  outdoor map fights under the hour: the night sky behind the arena, the
  tint on the mons, the sunset taking the arena's shadows with it; an indoor
  arena is untouched. The engine's own `world.tod` hook is answered
  (`MORNING`/`DAY`/`EVENING`/`NIGHT`), so palette or music packs keyed to the
  period ride this clock for free.

  **The clock rides the save slot.** On the engine's `save.writing` event the
  cycle's time is written into the mod's own save-file bucket
  (`save.modData.DRAMATIC_SHAPE`), and read back when a save is opened. A
  save with no clock in it starts at day.

- **Window glass.** The panes in the overworld art -- the framed squares on
  building fronts, the small lights in doors -- are found by SHAPE in the
  tileset image (a black border row, four or five black-flanked glass rows,
  a closing border), at pixel granularity because the door's pane straddles
  a 2x2 tile block. No tile ids are hardcoded: a conversion that draws its
  own windows in the same idiom gets glass for free. The scan yields a mask
  texture aligned to the tileset atlas, which the scene shader samples with
  the same coordinates the terrain does -- so the effect lands on any wall,
  at any angle, in free-roam and staged battles alike, with no geometry
  work.

  By day a thin glint crosses the panes WHILE THE VIEW MOVES: the sweep's
  phase is fed by the camera's own travel and its strength fades out within
  a beat of standing still -- a reflection is something the viewpoint does,
  so still camera means still glass. The sweep pattern lives in the pane's
  OWN texels, not the screen's: a screen-anchored pattern has the world
  sliding through it at zoom speed whenever the camera pans, which strobed
  (worst walking against the sweep); anchored to the glass, panning moves
  nothing and a step advances the glint a fraction of a texel, the same in
  every direction. It lifts the texels toward sky-white and leaves the
  shine art visible through it. The mask is consulted only by meshes
  textured from the tileset atlas (Voxel3D.glass), never by sprite sheets,
  whose coordinates would land on the panes' atlas positions by accident.
  After dark the panes are LIT: the texel's own pattern carried into a warm
  lamp colour, replacing the shaded answer entirely -- a lit window ignores
  the sun, every shadow and the hour's tint, exactly as a window with a lamp
  behind it does. The lamps follow the clock (DayNight.windowLight): on
  through dusk, full all night, mostly out by dawn, and never lit indoors.

- **A fade out of a battle, where there used to be a hard cut.** The engine
  wipes INTO a fight with one of the original's eight transitions and cuts
  straight out of it: `BattleState:finish` pops itself and the map is simply
  there on the next frame. Between a white field and a tile map the original got
  away with that; between a placed camera looking across an arena and a diorama
  looking down on a walking player it reads as a glitch. The battle now fades to
  black, closes behind it, and the map fades up out of it -- twelve frames each
  way, registered as a `voxel_battle_exit` transitions record so the timing is
  retunable in data like the wipes it answers.

  Only while voxel mode is on, and then for EVERY battle, including one that
  found no arena and drew on the flat battle screen: what is being smoothed over
  is the return to the map, and the map is a diorama either way. With the mode
  off, the vanilla cut is untouched.

  One black rectangle over the FINISHED composite does the fading, so the world,
  the letterbox bars and the battle's own text box all darken by the same amount
  -- the renderer's existing warp-fade overlay is painted between the world and
  the UI, which would have left the text box bright over the black. A blackout's
  own warp fade or an evolution prompt still owns the way out when it takes the
  screen: the fade stops at the cut rather than fading in over the top of it.

- **A `FULL` rung on the VOXEL row**, directly after `OFF`. One choice that
  puts the whole mode in its intended state -- the 35-degree camera, the
  miniature blur at maximum, the horizon flat, the view fitted, and battles
  on the map -- rather than making a player assemble it from four rows.

  While it is selected, every row it owns comes OFF the menu: V-GRID,
  V-CURVE, 3D-BTL and T-SHIFT. A row that no longer decides anything is
  worse than no row. Stepping onto or off `FULL` rebuilds the open menu in
  place, so the rows leave and return under the cursor instead of waiting
  for the menu to be reopened.

  It applies its settings when the row ARRIVES at `FULL`, not every frame:
  holding them would make the zoom keys and the wheel dead while it was on.
  Leaving it deliberately undoes nothing -- reverting would discard whatever
  had been changed since.

### Fixed

- **The hit flash whited out the whole screen.** The engine draws it as a
  full-screen white rectangle, which is a flash on a white battle field and
  a whiteout of the map, the HUD and the text box over a world. It is now
  dropped on the way past and put back where it was ever about: the two
  Pokemon go solid white for those frames, silhouette and all, and nothing
  else in the frame moves.

- **A scripted battle cut straight in with no transition** (an ENGINE seam,
  fixed in `src/script/Commands.lua` rather than in this mod): the rival in
  Oak's lab, and every `start_battle` script, pushed the BattleState bare --
  no flash, no wipe, the theme starting late -- where the original wipes
  into scripted fights like any other. `start_battle` now routes through the
  overworld's own `pushBattle`, which is also the path this mod wraps, so a
  scripted fight gets its arena staged and the cast culled BEFORE the wipe
  instead of catching up behind it. A battle scripted with no overworld
  under it still starts bare, and no music plays twice (BattleState's own
  start is a same-song no-op).

- **A standing figure's shadow detached from its feet under a low sun.** The
  shadow compare forgives `slack` world pixels so lit ground does not acne
  against its own texels, and that same forgiveness lit the first `slack` of
  every cast shadow -- so the shadow started a bias-width away from the feet,
  further the lower the sun reached (the classic peter-panning, invisible at
  the old fixed 45 degrees and plain at a day/night golden hour or under the
  moon). Sprite cards -- characters, authored figures, flowers, battle mons
  -- are now drawn into the shadow map snugged TOWARD the sun along their
  own ray (`ShadowMap.snug`): moving along the ray changes nothing about
  where a shadow falls, but storing the card shallower takes three quarters
  of the forgiveness back for the shadow it throws -- and for nothing else:
  no terrain moved, so the acne margin is untouched where it matters. The
  obligation that comes with it: every snugged caster's LIT draw hands the
  same snugged transform to its own shadow lookup (Voxel3D.draw's
  `sunModel`), so stored and lookup agree exactly and the compare keeps its
  full margin -- read un-snugged, the missing nine tenths showed up as
  diagonal moire bands crawling across every sprite. The shadow root lands
  back under the feet at every hour.

### Changed

- **Under `VOID FILL: TREES` the border wall is modelled trees or nothing.**
  Only the first block past the map body gets carved into round trunks and
  canopies; the two blocks past that were too far out to be worth the quads,
  so they fell through to the mesher's plain box and came out as a flat-topped
  slab of tree ART sitting beside the modelled forest -- a painted-on plateau,
  and the more obvious the lower the camera got. Rather than pay to carve
  hulls nobody walks near, the wall now simply STOPS where the carving does:
  `Structures` does not build the ring past that distance (the same "nothing
  out there" `BLACK` already produces), and the mesher drops any cell inside
  it the 2x2 canopy grouping could not claim, so no strip of boxes survives at
  a corner. `WATER` and every indoor border are untouched -- a flat sheet of
  water is what water looks like from above anyway.

- **The two HP boxes snap to the window's edges during a staged battle.** The
  battle screen is 160x144 in the middle of the window and the world is the
  whole of it, which left both HUD blocks huddled together in the middle of the
  frame with map showing on either side of them -- a Game Boy screenshot pasted
  over a diorama rather than the diorama's own furniture. The foe's block now
  sits against the left edge and the player's against the right, on the same
  frosted glass, with the same tiles at the same size on the same rows. The
  pokeball rows and the safari ball count travel with the block whose rows they
  share. On a window shaped like the GB screen there is nowhere to go and
  nothing moves.

  The engine draws them into the 160x144 canvas, which clips at its own edges,
  so the layer is rendered to a texture and composited into the world image --
  the one surface here that covers the whole window. A driver that cannot do
  that falls back to the HUD in the frame rather than to no HUD.

- **`BATTLE LAYOUT` is pinned to `OG` while battles are staged on the map**, and
  the row comes off the OPTIONS menu with the rows `FULL` owns. The staged shot
  is composed in the GB's own frame -- the arena camera is solved to put a cell
  under each pic's feet, and the HUD rects and the intercepted background fill
  are measured there too -- and `WIDE` re-lays that screen out on a 304x144
  surface, moving every one of them. Set rather than worked around, on every
  route in: the options row, hotkey `8`, the mod manager's page, `FULL`'s
  preset, and a save that arrived with `WIDE` already on. Switching `3D-BTL`
  off hands the row back with `WIDE` selectable again.

- **Hotkey `3` walks the angle rungs only and steps over `FULL`.** The key is
  a display-mode cycler -- it should change the camera and nothing else --
  and `FULL` reaches in and rewrites four other settings. Landing on it
  mid-walk would silently push the blur to maximum and flatten the horizon
  with nothing on screen saying a keypress had done it. `FULL` stays on the
  OPTIONS row, where a preset that changes other rows belongs.

  A press FROM `FULL` goes to `50`. `FULL` is already the 35-degree camera,
  so stepping to the rung of that name would look like the key had done
  nothing. Matched by angle, so it follows `FULL` if that is ever retuned.

- **The mode's four options are one block in the menu.** The engine splices
  a pipeline row in beside TILT and lands a mod's own rows at the end of the
  list, which had these four in two places with unrelated engine rows
  between them. The settings now follow the pipeline rows directly.

## 1.1.0

### Added

- **Battles happen on the map you were standing on.** The battle screen's
  white field is replaced by the world: the mod finds the nearest patch of
  open ground, points a placed over-the-shoulder camera at it, and draws the
  fight over that. New **3D-BTL** row and hotkey `8`, on by default.

  The arena is a 3x6 clearing of cells the player could walk on, with the
  two mons three cells apart down the middle column and a one-cell apron all
  round so the camera looks across floor rather than into a wall. Where no
  map has room for that -- a corridor, a cave, a shop -- the search relaxes
  to a 1x4 corridor with the apron given up, and where even that will not
  fit the battle draws exactly as it always did.

  Everything else in the frame is the engine's own. The mon pics, HUDs, HP
  bars, move animations, faint slides and text box are drawn by BattleState,
  in its order, at its coordinates -- the GB's own layout, with the player's
  mon low and left and the enemy's high and right, which is why the camera
  is placed east of the arena axis rather than the layout being moved to
  suit the camera. What changes is what is behind them.

  Three things carry the shot. The overworld's cast is culled before the
  wipe, so it plays over an empty map and no bystander is standing in the
  arena. The camera drifts on a slow orbit about a point between the two
  mons, which moves the near ground and the far ground by different amounts
  -- parallax, not a sliding backdrop. And a depth-of-field pass holds the
  band of frame the two mons stand in sharp and softens the middle distance
  and the foreground; both mons are in focus by construction, because they
  are drawn as the battle screen's own pics after the pass has run.

  **Nobody moves.** The arena is where the CAMERA goes. Nothing here writes
  a cell, a facing, a flag or a warp, so a trainer's post-battle dialogue is
  still talking to someone standing in front of them, and the blackout path,
  sight lines and every script find the player exactly where they left them.

  The two HUD blocks gain the backing the white field used to be. Gen 1
  draws them as black glyphs straight onto the background with no box round
  them, and black-on-grass is not readable; the backing is painted inside
  `drawHUDs`, so it lands in the same target and takes the same zone colour
  as the HUD it sits under, in both the colorized and flat pipelines.

  Declines cleanly at every step it cannot take: no depth support, no open
  ground, the row switched off, or a terrain mesh still building all end at
  the battle screen the engine has always drawn.

### Changed

- **Characters are flat sprite billboards, and nothing about a sprite is
  voxelized any more.** Every figure -- the player, NPCs, the ghosts
  standing on a neighbour map -- is now its current 2D frame on a single
  flat quad, with the shader's alpha discard cutting the exact silhouette
  out of it. It still faces south and leans back by the camera's pitch,
  so it reads face-on at every tilt exactly as before.

  Two things went away with that. The contoured slab, which gave each row
  a thickness measured from the sheet's own side view; and the carved
  visual-hull models (`lib/VoxelModels.lua`, `tools/build_voxels.py`, and
  ~70 generated files under `assets/voxels/`, 2 MB), which reconstructed
  a figure from its three drawn views.

  A sprite is a DRAWING, not an object seen from one side. Gen 1's
  overworld figures are 16x16 icons with a fixed front-on reading, and
  turning one into a solid invents a body the artist never drew and the
  game never implied. The shipped models were also the one place this mod
  carried a description of the ROM art -- a carve is a faithful record of
  a sprite's silhouette, pixel for pixel -- which sat badly against a mod
  that otherwise ships no game data at all.

  The flat card is cheaper on every axis: no pixel access (only the
  sheet's dimensions), one quad instead of hundreds of faces, and one
  mesh shared by the solid draw, the sun pass and the player's occlusion
  silhouette. That sharing is load-bearing rather than tidy -- the
  silhouette draws with the depth test inverted, and any self-overlap in
  the mesh would read as "behind something" and repaint the figure on
  open ground.

  A mod can still ship `overrides/voxels/<name>.lua`; that path is
  unchanged and still wins where it exists.

## 1.0.6

### Added

- **Conditional pins.** A profile entry may now carry `when_above`:
  tile id -> rules keyed on the tile drawn directly north of it,
  resolved per POSITION in `TileShape.at`. A pin is per tile id and one
  graphic can mean two things -- the route gates' `$32` is both the
  wall's dark base course and every service counter's front, and it is
  the bottom row of its cell either way. Pinned `wall` the counters
  stood a full 16px; pinned `counter` the deep wall banks corrugated
  16/8 for sixteen rows and the room read as crates. What separates the
  two uses is what sits on top, so that is what the rule reads. The
  gates now have half-height counters AND level walls.

- **The Pokemon Tower has an exterior.** It is the one catalogued
  building drawing the map edge cuts off (no roof band is on the map at
  all), and it had no `buildings` entry, so it fell to the volume path
  -- which tops a run by repeating its first two rows, laying window
  courses flat across the plateau. Sealing the silhouette on the north
  alone closes it (88% fill, one piece, against 37% and 126 pieces
  unsealed), and one row of roof band spent on the drawing's top margin
  costs no window course. It stands as a real tower, panes recessed,
  door on the ground.

- **The Indigo Plateau statues stand up**, built exactly like the gym
  statues: plinth a solid 16px block, figure a per-pixel cutout riding
  it. On the avenue the statues stack with no gap, so the flood joined
  six of them into one 24-row region and the volume builder raised
  ridges of boxes with the statue art folded on the front. The same
  bird is drawn at the foot of every badge-check pillar, so those are
  crowned too.

### Fixed

- **Tall grass: one clump per tile.** Each 8x8 tile is a whole clump,
  but the template split every tile AGAIN into its top and bottom four
  art rows and stood those at two different depths -- so any blade
  running down a tile was cut in half, into two 4px stubs 4px apart.
  One tile is now one full-height standing slab at its own depth; a
  cell's 2x2 tiles still stand independently, so the player walks
  between the north and south rows.

- **Ledge lines are continuous.** `$34` is the cliff slope's foot and
  also the pillar between hop-down segments; pinned `wall` with the
  rest of the slope chain (the Diglett's Cave fix) it stood those
  pillars 16px beside a 6px lip. At ledge height the run reads as one
  lip, and the mound is unchanged -- its foot row reads as the talus it
  is drawn as.

- **A prop only stands on furniture when its own cell is blocked.**
  "Is something drawn above me" is not "am I standing on it": a chair
  drawn against the north side of a table is above the table's trim row
  too, and was being lifted onto the tabletop, with its claimed cells
  re-tiled as tabletop so the table marched two rows north. Three
  chairs in Cinnabar's trade room and Fuchsia's meeting room, and the
  Celadon diner's stools. The world already knows the difference: a
  thing that sits ON furniture occupies a blocked cell, a seat you walk
  up to is in a walkable one.

- **Caves: nothing below sea level, and the water is water.** Two tiles
  were identified backwards in the first pass. `$14` -- the tile the
  engine animates, that `Map.WATER_TILES` names and that Surf runs on
  -- was pinned `wall`, so Cerulean Cave's lake and the Seafoam sea
  stood up as rock slabs. And the pale dithered rock fill was pinned
  `water`, cutting 612 tiles of two-cell-wide trench through four maps.
  Both corrected; a sweep of all 19 cave maps now reports zero tiles
  below the datum. The elevation scheme is documented in the entry and
  derived from the game's own `tilePairs`: dark floor, water and drop
  holes at 0, the lit shelf a 6px step above, rock at 16.

- **Cave ladders climb.** Which ladder graphic goes up and which goes
  down is unanimous in the warp table -- 37 cells of one always warp
  down, 40 of the other always up -- so they are real stepped flights
  now, not painted plates.

- **Poke Mart's register stands on the counter.** The pin was on the
  wrong tile: `$08` is the counter's own top band, not the register, so
  the standee flood ate everything but two black lines. The register is
  the keypad-and-receipt drawing one row up.

- **Celadon's televisions**, which were solid 16px boxes wearing the TV
  art on one face, and the **Pokemon Tower reception desk** and the
  **gate counters**, which stood at wall height, are all their drawn
  heights now. The **Fan Club and Silph boardroom statues** were read
  as seated chairmen and painted onto the tabletop; they are cutouts
  standing on their pedestals, and the tables are cut to a true
  octagonal footprint.

## 1.0.5

### Added

- **Every remaining interior is furnished.** The profile covered ten
  tilesets; it now covers twenty-three -- 1,190 pinned tiles across
  `GATE`, `FOREST_GATE`, `LOBBY`, `MUSEUM`, `LAB`, `MANSION`,
  `INTERIOR`, `CLUB`, `SHIP`, `SHIP_PORT`, `FACILITY`, `CEMETERY` and
  `UNDERGROUND`, plus full entries for `CAVERN` and `GYM` which had only
  stubs. Roughly 130 maps, surveyed against the standard the finished
  interiors already set: one 16px wall band carrying whatever is drawn
  built into it, half-cell counters so the drawn front folds up and the
  top stays on top, `bookcase` collapse for free-standing shelves,
  thin-pool standees for plants, and small objects riding the furniture
  they are drawn above.

  What the detector was doing before, by way of what changed:

  - **Rooms with no walls.** Three tile ids (`$14`, `$32`, `$48`) are
    claimed by the engine's water set in EVERY tileset, and collision is
    per CELL, so one of them in a cell's bottom-left corner sank the
    whole cell. `$32` draws both the route gates' wall base course and
    every counter front, so all 25 gate maps were a checkered floor in a
    moat; the same trap put ponds through two thirds of Seafoam B4F,
    under every museum vitrine, along the S.S. Anne's wall corners and
    across Silph Co 1F's lobby island. The set is wider than three ids
    in practice -- `LAB`, `MANSION` and `INTERIOR` each hit six to nine
    -- because the test is per cell, so an innocent tile sharing a cell
    with a trapped one sinks with it and has to be pinned too.
  - **Towers and fused monoliths.** Counters raised to 48px dragging
    their wall band with them, merchandise racks fused sideways into
    32px blocks four tiles deep, cave shelf edges standing as 48px fins
    beside a 16px band, the Vermilion liner folded upright into a lumpy
    48px slab.
  - **Furniture that was not there at all.** Anything whose cell is
    walkable resolved to flat ground: 59 department-store stools, every
    gate lounge table and pair of binoculars, both museum staircases,
    the gym-lounge chairs, and -- via the void rule -- the black
    partition walls every gym is divided by, which left their white rim
    columns standing as hollow 48px fins.
  - **314 gravestones** in Pokemon Tower were 8px stubs, because the
    volume path measured only their bottom row and dropped the arch.

  Notable readings: the S.S. Anne's hull is `roof` (a drawing seen from
  above, so the art belongs on the top face); the Warden's specimens and
  Celadon Gym's shrubs are `cylinder` voxel balls, the first indoor use
  of that class; the Fan Club's octagonal boardroom table is `counter`
  rather than `table`, because only a counter rides its upper rows onto
  the top face in drawn order -- which is what draws the seated chairman
  exactly once, the Pokemon Center couch case verbatim.

  Fuchsia Gym's invisible maze is deliberately left flat. Raising it
  would read better as a room, and would also hand the player the
  solution; a shape is purely presentational, so the drawn answer wins
  and the gym plays as the flat game does.

### Fixed

- **A profile pin now outranks the door fold.** `Structures.forMap`
  folds a door cell into its facade so the doorway does not punch a hole
  in the wall -- but it overwrote the resolved shape unconditionally,
  including for AUTHORED tiles, which contradicts rule 1 of the
  documented resolution order. Any pin on a tile its tileset also lists
  in `doorTiles` was dead on arrival: all four Celadon Mansion
  staircases and Pokemon Mansion 3F's descent are door tiles, so
  `stair_*` pins there silently did nothing and the flights stayed
  painted flat on the floor. The fold now skips authored tiles.

## 1.0.4

### Added

- **Viridian Forest grows real trees.** Nearly everything drawn in the
  forest is ROUND, and the detector was boxing all of it: the big trees
  came out as ragged mixed-height volumes (their sparse canopy-rim
  tiles read 0px against 32px bodies, leaving gap-toothed hedge walls),
  the stump rows merged into 16px crate walls wearing folded stump art,
  and the trail signs were broken piles -- their $32 tile is the
  water-fallback trap and recessed into a pond lip in the middle of the
  woods. All of it is now profile-pinned to the treatments the rest of
  the world already uses: every tile of the tree drawing (ball, rim
  wisps, feet) and the stumps take the per-cell voxel HULL the overworld
  border forest wears -- a tree spans 2x2 cells, so its four
  quarter-hulls tile into one big lumpy canopy, and each stump becomes a
  round bollard; the signs take the standing thin-slab `signpost`
  treatment every town sign gets; and the white sparkle filler inside
  the tree masses is flat ground instead of an invisible zero-height
  box. The whole map now resolves to hulls, signs, ledges and ground --
  a detector sweep finds no stray boxed column anywhere.

  Two refinements over the first cut, both new hull-builder abilities.
  A tree's drawing spans 2x2 CELLS, and per-cell hulls unfolded it onto
  the ground -- the ball's top half sat one cell north of its bottom
  half at the same elevation, reading as a tree cut in half. The new
  `canopy` class pins the drawing's corner tile as a group anchor and
  the whole 2x2-cell drawing carves as ONE 32px hull, so every tree is
  a single tall round canopy (the carver is now parametric over its
  canvas size, and hull stamps carry their footprint radius). And the
  stumps' drawn tops are a CUT FACE -- an ellipse of growth rings seen
  at an angle, not body: the new `stump` class builds the hull from the
  bark rows alone and projects the ellipse across the round flat top,
  near arc to the south (`stump_cap` names the ellipse's drawn height),
  so the rings ride the round part in perspective.

- **Flowers stand up, and keep swaying.** The animated meadow tile
  ($03, the one tile the overworld animates by frame rewrite) now
  renders as a billboard one voxel deep: the drawing's darkest tones
  plus everything they enclose are cut out per pixel, and the ground
  beneath is synthesized from the commonest flat neighbour, exactly
  like the ground under a detected prop.

  The interesting part is that the cutout still animates. A mesh is
  static, so the geometry spans the UNION of the mask over the base art
  and all three animation frames, and the animation lives entirely in
  the texture: TerrainAtlas already rewrites the flower's slot in the
  private animated atlas each step, and for this tile it now writes
  only the current frame's mask opaque with everything else keyed to
  alpha 0 -- which the voxel shader discards, and the shadow pass with
  it. The standing silhouette trims itself frame by frame in texture
  space, off the same engine clock as the flat path, without a vertex
  moving. The class is derived, not authored: any frames-animated tile
  resolves to the new `flower` class with no profile entry, the same
  way tall grass derives from `grassTile` (hand-authoring still wins).

- **The cuttable bush is a standing cutout.** The four tiles Cut
  deletes ($2D/$2E/$3D/$3E -- across the whole tileset they appear only
  in the five cut-tree blocks) are pinned to the thin `prop` pool: a
  per-pixel standee 5 voxels deep, black-outline segmented with its
  enclosed pixels kept, the drawn grass dither flooding away. It
  stands on plain grass ($2C) -- the very tile Cut leaves behind per
  field.cutTreeSwaps -- via the profile's new `prop_ground` key, which
  names the tile painted under a pinned prop instead of whatever flat
  tile its neighbours vote in.

- **Gym statues: a solid plinth, a standing bird.** The statue pair
  flanking every badge gym's aisle (and Bruno's room) is one cell of
  figure over one cell of plinth. The plinth ($22/$23/$32/$33) is
  pinned `wall`: a solid 16px block. The figure ($02/$38/$12/$13) is
  pinned `prop`: a 5-voxel cutout that stands ON the plinth through the
  authored-box support rule, its checkered background flooded away and
  the pixels its outline encloses kept.

  The whole statue keeps ONE cell of footprint. The support rule used
  to extend the box under the claimed cell (the monitor-on-desk path),
  which marched the plinth a second block backwards; a figure whose
  support is a FULL-HEIGHT block now collapses instead -- the drawn
  figure cell becomes synthesized floor, since the block below already
  carries the whole base. Furniture supports keep the extension: their
  drawn cell is the furniture's own upper rows, and floor there would
  amputate the desk. The round boulder drawn beside some statues is
  deliberately NOT pinned -- it also tiles wall-to-wall as Pewter's
  rock rows, which are scenery for the detector.

- **Lt. Surge's trash cans stand up.** The can ($0B/$0C/$1B/$1C, the
  lone graphic of blocks 38/39) takes the same treatment as the
  cuttable bush: a 5-voxel `prop` cutout, black-outline segmented with
  its enclosed pixels kept, standing on the gyms' main floor tile
  ($11) via `prop_ground`.

- **The Poke Marts furnished to the Center's standard.** The MART
  tileset shares the Center's atlas image but is its own id, so none
  of the Center's pins applied, and every mart was raw detector
  output: a 32px double-height display band for a back wall, the two
  shelf racks fused into one four-tile-deep monolith, and the clerk's
  booth towered into a 48px slab wearing the juice poster. Pinned the
  way the finished interiors are -- the back wall's SALE cases and
  drink fridges one 16px face like the Center's healing consoles, the
  racks collapsed to one-cell-deep shelves at drawn height like Red's
  bookcases, the counter half a cell with the poster riding its top
  like the nurse's tray, and the cash register standing ON the counter
  through the authored-box support rule. One 4x4 layout serves every
  city, so this covers all eight marts.

### Fixed

- **Cut trees now vanish in voxel mode -- and grow back.** The
  engine's Cut path swapped the block with a raw `setBlock` + renderer
  rebuild, never emitting `world.block_replaced` -- so this mod's
  listener (which rebuilds the map's mesh exactly for this) never
  heard about it, and the diorama kept showing the tree. The engine
  now routes Cut through `replaceBlock`
  (src/world/OverworldController.lua), whose whole purpose -- per its
  own comment, "Victory Road barriers, Cut trees" -- is that same swap
  plus the event. The regrowth path had the same hole one door away:
  cut trees are restored block by block when the map is re-entered,
  and the card-key doors are stamped closed on floor load, both
  through the same silent `setBlock` -- with the mesh cache staying
  warm across a round trip (that is what prevLive is for), the world
  kept showing the stump you left. Both paths now announce each block.

- **A block edit no longer blinks the world down to 2D.** The
  listener used to drop the edited map's mesh outright, and mesh
  builds are asynchronous -- so cutting a tree (or stepping out of a
  door onto a map whose trees just regrew) flashed the flat 2D world
  for the frames the rebuild took. `ChunkMesher.refresh` rebuilds in
  place instead: the stale mesh keeps drawing, the replacement cooks
  in the background, and each slot swaps as its build lands -- the
  tree pops out (or back in) with the scene never leaving 3D.

- **Flowers cull the player correctly from every angle.** The flower
  billboards were baked into the terrain mesh, which draws without
  the characters' camera-ward pull -- so a walker standing among
  flowers won the depth test against ALL of them, including the
  flower south of their feet that should overdraw them. The flower
  quads now ride their own mesh, drawn after the characters with
  exactly the characters' pull (the tall-grass trick): the flower in
  front of a walker occludes their feet, the one behind them hides,
  at every camera angle. Unlike grass the flower mesh still casts
  shadows -- it is a handful of cutouts per meadow, not thousands of
  tufts.

- The `voxel_anim_probe` driver crashed on engine builds without the
  optional `TileRenderer.animFrame` seam, and again on tilesets whose
  animation list carries a "toggle" entry (spinner rooms), which claims
  a tile LIST rather than one slot. It now reads the clock through the
  mod's own fallback chain and skips toggle entries in the placement
  census.

- **The shoreline no longer opens into the sky beside buildings and
  signs.** Water recesses 2px below the ground, and the ground tile beside
  it closes the step with a small below-ground side band -- but a tile
  CLAIMED by a standing object (a building footprint, a sign standee, the
  bushes ringing Fuchsia's ponds) only painted its synthesized flat ground
  and never emitted sides. Along every stretch where such a tile met
  water, the two-pixel step was an open slit straight through to the sky
  behind the mesh. The skip branch now emits the same below-ground bands
  ordinary ground does, cut from the synthesized ground's own art, so the
  shoreline lip is continuous whatever stands on the bank.

- **Edge-row buildings keep their facades.** The south wall of Saffron's
  row houses -- profiled buildings whose front row is the map's last tile
  row -- lies exactly on the boundary plane shared with Route 6, and the
  prebuilt-quad keep rules dropped it: the strict body test excludes the
  plane, and the closed neighbour mask (which exists to kill ring scraps
  whose rects sit exactly on that line) swallowed what was left, so from
  Route 6 the houses stood hollow. The two cases are geometrically
  identical degenerate rects, but they FACE opposite ways: a face pointing
  away from the body is this map's own facade and nothing in the
  neighbour will ever draw that plane, while a face pointing into the
  body is the scrap the mask is for. The mesher now reads the winding and
  keeps outward faces on the body's boundary planes, on all four edges.

  The roof RIM had the same problem one step further out: an edge-row
  house's eave overhangs `frontEave` voxels PAST the boundary plane into
  the neighbour's airspace, and those quads are neither on the plane
  (the winding rescue) nor over the body -- the neighbour-body mask ate
  them as ring scraps, so from across the seam the roof edge was open
  sky at low camera angles. Building placements only ever scan the map
  BODY, so every building quad is this map's own structure by
  construction: they now carry an `own` flag the edge keep-rules never
  touch.

- **Diglett's Cave mounds (and cliffs everywhere) stop sprouting
  towers.** Two detector misreadings stacked up on the cave-entrance
  mound. The dark east slope of the cliff drawing ($02/$24/$34) is one
  texture repeated over the mound's whole height, but its corner tiles
  break the repeat scan, so those columns rose to 32px -- the rock
  pillar beside the entrance. And a folded doorway column reads its own
  drawn extent (the door plus everything above it), which is a house's
  real height when the door is a house's, but a 32px tower over a 16px
  plateau when the door is a cave mouth -- the entrance jumped a block
  above the mound around it. The slope chain is now profile-pinned to
  one 16px course, and a doorway column answers to its REGION entirely:
  height from the region's dominant column, top flat when those columns
  are flat repeats (the mound) and roofed when they are drawn facades
  (a house). Both cave entrances -- and every cliff built from the same
  slope tiles -- now read as one level mesa with the cave mouth at
  ground level. A new `voxel_mound_probe` driver prints the detector's
  per-column class and height over any rectangle, which is how this was
  diagnosed.

  Routes 3 and 4 had a third variant of the same misreading: the repeat
  scan anchors at a column's FRONT tile, and a plateau column that ends
  in a one-off rounded corner tile ($13/$35) never matched -- it read
  its whole capped extent and shot up as a 48px fin (several together
  made a tent). When the two rows directly above the front are
  identical, the column is now read as that repeat wearing a trim foot:
  its unit is one course plus the trim. Doorway columns still answer to
  their region first, so houses are untouched.

## 1.0.3

### Added

- **The player shows through whatever hides them.** Occlusion in this mode is
  the real thing -- walk north of Red's house and the roof is genuinely in
  front of you -- but a player who cannot see their own character has lost
  track of where they are standing, which the flat game never allowed. The
  figure now draws a second time as a translucent silhouette wherever the
  world is in front of it.

  No code anywhere asks whether the player is occluded: the depth buffer
  already knows, and the test is the question. The silhouette is drawn with
  the depth compare INVERTED -- `greater` where the scene uses `lequal` --
  so it appears exactly where the ordinary draw would have lost, and nothing
  at all is drawn when nothing is in the way. LOVE hands the compare straight
  to `glDepthFunc`, so the two are true complements with no seam between
  them.

  It goes down BEFORE the characters, so the only thing it can meet in the
  depth buffer is the world -- terrain, buildings, trees. Drawn after the
  solid pass it would meet the player's own card instead, and every fragment
  of a figure sits behind the one that just wrote it, so it would paint over
  the player permanently. Characters then draw on top as usual.

  It uses the FLAT card (`SpriteBillboards.shadowQuad`), not the relief slab
  the solid pass draws. The slab carries front and back faces and the mode
  culls neither, so with the test inverted its own back faces -- a few voxels
  deeper than the front ones that just won -- read as "behind something", and
  the figure repaints itself on open ground whether or not anything is in
  front of it. One quad has no self-overlap, which is exactly why the shadow
  pass already uses this mesh, and it cannot double-blend into a mottled
  patch either. A silhouette is an outline, so the outline is the right mesh.

  Depth writes are off: the pass is behind the scenery by definition, and
  writing would file the hidden figure in front of the building hiding it,
  which the grass pass at the end of the frame reads. The card carries the
  same transform and the same camera-ward pull as the solid draw (both now
  come from one shared `billboardMatrix`/`billboardPull`, so they cannot
  drift), which is what keeps the leaning-over-a-near-wall case out of it:
  pull already won that fight for the solid draw, so a character merely
  standing close to a wall does not shimmer a silhouette over it.

  It is drawn as ONE flat translucent grey, not as a dimmed copy of the
  sprite. Tinting through the vertex colour could only MULTIPLY the sprite's
  own pixels, which darkens each one by its own amount and keeps all the
  character's internal detail -- a murky picture of Red rather than a shape.
  So the fragment shader carries a `ghost` / `ghostColor` pair and replaces
  the colour outright, last in the chain so neither the sun nor a voxel seam
  can mottle it. Staying translucent is what keeps it reading as "behind
  that wall" rather than as a hole punched through it.

  `Voxel3D.GHOST_COLOR` and `GHOST_ALPHA` (0.5) are the knobs. Only the
  player gets this -- NPCs and the ghosts standing on a neighbouring map are
  left to honest occlusion, because it is only your own character you cannot
  afford to lose behind a roof.

## 1.0.2

### Fixed

- On Android the diorama drew into the top-left corner at a fraction of the
  screen -- about a third of the width and height on a 420dpi panel -- with
  the field effects (dust, emotes, the cut-tree shudder) correspondingly
  oversized against the world they sat on. Desktop was unaffected.

  The pipeline ctx hands over `width`/`height` measured in LOVE UNITS
  (`love.graphics.getDimensions`), but the engine composites a pipeline's
  returned canvas with `draw(canvas, 0, 0, 0, 1/dpiX, 1/dpiY)` -- a scale
  that only covers the window if the canvas is at PIXEL resolution. Sizing
  the scene canvas from the ctx therefore paid the DPI scale twice: the
  canvas came out that much smaller, and was then drawn that much smaller
  again. On desktop the two units are the same number and nothing shows;
  Android's DPI scale is the display density (2.625 at 420dpi), so that is
  where it surfaced.

  The scene canvas is now sized from `love.graphics.getPixelDimensions`
  directly rather than from the ctx. That is the number a fixed engine would
  hand over, so this does not double-correct if the ctx is ever changed to
  agree with the compositor. It also squares the FX pass for free:
  `ctx.scale` was ALREADY in pixels per world pixel (`Zoom.scale` over
  `Renderer:fitScale`, which measures the drawable), so the closures were
  being scaled for a canvas 2.6x bigger than the one they were drawing into
  -- one wrong number, not two.

## 1.0.1

### Fixed

- The RED++ texture-readback fallback in `TerrainAtlas` never worked on real
  drivers: LOVE refuses `Canvas:newImageData` while that canvas is currently
  active, and `readback()` read the pixels back before restoring the previous
  render target, so the call threw on every driver rather than only on
  stubborn ones. The previous target is now put back BEFORE the read. The
  headless suite could not see this -- its stub canvas does not enforce the
  rule -- so it survived until a live probe ran the chain unguarded.

  Harmless for vanilla tilesets, where the CPU rebuild (`gbcPixels`) answers
  first and the fallback is never consulted; it was the last-resort route for
  a map the palette pack does not know, which until now had no working route
  at all.

## 1.0.0

First release, ported from the engine-internal voxel branch onto the
`render_pipelines` mod API.

Interior furniture gets the shapes it depicts
(mods/DRAMATIC_SHAPE/tools/voxel-survey.md is the procedure that found and
verified these).

Buildings stop being boxes wearing their own elevation. A profiled
building is voxelized from its own sprite, band by band -- the pipeline
written up in `assets/docs/buidling_to_voxel/`.

Terrain meshing goes asynchronous, instanced and bounded. The first voxel
frame used to build every neighbourhood map synchronously (a ~2.4s
freeze), retain every map's analysis forever (gigabytes over a
cross-region trek), and string stray pixels along map seams.

Real shadows. The sun moves to the southeast and drops to 45 degrees, so
shadows fall northwest -- up and to the left on screen -- and run about as
long as the thing throwing them is tall.

### Added

- `voxel` render pipeline: 3D diorama overworld with extruded terrain,
  depth-buffered occlusion, leaning sprite billboards, drop shadows and
  contact AO. VOXEL options row and hotkey `3` (OFF / 15 / 35 / 50 / 75).
- `tiltshift` render pipeline: a `worldPresent` post-process giving the
  miniature-photo look. T-SHIFT options row and hotkey `6` (OFF / 1 / 2 / 3).
- Carved voxel models for 67 overworld sprites, plus the
  `tools/build_voxels.py` that produced them.
- `data/voxel_heights.lua`, the hand-authored tile shape profile.

- Furniture shape classes in the profile: `bed` (a low slab wearing its
  top-down art), `table` and `desk` (boxes at their drawn height whose
  faces fold the artwork up), `relief` (a prop drawn from above -- a
  game console -- lying flat and extruding a few voxels inside its
  outline), the standee pools `billboard` (10px) / `prop` (5px) /
  `stool` (5px, and characters standing on its walkable cell sit at
  seat height) / `cutout` (one voxel: pure profile, for the vase on the
  table), and the stair archetypes `stair_e`/`stair_w` (a rising flight
  of real steps) and `stair_down_e`/`stair_down_w` (a sunken stairwell
  descending below the floor -- stairs that lead down).  Separate pools
  cluster separately, so touching drawings never merge into one cutout.
- Standee clusters split into per-pixel connected components, each
  standing on its own feet in the depth band of the row it is drawn in:
  two stools stacked in adjacent cells become two stools, and no
  fragment of a drawing ever floats at its bounding-box height.  A
  `cutout` keeps only its largest component -- a cast shadow's drawn
  edge is background, not a floating scrap.
- `bookcase` class: free-standing shelf drawings collapse in ranks onto
  one-cell-deep boxes at their full drawn height, back rows becoming
  hidden floor; the trim row above a rank -- undetected structure or a
  row pinned `table`, since the same trim tiles cap other furniture --
  is adopted as its cap.  Pinned for Oak's Lab (`DOJO`).
- Oak's Lab tables pinned `table`: the starter-ball display and the
  north tables stand at real table height, the display frame's black
  corner brackets no longer auto-extract into standing prisms, and the
  Poke Ball / Pokedex sprites ride the authored height onto the
  tabletops.
- Pinned props drawn directly above a pinned box stand ON it: the PC
  monitor on its desk, the flower pot on the dining table.
- Profile pins for `REDS_HOUSE_1` / `REDS_HOUSE_2` (Red's house and the
  Copycat's, both floors): bed, stools, tables, PC desk with its
  standing monitor, bookcases, TV standing on the floor behind the game
  console's relief, potted plant, flower pot, both staircases, and the
  wall/window band.
- `mods/DRAMATIC_SHAPE/tests/voxel_survey.lua`: screenshot-survey driver
  behind the repeatable inspection procedure (SURVEY_MAP / SURVEY_SPOTS /
  SURVEY_LEVELS / SHOT_DIR), documented in
  mods/DRAMATIC_SHAPE/tools/voxel-survey.md.

- `lib/Buildings.lua`: a building archetype. Where the volume path folds a
  whole drawing upright (roof, facade and sloped ends alike) into one box,
  this classifies each BAND of the drawing by the 3D surface it depicts and
  applies the matching operation: top-facing rows lay flat over the
  footprint, the facade extrudes straight back, an awning band juts past
  the walls, and the drawn taper at the ends becomes a stepped slope in
  elevation. Every visible voxel carries a real texel of the drawing, so
  the model recolours with the atlas.
- A `buildings` section in `data/voxel_heights.lua`. A building is matched
  by its exact tile grid (the drawings are catalogued in `assets/docs/buildings/`),
  so one entry covers every map that places the same art -- Red's house,
  Blue's house, Bill's, the Copycat's and the two Fuchsia houses are one
  seven-placement entry, and Oak's lab is a second. Only the band table is
  authored; the silhouette, the taper rate, the eave height and every
  window and doorway are measured off the pixels.
- The flat-roofed civic block and its sixteen relatives -- every Pokemon
  Center and every Poke Mart, Fuchsia Gym, the museum, the Game Corner,
  Celadon Mansion and its department store, the Power Plant, the Route 5
  and Route 22 gates, Silph Co and five anonymous scenery blocks. They are
  one architecture drawn at eleven different footprints, from 4x4 cells up
  to Silph Co's 8x12, and they share one band table: their lattice is drawn
  from straight above, so the measured taper comes out flat and the whole
  band is depth under one level roof. No new roof mode was needed -- the
  drawn profile was always the shape, and a drawing with no taper simply
  yields a level one.
- Pewter's museum hall (`assets/docs/buildings/B24`). It is the one
  sloped-roof building in this pass, and the only one so far whose roof
  texture is not a plain repeat: the drawing states its own period by
  repeating the whole lattice-and-course motif, rows 8..31 again at 32..55,
  so the cycle is 24 rows and the roof carries its drawn courses across the
  depth instead of a bare lattice. The band below them is the roof's
  fascia, wider than the wall it covers, so it belongs to the roof and
  lands on the south rim. Note the museum is TWO drawings: this hall and
  the east entrance beside it, which is B18 and shares its drawing with the
  Route 2 gate.
- The rest of the 2:1 sloped-roof buildings: both gym drawings (the
  standard one at Cinnabar, Pewter, Vermilion and Viridian plus the
  Fighting Dojo, and the wider Celadon / Cerulean / Saffron one), the 4x2
  cottage that houses Mr Fuji, the Cubone house, Bill's grandpa, the Name
  Rater and the Viridian school, Cerulean's three wide houses, the day
  care, and three scenery blocks -- among them B01, which at 19 placements
  is the commonest drawing in the game. Each one's roof band is pixel for
  pixel one of the three already authored, so they take that sibling's band
  table unchanged: 16 rows for Red's house's, 32 for Oak's lab's, 64 for
  the museum's.
- The Safari Zone rest houses and the Victory Road entrance, the first
  buildings outside the `OVERWORLD` tileset -- `buildings` is keyed by
  tileset and until now only had the one section. The rest house's
  corrugated roof repeats every 5 rows rather than the overworld lattice's
  8, which is the point of `roofCycle` being authored per building.
- Route 10's scenery block, via a new `seal` field. Its drawing has no
  black base course -- it ends on a row of light brick -- so the silhouette
  flood climbed in from the south border through the mortar and hollowed
  the wall out, leaving 72% of the sprite in 65 pieces. `seal` names the
  sides a drawing runs off rather than closing, and the flood does not seed
  there: sealed, it is 95% in one piece, and the model is its twin the
  museum's. No other building sets it, and none changes by a voxel.
- Together these take the mod to 31 of the catalogue's 34 drawings and 144
  of its 147 placements. The last three, and why each resists, are written
  up in `assets/docs/buildings/REMAINING.md`.
- A roof no longer runs past the drawing's own silhouette. These sprites
  are inset from their boxes, and the columns outside the inset carry no
  roof: they now get none, and the fascia belongs to the outermost columns
  the drawing actually paints. Before, they raised a four-voxel slab of
  black kerb the full depth of the building, flanking its walls at ground
  level. Nothing shipped hit this -- Red's house and Oak's lab are drawn
  edge to edge -- so no existing model changes by a single voxel.
- Windows and doorways sink a voxel behind their frames, found rather than
  listed: a pane is a non-black region the drawing seals off behind its own
  black outline. A nested frame (the door's own little window) layers for
  free.
- `tools/building_voxels.py`: the reference implementation of the same
  algorithm, with the geometric asserts and isometric previews Stage 5 of
  the methodology calls for. It and the runtime agree exactly on voxel and
  shell counts for all 19 templates -- 96,617 / 12,866 for Red's house up
  to 3,715,963 / 146,762 for Silph Co, which ship as 3,410 and 13,994
  quads. Its slope asserts read the drawn columns only and stand down for a
  roof with no taper, where the check is that the roof is level instead;
  its previews fit the projection to the model rather than to a fixed
  camera, so a building taller or deeper than the first two still lands on
  the canvas.

- A sky at the 75-degree rung. Pitched that far over, the horizon comes
  into frame and a good part of the picture is void, so the void gets
  filled instead of reading as the black plate it does at every rung below.
  No skybox and no geometry -- it is the colour the scene canvas clears to.

  **Outdoor maps only.** A house, a cave or a gym is a room with a ceiling,
  and the void past its walls is the outside of a box rather than open air.
  The test is `Map.isOutdoor`, the same one the engine uses for door SFX
  and the town map, and the same one `Structures` already asks to decide
  whether a map rings with trees.

  The colour is a four-shade ramp shaped like a world palette and run
  through `PaletteFX.effectiveColors`, so it answers to the display mode
  exactly as the baked terrain does: blue in the colour modes, grey under
  GRAY, green under CLASSIC, dark under GBC INV. A hardcoded blue would sit
  wrong in every mode that is not a colour mode. It fades across the
  approach to the top rung rather than switching at the keypress, so it
  arrives with the camera tween.

- The mod's four controls sit on adjacent keys, and the two that never had
  one now have a hotkey at all:

  | key | control |
  | --- | --- |
  | 3 | VOXEL, the camera ladder |
  | 5 | V-GRID, the wireframe |
  | 6 | T-SHIFT, the blur ladder |
  | 7 | V-CURVE, the horizon bend |

  Only 6 arrives by the documented route. `Game:keypressed` answers the
  engine's own display keys first and returns -- 2 COLORS, 3 TILT, 4 ZOOM,
  5 GBC FX -- and only then offers the key to `Pipelines.hotkey`, expressly
  so that "a pipeline can never shadow one". Two of the four wanted keys are
  in that set, and V-GRID and V-CURVE own no render pass, so they have no
  registry to claim a key from in the first place. The mod wraps
  `Game:keypressed` to take the four. Polling the keyboard in `update`
  would not do: it fires alongside the engine's handler rather than instead
  of it, so 3 would cycle this mode AND the engine's TILT on one press.

  **TILT (3) and GBC FX (5) are no longer reachable by key while this mod
  is enabled.** Both are still on the OPTIONS menu. Key 9 is now free.

  So the VOXEL key turns both off itself, on every press. Both fight the
  diorama -- TILT is the flat fake of what this mode does for real, GBC FX
  a full-screen present pass laid over the top -- and with 3 the only key
  that now reaches either, it also has to be the way back from having left
  one on. Every press, not just the one that switches the mode on: the
  registry's own tilt exclusion covers switching ON, but the press that
  cycles the ladder round to OFF would otherwise leave both running with
  no key left to clear them.

  The wrapper delegates rather than reimplements: `Pipelines.hotkey` still
  applies its own gate and ladder, the settings borrow the same free-roam
  gate the voxel pipeline uses, and a screen with its own key handler keeps
  the keyboard -- so typing a nickname cannot cycle a render mode behind
  the text box.

- `lib/ShadowMap.lua`: the scene rendered once from the sun into an
  orthographic depth map, which the main pass then samples per fragment.
  What the sun cannot see is in shadow, whatever surface it is, so a
  shadow climbs a wall, drapes over a roof and slides across a passing
  NPC with no case in the code -- and every caster is simply whatever the
  pass draws. The terrain mesh goes in, which means buildings, trees,
  ledges, signs and every prop cast, where before only characters did.
- Depth is packed into two 8-bit channels of an ordinary color canvas
  (~16 bits over a ~700px frustum, a hundredth of a world pixel).
  Readable depth textures are the least portable corner of the graphics
  API, and the mod's contract is that an unsupported driver falls back
  rather than errors: `available()` reports, and VoxelScene keeps the old
  flat decals when it says no.
- The map resolution is picked per frame from a 1024/1536/2048 ladder
  against a 0.45 world-pixels-per-texel target, because the light frustum
  is fitted to the world view and that swings 3x between the closest zoom
  and a maximised window at the widest. The frustum is snapped to whole
  texels, without which every shadow edge in the world crawls as you walk.
- Ambient occlusion, the genuine article: each vertex counts the
  neighbours crowding it and steps down once per neighbour, on top faces
  (four corners, three neighbours each) and now on upright faces too --
  the crease a wall rises out of, and the inside corners where flanking
  columns box it in. It is the complement of the shadow pass rather than
  a duplicate: the map draws the long directional shadow, this draws the
  dark seam in every corner the sky cannot see into, at scales finer than
  a shadow map texel.
- Plus a ground-contact term for the prebuilt prop quads -- per-pixel
  plants, signs and lone trees, and the round-tree stamps. Those arrive
  from Structures already finished, so the neighbour counting has no
  columns to count; what it can still say is that the floor blocks half
  the sky, so a voxel's first 6px of rise ramps back to full light. It is
  what stops a prop reading as pasted over the ground rather than
  standing on it, and outdoors it is most of what AO does at all, since
  trees and posts are nearly all prop geometry.
- One knob for the lot: `AO_STRENGTH` in `ChunkMesher` scales every term
  (they are written as darkening amounts, not multipliers), against a
  floor that keeps a crank from punching holes of pure black.
- The **V-CURVE** row in OPTIONS: the curved world, the Animal Crossing
  horizon. Every vertex is pushed down by the square of its horizontal
  distance from the camera's focus, and that is the whole effect -- a
  quadratic is nearly zero near its vertex, so the ground being played on
  stays flat, and the falloff accelerates, so the far edge rolls away over
  a near horizon and the town reads as sitting on a small sphere.
- It is deliberately NOT a fisheye. A fisheye is a LENS -- a screen-space
  warp -- which bends straight lines everywhere including right in front of
  the player, resamples every pixel to do it, and would leave this mode's
  art blurred and crawling. Bending the WORLD is one line in the vertex
  shader: lines near the camera stay straight and not a pixel is resampled.
- Displacing along Y only is what keeps it readable rather than
  nauseating: the drop depends on where a column stands, not how tall it
  is, so the world tips away and the buildings on it stay upright.
- Shadows and the wireframe ride along for free. Both are already worked
  out before the bend -- the shadow map in flat world space, the grid in
  model space -- so the bend carries them exactly as if they had been
  painted on, and neither the light frustum nor the grid needs to know the
  curve exists. `Voxel3D.project` applies the same drop on the CPU, which
  is what keeps the overworld's 2D field FX on their ground points.
- The strength scales with the view height, so a rung reads the same at
  every zoom, and the ladder is calibrated against the far edge of the
  visible ground rather than against nothing.
- `lib/ModSetting.lua`: the ladder/store/rows a setting of this mod's own
  needs, now that there are two of them. V-GRID's copy of it moved here.
- A **75 degree** rung on the VOXEL ladder, below the 15/35/50 it shared
  with the engine's TILT: low enough to read as a diorama shot from table
  height. Tilt could not have it -- its flat plane degenerates into a
  horizon line down there -- but geometry only gets more of itself to show.
- The **V-GRID** row in OPTIONS: a one-display-pixel wireframe along every
  voxel edge, 3D Dot Game Heroes style. Every mesh here is built one unit
  per voxel in its OWN model space, so the seams are that space's integer
  planes, and reading them in model space rather than world space is what
  keeps them glued to a thing however it is posed -- a character's slab
  leans back by the camera's pitch and its seams lean with it.
- The seams fade out where a voxel shrinks under about 3 display pixels.
  Survey zoom draws a world pixel at roughly a display pixel, and a wall
  seen nearly edge-on squashes one to nothing at any zoom; drawn anyway,
  the lines land closer together than they are wide and the wireframe
  stops being a wireframe and becomes a flat 45% dimming of the scene.
- `lib/VoxelGrid.lua` owns the toggle. It is NOT a pipeline: it owns no
  pass of the frame, it parameterises the voxel one, so it has nothing to
  put in `drawWorld` or `present` and the registry rightly rejects it. A
  plain mod setting instead -- `options:define` for the store and the mod
  manager's page, `ui.options.rows` for the row in OPTIONS next to VOXEL
  and T-SHIFT. Both rows read and write the one stored value.
- The wireframe is a SECOND COMPILATION of the scene shader rather than a
  branch inside it, because it needs shader derivatives (`fwidth`) -- the
  one part of the mode a driver can refuse. A refusal costs the grid and
  nothing else.
- `mods/DRAMATIC_SHAPE/tests/voxel_shadow_probe.lua`: reports the fitted
  frustum and the resolution rung, dumps the map itself, and shoots a
  stand point at every pitch. `SHADOW_SUN="kx,kz"` retunes the bearing for
  one run, `SHADOW_GRID=1` forces the wireframe on, and `SHADOW_ZOOM` pins
  the zoom, without which two runs are not comparable -- a driver inherits
  whatever the player left in `options.lua`, and the world view size (which
  the light frustum is fitted to) swings 3x across that range.

- A `counter` class (8px, upright): half-cell furniture. One 8px band,
  so exactly the drawing's bottom row stands up as the front and every
  row above it rides the top face in drawn order. `table`'s 12px could
  not be retuned for it; the houses share that class.

- `tilesets.POKECENTER` in `data/voxel_heights.lua`. Before it, the
  detector merged the wall-touching counters and healing machines into
  the wall band and towered them 3-6 blocks, flattened the machines'
  near-black screens to void, read the pillar bases, plant pots and
  machine bodies as ponds (the $14/$32/$48 stale-cache water fallback),
  boxed each plant pair into one hedge cube, and extruded the lounge
  seat -- a PERSON is drawn into its tile art -- into a monolith wearing
  his face.
- The pins, by shape: the wall band, windows, poster, pillars and the
  16px machine bodies are `wall`; the counters (with the nurse's tray)
  are `counter` and the PC's desk is `table`; the machine screens and
  the PC are `billboard`, standing on the pinned boxes below them; the
  potted plants are `prop` standees like every other interior plant.
- The lounge couch with the man sitting on it is a `counter` box: its
  bottom row stands up as the couch's front and the cushion and the man
  ride the top face, each drawn exactly once.
  He cannot be stood upright, and the reason is structural rather than a
  tuning question. His skin pixels span two tile rows and stop dead at
  the row 9/10 seam; folding two rows upright requires both to share a
  class, which makes the box two tiles deep, and a fully folded box
  repeats its north row across its whole top face. So every upright
  arrangement puts his head on screen two or three times -- as a 16px
  seat-back, on the front and twice more on the top; as a 32px bookcase,
  a cabinet taller than the room's own walls. Dropping the seat in front
  of him to floor level only changes which copy you see. Nor can he be a
  standee: the drawing has no floor margin, so all three non-black
  shades touch the cluster rim and the mask drains 307 of its 420
  interior pixels -- 46% of him even segmented alone, because his skin
  is the same light shade as the couch behind him.
- Survey evidence: full before/after passes of VIRIDIAN_POKECENTER at
  15/35/50 degrees, plus spot-checks of CELADON_POKECENTER and
  CELADON_HOTEL (shared tileset, both inherit correctly) and of
  REDS_HOUSE_1F, OAKS_LAB and VIRIDIAN_CITY (unchanged -- the new class
  is additive and no other tileset lists it).

### Changed

- Pinned props are segmented the way the art is authored: objects wear a
  black outline, so background is the shades touching the cluster's edge
  (white floor around a TV, grey tabletop around a vase) flooded in from
  the aprons; the outline, its interior, paint whites and anything they
  enclose survive -- pixel-perfect cutouts on any surface.
- Indoor structure analysis floods background from all four aprons and
  accepts ground contact on any side (outdoors keeps the south-only rule
  that protects roofs), so face-on furniture drawings voxelize per pixel
  instead of rising as wall-height volumes.
- Profile-pinned standees are 10px deep (detected props stay 6px), so a
  deliberate object like a TV keeps a body at shallow camera angles.
- Authored upright boxes fold their artwork up every face (flanks and
  back wear the front stack darkened) and top faces keep the drawn
  tabletop: face-on rows wear the row above the fold instead of
  repeating their front art lying flat, and a run that folded entirely
  tops with the furniture row drawn above it (a bookcase's shelf trim).
- Characters no longer ride a pinned stair tile's class height: stairs
  are walked through at floor level, fixing the step-up onto thin air in
  front of stairwells.

- A voxelized building is as tall as its facade plus its roof slab rather
  than as tall as its drawing: the roof rows are DEPTH now, not height, so
  Red's house is 36px over a 4x3-cell plot instead of a 48px cube.
- Round trees (the `cylinder` pin: lone canopies and the border tree
  wall) stop being lathes -- the sprite wrapped around a 12-segment
  column read as exactly that, art smeared on a barrel. Each cell is now
  a real voxel hull: the canopy is segmented out of its cell as the
  darkest-pixel outline plus everything it encloses (which also drops
  the background grass that used to inflate every row to full width, and
  the cast shadow under the ball), and each mask row runs its own span's
  circular chord in depth -- the front view is the sprite pixel for
  pixel, the plan view is the sprite's width profile turned in depth.
  Dithered art with no closed outline (the tree wall) falls back to
  light-shades-only flooding, per the methodology doc's boundary rule.
  Sides de-outline like building extrusions so flanks read as canopy
  rather than solid black, and dome caps keep their outline on the rim
  while the interior samples the canopy a couple of rows deeper.
- A `post` standee pool, pinned for the overworld's vertical fence-post
  cell (tiles 14/85 -- across every map the pair appears only as this
  cell). The detector already turns HORIZONTAL fence runs (tile 57) into
  per-post standees, but a vertical run of repeated cells trips its
  scenery-repetition guard and fell to the volume path as a
  fence-textured tower (Viridian's west line, Route 25).
  `post` extracts every CELL as its own cluster -- pooled clustering
  would stand the whole line up as one drawing-tall slab at one depth --
  and classifies pixels the way the detector does (non-white is body)
  rather than by the pinned-prop outline rule, which would strip the
  posts to black skeletons; at the detector's own 6px depth, pinned and
  detected fences look alike.
- Town signs move from the `billboard` pool to a new `signpost` pool: the
  same per-pixel standing slab, but 2 voxels thin instead of 10. A sign
  is a plate on a stick, and the standee body that keeps a TV from
  vanishing at shallow angles read as a solid block of furniture here.
- The ground under a round tree matches the tree's own drawn background
  instead of the map's commonest ground tile. The hull's segmentation
  already knows which pixels are NOT the tree; those pixels are scored
  against every flat ground tile the map places and the closest art
  wins, per template -- so border trees drawn over checker grass stand
  on checker grass even on a map that is mostly pale path (the old
  fallback painted path under every mid-forest tree, which has no flat
  neighbour to vote with). The drawn cast shadow stays out of the score:
  no ground tile carries a shadow, and its darks would drag every match.

- Mesh builds stream in the background. `ChunkMesher` queues per-map
  build jobs and `pump()` -- driven from the pipeline's update -- runs
  them inside a few-millisecond frame budget (`lib/BuildBudget.lua`
  suspends the build coroutine mid-loop when the slice is spent). The
  camera tween holds at flat until the current map's terrain exists, so
  toggling voxel mode shows a handful of flat frames instead of a frozen
  one; neighbours pop in as they finish. Warp fades prefetch the
  destination (the pipeline update ticks while the Transition covers the
  screen, with a wider pump slice), so a door exit lands on terrain that
  is already built.
- Vertex packing goes through FFI into one native buffer
  (`Mesh:setVertices(ByteData)`) instead of a Lua table per vertex --
  the headless table path remains for the pure `geometry()` API and its
  suite.
- Round-tree hulls are carved once per (tileset, art, ground set) and
  kept as stamps -- template plus cell offset, expanded during vertex
  packing -- instead of materialized per-cell quad tables. A route's
  border forest was ~500 quads x hundreds of cells of retained heap.
- Mesh and analysis caches evict down to the live neighbourhood (current
  map + rendered neighbours, plus one set of history so a house
  round-trip keeps the town warm). Evicted meshes are released
  explicitly. Memory over Pallet -> Mt Moon: was ~2.9GB and monotonic,
  now oscillates between ~90 and 200MB.

- `Voxel3D.SHADOW_KX/KZ` are -0.85 / -0.55, from +0.30 / +0.45: the sun
  crosses to the southeast and drops from 62 degrees to 45. The bearing
  leans WEST of northwest on purpose -- a character is drawn as a slab
  leaning away from the camera, which covers the ground due north of its
  feet, so a shadow thrown straight up-screen lands entirely underneath
  the figure casting it and is never seen.
- `Voxel3D.SHADOW_ALPHA` 0.32 -> 0.40, a quarter darker.
- `FACE_SHADE` east 0.78 -> 0.84 and west 0.78 -> 0.72. The two were equal
  because the old sun sat due northwest and they were symmetric about it;
  under a southeastern sun east is a lit flank and west a shaded one.
- A character's shadow lookup runs off the UPRIGHT card the sun saw, not
  the leaning slab the camera sees (`Voxel3D.draw`'s `sunModel`). Casting
  the leaning slab instead would shrink every shadow to nothing as the
  camera flattened toward top-down; looking up with the leaned position
  put each sprite's own card across its front.
- The contact-shadow term in `ChunkMesher` was a one-directional stripe
  keyed to a northwestern sun -- two neighbours, one corner, top faces
  only. It is now the ambient occlusion above.
- The light frustum is fitted to the ground the CAMERA CAN SEE rather than
  to a view-sized box around the focus, and both of its margins are now
  asymmetric -- for opposite reasons. The camera sits south of its focus
  and looks north, so the ground it sees runs far north and barely south;
  the sun sits southeast, so the casters for that ground stand south and
  east of it. Paying for a view-sized box plus caster margin on all four
  sides covered about a third of what was on screen at 75 degrees, and
  overpaid at 15.
- Shadows ease off at the frustum's rim instead of ending on it. Past the
  low rungs the horizon is further out than any box worth paying for, and
  a covered region that simply stops draws a hard line across the middle
  distance where every shadow ends at once.

The Pokemon Center interiors. One `POKECENTER` group in
`data/voxel_heights.lua` plus one new class, and because
VIRIDIAN_POKECENTER places every tile the tileset's other maps use, the
one pin set covers all eleven Centers and the Celadon Hotel.

### Fixed

- The generic town-house tileset (`HOUSE` -- Blue's house, Daisy at her
  table, and eighteen more homes, the schoolhouse and the trashed house
  among them) is now pinned in `data/voxel_heights.lua` the way Red's
  rooms already were: the dining table stops towering as a wall-height
  volume and sits at table height with its front folded upright, stools
  become seat-high boxes that characters sit on, the corner potted
  plants become per-pixel standees instead of texture-smeared box
  stacks, the bookcases get clean capped tops, and the wall band (with
  its window, picture and the schoolhouse blackboard) stays one 16px
  face.  The schoolhouse's open book stands on the pinned tabletop as a
  cutout, and the trashed house's ransacked table corner keeps table
  height.
- Interior door mats lie flat again in Red's and the generic houses.
  Their collision tile is $14, which the engine's stale-cache fallback
  counts as water in every tileset, so the rug recessed into a pond lip;
  a `ground` pin now overrides the water read.

- Stray pixels along map seams: ring props (border-tree hulls) whose
  quad CENTER sat exactly on a neighbour body's edge line escaped the
  strict point-in-rect mask and survived as fragments of otherwise
  dropped trees. Object quads now keep/drop by their full extent,
  boundary inclusive; props straddling the body edge also stay whole
  instead of shedding their outer half.
- The one-step "ledge hop" when crossing a connection into a tree-ringed
  map: the seam step stands the player one cell off the new map, where
  `Map:cellTile` border-extends into the borderBlock -- a raised tile on
  maps ringed with trees. Off-map ground now reads as height 0 (the
  departed neighbour's flat walkway, which is what is actually rendered
  there).

- Cycling palette modes with voxel mode on eventually killed the pipeline
  outright: `attempt to call field 'atlasImageData' (a nil value) --
  disabled for this session`. Nothing brought it back short of a restart.

  `TerrainAtlas` reads three engine seams to animate water and flowers in
  the terrain texture, and this build ships only one of them
  (`defaultAnimatedTiles`). The tile clock, `animFrame`, was already read
  guarded and simply degrades. `atlasImageData` was called straight -- but
  only down the branch where the mod had NOT baked the atlas itself, which
  is why it looked stable until a palette changed. Every mode with no world
  palette for the map (`PaletteFX.pal` answering nil), plus RED++ and any
  trueColor tileset, takes that branch, so the first map with animated
  tiles entered under one of them threw out of `drawWorld` and the engine
  disabled the pass for the session, exactly as it should.

  The seam is now read guarded like its sibling, and when it is absent the
  pixels are recovered rather than given up on. An atlas neither we nor
  RED++ replaced is the tileset art itself, so animation carries on from
  the art on disk. RED++'s per-map bake exists only as a texture --
  `getGbcAtlas` throws its `ImageData` away -- so that one comes back off
  the GPU: the atlas is drawn 1:1 into a canvas and read back, once per map,
  with the pass's own render target captured and restored around it (the
  usual `setCanvas()` would drop the rest of the frame). A driver that
  refuses the readback declines to animate and keeps the static atlas.
  Worst case now costs one animation, never the pipeline.

- Water and flowers did not animate in voxel mode at all, and had not since
  the mode shipped -- a silent one, since the terrain was otherwise correct.

  The tile clock is the third seam, and this build does not export it
  either. Being read guarded, it answered 0 forever instead of throwing,
  which pinned every animated tile at step 0. `animFrame` is a plain local
  in `TileRenderer`, but an upvalue of the exported `tick()`, so the mod now
  reads the real counter through it. That it is the ENGINE's counter is the
  point: the flat tile layer draws from the same number, so toggling voxel
  mode mid-cycle continues the animation rather than restarting it. A build
  that exports `animFrame()` outright is preferred; a build that hides the
  local falls back to wall time in 60Hz steps, which free-runs against the
  2D path but still moves the water.

- Toggling palettes in voxel mode flashed the flat 2D world for a moment on
  every switch.

  `PaletteFX.setMode` reloads the live map to rebuild its atlas, and this
  mod dropped that map's terrain mesh on any `map.reloaded` at all. Mesh
  builds are asynchronous, so the frames between the drop and the first
  rebuilt mesh had no terrain to draw -- and a voxel `drawWorld` with no
  terrain returns nil, which is exactly how the pipeline asks for the 2D
  fallback. The flash was the mod correctly reporting that it had nothing
  to show.

  The geometry was never stale: the mesher reads block layout and tile ids
  and never reads colour, and the palette lives entirely in the texture
  `TerrainAtlas` hands back per frame, keyed by palette and so already
  rebuilt by the next frame. A reload whose reason is `colors` now keeps
  the mesh, and the new palette lands on the diorama already on screen in
  one frame. Every other reload -- warps re-entering a map, hot reload, a
  replaced block -- still drops it.

- Every non-colour palette mode rendered as SGB in voxel mode: GRAY and
  both INVERTED modes came through as the map's blue.

  `paletteFor` hands a pipeline the map's RAW SGB zone palette. The flat
  path runs that through `PaletteFX.effectiveColors` on its way to the
  shade-remap shader, and that call is where the non-colour modes actually
  happen -- OG and OG INV swap in the DMG greys (reversed for the latter),
  CLASSIC swaps in the green set, GBC INV permutes the zone's own shades,
  and only GBC and RED++ pass through. This pass bakes colour into the
  atlas and the sprite sheets ahead of the draw rather than shading at blit
  time, so it never reached that call and painted the raw zone palette in
  every mode.

  Both bakes now run the same transform the shader would have. Terrain and
  characters go through one resolve, so they cannot disagree about what
  mode is on.

- VOID FILL did nothing in voxel mode, in two separate ways.

  **BLACK crashed the build.** The mode is not a block at all --
  `TileRenderer.borderBlockFor` answers `false` for it -- and `Structures`
  added 1 to that `false`. The arithmetic threw, which failed the mesh
  build for every map in the neighbourhood, which left the mode with no
  terrain and dropped it to the flat 2D path entirely. It now builds no
  ring: `tileLookup` answers nil past the body and those keys are never
  written, which the rest of the file already copes with -- every
  neighbour query in it reaches one step outside the analysed range and
  reads nil for its trouble, so an absent cell is the shape "nothing" has
  always had here.

  **WATER changed nothing on screen.** The ring is BAKED INTO THE MESH in
  this mode rather than drawn each frame, and nothing dropped the cache
  when the option moved, so the old ring simply stayed until the meshes
  were invalidated for some other reason. The pipeline's update hook now
  polls `TileRenderer.voidFill` and invalidates on a change -- polled
  rather than hooked because the engine changes it from three places (the
  options row, `applyOptions` on load, `setVoidFill`) and none of them
  announces it, and checked ahead of the active() gate so switching it
  while voxel mode is off still drops what is cached.

  `mods/DRAMATIC_SHAPE/tests/voxel_void_probe.lua` walks the three modes
  and reports the border block, whether the mesh built and whether the
  scene took the 3D path. It deliberately does NOT invalidate the cache
  itself, since doing so would hide the second half of this.

- Water and flowers did not animate. The 2D path animates them by
  OVERDRAWING the animated cells on top of the static tile layer each
  frame, which a single static mesh has no equivalent of -- the geometry
  samples one texture and that is that. So `TerrainAtlas` animates the
  texture instead: a private copy of the atlas whose animated tile slots
  are rewritten when the step advances, which moves every instance of that
  tile across the whole mesh at once. Which is what the Game Boy does in
  the first place (`home/vcopy.asm` rewrites the tile's VRAM bytes); the
  overdraw is the port's workaround for a tile layer, not the original.
  ~130 pixels of work three times a second, on the same
  `TileRenderer.animFrame` clock the 2D path uses, so the two can never
  disagree about which frame they are on.
- The frame files (`flower1..3.png`) are raw grayscale and have to land on
  the colours of the tile they replace, but the two recolour paths do not
  share a rule -- SGB bakes one world palette over everything, RED++ picks
  a palette group per tile graphic. So the shade mapping is LEARNED from
  the atlas: read the static tile's slot in the raw art and in the finished
  atlas side by side and ask what each shade became. Right under both
  without this file knowing which one ran.
- Terrain art was off the pixel grid by up to half a pixel, with one art
  pixel per tile sampled twice and another never at all. A tile is 8
  texels across 8 world pixels -- one texel per pixel exactly -- and
  `ChunkMesher`'s uv inset squeezed that art into a 7-texel sample range
  while the quad still covered 8 world pixels, so it advanced 7/8 of a
  texel per pixel and drifted. The inset exists to stop the rasteriser
  reaching a neighbouring tile along a shared edge, but half a texel was
  fifty times more than that needs: 0.02 is as safe (interpolation error
  is nowhere near it) and drifts 0.25% of a pixel across a whole tile.
  Nothing showed the fault until the voxel wireframe drew the grid those
  pixels were supposed to be sitting on.

### Changed from the pre-mod version

- The level is no longer the mod's to keep. The engine owns the ladder, the
  options rows, the hotkeys, persistence and the TILT exclusion; the mod
  keeps only the camera-angle tween.
- Persistence moved from `save.options.voxel` / `save.options.tiltshift` to
  `save.options.pipelines.voxel` / `.tiltshift`.
- Hotkeys moved from `4`/`9` to `3`/`6`: the fork already uses `4` for
  survey zoom.
- The tilt-shift pass is a declared `worldPresent` stage rather than a call
  spliced into the world draw, so it composes with any world pipeline
  instead of only this one.
- The cut-tree animation now draws in voxel mode; the pre-mod version
  omitted it from the 3D field-effect list.