inicio mail me! sindicaci;ón

Archive for Projects

Twackr: Twitter-style time tracking

It’s been a while since my last rails post, so i decided to try out something different.

Specifically, i’ve always wanted to track my time, but i never seem to find a solution that works. The solution is either too simple and doesn’t give me any feedback, or it’s extremely complicated and hard to use.

So i set about to make a time tracking solution that was both ridiculously simple to use, and could give me some useful reports back. Thus, Twackr was born!

I modelled the entry system after Twitter: at its simplest, all you need to do is type in what you are doing, and Twackr will start tracking your time instantly. When you are done, simply click on “Finish” and it will be done!

Already spent some time doing something but couldn’t get to Twackr? Then you can backdate entries by adding “-1H“. Still working on something? Then try “-1H+“. Blocking out some time? Then use “+1H“. Want to see if you’ll make the deadline? try typing “1H“.

Time can also be categorised into “Services” (#service) and “Projects” (@project).

You can check out a live demo of twackr on heroku. Just sign up, and check it out – it couldn’t be any simpler!

Like most of my other rails projects, Twackr is Open Source. So feel free to fork it on github.

CSS Transform Exporter for Blender

Following on from Creating CSS Animations, i have decided to release the exporter script used to create the animated orange test guy.

As the title implies, the exporter script runs in Blender. Simply construct a 2D scene using planes, add in an animation track, run the script and click Export. It’s as simple as that!

Each plane is exported as a HTML DIV. If present, any Ipos will be exported as CSS keyframes.

The exporter even supports parenting, so you can build up complex hierarchies of elements which can easily be transformed in an animation, or even javascript.

Note that currently the exporter only supports Webkit-based browsers (i.e. Chrome, Safari, MobileSafari). It also has limited support for Firefox (sans animations).

For the curious, there are 3 examples:

As for the actual exporter script, it’s available on github.

Happy animating!

EDIT: For those of you who for whatever reason want a video demonstration, there’s a video of it in action on youtube.

Creating CoreAnimation Animations

Moving on from Creating CSS Animations, i thought “How can i make this exporter more useful?”.

The answer is of course to completely remove Webkit from the equation, which leaves us with CoreAnimation. The end result being that the animation can be directly compiled into an iPhone or Mac OS X application.

Not going into much detail, CoreAnimation is essentially the library used by Webkit to display and animate any elements which have been transformed by a CSS Transform.

The actual scene is simply constructed using transformed CALayers. As for the animation, a CAKeyframeAnimation is created and attached to each CALayer. In the case of multiple properties being animated at the same time, a CAAnimationGroup is used to group these animations together.

The end result is a handy animation class which creates both the scene and the related animation tracks. i.e.:


    CALayer *root = [self.view layer];

    // Make anim
    MyAnim *anim = [[MyAnim alloc] init];
    CALayer *animRoot = anim.root;
    [root addSublayer:animRoot];

    [anim play]; // easy!

As an example, the MyAnim class for the previously featured walking orange figure is as follows.

Which leads onto a repeat of the question, is there a real-world demand for such a tool yet?

Creating CSS Animations

CSS Transforms combined with animations are undoubtedly useful. Unfortunately though, the only way to create them is to manually input values and pretty much guess the result.

This methodology pretty much kills any creative aspirations anyone might have in making these animations. So while there are quite a few cool looking examples out there they lack the glamour of say, flash animations.

It seems to me there is a need for a tool which allows anyone to create these css animations in a visual way. As far as i know, no such tool currently exists. So naturally, i set about making something myself.

Rather than make an entire tool from scratch though, i decided to simply write an exporter script for another tool – in this case, Blender.

Why Blender? Well, it exposes pretty much all of the information i require to construct both a scene and animation tracks. Also, since Blender handles 3D scenes, there is a potential to work with 3D CSS Transforms in the future.

As an example, here’s a simple animation of an orange stick man walking across the screen. The stick man was both constructed and animated entirely within Blender, and exported using my export script.

example-walk

And the scene as seen in blender:

Example animation in Blender

Which is simply a set of planes linked together and animated. Really, it couldn’t be any simpler.

Currently the only browsers which seem to support both CSS transforms and animations are based off Webkit. i.e. Safari and Chrome (including the iPhone and Android browsers).

Which leads onto the question, is there a real-world demand for such a tool yet?

A Browser within a Browser: HtmlCanvas

It’s been a while since my last truly silly project, so i thought i’d come up with something else.

There has been a lot of talk recently about how the web is essentially replacing desktop applications, which to me sounds great.

But there is something missing from this new age of web applications. In order to run web apps you need a web browser, which is still a desktop app. It seems to me odd that a platform which replaces another still requires that platform to operate.

Which is where htmlcanvas comes in. It’s a HTML renderer implemented in JavaScript, which runs nicely in any capable web browser which supports the Canvas element.

htmlcanvas in action

In essence, it’s a web browser implemented within a web browser. The above example was rendered from this HTML:


<html>
<head>
  <title></title>
</head>
<body><!-- Begin test -->
  <p class="woo" id="render">
Rendering <b>HTML</b>...</p>
  <p><span>In <b>Canvas</b></span>!</p>
  <p>0_0</p>
</body>
</html>

This sort of recursive abstraction is not uncommon in the computing world. For example, C compilers are written in C, Pascal compilers are written in Pascal. There’s even a version of Python implemented within Python. So a web platform implemented within a web platform is quite natural.

Still, it will be a long while before htmlcanvas is remotely capable of running within itself, so a truly recursive web browsing experience is still a long way off.

As with most of my silly projects, the code to htmlcanvas is hosted on github. Fork it here!

Note: Currently only known to work in Safari 4, FireFox 3.5, or Google Chrome.

RailsCollab isn’t Dead

For those of you interested in web-based project management tools, you might have noticed i’ve not really been maintaining RailsCollab for quite a few months now. Why? well because i really wanted to concentrate on other things, such as making cool iPhone apps and the usual contracts.

(Plus to be honest i wasn’t really using it myself)

Still, since its open source other people were free to use and modify it for their own needs. I was pleased to see that there has been a healthy level of forking according to github’s network graph.

fork_graph_rc

Feature-wise, one fork made by scambra has even implemented a fully fledged wiki.

wiki_tab

I’ve also seen partial localisation’s implemented for German and Simplified Chinese. So safe to say, i’m very impressed that despite my lack of updates, RailsCollab is still going strong – all thanks to its growing community!

Now for my input…

Projects like RailsCollab are hardly one-way streets. One has to give back as well as receive contributions.

So i’m pleased to announce that as well as merging the wiki and language updates into the main RailsCollab tree, i’ve also merged in my own updates which convert the Message, Comment, and File controllers into RESTful resource controllers.

Simply put, this means that you can now manipulate messages, comments, and files as XML. e.g.:

/project/1/messages/1.xml


<message>
  <additional-text/>
  <attached-files-count type="integer">0</attached-files-count>
  <category-id type="integer">1</category-id>
  <comments-count type="integer">2</comments-count>
  <comments-enabled type="boolean">true</comments-enabled>
  <created-by-id type="integer">1</created-by-id>
  <created-on type="datetime">2009-07-16T19:35:00Z</created-on>
  <id type="integer">1</id>
  <is-important type="boolean">false</is-important>
  <is-private type="boolean">false</is-private>
  <milestone-id type="integer">0</milestone-id>
  <project-id type="integer">1</project-id>
  <text>It's a *test*!</text>
  <title>Test message!</title>
  <updated-by-id type="integer">1</updated-by-id>
  <updated-on type="datetime">2009-07-16T19:35:16Z</updated-on>
</message>

/project/1/messages/1/comments.xml


<comments type="array">
  <comment>
    <attached-files-count type="integer">0</attached-files-count>
    <author-name nil="true"/>
    <created-by-id type="integer">1</created-by-id>
    <created-on type="datetime">2009-07-17T20:34:12Z</created-on>
    <id type="integer">5</id>
    <is-anonymous type="boolean">false</is-anonymous>
    <is-private type="boolean">true</is-private>
    <text>Test REST comment - edited</text>
  </comment>
</comments>

/project/1/files.xml


<files type="array">
  <file>
    <comments-count type="integer">0</comments-count>
    <comments-enabled type="boolean">true</comments-enabled>
    <created-by-id type="integer">1</created-by-id>
    <created-on type="datetime">2009-07-18T13:22:20Z</created-on>
    <filename>kitten-logo.png</filename>
    <id type="integer">9</id>
    <is-important type="boolean">false</is-important>
    <is-locked type="boolean">false</is-locked>
    <is-private type="boolean">false</is-private>
    <updated-on type="datetime">2009-07-18T13:34:50Z</updated-on>
  </file>
</files>

So what are you waiting for? fork it, use it, enjoy!

Playing Animated GIFs on the iPhone

Following on from my Animated images on the iPhone post, i thought i’d take things a step further.

To re-cap, i pretty much summarised the available options for playing back simple animations on the iphone in this nice table:

Method Problem
Use UIImageView It doesn’t scale
Re-draw a UIView every frame Far too slow
Use GLES Beyond the scope of the last article, but not this one!
Transform a clipped UIView each frame We did that last time

To take things further, OpenGLES needs to be used. Specifically, you need to upload and draw a texture for every frame of your animation.

Now while this sounds like a great idea, there is a slight problem: uploading textures on the iPhone is hideously slow. Excluding the requirements of a video decoder, you only have enough time per frame to be able to playback a small stop motion video in RGB format.

All is not lost though. The iPhone supports two rather interesting texture formats: GL_COMPRESSED_RGB_PVRTC_* which is the native format, and GL_PALETTE* which is, as the name implies is a texture with a palette.

The fastest format to upload is PVR, but unfortunately there aren’t many native video codecs or animation formats about that decode to PVR format. Which leaves us with the palette format, which is just about fast enough to playback something more substantial…

Now which animation format uses a palette and is widely supported? Animated gif!

So to cut a long story short, i ended up writing a fairly elaborate library to decode and playback animated gifs on the iPhone, all in realtime.

Provided the gif is not gigantic (since the bigger the gif, the slower the decode + upload), it’s actually quite useable.

anim8gif

In fact, as a proof of concept i ended up writing an app using this library to playback animated gifs from any website in fullscreen (similar to the youtube app). Feel free to check it out – anim8gif.

The code

The code for this gif animation library, glgif, is located on github. As always, feel free to fork!

What’s New in Rucksack

A while ago, i posted a little piece about my Backpack-inspired organisation tool, Rucksack. At the time, i only just got the basics working, and it was nowhere near “production ready”.

Now, it still isn’t really “production ready”, but it has drastically improved these past few months. In August, it started out looking like:

And now it looks like this:

Which to say the least, is a big improvement.

But “What’s new?“, you may ask. Well apart from the new grey spaced out look…

  • You can now see a general overview of recent activity
  • You can now upload files
  • You can send emails to to pages
  • Basic reminders have been implemented with email functionality
  • Journals and Status (think Twitter) have been implemented
  • Fed-up of the default page width? You can now resize Pages!
  • Pages can now be shared to the public
  • Client-side interface re-written in jQuery
  • Bug fixes and stability improvements

So safe to say, a lot of improvements. But still, a long way to go before it is truly useful for every day organisation.

As always, Rucksack is open source and can be checked out on github.

Cloning Backpack

Just over a month ago now, i got sick of my chief open source project, RailsCollab. Nobody seemed interested in it, and the code was growing tired and deprecated. So i decided to try making another open Ruby on Rails project.

Like my previous chief open source project, i decided my new one was also going to be a clone. Mainly because i couldn’t really come up with anything else more interesting, bu i also wanted to see what it would be like cloning something from scratch.

After much deliberation, i decided the focus of my attention would be to clone another of 37Signals’ products. Not Basecamp this time – that has already been done to death. Instead, i decided to try and clone… Backpack!

Interestingly while i looked far and wide for a comparable product, i couldn’t seem to find anything. The only one that came remotely close was TiddlyWiki. But while that was free and open, i felt it completely missed the niche that Backpack filled. Collaboratively edited pages, which are actually easy to edit.

The nitty gritty

First of all – before i even writ one line of code – i decided to check out Backpack’s underlying data models. They told me a lot about how Backpack worked, and of course they gave me a few hints about what data i should store.

Backpack

Models

(generally created and modified dates exist for all of these) 

Pages
    - scope
    - title
    - email_address

    Belongings (basically reference from page -> list item + position.
                     referred to by id)
    Lists
        - name
        List Items
            - completed
            - content
            - order
    Notes
        - title
        - content
    Seperators
        - name
        - page id
    Tags
        - name
    WriteboardLink
Writeboard
    - title

    WriteboardPages
        - content
Reminders
    - at time
    - content
    - creator
    - remindees [Users]
Emails
    - title
    - content
Statuses (one per user)
    - message (text)
    - last update
    - owner
Journals
    - body (length=255)
    - owner
    - last update
Users
    - name
Calendar
    - color
    - subscription url (pulling from other calendar?)
    - name
    - token (used in url for sharing)

    Events
        - title
        - occurs_at
        - occurs_until
        - reminded_at
        - remind (bool, note fixed time before)
        - all day (bool)

Next i decided to sketch out some of the models. has_many, belongs_to, etc. I also decided to give some models such as the “Belongings” different names, as i thought the originals sucked.

(Note that by this time i decided to concentrate my efforts on making a Page editor, as i felt that was the key defining feature)

After i got that out the way, i built a simple page RESTful scaffold for editing pages. All it did was render page slots and the widgets contained therein. What it lacked was the rather crucial AJAX editing that was prevalent in Backpack.

So then i decided to take a closer look at how Backpack’s AJAX page editing worked. It turned out that there were a few crucial components:

  • The widgets – the real content of the page. e.g. Notes, Lists, Dividers
  • The insertion bar – this pops up when you hover your mouse over the top or bottom of the widgets.
  • The action bar – this pops up when you click “Insert Here” on the insertion bar, and is inserted between the relevant widgets.
  • The actions on the action bar – when you click on them, either a widget is inserted (e.g. list) or a form is shown in the slate.
  • The slate – this either exists in a container before the widgets, or in the action bar. It contains most of the forms.

These components are almost exclusively powered by client-side Javascript. Only when you get to the parts where content is added, edited, or removed from a page do you get an AJAX request sent to the server. e.g. Inserting edit forms, adding widgets and belongings, etc.

What you get back from the server is usually Javascript code which alters the content in the page according to the request.

So once i figured all that out, i eventually managed to implement a rather nifty AJAX-powered page editor which somewhat resembled Backpack’s. Mission accomplished!

The result

Well, here it is. It’s called Rucksack, and it acts similarly to Backpack. You can make pages, and share them with others to edit collaboratively. Strange but true.

Now wait a minute!” you might be thinking, “it looks like crap, and it doesn’t implement everything“. True, but remember that i was only interested in implementing a proof-of-concept page editor. I wasn’t planning on implementing everything and making it look nice. That is for later.

Now while i did start off thinking of Rucksack as a Backpack clone, i don’t think it is the best frame of mind to be in. So for future development, i will be concentrating less on copying backpack, and more on tailoring it to what i think will be useful in organising.

Meanwhile, i have put the code up on github for anyone to check out.

RailsCollab Alpha 3

Hot off the presses, i’ve just pushed alpha 3 of RailsCollab to both Rubyforge and Github.

Railscollab? What’s that?

Railscollab is a re-write of the Project Management solution ActiveCollab (otherwise known as ProjectPier), which instead is written in Ruby and runs on the Ruby on Rails web development framework.

Why on earth would you want to do that?

Good question. Well, it all started when the developer of ActiveCollab announced they were ditching the open source version and going commercial and closed source. Of course, there were people like me that didn’t like that.

So i decided to make my own fork – however i added a twist. I decided to re-write it using Ruby on Rails, since the original PHP code was giving me a headache. Plus it seemed like a great way to get to know the Ruby on Rails framework.

Note that around the same time, another fork called ProjectPier arose, which opted to develop from the original PHP code.

So what’s new?

Quite a lot, actually. Pretty much everything that was present in ActiveCollab 0.7.x is now implemented, sans the the fancy web-based installer. I’ve also focussed a lot on fixing bugs and improving stability, as well as enhancing the time tracking components.

Time tracking with CSV export

… and of course there is the configuration editor which takes advantage of Phusion Passenger.

Configuration Editor

In addition, i have updated the RailsCollab demo, so if you don’t have the time to set everything up, you can still try out Alpha 3.

I’d also like to thank everyone (you know who you are) who has reported issues with RailsCollab over the past few months. Without your help, i doubt i would have had the willpower to make another release.

So what are you waiting for, try it out already. :)

Edit: If you are stuck wondering “How do i login?”, have no fear, the solution is here. You will need to use OpenID to login.

OpenID Logo

Simply select the “Use OpenID” checkbox and type in your OpenID to login. An account should automatically be created for you if one does not already exist, provided that your OpenID provider provides a username, email, and name.

You can get an OpenID from many places – one of my favourites being myOpenID.

Next entries »