Skip to content

Commit 44fdab8

Browse files
committed
Add new visual effect examples
CompositorEffectsExample: - Add MatrixRainWindow.cs - Matrix-style digital rain effect - Add ParticleSystemWindow.cs - Particle system animation - Add WipeTransitionWindow.cs - Wipe transition effects - Update Program.cs to include new effect windows MultiDashboard: - Minor updates to dashboard configuration
1 parent 0758833 commit 44fdab8

5 files changed

Lines changed: 845 additions & 17 deletions

File tree

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
using SharpConsoleUI;
2+
using SharpConsoleUI.Controls;
3+
using SharpConsoleUI.Layout;
4+
using Spectre.Console;
5+
6+
namespace CompositorEffectsExample;
7+
8+
/// <summary>
9+
/// Demonstrates PreBufferPaint hook with iconic "Matrix" falling characters effect.
10+
/// Green characters cascade down columns at varying speeds, creating depth and movement.
11+
/// </summary>
12+
public class MatrixRainWindow : Window
13+
{
14+
private int[] _columnPositions = Array.Empty<int>();
15+
private float[] _columnSpeeds = Array.Empty<float>();
16+
private char[][] _columnTrails = Array.Empty<char[]>();
17+
private const int TrailLength = 15;
18+
private readonly Random _random = new();
19+
private System.Timers.Timer? _animationTimer;
20+
21+
public MatrixRainWindow(ConsoleWindowSystem windowSystem) : base(windowSystem)
22+
{
23+
Title = "Matrix Rain Effect (PreBufferPaint)";
24+
Width = 80;
25+
Height = 30;
26+
27+
InitializeColumns();
28+
29+
30+
// Add info panel
31+
AddControl(new MarkupControl(new List<string>
32+
{
33+
"[bold green]╔════════════════════════════════════════════════════╗[/]",
34+
"[bold green]║ MATRIX RAIN - PreBufferPaint Demo ║[/]",
35+
"[bold green]╚════════════════════════════════════════════════════╝[/]",
36+
"",
37+
"[white]This demonstrates PreBufferPaint hook which fires[/]",
38+
"[white]BEFORE controls are painted, allowing custom animated[/]",
39+
"[white]backgrounds that don't interfere with UI elements.[/]",
40+
"",
41+
"[dim]• Green characters cascade at varying speeds[/]",
42+
"[dim]• Each column has independent position and trail[/]",
43+
"[dim]• Brightness fades from head to tail[/]",
44+
"[dim]• Runs at 30fps with minimal overhead[/]",
45+
"",
46+
"[yellow]Press Esc to close this window[/]"
47+
}));
48+
49+
// Hook into PreBufferPaint AFTER all controls are added
50+
if (Renderer != null)
51+
{
52+
Renderer.PreBufferPaint += RenderMatrixRain;
53+
}
54+
55+
// Start animation (exactly like FadeInWindow)
56+
_animationTimer = new System.Timers.Timer(33); // ~30 FPS
57+
_animationTimer.AutoReset = true;
58+
_animationTimer.Elapsed += (sender, e) =>
59+
{
60+
UpdateColumnPositions();
61+
this.Invalidate(redrawAll: true);
62+
};
63+
_animationTimer.Start();
64+
65+
// Cleanup on window close
66+
OnClosing += (sender, e) =>
67+
{
68+
_animationTimer?.Stop();
69+
_animationTimer?.Dispose();
70+
71+
if (Renderer != null)
72+
{
73+
Renderer.PreBufferPaint -= RenderMatrixRain;
74+
}
75+
};
76+
}
77+
78+
private void InitializeColumns()
79+
{
80+
int cols = Width;
81+
_columnPositions = new int[cols];
82+
_columnSpeeds = new float[cols];
83+
_columnTrails = new char[cols][];
84+
85+
for (int i = 0; i < cols; i++)
86+
{
87+
_columnPositions[i] = _random.Next(-TrailLength, Height);
88+
_columnSpeeds[i] = 0.5f + (float)_random.NextDouble() * 1.5f;
89+
_columnTrails[i] = GenerateRandomTrail();
90+
}
91+
}
92+
93+
private void RenderMatrixRain(CharacterBuffer buffer, LayoutRect dirtyRegion, LayoutRect clipRect)
94+
{
95+
// Clear to black first
96+
buffer.FillRect(new LayoutRect(0, 0, buffer.Width, buffer.Height),
97+
' ', Color.Black, Color.Black);
98+
99+
// Render each column's trail
100+
for (int x = 0; x < _columnPositions.Length && x < buffer.Width; x++)
101+
{
102+
int headY = _columnPositions[x];
103+
104+
for (int i = 0; i < TrailLength; i++)
105+
{
106+
int y = headY - i;
107+
if (y < 0 || y >= buffer.Height) continue;
108+
109+
// Fade from bright green (head) to dark green (tail)
110+
float brightness = 1.0f - (i / (float)TrailLength);
111+
Color color = new Color(
112+
0,
113+
(byte)(255 * brightness),
114+
(byte)(128 * brightness)
115+
);
116+
117+
char ch = i < _columnTrails[x].Length ? _columnTrails[x][i] : ' ';
118+
buffer.SetCell(x, y, ch, color, Color.Black);
119+
}
120+
}
121+
}
122+
123+
private void UpdateColumnPositions()
124+
{
125+
for (int i = 0; i < _columnPositions.Length; i++)
126+
{
127+
_columnPositions[i] += (int)_columnSpeeds[i];
128+
129+
// Reset at bottom with random delay
130+
if (_columnPositions[i] - TrailLength > Height)
131+
{
132+
_columnPositions[i] = -TrailLength - _random.Next(0, 20);
133+
_columnTrails[i] = GenerateRandomTrail();
134+
}
135+
}
136+
}
137+
138+
private char[] GenerateRandomTrail()
139+
{
140+
char[] trail = new char[TrailLength];
141+
for (int i = 0; i < TrailLength; i++)
142+
{
143+
// Mix of katakana-like characters, numbers, and symbols
144+
trail[i] = _random.Next(0, 100) switch
145+
{
146+
< 40 => (char)_random.Next('A', 'Z' + 1), // Uppercase letters
147+
< 70 => (char)_random.Next('0', '9' + 1), // Numbers
148+
< 90 => "!@#$%^&*+-=<>?"[_random.Next(15)], // Symbols
149+
_ => ' ' // Space
150+
};
151+
}
152+
return trail;
153+
}
154+
155+
}

0 commit comments

Comments
 (0)