Hello all,
I like to build a random feature in a typeface I'm working on.
Every character has four alternates and I like the fontsoftware to choose between them.
Can I do this in OpenType? And if so, how?
Thanks.
Pieter
Although rand is in the OT spec, no application currently support it (or are likely to any time soon).
You can emulate it in some way using calt though. Check our Thomas Phinney's sample code from the Adobe FDK forums: http://www.adobeforums.com/cgi-bin/webx?50@755.561rfSM0Gas.1@.3bbc5ea4
Thanks you, but it's not working. I made a test font with code like this:
feature calt { # Connection or other contextual Forms
# Latin
lookup rotate {
sub @default @default' by @calt1;
sub @calt1 @default' by @calt2;
sub @calt2 @default' by @calt3;
sub @calt3 @default' by @calt4;
} rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
lookup rotate;
} calt;
@default = [a b c d e f g h i j];
@calt1 = [b c d e f g h i j a];
@calt2 = [c d e f g h i j a b];
@calt3 = [d e f g h i j a b c];
@calt4 = [e f g h i j a b c d];
I only get an a followed by a b. Is there something wrong in the code?
Thanks!
If I'm understanding your problem correctly, I think it's because each of your groups is effectively equivalent to the next. A better example would be
*****
@default = [a b c d];
@calt1 = [e g h i];
@calt2 = [j k l m];
@calt3 = [n o p q];
*****
where each of the groups contain unique characters.
so, aaaa becomes aejn.
I've never done any OpenType programming, but I would guess that the 13 lookups work like modulo.
So instead of the eight alternatives coming in this order:
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
You get a pseudo-random order:
1 6 3 8 5 2 7 4 1 6 3 8 5 2 7 4
But there's probably more to it since I get the same series repeating...
You can make seemingly-random randomization, but not actually-random randomization. The OpenType version of LetTerror's Kosmik by John Butler does this, as does Christian Schwartz's Local Gothic, thanks to Tal Leming's brilliant code.
Zapfino Extra LT Pro uses approx. 600 contextual substitutions to simulate pseudorandom typesetting. Each letter has between 4 and 7 variants. Some of the feature definition code was generated by Python code that I wrote.
The slides that I showed at TypoTechnica in London show some excerpts from the Python code and the OT code for Zapfino Extra LT Pro that I developed:
http://www.twardoch.com/adam/project.php?pid=0049
Regards,
Adam
yay! i found a cached version of Christian Robertson's thread for Dear Sarah on Google. Here it is with Christian's OT code hacks intact:
Excerpt of Christian's comments:
It's not true randomness. The OT code looks something like this:
@random_set_1 = [a d g j l m n o c];
@random_set_2 = [k e i n p q t v z];
@letter = [a b c d e f g h i j k l m n o p q r s t u v w x y z];
@letter_alt = [a.alt b.alt c.alt d.alt e.alt f.alt g.alt h.alt i.alt j.alt k.alt l.alt m.alt n.alt o.alt p.alt q.alt r.alt s.alt t.alt u.alt v.alt w.alt x.alt y.alt z.alt];
feature calt {
sub @random_set_1 @letter @letter' by @letter_alt;
sub @random_set_2 @letter @letter' by @letter_alt2;
} calt;
If you put in enough of these ugly hacks it starts to appear random. You would also want to make sure that no two letters were ever the same right next to each other. There are only so many of those that happen regularly in English, so I have added specific substitution rules for each of those cases (ee ff gg ll mm nn oo, etc.) Also notice that I have placed an @letter between the @random character. This makes the pattern even more difficult to spot. You might notice the funky h after every t, but you wouldn't notice the funky h after t-anycharacter, (unless you were freaking crazy).
In the case of this font, the fact that there are a different set of characters to connect to the o b v w also helps the font appear more random. The randomness feature above needs to be adjusted to get the connectors right for this one, which makes it more complicated. To be honest, I haven't completely figured it out.
also, for a bit of pseudo randomness, i think you could combine a couple contextual lookups that do different things. For example, you could have 2 sets of letters and have every third one switch to an alternate. Then have another lookup that changes double letter combinations so that the second letter in the combo gets switched out by its alternate. the interplay of these two functions will give a predictable, but somewhat random appearing effect. this is just one example, there are probably endless ways of combining effects such as this to get something that approaches randomness.
How should I change my OTF code to get the line “I need“ (image link http://clip2net.com/s/1qAvm)?
My code:
@letter = [b c d e f g h i j k l m n o p q r s t u v w x y z space];
@letter1 = [a c d e f g h i j k l m n o p q r s t u v w x y z space];
@letter2 = [a b d e f g h i j k l m n o p q r s t u v w x y z space];
feature calt {
lookup rotate {
sub a a' by a.calt1;
sub a.calt1 a' by a.calt2;
sub a.calt2 a' by a;
sub a @letter a' by a.calt1;
sub a.calt1 @letter a' by a.calt2;
sub a.calt2 @letter a' by a;
sub a @letter @letter a' by a.calt1;
sub a.calt1 @letter @letter a' by a.calt2;
sub a.calt2 @letter @letter a' by a;
sub a @letter @letter @letter a' by a.calt1;
sub a.calt1 @letter @letter @letter a' by a.calt2;
sub a.calt2 @letter @letter @letter a' by a;
sub a @letter @letter @letter @letter a' by a.calt1;
sub a.calt1 @letter @letter @letter @letter a' by a.calt2;
sub a.calt2 @letter @letter @letter @letter a' by a;
sub a @letter @letter @letter @letter @letter a' by a.calt1;
sub a.calt1 @letter @letter @letter @letter @letter a' by a.calt2;
sub a.calt2 @letter @letter @letter @letter @letter a' by a;
sub a @letter @letter @letter @letter @letter @letter a' by a.calt1;
sub a.calt1 @letter @letter @letter @letter @letter @letter a' by a.calt2;
sub a.calt2 @letter @letter @letter @letter @letter @letter a' by a;
sub b b' by b.calt1;
sub b.calt1 b' by b.calt2;
sub b.calt2 b' by b;
sub b @letter1 b' by b.calt1;
sub b.calt1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 b' by b;
sub b @letter1 @letter1 b' by b.calt1;
sub b.calt1 @letter1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 @letter1 b' by b;
sub b @letter1 @letter1 @letter1 b' by b.calt1;
sub b.calt1 @letter1 @letter1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 @letter1 @letter1 b' by b;
sub b @letter1 @letter1 @letter1 @letter1 b' by b.calt1;
sub b.calt1 @letter1 @letter1 @letter1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 @letter1 @letter1 @letter1 b' by b;
sub b @letter1 @letter1 @letter1 @letter1 @letter1 b' by b.calt1;
sub b.calt1 @letter1 @letter1 @letter1 @letter1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 @letter1 @letter1 @letter1 @letter1 b' by b;
sub b @letter1 @letter1 @letter1 @letter1 @letter1 @letter1 b' by b.calt1;
sub b.calt1 @letter1 @letter1 @letter1 @letter1 @letter1 @letter1 b' by b.calt2;
sub b.calt2 @letter1 @letter1 @letter1 @letter1 @letter1 @letter1 b' by b;
sub c c' by c.calt1;
sub c.calt1 c' by c.calt2;
sub c.calt2 c' by c;
sub c @letter2 c' by c.calt1;
sub c.calt1 @letter2 c' by c.calt2;
sub c.calt2 @letter2 c' by c;
sub c @letter2 @letter2 c' by c.calt1;
sub c.calt1 @letter2 @letter2 c' by c.calt2;
sub c.calt2 @letter2 @letter2 c' by c;
sub c @letter2 @letter2 @letter c' by c.calt1;
sub c.calt1 @letter2 @letter2 @letter2 c' by c.calt2;
sub c.calt2 @letter2 @letter2 @letter2 c' by c;
sub c @letter2 @letter2 @letter2 @letter2 c' by c.calt1;
sub c.calt1 @letter2 @letter2 @letter2 @letter2 c' by c.calt2;
sub c.calt2 @letter2 @letter2 @letter2 @letter2 c' by c;
sub c @letter2 @letter2 @letter2 @letter2 @letter2 c' by c.calt1;
sub c.calt1 @letter2 @letter2 @letter2 @letter2 @letter2 c' by c.calt2;
sub c.calt2 @letter2 @letter2 @letter2 @letter2 @letter2 c' by c;
sub c @letter2 @letter2 @letter2 @letter2 @letter2 @letter2 c' by c.calt1;
sub c.calt1 @letter2 @letter2 @letter2 @letter2 @letter2 @letter2 c' by c.calt2;
sub c.calt2 @letter2 @letter2 @letter2 @letter2 @letter2 @letter2 c' by c;
} rotate;
} calt;
@default = [b c d e f g h i j k l m n o p q r s t u v w x y z space];
@alt1 = [a c d e f g h i j k l m n o p q r s t u v w x y z space];
@alt2 = [a b d e f g h i j k l m n o p q r s t u v w x y z space];
feature calt {
lookup rotate {
sub @default @default' by @alt1;
sub @alt1 @default' by @alt2;
sub @alt2 @alt2' by @default;
} rotate;
lookup rotate;
} calt;
Every character have two alternates.
This code doesn't show b.calt1 and c.calt2.
This code does not include the work of all the other letters.
How can I do it?
Your code:
@default = [b c d e f g h i j k l m n o p q r s t u v w x y z space];
@alt1 = [a.calt1 c.calt1 ....... space];
@alt2 = [a.calt2 b.calt2 ....... space];
feature calt {
lookup rotate {
sub @default @default' by @alt1;
sub @alt1 @default' by @alt2;
sub @alt2 @alt2' by @default;
} rotate;
lookup rotate;
} calt;
I correct my code. All works.
Do not work correctly only a and j characters.
why?
My new code:
feature calt {
lookup rotate {
sub @default @default' by @calt1;
sub @calt1 @default' by @calt2;
sub @calt2 @default' by @default;
sub @default_jpqx @default_jpqx' by @calt1_jpqx;
sub @calt1_jpqx @default_jpqx' by @default_jpqx;
} rotate;
lookup rotate;
} calt;
@default = [a b c d e f g h i k l m n o r s t u v w y z space];
@calt1 = [a.calt1 b.calt1 c.calt1 d.calt1 e.calt1 f.calt1 g.calt1 h.calt1 i.calt1 k.calt1 l.calt1 m.calt1 n.calt1 o.calt1 r.calt1 s.calt1 t.calt1 u.calt1 v.calt1 w.calt1 y.calt1 z.calt1 space];
@calt2 = [a.calt2 b.calt2 c.calt2 d.calt2 e.calt2 f.calt2 g.calt2 h.calt2 i.calt2 k.calt2 l.calt2 m.calt2 n.calt2 o.calt2 r.calt2 s.calt2 t.calt2 u.calt2 v.calt2 w.calt2 y.calt2 z.calt2 space];
@default_jpqx = [j p q x space];
@calt1_jpqx = [j.calt1 p.calt1 q.calt1 x.calt1 space];
Captured from web.archive.org on 19 Oct 2013. view this capture