Repository navigation
Expand file tree
/
Copy pathfeatures.html
More file actions
878 lines (783 loc) · 113 KB
/
Copy pathfeatures.html
File metadata and controls
878 lines (783 loc) · 113 KB
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Features - CNA</title>
<meta name="description" content="Explore CNA snapshot c1c316b9: XNA 4.0 compatibility, four independent build axes (target OS, platform, renderer and audio) with SDL3 as the one windowing platform, 14 renderer identities in 12 families, XNB and CNB content, effects, PBR, Gamer Services, the C ABI and CNA.NET, with the evidence behind each.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="CNA">
<meta property="og:url" content="https://libcna.com/features.html">
<meta property="og:title" content="Features - CNA">
<meta property="og:description" content="Explore CNA snapshot c1c316b9: XNA 4.0 compatibility, four independent build axes (target OS, platform, renderer and audio) with SDL3 as the one windowing platform, 14 renderer identities in 12 families, XNB and CNB content, effects, PBR, Gamer Services, the C ABI and CNA.NET, with the evidence behind each.">
<link rel="stylesheet" href="css/style.css">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="canonical" href="https://libcna.com/features.html">
<link rel="stylesheet" href="css/prism-tomorrow.min.css">
<script>(function(){try{var t=localStorage.getItem("cna-theme");if(t==="light"||t==="dark")document.documentElement.setAttribute("data-theme",t);}catch(e){}})();</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "Features - CNA",
"url": "https://libcna.com/features.html",
"description": "Explore CNA snapshot c1c316b9: XNA 4.0 compatibility, four independent build axes (target OS, platform, renderer and audio) with SDL3 as the one windowing platform, 14 renderer identities in 12 families, XNB and CNB content, effects, PBR, Gamer Services, the C ABI and CNA.NET, with the evidence behind each.",
"dateModified": "2026-10-09"
}
</script>
</head>
<body>
<a class="skip-link" href="#main-content">Skip to content</a>
<nav class="nav">
<div class="nav-container">
<a href="index.html" class="nav-brand">CNA</a>
<button class="nav-toggle" aria-label="Toggle navigation" aria-expanded="false">
<span></span><span></span><span></span>
</button>
<div class="nav-menu">
<a href="index.html" class="nav-link">Home</a>
<a href="about.html" class="nav-link">About</a>
<a href="features.html" class="nav-link">Features</a>
<a href="architecture.html" class="nav-link">Architecture</a>
<a href="documentation.html" class="nav-link">Documentation</a>
<a href="development/index.html" class="nav-link">Development</a>
<a href="deep-dives/index.html" class="nav-link">Deep Dives</a>
<a href="tutorials.html" class="nav-link">Tutorials</a>
<a href="demos.html" class="nav-link">Demos</a>
<a href="showcase.html" class="nav-link">Showcase</a>
<a href="videos.html" class="nav-link">Videos</a>
<a href="roadmap.html" class="nav-link">Roadmap</a>
<a href="contact.html" class="nav-link">Contact</a>
<a href="network.html" class="nav-link">Network</a>
<a href="search.html" class="nav-link">Search</a>
<a href="https://github.com/libcna/cna" class="nav-link nav-link--github" target="_blank" rel="noopener">GitHub</a><a href="https://blog.libcna.com/" class="nav-link nav-link--blog" target="_blank" rel="noopener">Blog</a>
<a href="https://www.youtube.com/@libcna" class="nav-link nav-link--youtube" target="_blank" rel="noopener">YouTube</a>
<a href="https://discord.gg/vrnc4n6DaE" class="nav-link nav-link--discord" target="_blank" rel="noopener">Discord</a>
</div>
<button class="theme-toggle" type="button" aria-label="Switch to light theme" title="Switch to light theme">
<svg class="theme-icon-light" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 17a5 5 0 1 1 0-10 5 5 0 0 1 0 10zm0-2a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.5 4.9l1.4-1.4 2.1 2.1-1.4 1.4L3.5 4.9zm13.5 13.5l1.4-1.4 2.1 2.1-1.4 1.4-2.1-2.1zM19.1 3.5l1.4 1.4-2.1 2.1-1.4-1.4 2.1-2.1zM5.6 17l1.4 1.4-2.1 2.1-1.4-1.4L5.6 17zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></svg>
<svg class="theme-icon-dark" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12.3 22a10 10 0 0 1-1.6-19.9c.6-.1 1 .5.8 1a7.9 7.9 0 0 0 9.7 10.6c.5-.2 1 .3.9.8A10 10 0 0 1 12.3 22z"/></svg>
</button>
</div>
</nav>
<main id="main-content">
<div class="page-header">
<div class="container">
<span class="section-label">Features</span>
<h1>What CNA offers</h1>
<p>CNA provides a structured, incremental C++ implementation of the XNA 4.0 programming model. Below is a detailed overview of what the current development snapshot provides, where it is still partial, and what remains planned.</p>
</div>
</div>
<section class="section">
<div class="container">
<div class="callout callout--warn">
<span class="callout-icon">⚠</span>
<p><strong>This page describes CNA c1c316b9 (post 0.1.0-alpha.1).</strong> That is a development snapshot: branch <code>apple/m4-stabilization</code> as of 9 October 2026, 3,687 commits after the tag <code>v0.1.0-alpha.1</code>; CNA's product version string is still <code>0.1.0-alpha.1</code> and no newer tag exists. Compared with alpha.1 it has a curated set of 14 renderer identities in 12 implementation families, SDL3 as the one windowing platform (Windows, X11 and Wayland through SDL’s video drivers), an SDL-optional windowless build, ALSA audio with CNA's own mixer, a build-time content pipeline with the CNB format and an XNB writer, Framework.Design converters, Diagnostics and Inspector modules, a renderer capability-profile API, service-backed Gamer Services with an optional server, and an experimental C ABI at version 0.46.0 that the C# binding CNA.NET builds on. Presence is not the same as behavior: use the per-renderer capability and verification pages, and expect API changes before 1.0. Build it from commit <code>c1c316b9</code> on branch <code>apple/m4-stabilization</code> (sharp-runtime and meta-gl on their branches of the same name); the repository's default branch still points at alpha.1. See the <a href="docs/releases.html">release notes</a>.</p>
</div>
<!-- XNA API -->
<span class="section-label">Core API</span>
<h2 id="xna-api">XNA 4.0 API Implementation</h2>
<p class="section-desc">CNA mirrors the <code>Microsoft::Xna::Framework</code> namespace hierarchy, translating XNA's C# API into idiomatic C++23.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-blue">⚙</div>
<span class="status-badge status-done">Implemented</span>
<h3>Game Loop</h3>
<p>The <code>Game</code> base class provides the full <code>Initialize()</code>, <code>LoadContent()</code>, <code>Update()</code>, <code>Draw()</code>, <code>UnloadContent()</code> lifecycle. <code>GameTime</code>, <code>GameComponent</code>, <code>DrawableGameComponent</code>, <code>GameComponentCollection</code>, <code>GameWindow</code>, and <code>FrameworkDispatcher</code> are all implemented.</p>
<p style="margin-top:0.5rem;"><strong>XNA clock semantics:</strong> with a fixed time step the first <code>Update</code> runs with <code>ElapsedGameTime</code> equal to zero (a variable time step reports the measured elapsed time) and <code>TotalGameTime</code> advances after <code>Update</code> returns, as measured on the real XNA runtime (alpha.1 followed FNA here); the default presentation mode of <code>GraphicsDeviceManager</code> is <code>Letterbox</code>. The rule applies to the native <code>Tick()</code> path; the Emscripten main-loop callback keeps its own fixed-step accumulator. The <code>Game</code> constructor now registers the built-in XNB readers, and on Emscripten <code>Game::Run()</code> no longer unwinds the caller, so a stack-allocated <code>Game</code> is legal (application executables opt in to Asyncify).</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🎨</div>
<span class="status-badge status-done">Implemented</span>
<h3>SpriteBatch</h3>
<p>Full 2D rendering abstraction. Supports all <code>SpriteSortMode</code> values, transform matrix, custom <code>Effect</code>, blend and sampler states. <code>DrawString</code> with <code>SpriteFont</code> included. Renderer-agnostic across all 12 identities that produce pixels; <code>HEADLESS</code> validates and traces the calls and <code>STUB</code> discards them.</p>
<p style="margin-top:0.5rem;"><strong>XNA behavior kept:</strong> <code>Begin</code> has eight overloads (including <code>const BlendState*</code> variants), destinations stay sub-pixel, <code>DrawString</code> follows XNA's first-glyph rule, and <code>SpriteBatch</code> never restores blend, sampler, depth or rasterizer state after <code>End</code>. See the <a href="docs/spritebatch.html">SpriteBatch guide</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">📷</div>
<span class="status-badge status-done">Implemented</span>
<h3>Texture2D</h3>
<p>Full texture lifecycle: load from disk, <code>GetData</code>/<code>SetData</code> for all mip levels, <code>SaveAsPng</code>/<code>SaveAsJpeg</code>, pixel cache. <code>RenderTarget2D</code> is a proper subclass with FBO + depth renderbuffer (EasyGL), off-screen Vulkan images, or the equivalent native target on the other 3D renderers; its <code>IsContentLost</code> flag and <code>ContentLost</code> event are real.</p>
<p style="margin-top:0.5rem;"><strong>Known gap:</strong> public format support is renderer-qualified. <code>SurfaceFormat</code> has 27 members (20 XNA plus 7 CNAEXT); eight renderer families (<code>SDL_GPU</code>, <code>VULKAN</code>, <code>WEBGPU</code>, <code>DIRECTX11</code>, <code>METAL</code>, <code>FNA3D</code>, the EasyGL family and <code>SOFTWARE</code>) classify Texture2D formats themselves, and all of them but <code>FNA3D</code> classify render-target formats too, while the rest defer to the framework's <code>SurfaceFormat::Color</code>-only rule, under which any other format throws. The default <code>GraphicsProfile</code> is <code>Reach</code>, so HiDef-only formats also throw unless <code>HiDef</code> is requested. An internal native-format table does not by itself make that format constructible through the public API.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">💥</div>
<span class="status-badge status-done">Implemented</span>
<h3>GraphicsDevice</h3>
<p>Full render state API: <code>BlendState</code>, <code>DepthStencilState</code>, <code>RasterizerState</code>, <code>SamplerState</code>, scissor rect, viewport, render targets. <code>DrawPrimitives</code>, <code>DrawIndexedPrimitives</code>, <code>DrawUserIndexedPrimitives</code> (including the XNA generic-array overloads, spelled with <code>std::vector</code>), <code>DrawInstancedPrimitives</code> (hardware-accelerated on the renderers that support instancing), <code>GetBackBufferData<Color></code> all implemented. <code>GraphicsDevice</code> exposes all 6 XNA events and all 5 <code>Draw*</code> families. State objects follow XNA's binding rule: mutating one after it was bound to a device throws <code>InvalidOperationException</code>.</p>
<p style="margin-top:0.5rem;"><strong>Cross-renderer caveat:</strong> <code>GraphicsCapability</code> now has 19 members. The base <code>SupportsCapability()</code> still answers <code>true</code> for most of the original members, but only <code>DIRECTX9</code> relies on that default wholesale; every other renderer overrides it, and <code>GraphicsDevice</code> itself derives six answers (compiled effects, float and half-float render targets, half-float filtering, compute, indirect draw) from hooks that default to <code>false</code> and ANDs multiple render targets with the profile limit. Treat a <code>true</code> from <code>DIRECTX9</code> as "not contradicted", and use the capability-profile API below when you need detail.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🏹</div>
<span class="status-badge status-done">Implemented</span>
<h3>Math Types</h3>
<p>Complete math library: <code>Vector2/3/4</code>, <code>Matrix</code>, <code>Quaternion</code>, <code>Color</code>, <code>Rectangle</code>, <code>Point</code>, <code>BoundingBox</code>, <code>BoundingSphere</code>, <code>BoundingFrustum</code>, <code>Plane</code>, <code>Ray</code>, <code>MathHelper</code>, <code>Curve</code>, <code>CurveKey</code>. All operators, static factories, and interpolation methods. <code>Matrix</code> has all 30 statics including <code>Decompose</code>, billboards, shadow and reflection; <code>Curve::Evaluate</code> handles all 5 loop types; <code>Color</code> carries all 141 named constants. <code>Vector3::Transform</code>, matrix products and inversion, and <code>BoundingSphere::CreateFromPoints</code> reproduce XNA's 32-bit x87 accumulation width, so results can differ in the last bits from alpha.1; <code>Vector3::Length</code> and <code>Distance</code> still sum in <code>float</code> and can differ in the last bit from XNA. A known gap in the core <code>Framework</code> namespace is <code>BoundingFrustum::Intersects(Ray)</code>: unlike real XNA 4.0, which computes the entry distance, CNA reports no hit for every ray whose origin is outside the frustum, 0 for an origin inside, and throws <code>NotImplementedException</code> only for an origin exactly on a frustum plane. It is not the only one: <code>BoundingSphere::Contains(BoundingFrustum)</code> and <code>BoundingBox::Contains(BoundingFrustum)</code> never answer <code>Disjoint</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">📊</div>
<span class="status-badge status-done">Implemented</span>
<h3>PackedVector Types</h3>
<p>All <strong>17 XNA 4.0 PackedVector types</strong> implemented in the <code>Microsoft::Xna::Framework::Graphics::PackedVector</code> namespace: <code>Byte4</code>, <code>HalfSingle</code>, <code>HalfVector2/4</code>, <code>NormalizedByte2/4</code>, <code>NormalizedShort2/4</code>, <code>Rg32</code>, <code>Rgba1010102</code>, <code>Rgba64</code>, <code>Short2/4</code>, <code>Vector2/4</code>. A correct IEEE 754 half-float codec is implemented from scratch, handling subnormals, infinities and NaN in both directions. Float-taking constructors now saturate, round ties-to-even and pack NaN as zero, checked against 68 measurements from the genuine XNA 4.0 runtime. The alpha.1 gap is closed: all 17 types now have <code>ToString()</code> (the packed value in hex), <code>GetHashCode()</code> and <code>Equals</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🎮</div>
<span class="status-badge status-done">Implemented</span>
<h3>Input</h3>
<p>The <code>Input</code> namespace has <strong>zero stubs</strong>. <code>Keyboard</code> exposes all 160 <code>Keys</code> members; <code>Mouse</code> covers position, buttons and wheel; on the SDL3 platform — the platform of every windowed build — <code>GamePad</code> is a real SDL3 bridge with rumble, trigger rumble, LED control, hot-plug and per-device capability probing. <code>TouchPanel</code> genuinely detects <strong>all 10 XNA gesture types</strong> via a 474-line state machine with exponentially-smoothed flick velocity; optional mouse-to-touch emulation is off by default. A MIME-typed <code>CNA::Input::Clipboard</code> API is new.</p>
<p style="margin-top:0.5rem;"><strong>Known bug:</strong> <code>TouchCollection</code> reports <code>IsReadOnly == true</code>, but its mutators mutate instead of throwing.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🔋</div>
<span class="status-badge status-done">Implemented (~85–90%)</span>
<h3>Devices & Sensors</h3>
<p>The <code>Microsoft::Devices</code> namespace talks to real hardware. <code>Accelerometer</code> and <code>Gyroscope</code> use the SDL sensor path on Android, iOS and desktop with m/s²-to-g conversion and concurrency handling. <code>VibrateController</code> uses haptics and deliberately excludes gamepads. <code>Compass</code> and <code>Motion</code> are Android-only and report <code>NotSupported</code> elsewhere. <code>Microsoft::Devices::Environment</code> reports <code>Device</code> on mobile targets and <code>Emulator</code> elsewhere.</p>
<p style="margin-top:0.5rem;"><strong>Build and evidence:</strong> the <code>CNA_DEVICES</code> CMake option defaults to <strong>OFF</strong> and gates only the CNA-specific <code>CNA::Devices</code> extensions (the <code>Microsoft::Devices</code> sensors are always built). The path-filtered <code>devices-tests.yml</code> workflow turns it on and runs the Microsoft::Devices and CNA::Devices suites named in its two test filters with UBSan on desktop Linux (the filters miss seven Microsoft::Devices suites and, by naming renamed dialog suites, four CNA::Devices ones); hardware-dependent checks self-skip when no physical sensor is present.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🎵</div>
<span class="status-badge status-done">Implemented (~92%)</span>
<h3>Audio</h3>
<p><strong>Implemented (SDL3_mixer, or CNA's own mixer on ALSA):</strong> <code>SoundEffect</code>, <code>SoundEffectInstance</code> (volume, pitch, pan, looping), <code>DynamicSoundEffectInstance</code>, <code>MediaPlayer</code>/<code>Song</code>. Multi-listener <code>Apply3D</code> accepts any positive listener count (the nearest listener decides); <code>Microphone</code> capture is real on SDL3 and ALSA.<br>
<strong>XACT is a real parser and player</strong>, not a facade: a binary parser for XGS/XWB/XSB behind <code>AudioEngine</code>, <code>SoundBank</code>, <code>WaveBank</code> and <code>Cue</code>, using FACT volume and RPC behavior. The default output path is SDL3_mixer; audio-platform selection is independent (see Platform and audio implementations).</p>
<p style="margin-top:0.5rem;"><strong>Known gaps:</strong> only the first <code>PlayWave</code> per track is honoured; XMA and WMA wave-bank entries are <em>not</em> decoded — they log a diagnostic and yield a null sound rather than throwing, so the effect is silently missing; reverb send is a deliberate no-op; <code>.m4a</code>/<code>.aac</code> are unplayable; and neither mixer decodes Opus (the vendored SDL3_mixer is built with Opus off, and CNA's own ALSA mixer refuses it).</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">💾</div>
<span class="status-badge status-partial">Partial — read at run time, write at build time</span>
<h3>Content System & <code>.xnb</code> Pipeline</h3>
<p>Extensible <code>ContentManager</code> with the <code>ContentTypeReader<T></code> pattern. <code>Load<T>()</code> returns the asset by value and resolves a name through a ladder: <code>.xnb</code>, then <code>.cnb</code> (CNA's own binary container), then loose files — <code>Texture2D</code> (PNG/BMP/etc.), <code>SoundEffect</code> (WAV), <code>Song</code>, <code>Video</code>, plus <code>SpriteFont</code>, <code>Model</code> and <code>Effect</code> from CNA's <code>.cnj</code> JSON descriptor format.</p>
<p style="margin-top:0.5rem;"><strong>A real <code>.xnb</code> loader exists.</strong> It offers 61 built-in readers (60 without native 128-bit integer support), including typed external references and a renderer-qualified compiled-effect reader. LZX decompression, shared resources and malformed-input checks are implemented. The <code>Game</code> constructor registers the built-ins; a stand-alone <code>ContentManager</code> (tools, tests) still starts with an empty registry and needs <code>CNA::Internal::Xnb::RegisterAllBuiltInXnbReaders()</code>.</p>
<p style="margin-top:0.5rem;"><strong>CNA now also writes content.</strong> The build-time tool <code>cna-content</code> compiles source assets to <code>.cnb</code> or <code>.xnb</code> (see Content Pipeline & Formats below); it is not linked into a shipped game. <code>ResourceContentManager</code> is implemented as well (XNA's constructor and its protected <code>OpenStream</code>).</p>
<p style="margin-top:0.5rem;"><strong>Known boundaries:</strong> CNA cannot discover arbitrary game types through .NET reflection, but a game can register an explicit <code>ContentTypeReader<T></code> factory or declare a field list once with <code>ReflectiveTypeReaderBuilder<T></code>. The real <code>EffectReader</code> requires an active renderer with <code>CompiledEffects</code>, and closed generic readers beyond the pre-registered ones still need explicit registration. Public <code>Load<T></code> still uses the file ladder, so only derived classes reach the resource-stream path.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🌐</div>
<span class="status-badge status-done">Implemented with documented limits</span>
<h3>Networking</h3>
<p>The <code>Net</code> namespace provides ENet networking and SystemLink/LAN discovery. CNA's own service supports <code>PlayerMatch</code> and <code>Ranked</code> discovery, invitations, authenticated WSS relay, restart recovery and host migration. Online sessions use relay from the outset; there is no direct Internet peer negotiation or STUN/ICE hole punching. Optional Opus voice has capture, encode, transport, decode and playback implementations, with one local talker per machine. Loopback and synthetic voice paths are tested; real WAN/NAT, microphone/speaker and cross-platform qualification remain separate.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🎮</div>
<span class="status-badge status-partial">Local runtime and CNA online service</span>
<h3>GamerServices & Avatar</h3>
<p>CNA implements XNA-style GamerServices APIs backed by local profiles and a real CNA HTTPS/SQLite service: account sign-in, profiles, friends, presence, messages, achievements and leaderboards, player reviews, parties and per-account avatars. Local progress uses checked, locked JSON replacement and reloads after application restart; it does not promise power-loss durability. Achievements and eligible scores are authenticated title-managed claims, with server-derived timestamps, aggregation and ranking; ranked agreement does not prove gameplay or implement TrueSkill.</p>
<p style="margin-top:0.5rem;"><strong>Guide and avatars:</strong> Guide provides custom in-game sign-in, keyboard/message boxes, social panes, invitations, avatar editing and notifications. Standard <code>AvatarRenderer::Draw()</code> loads CNA models and issues SkinnedEffect draws using a 71-bone skeleton. Avatar descriptions, catalogs, assets and animations are CNA-owned formats and art; matching XNA names or the 1021-byte buffer does not make them compatible with Xbox avatar data.</p>
<p style="margin-top:0.5rem;"><strong>Boundaries:</strong> this service does not interoperate with Xbox Live/Microsoft identity, partner tokens, marketplace commerce or Xbox avatar assets. Guide is custom game UI, and marketplace screens do not provide real payment. Browser online transport, service-computed skill, online guests and online pre-join QoS remain partial or unsupported. Software tests establish working paths without certifying every original Xbox behavior or physical device.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🧩</div>
<span class="status-badge status-done">Implemented (opt-in module)</span>
<h3>Framework.Design converters</h3>
<p><code>Microsoft::Xna::Framework::Design</code> is implemented as the opt-in <code>CNA::Design</code> module: <code>MathTypeConverter</code> (derived from <code>System::ComponentModel::ExpandableObjectConverter</code>) plus twelve concrete converters for <code>Point</code>, <code>Rectangle</code>, <code>Vector2/3/4</code>, <code>Quaternion</code>, <code>Matrix</code>, <code>Color</code>, <code>BoundingBox</code>, <code>BoundingSphere</code>, <code>Plane</code> and <code>Ray</code>. Property lists follow XNA's order, string parsing is culture-aware for the types that accept strings, and malformed text throws <code>ArgumentException</code>. Registered with <code>EnsureFrameworkDesignConvertersRegistered()</code>; 25 test definitions.</p>
<p style="margin-top:0.5rem;"><strong>Boundary:</strong> it needs the sharp-runtime ComponentModel implementation and is deliberately outside the <code>CNA</code> umbrella target — link <code>CNA::Design</code> explicitly. The Windows Forms property-grid side has no C++ counterpart. Alpha.1 documented this namespace as the one XNA area CNA did not cover. See <a href="docs/design-converters.html">Framework.Design converters</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">📱</div>
<span class="status-badge status-done">Implemented (opt-in module)</span>
<h3>Windows Phone shell & push (Microsoft::Phone)</h3>
<p>The new <code>phone</code> module provides <code>Microsoft::Phone::Shell</code> (<code>PhoneApplicationService</code> with Launching, Activated, Deactivated and Closing events driven from <code>Game</code>'s platform lifecycle after an <code>AttachEXT</code> call) and <code>Microsoft::Phone::Notification</code> (<code>HttpNotificationChannel</code>, which is its own local HTTP listener thread, <code>RawPushNotificationMessage</code> and <code>ToastPushNotificationMessage</code>). It is the Windows Phone 7 lifecycle and push API rather than XNA 4.0, is linked only when a game names <code>cna_phone</code>, and is outside the C API scope. 18 test definitions.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">📋</div>
<span class="status-badge status-done">Represented — not the same as verified</span>
<h3>XNA API coverage census</h3>
<p>All <strong>331 documented XNA 4.0 runtime types</strong> and <strong>3,627 documented members</strong> (253 constructors, 1,518 methods, 1,040 properties, 753 fields, 63 events) have a matching C++ declaration in this snapshot, measured by <code>tools/audit_xna_runtime_surface.py</code>, a Clang-based census against Microsoft's own XML documentation and DLL metadata. The XNA Content Pipeline assembly is a separate census (128 of 128 types, 705 of 705 members, 10 importers, 12 processors).</p>
<p style="margin-top:0.5rem;"><strong>Read it correctly:</strong> the report itself says it measures <em>representation</em> of the documented surface only. Behavior, exception detail, renderer output and online-service availability are separate measures, verified only for the subsets listed on <a href="docs/verification.html">Verification & Known Issues</a>. The census is a manual script, not a CTest or CI gate; only the Input namespace has a compile-time signature freeze. See <a href="docs/xna-compatibility.html">XNA compatibility</a>.</p>
</div>
</div>
<!-- 3D Graphics -->
<span class="section-label">3D Graphics</span>
<h2 id="rendering-pipeline">3D Rendering Pipeline</h2>
<p class="section-desc">Twelve of the 14 renderer identities report a 3D pipeline (<code>HEADLESS</code> only validates the calls). <code>SDL_RENDERER</code> is deliberately 2D-only and refuses 3D calls deterministically rather than silently doing nothing, and <code>STUB</code> is a no-op that reports no 3D either. The desktop and ES GL profiles, Vulkan and the Direct3D 9 and 11 renderers are declared Production by CNA, Metal and SDL_GPU Supported; SDL_GPU (declared Supported) and the CPU Software rasterizer (Experimental) are the fast-moving 3D paths.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-blue">🏠</div>
<span class="status-badge status-done">Implemented (12 identities)</span>
<h3>3D Rendering</h3>
<p>Vertex layouts, depth test/write, blend, cull mode and matrix upload across every renderer that reports <code>ThreeD</code>; the stock effects carry per-renderer shader sets for EasyGL, Vulkan, SDL_GPU, WebGPU and the Direct3D renderers. Tested with the House 3D demo — procedural walls, roof, windows, door, floor with player movement and gravity. Also runs via WebGL 2 in the browser. See the <a href="docs/3d-rendering.html">3D rendering guide</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">✨</div>
<span class="status-badge status-done">Implemented</span>
<h3>Effects System</h3>
<p>All five XNA stock effects — <code>BasicEffect</code>, <code>AlphaTestEffect</code>, <code>DualTextureEffect</code>, <code>EnvironmentMapEffect</code>, <code>SkinnedEffect</code> — and a public <code>SpriteEffect</code> (XNA keeps its sprite effect internal), implemented natively in C++ rather than translated from bytecode. All <code>IEffectMatrices</code>, <code>IEffectFog</code> and <code>IEffectLights</code> interfaces, and <code>EffectParameter</code> with all Get/Set overloads.</p>
<p style="margin-top:0.5rem;"><strong>Compiled effects:</strong> already-compiled XNA/FNA Direct3D 9 Effect Framework binaries (<code>.fxb</code>, or an XNB <code>Effect</code> through <code>EffectReader</code>) run on <strong>11 of the 14 identities in 9 families</strong>: <code>FNA3D</code> always, and 10 identities behind default-OFF build options (one option enables all three EasyGL identities; Vulkan, WebGPU, Software, Direct3D 9, Direct3D 11, SDL_GPU and Metal each have their own). A default configure therefore reports <code>CompiledEffects</code> true on <code>FNA3D</code> only. <code>Effect(GraphicsDevice&, bytes)</code> is a real constructor, not a throwing stub; MGFX and DXBC are refused. CNA does not compile HLSL <code>.fx</code> at run time. At build time <code>cna-content</code> compiles <code>.fx</code> through an external legacy <code>fxc</code> (not yet checked against a genuine Microsoft <code>fxc</code>). CNAEXT <code>ShaderEffect</code> remains the renderer-oriented source path (GLSL, SPIR-V, WGSL or HLSL, depending on the renderer). See <a href="docs/effects.html">Effects</a> and <a href="docs/tutorials/128-compiled-xna-effects.html">Tutorial 128</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">✨</div>
<span class="status-badge status-done">Implemented (CNAEXT)</span>
<h3>PBR & Skeletal Animation</h3>
<p>Beyond the XNA stock set, CNA ships non-XNA effects and types: <code>PbrEffect</code> and <code>SkinnedPbrEffect</code> for physically based rendering, and a full skeletal-animation stack (<code>SkinningData</code> on <code>Model::Tag</code> with <code>AnimationPlayer</code>, <code>AnimationClipEXT</code>, <code>BoneTrackEXT</code> and <code>KeyframeEXT</code>, alongside the separate Avatar-oriented <code>SkinnedModelEXT</code>). <code>MorphTargetEXT</code> adds blend shapes, alongside tangent and skinned vertex types and sRGB/BC7 surface formats. Shadow-receiver and image-based-light state (<code>IShadowReceiverEXT</code>, <code>ImageBasedLightEXT</code>, punctual and area lights) sit on the effects.</p>
<p style="margin-top:0.5rem;"><strong>Where it draws:</strong> full metallic-roughness PBR with specular-texture sampling on seven families (9 identities: <code>DIRECTX9/11</code>, the three EasyGL identities, <code>SDL_GPU</code>, <code>VULKAN</code>, <code>WEBGPU</code>, <code>METAL</code>); a reduced CPU cross-check on <code>SOFTWARE</code>; <code>FNA3D</code> refuses PBR draws by name. Direct glTF loads assign <code>PbrEffect</code>/<code>SkinnedPbrEffect</code> per mesh part. Shadow <em>sampling</em> and image-based lighting are honoured only by the EasyGL identities, <code>VULKAN</code>, <code>SDL_GPU</code> and <code>WEBGPU</code>; a renderer without them accepts the state and ignores it. The shadow map and environment textures themselves are rendered by the application.</p>
<p style="margin-top:0.5rem;"><strong>Build boundary:</strong> these XNA-shaped extensions are always compiled. The <code>CNA_CNAEXT</code> CMake option defaults to <strong>OFF</strong> and gates only the separate <code>CNA::Graphics</code> module (next card). No CI workflow enables <code>CNA_CNAEXT</code>; verify the exact extension and renderer configuration you ship.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">🌟</div>
<span class="status-badge status-wip">Opt-in — small module</span>
<h3>CNAEXT extensions (<code>CNA::Graphics</code>)</h3>
<p>With <code>-DCNA_CNAEXT=ON</code> CNA adds a small module of graphics helpers that XNA never had: three retro post-processing effects — <code>CRTEffect</code> (scanlines, curvature, vignette, display masks), <code>DepthEffect</code> (colour-depth and palette reduction with optional ordered dithering) and <code>AsciiPostProcessEffect</code> (an ASCII-art rendering of any finished frame) — plus <code>DebugDraw</code> for debug lines, boxes, spheres and frusta, and portable shader packages (<code>ShaderCodeEXT</code>, <code>ShaderPackageEXT</code>) for <code>ShaderEffect</code>.</p>
<p style="margin-top:0.5rem;"><strong>Requirements:</strong> the CRT and colour-depth effects need a renderer that executes custom <code>ShaderEffect</code> source from their package (the EasyGL family, <code>VULKAN</code>, <code>WEBGPU</code>; HLSL variants exist but are unproven on Direct3D); the ASCII effect and <code>DebugDraw</code> run on any renderer with readback or <code>BasicEffect</code>. No CI workflow builds the module. See <a href="docs/cnaext-extensions.html">CNAEXT extensions</a> and <a href="docs/tutorials/116-post-process-effects.html">Tutorial 116</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">📈</div>
<span class="status-badge status-done">Implemented</span>
<h3>Vertex & Index Buffers</h3>
<p><code>VertexBuffer</code>, <code>DynamicVertexBuffer</code>, <code>IndexBuffer</code> (16/32-bit), <code>DynamicIndexBuffer</code>. All four <code>VertexPosition*</code> types: <code>VertexPositionColor</code>, <code>VertexPositionTexture</code>, <code>VertexPositionColorTexture</code>, <code>VertexPositionNormalTexture</code>. Under the default <code>Reach</code> profile 32-bit indices throw unless <code>HiDef</code> is requested. A buffer that is currently bound cannot be rewritten (<code>SetData</code> throws) unless you use <code>SetDataOptions::Discard</code> or <code>NoOverwrite</code> on a dynamic buffer.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🌹</div>
<span class="status-badge status-done">Implemented</span>
<h3>Model System</h3>
<p><code>Model::Draw</code> with bone transforms, <code>IEffectMatrices</code> binding, and a full mesh/part rendering pipeline. Models load from <code>.cnj</code> descriptors, from <code>.gltf</code>/<code>.glb</code> directly, or from <code>.xnb</code> and <code>.cnb</code> via <code>ContentManager</code>. Content routes are now plural: direct runtime glTF, <code>.cnb</code>/<code>.xnb</code> compiled by <code>cna-content</code>, and <code>gltf_to_cnj</code>, the offline glTF 2.0 → <code>.cnj</code> Model/AnimationClip converter that is built unconditionally. Runtime glTF imports every mesh group into one <code>Model</code>, keeps skins and rigid node animation, and enforces <code>extensionsRequired</code>. See <a href="docs/model-loading.html">Model loading</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🎦</div>
<span class="status-badge status-done">Implemented</span>
<h3>SpriteFont</h3>
<p>Full glyph data model, <code>MeasureString</code>, and <code>SpriteBatch::DrawString</code> with three overloads. Fonts load from <code>.cnj</code> descriptors naming a pre-rendered glyph atlas, from <code>.xnb</code>/<code>.cnb</code>, or are built from a <code>.spritefont</code> description by <code>cna-content</code> (FreeType, <code>CNA_ENABLE_FONT_PIPELINE</code>, default AUTO).</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🎬</div>
<span class="status-badge status-partial">Partial</span>
<h3>Media & Video Playback</h3>
<p><strong>Real:</strong> <code>MediaPlayer</code> genuinely plays songs through the selected mixer (SDL3_mixer, or CNA's own mixer on ALSA) and exposes a real <strong>FFT spectrum and waveform</strong> via <code>GetVisualizationData</code>, captured from the live post-mix callback. <code>VideoPlayer</code> genuinely decodes video through FFmpeg (real libavcodec/libavformat/libswresample with PTS-driven pacing) when the backend is built, plays the video's own <strong>audio track</strong>, and supports multi-track selection. The <code>MediaLibrary</code> catalogue is also real: it resolves your actual Music and Pictures folders, scans them recursively, parses ID3v2, Vorbis-comment, Opus and FLAC tags, probes durations, discovers album art, reads playlists and saves pictures to disk.</p>
<p style="margin-top:0.5rem;"><strong>Known gaps:</strong> FFmpeg is now <strong>optional</strong>: <code>CNA_ENABLE_VIDEO</code> is <code>AUTO</code> (default, enabled only when libavcodec, libavformat, libavutil and libswresample are found), <code>ON</code> (requires them) or <code>OFF</code>. The <code>Video</code> and <code>VideoPlayer</code> types and the XNB <code>VideoReader</code> exist in every build; without the backend a file-backed <code>Video</code> or <code>VideoPlayer::Play</code> throws <code>NotSupportedException</code> at run time instead of failing to link. FFmpeg is never built on Windows, Emscripten, Android or iOS, so real video playback is native Linux/macOS only, and the optional split was not run on macOS by its author. Unrecognised video pixel formats render magenta rather than raising an error. See <a href="docs/video-playback.html">Video playback</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">💾</div>
<span class="status-badge status-done">Implemented (100%)</span>
<h3>Storage</h3>
<p>All 3 <code>Storage</code> types use real <code>std::filesystem</code> IO, a hand-written glob matcher, and <code><root>/<displayName>/Player{N}</code> namespacing. The async <code>Begin*</code>/<code>End*</code> pairs execute synchronously. New: container names and every container-relative path are contained — absolute paths, <code>..</code> escapes and symlink escapes throw <code>std::invalid_argument</code>. The root comes from <code>XDG_DATA_HOME</code>, <code>%LOCALAPPDATA%</code> or the platform equivalent (not <code>SDL_GetPrefPath</code>) under an app name that is the literal <code>game</code> unless the program calls <code>StorageDevice::SetAppNameEXT</code>.</p>
<p style="margin-top:0.5rem;"><strong>Caveats:</strong> the Storage module has one test source with 14 static definitions (ten on path containment and container deletion, four on an exception round trip) and no read/write round-trip test, so applications should verify their target filesystem behavior. On the web CNA mounts no persistent file system: anything written is lost on page reload unless you persist through your own browser storage.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🔀</div>
<span class="status-badge status-partial">Renderer-dependent</span>
<h3>Multisample Anti-Aliasing</h3>
<p>Enabled via <code>GraphicsDeviceManager</code>: set <code>PreferMultiSampling = true</code> and <code>MultiSampleCount</code> on <code>PresentationParameters</code> before device creation. Support is decided per device: MSAA is reported (probed where the API requires it) on the EasyGL identities, <strong>Vulkan</strong>, <strong>WebGPU</strong>, <strong>SDL_GPU</strong>, <strong>Direct3D 11</strong>, <strong>Metal</strong> (from the device’s sample counts) and <code>FNA3D</code>; <strong>Software</strong> implements 4x MSAA on the CPU. It is not available on the 2D-only <code>SDL_RENDERER</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🔍</div>
<span class="status-badge status-partial">Renderer-dependent</span>
<h3>OcclusionQuery</h3>
<p>Hardware occlusion queries are reported by the EasyGL identities, <strong>Vulkan</strong>, <strong>WebGPU</strong> (counts reported as imprecise on a Metal adapter), <strong>Direct3D 9/11</strong> and <strong>Metal</strong>, by <code>FNA3D</code> where its driver has them, by <code>SOFTWARE</code> as a CPU implementation, and by <code>HEADLESS</code> without rasterizing. They are not available on <code>SDL_GPU</code> (SDL’s GPU API has no occlusion query) or the 2D-only <code>SDL_RENDERER</code>. Under the default <code>Reach</code> profile an <code>OcclusionQuery</code> throws unless <code>HiDef</code> is requested.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">⚡</div>
<span class="status-badge status-partial">Implemented (renderer-dependent)</span>
<h3>Context-Loss Recovery</h3>
<p><code>GraphicsDevice</code> exposes <code>DeviceLost</code>, <code>DeviceResetting</code> and <code>DeviceReset</code> events following the XNA pattern. <strong>EasyGL</strong> implements real GL context-loss recovery (relevant on Android and some desktop compositors), and <strong>DIRECTX9</strong> implements full device-lost and <code>D3DPOOL_DEFAULT</code> recovery. Reading the sources, <code>DIRECTX11</code> and <code>WEBGPU</code> also raise the reset events from their recovery paths, while <code>VULKAN</code> reports a lost device (<code>DeviceLost</code>, status <code>Lost</code>) but deliberately does not attempt a reset. Recovery was not exercised on real hardware for this page; <code>DeviceLostException</code>, <code>DeviceNotResetException</code> and <code>NoSuitableGraphicsDeviceException</code> now derive from <code>System::Exception</code> rather than <code>std::runtime_error</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">📊</div>
<span class="status-badge status-done">Implemented (CNAEXT, always compiled)</span>
<h3>Renderer capability profiles</h3>
<p><code>GraphicsCapability</code> grew from 14 to <strong>19</strong> members (adding <code>FloatRenderTargets</code>, <code>HalfFloatRenderTargets</code>, <code>HalfFloatTextureLinearFiltering</code>, <code>ComputeShaders</code> and <code>IndirectDraw</code>). Beyond that, <code>GraphicsDevice::GetRendererCapabilityProfileEXT()</code> returns a <code>RendererCapabilityProfile</code>: <strong>32 <code>RendererFeature</code> ids</strong> with a four-state answer (Unknown, Unsupported, Supported, Restricted), <strong>22 <code>RendererLimit</code> values</strong> (texture size, vertex streams, compute work-group limits, buffer sizes, attachments, alignments, timestamp period), per-format usage for all 27 <code>SurfaceFormat</code> members, and a readable English report from <code>GetRendererCapabilityReportEXT()</code>. It is built lazily, cached, and exposed through five C ABI functions. Branch on capabilities, never on renderer names. See <a href="docs/tutorials/133-renderer-capability-profile.html">Tutorial 133</a> and <a href="docs/tutorials/101-renderer-capabilities.html">Tutorial 101</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">⚙</div>
<span class="status-badge status-partial">Renderer-dependent</span>
<h3>Modern graphics features</h3>
<p>Modern renderers report modern capabilities: base-instance drawing, float and half-float render targets, and shadow-map and image-based-lighting sampling on <code>VULKAN</code>, <code>SDL_GPU</code>, <code>WEBGPU</code> and the EasyGL family (some device-conditional). Compute and indirect-draw support is reported by <code>VULKAN</code>, <code>SDL_GPU</code>, <code>WEBGPU</code>, <code>DIRECTX11</code> and the EasyGL family on ES 3.1 / GL 4.3 or newer contexts (never on WebGL). These are capability answers from the renderers’ internal implementations; there is no public compute-shader or storage-buffer class for game code.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🔒</div>
<span class="status-badge status-done">Enforced on every renderer</span>
<h3>GraphicsProfile: Reach by default</h3>
<p>The default <code>GraphicsProfile</code> is <strong>Reach</strong>, and this snapshot enforces its ceilings on every renderer (alpha.1 enforced them on <code>DIRECTX9</code> only). Under Reach, multiple render targets, <code>OcclusionQuery</code>, 32-bit indices, float and HDR targets, packed formats and large cubes throw or degrade unless you request <code>HiDef</code> through <code>GraphicsDeviceManager</code> (or <code>CNA::SetProjectGraphicsProfileEXT</code>). Many alpha.1-era tutorials omit this, so a snippet that renders MRT or 32-bit-indexed terrain may throw as written.</p>
</div>
</div>
<!-- Content pipeline -->
<span class="section-label">Content</span>
<h2 id="content-pipeline">Content Pipeline & Formats</h2>
<p class="section-desc">CNA still loads content at run time through <code>ContentManager</code>; what is new in this snapshot is a build-time pipeline that produces it. The pipeline lives outside the runtime link closure — only the <code>cna-content</code> compiler links it — so FreeType and FFmpeg never enter a shipped game. Alpha.1 could only read <code>.xnb</code>; this snapshot also writes <code>.xnb</code> and a new native format, <code>.cnb</code>.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-blue">🔧</div>
<span class="status-badge status-done">Implemented (build-time tool)</span>
<h3>The <code>cna-content</code> build tool</h3>
<p><code>cna-content build <source | directory | .contentproj> -o <out> [--format cnb|xnb]</code> runs Importer → Processor → Writer over a file or a whole tree, preserving relative logical names. Options include <code>--workers 1..64</code>, <code>--config</code> for a strict <code>.cna-content.json</code>, <code>--explain</code> and <code>--xna-compatible</code> (three refusals become XNA-style warnings). Builds are incremental through a manifest and a lock file, and CMake gets <code>cna_add_content(TARGET ... SOURCE_DIR ... OUTPUT_DIR ... FORMAT ...)</code>. The tool is built by default; only its optional inputs are switchable: FreeType (<code>CNA_ENABLE_FONT_PIPELINE</code>), FFmpeg (<code>CNA_ENABLE_MEDIA_PIPELINE</code>), zstd (<code>CNA_CNB_ZSTD</code>) and an external <code>fxc</code>. See <a href="docs/content-pipeline.html">Content Pipeline</a> and <a href="docs/tools.html">Command-line tools</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">📦</div>
<span class="status-badge status-done">Implemented (CNA format)</span>
<h3>CNB — CNA's compiled container</h3>
<p>A deterministic, little-endian, one-asset-per-file container that shares no code with XNB and has no reader tables or platform byte: a 64-byte header, 48-byte table-of-contents entries and a CRC-32C on the header, the table and every chunk (hardware CRC where available). Schemas exist for <code>Texture2D/3D/Cube</code>, <code>SpriteFont</code>, <code>Model</code>, <code>AnimationClip</code>, <code>Curve</code>, <code>SoundEffect</code>, <code>Song</code> and <code>Video</code>; game-defined types register through <code>RegisterCnbLoaderEXT<T></code>. Zstandard chunk compression exists in the library but no shipped tool enables it, and memory mapping was measured and rejected. <code>cna_tool_cnb_info</code> validates and prints a file. See <a href="docs/cnb-format.html">CNB format</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">📂</div>
<span class="status-badge status-done">Implemented</span>
<h3>XNB writing</h3>
<p><code>cna-content --format xnb</code> writes XNB (version 4 or 5, Reach or HiDef profile, no compression, LZX or LZ4, XNA 4.0 or portable reader names, several target platforms) with a real LZX encoder. Writers exist for <code>Texture2D/3D/Cube</code>, <code>SpriteFont</code>, <code>SoundEffect</code>, <code>Song</code>, <code>Video</code>, vertex and index buffers, the stock effects, compiled <code>Effect</code>, <code>EffectMaterial</code>, <code>Model</code> and common collections. CNA reports golden-file byte identity with XNA 4.0 for simple types and that its LZX output loads in a genuine XNA runtime under Wine; treat that as developer evidence, not a CI result. A glTF → XNB <code>Model</code> drops skeleton, animation clips, morph targets and lights with warnings and downgrades PBR to stock effects.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🧩</div>
<span class="status-badge status-done">Implemented (build-time API)</span>
<h3>XNA Content Pipeline API</h3>
<p><code>Microsoft::Xna::Framework::Content::Pipeline</code> is represented in 107 headers: 10 importers (Texture, Wav, Mp3, Wma, Wmv, Effect, FontDescription, X, Fbx, Xml), 12 processors, <code>IntermediateSerializer</code>, <code>ContentCompiler</code>/<code>ContentWriter</code>, and the <code>BuildContent</code> and <code>ContentProject</code> tasks (<code>.contentproj</code> is read without MSBuild). It is a view over CNA's canonical pipeline engine, not a second engine: 128 of 128 types and 705 of 705 members are represented. The custom-component API is explicitly experimental, the <code>.wma</code>/<code>.wmv</code> importers could not be measured against the genuine runtime, and there is no Content Pipeline C ABI.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">✨</div>
<span class="status-badge status-partial">Needs an external compiler</span>
<h3>Effects at build time</h3>
<p>A compiled <code>.fxb</code> needs no compiler and becomes an XNB <code>Effect</code>. HLSL <code>.fx</code> source is compiled by an <strong>external, legacy <code>fxc</code></strong> at profile <code>fx_2_0</code> (chosen with <code>--fx-compiler</code>, the <code>CNA_FXC</code> environment variable, a CMake-baked path or <code>fxc</code> on <code>PATH</code>, optionally under <code>wine</code>) and only with <code>--format xnb</code>: CNB has no Effect schema. CNA embeds no HLSL compiler, MGFX and DXBC remain unsupported, and the <code>.fx</code> route has not been checked against a genuine Microsoft <code>fxc</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🛠</div>
<span class="status-badge status-done">Built by default</span>
<h3>Converters & inspection tools</h3>
<p>Alongside <code>cna-content</code> the tree builds <code>cna_tool_gltf_to_cnj</code> (offline glTF 2.0 → <code>.cnj</code>), <code>cna_tool_gltf_to_cnb</code>, <code>cna_tool_cnj_to_cnb</code>, <code>cna_tool_source_to_cnb</code> (image, sound, song, video and cube-map sources), <code>cna_tool_cnb_info</code> and an XNB interop-fixture tool. Alpha.1 shipped only <code>gltf_to_cnj</code>. See <a href="docs/tools.html">Command-line tools</a>.</p>
</div>
</div>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">What each built-in <code>cna-content</code> route turns a source file into</caption>
<thead>
<tr><th scope="col">Source</th><th scope="col">Output as <code>.cnb</code></th><th scope="col">Output as <code>.xnb</code></th></tr>
</thead>
<tbody>
<tr><td><code>.png .jpg .bmp .tga .gif .psd .hdr</code> and similar</td><td>Texture2D (Rgba8 only; a DXT request keeps Rgba8 and warns)</td><td>Texture2D</td></tr>
<tr><td><code>.wav</code> (and <code>.mp3</code>/<code>.wma</code> decoded, with the media pipeline)</td><td>SoundEffect</td><td>SoundEffect</td></tr>
<tr><td><code>.mp3 .ogg .flac .opus .aac .wma</code> as a Song</td><td>Song: metadata plus a streaming reference; the media file is deployed beside it</td><td>Song</td></tr>
<tr><td><code>.mp4 .ogv .webm .mkv .avi .mov</code></td><td>Video: metadata plus a reference</td><td>Video</td></tr>
<tr><td><code>.gltf .glb</code></td><td>Model (one primary; <code>generateChildAssets</code> for multi-group files)</td><td>Model, with skeleton, animation, morphs and lights dropped and warned</td></tr>
<tr><td><code>.cnj</code></td><td>Texture, SpriteFont, SoundEffect, Curve, AnimationClip, Model</td><td>The same, where the XNB writer supports the type</td></tr>
<tr><td><code>.spritefont</code> (FreeType)</td><td>SpriteFont</td><td>SpriteFont</td></tr>
<tr><td><code>.fxb</code> / <code>.fx</code></td><td>Not supported (no Effect schema)</td><td>Effect (<code>.fx</code> only with an external <code>fxc</code>)</td></tr>
<tr><td><code>.x .fbx</code></td><td>Model through the XNA <code>ModelProcessor</code></td><td>Model</td></tr>
<tr><td><code>.xml</code> (XNA intermediate)</td><td>Refused</td><td>Any type registered with the XNA <code>ContentCompiler</code></td></tr>
<tr><td><code>.xnb</code></td><td>Transcoded to native CNB</td><td>Source only, not rewritten</td></tr>
</tbody>
</table>
</div>
<!-- Platform implementations -->
<span class="section-label">Platform</span>
<h2 id="platform-audio">Platform and audio implementations</h2>
<p class="section-desc">SDL3 is the windowing platform, while this snapshot independently selects host integration and an audio device, and can be configured without SDL for windowless builds. The three audio values are not feature-equivalent: high-level XNA playback exists for SDL3 (SDL3_mixer) and ALSA (CNA's own mixer) only.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-blue">🖥</div>
<span class="status-badge status-done">Implemented</span>
<h3>Windowing & Events</h3>
<p>The default SDL3 platform manages windows and events on every operating system. The <code>IPlatform</code> layer has <strong>three</strong> implementations selected with <code>CNA_PLATFORM</code>: <code>SDL3</code> (default, the only one with windows), <code>HEADLESS</code> and POSIX <code>TERMINAL</code>; any other name is refused at configure time. A 32-flag <code>PlatformCapabilities</code> contract states exactly what each implementation can do, and a missing capability refuses deterministically instead of half-working. See <a href="docs/platforms.html">Platform Support</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🎵</div>
<span class="status-badge status-partial">Selection boundary</span>
<h3>Selectable audio integration</h3>
<p><code>CNA_AUDIO_PLATFORM</code> independently selects <code>SDL3</code>, <code>NULL</code> or <code>ALSA</code> (<code>OPENAL</code> and <code>WASAPI</code> are reserved and refused). SDL3 and ALSA define <code>SOUND_ENABLED</code> and provide a mixer (SDL3_mixer or CNA's own) behind <code>SoundEffect</code>, <code>MediaPlayer</code>, XACT and decoding. Null compiles the low-level device contract without providing XNA playback, and only Linux has an SDL-free audio path with playback (ALSA), so SDL-free builds elsewhere use Null audio.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">📷</div>
<span class="status-badge status-done">Implemented</span>
<h3>SDL3_image Loading</h3>
<p>SDL3_image is used for loading PNG, JPG, and other texture formats into <code>Texture2D</code>. Vendored alongside SDL3.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🕵</div>
<span class="status-badge status-done">Implemented</span>
<h3>Windows, X11 and Wayland through SDL3</h3>
<p>SDL3 is CNA’s one windowing implementation. Windows, X11 and Wayland are reached through SDL’s <code>windows</code>, <code>x11</code> and <code>wayland</code> video drivers (<code>SDL_VIDEODRIVER</code> picks one), and the native handles renderers need — an <code>HWND</code>, an X11 <code>Display*</code> and window, a Wayland <code>wl_display*</code> and <code>wl_surface*</code> — reach them through <code>NativeWindowHandle</code>. CI runs the SDL3 window suite on SDL’s <code>x11</code> driver under Xvfb and its <code>wayland</code> driver under a headless Weston, asserting the handle each hands a renderer; a native-MSVC Windows job runs on manual dispatch. See <a href="docs/native-platforms.html">Windows, X11 and Wayland</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🔌</div>
<span class="status-badge status-done">Implemented</span>
<h3>SDL is optional (<code>CNA_ENABLE_SDL</code>)</h3>
<p><code>CNA_ENABLE_SDL=AUTO|ON|OFF</code> decides whether the vendored SDL3 sub-build runs at all. With <code>OFF</code>, any selection that needs SDL is refused with a named reason: the SDL3 platform, SDL3 audio, and the <code>SDL_RENDERER</code>, <code>SDL_GPU</code> and <code>FNA3D</code> renderers. Because SDL3 is the only windowing implementation, an SDL-free build is windowless — <code>HEADLESS</code> or <code>TERMINAL</code> with a CPU or no-pixel renderer — for servers, test runners and terminal games; CI builds one with ALSA audio and checks that nothing links SDL.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🎤</div>
<span class="status-badge status-done">Implemented — Linux</span>
<h3>ALSA audio & CNA's own mixer</h3>
<p><code>CNA_AUDIO_PLATFORM=ALSA</code> loads <code>libasound.so.2</code> at run time (never linked); the device comes from <code>CNA_AUDIO_DEVICE</code> (<code>null</code> is silent) and capture from <code>CNA_AUDIO_RECORDING_DEVICE</code>. CNA's own mixer provides a linear-interpolation resampler, per-track and post-mix callbacks, loops and streams, and decodes WAV (PCM, float, MS-ADPCM, IMA-ADPCM), Ogg Vorbis, MP3 and FLAC; it does not decode Opus, WMA/xWMA or XMA. CI runs the mixer, ALSA device, capture and XACT-category suites on ALSA's <code>null</code> device. PipeWire and PulseAudio desktops are reached through ALSA's default device plug-ins.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🖥</div>
<span class="status-badge status-done">Implemented</span>
<h3>Terminal & Headless platforms</h3>
<p>The POSIX <code>TERMINAL</code> platform (termios/poll, Kitty keyboard-protocol probe, one window) accepts only the CPU renderers <code>SOFTWARE</code>, <code>HEADLESS</code> and <code>STUB</code>, and only <code>SOFTWARE</code> actually displays: it hands each finished frame to the terminal's surface presenter. <code>HEADLESS</code> is always compiled: one window object, no services, every capability false. CI covers both, including a pseudo-TTY test of the 2D demo.</p>
</div>
</div>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">Platform implementations selected with CNA_PLATFORM</caption>
<thead>
<tr><th scope="col">Platform</th><th scope="col">Uses SDL?</th><th scope="col">GL / Vulkan services</th><th scope="col">Notable host services</th><th scope="col">Automatic CI evidence</th></tr>
</thead>
<tbody>
<tr><td><code>SDL3</code> (default)</td><td>SDL3</td><td>GL context; Vulkan surface where SDL reports support</td><td>Clipboard, drag-and-drop, gamepad, sensors, dialogs, tray, camera (conditional); the only windowing implementation, on every operating system (Windows, X11 and Wayland through SDL’s video drivers)</td><td>Many workflows: Linux (Xvfb and headless Weston), macOS, iOS, Emscripten; Windows on manual dispatch</td></tr>
<tr><td><code>HEADLESS</code></td><td>No</td><td>None</td><td>One window object, all capabilities false; always compiled</td><td>Yes</td></tr>
<tr><td><code>TERMINAL</code></td><td>No</td><td>None (CPU frames only)</td><td>POSIX only; surface presenter, Kitty keyboard probe</td><td>Unit tests plus a pseudo-TTY demo test</td></tr>
</tbody>
</table>
</div>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">Audio implementations selected with CNA_AUDIO_PLATFORM</caption>
<thead>
<tr><th scope="col">Audio value</th><th scope="col">OS</th><th scope="col"><code>SOUND_ENABLED</code> / mixer</th><th scope="col">Capture</th><th scope="col">XNA playback</th></tr>
</thead>
<tbody>
<tr><td><code>SDL3</code> (default)</td><td>Every target CNA supports</td><td>Yes / SDL3_mixer</td><td>Yes</td><td>SoundEffect, instances, DynamicSoundEffectInstance, MediaPlayer, XACT, 3D audio</td></tr>
<tr><td><code>NULL</code></td><td>All</td><td>No / none</td><td>No</td><td>Deterministic silent transport; classes compile without playback</td></tr>
<tr><td><code>ALSA</code></td><td>Linux only</td><td>Yes / CNA's own mixer</td><td>Yes</td><td>The same XNA surface, decoding WAV, Vorbis, MP3 and FLAC</td></tr>
</tbody>
</table>
</div>
<!-- Renderers -->
<span class="section-label">Rendering</span>
<h2 id="renderers">Pluggable Renderers</h2>
<p class="section-desc">CNA separates game-facing APIs from 14 public renderer identities implemented by 12 families (the three GL profiles share one EasyGL implementation). <code>CNA_GRAPHICS_RENDERER</code> selects the compact single-renderer default; <code>CNA_GRAPHICS_RENDERERS</code> can link a compatible set and <code>GraphicsRendererSelection</code> resolves one before the first device. A name outside the 14 is a configure-time error, never a silent fallback. Game code continues to use the same XNA-shaped interfaces. See the <a href="docs/rendering-backends.html">renderer reference</a>.</p>
<div class="callout callout--warn">
<span class="callout-icon">⚠</span>
<p><strong>14 renderer identities is not 14 equally complete renderers.</strong> They range from paths with real-XNA pixel evidence through deliberately 2D-only families, to renderers that never present to a window at all (<code>HEADLESS</code>, <code>STUB</code>) and experimental implementations. The Maturity column below is CNA's own declaration in <code>GraphicsBackendMaturity</code> (Production, Supported or Experimental), not a measurement, and capability reporting still varies, so a <code>true</code> is not universal proof. Single-renderer builds remain the smallest verification slices; a compatible multi-renderer build can exercise several linked families at runtime, but dependencies, platform gates and test registration still vary.</p>
</div>
<div class="table-wrap mb-4">
<table>
<thead>
<tr><th>Renderer</th><th>Maturity</th><th>Scope</th><th>Notes</th></tr>
</thead>
<tbody>
<tr><td><code>OPENGLES3</code></td><td><strong>Production</strong> (declared)</td><td>2D + 3D</td><td>Linux-default EasyGL profile: MRT, occlusion, Texture3D and instancing; MSAA and anisotropy by runtime probe.</td></tr>
<tr><td><code>OPENGL33</code></td><td>Production (declared)</td><td>2D + 3D</td><td>Desktop OpenGL 3.3 core through EasyGL, with native wireframe; on macOS the core-profile context, where the Apple campaign ran EasyGL’s tests.</td></tr>
<tr><td><code>WEBGL2</code></td><td>Supported (declared)</td><td>2D + 3D</td><td>Emscripten-only default of the web; in the <code>WEBGL2</code> + <code>WEBGPU</code> bundle that CI builds and link-checks.</td></tr>
<tr><td><code>VULKAN</code></td><td>Production (declared)</td><td>2D + 3D</td><td>Most complete modern surface: SPIR-V pipeline, MSAA resolve, stencil, compute, indirect draw, GPU timers, float targets; compiled effects are opt-in.</td></tr>
<tr><td><code>DIRECTX9</code></td><td>Production (declared)</td><td>2D + 3D</td><td>Windows-only; target of the real-XNA oracle corpus (recorded 0-diff at tolerance 0 under Wine + DXVK; not in CI). Still the one renderer without a <code>SupportsCapability</code> override.</td></tr>
<tr><td><code>DIRECTX11</code></td><td>Production (declared)</td><td>2D + 3D</td><td>Windows-only; state-object caches, MRT, float targets and runtime shader compilation; renderer-internal compute and indirect draw; Windows lanes are manual (a recorded native-MSVC run passed its 300 CTest entries).</td></tr>
<tr><td><code>SDL_GPU</code></td><td>Supported (declared)</td><td>2D + 3D</td><td>SPIR-V on SDL3's GPU API with compute, indirect draw and float, wide and packed texture formats; SDL’s Direct3D 12 and Metal drivers through SDL_shadercross where enabled.</td></tr>
<tr><td><code>METAL</code></td><td>Supported (declared)</td><td>2D + 3D</td><td>macOS and iOS; MSAA, MRT, occlusion queries, instancing and multi-stream input, float, packed and DXT formats, <code>SpriteBatch</code> MSL custom effects and opt-in compiled XNA effects; no compute. Qualified on a physical Mac mini M4 in CNA’s Apple campaign (see <a href="docs/platforms.html#macos">macOS</a>); CI runs it on GitHub’s virtual Macs.</td></tr>
<tr><td><code>FNA3D</code></td><td>Experimental (declared)</td><td>2D + 3D</td><td>Adapter over FNA3D; compiled effects always on, no <code>ShaderEffect</code> source; refuses PBR draws; its CTest gates only that scenes render.</td></tr>
<tr><td><code>WEBGPU</code></td><td>Experimental (declared)</td><td>2D + 3D</td><td>Native <code>wgpu-native</code> and a browser route; MRT, occlusion, instancing, compute and half-float linear filtering reported; CI builds it only inside the Emscripten bundle; the Apple campaign ran its GPU tests on macOS.</td></tr>
<tr><td><code>SOFTWARE</code></td><td>Experimental (declared)</td><td>2D + 3D</td><td>CPU rasterizer, no GPU needed; MSAA, up to 4 MRTs, occlusion, instancing; ignores custom shader source; off-screen except on the Terminal platform.</td></tr>
<tr><td><code>HEADLESS</code></td><td>Supported (diagnostic)</td><td>none</td><td>Test harness: validates arguments and traces calls, deliberately renders nothing; useful for game-logic CI.</td></tr>
<tr><td><code>STUB</code></td><td>Supported (diagnostic)</td><td>none</td><td>Smallest complete renderer: renders nothing, all 19 capabilities false; default of the <code>dev</code>/<code>unit</code> presets.</td></tr>
<tr><td><code>SDL_RENDERER</code></td><td>Production (declared), within 2D scope</td><td>2D only</td><td>Portable SDL path with deliberate 3D rejection; the default on Windows, macOS, iOS and Android, and one of the two renderers the iOS build admits.</td></tr>
</tbody>
</table>
</div>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">Capability matrix for the 14 identities (Y = reports true, – = false, c = conditional on device, driver, context or build). Columns are the 19 <code>GraphicsCapability</code> members; hover a header for its name.</caption>
<thead>
<tr><th scope="col">Renderer</th><th scope="col"><abbr title="ThreeD">3D</abbr></th><th scope="col"><abbr title="DepthStencilBuffer">DS</abbr></th><th scope="col"><abbr title="MultiSampleAntiAliasing">AA</abbr></th><th scope="col"><abbr title="MultipleRenderTargets">RT</abbr></th><th scope="col"><abbr title="AnisotropicFiltering">An</abbr></th><th scope="col"><abbr title="WireFrame">Wf</abbr></th><th scope="col"><abbr title="OcclusionQuery">Oq</abbr></th><th scope="col"><abbr title="CustomEffects">Cx</abbr></th><th scope="col"><abbr title="Texture3D">T3</abbr></th><th scope="col"><abbr title="MultiStreamVertexInput">MS</abbr></th><th scope="col"><abbr title="Instancing">In</abbr></th><th scope="col"><abbr title="StencilBuffer">St</abbr></th><th scope="col"><abbr title="AdditiveBlending">Ad</abbr></th><th scope="col"><abbr title="CompiledEffects">CE</abbr></th><th scope="col"><abbr title="FloatRenderTargets">F32</abbr></th><th scope="col"><abbr title="HalfFloatRenderTargets">F16</abbr></th><th scope="col"><abbr title="HalfFloatTextureLinearFiltering">HF</abbr></th><th scope="col"><abbr title="ComputeShaders">Cs</abbr></th><th scope="col"><abbr title="IndirectDraw">Id</abbr></th></tr>
</thead>
<tbody>
<tr><td><code>SDL_RENDERER</code></td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>Y</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td></tr>
<tr><td><code>OPENGLES3</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>c</td><td>c</td></tr>
<tr><td><code>OPENGL33</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>c</td><td>c</td></tr>
<tr><td><code>WEBGL2</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>–</td><td>–</td></tr>
<tr><td><code>VULKAN</code></td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>c</td><td>c</td><td>c</td></tr>
<tr><td><code>WEBGPU</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>c</td></tr>
<tr><td><code>HEADLESS</code></td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>–</td><td>Y</td><td>Y</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td></tr>
<tr><td><code>SOFTWARE</code></td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>–</td></tr>
<tr><td><code>STUB</code></td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td></tr>
<tr><td><code>DIRECTX11</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>Y</td></tr>
<tr><td><code>DIRECTX9</code></td><td>Y</td><td>Y</td><td>Y</td><td>Y*</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td></tr>
<tr><td><code>SDL_GPU</code></td><td>Y</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>c</td><td>c</td><td>c</td><td>c</td><td>Y</td><td>Y</td></tr>
<tr><td><code>METAL</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>–</td><td>–</td></tr>
<tr><td><code>FNA3D</code></td><td>Y</td><td>Y</td><td>c</td><td>Y</td><td>Y</td><td>Y</td><td>c</td><td>–</td><td>Y</td><td>Y</td><td>c</td><td>c</td><td>Y</td><td>Y</td><td>–</td><td>–</td><td>–</td><td>–</td><td>–</td></tr>
</tbody>
</table>
</div>
<p style="margin-bottom:1.5rem;"><strong>Reading the matrix:</strong> the cells are code-derived from each renderer's <code>SupportsCapability</code> arms at this snapshot, not measured results. The public answer is <code>GraphicsDevice::SupportsCapability()</code>, which derives CE, F32, F16, HF, Cs and Id from separate hooks that default to false. <code>DIRECTX9</code> inherits the permissive base default; <code>Y*</code> means its MRT count is additionally limited by profile (<code>Reach</code> 1, <code>HiDef</code> 4). For <code>SDL_GPU</code> the renderer-level switch answers a few cells more conservatively than the device level does. Conditions behind <em>c</em>: GL MSAA needs <code>GL_MAX_SAMPLES</code> above 1; anisotropy needs the anisotropic-filter extension; compute needs ES 3.1 or GL 4.3 (never WebGL); compiled effects need the build option below; float and half-float targets come from a runtime probe or DXGI format queries.</p>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">Compiled XNA effects (<code>CompiledEffects</code>): which families can report true, and behind which CMake option. Every option defaults to OFF except <code>FNA3D</code>, which has none.</caption>
<thead>
<tr><th scope="col">Family (identities)</th><th scope="col">Compiled effects</th><th scope="col">Gate</th></tr>
</thead>
<tbody>
<tr><td>FNA3D (<code>FNA3D</code>)</td><td>Always on</td><td>None: FNA3D pulls MojoShader unconditionally</td></tr>
<tr><td>EasyGL (<code>OPENGLES3</code>, <code>OPENGL33</code>, <code>WEBGL2</code>)</td><td>With the option</td><td><code>CNA_EASYGL_COMPILED_EFFECTS</code> (one option for all three)</td></tr>
<tr><td>Vulkan (<code>VULKAN</code>)</td><td>With the option</td><td><code>CNA_VULKAN_COMPILED_EFFECTS</code></td></tr>
<tr><td>WebGPU (<code>WEBGPU</code>)</td><td>With the option</td><td><code>CNA_WEBGPU_COMPILED_EFFECTS</code>; the browser build translates SPIR-V to WGSL</td></tr>
<tr><td>SDL_GPU (<code>SDL_GPU</code>)</td><td>With the option</td><td><code>CNA_SDL_GPU_COMPILED_EFFECTS</code></td></tr>
<tr><td>Software (<code>SOFTWARE</code>)</td><td>With the option</td><td><code>CNA_SOFTWARE_COMPILED_EFFECTS</code></td></tr>
<tr><td>Metal (<code>METAL</code>)</td><td>With the option</td><td><code>CNA_METAL_COMPILED_EFFECTS</code>; MojoShader SPIR-V translated to MSL by SPIRV-Cross</td></tr>
<tr><td>Direct3D 9, 11 (<code>DIRECTX9</code>, <code>DIRECTX11</code>)</td><td>With the option</td><td><code>CNA_DIRECTX9_COMPILED_EFFECTS</code>, <code>CNA_DIRECTX11_COMPILED_EFFECTS</code></td></tr>
<tr><td><code>HEADLESS</code>, <code>STUB</code>, <code>SDL_RENDERER</code></td><td>Never</td><td>No implementation</td></tr>
</tbody>
</table>
</div>
<div class="table-wrap mb-4">
<table>
<caption style="caption-side:top;text-align:left;padding:0 0.25rem 0.6rem;color:var(--text-muted);font-size:0.85rem;">Platform gates, SDL requirement and dependencies by implementation family</caption>
<thead>
<tr><th scope="col">Family (identities)</th><th scope="col">Platform gate</th><th scope="col">Needs SDL3?</th><th scope="col">Dependency</th></tr>
</thead>
<tbody>
<tr><td>EasyGL: <code>OPENGLES3</code>, <code>OPENGL33</code></td><td>Native hosts (not Emscripten); CMake warns <code>OPENGLES3</code> is primarily tested on Linux elsewhere</td><td>No; needs a GL context from the SDL3 platform</td><td>Siblings <code>../easy-gl</code> and <code>../meta-gl</code></td></tr>
<tr><td>EasyGL: <code>WEBGL2</code></td><td>Emscripten only</td><td>No</td><td>Same siblings; the link contract pins WebGL 2</td></tr>
<tr><td><code>VULKAN</code></td><td>Any host with a Vulkan loader and a Vulkan surface from the SDL3 platform</td><td>No</td><td>Vulkan SDK/loader</td></tr>
<tr><td><code>WEBGPU</code></td><td>Native (Linux, macOS, Windows) and browser</td><td>No</td><td>Pinned <code>wgpu-native</code> v29.0.1.1 (SHA-256 verified) or the Emscripten <code>emdawnwebgpu</code> port</td></tr>
<tr><td><code>SDL_GPU</code></td><td>Any host SDL3's GPU API supports</td><td><strong>Yes</strong></td><td>SDL3; SDL_shadercross + SPIRV-Cross (default ON on Windows and Apple); optional libshaderc</td></tr>
<tr><td><code>FNA3D</code></td><td>Any host FNA3D and SDL3 support</td><td><strong>Yes</strong></td><td>Fetched FNA3D and MojoShader</td></tr>
<tr><td><code>DIRECTX9</code>, <code>DIRECTX11</code></td><td>Windows only (native or mingw-w64 cross-build)</td><td>No; takes the <code>HWND</code> of the SDL3 window</td><td>Windows SDK libraries (<code>d3d9</code>, <code>d3d11</code>, <code>dxgi</code>, <code>d3dcompiler</code>)</td></tr>
<tr><td><code>METAL</code></td><td>macOS and iOS (tvOS refuses it)</td><td>SDL3 is the Apple platform</td><td>Objective-C++; AppKit or UIKit, Metal, QuartzCore, Foundation</td></tr>
<tr><td><code>SDL_RENDERER</code></td><td>Any SDL3 platform</td><td><strong>Yes</strong></td><td>Vendored SDL3</td></tr>
<tr><td><code>SOFTWARE</code></td><td>Any host; off-screen except on the Terminal platform</td><td>No</td><td>None (MojoShader only with its compiled-effects option)</td></tr>
<tr><td><code>HEADLESS</code>, <code>STUB</code></td><td>Any host</td><td>No</td><td>None</td></tr>
</tbody>
</table>
</div>
<div class="callout callout--info">
<span class="callout-icon">ℹ</span>
<p><strong>Choosing and switching renderers.</strong> Build time: exactly one <code>-DCNA_GRAPHICS_RENDERER=<NAME></code> (or one <code>CNA_RENDERER_<NAME>=ON</code>); omit it for the per-host default (Emscripten <code>WEBGL2</code>, Linux <code>OPENGLES3</code>, everything else <code>SDL_RENDERER</code>). Names are exact-case in CMake. One combination rule is enforced: Windows-only, Emscripten-only and Apple-only identities cannot mix. Run time: an explicit <code>GraphicsRendererSelection::SetPreferred()</code> beats the <code>CNA_GRAPHICS_RENDERER</code> environment variable (or the Emscripten <code>Module.cnaPreferredRenderer</code> property), which beats the build default. A renderer that is not compiled in throws, fallback is off unless you enable a chain or automatic fallback, and the choice latches when the first <code>GraphicsDevice</code> is created successfully. <code>GraphicsAdapter::UseNullDevice</code> and <code>UseReferenceDevice</code> map to <code>HEADLESS</code> and <code>SOFTWARE</code>. See <a href="docs/runtime-renderer-selection.html">Runtime renderer selection</a>.</p>
</div>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-green">💥</div>
<span class="status-badge status-done">Production (2D scope)</span>
<h3>SDL_Renderer Renderer</h3>
<p>The most portable 2D renderer, built on SDL3's own hardware-accelerated renderer. It is the default on Windows, macOS, iOS, Android and other non-Linux hosts and one of the two renderers the iOS build admits. 3D calls throw by design rather than quietly drawing nothing, and its capability reporting is written to match what it can actually do (additive blending is the one capability it reports). Requires the SDL3 platform. Selected with <code>-DCNA_GRAPHICS_RENDERER=SDL_RENDERER</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🔸</div>
<span class="status-badge status-done">Production — most mature</span>
<h3>EasyGL (OpenGL) Renderer</h3>
<p>The shared family behind three public profiles: <code>OPENGLES3</code> (the Linux default), <code>OPENGL33</code> and <code>WEBGL2</code> (the Emscripten default). It provides shader-driven 2D/3D rendering with MRT, occlusion queries, Texture3D, multi-stream input and instancing on every profile, and MSAA, anisotropy and (outside WebGL) compute where the context provides them; on macOS it runs on Apple’s core-profile OpenGL. Needs the sibling <code>easy-gl</code> and <code>meta-gl</code> repositories, and compiled effects are opt-in with one option for all three. Selected with <code>-DCNA_GRAPHICS_RENDERER=OPENGLES3</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">🔸</div>
<span class="status-badge status-done">Production — modern surface</span>
<h3>Vulkan Renderer</h3>
<p>A native Vulkan family with SPIR-V <code>ShaderEffect</code>, render-target and readback paths, and the most complete modern surface of any renderer: compute, indirect draw, base-instance drawing, GPU timers, float and half-float render targets, shadow sampling and image-based lighting (some device-conditional). XNA/FNA compiled Effect Framework bytecode is separately opt-in with <code>CNA_VULKAN_COMPILED_EFFECTS</code>. Selected with <code>-DCNA_GRAPHICS_RENDERER=VULKAN</code>.</p>
<p style="margin-top:0.5rem;"><strong>Known gaps:</strong> it reports a lost device but deliberately does not attempt a reset, and compiled effects refuse vertex-stage texture sampling; see the <a href="roadmap.html">Roadmap</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🖥</div>
<span class="status-badge status-done">Production — Windows-only</span>
<h3>Direct3D 11 Renderer</h3>
<p>Windows-only, hard-gated at CMake configure time, with state-object caches, MRT, instancing, float and half-float render targets and runtime HLSL compilation for <code>ShaderEffect</code>. Compiled effects are opt-in with <code>CNA_DIRECTX11_COMPILED_EFFECTS</code>. Native MSVC coverage is manual-dispatch. Selected with <code>-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64.cmake -DCNA_GRAPHICS_RENDERER=DIRECTX11</code>.</p>
<p style="margin-top:0.5rem;"><strong>Verify capability boundaries:</strong> the renderer now overrides <code>SupportsCapability()</code> (compute and indirect draw report false), but do not infer correct draw offsets or device support from the family's presence alone.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🌐</div>
<span class="status-badge status-partial">Experimental</span>
<h3>WebGPU Renderer</h3>
<p>An experimental renderer using native <code>wgpu-native</code> (pinned v29.0.1.1) and, new since alpha.1, a browser route through the Emscripten <code>emdawnwebgpu</code> port. It has a working 2D baseline and a real 3D path: MRT (two to four targets), occlusion queries, wireframe by edge expansion, multi-stream input, instancing, probed MSAA and float render targets, compute, and shadow and IBL sampling. Compiled effects are opt-in and translate SPIR-V to WGSL in the browser build. Selected with <code>-DCNA_GRAPHICS_RENDERER=WEBGPU</code>.</p>
<p style="margin-top:0.5rem;"><strong>Known gaps:</strong> CNA still declares it Experimental; half-float linear filtering is false, source <code>ShaderEffect</code> runs as WGSL only, and no CI workflow names it. The alpha.1 statements that it had no render targets, MSAA, instancing or working stencil no longer hold.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🧪</div>
<span class="status-badge status-done">Test harness, not a renderer</span>
<h3>Headless Renderer</h3>
<p>Renders nothing by design: no window, GPU or graphics API calls. It provides argument validation, resource-lifecycle tracking and draw counters for game-logic CI, in three modes (<code>Fast</code>, <code>Validation</code> by default, <code>Trace</code>). It is also what <code>GraphicsAdapter::UseNullDevice</code> selects. Selected with <code>-DCNA_GRAPHICS_RENDERER=HEADLESS</code>.</p>
<p style="margin-top:0.5rem;"><strong>Be aware:</strong> <code>GetBackBufferData</code> now throws <code>NotSupportedException</code> instead of returning the last clear colour: a renderer with no honest pixel result refuses rather than inventing one. It is not a pixel oracle.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🖥</div>
<span class="status-badge status-partial">Experimental — CPU</span>
<h3>Software Renderer</h3>
<p>A genuine CPU rasterizer with edge functions, a Z-buffer and perspective-correct interpolation into a CPU-owned framebuffer. Useful for GPU-free pixel tests, and it is what <code>GraphicsAdapter::UseReferenceDevice</code> selects. Selected with <code>-DCNA_GRAPHICS_RENDERER=SOFTWARE</code>.</p>
<p style="margin-top:0.5rem;"><strong>Scope and gaps:</strong> it now handles triangle lists and strips, lines and points, indexed and multi-stream draws, up to four render targets, 4x MSAA, occlusion queries, instancing and float render targets, with opt-in compiled effects. It still ignores custom <code>ShaderEffect</code> source, has no shadow sampling or IBL, and is not a real-time renderer by design. It is off-screen on every windowing platform; only the Terminal platform displays its frames. On the real-XNA oracle corpus it was measured at 18 of 39 scenes byte-exact (30 within one channel value), and only two line scenes have a CTest, which fails on a render failure rather than on a pixel difference.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">🖥</div>
<span class="status-badge status-done">Production — Windows-only</span>
<h3>Direct3D 9 Renderer</h3>
<p>Windows-only and the renderer used for the 39-scene XNA oracle comparison at zero tolerance. It includes shader, device-lost recovery and MRT paths. The oracle result is specific to <code>DIRECTX9</code> and was recorded through Wine and DXVK on Linux, the same host that produced the genuine-XNA reference images; it is not repeated on native Windows and does not run in CI. Compiled effects are opt-in with <code>CNA_DIRECTX9_COMPILED_EFFECTS</code>. Selected with <code>-DCNA_GRAPHICS_RENDERER=DIRECTX9</code>.</p>
<p style="margin-top:0.5rem;"><strong>Note:</strong> <code>SupportsCapability()</code> is still not overridden, so this is the one renderer that relies wholesale on the permissive default.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">💥</div>
<span class="status-badge status-done">Supported</span>
<h3>SDL_GPU Renderer</h3>
<p>Built on SDL3's GPU API with deferred/retained rendering, stencil and MSAA paths, compute, indirect draw and float render targets. Compiled XNA/FNA effects are separately opt-in with <code>CNA_SDL_GPU_COMPILED_EFFECTS</code>. Selected with <code>-DCNA_GRAPHICS_RENDERER=SDL_GPU</code>.</p>
<p style="margin-top:0.5rem;"><strong>Known gaps:</strong> it is no longer Vulkan-only: with <code>CNA_SDL_GPU_SHADERCROSS</code> (default ON on Windows and Apple) CNA's SPIR-V shaders are translated for SDL’s Direct3D 12 and Metal drivers. Occlusion queries are not available (SDL’s GPU API has none), and source <code>ShaderEffect</code> needs libshaderc, so it is unavailable on Windows, Apple and Emscripten builds. It requires the SDL3 platform.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🖲</div>
<span class="status-badge status-done">Functional</span>
<h3>ASCII post-process effect</h3>
<p>Quantizes any <code>Texture2D</code> or <code>RenderTarget2D</code> into a glyph and colour grid. It is a CNAEXT post-process effect, <code>CNA::Graphics::AsciiPostProcessEffect</code>: because it works through the public <code>Texture2D::GetData()</code> and <code>SpriteBatch</code> API rather than a renderer-internal type, it runs on <em>any</em> renderer, including 3D-rendered sources.</p>
<p style="margin-top:0.5rem;"><strong>Note:</strong> it is deliberately not an XNA <code>Effect</code> subclass — it performs its own multi-step CPU readback and re-upload, so it costs a GPU→CPU readback per draw. Requires <code>-DCNA_CNAEXT=ON</code>. It is not a terminal renderer; the POSIX Terminal platform instead displays frames from the <code>SOFTWARE</code> renderer.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🍏</div>
<span class="status-badge status-partial">Supported (declared) — macOS and iOS</span>
<h3>Metal Renderer</h3>
<p>A native Apple Metal renderer for macOS and iOS; SDL3 supplies only the window and the view that holds the <code>CAMetalLayer</code>. It draws 2D and 3D with MSAA, multiple render targets, occlusion queries, instancing and multi-stream input, stores XNA’s float, packed and DXT formats natively in 2D, cube and volume textures, runs <code>SpriteBatch</code> custom effects written in MSL, and runs compiled XNA effects when built with <code>CNA_METAL_COMPILED_EFFECTS</code>. It has no compute or indirect draw. It was qualified on a physical Mac mini M4 in CNA’s Apple campaign. Selected with <code>-DCNA_GRAPHICS_RENDERER=METAL</code>.</p>
<p style="margin-top:0.5rem;"><strong>Evidence boundary:</strong> on a physical Mac mini M4 the full test tree passed (11,015 tests, none failed), the 261 Metal-labelled tests passed under the Metal validation layers in Debug and Release, and all 91 ported XNA samples passed the renderer matrix; the console was locked, so on-screen presentation was not observed. CNA’s verdict is <em>Supported</em>, not primary-production (compiled effects are opt-in, custom effects are SpriteBatch-only, <code>PresentInterval.Two</code> presents as <code>One</code>, no soak run). On iOS it ran in the iOS Simulator with an exact pixel probe; no physical iPhone or iPad ran it. CI builds it on GitHub’s <code>macos-26</code> runners.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🔁</div>
<span class="status-badge status-partial">Experimental</span>
<h3>FNA3D Renderer</h3>
<p>An adapter over the FNA-XNA <code>FNA3D</code> C library (pinned), which chooses SDL_GPU, Direct3D 11 or OpenGL at run time (override with <code>FNA3D_FORCE_DRIVER</code>). It runs any compiled Effect Framework binary — compiled effects are always on, with no build option — but not <code>ShaderEffect</code> source. It reports 3D, MRT, multi-stream input and probed MSAA and instancing; no float render targets or compute, and it refuses PBR draws by name. Requires the SDL3 platform. Selected with <code>-DCNA_GRAPHICS_RENDERER=FNA3D</code>.</p>
<p style="margin-top:0.5rem;"><strong>Evidence boundary:</strong> its oracle CTest gates only that all 39 scenes render, not pixel equality.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">⚪</div>
<span class="status-badge status-done">Diagnostic</span>
<h3>Stub Renderer</h3>
<p>The smallest possible complete renderer: it renders nothing and keeps no bookkeeping, all 19 capabilities are false and it reports no 3D. It is the default of the <code>dev</code>, <code>unit</code> and <code>release-modules</code> presets and is always ranked last by automatic fallback. Selected with <code>-DCNA_GRAPHICS_RENDERER=STUB</code>.</p>
</div>
</div>
<!-- Platform targets -->
<span class="section-label">Platform Support</span>
<h2 id="cross-platform">Cross-Platform Architecture</h2>
<p class="section-desc">CNA separates target OS from host integration, audio I/O and graphics rendering; support claims below are scoped to the evidence in this snapshot.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-blue">🔗</div>
<span class="status-badge status-done">Supported</span>
<h3>Linux (x86_64)</h3>
<p>The primary development platform, with <code>OPENGLES3</code> as the default renderer and the broadest CI coverage: SDL3 with <code>OPENGLES3</code>, <code>VULKAN</code>, <code>SOFTWARE</code> and <code>SDL_RENDERER</code>, the SDL3 window suite on SDL’s <code>x11</code> driver (Xvfb) and <code>wayland</code> driver (headless Weston), and an SDL-free Headless lane with ALSA audio. SDL3’s Wayland driver is built only if its development packages were present when SDL was first built. FFmpeg video decoding is optional (<code>CNA_ENABLE_VIDEO</code>) and built on Linux and macOS only when the FFmpeg libraries are found. See <a href="docs/native-platforms.html">Windows, X11 and Wayland</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">🖥</div>
<span class="status-badge status-done">Supported</span>
<h3>Windows (x86_64)</h3>
<p>Reached through a MinGW-w64 cross-toolchain as well as native MSVC, with windows from SDL3’s <code>windows</code> video driver. Two renderers are Windows-only (<code>DIRECTX9</code>, <code>DIRECTX11</code>). The Direct3D paths have focused evidence — Direct3D 11 validated on one physical Windows 11 machine, and a recorded native-MSVC run on GitHub’s Windows image passing all 300 of its CTest entries — but the native Windows workflows remain manual-dispatch rather than automatic merge gates, and much Windows evidence is cross-compiled and run under Wine. FFmpeg video is never built for Windows.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">📱</div>
<span class="status-badge status-partial">Code-level support — no CI</span>
<h3>Android</h3>
<p>Genuinely wired through CMake and the Android NDK — sensors link against <code>android</code>, and <code>Compass</code>/<code>Motion</code> use a real NDK fusion of 5 sensors. The default renderer is <code>SDL_RENDERER</code> and the platform is SDL3. <strong>Caveats:</strong> there is no Android CI and no CMake preset, the only Android build project is the Devices demo (minSdk 24, arm64-v8a), and FFmpeg video is unavailable on this target.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🌐</div>
<span class="status-badge status-done">Supported</span>
<h3>Emscripten / Web</h3>
<p>A real platform with <code>WEBGL2</code>, the Emscripten-only default, plus <code>WEBGPU</code> through its browser route. CI builds and links one bundle with <code>WEBGL2;WEBGPU</code> and asserts both renderers and the JavaScript selection surface are in it; it does not run them in a browser. Saves persist: the storage module mounts the browser’s IndexedDB for <code>StorageDevice</code> and isolated storage and restores it before <code>main()</code>. Games that start threads build with Emscripten threads. FFmpeg video remains excluded. The strongest evidence is the 90 C++ ports of XNA samples that play at <a href="https://samples.libcna.com/" target="_blank" rel="noopener">samples.libcna.com</a>, each run in Chrome when it was completed.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🖥</div>
<span class="status-badge status-partial">Scoped support</span>
<h3>macOS / iOS</h3>
<p>macOS was tested on a physical Mac mini M4 (macOS 27.0.1, Xcode 27): seven renderer trees — <code>METAL</code>, <code>OPENGL33</code>, <code>WEBGPU</code>, <code>SDL_GPU</code>, <code>FNA3D</code>, <code>SOFTWARE</code> and <code>SDL_RENDERER</code> — passed their full CTest suites with no failure, and CI builds on GitHub’s <code>macos-26</code> runners (deployment floor macOS 13.3; no Intel Mac was run). iOS is experimental: <code>SDL_RENDERER</code> and <code>METAL</code> are admitted (floor iOS 16.3, networking off); the iOS Simulator (iPhone 17 profile) runs a smoke app and an exact <code>METAL</code> pixel probe, and device apps final-link but no physical iPhone or iPad ran them. tvOS is unsupported.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">⌨</div>
<span class="status-badge status-done">Supported (POSIX)</span>
<h3>Terminal & headless hosts</h3>
<p>The <code>TERMINAL</code> platform runs CNA in a POSIX terminal with the <code>SOFTWARE</code> renderer displaying frames, and <code>HEADLESS</code> runs any game logic without a window. CI covers both, including a pseudo-TTY test that runs the 2D demo through the terminal presenter. There is no Windows console backend.</p>
</div>
</div>
<!-- Diagnostics, inspector, C API -->
<span class="section-label">Tooling</span>
<h2 id="tooling">Diagnostics, Inspector & C API</h2>
<p class="section-desc">Three new opt-in pieces sit beside the runtime: an in-process diagnostics layer, an out-of-process inspector built on it, and an experimental C ABI. The Inspector and the C API stay outside a default game's link closure, Diagnostics compiles to nothing unless enabled, and none of the three is a release.</p>
<div class="feature-grid mb-4">
<div class="feature-card">
<div class="feature-icon icon-green">📈</div>
<span class="status-badge status-done">Implemented (opt-in)</span>
<h3>Diagnostics & Profiler</h3>
<p><code>CNA::Diagnostics</code> is a renderer-independent, in-process observation layer: counters, gauges, per-frame counters, a 240-frame history, resource metadata and, in <code>FULL</code> mode, CPU zones, markers and an event history with bounded recording and Chrome-trace export. It uses only the C++ standard library: no thread, no socket, no renderer dependency. Enable it with <code>-DCNA_DIAGNOSTICS=OFF|STATS|FULL</code> (default <code>OFF</code>); in lower modes the instrumentation macros compile to nothing and never evaluate their arguments.</p>
<p style="margin-top:0.5rem;"><strong>Built in:</strong> game tick, update and draw zones, draw-call, primitive, texture-binding, effect and render-target counters, sprite submissions, resource metadata for textures and buffers, and audio voice gauges. <strong>Not published:</strong> GPU timings, input metrics and process memory; no C ABI routes exist for it, and no CI workflow enables it. See <a href="docs/diagnostics.html">Diagnostics</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-blue">🔍</div>
<span class="status-badge status-done">Implemented (opt-in, desktop)</span>
<h3>Inspector</h3>
<p>An optional, <strong>view-only</strong> development tool with two parts: an in-process agent (<code>CNA::Inspector::Agent</code>, one background thread, authenticated TCP, a compact binary protocol) and a separate <code>cna-inspector</code> bridge that serves an offline browser UI at <code>http://127.0.0.1:<port>/</code>. The UI has Session, Performance, CPU profiler, Graphics, Resources, Audio, Input and Events views. It cannot edit state, run scripts or inject input.</p>
<p style="margin-top:0.5rem;"><strong>Security and limits:</strong> loopback by default (a remote bind needs <code>allowRemote</code>), a 256-bit token from the OS random source, and nothing runs until the application calls <code>Agent::Start()</code> — there is no static initializer or environment hook. Build it with <code>-DCNA_BUILD_INSPECTOR=ON</code> (refused on Emscripten, Android and iOS; not in the <code>CNA</code> umbrella target). Resource previews are unavailable in real sessions today because no renderer installs a preview provider, and no CI workflow covers it. See <a href="docs/inspector.html">Inspector</a>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🔌</div>
<span class="status-badge status-partial">Experimental — ABI 0.46.0</span>
<h3>C API (C ABI 0.46.0)</h3>
<p>A C99-consumable ABI over the C++ framework: 60 public headers and <strong>3,210</strong> exported routes, opaque handles, a per-thread last-error record, count-then-copy strings, one active runtime per process, a host-driven frame loop and an opt-in queue for calls from other threads. The version is 0.46.0 (alpha.1: 0.7.0) and remains an experimental <code>0.x</code> ABI; renderer identity values are stable and unused ones stay reserved, and 0.46.0 adds a UIKit native-window kind for iOS. A recorded baseline (197 struct layouts, 3,210 exports) is enforced by header-only gates, and a <code>find_package(CNA CONFIG)</code> package with <code>CNA::CApi</code> and a <code>hello_cna</code> example is exercised by a local consumer test on Linux and, on a physical Mac mini M4, as a Mach-O <code>libcna_c_api.dylib</code> exporting exactly the 3,210 routes, installed with an <code>@loader_path</code> rpath, plus a static archive (119/119 C API tests in the <code>SOFTWARE</code> and <code>SDL_RENDERER</code> trees).</p>
<p style="margin-top:0.5rem;"><strong>Status:</strong> CNA's semantic inventory lists 8,142 public C++ symbols — 7,053 implemented, 15 partial, 631 planned and 443 not applicable — and its own release gate reads “Not ready” because of those 631. No CNA CI job builds the C library on any platform; the CNA.NET project builds and uses it on Linux and, locally, on a physical Mac mini M4. The C# binding <a href="docs/cna-net.html">CNA.NET</a> is the maintained consumer and admits exactly this ABI version after a compatibility review; the Common Lisp, Go, Java, Python, Ruby, Rust, Swift and TypeScript bindings are archived and not maintained. See the <a href="docs/c-api.html">C API page</a>.</p>
</div>
</div>
<!-- C++23 -->
<span class="section-label">Technology</span>
<h2 id="cpp23">Modern C++23 Codebase</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="feature-icon icon-blue">⚡</div>
<h3>C++23 Standard</h3>
<p>CNA targets C++23 throughout (extensions off). CMake does not check a compiler version; CI builds with GCC 14, current AppleClang, MSVC on <code>windows-latest</code>, mingw-w64 and Emscripten 6.0.3, and the code base uses <code><format></code> unconditionally, which needs libstdc++ 13, a current libc++ or MSVC 2022. The alpha.1 statement “GCC 12+, Clang 15+, or MSVC 2022 v17.8+” is neither enforced by the build nor proven by CI.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">📦</div>
<h3>CMake Build System</h3>
<p>CMake 3.20+ with vendored SDL dependencies (git submodules) by default. Configure the target OS, platform (<code>CNA_PLATFORM</code>), renderer set, audio (<code>CNA_AUDIO_PLATFORM</code>) and SDL availability (<code>CNA_ENABLE_SDL</code>) as independent axes; single-renderer SDL3 remains the simplest default. 17 visible configure presets ship, and on native ELF GNU/Clang builds with CMake 3.27+ <code>CNA_SHARED_LIBRARY</code> defaults ON so executables link one <code>libcna.so</code>. Optional inputs are three-state switches (<code>CNA_ENABLE_VIDEO</code>, <code>CNA_ENABLE_FONT_PIPELINE</code>, <code>CNA_ENABLE_MEDIA_PIPELINE</code>, <code>CNA_CNB_ZSTD</code>). Siblings: <code>sharp-runtime</code> always, <code>easy-gl</code> (with <code>meta-gl</code>) for the GL identities. For this snapshot clone CNA and sharp-runtime on branch <code>apple/m4-stabilization</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-orange">🧪</div>
<h3>Test Suite</h3>
<p>This snapshot contains 813 C++ test source files (781 with a counted test macro) and 11,380 static GoogleTest-family definitions, counted with the site's published method (alpha.1: 568 and 8,263), plus 781 standalone <code>examples/**/*_test.cpp</code> pixel programs outside those figures. Instantiated GoogleTest cases and CTest registrations vary with renderer, platform, feature options and dependencies, so every result is reported for a configured build and no CTest total is published. There are 22 focused per-module test targets besides the aggregate <code>CnaTests</code>. Renderer pixel programs, the XNA oracle and FNA differential checks cover separate compatibility questions. See <a href="docs/verification.html">Verification & Known Issues</a>.</p>
<p style="margin-top:0.5rem;"><strong>Coverage is uneven:</strong> Storage has one source with 14 statically discoverable definitions and Media 304; each still needs configuration-specific execution evidence.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-red">⚙</div>
<h3>Continuous Integration</h3>
<p>The snapshot has 18 GitHub Actions workflow files (24 jobs), 16 of which trigger automatically on push and pull request. They span intended general and focused Linux tests, runtime multi-renderer sets, platform abstraction (SDL3 on X11 and Wayland, an SDL-free Headless job, and a manual native-MSVC SDL3 job), Emscripten and browser lanes, Apple/Metal and five build-free C API gates. The alpha.1 defect (a stale <code>EASYGL</code> value in the general job and two Input rows) is fixed. Native Windows workflows remain manual, and there is no Android, C-library-build or oracle-corpus workflow. Workflow files are configuration, not results: whether each lane currently passes was not evaluated for this page, and build/link/simulator evidence must not be upgraded into a physical-device or universal runtime claim.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-green">✓</div>
<h3>Reference-checked behavior</h3>
<p>CNA keeps <strong>39</strong> renderer-neutral test scenes (256×256, HiDef) whose reference images come from running the genuine Microsoft XNA 4.0 runtime under Wine with DXVK on Linux, plus 7 unbound-texture scenes and a 17-format channel-expansion table measured the same way. The repository records all 39 scenes as pixel-exact on the <code>DIRECTX9</code> oracle path (CTest <code>D3D9_XNA_Diff</code>, the same stack, zero tolerance); the last consolidated dated report covers 31 of them and later per-scene notes record the rest. No 39-scene run was executed for this documentation, it has not been repeated on native Windows, and it does not run in CI. No other renderer is held to that bar: EasyGL and Software have a CTest on two line scenes (the EasyGL test fails on any pixel difference; the Software test only if a scene does not render), and FNA3D gates only that scenes render.</p>
<p style="margin-top:0.5rem;"><strong>Also present:</strong> 32 cross-renderer parity fixtures registered for EasyGL, WebGPU, SDL_GPU and Direct3D 11 (their oracle is the fixtures' own assertions, not real XNA); a glTF conformance corpus of 148 assets (140 captured and 8 safely rejected) with renderer-owned goldens, plus a Khronos comparison subset of 13; and a manual harness that diffs enums, presets, packed vectors and viewport against a running FNA build.</p>
</div>
<div class="feature-card">
<div class="feature-icon icon-purple">🔧</div>
<h3>sharp-runtime</h3>
<p>A required sibling repo and a substantial project in its own right: a C++23 reimplementation of a .NET BCL subset, described by its own README as a set of 41 independently selectable components (a moving companion-project figure, not a CNA metric; its test counts are deliberately not restated here). CNA now requests the <code>Resources</code> and <code>Xml.Serialization</code> components, which exist only on sharp-runtime's <code>apple/m4-stabilization</code> branch, so this snapshot needs sharp-runtime <code>next</code>, not its default <code>main</code>. It implements <code>System::*</code> broadly — primitives, <code>Collections</code> (Generic, Immutable, Concurrent, Frozen, Specialized, ObjectModel), <code>IO</code> (plus Compression, Hashing, IsolatedStorage), <code>Text</code> (including a full <code>System.Text.Json</code> and <code>Regex</code>), <code>Net</code> (Sockets, Http, WebSockets), <code>Threading</code> (plus Tasks and Channels), <code>Xml</code> (plus Linq and XPath), <code>Globalization</code> (10 calendars), <code>Numerics</code> (including <code>BigInteger</code>), <code>Diagnostics</code> and <code>Buffers</code>. <code>Security.Cryptography</code> covers hashing rather than asymmetric crypto, TLS or X.509.</p>
</div>
</div>
</div>
</section>
</main>
<footer>
<div class="footer-inner">
<div class="footer-top">
<div class="footer-brand">
<div class="footer-brand-name">CNA</div>
<p>Documentation snapshot for CNA commit c1c316b9 (9 October 2026), a post-alpha.1 development snapshot. CNA exposes 14 renderer identities across 12 implementation families; APIs may change before 1.0.</p>
</div>
<div class="footer-col">
<h4>Project</h4>
<ul>
<li><a href="about.html">About</a></li>
<li><a href="features.html">Features</a></li>
<li><a href="architecture.html">Architecture</a></li>
<li><a href="roadmap.html">Roadmap</a></li>
<li><a href="network.html">CNA Network</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Docs</h4>
<ul>
<li><a href="docs/getting-started.html">Getting Started</a></li>
<li><a href="docs/building.html">Building</a></li>
<li><a href="docs/platforms.html">Platforms</a></li>
<li><a href="docs/rendering-backends.html">Renderers</a></li>
<li><a href="docs/faq.html">FAQ</a></li>
<li><a href="deep-dives/index.html">Deep Dives</a></li>
<li><a href="known-issues/index.html">Known Issues</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Community</h4>
<ul>
<li><a href="https://github.com/libcna/cna" target="_blank" rel="noopener">GitHub</a></li>
<li><a href="https://discord.gg/vrnc4n6DaE" target="_blank" rel="noopener">Discord</a></li>
<li><a href="demos.html">Demos</a></li>
<li><a href="videos.html">Videos</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p>CNA is not affiliated with or endorsed by Microsoft Corporation. XNA is a trademark of Microsoft. Licensed under the Microsoft Public License (Ms-PL).</p>
<div class="footer-links">
<a href="https://github.com/libcna/cna/blob/c1c316b9c7a846ce8002809c151fcd1af14942c9/LICENSE" target="_blank" rel="noopener">License</a>
<a href="contact.html">Contact</a>
</div>
</div>
</div>
</footer>
<script src="js/main.js"></script>
<script src="js/prism/prism.min.js" defer></script>
<script src="js/prism/prism-cpp.min.js" defer></script>
<script src="js/prism/prism-glsl.min.js" defer></script>
<script src="js/prism/prism-json.min.js" defer></script>
<script src="js/prism/prism-bash.min.js" defer></script>
<script src="js/prism/prism-cmake.min.js" defer></script>
</body>
</html>