2025-05-17 14:21:00
suberic.net
I wanted to make a programming language that resembled magical circles. This is more like a way to write PostScript that looks like a magical circle, but I will refer to it as Mystical in this document.
Rings
The structure of Mystical is based on rings. These are circular bands of text and sigils, with an inner and outer border. The content of the main ring of a program starts at the rightmost (3:00) point and flow continues widdershins (counter-clockwise) both to respect postscript’s angles and to reflect the assumption that these rings should be written from the outside. Subsidiary rings start from their attachment point to their caller.
There are three types of rings in Mystical:
- executable arrays, written in
{
}
in PostScript, are represented with simple circular borders on the inside and outside of the ring, with a star of some sort inside. The start/end point is marked by a symbol based on the “work complete” symbol from alchemy. - non-executable arrays, written in
[
]
in PostScript, are the same but without the star. The start/end point is marked with a simple triangle. - dictionaries, written in
>>
in PostScript, are polygons with a double outer border and a single inner border. The start/end point is marked the same as the array.
xarray | array | dict |
---|---|---|
![]() |
![]() |
![]() |
{ 0 0 currentlinewidth 1.5 mul 0 360 arc fill } |
[ 0 1 2 1.5 40 360 (Hooray World) ] |
> |
(Note that the entries in the dict image are in a different order than the PostScript text since dict insertion order is not preserved in PostScript.)
When one of these structures appear inside a different structure, a small circle or dot at the inclusion point is connected to a line which leads to the subsidiary ring’s start/end sigil.
[
0 1 2 1.5 40 360 >
]
It is theoretically possible to use [ ]
and >
in PostScript in ways that Mystical can’t handle:
[ 1 2 3 split { ] /first exch def [ } if 4 5 6 ] /final exch def
so don’t do that.
Other commands like gsave/grestore
and begin/end
are more likely to be used in non-balanced or loop-crossing ways so those are treated as normal sigils below.
Text and Sigils
The rings’ rims contain text or sigils. Sigils are symbols that stand in for operators, variables, or other keywords. Any name, written in PostScript as /name
, is instead written with a triangle surrounding or superimposing the text of the name or its sigil. Any strings, written in () in Postscript, are cartouche-like shapes containing the string text.
Standard Sigils
Many built-in operators have been given their own sigils. These are used in place of the text of the operator if it appears as a name or operator (but not if it appears as a string). I have generally made these sigils based on the initial of the command and an illustration of the concept, though in some cases I have taken a more fully illustrative route or created some standard visual language. Some examples are below – see Standard Sigils for a full list.
Sample sigils
User Sigils
Sigils for new functions or names can be added to sigil_bank
at runtime. They should fit into the 1-unit square centered on the origin, so no coordinate should be more than 0.5 (of course, you can transform your coordinate system for convenience). If you use nstroke
instead of stroke
you will get the same calligraphic effect as the standard sigils.
Sigils for user variables can be designed with any sigil system. My examples mostly use letter collision, inspired by Spare’s Chaos Magick system, but anything that turns a word into a symbol will work – kameas, wheels, Square Word Calligraphy, Circular Gallifreyan, sitelen sitelen, illustration, puns, etc. New names based on official operators can incorporate the standard sigils for those operators.
![]() |
![]() |
![]() |
![]() |
arg | dot | softscale | nstroke |
Ligature for /name { ring } def
There is a sigil for def
but a very common pattern is to push a name, push a function, and def the name to the function. To save space and to emphasize this definition, there is special syntax for this case consisting of the usual name triangle with the end of the link line directly below it, and the def sigil is omitted entirely. This is extended to the other two ring types for simplicity. Any other use of def
will just use the def sigil as normal.
![]() |
---|
{ ... /even { 2 mod 0 eq } def ... } |
This only applies inside of executable arrays. I considered a similar ligature for /name { ring } in dictionaries but there’s too much chance of getting it wrong.
Sample Algorithms
Quicksort is the illustration at the top of this page.
Euclid’s GCD algorithm (using my /arg {exch def} def
function from dmmlib):
Functions to generate Mystical images
All of these are defined in “mystical.ps”.
mystical
: takes an array, xarray, or dict and renders it in mystical, descending into substructures as necessary. The entire image will be scaled to fit into a unit circle.
mystical_evoke
: The same as mystical
but it takes a name that is looked up in the current dictionary.
mystical_evoke_label
: Like mystical_evoke
but adds a name-def ligature with the name at the top and orients the image so that the name sigil is right-side-up.
All of these have versions with _unscaled
appended to them that skip the scaling step. The rings will be 1 unit thick so the image will be quite large.
layout issues
Currently the code figures out the layout of the subcircles so that nothing collides, but it’s overly safe so most programs will be very spread out. For the examples on this page I ran the parsing/layout functions (mystical_get_spell
and mystical_make_evocation_ligature
) and then adjusted the results before calling the draw functions draw_sigil
and draw_link
. I’m intending to improve the default layout somewhat.
Is this a programming language?
At the moment it’s a way to draw a PostScript program – there’s no interpreter that will ingest a Mystical image and perform the appropriate computation. It could be run and interpreted by a human, or (more likely) a human could read it and turn it into a PostScript program and run that. I’ll leave further philosophical arguments to other people for now.
Could this work for other languages?
This approach seems applicable to other language with just operators, such as Forth. Languages with more complicated statements might be more difficult, and I don’t know if a new ring for every brace or indent will be overly busy.
This page generated 2025-05-16 by Denis.
Keep your files stored safely and securely with the SanDisk 2TB Extreme Portable SSD. With over 69,505 ratings and an impressive 4.6 out of 5 stars, this product has been purchased over 8K+ times in the past month. At only $129.99, this Amazon’s Choice product is a must-have for secure file storage.
Help keep private content private with the included password protection featuring 256-bit AES hardware encryption. Order now for just $129.99 on Amazon!
Help Power Techcratic’s Future – Scan To Support
If Techcratic’s content and insights have helped you, consider giving back by supporting the platform with crypto. Every contribution makes a difference, whether it’s for high-quality content, server maintenance, or future updates. Techcratic is constantly evolving, and your support helps drive that progress.
As a solo operator who wears all the hats, creating content, managing the tech, and running the site, your support allows me to stay focused on delivering valuable resources. Your support keeps everything running smoothly and enables me to continue creating the content you love. I’m deeply grateful for your support, it truly means the world to me! Thank you!
BITCOIN bc1qlszw7elx2qahjwvaryh0tkgg8y68enw30gpvge Scan the QR code with your crypto wallet app |
DOGECOIN D64GwvvYQxFXYyan3oQCrmWfidf6T3JpBA Scan the QR code with your crypto wallet app |
ETHEREUM 0xe9BC980DF3d985730dA827996B43E4A62CCBAA7a Scan the QR code with your crypto wallet app |
Please read the Privacy and Security Disclaimer on how Techcratic handles your support.
Disclaimer: As an Amazon Associate, Techcratic may earn from qualifying purchases.