diff --git a/Examples/UICatalog/Scenarios/BigText/BigText.cs b/Examples/UICatalog/Scenarios/BigText/BigText.cs
new file mode 100644
index 0000000000..1f1b9a1d47
--- /dev/null
+++ b/Examples/UICatalog/Scenarios/BigText/BigText.cs
@@ -0,0 +1,564 @@
+#nullable enable
+using System.Numerics;
+using JetBrains.Annotations;
+using SixLabors.Fonts;
+
+namespace UICatalog.Scenarios;
+
+///
+/// A that renders text in large block letters using .
+/// The text is rendered using TrueType fonts converted to vector outlines and approximated as box-drawing characters.
+///
+///
+///
+/// uses SixLabors.Fonts to load TrueType fonts and extract glyph outlines as vector paths.
+/// These paths are then approximated as horizontal and vertical lines that can be rendered using LineCanvas.
+/// The characters are rendered at a larger scale than normal text, making them suitable for titles, headers, or
+/// emphasis.
+///
+///
+/// The view automatically sizes itself based on the text content and the configured .
+///
+///
+///
+///
+/// var bigText = new BigText
+/// {
+/// Text = "Hello!",
+/// GlyphHeight = 8,
+/// Style = LineStyle.Double,
+/// Font = "Arial"
+/// };
+///
+///
+public class BigText : View
+{
+ private int _glyphHeight = 8;
+ private LineStyle _style = LineStyle.Single;
+ private Font? _font;
+ private string _fontFamily = "Arial";
+ private static readonly FontCollection _fontCollection = new ();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BigText ()
+ {
+ CanFocus = false;
+ Height = Dim.Auto (DimAutoStyle.Content);
+ Width = Dim.Auto (DimAutoStyle.Content);
+
+ // Try to load system fonts
+ TryLoadSystemFonts ();
+ UpdateFont ();
+ }
+
+ private static bool _systemFontsLoaded;
+
+ private static void TryLoadSystemFonts ()
+ {
+ if (_systemFontsLoaded)
+ {
+ return;
+ }
+
+ try
+ {
+ // Try to add system fonts
+ if (OperatingSystem.IsWindows ())
+ {
+ string fontsPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Fonts));
+
+ if (Directory.Exists (fontsPath))
+ {
+ foreach (string fontFile in Directory.GetFiles (fontsPath, "*.ttf"))
+ {
+ try
+ {
+ _fontCollection.Add (fontFile);
+ }
+ catch
+ {
+ // Ignore individual font loading errors
+ }
+ }
+ }
+ }
+ else if (OperatingSystem.IsLinux ())
+ {
+ string [] fontPaths =
+ {
+ "/usr/share/fonts/truetype",
+ "/usr/local/share/fonts",
+ Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), ".fonts")
+ };
+
+ foreach (string fontPath in fontPaths)
+ {
+ if (Directory.Exists (fontPath))
+ {
+ foreach (string fontFile in Directory.GetFiles (fontPath, "*.ttf", SearchOption.AllDirectories))
+ {
+ try
+ {
+ _fontCollection.Add (fontFile);
+ }
+ catch
+ {
+ // Ignore individual font loading errors
+ }
+ }
+ }
+ }
+ }
+ else if (OperatingSystem.IsMacOS ())
+ {
+ string [] fontPaths =
+ {
+ "/System/Library/Fonts",
+ "/Library/Fonts",
+ Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.UserProfile), "Library/Fonts")
+ };
+
+ foreach (string fontPath in fontPaths)
+ {
+ if (Directory.Exists (fontPath))
+ {
+ foreach (string fontFile in Directory.GetFiles (fontPath, "*.ttf", SearchOption.AllDirectories))
+ {
+ try
+ {
+ _fontCollection.Add (fontFile);
+ }
+ catch
+ {
+ // Ignore individual font loading errors
+ }
+ }
+ }
+ }
+ }
+
+ _systemFontsLoaded = true;
+ }
+ catch
+ {
+ // If we can't load system fonts, we'll just use the built-in SixLabors fonts
+ }
+ }
+
+ ///
+ /// Gets or sets the font family name to use for rendering. Default is "Arial".
+ /// If the font is not found, falls back to the default SixLabors font.
+ ///
+ public string FontFamily
+ {
+ get => _fontFamily;
+ set
+ {
+ if (_fontFamily != value)
+ {
+ _fontFamily = value;
+ UpdateFont ();
+ UpdateContentSize ();
+ SetNeedsLayout ();
+ SetNeedsDraw ();
+ }
+ }
+ }
+
+ private void UpdateFont ()
+ {
+ try
+ {
+ FontFamily family;
+
+ if (_fontCollection.TryGet (_fontFamily, out family!))
+ {
+ _font = family.CreateFont (_glyphHeight, FontStyle.Regular);
+ }
+ else
+ {
+ // Fallback to system default
+ family = SystemFonts.Get (_fontFamily);
+ _font = family.CreateFont (_glyphHeight, FontStyle.Regular);
+ }
+ }
+ catch
+ {
+ // If font not found, use system default
+ try
+ {
+ FontFamily family = SystemFonts.Families.First ();
+ _font = family.CreateFont (_glyphHeight, FontStyle.Regular);
+ }
+ catch
+ {
+ // Last resort - null font will cause fallback rendering
+ _font = null;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the height of each glyph in terminal cells. Default is 8.
+ ///
+ ///
+ /// This controls how tall the rendered characters will be. Larger values create
+ /// taller letters but require more vertical space.
+ ///
+ public int GlyphHeight
+ {
+ get => _glyphHeight;
+ set
+ {
+ if (_glyphHeight != value)
+ {
+ _glyphHeight = value;
+ UpdateFont ();
+ UpdateContentSize ();
+ SetNeedsLayout ();
+ SetNeedsDraw ();
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the used to draw the text. Default is .
+ ///
+ public LineStyle Style
+ {
+ get => _style;
+ set
+ {
+ if (_style != value)
+ {
+ _style = value;
+ SetNeedsDraw ();
+ }
+ }
+ }
+
+ ///
+ protected override bool OnDrawingContent (DrawContext? context)
+ {
+ if (string.IsNullOrEmpty (Text))
+ {
+ return true;
+ }
+
+ // Render directly to a dictionary of filled cells
+ var filledCells = new Dictionary ();
+ DrawText (filledCells, Text, 0, 0, _font);
+
+ // Render the filled cells
+ foreach (KeyValuePair kvp in filledCells)
+ {
+ // Check if position is within viewport
+ if (kvp.Key.X < 0 || kvp.Key.X >= Viewport.Width || kvp.Key.Y < 0 || kvp.Key.Y >= Viewport.Height)
+ {
+ continue;
+ }
+
+ Move (kvp.Key.X, kvp.Key.Y);
+ AddStr ("?"); // Full block character
+ }
+
+ return true;
+ }
+
+ ///
+ public override string Text
+ {
+ get => base.Text;
+ set
+ {
+ base.Text = value;
+ UpdateContentSize ();
+ SetNeedsLayout ();
+ }
+ }
+
+ private void UpdateContentSize ()
+ {
+ // Calculate the size needed for the text
+ if (!string.IsNullOrEmpty (Text))
+ {
+ Size size = MeasureText (Text, _font);
+ SetContentSize (size);
+ }
+ else
+ {
+ SetContentSize (new Size (0, 0));
+ }
+ }
+
+ ///
+ /// Draws text as filled glyphs at the specified position.
+ ///
+ /// Dictionary to store which cells should be filled.
+ /// The text to draw.
+ /// Starting X position.
+ /// Starting Y position.
+ /// The font to use for rendering.
+ private static void DrawText (Dictionary filledCells, string text, int x, int y, Font? font)
+ {
+ if (font is null || string.IsNullOrEmpty (text))
+ {
+ return;
+ }
+
+ var glyphRenderer = new FilledGlyphRenderer (filledCells);
+ var renderer = new TextRenderer (glyphRenderer);
+
+ var options = new TextOptions (font)
+ {
+ Origin = new (x, y),
+ Dpi = 96
+ };
+
+ renderer.RenderText (text, options);
+ }
+
+ ///
+ /// Measures the size required to render the given text.
+ ///
+ /// The text to measure.
+ /// The font to use for measuring.
+ /// The size in terminal cells.
+ private static Size MeasureText (string text, Font? font)
+ {
+ if (string.IsNullOrEmpty (text) || font is null)
+ {
+ return Size.Empty;
+ }
+
+ try
+ {
+ FontRectangle bounds = TextMeasurer.MeasureBounds (text, new (font));
+
+ // Convert font units to terminal cells
+ // We scale based on the font size
+ var width = (int)Math.Ceiling (bounds.Width / font.Size * font.Size);
+ var height = (int)Math.Ceiling (bounds.Height / font.Size * font.Size);
+
+ return new (width, height);
+ }
+ catch
+ {
+ // Fallback if measurement fails
+ return new ((int)(text.Length * (font?.Size ?? 8)), (int)(font?.Size ?? 8));
+ }
+ }
+
+ ///
+ /// A custom glyph renderer that fills font glyph outlines with solid blocks.
+ ///
+ private class FilledGlyphRenderer : IGlyphRenderer
+ {
+ private readonly Dictionary _filledCells;
+ private Vector2 _currentPoint;
+ private readonly List _currentPath = new ();
+ private readonly int _samplesPerSegment = 10; // Number of line segments to approximate curves
+
+ public FilledGlyphRenderer (Dictionary filledCells)
+ {
+ _filledCells = filledCells;
+ }
+
+ public bool BeginGlyph (in FontRectangle bounds, in GlyphRendererParameters parameters)
+ {
+ _currentPath.Clear ();
+
+ return true;
+ }
+
+ public void BeginFigure () { _currentPath.Clear (); }
+
+ public void MoveTo (Vector2 point)
+ {
+ _currentPoint = point;
+
+ if (_currentPath.Count > 0)
+ {
+ // Start a new path segment
+ ProcessPath ();
+ _currentPath.Clear ();
+ }
+
+ _currentPath.Add (point);
+ }
+
+ public void LineTo (Vector2 point)
+ {
+ _currentPath.Add (point);
+ _currentPoint = point;
+ }
+
+ public void QuadraticBezierTo (Vector2 control, Vector2 end)
+ {
+ // Approximate quadratic Bezier with line segments
+ Vector2 start = _currentPoint;
+
+ for (var i = 1; i <= _samplesPerSegment; i++)
+ {
+ float t = i / (float)_samplesPerSegment;
+ float t1 = 1 - t;
+
+ // Quadratic Bezier formula: B(t) = (1-t)²P? + 2(1-t)tP? + t²P?
+ Vector2 point = t1 * t1 * start + 2 * t1 * t * control + t * t * end;
+ _currentPath.Add (point);
+ }
+
+ _currentPoint = end;
+ }
+
+ public void CubicBezierTo (Vector2 control1, Vector2 control2, Vector2 end)
+ {
+ // Approximate cubic Bezier with line segments
+ Vector2 start = _currentPoint;
+
+ for (var i = 1; i <= _samplesPerSegment; i++)
+ {
+ float t = i / (float)_samplesPerSegment;
+ float t1 = 1 - t;
+
+ // Cubic Bezier formula: B(t) = (1-t)³P? + 3(1-t)²tP? + 3(1-t)t²P? + t³P?
+ Vector2 point = t1 * t1 * t1 * start
+ + 3 * t1 * t1 * t * control1
+ + 3 * t1 * t * t * control2
+ + t * t * t * end;
+ _currentPath.Add (point);
+ }
+
+ _currentPoint = end;
+ }
+
+ public void EndFigure () { ProcessPath (); }
+
+ public void EndGlyph ()
+ {
+ // Glyph rendering complete
+ }
+
+ private void ProcessPath ()
+ {
+ if (_currentPath.Count < 3)
+ {
+ return;
+ }
+
+ // Find the bounding box of the path
+ float minY = float.MaxValue;
+ float maxY = float.MinValue;
+
+ foreach (Vector2 point in _currentPath)
+ {
+ minY = Math.Min (minY, point.Y);
+ maxY = Math.Max (maxY, point.Y);
+ }
+
+ var startRow = (int)Math.Floor (minY);
+ var endRow = (int)Math.Ceiling (maxY);
+
+ // For each row (scanline), find where the path outline intersects
+ // and fill the cells between intersection pairs
+ for (int row = startRow; row <= endRow; row++)
+ {
+ var intersections = new List ();
+
+ // Check each edge of the path polygon
+ for (var i = 0; i < _currentPath.Count; i++)
+ {
+ Vector2 p1 = _currentPath [i];
+ Vector2 p2 = _currentPath [(i + 1) % _currentPath.Count];
+
+ float y1 = p1.Y;
+ float y2 = p2.Y;
+
+ // Check if this edge crosses the current scanline
+ if ((y1 < row && y2 >= row) || (y2 < row && y1 >= row))
+ {
+ // Calculate x coordinate where edge intersects this row
+ if (Math.Abs (y2 - y1) < 0.001f)
+ {
+ // Horizontal edge at this row
+ intersections.Add (p1.X);
+ intersections.Add (p2.X);
+ }
+ else
+ {
+ // Interpolate to find x
+ float t = (row - y1) / (y2 - y1);
+ float x = p1.X + t * (p2.X - p1.X);
+ intersections.Add (x);
+ }
+ }
+ }
+
+ // Sort intersections and fill cells between pairs
+ if (intersections.Count >= 2)
+ {
+ intersections.Sort ();
+
+ // Fill cells between pairs of intersections
+ for (var i = 0; i < intersections.Count - 1; i += 2)
+ {
+ var x1 = (int)Math.Round (intersections [i]);
+ var x2 = (int)Math.Round (intersections [i + 1]);
+
+ // Fill all cells in this horizontal span
+ for (int x = x1; x <= x2; x++)
+ {
+ _filledCells [new Point (x, row)] = true;
+ }
+ }
+ }
+ }
+ }
+
+ public void SetColor (GlyphColor color)
+ {
+ // Not used for terminal rendering
+ }
+
+ public void EndText ()
+ {
+ // All text rendering complete
+ }
+
+ public void BeginText (in FontRectangle bounds)
+ {
+ // Starting text rendering
+ }
+
+ public TextDecorations EnabledDecorations ()
+ {
+ // We don't support text decorations like underline, strikethrough, etc.
+ return TextDecorations.None;
+ }
+
+ public void SetDecoration (TextDecorations textDecorations, Vector2 start, Vector2 end, float thickness)
+ {
+ // Not needed for terminal rendering - we don't support decorations
+ }
+ }
+
+ ///
+ /// Gets the width of a glyph at the specified height.
+ ///
+ private static int GetGlyphWidth (char c, int height)
+ {
+ // Normalize to lowercase for consistent sizing
+ char normalized = char.ToLowerInvariant (c);
+
+ return normalized switch
+ {
+ ' ' => height / 2,
+ 'i' or 'l' or '!' or '|' => Math.Max (2, height / 4),
+ 't' or 'f' or 'j' => Math.Max (3, height / 3),
+ 'm' or 'w' => Math.Max (5, height * 5 / 8),
+ _ => Math.Max (4, height / 2)
+ };
+ }
+}
diff --git a/Examples/UICatalog/Scenarios/BigText/BigTextExample.cs b/Examples/UICatalog/Scenarios/BigText/BigTextExample.cs
new file mode 100644
index 0000000000..5ad19f697a
--- /dev/null
+++ b/Examples/UICatalog/Scenarios/BigText/BigTextExample.cs
@@ -0,0 +1,62 @@
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("BigText", "Demonstrates the BigText view for large text rendering.")]
+[ScenarioCategory ("Controls")]
+[ScenarioCategory ("Drawing")]
+public class BigTextExample : Scenario
+{
+ public override void Main ()
+ {
+ Application.Init ();
+
+ Window app = new () { Title = GetQuitKeyAndName () };
+
+ Label inputLabel = new () { Text = "Enter text to render:" };
+ app.Add (inputLabel);
+
+ TextField textField = new ()
+ {
+ X = Pos.Right (inputLabel) + 1,
+ Y = Pos.Top (inputLabel),
+ Width = 40,
+ Text = "Hello World!"
+ };
+ app.Add (textField);
+
+ Button renderButton = new ()
+ {
+ X = Pos.Right (textField) + 1,
+ Y = Pos.Top (inputLabel),
+ Text = "Render"
+ };
+ app.Add (renderButton);
+
+ BigText dynamicText = new ()
+ {
+ X = 0,
+ Y = Pos.Bottom (textField) + 1,
+ Text = textField.Text,
+ GlyphHeight = 8,
+ Style = LineStyle.Single
+ };
+ app.Add (dynamicText);
+
+ renderButton.Accepting += (s, e) =>
+ {
+ dynamicText.Text = textField.Text;
+ e.Handled = true;
+ };
+
+ Label helpLabel = new ()
+ {
+ X = Pos.Center (),
+ Y = Pos.AnchorEnd (),
+ Text = "BigText uses TTF fonts rendered as LineCanvas box-drawing characters."
+ };
+ app.Add (helpLabel);
+
+ Application.Run (app);
+ app.Dispose ();
+ Application.Shutdown ();
+ }
+}
diff --git a/Examples/UICatalog/UICatalog.csproj b/Examples/UICatalog/UICatalog.csproj
index 88e916f9cf..b0e2821ee0 100644
--- a/Examples/UICatalog/UICatalog.csproj
+++ b/Examples/UICatalog/UICatalog.csproj
@@ -33,6 +33,7 @@
+