Saturnboy
 6.3

Going from SVG data to a Degrafa Path couldn’t be easier: just copy & paste. You can watch this video tutorial or you can check out this demo.

But there is one trick for Inkscape: even though the coordinate origin on the Inkscape document is the normal cartesian origin in the bottom left and the y-axis points up, the SVG output always uses the upper left corner of the document as the origin and the y-axis points down (per the SVG Spec, § 7.3).

To demonstrate, I created a new document in Inkscape, set my dimensions to 500 x 500, and placed a simple path (which happens to be a square) in the upper left corner:

square

You can see by the rulers in Inkscape that the square’s origin is at (0,500).

If we save our square and examine the SVG output, we see:

<svg ...>
  <g ...>
    <path d="M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z" />
  </g>
</svg>

If we ignore everything in the file except the relevant path data, we can see the very first path command is M 0,0 which is path-speak for move to (0,0). This is exactly as expected from the SVG spec: upper left is the coordinate origin. The cartesian origin in Inkscape is bogus!

Next, we can just copy the path data from the SVG file and paste it into the data attribute of a Degrafa Path component.

<Degrafa:Path data="M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z">
    <Degrafa:fill>
        <Degrafa:SolidFill color="#EECCEE" />
    </Degrafa:fill>
    <Degrafa:stroke>
        <Degrafa:SolidStroke color="#FF00FF" weight="3" />
    </Degrafa:stroke>
</Degrafa:Path>

Give it a fill color and a stroke color, and we get a pretty purple square. Now I know my Degrafa Path component will have a square in the upper left, because I know my square was in the upper left in Inkscape. Nice and easy.

Files

 6.1
Code
off

The plan is simple, take the nice Degrafa-skinned components from Part 1 and assemble them into a video player powered by the OvpNetStream class from the Open Video Player project.

Design

I knew right away that the design was not going to have any right angles, but I also didn’t want to go with rounded rectangles everywhere. Modern TVs tend to have a lot of soft rounded edges, so I decided to go with a more vintage look. So I fired up Inkscape and got to work:

tv

Implementing the video player design above in Degrafa, the cabinet mapped to a RoundedRectangle, and the screen & antenna became Paths. You can read more about about translating SVG to Degrafa in my Inkscape SVG to Degrafa Path article. But for now, let’s focus on the resulting Degrafa code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
        xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:Degrafa="http://www.degrafa.com/2007"
        layout="absolute">
 
    <Degrafa:GeometryComposition graphicsTarget="{[box]}">
        <!-- Antenna -->
        <Degrafa:Path data="...path data...">
            <Degrafa:transform>
                <Degrafa:TranslateTransform x="15" />
            </Degrafa:transform>
        </Degrafa:Path>
 
        <!-- TV cabinet -->
        <Degrafa:RoundedRectangle y="144" width="350" height="300"
                cornerRadius="20" />
 
        <Degrafa:fill>
            <Degrafa:SolidFill color="#333333" />
        </Degrafa:fill>
        <Degrafa:stroke>
            <Degrafa:SolidStroke color="#FF00FF" weight="4" alpha="0.4" />
        </Degrafa:stroke>
    </Degrafa:GeometryComposition>
 
    <!-- TV Screen -->
    <Degrafa:GeometryComposition graphicsTarget="{[tvscreen]}">
        <Degrafa:Path data="...path data...">
            <Degrafa:fill>
                <Degrafa:SolidFill color="#FF99FF" />
            </Degrafa:fill>
            <Degrafa:stroke>
                <Degrafa:SolidStroke color="#FF00FF" weight="2" alpha="0.4" />
            </Degrafa:stroke>
            <Degrafa:filters>
                <mx:GlowFilter color="#EEEEEE" alpha="0.2" blurX="16" blurY="16" />
            </Degrafa:filters>
        </Degrafa:Path>
    </Degrafa:GeometryComposition>
 
    <mx:Canvas width="350" height="444"
            horizontalCenter="0" verticalCenter="0">
        <mx:Canvas id="box" />
        <mx:Canvas x="50" y="174" id="tvscreen" />
    </mx:Canvas>
</mx:Application>

I ended up using a pair of GeometryCompositions to wrap my three shapes to help keep my fills, strokes, and filters organized. It made sense to do it this way, but I won’t claim it’s the best way. Throw the control bar on below the TV screen, and the design is done.

Backend

The backend is build on the OvpNetStream class provided by the Open Video Player project. OvpNetStream extends NetStream and smooths out some of the rough edges as I discussed previously. Basically, it provides a sane interface (no need to construct a dynamic object with function callbacks) and useful events (like metadata and progress events).

For this demo, we simply instantiate OvpNetStream on creationComplete and wire up all the event handlers:

private function complete():void {
    nc = new OvpConnection();
    nc.addEventListener(OvpEvent.ERROR, errorHandler);
    nc.addEventListener(NetStatusEvent.NET_STATUS, connStatusHandler);
    nc.connect(null);
 
    ns = new OvpNetStream(nc);
    ns.addEventListener(OvpEvent.ERROR, errorHandler);
    ns.addEventListener(NetStatusEvent.NET_STATUS, streamStatusHandler);
    ns.addEventListener(OvpEvent.NETSTREAM_METADATA, streamMetadataHandler);
    ns.addEventListener(OvpEvent.PROGRESS, streamProgressHandler);
    ns.addEventListener(OvpEvent.COMPLETE, streamCompleteHandler);
 
    vid = new Video();
    vid.attachNetStream(ns);
    vidContainer.addChild(vid);
}

The most interesting events are the metadata and progress events. The metadata event delivers the duration of the video and its size. The progress event arrives periodically (theoretically every 100ms by default, but in reality I see them come in just a couple of times per second) and delivers the current video time.

Control Bar

The control bar consists of three components: a play-pause button, a scrubber, and a volume slider. They were skinned using Degrafa in Part 1. In order to control video playback, we need to wire the control bar components to the instance of OvpNetStream created above.

Here are the event handlers for the three control bar components:

// PlayPause event handler
private function playPauseClick():void {
    if (first) {
        first = false;
        ns.play(filename);
    } else {
        ns.togglePause();
     }
}
 
// Scrub event handlers
private function scrubPress():void {
    ns.pause();
    playPause.selected = false;
}
private function scrubDrag():void {
    ns.seek(scrub.value);
}
private function scrubRelease():void {
    ns.togglePause();
    playPause.selected = true;
}
 
// Volume event handler
private function volumeChange():void {
    ns.volume = volume.value;
}

In the playPauseHandler(), the initial click calls play() which actually loads the video (and then starts playback), all subsequent clicks just toggle between play or pause. For the scrubber handlers, I chose to break them up into three separate steps: on mouse down pause the video, on mouse up restart playback, and on drag attempt to seek to the to the new time.

That’s it. Here is the resulting Degrafa-skinned video player (view source enabled):

Flash is required. Get it here!

Click Play to start playing Elephants Dream (which is the “world’s first open movie,” and pretty cool too). Right away you’ll notice some visual issues because the dimensions of the video are unknown until the metadata arrives. Also, scrubbing has some problems which I believe are related to cue points in progressive downloads. Lastly, I didn’t implement any indicators for buffering or download progress, so you’ll need to be patient. Since this is just a demo, I’ll have to leave fixing those bugs as an exercise for the reader.

Files

 11.6

I don’t know how a real designer does it, but when I attempt a design, particularly a blog design, I always start with a simple theme. If the ideas begin to flow, I’ll know I chose well. If not, and I still think it’s a good theme, I’ll visit the usual suspects for some inspiration.

On this blog, I started with robots, which quickly lead to gears and mechanics. For this post, I started with circles. Actually, I started with Ironman’s HUD. The whole movie was super cool, but the HUD was the best. And the HUD had all this motion and targeting, and that’s what got me to circles. So that’s the theme. I already know I’m going to apply this theme to a simple grid-based blog layer that I discussed earlier.

Palette

After the theme, I worked on the color palette. I’ve used Kuler in the past to build out a couple of palettes, but this time I just jumped into Inkscape and started messing around. I came up with a nice blood red and black palette.

palette
Circles

Now that I have a palette, I shift my design focus back to circles. It’s not just gonna be “Dot, dot, dot” as my daughter likes to say, so it’s back to Inkscape. Here’s the result:

circles
Layout

Not much left but the real work – make a cool blog design with circles plus some pretty colors. I know my layout, so once again it’s back to Inkscape. There is a nice Inkscape template generator for Blueprint CSS grid layouts. Choosing which colors go where isn’t too bad, because I love dark text on white for blogs. Following that decision, I go with lots of circles in the header in blood red, over a black background. We know the main content will be white with black text, so I decide to make the sidebar really stand out with a bold blood red.

The circles in the header are really easy, I just pick random sizes and put them in random locations. Darker usually means further away, so I just reduce the opacity to let more black through. I use a rounded rectangle with a thick stroke for the main content area. I also add a black shadow around the entire content area to highlight the content. The finished design is here, and I’m calling it Circles Of Doom. Here is a closeup of the header:

Next, we slice and dice

Files

© 2014 saturnboy.com