AOTLogoSharp.Drawing
1.3.1
dotnet add package AOTLogoSharp.Drawing --version 1.3.1
NuGet\Install-Package AOTLogoSharp.Drawing -Version 1.3.1
<PackageReference Include="AOTLogoSharp.Drawing" Version="1.3.1" />
<PackageVersion Include="AOTLogoSharp.Drawing" Version="1.3.1" />
<PackageReference Include="AOTLogoSharp.Drawing" />
paket add AOTLogoSharp.Drawing --version 1.3.1
#r "nuget: AOTLogoSharp.Drawing, 1.3.1"
#:package AOTLogoSharp.Drawing@1.3.1
#addin nuget:?package=AOTLogoSharp.Drawing&version=1.3.1
#tool nuget:?package=AOTLogoSharp.Drawing&version=1.3.1
AOTLogoSharp
Logo programming language for managed world.
What's Logo?
Logo is a programming language that controls a turtle on the screen to draw amazing pictures, like below:

More beautiful pictures drawn by AOTLogoSharp:
Box Picture

Beautiful Flower

Square Flower

Web

Logo is widely used in computer education for kids, as it is simple and interesting. AOTLogoSharp is a .NET implementation of the Logo programming language which is based on a hand-written recursive descent parser.
Why AOTLogoSharp?
AOTLogoSharp is fully compatible with Native AOT and trimming. You can publish your application as a single native executable with minimal size and fast startup, without any JIT overhead. This makes it ideal for scenarios where deployment size and startup speed matter, such as command-line tools, educational apps, or embedded drawing pipelines.
The assembly names remain LogoSharp.dll and LogoSharp.Drawing.dll, and the namespace stays as LogoSharp / LogoSharp.Drawing, so existing code that references the original LogoSharp can migrate by simply swapping the NuGet package.
How to use AOTLogoSharp?
It is very simple and straightforward to use AOTLogoSharp in your .NET projects that is either based on .NET Framework 4.8, .NET Standard 2.0, or .NET 10. This means that you can make your AOTLogoSharp app working with .NET Core and thereby provides the cross-platform capability.
- Install AOTLogoSharp NuGet Package, for example:
Install-Package AOTLogoSharp -Version 1.3.1
- Write your first app:
using LogoSharp;
static void Main(string[] args)
{
var logo = new Logo();
logo.Forward += (s, e)
=> Console.WriteLine($"Forwarded {e.Steps} steps.");
logo.Execute("FD 102");
}
- Run your app, you should get the message
Forwarded 102 steps.on your console
Basically, a Logo program code is provided to the Execute method of the logo instance, AOTLogoSharp will execute the code and emit the events. Therefore, event handlers that subscribe to a particular event will be hit once the execution of the code emits the subscribed event.
The Logo class exposes the HeadingMode property to control the semantics of SETH / SETHEADING:
"logo"(default): 0° = north, clockwise. This matches the standard Logo language specification."standard": 0° = east, counter-clockwise. This matches the mathematical polar coordinate convention.
var logo = new Logo();
logo.HeadingMode = "standard"; // switch to mathematical heading semantics
logo.Execute("SETH 0"); // now points east instead of north
The Logo class also exposes the WaitMode property to control the unit of the WAIT command:
"logo"(default): 1 tick = 1/60 second (~16.67 ms), following traditional Logo specifications."ms"/"standard": 1 tick = 1 millisecond.
var logo = new Logo();
logo.WaitMode = "logo"; // WAIT 1 ≈ 16.67 ms
logo.Execute("WAIT 60"); // waits ~1 second
PRINT Command and Print Event
AOTLogoSharp supports the PRINT command, which has three forms:
PRINT "text— output a string literal (everything after"up to the next whitespace).PRINT 42— output a numeric value.PRINT [word1 word2 ...]— output a list literal as a space-separated sentence.
Each PRINT invocation fires the Print event, which is exposed as EventHandler<PrintEventArgs>. The Text property carries the rendered text. String literal contents preserve the user's original casing, so PRINT "Hello outputs Hello exactly as written, even though keywords such as PRINT are matched case-insensitively.
using LogoSharp;
var logo = new Logo();
logo.Print += (s, e) => Console.WriteLine($"[print] {e.Text}");
logo.Execute(@"
PRINT [Test OK]
PRINT ""Hello World
PRINT 3.14
");
Error Reporting
Runtime errors (for example, calling an undefined procedure) are reported with a precise [line:column] location in the source program. When multiple errors occur in a single Execute call, the engine aggregates them into a single RuntimeException whose Message contains every error on its own line, so a host UI can display each error as a separate list item.
STOP Command and Recursion/Loop Limits
STOP is a built-in keyword that immediately exits the innermost running procedure. It does not fire any event — instead it throws an internal StopException that the procedure dispatcher swallows, so a host UI does not see a crash. STOP outside any procedure has no effect (the exception escapes without anything to catch it and is rethrown as a normal RuntimeException).
The engine guards against runaway Logo programs with two public properties on Logo:
MaxRepeatIterations(default10000) — caps the count of a singleREPEATand the per-step iterations of aWHILEloop. Exceeding it throwsRuntimeExceptionwith aStackOverflowExceptionprefix.MaxCallStackDepth(default500) — caps the recursion depth of user-defined procedure calls.
var logo = new Logo
{
MaxRepeatIterations = 1000000, // allow long-running drawings
MaxCallStackDepth = 2000 // allow deeper recursion
};
logo.Execute("REPEAT 1000000 [FD 1]");
For an additional process-level safety net, the static LogoSharp.MemoryGuard helper watches the process's private memory and exits the process as soon as it crosses a threshold. This catches scenarios that pure language-level limits cannot (e.g. runaway AST growth from pathological input):
using LogoSharp;
// Start a 1 GiB watchdog (defaults: 1024 MB threshold, 1000 ms check interval).
MemoryGuard.Start(thresholdMB: 1024, checkIntervalMs: 1000);
// ... run Logo code ...
MemoryGuard.Stop();
For more information about how to use AOTLogoSharp, please refer to the LogoSharp.Drawing project.
Using AOTLogoSharp.Drawing
AOTLogoSharp.Drawing provides a Turtle class that renders Logo programs to images. It is also available as the AOTLogoSharp.Drawing NuGet package.
- Install AOTLogoSharp.Drawing NuGet Package, for example:
Install-Package AOTLogoSharp.Drawing -Version 1.3.1
- Write your first app:
using LogoSharp;
using LogoSharp.Drawing;
using SkiaSharp;
static void Main(string[] args)
{
var turtle = new Turtle();
var logo = new Logo();
// Wire Logo events to the Turtle
logo.TurnLeft += (s, e) => turtle.Left(e.Angle);
logo.TurnRight += (s, e) => turtle.Right(e.Angle);
logo.SetHeading += (s, e) => turtle.Angle = e.Angle;
logo.Forward += (s, e) => turtle.MoveForward(e.Steps);
logo.Backward += (s, e) => turtle.MoveBackward(e.Steps);
logo.PenUp += (s, e) => turtle.PenStatus = PenStatus.Up;
logo.PenDown += (s, e) => turtle.PenStatus = PenStatus.Down;
logo.SetPenColor += (s, e) =>
{
turtle.SetPenColor(e.R, e.G, e.B);
var color = Color.FromRgb(
(byte)Math.Clamp(e.R, 0, 255),
(byte)Math.Clamp(e.G, 0, 255),
(byte)Math.Clamp(e.B, 0, 255));
// 关键:UI 操作必须在 UI 线程执行
Dispatcher.UIThread.Invoke(() =>
{
PenColor = new SolidColorBrush(color);
StrokeColor = color;
});
};
logo.SetPenSize += (s, e) => turtle.SetPenWidth(e.Width);
logo.Delay += (s, e) => turtle.DelayMilliseconds = e.Milliseconds;
logo.Wait += (s, e) =>
{
// SETWAIT 会改 logo.WaitMode;先同步到 turtle,再触发一次性延时。
turtle.WaitMode = logo.WaitMode;
turtle.WaitOneShot(e.Ticks);
};
logo.ClearScreen += (s, e) => turtle.Clear();
logo.GoHome += (s, e) => turtle.Reset();
logo.ShowTurtle += (s, e) => turtle.ShowTurtle();
logo.HideTurtle += (s, e) => turtle.HideTurtle();
logo.PenErase += (s, e) => turtle.PenErase();
logo.PenNormal += (s, e) => turtle.PenNormal();
logo.SetX += (s, e) => turtle.SetX(e.X);
logo.SetY += (s, e) => turtle.SetY(e.Y);
logo.SetXY += (s, e) => turtle.SetXY(e.X, e.Y);
logo.Execute(@"
REPEAT 4 [
FD 100
RT 90
]
");
turtle.Save("output.png");
}
The Turtle class exposes the following APIs:
SetCanvasSize(int width, int height)- set the canvas sizeShowTurtle()/HideTurtle()- toggle turtle visibilitySave(string fileName)- save the rendered image to a fileGetLineSegments()- get the list of drawn line segments for custom renderingGetTurtleState()- get the current turtle position, angle, and visibilityDelayMilliseconds- control the delay between drawing steps. The delay only applies to drawing operations (PENDOWN / PENERASE). Non-drawing moves (e.g.SetX/SetY/SetXY/MoveForwardwhile PENUP) are instantaneous, so repositioning the turtle with the pen up does not stall the program.Delay behavior:
0ms: instantaneous drawing, no sleep overhead.1–19ms: batches multiple segments into a single sleep to amortize OS scheduling overhead. For example, at 1 ms delay, 20 segments are drawn before a single 20 ms sleep; at 10 ms, 2 segments before a 20 ms sleep.20ms or higher: one segment per sleep, matching the requested delay exactly.
On Windows 10 (1803+) and above, .NET 10.0/.NET Framework 4.8, delays use QuickTickLib for high-precision timing via IO Completion Ports. On older Windows versions or unsupported platforms, it falls back to
Thread.Sleep.
Key Features
AOTLogoSharp provides the following commands and features:
- Basic Pen Commands
- PENDOWN/PD
- PENUP/PU
- SETPENCOLOR/SETPC/PC
- SETPENSIZE
- PENERASE/PE
- PENNORMAL/PN
- Basic Drawing Commands
- LEFT/LT (anticlockwise)
- RIGHT/RT (clockwise)
- FORWARD/FD
- BACKWARD/BK/BACK
- DRAW/CLS/CLEARSCR/CLEARSCREEN/CS
- Turtle Control Commands
- HOME
- SHOWTURTLE/ST
- HIDETURTLE/HT
- SETX/SETY/SETXY
- SETH/SETHEADING (Logo semantics: 0° = north, clockwise; set
logo.HeadingMode = "standard"for 0° = east, counter-clockwise)
- Flow Control Commands
- REPEAT and RepCount
- IF / IFELSE
- WHILE
- DELAY
- WAIT
- PRINT (string literal, number, or list literal; fires the
Printevent) - STOP (exits the innermost running procedure)
- OUTPUT/OP/RETURN
- Language Features
- Variables (The MAKE command)
- Expressions
- Arithmetic:
+,-,*,/,^ - Comparison:
==,<>,<,>,<=,>= - Logic: AND, OR, NOT
- Arithmetic:
- Procedures
- Function Calls
- SQRT
- RANDOM
- SIN / COS / TAN (degrees)
- ASIN / ACOS / ATAN (degrees), aliases: ARCSIN / ARCCOS / ARCTAN
- ABS
- POWER
- EXP
- LOG (natural) / LOG10, alias: LN
- Inline Comments
- Built-in Constants
- PI
- E
Limitations
- Code editing doesn't support multi-line format
- Logo commands other than the ones listed above are not supported. More will be added in future
- Function calls need to be surrounded by the braces, for example, {SQRT 2} or {RANDOM 100}
PRINT "textreads the literal up to the next whitespace or delimiter (parenthesis / bracket). To include spaces inside the printed text, use a list literal:PRINT [Hello World]- Quoted identifiers (
"name) and variable/keyword matching are both case-insensitive, but the text inside aPRINT "textliteral is preserved verbatim in its original casing.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.8
- AOTLogoSharp (>= 1.3.1)
- NetTopologySuite (>= 2.6.0)
- NetTopologySuite.Features (>= 2.2.0)
- QuickTickLib (>= 2.3.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
-
.NETStandard 2.0
- AOTLogoSharp (>= 1.3.1)
- NetTopologySuite (>= 2.6.0)
- NetTopologySuite.Features (>= 2.2.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
-
net10.0
- AOTLogoSharp (>= 1.3.1)
- NetTopologySuite (>= 2.6.0)
- NetTopologySuite.Features (>= 2.2.0)
- QuickTickLib (>= 2.3.0)
- SkiaSharp (>= 3.119.4)
- SkiaSharp.NativeAssets.Linux (>= 3.119.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.