1) First Step - Learn the original CFDG
First thing you need to do is learn the original CFDG language, which ContextFree1, implements. You can learn all the basic concepts at http://www.contextfreeart.org/mediawiki/index.php/CFDG_HOWTO.
2) What CInk doesn't support?
CInk implements almost everything of CFDG1, but fews bolts are still missing due to technical limitations.
includestatements are ignored. Since CInk runs in a browser so it doesn't have the notion of files, but URLs instead. This is technically possible to implement but that would require some code to make AJAX calls to fecth these included files. In fact, I need to think a little more about this. You can consider this in future scope. I won't give any time frame for this.sizein CInk behaves very differently from ContextFree. Whereas in ContextFree, it defines the dimension of the canvas, in CInk canvas size is constant and has no special meaning except that all transforms are applied globally. So this is the best place put code to scale the whole design. Usually any ContextFree code needs to be scaled down by a factor of 50 - 100 times if it is to be rendered by CInk.- Support for
tileis broken. Technically it cannot be supported in CInk. To support proper tiling as ContexFree does, CInk will need to retain the primitive informations till the very end of the rendering process. This is not possible since CInk renders all primitives on HTML5canvas, andcanvasremembers only the bitmap information. All primitive information are lost. Had CInk used SVG then it might have been possible, but SVG was not used since it might have had huge performance penalty. - Path command
ARCTOallows two parameterscwandlarge. ContexFree (tested on version 2) seems to behave wierdly when both these parameters are used. If you have ContextFree then try running the following code:-
You will notice that ContexFree still renders the small arc. I believe that is incorrect. CInk will render it correctly.startshape wrongArc
#size {s 0.4}
path wrongArc {
ARCTO {x 2 y 0 r 0 rx 2 ry 1 p large p cw }
STROKE {}
}
3) CInk extensions - CFDG2
This section enlists the language extensions added to CFDG. These statements and features are not available in original CFDG and ContextFree.
New transforms
CInk has thrown in some new transforms that can be used like any other existing transforms, like -
hue,x,skew, etc.You can draw shadows! So, now anything which is drawn can have shadow and you do not need to fake it in some way. It is immensly useful and is used by Neon Letters (in gallery). You can learn how to use them here.
shx- Shadow's x-offset.shy- Shadow's y-offset.shblur- Set shadow blur.shh- Set shadow color's hue.shb- Set shadow color's brightness (actually value).shsat- Set shadow color's staturation.sha- Set shadow color's alpha, i.e. transperency.
Some miscellenious transforms
sw- This sets the stroke width. This doesn't affect path's stroke width.gx- Global x. This is a totally different kind of transformation. Allow me to explain it using the below example:-
In the above code we can see that since in the current transform x is 0 sostartshape A
rule A {
B {x 1}
C {x 2}
}
rule B {
CIRCLE {}
}
rule C {
CIRCLE {}
}
Bwill be displayed at (1,0) andCwill be displayed at (2,0). Now if we modifiy the code as:-startshape A
rule A {
B {gx 1} //...(1)
C {gx 2} //...(2)
}
rule B {
CIRCLE {}
}
rule C {
CIRCLE {}
}
Then
Bwill still be displayed at (1,0), butCwill be displayed at (3,0). You might ask how? Well the answer isgx, as its name suggest is a global transform. All other transforms in CFDG are local, so they have limited scope where they can have effect. In this case what exactly happend was that the expression marked by (1) incremented the global x by 1. The initial value of gloabal x is zero. When a primitive (here it isCIRCLE) is displayed then it adds the current value ofgxto its local value ofx. In this code we never changed the local x so it was always 0. So, the evaluation of steps were:When in B -> x=0, gx=0+1=1, so B draws at x=0 + 1 -> Now we goto C -> x=0, gx=1+2=3, so C is drawn at x=0 + 3 ->Now finally gx is 3.Unfortunately, this transform bends the rules of CFDG. It doesn't gel well but is needed in some scenarios i.e. all this global funda is not for regular use but is nonetheless sometimes required. Check out Neon Letters for example.
-
gy- Global y. Similar togx, but this affectsytransform.
Predefined Event Rules
First concocted by Aza for Algorithm Ink2, the Predefined Event Rules are a beatiful addition to CFDG. I have added a few more from my end. They can be used like any other rule but will automatically be triggered when their events occur.
MOUSECLICK- As it sounds, whenever a user clicks on the canvas this rule will be fired. There is one twist though. The (x,y) location of the click will be applied as local transforms to this rule.MOUSEMOVE- This is similar toMOUSECLICKbut is triggered when the mouse moves over the canvas.TIME- This is a time event. Unlike the other event rules this is not triggered automatically, instead the designer needs to call this rule from another rule. The difference being, unlike normal rules, this won't be executed immediately, instead it will lie idle till the "right time". Once it is executed this won't recurr. If you need to created a recurring timer then you can call this rule recursively. The "right time" I spoke of is the weight of this rule. This rule has one caveat - it can be defined only once. So it is illegal to define more than oneTIMErule. If at anytime you want to cancel a 'scheduled' call, you can call theSTOPTIMEprimtive.TYPE- This is triggered on keypress, but requires that the canvas has the focus. This will capture the character typed-in and apply that as local text transform (discussed later).
-
New primitives
Primitives are atomic tasks (explained in section 4). They render a basic shape after applying all the current transforms on it. So a
CIRCLEalyways renders a circle of unit radius and at the origin of the coordinate system. The coordinate system decides the shape, size, location and color of the shape, based on the current applicable transforms. Note the phrase, 'applicable transforms', which means that some transforms could be ignored. Sosw(stroke width) transform will have no impact onCIRCLE, since it is drawn filled and not stroked, however it will have its impact onLINE, since it is stroked.LINE- It draws a line of unit length.ECHO- Draws some texts. Discussed next.
-
Text transforms
This is the single most important extension to CFDG, the ability to print texts. ContextFree comes bundled with a CFDG program with paths that draw many alphabets. We can avoid this using CInk as
canvasalready provides first class support for characters. CInk doesn't twist the original grammar to force this. Infact, it introduces a new primitive -ECHO, which behaves exactly like any other primitives.New text transforms:-
fn- Sets the font name.fs- Sets the font size. This is additive. So when multiplefstransforms are encountered then their values will be added up as we progress. This allows us to print texts which progressively vary in size.fu- Sets the unit for the font size, i.e. 'em', 'px' or 'pt'.fstyle- Sets the font stlye. Possible values -italic,bold,capandnormal.normalis default.t- Aah! The prized transform. This is the one which allows you to set the text that needs to be shown. This too is additive, so if your expression ist A t B t C, then the net output will be the stringABC.taccepts single character or a string of characters as argument. If the supplied string contains anything other than digits or english alphabets then it must be enclosed in double quotes.bkspc- This removes the last character, if any. So, if we modify the above example to –t A t B t C bkspc, the output then changes toAB.e- This is likebkspcbut instead of removing the last character it empties out the full text. So, whenever this is used the the final output will always be an empty string.|t- This one is a genius!
I can't help myself from putting so many exclamations and smileys. There goes one more.
This command should be followed by an integer. This value is then added to the last character's unicode (decimal) value. So when the current string is ABCthen the expression|t 1will output the stringABCD. This is because on adding 1 to unicode (in this case the ASCII) value ofC, we getD. ThisDthen gets concatenated with the last string.This little buddy has one more trick up its sleeve. What do you expect will be the output of
t ABC e |t 1? Well, it won't be an empty string. It will beD! This is becauseeandbkspcare, what I call, past-influential transforms. Past-influential transforms are not supposed to influence the output of the future transforms. In this exampleC's ASCII code is passed-on to|teven whenCperishes. Had it not done that then|twould output different strings, based on if it was preceeded or not preceeded byeandbkspc. That is against the nature of past-influential transforms, and would have made it hard to predict the output. So,eorbkspcdo not influence the output of|t.base- This is better explained here.align- This is better explained here.st- Strokes the text, i.e. draws the text's outlines. Value ofswis used here to set the thickness of the stroke lines.ft- Fills the text. This is the default behavior for drawing texts. We cannot stroke and fill the same text sostandftshould not be used together.
Unicode Support:-Text transforms support Unicode3 characters. This allows you to print non-english characters. Its format is
{ux}, where the 'x' should be replaced by the decimal Unicode value of the character. So,{u65}will printA. You might wonder; how will you print the character '{'? Well the only way is to use{u123}to print{and{u125}for}. This applies for double and single quotes too. For them use{u34}and{u39}respectively.Check out the example code with live demo on my blog here.
4) CInk caveats
This enlists some gotchas you need to be aware of.
ARCTOgotcha - CInk uses a complex and non-optimal method to draw theARCTOarcs. This becausecanvasdoesn't provide any API to draw elliptical arcs. It does provide some APIs to draw circular arcs but they need different set of information. To keep the code maintainable I didn't optimise this part.- Paths gotcha - Javascript engines are single threaded so if any JS code takes too long to respond then the browser will lockup (in case of Chrome only that tab will lock up). CInk being processor intensive, it uses a trick to tackle this. It mimics the behavior of a time sharing OS running on a single core processor. In such a scenario when you have two or more simultaneously running processes then the OS makes sure that each process gets access to the processor for a breif period of time. This is called time-slicing and these time slices are so small that the user gets the impression that all of them are using the processor simultaneously. Similarly, CInk too divides all its tasks into chunks of atomic tasks and collection tasks. Each atomic task needs to be complete in one cycle.
While a collection task is, ofcourse, a collection of many atomic or collection tasks. Atomic works cannot be sub-divided like a collection. A
ruleis a collection task as it might be divided into a number of more tasks.pathon the other hand is by nature atomic and cannot be subdivded. So, I will advise you against defining complex paths as they might lockup the browser when drawn in hordes. z-index rendering - HTML
canvasdoesn't support z-index and there is no way to handel the different layers. CInk uses a workaround to implement this very much needed feature. The workaround is to create a bunch ofcanvasDOMs, stacked over each other. Theirz-indexare set toztransform's values (accurately speaking, the value is not equal to thezvalue but calculated from it).When CInk renderer is instantiated then it checks for a
hasZflag in the compiled code, if found then it switches to a z-mode. This flag is set by the compiler, if it finds that the code usesztransform. When in z-mode, CInk wraps the passedcanvasinside adivwith CSS class - CInkWrapper. CInk also changes thecanvas'postionproperty toabsolute. It takes care of positioning thecanvassuch that it stays at the original spot. Since thecanvasis now absolutely positioned, it may mess up your layout. I suggest you to setup your layout withcanvasabsolutely positioned. At the end of the rendering process, all the different pieces of the design will be copied to the originalcanvasand the clone canvases will be deleted. The wrapperdivwill be gone too and the original canvas' CSS styles will be reverted. This scheme works but seems to take a heavy toll on Firfox. Chrome easily handels this pressure.As I mentioned, CInk creates layers of canvases, and fortunately we can 'see-through' them. Ofcourse, unless you fill it with some color, but CInk needs to fill it with the background color. So it creates an extra canvas to fill with only the background color. CInk makes sure that this canvas is the bottom of the stack. While rendering, whenever it finds that it doesn't have a canvas at the required
z, it creates one. CInk makes sure that all clone canvases are of exact same dimension and positioned at exactly the same spot and are within the wrapperdiv. During rendering you might end up with loads of such clones. You might wonder how can you create an UI element (e.g.div) which is guaranteed to stay on top of CInk. For this you need to create a positioned element and set itsz-indexvalue to more than 200. CInk will never create any layer overz-indexof 200.- z-index rendering for code that uses Predefined Event Rules - Everything stated above applies here too, except that at the end of rendering the wrapper
divwon't be removed. The backgroundcanvastoo will retained, but clone canvases will be deleted after copying the bitmaps from them. This is done so, because, after the main rendering process, the events may still fire some rules. Those rules may also try to useztransform. The wrapper and backgroundcanvaswill be removed only whenshutAndDispose()4 is called.
- http://www.contextfreeart.org/mediawiki/index.php/Context_Free_Art:About (Context Free Art)
- http://azarask.in/projects/algorithm-ink (Algorithm Ink)
- What is Unicode? (Wikipedia article)
- Download and API Reference (Look inside API reference section)