One-liner challenge

@afre is right on my effort: the cutoff is brutal. The heart, soul and humor of animation - everything - comes down to timing. I need to visit this, one fine day, when there is nothing to do - sometime mid-century, perhaps.

Got a bit of free time this afternoon, the occasion to revive this thread :slight_smile:
Here is a new one-liner proposal, written here for bash:

$ gmic v - do 300,300,1,3,"begin(R=rot(10*sin((t=$|)%)));Z=80+40*cos(x/230+2*t)*sin(y/50+4*t);P=R*(Z+100)*([x,y]-[w,h]/2)%;(0.4+exp(-Z/60))*(P[0]<-100?[0,0,255]:P[0]<100?[255,255,255]:[255,0,0])*lerp(0.5,1,xor(P[0]%64,P[1]%64)/64)" w. 200%,200%,0 rm. wait 20 while "{*}"

which displays this little animation:

Here is the “unrolled” version to be put in a .gmic file:

french_flag :
    const t = "$|";
    begin(R = rot(10*sin(t°)));
    Z = 80 + 40*cos(x/230 + 2*t)*sin(y/50 + 4*t);
    P = R*(Z + 100)*([x,y] - [w,h]/2)%;
  w. 200%,200%,0 rm. wait 20
  while {*}

Liberté, égalité et fraternité ! :fr:

Liberty and equality at France?

Liberty, equality and brotherhood.


gmic 512,1,1,1 '(37,17)' eval. 'i(#0,i(x))=1' k.. ifft. a[-2,-1] c n. 0,{2*w#0-16} +. 8 {2*w#0},{2*w#0},1,1 permute.. cyzx  eval. ">begin(PV=crop(#0);polygon(#-1,-s#0,PV,1,0xffffffff,255))" k. expand_xy. 4 dilate_circ 4 r2dx 50%,5 





  1. The width of the first image sets the sides of the painting canvas. Leave remaining image dimensions at one.
  2. The 2, 3, 4… numbers comprising the second image shape the rose. The first pattern arises from (37,3). Suggest that these numbers should be no larger than 10% of the width and should not have common factors. (16,8,4) is (4,2,1) in disguise. Order does not matter: (7,5,3) paints the same rose as (5,3,7)
  3. The example images embed their shaping numbers.

Here’s a command file version:

roses :
   repeat $#-1,j
      =. 1,${a{$j+2}},0,0,0
   s. c
   a[-2,-1] c
   n. 0,{2*w#0-16}
   +. 8
   permute.. cyzx
   eval. ">begin(PV=crop(#0);polygon(#-1,-s#0,PV,1,0xffffffff,255))"


gmic roses.gmic roses 4096,37,3 expand_xy. 4 dilate_circ 4 r2dx 50%,5 o. rose_37-7.png

For the first example drawn large. With the command version, the first argument sets the image size, an arbitrary number of shaping numbers follow. Same guidelines apply.

I have a vague notion that something like this was written a long time ago. I can’t find it. @David_Tschumperle’s Hypotrochoid has some resemblance of what is going on here, but what’s going on here is not circles rolling within/without circles. The shaping numbers are spectral coefficients. Temporally Fourier transformed and circular plotted: real provide the x coordinate and imaginary provides the y. Might trace one by happenstance.


What does the $#_-1,j mean?

Note to self: Look at my gmic file for similar confusing syntax.

Adding Custom Commands is your friend.

"$# is substituted by the maximum index of known arguments (either specified by the user or set to a default value in the custom command)."

$# includes the command name in its count, so less one to shorten the iteration to just the arguments following the command line. j is a local variable that aliases $>. See repeat … done.

1 Like

Ah, that makes sense now. I use narg($*) instead since it’s a bit more obvious of what it says (n = number, and arg means argument), and there’s a syntax difference involved being outside math parser and inside it. I will explore $# then.

There are so many of those that I forget to use them…



I really like the rendering of your command line from your message One-liner challenge - #54 by afre

It is necessary to replace the character ’ by " so that this line of commands also works under GMIC CLI, GMIC-QT, GMIC-GIMP Windows

It will also work on Linux.

Thank you :o)

gmic 512,1,1,1 "(37,17)" eval. "i(#0,i(x))=1" k.. ifft. a[-2,-1] c n. 0,{2*w#0-16} +. 8 {2*w#0},{2*w#0},1,1 permute.. cyzx eval. ">begin(PV=crop(#0);polygon(#-1,-s#0,PV,1,0xffffffff,255))" k. expand_xy. 4 dilate_circ 4 r2dx 50%,5

1 Like

Agree that narg() self-documents well.

But subtle are the differences betwixt $# and narg($*). These differences stem from G’MIC setting up $# directly, conveying the command line item count datum straight from the underlying environment, while narg($*) performs computation on a vector. It is this vector computation from which differences arise, particularly the role that commas play in vector string representations: commas are the item separators of vectors.

Consider this custom command defined in foobar.gmic:

foobar :
   e {narg($*)}
   e {$#}

Doris Diligence runs this to test a typical argument list for a G’MIC command she is (diligently) developing:

$ gmic foobar.gmic foobar 1,3,2.718,"Oh, yes, We have no bananas."
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'foobar.gmic' (1 new, total: 4422).
[gmic]-0./foobar/ 6
[gmic]-0./foobar/ 6
[gmic]-0./ End G'MIC interpreter.

The two command line counters are in agreement, but Doris is unsettled. She has been thinking that her argument list has four elements: “1”, “3”, “2.718” and “Oh, yes, We have no bananas.”

Being a diligent cheat sheet reader, she has read Cheat #4: You’ve Moved Fast and Broken Things. Now What?. So Doris runs the script under -debug to understand how G’MIC sees the command line, which may differ from her view. Here is the -debug excerpt of G’MIC’s pipeline decomposition for entry into the foobar/ scope:

<gmic>-0./ Command 'foobar': arguments = '1,3,2.718,Oh, yes, We have no bananas.'.
<gmic>-0./ Found 6 given arguments for command 'foobar':
<gmic>-0./   $1 = '1'
<gmic>-0./   $2 = '3'
<gmic>-0./   $3 = '2.718'
<gmic>-0./   $4 = 'Oh'
<gmic>-0./   $5 = ' yes'
<gmic>-0./   $6 = ' We have no bananas.'

“Oh — foo!!!” cries Doris “I must bar the parsing of my last string argument into separate items! Of course! I have forgotten to escape the double quotes!”

So Doris — in a rare lapse of diligence — fails to consider the significance of initial spaces in arguments $5 and $6; she just escapes the double quotes and runs the command again.

G’MIC’s pipeline decomposition for entry into the foobar/ scope appears to have changed for the better:

<gmic>-0./ Command 'foobar': arguments = '1,3,2.718,Oh\, yes\, We have no bananas.'.
<gmic>-0./ Found 4 given arguments for command 'foobar':
<gmic>-0./   $1 = '1'
<gmic>-0./   $2 = '3'
<gmic>-0./   $3 = '2.718'
<gmic>-0./   $4 = 'Oh\, yes\, We have no bananas.'

“Success!” cries Doris. “Escaping the quotes did the trick. Now my string argument comes across intact!”

Whistling a merry tune, Doris scrolls further down to examine the substitutions going on within the foobar/ scope.

<gmic>-0./foobar/ Enter scope 'foobar/'.
<gmic>-0./foobar/#2 Item 'e', selection [].
<gmic>-0./foobar/#2 Command 'echo': arguments = '{narg(1,3,2.718,Oh, yes, We have no bananas.)}' -> '6'.
[gmic]-0./foobar/ 6
<gmic>-0./foobar/#3 Item 'e', selection [].
<gmic>-0./foobar/#3 Command 'echo': arguments = '{4}' -> '4'.
[gmic]-0./foobar/ 4
<gmic>-0./foobar/#3 Exit scope 'foobar/'.

“Oh! Triple foo with cherries on top — and whipped cream!!! I have six arguments and four arguments. Now — bar it all! — what am I to believe?”


  1. narg() is a math function that counts elements of string-represented vectors. Commas separate elements in these representations, so the five commas in “1,3,2.718,Oh, yes, We have no bananas.” begat six elements: ["1", "3", "2.718", "Oh", " yes", " We have no bananas."]. Observe that the penultimate and last vector elements have leading spaces; these follow the commas upon which elements were split. Had Doris noticed these leading spaces earlier on, she would have been cued to the fact as to how her argument list was going off the rails.
  2. $# is a substitution G’MIC maintains for custom commands, relaying how many items it discovered when blocking out the pipeline, a part of scope-entry setup. When G’MIC reports "Found 4 given arguments for command 'foobar':", then $# relays the number following “Found”: the item count of the blocked-out, incoming pipeline, less the custom command name itself.

The construct:


induces G’MIC to provide the items themselves, exactly as to how G’MIC blocked them out. G’MIC expands this pseudo assignment into a series of actual assignments, one for each item of the blocked-out incoming pipeline plus the command name itself.

foobar modified:

foobar :
   e "Narg sez: "{narg($*)}
   e "Dollar Hash sez: "{$#}
   e ${citems_0}"'s arguments are:"
   repeat $#,k
      e "Argument "{$k+1}" is: "${citems_{$k+1}}"." 

Running it yields:

$ gmic foobar.gmic foobar 1,3,2.718,\"Oh, yes, We have no bananas.\"
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'foobar.gmic' (1 new, total: 4422).
[gmic]-0./foobar/ Narg sez: 6
[gmic]-0./foobar/ Dollar Hash sez: 4
[gmic]-0./foobar/ foobar's arguments are:
[gmic]-0./foobar/*repeat/ Argument 1 is: 1.
[gmic]-0./foobar/*repeat/ Argument 2 is: 3.
[gmic]-0./foobar/*repeat/ Argument 3 is: 2.718.
[gmic]-0./foobar/*repeat/ Argument 4 is: Oh, yes, We have no bananas..
[gmic]-0./ End G'MIC interpreter.

The offsetting of local variable $k by one accommodates the fact that the first element of the blocked out pipeline contains the command name, useful should one be contemplating conditional command name processing.

The takeaway here is not that narg() is bad and $# is good; they are different tools that serve closely-related, but different purposes, and their operating mechanisms are different. That they almost always report the same results could lull us into thinking they are the same tools just spelled differently. They’re not. Corner cases exist and need to be understood — and navigated.


gmic sp lion f "<begin(P=whd);P--;Q=round(P/2);swap(I[Q],I)"


This is really not interesting.

rep_concat: 64,64,1,1,"begin(concat(a,b)=b+a*10^(ceil(log10(b+1))+ceil(abs(b-.5))-b););px=abs(x-32);py=abs(y-32);q=int(norm(px,py));p=max(px,py);concat(p,q)%128;"


This basically utilize concatenate two integer number.

I got this idea from a blog that I can’t seem to find anymore which utilize concatenation, but the person didn’t made this sort of result with it, but something else.


With 31, it’d look like this:


And can also do this with concat(a,b):


Edit: I found the blog - Concatenations — Kerry Mitchell

That is where I got this idea. I don’t understand it though.

1 Like

gmic sp inside g xy,-1 sign g.. x,1 g. y,1 add ilaplacian ,

The kilometrage varies with ilaplacian. Not sure what to do with it…

Seen a Twitter post about this today (but cannot find the link anymore). It creates an image that exhibits a strong 3D effet (at least for me, particularly when I move my head) :

$ gmic 800,800,1,3 s0,s1,s2,s3,s4=\"255,0,0\",0,\"0,0,255\",0,\"255,0,0\" repeat 5 circle 50%,50%,'{arg0($>,35,25,22,13,10)}'%,1,'${s$>}' done f 'u<0.1?0:i' erode_circ. 3 r2dx 50%



Ah yes, that’s called “Colour Pseudo-Stereopsis”, caused by chromatic aberration of the eye, and pupils not being central. Interestingly the effect can be reversed depending on the observer!


lovely example here

more recent tweet


I have been wondering if it was possible to generate random numbers via new seed, it appears it is possible! If you change 45 to something else, note the other numbers doesn’t change.

$ gmic echo {expr('>begin(test=[2,6];seed_collect=[23,45,60];k=0;test_seed=1;);if(x==test[k]&&k<2,++k;test_seed=1;);if(test_seed,srand(seed_collect[k]);test_seed=0;);int(u(0,11));',12)}

This would be perfect for finishing up new version of Stitch filter.

This is the expanded expr code.




, 12 )