Last week, at work, they decided that we need another site redesign for the DAAC Website.  The new frontpage is significantly smaller than before, so one idea early one was to incorporate a Flash Menu to scroll between different items.  That way we increase exposure of various things, without dedicating any more screen space.  It was a good idea, and pretty quickly we decided on something like the widget at www.steampowered.com and gamespot.com.  By "we" I mean that the group decided I needed to make it :)   So I broke down the requirements like so:

  1. It should smoothly transition between 5 images, about once every 3 seconds.
  2. Buttons across the bottom that indicate which of the 5 images is shown
  3. When they click on a button, go directly to that image and disable the automatic transition
  4. Each image should be accompanied by a small text Description
  5. Clicking on the Image should go to a URL

Seemed simple enough, right?  Unfortunately, I’ve never done anything in Flash before, and we don’t have the Adobe Flash CS2 package in the office.  Being the proponent of Open-Source that I am (and having a deadline of "On the Website" within 4 weeks), I hit the net to see what I could find.  It wasn’t long before I stumbled upon the SWFTools.
[tag:flash][tag:swftools][tag:swfc]

SWF, the file format that most Flash Animations you find on the web are in, is actually a fairly well known format.  It’s proprietary, but alot of effort has gone into reverse engineering it.  It’s essentially a vector-graphics format coupled with timeline support (for animation) and "ActionScript" for programming.  ActionScript is scripting language based on an old language called ECMAScript, and looks alot like JavaScript or C in it’s implementation.  Together you can develop nice vector graphics that animate over time, and the user can interact with them via callbacks into ActionScript code.  It’s a nice combination of technologies, but it takes some getting used to.

But for all it’s niceties, SWFtools is a pain.  SWFTools comes with a "SWF Compiler" called SWFC.  It’s capable of taking "SC" files and compiling them into flash animations.  It works surprisingly well.  The real problems manifest in a few different areas,s ome of which are just ActionScript/SWF and some of which are unique to SWFC (I think).  After many trials and tribulations, however, I finally got the flash widget (now visible at the top of viz.hpc.mil) working.  I did find a few deficiencies in SWFc compared to the full Adobe Flash Package:

  1. SWFC seems to not have all the SDK stuff that the Adobe Flash package has.  Because of this, you can’t do "import"’s, classes, or many of the other fancy objects in your ActionScript.  For me, it was the loss of the XML classes that caused a problem.
  2. There seems to be some problems in the "tween" algorithms.  Specifically:
    1. At one point, the transitions between the pictures faded to black.  I would fade the existing image to alpha=0%, then fade the next image in from alpha=0% to 100%.  For some reason, the colors were all messed up during the transition and would suddenly "Pop" to the correct image right when it hit alpha=100%.  I changed it to smoothly fade between the 2 images (what you see now, no black in the middle) and now it’s fixed.
    2. While I was trying to fix that, I changed it to "scroll" the images in from the left by animating from x=458 to x=0, then from x=0 to x=-458.  For some reason, the images wouldn’t go to x=0, but rather x=15.  So I tried setting them to x=-15, and then they scrolled 15 pixels off the left.  Never could get that to work right.
  3. Alot of the examples on the net for ActionScript use Explicit type casting in the form "var mc:MovieClip = createEmptyMovieClip(blah)".  That syntax isn’t recognized in SWFC. Simply say "var mc = CreateEmptyMovieClip()".
  4. "Text" objects (created via .text) cannot be changed once they’re created.  Alot of the code online uses ActionScript to create the text fields at run-time, but then I couldn’t get the SWF fonts to work.  I finally had to compromise by just created 5 different text objects & fading between them.

#4 was probably the biggest hurdle I ran into.  Being a programmer, I approached the problem with the mindset that I would need 5  buttons, 1 text label, and 1 image area, and then I could just update them as needed.  It seems the "Flash Way" of doing things is to create 5 images and 5 textlabels, and then lay them out like frames in a movie with smooth fades.  It works, but it takes a different mindset to think "flashy".

So, with all that figured out, click on through for the Code it takes to make this work.
[page_break]
Being a Programmer, I treated this like writing a program rather than creating an animation.  Therefore, I first created a Makefile structure for compiling files with SWFC.  For your use, it looks something like this:

SWFC = /viz/home/rhand/src/swf/swftools/src/swfc -v

all: main.swf

main.swf: Hanzei.swf main.sc
Hanzei.swf: Hanzei.ttf

clean:
    rm -f *.swf

.SUFFIXES: .swf .sc .ttf
.sc.swf:
    @echo Compiling $<
    $(SWFC) -o $@ $<

.ttf.swf:
    @echo Converting $<
    font2swf $< -o $

Makefile for SWFC

The bottom of that is the important part.  It defines 2 compiler rules.  First is a rule for compiling SC files into SWF’s.  The second is a rule for converting TTF Fonts into SWF Fonts.  You can look up top and see I compile my "main.sc" with the HanzeI (Hanze Italic) font to make my animation.  The actual script for the animation looks like this:

.flash fps=30 bbox=457×172 compress

.font Hanzei "Hanzei.swf"
.box bg width=457 height=40 color=white fill=white
.box boxNorm color=white fill=#bbbbbb width=30 height=20
.box boxOver color=white fill=#dddddd width=30 height=20
.box boxDown color=white fill=#ffffff width=30 height=20
.box boxUnder color=blue fill=blue width=34 height=24

.button normal_button
    .show boxNorm as=idle
    .show boxOver as=hover
    .show boxDown as=pressed
.end

.sprite text
    .text img1Desc font=Hanzei text="Amethyst Cluster" color=black size=25%
    .text img2Desc font=Hanzei text="Field Fortifications" color=black size=25%
    .text img3Desc font=Hanzei text="EnSight 8" color=black size=25%
    .text img4Desc font=Hanzei text="Breaking Waves" color=black size=25%
    .text img5Desc font=Hanzei text="ParaView" color=black size=25%
    .put img1Desc x=230 y=160 alpha=100%
    .put img2Desc x=230 y=160 alpha=0%
    .put img3Desc x=230 y=160 alpha=0%
    .put img4Desc x=230 y=160 alpha=0%
    .put img5Desc x=230 y=160 alpha=0%

    .frame 90
        .change img1Desc alpha=100%
    .frame 105
        .change img1Desc alpha=0%
        .change img2Desc alpha=0%
    .frame 120
        .change img2Desc alpha=100%

    .frame 210
        .change img2Desc alpha=100%
    .frame 225
        .change img2Desc alpha=0%
        .change img3Desc alpha=0%
    .frame 240
        .change img3Desc alpha=100%

    .frame 330
        .change img3Desc alpha=100%
    .frame 345
        .change img3Desc alpha=0%
        .change img4Desc alpha=0%
    .frame 360
        .change img4Desc alpha=100%

    .frame 450
        .change img4Desc alpha=100%
    .frame 465
        .change img4Desc alpha=0%
        .change img5Desc alpha=0%
    .frame 480
        .change img5Desc alpha=100%

    .frame 570
        .change img5Desc alpha=100%
    .frame 585
        .change img5Desc alpha=0%
        .change img1Desc alpha=0%
    .frame 600
        .change img1Desc alpha=100%
.end

.sprite toolbar
    .put bg y=132 x=0 alpha=50%
    .put boxUnder x=8 y=140
    .put b1=normal_button x=10 y=142
    .put b2=normal_button x=50 y=142
    .put b3=normal_button x=90 y=142
    .put b4=normal_button x=130 y=142
    .put b5=normal_button x=170 y=142
    .action:
        function SetPoint(x) {
            _root.transition.gotoAndStop(x);
            _root.toolbar.gotoAndStop(x);
            _root.text.gotoAndStop(x);
            _root.stop();
        }
        b1.onPress = function() { SetPoint(3);   };
        b2.onPress = function() { SetPoint(123); };
        b3.onPress = function() { SetPoint(243); };
        b4.onPress = function() { SetPoint(363); };
        b5.onPress = function() { SetPoint(483); };
    .end
    .frame 90
        .change boxUnder x=8
    .frame 120
        .change boxUnder x=48
    .frame 210
        .change boxUnder x=48
    .frame 240
        .change boxUnder x=88
    .frame 330
        .change boxUnder x=88
    .frame 360
        .change boxUnder x=128
    .frame 450
        .change boxUnder x=128
    .frame 480
        .change boxUnder x=168
    .frame 570
        .change boxUnder x=168 alpha=100%
    .frame 585
        .change boxUnder alpha=0%
    .frame 586
        .jump boxUnder x=8 alpha=0%
    .frame 600
        .change boxUnder x=8 alpha=100%

.end

.sprite transition
    .box whitebg color=white fill=white width=457 height=172
    .jpeg img1 "img/amethyst.jpg" quality=80%
    .jpeg img2 "img/fort.jpg" quality=80%
    .jpeg img3 "img/ensight.jpg" quality=80%
    .jpeg img4 "img/ship.jpg" quality=80%
    .jpeg img5 "img/paraview.jpg" quality=80%
    .put whitebg x=0 y=0
    .put img1 alpha=100%  x=0 y=0
    .put img2 alpha=0%  x=0 y=0
    .put img3 alpha=0%  x=0 y=0
    .put img4 alpha=0%  x=0 y=0
    .put img5 alpha=0%  x=0 y=0
    .action:
      img5.onPress = function() {
          frame = _root.movie._currentframe;
          url = ‘javascript:alert(‘ERROR’);’;
          if (frame < 105) {
              url = "https://visualization.hpc.mil/article.php/2007040212570538";
          } else if (frame < 225) {
              url = "https://visualization.hpc.mil/wiki/index.php/Shock_Conditions_in_Field_Fortifications";
          } else if (frame < 345) {
              url = "https://visualization.hpc.mil/ensight";
          } else if (frame < 465) {
              url = "https://visualization.hpc.mil/wiki/index.php/Breaking_Waves_around_a_Ship_3";
          } else {
              url = "https://visualization.hpc.mil/paraview";
          }
          this.getUrl(url);
      };
    .end
    .frame 90
        .change img1 alpha=100%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=0%
    .frame 120
        .change img1 alpha=0%
        .change img2 alpha=100%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=0%

    .frame 210
        .change img1 alpha=0%
        .change img2 alpha=100%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=0%
    .frame 240
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=100%
        .change img4 alpha=0%
        .change img5 alpha=0%

    .frame 330
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=100%
        .change img4 alpha=0%
        .change img5 alpha=0%
    .frame 360
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=100%
        .change img5 alpha=0%

    .frame 450
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=100%
        .change img5 alpha=0%
    .frame 480
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=100%

    .frame 570
        .change img1 alpha=0%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=100%
    .frame 600
        .change img1 alpha=100%
        .change img2 alpha=0%
        .change img3 alpha=0%
        .change img4 alpha=0%
        .change img5 alpha=0%
.end

.put transition x=0 y=0
.put toolbar x=0 y=0
.put text x=0 y=0

.end

So, that’s it.  it’s a pretty big SC file, so let me break it down for you:

  • At the top is just basic initialization.  I build and define what a Button is, and load the font.
  • Next I define the "Text" sprite.  That’s a simple animation that simply contains the text descriptions for my 5 entries, and animates a smooth fade in/out transition between them.
  • Next I define the "toolbar" sprite.  That’s the white bar at the bottom.  It contains the 5 buttons, and the blue-box that moves behind them highlighting the current image.  Also, I use a bit of ActionScript to set the "OnPress" event for each of the 5 buttons to simply jump to a certain point within the various timelines.  The code is pretty self-explanatory, but I essentially just call "gotoAndStop" for each MovieClip, and then call "stop" on everything.
  • Next is the "Transition" sprite, which fades between the 5 images.  I define an "onPress" event for one of the images (It seems ActionScript passes events through objects until it hits something, so only 1 image needs the callback since they all overlap) that decides the URL to load based on the Frame Number, and loads it.
  • Finally, I put all the objects on the screen. At one point I was creating Movieclips for each sprite, so that I could use use the 2nd argument (the integer) to define what level each object is in, making sure that the Toolbar is on top of the Transitions, and the Text is on top of the toolbar.  That really increased the CPU load tho, (I think I wound up having every sprite animating twice on the screen, making the transitions pretty nasty) and was unnecessary.

The result is pretty good.  I had hoped to make it a bit more "dynamic" by having it load a list of Images/Descriptions/URLS from JavaScript Parameters or an XML file.  Unfortunately, I was never able to figure out how to load these images a Run-Time.  I had several people try to help me, but they were all Adobe Flash folks and were pretty unfamiliar with the intricacies of SWFC.  This way works, and even though the 5 JPG’s are about 80K a piece, the resulting SWF file is only 75K.  The compression is pretty impressive. The CPU Usage on the final SWF is pretty high too, but that seems to be the case for any Flash animation. 

So I’m pretty happy.  I have a nice programmer-friendly way to generate SWF’s.  I can do all my editing in VI, and then run "make" and I’m done.  Open-source triumphs again :)