Show HN: CFR[]: Very minimal drawing language with 5 commands: C, F, R, [, ]
susam.net
susam.net
My best rendition (would have been better if there was a counter clockwise rotation, improvements to my code are welcome!):
[[FFFFFFR[[CFFFFF]]][[[[[[[FF]]]]RR[[F[CC[RC[FFFFFF]]RFFFFF[RFFFFF][R[CFFFFFF]]]]]R[[[[FFFFFFFFFFFFFFFFFFFFF]]]]][[FFFFFFFFF]]]]
I made a pinwheel, which is maybe not that exciting, but was a lot of fun for me. I like the bracket syntax a lot, and figuring out how to make this work actually recaptures some of the old sense of exploration and fun that I felt before programming was my day job.
You're touching on an important point. I tried to figure out CFR[] by trial and error and it was a lot of fun, the kind of which I didn't feel for a long time. I think this boils down to two things: - Bounded complexity, which encourages you to explore it to its fullest - Immediate feedback, the result is not disconnected from the act of editing the code, so your iteration cycle is super short.
Congrats OP, amazing design work!
I made a space-filling curve:
[[[[[[[[[[[[[[[[FR]]FRR]]RRRRRRF]]FFFFFFFRR]]RRRRRRFFFFFFFFF]]FFFFFFFFFFFFFFFFFFFFFFFRR]]RRRRRRFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF]]FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFRR]]
It's not very interesting by itself (it just fills the whole screen with white) but you get cool-looking visualisations of its fractal-like structure by putting "C" at different points of the opening brackets.
For example:
C[[[RC[[[RC[[[CR[[[C[[C[C[FCR]]FRR]]RRRCRRRF]]FFFRFFFFRR]]RRRRCRRFFFFFFFFF]]FFFRFFFFFFFFFFFFFFFFFFFFRR]]RRRRRRFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF]]FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCFFFFFFFFFFCFFFFFFFFFFFFFFFFRR]]CC
]
[[[[[[[[[[[[[[[[F]]]]]]]]RRF[[R]R]]]]]]]]]
[[[[[[[[[[[[[[[FF]]]]]]]RRF[RRR]]]]]]]]]
I then found a solution in 37 which uses a slightly different approach (namely, create a pattern that spans the full X and Y output space, then shift it by one step each iteration): [[[[[[[[[[[[[[[[FFF]]]]]R]]]F]]]]]]]]I wonder what an AI could design with instructions for how to use this.
Poincarne / Hilbert ideas in reasonable/editable form, L-Systems[1][2][3]
[0] : http://esolangs.org/wiki/Piet
[1] : apl for postscript : http://en.wikipedia.org/wiki/L-system
[2] : https://fse.studenttheses.ub.rug.nl/14938/1/MSc_EducationMat...
[3] : https://www.sidefx.com/docs/houdini/nodes/sop/lsystem.html
[4] : https://mizzlrblog.wordpress.com/2016/06/17/l-system-compile...
[5] : nature of code : https://www.youtube.com/watch?v=f6ra024-ASY
I tried asking chatGPT to use it, removing the colour instruction to reduce complexity. After clarifying what each instructions does and providing some documented examples, it could write syntactically valid programs, but they never drew the shape or pattern it explained they would. I think the language being repetitive strings of characters doesn't mesh well with predicting tokens.
Feature request: dedicated command for “forward without color”. Perhaps “L”, as in “lifting the pen”?
I know black on black is treated the same, but I would like the separation of concerns.
I would even accept dropping “C” if this helped (effectively: reducing color palette to two, making “C” work like my proposed “L”).
So perhaps this feature request is about defining custom color palettes.
Edit - random doodling: https://susam.net/cfr.html#B12F2E3RB3CF2E3RE2RE3CB6F2E3R4ER2...
- If you raised the bit limit and added a "skip" option (ability the move cursor forward without drawing) you could potentially render simple 3d objects and run Doom by converting objects to commands
- You could implement a function that simplifies your existing inputs, so: FFFF becomes [[F]]
I made a grid:
[[[[[[[[[[FFFF]RR[FFFF]RR[FFFF]RR[FFFF]C[RRR][FFFF][RRR][FFFF][RRR][FFFF]]]]][FFFF]C]]]]]Thanks for pointing this out! I have pushed a fix for it just now. Please hard-refresh the page (ctrl+F5, cmd+shift+r, etc.) and let me know if you still see issues.
https://susam.net/cfr.html#BR3EB6FEFEFEFEFEFEFBR3EB6FEFEFEFE...
Prepend a C to get there without drawing lines on the way. Suffix with [RRRRRR]C to rotate upwards and get a visible color again.
Whenever I'm lost I paste [[[[CFCF]]]] at the end to find my cursor.
Are you parsing it yourself or are you using something like ANTLR or tree-sitter?
The entire implementation is a single HTML page written in plain HTML + JavaScript. The evaluation of the code happens here: <https://github.com/susam/cfr/blob/0.2.0/cfr.html#L204>.
[[[[[[FFCFFFFFFFFFCCCCCCC[[[FFR]]FFR]]]RRRRRCFFFFFFFFFFFFFFFFFFC[[[FFCFFFFFFFFFCCCCCCC[[[FFR]]FFR]]]CCCCCCRRRRRRCCCCCCCCCFFFFFFFFFFFFFFFFFFFFFCCCC[[[FFCFFFFFFFFFFFFFCCCCCCC[[[FFR]]FFR]]]CCFF]]
This is so cool by the way! I love this! Thank you for making this!! :)
I was wondering if there are other languages like these, and a measure analogous to Turing completeness, but for "canvas completeness" for drawing any bitmap on a canvas! :)
Edit: ah, it’s F
`CFR[]` is brilliant for being descriptive, and I think it’ll stick. But it read to me like a regulation or tax code. Perfect for misdirection.
No one ever suspects the return of LOGO as “Brackish Bletchly!”
Okay, who's going to write the first interpreter in bf that's also a quine? ;D
[[[[[[[[FFCFF]]RR]RR]R]RR]R]]
I'd suggest a little hint box below explaining what do the commands do, I had to check github for those
[[[[[[[CC[[FF]]]]R]R]R]]]
Techinques in the unpublished report make use of some solid applied analytic geometry regessions (byte sized pixels[2][3]) using sources of integer sequence[1] for a different mechanical engineering take on what CFR[] does.
Although, the overall goal was to maximize font type useage[4][6] while minimizing IRQ/type ball interuptions[5]. aka mechanical/impressionist e-ink. Takes less effort to generate striking details with CFR[].
**
[1] : HN resource on integer number sequences : https://news.ycombinator.com/item?id=36038302
a few noteable websites :
The Cinco Library Encyclopedia of Numbers : https://www.youtube.com/watch?v=rVtHrgdcvZA
On-Line Encyclopedia of Inter Sequences : https://en.wikipedia.org/wiki/On-Line_Encyclopedia_of_Integer_Sequences
offline/local dabase intdb : https://github.com/popey456963/intdb
***[2] 40 yr lang; https://www.fosslife.org/awk-power-and-promise-40-year-old-l...
[3] gawk chapter "11.3.11 And Now for Something Completely Different" program : https://www.gnu.org/software/gawk/manual/gawk.pdf
[4] DR thesis commentary : https://computerhistory.org/blog/discovering-dennis-ritchies...
[5] HN (char)0 = 0; (https://news.ycombinator.com/item?id=37910983 )
[5] "selectric typewriter goes from trash can to linux" : https://hackaday.com/2023/07/25/selectric-typewriter-goes-fr...
[6] diy typewriter : https://hackaday.com/2023/04/11/ibm-selectric-typewriters-fi... No comicon sans cast type example provided.
F (fill/forward): draw a pixel and move forward
C (color): change the color
R (rotate): rotate the direction of F by 45 degrees
[ ... ] (loop): anything inside this is executed twice
Are you referring to the short list at the top of the README on GitHub? That list does not provide "syntax definitions". That's just a quick introduction about what is about to come.
The commands are explained in detail in the section "Commands" later here: https://github.com/susam/cfr#commands
> F (fill/forward): draw a pixel and move forward
The command "F" does not draw a pixel and move forward. Instead "F" moves forward first and then draws a cell.
> [ ... ] (loop): anything inside this is executed twice
The control flow command "[" can be written without a corresponding "]". For example "[", "[F", "[[F", etc. are valid CFR[] inputs. Again, the section of the README I have linked to above defines what "[" and what "]" are.
I am hoping the information in the new help screen will make the commands easier to understand. However, if you or anyone has better ideas about describing the commands, please feel free to send pull requests.
Thank you for playing with this tool and for offering your feedback! It has been very helpful in refining the command descriptions.
Are those different from just "F"?
If not, even if those are technically valid syntax, op's explanation seems clearer. I was confused by the README definition too and came to op's conclusion after experimenting for a while.
If they are not equivalent to just "F" I still don't get the distinction so the README definition is not very good considering it confused at least both op and me.
(This is meant as constructive criticism, I'm having a lot of fun playing with this.)
Between "[F" and "[[F", there is no visual difference. The command "[" is a control flow command that does not alter the state of the canvas or the invisible turtle. Instead it merely marks the current position in the code as the beginning of a block. The execution continues normally after "[" regardless of whether there is a corresponding closing "]" or not. However, if a corresponding "]" is found, then the execution jumps back to the corresponding "[" and executes the enclosed block once more. This produces the effect of a loop that executes twice. For most drawing purposes the code bounded by "[" and "]" indeed behaves like a loop that executes twice.
I have updated the README to make this clearer. However, I am open to improving the README further if there are better suggestions. Pull requests are welcome too.