FX Experience Has Gone Read-Only

I've been maintaining FX Experience for a really long time now, and I love hearing from people who enjoy my weekly links roundup. One thing I've noticed recently is that maintaining two sites (FX Experience and JonathanGiles.net) takes more time than ideal, and splits the audience up. Therefore, FX Experience will become read-only for new blog posts, but weekly posts will continue to be published on JonathanGiles.net. If you follow @FXExperience on Twitter, I suggest you also follow @JonathanGiles. This is not the end - just a consolidation of my online presence to make my life a little easier!

tl;dr: Follow me on Twitter and check for the latest news on JonathanGiles.net.

I had great fun entering the JFXStudio challenge to write a time themed JFX application in less than 30 lines or 3000 characters. Here is my entry a radial clock made of words:

Click to run "Radial Word Clock"

Click to run "Radial Word Clock"

Unfortunatly I did not win you can see the winner and other great entries at JFXStudio challenge “Time” winner announced. My favorite entry is Spin Clock by Stephen Chin. I have to admit I the idea for mine from a Mac Screensaver that I liked. Here is the code for it if you want to try it out your self.

import javafx.stage.Stage; import javafx.scene.*; import javafx.scene.transform.*;
import javafx.scene.text.*; import javafx.scene.paint.*; import javafx.animation.*;
import java.util.Calendar;
def font = Font{size:12};
def numbers = ["twelve","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve",
def tens = ["","","twenty","thirty","forty","fifty"];
var hRot:Number;var mRot:Number;var sRot:Number;var mOffset:Number;var sOffset:Number;
def hours = for (h in [0..11]) Text { transforms: [Rotate{angle: bind hRot+((360/12)*h)},Translate{x:80}] fill:Color.WHITE font: font content:numbers[h] };
def minutes = for (m in [0..59]) Text { transforms: [Rotate{angle: bind mRot+((360/60)*m)},Translate{x:bind mOffset+80}] fill:Color.WHITE font: font content: if(m==0) "o’clock" else if (m<10) "oh-{numbers[m]}" else if (m<20) numbers[m] else "{tens[(m/10)]}{if(m mod 10==0)""else "-{numbers[m mod 10]}"}"};
def seconds = for (s in [0..59]) Text { transforms: [Rotate{angle: bind sRot+((360/60)*s)},Translate{x:bind sOffset+80}] fill:Color.WHITE font: font content: if(s==0) "precisely" else if (s<20) numbers[s] else "{tens[(s/10)]}{if(s mod 10==0)""else "-{numbers[s mod 10]}"}"};
def andT = Text{ font: font, fill: Color.RED, content: "and"};
def secondsT = Text{ font: font, fill: Color.RED, content: bind if (c.get(c.SECOND)==0) then "second" else "seconds"};
var c:Calendar;
Stage { scene:Scene {fill:Color.BLACK width: 800,height: 800 content: Group{translateX: 400 translateY: 400 content:[hours,minutes,seconds,andT,secondsT]}}}
Timeline { repeatCount: Timeline.INDEFINITE, keyFrames: KeyFrame{ time: 1s, action: function(){
var nc = Calendar.getInstance();
if (c.get(c.HOUR)!=nc.get(c.HOUR)) Timeline { keyFrames: at(200ms) {hours[c.get(c.HOUR)].fill => Color.WHITE;hours[nc.get(c.HOUR)].fill => Color.RED}}.play();
if (c.get(c.MINUTE)!=nc.get(c.MINUTE)) Timeline { keyFrames: at(200ms) {minutes[c.get(c.MINUTE)].fill => Color.WHITE;minutes[nc.get(c.MINUTE)].fill => Color.RED}}.play();
Timeline { keyFrames: at(200ms) {
hRot => 360-((360/12) *nc.get(c.HOUR));mRot => 360-((360/60) *nc.get(c.MINUTE));sRot => 360-((360/60) *nc.get(c.SECOND));
seconds[nc.get(c.SECOND)].fill => Color.RED;seconds[c.get(c.SECOND)].fill => Color.WHITE;
mOffset => hours[nc.get(c.HOUR)].layoutBounds.width + 5;
andT.translateX => hours[nc.get(c.HOUR)].layoutBounds.width + minutes[nc.get(c.MINUTE)].layoutBounds.width + 85;
sOffset => hours[nc.get(c.HOUR)].layoutBounds.width + andT.layoutBounds.width + minutes[nc.get(c.MINUTE)].layoutBounds.width + 5;
secondsT.translateX => hours[nc.get(c.HOUR)].layoutBounds.width + andT.layoutBounds.width + minutes[nc.get(c.MINUTE)].layoutBounds.width + seconds[nc.get(c.SECOND)].layoutBounds.width + 85
} }.play();
c = nc;
}} }.play();