diff --git a/ExternalToolProjects/FakeTemporalAA/FakeTemporalAA.csproj b/ExternalToolProjects/FakeTemporalAA/FakeTemporalAA.csproj
new file mode 100644
index 0000000000..f61ddc82c4
--- /dev/null
+++ b/ExternalToolProjects/FakeTemporalAA/FakeTemporalAA.csproj
@@ -0,0 +1,11 @@
+
+
+
+
+ true
+ $(NoWarn);IDE0065;SA1200
+
+
+
+
+
diff --git a/ExternalToolProjects/FakeTemporalAA/FakeTemporalAAToolForm.cs b/ExternalToolProjects/FakeTemporalAA/FakeTemporalAAToolForm.cs
new file mode 100644
index 0000000000..d6720cc94f
--- /dev/null
+++ b/ExternalToolProjects/FakeTemporalAA/FakeTemporalAAToolForm.cs
@@ -0,0 +1,83 @@
+namespace BizHawk.Experiments.FakeTemporalAA;
+
+using System;
+
+using BizHawk.Bizware.Graphics;
+using BizHawk.Client.Common;
+using BizHawk.Client.EmuHawk;
+using BizHawk.Emulation.Common;
+
+[ExternalTool(TOOL_NAME, Description = "Naively blends each frame with the previous")]
+public sealed class FakeTemporalAAToolForm: ToolFormBase, IExternalToolForm
+{
+ private const string TOOL_NAME = "Fake Temporal Anti-aliasing";
+
+ private BitmapBuffer? _bbPrev = null;
+
+ [RequiredService]
+ public IVideoProvider? _maybeVideoProvider { get; set; }
+
+ public ApiContainer? _maybeAPIContainer { get; set; }
+
+ private ApiContainer APIs
+ => _maybeAPIContainer!;
+
+ protected override string WindowTitleStatic
+ => TOOL_NAME;
+
+ public FakeTemporalAAToolForm()
+ => _ = _maybeVideoProvider; // used via ToolFormBase.MainForm
+
+ private void ClearDrawingSurface()
+ => APIs.Gui.WithSurface(DisplaySurfaceID.EmuCore, g => g.ClearGraphics(DisplaySurfaceID.EmuCore));
+
+ protected override void Dispose(bool disposing)
+ {
+ ClearDrawingSurface();
+ base.Dispose(disposing);
+ }
+
+ public override void Restart()
+ {
+ _bbPrev = null;
+ ClearDrawingSurface();
+ }
+
+ public override void UpdateValues(ToolFormUpdateType type)
+ {
+ const int OPACITY_MASK = 0xFF << 24;
+ static void Invert(Span buf)
+ {
+ for (var i = 0; i < buf.Length; i++) buf[i] = OPACITY_MASK | ~buf[i]; //TODO vectorise?
+ }
+ static int AverageXRGB(int c1, int c2)
+ {
+ //TODO can this be improved?
+ const int R_MASK = 0xFF0000;
+ const int G_MASK = 0xFF00;
+ const int B_MASK = 0xFF;
+ var r = (((c1 & R_MASK) + (c2 & R_MASK)) / 2) & R_MASK;
+ var g = (((c1 & G_MASK) + (c2 & G_MASK)) / 2) & G_MASK;
+ var b = (((c1 & B_MASK) + (c2 & B_MASK)) / 2) & B_MASK;
+ var c3 = r | g | b;
+ c3 &= ~OPACITY_MASK;
+ return OPACITY_MASK | c3;
+ }
+ if (type is not (ToolFormUpdateType.PreFrame or ToolFormUpdateType.FastPreFrame)) return;
+
+ var bbCurrent = MainForm.MakeScreenshotImage();
+ var spanCurrent = bbCurrent.AsSpan();
+ Invert(spanCurrent);
+ if (_bbPrev is null) // initialisation
+ {
+ _bbPrev = bbCurrent;
+ return;
+ }
+
+ var spanPrev = _bbPrev.AsSpan(); // was inverted before saving
+ for (var i = 0; i < spanCurrent.Length; i++) spanPrev[i] = AverageXRGB(spanPrev[i], spanCurrent[i]);
+ Invert(spanPrev);
+ APIs.Gui.WithSurface(DisplaySurfaceID.EmuCore, g => g.DrawImage(_bbPrev!.ToSysdrawingBitmap(), 0, 0, cache: false));
+ _bbPrev = bbCurrent;
+ }
+}
diff --git a/ExternalToolProjects/FakeTemporalAA/build_debug.sh b/ExternalToolProjects/FakeTemporalAA/build_debug.sh
new file mode 120000
index 0000000000..c2127aded1
--- /dev/null
+++ b/ExternalToolProjects/FakeTemporalAA/build_debug.sh
@@ -0,0 +1 @@
+../.build_debug.sh
\ No newline at end of file
diff --git a/ExternalToolProjects/FakeTemporalAA/build_release.sh b/ExternalToolProjects/FakeTemporalAA/build_release.sh
new file mode 120000
index 0000000000..801b8e5998
--- /dev/null
+++ b/ExternalToolProjects/FakeTemporalAA/build_release.sh
@@ -0,0 +1 @@
+../.build_release.sh
\ No newline at end of file
diff --git a/ExternalToolProjects/FakeTemporalAA/run_with_tool.sh b/ExternalToolProjects/FakeTemporalAA/run_with_tool.sh
new file mode 120000
index 0000000000..b7cf6138ab
--- /dev/null
+++ b/ExternalToolProjects/FakeTemporalAA/run_with_tool.sh
@@ -0,0 +1 @@
+../.run_with_tool.sh
\ No newline at end of file
diff --git a/ExternalToolProjects/NET48ExternalToolForm.targets b/ExternalToolProjects/NET48ExternalToolForm.targets
index f65ba71ec9..822130c2c6 100644
--- a/ExternalToolProjects/NET48ExternalToolForm.targets
+++ b/ExternalToolProjects/NET48ExternalToolForm.targets
@@ -8,6 +8,9 @@
+