Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Quill/llms.txt
Use this file to discover all available pages before exploring further.
Every stroked path in Prowl.Quill reads from a mutable state object that you configure before calling Stroke() or FillAndStroke(). State is inherited until you explicitly change it, so you only need to set what is different from the previous shape. Use SaveState() / RestoreState() to scope style changes to a block of draw calls without having to manually restore each field.
Color and Width
SetStrokeColor
Sets the color applied to all stroked paths until changed.
void SetStrokeColor(Color32 color)
canvas.SetStrokeColor(Color32.FromArgb(255, 255, 255, 255)); // Opaque white
canvas.SetStrokeColor(Color32.FromArgb(128, 255, 80, 80)); // Semi-transparent red
SetStrokeWidth
Sets the stroke width in logical units. The default is 2. Values below 1 produce hair-thin lines; values above 20 produce thick bands.
void SetStrokeWidth(float width = 2f)
SetStrokeScale
Multiplies the effective stroke width and dash lengths by a scale factor. This is useful when the canvas transform includes a zoom level — setting the stroke scale to the inverse zoom keeps lines visually constant-width.
void SetStrokeScale(float scale)
float zoom = 2.0f;
canvas.TransformBy(Transform2D.CreateScale(zoom, zoom));
canvas.SetStrokeScale(zoom); // Compensate so strokes stay 1 logical unit wide
Joint Styles
SetStrokeJoint
Controls how corners are drawn where two line segments meet. The JointStyle enum has three values:
void SetStrokeJoint(JointStyle joint)
The two segment ends are capped with a flat edge and connected by a filled triangle. This is the default — it is the cheapest to tessellate and avoids the spike problem of miter joins at sharp angles.canvas.SetStrokeJoint(JointStyle.Bevel);
canvas.SetStrokeColor(Color32.FromArgb(255, 255, 100, 100));
canvas.SetStrokeWidth(8f);
canvas.BeginPath();
canvas.MoveTo(20, 80);
canvas.LineTo(80, 20);
canvas.LineTo(140, 80);
canvas.Stroke();
The outer edges of the two segments are extended until they meet at a sharp point. Can produce very long spikes at acute angles. Use SetMiterLimit to control the fallback behaviour.canvas.SetStrokeJoint(JointStyle.Miter);
canvas.SetMiterLimit(4f); // Fall back to bevel when spike would exceed 4× width
canvas.SetStrokeColor(Color32.FromArgb(255, 100, 100, 255));
canvas.SetStrokeWidth(8f);
canvas.BeginPath();
canvas.MoveTo(20, 80);
canvas.LineTo(80, 20);
canvas.LineTo(140, 80);
canvas.Stroke();
A circular arc is added at the joint, centred on the meeting point. Produces the smoothest appearance but uses the most geometry. Ideal for organic or hand-drawn aesthetics.canvas.SetStrokeJoint(JointStyle.Round);
canvas.SetStrokeColor(Color32.FromArgb(255, 100, 255, 100));
canvas.SetStrokeWidth(8f);
canvas.BeginPath();
canvas.MoveTo(20, 80);
canvas.LineTo(80, 20);
canvas.LineTo(140, 80);
canvas.Stroke();
Cap Styles
Caps are applied to the open ends of a path (i.e., paths where the first and last points do not meet). You can set both caps at once with SetStrokeCap, or set start and end independently.
void SetStrokeCap(EndCapStyle cap) // Sets both start and end caps
void SetStrokeStartCap(EndCapStyle cap) // Start of the path only
void SetStrokeEndCap(EndCapStyle cap) // End of the path only
The stroke ends exactly at the first and last path points with no extension. This is the default and produces the tightest bounding box.canvas.SetStrokeCap(EndCapStyle.Butt);
canvas.SetStrokeColor(Color32.FromArgb(255, 255, 100, 100));
canvas.SetStrokeWidth(16f);
canvas.BeginPath();
canvas.MoveTo(30, 60);
canvas.LineTo(170, 60);
canvas.Stroke();
Extends the stroke by half the stroke width beyond both endpoints, producing a square cap. The path visually appears longer than with Butt.canvas.SetStrokeCap(EndCapStyle.Square);
canvas.SetStrokeColor(Color32.FromArgb(255, 255, 180, 100));
canvas.SetStrokeWidth(16f);
canvas.BeginPath();
canvas.MoveTo(30, 60);
canvas.LineTo(170, 60);
canvas.Stroke();
Adds a semicircular cap centred on the endpoint, extending half the stroke width beyond the path. Produces soft, pill-shaped line ends.canvas.SetStrokeCap(EndCapStyle.Round);
canvas.SetStrokeColor(Color32.FromArgb(255, 100, 255, 100));
canvas.SetStrokeWidth(16f);
canvas.BeginPath();
canvas.MoveTo(30, 60);
canvas.LineTo(170, 60);
canvas.Stroke();
Closes the cap with a diagonal chamfer, giving a wedge appearance. Rarely used on straight paths but can create interesting arrow-head-like endings.canvas.SetStrokeCap(EndCapStyle.Bevel);
canvas.SetStrokeColor(Color32.FromArgb(255, 100, 180, 255));
canvas.SetStrokeWidth(16f);
canvas.BeginPath();
canvas.MoveTo(30, 60);
canvas.LineTo(170, 60);
canvas.Stroke();
Mixed caps example
// Arrow-like: flat start, round tip
canvas.SetStrokeStartCap(EndCapStyle.Butt);
canvas.SetStrokeEndCap(EndCapStyle.Round);
canvas.SetStrokeWidth(12f);
canvas.SetStrokeColor(Color32.FromArgb(255, 255, 255, 150));
canvas.BeginPath();
canvas.MoveTo(20, 80);
canvas.LineTo(200, 80);
canvas.Stroke();
Miter Limit
SetMiterLimit
When the joint style is Miter, this value caps how far the miter spike can extend before the joint automatically falls back to Bevel. The limit is expressed as a ratio of the miter length to the stroke width. The default is 4.
void SetMiterLimit(float limit = 4)
// Very sharp angles allowed — use with care
canvas.SetStrokeJoint(JointStyle.Miter);
canvas.SetMiterLimit(10f);
// Conservative — falls back to bevel at moderate angles
canvas.SetMiterLimit(2f);
Tessellation and Rounding
SetTessellationTolerance
Controls the maximum allowed deviation (in logical units) when flattening Bézier curves and arcs into line segments. Lower values produce smoother curves with more triangles. Default is 0.5.
void SetTessellationTolerance(float tolerance = 0.5f)
SetRoundingMinDistance
Sets the minimum distance between consecutive arc sample points. This bounds the maximum segment count for very large arcs or circles. Default is 3 logical units.
void SetRoundingMinDistance(float distance = 3)
Dash Patterns
SetStrokeDash
Activates a dash pattern on all subsequent strokes. The pattern list alternates between dash length and gap length in logical units (e.g., [10, 5] = 10-unit dash, 5-unit gap). If the list has an odd number of elements it is automatically doubled so the pattern can tile evenly. The optional offset shifts the phase along the path.
void SetStrokeDash(List<float> pattern, float offset = 0.0f)
// Simple equal dashes and gaps
canvas.SetStrokeDash(new List<float> { 10, 5 });
// Long-short-long pattern
canvas.SetStrokeDash(new List<float> { 20, 5, 5, 5 });
// Animated marching ants (increment offset each frame)
canvas.SetStrokeDash(new List<float> { 8, 4 }, offset: _time * 20f);
ClearStrokeDash
Reverts to a solid stroke.
Global Alpha
SetGlobalAlpha
Applies a uniform transparency multiplier to all subsequent vertices, including fills and strokes. Values range from 0 (fully transparent) to 1 (fully opaque, the default).
void SetGlobalAlpha(float alpha)
// Fade out an entire group of shapes
canvas.SetGlobalAlpha(0.4f);
canvas.RectFilled(10, 10, 100, 60, Color32.FromArgb(255, 255, 100, 100));
canvas.CircleFilled(80, 80, 30, Color32.FromArgb(255, 100, 200, 255));
canvas.SetGlobalAlpha(1.0f); // Restore full opacity
SetGlobalAlpha multiplies the vertex alpha at the point of insertion. This is different from a blend-mode layer — it does not compose the group first. For composited group transparency, use SaveState() / RestoreState() together with a semi-transparent fill.
Putting It All Together
// Heartbeat-style animated polyline with round joins and caps
canvas.SaveState();
canvas.SetStrokeColor(Color32.FromArgb(255, 80, 220, 120));
canvas.SetStrokeWidth(5f);
canvas.SetStrokeJoint(JointStyle.Round);
canvas.SetStrokeCap(EndCapStyle.Round);
canvas.SetMiterLimit(4f);
canvas.BeginPath();
canvas.MoveTo(10, 60);
canvas.LineTo(40, 60);
canvas.LineTo(60, 10); // Spike up
canvas.LineTo(80, 110); // Spike down
canvas.LineTo(100, 60);
canvas.LineTo(190, 60);
canvas.Stroke();
// Dashed reference line
canvas.SetStrokeColor(Color32.FromArgb(80, 255, 255, 255));
canvas.SetStrokeWidth(1f);
canvas.SetStrokeDash(new List<float> { 6, 4 });
canvas.BeginPath();
canvas.MoveTo(10, 60);
canvas.LineTo(190, 60);
canvas.Stroke();
canvas.RestoreState();