artc language
...seeks to be a moderately good option for expressing some forms of art concisely and precisely.
What is it?
It's a function, which deterministically evaluates/renders...
  ...from:            to any one of these formats:
┌───────────────┐      ⎧ .usdz files of 3D objects / scenes / animations,⎫
│               │      ⎪                                                 ⎪
│  .artc code   │ -->  ⎨ .json files of 2D Canvas drawing operations,    ⎬
│               │      ⎪                                                 ⎪
│ (Python fork) │      ⎩ .mid  files of MIDI                             ⎭
└───────────────┘
       ⎧ language for,  ⎫    ⎧ OpenUSD,                  ⎫
       ⎪                ⎪    ⎪                           ⎪
It's a ⎨ library for,   ⎬ ── ⎨ CanvasRenderingContext2D, ⎬
       ⎪                ⎪    ⎪                           ⎪
       ⎪ intro to,      ⎪    ⎪ MIDI,                     ⎪
       ⎪                ⎪    ⎪                           ⎪
       ⎩ celebration of ⎭    ⎩ some basic physics        ⎭
It does NOT involve generative AI or seek to replace or automate artistic choices or subtleties.What's OpenUSD?
What's CanvasRenderingContext2D?
What's MIDI?
Why is it?
It's for:
- art
- diagrams
- { learning / teaching / exploring } stuff
It doesn't make new stuff possible,
but it tries to make some forms of already-possible stuff somewhat easier.
Binary encoding
       .artc code    <------->      binary-encoded
        (as text)                 form of .artc code
Questions
What works of art are we capable of expressing in at most 100 bytes of [additional] information?
If there's an information-storage bottleneck someday, how much art could losslessly survive?
Design goals
- Have the encoded hex be (somewhat) readable:
- Operate on syntax trees, not text- Note: this will normalize / autoformat your code
- Note: there's a .GapAST node for expressing additional blank lines
 
- Optimize for names and patterns specific to this language and standard library
 (vs plain text or Python in general).
- You should be able to simply (albeit tediously) decode it yourself, with pencil and paper
Examples
Example 1
B26B2 is a 2.5-byte encoding of the following:
    scene.aspect_ratio = "√2:1"
    scene.background = Gray(25%)
    scene.padding = 6%
Note: this is a common initial pattern for concise 2D works ("set aspect ratio, background, and a padding percentage beyond the bounding box of whatever shapes end up in the scene graph"), so the encoding optimizes for it.Full walk-through of this example
Background:
- Current state: there's a finite set of states, each of which has its own Huffman tree which maps input-nibble prefix code sequences to action bundles. Some states (like .end_sequence_b2_init) map the empty string to one specific action bundle and do nothing else.
- Input chunk: a full prefix code of one or more nibbles, which take us all the way from the root of this state's Huffman tree to one of its leaves
- Action bundle: a named list of actions
- State stack: like a to-do list, defining upcoming states. See also: Pushdown automaton
- Node stack: a temporary stack of AST nodes, to be used soon in upcoming action bundles
- Code: the AST that's been built so far. Its root is a .Modulenode.
| Current state | Input chunk | Action bundle for this (state, input) | 
|---|
| .initialPossible input
B→.use_draft_b | B(for "Draft B")
 | .use_draft_b:
 
 Result
State stack: [.b_initial]Node stack: []
 | 
| .b_initialPossible input
2→ 2D a;b;p
 3→ 3D mainelse : (reserved)
 | 2(for "2D with aspect / background / padding")
 | .start_sequence_b2_init:
 
 Set state stack to [.end_sequence_b2_init]Push state .get_aspect_ratioPush state .get_background_colorPush state .get_padding_percent
 Result
State stack: [.end_sequence_b2_init, .get_aspect_ratio, .get_background_color, .get_padding_percent]Node stack: []
 | 
| .get_padding_percentPossible input
0→ 0
 1→ 1%
 2→ 2%
 3→ 3%
 4→ 4%
 5→ 5%
 6→ 6%
 7→ 7%
 8→ 8%
 9→ 9%
 A→ 10%
 B→ 15%
 C→ 20%
 
 D*,E*, andF*are reserved. At least one of them will lead to additional nibbles. | 6 | .make_padding_percentwithvalue=6:
 
 Make temp node 6%(an AST node of type.Constantand subtype.ConstantQuantityPercent)
 Result
State stack: [.end_sequence_b2_init, .get_aspect_ratio, .get_background_color]Node stack: [6%]
 | 
| .get_background_colorPossible input
0→ Gray(0)
 1→ Gray(10%)
 2→ Gray(20%)
 3→ Gray(30%)
 4→ Gray(40%)
 5→ Gray(50%)
 6→ Gray(60%)
 7→ Gray(70%)
 8→ Gray(80%)
 9→ Gray(90%)
 A→ Gray(1)
 B→ Gray(25%)
 C→ Gray(75%)
 
 D*,E*, andF*are reserved. At least one of them will lead to additional nibbles and the ability to express RGB or HSL colors. | B | .make_gray_percentwithvalue=25:
 
 Make temp node Gray(25%)(node type.Call, containing a.Constant)
 Result
State stack: [.end_sequence_b2_init, .get_aspect_ratio]Node stack: [6%, Gray(25%)]
 | 
| .get_aspect_ratioPossible input
0→ "16:9"
 1→ '"3:2"'
 2→ '"√2:1"'
 4→ '"4:3"'
 5*, 6* : (reserved)
 
 7→ "1:1"8*, 9*, A*, B* : (reserved)
 
 
 C→ "3:4"
 D→ "1:√2"
 E→ "2:3"
 F→ "9:16" | 2 | .make_stringwith value = (index of "√2:1" in the list of string constants):
 
 Make temp node "√2:1"(a.Constantof subtype.ConstantStr)
 Result
State stack: [.end_sequence_b2_init]Node stack: [ 6%, Gray(25%), "√2:1" ]
 | 
| .end_sequence_b2_initPossible input
None. This state doesn't read any input.
 |  | .end_sequence_b2_init:
 
 Append node scene.aspect_ratio = 🍿(an
 .Assignnode, where🍿is whatever gets popped from the node stack)Append node scene.background = 🍿Append node scene.padding = 🍿Set state to .b2_main
 Result
State stack: [.b2_main]Node stack: []Code:
 scene.aspect_ratio = "√2:1"
scene.background = Gray(25%)
scene.padding = 6%
 |