This week I have been posting tiny JungleDragon updates based on the progress I made last week. I sure hope you are not getting tired of these updates yet, because I’m not done :)

Today’s topic is untagged images.

Tags are an important way to find and browse images in JungleDragon, so it sucks when an image has no tags. Instead of frustrating users by making tags required, I have a different strategy:

  • Tagging an image is rewarded with karma points
  • With enough reputation, you can even tag images of other users
  • I make tagging as easy and fun as possible

Let’s talk about the fun and easy part, which I improved greatly last week. From the general tags page, one can navigate to the Untagged page, which looks like this (click to enlarge):

Essentially, it looks mostly like all other image lists in JungleDragon. Difference number one is that it is much more simple, it rids of all image details and actions, only the title and image is shown. The other difference is that it frames images that you are allowed to tag as orange. In this screenshot it has framed all images, because I have administrator rights. Normal users will see the orange frame if:

  • They own the image
  • They have earned the “Image moderation” power, allowing them to edit details of all images

Now, in normal image lists clicking on the image brings you to the image page. In the Untagged list, it brings up a popup for inline tagging:

And if we click “Save”, we are rewarded and the image we just tagged dissapears from the overview:

Like normal image edits, all history is kept so things can be undone by owners and there is a cap on how many edits one can do within the hour or day.

Why is this so important?

I should have created a video to demonstrate this approach. Tagging a lot of images like this is super easy, super fast and dare I say it, fun. It feels like a game. This means that even in a worse case scenario, where users hardly tag their images, it won’t be a royal pain for administrators to do it for them. Users happy, admins happy.

The Mechanical Turk in action :)

Last week I spent an entire week of leave on JungleDragon development.
This week I will be sharing the progress in little bits and pieces.
This week’s 4th update is about Tag history.

JungleDragon followers know that every action that a user makes is recorded in their karmalog. The resulting activity stream is displayed on the user’s profile. What is new is that tags now also have an activity stream called the tag history (click to enlarge):

The screenshot shows the tag “Animals”. Normally, you simple see the images inside this tag. However, on the screenshot we’ve opened the “History” tab. This tab shows the tag’s activity, including its creator, most valuable contributors and every imaged added to it as a historic entry.

I fully realize this is a nice-to-have feature. I think it can be of value mostly for enthusiasts who are fanatic about a particular topic.

Once again, please ignore the grey tags in the tag bar. This is subject to a future article.

Last week I spent an entire week of leave on JungleDragon development.
This week I will be sharing the progress in little bits and pieces.
This week’s 3rd update is about User display modes.This update is quite similar to yesterday’s update where I demonstrated tag display modes. Nevertheless, here is how it works…

JungleDragon has a dedicated page that allows users to find other users (click to enlarge):

From this page, users can browse, sort and search for users. On the right, one can see who they are following, if signed in. The users in the screenshot above are visualized as mini users, showing their avatar, name and level in the reputation system. This small display of users allows for a lot of entries on one page.

As of now, it is possible to view users in a secondary display mode: user cards. Here is the same list of users in the user card display mode:

In user card mode, more detail of a user is revealed:

  • Avatar
  • Level
  • Class
  • Username
  • Summary of age, location, gender, if filled out by that user

As with tag display modes:

  • the prefered display mode can be saved by members
  • how many entries they see per page depends on reputation
  • search supports search highlighting

All in all, JungleDragon allows users to view images, tags and users in one’s preferred display mode in one consistent, accessible experience. I hope.

Tomorrow I will talk about tag history. Stay tuned!

Last week I spent an entire week of leave on JungleDragon development. This week I will be sharing the progress in little bits and pieces. Today’s topic is Tag display modes.

Tags are visible across Jungledragon in various places. They are one of the primary ways to navigate content. The dedicated tags screen currently looks like this (click to enlarge):

Note: please do ignore the tags above the search bar, this is food for another forthcoming article.

This screen provides a way to browse, sort and search tags. As you can see, tags are visualized in a table and are all of equal size. What’s new is that JungleDragon now supports two additional display modes for tags. You will find these to the right of the sort bar.

The first new display mode for tags is “Cloud”. This does what you expect, it visualizes tags in different sizes based on tag popularity (click to enlarge):

And of course, sorting and searching works in this tag display mode too. Finally, the coolest and most powerful tag display mode is “Pictures” (click to enlarge):

I’m finding this last display mode to be very usable. For each tag, the most popular image within the tag is visualized as a thumb. Quite a distinguishing feature, especially when combined with type ahead searching.

As with image lists, members are able to save their preferred display mode for tags. From there on, they will always see tags in their preferred display mode. Like image display modes, tag display modes are integrated into the reputation engine: The better your reputation, the more you see per page. Of course you will see a good set of results even without being a member.

Finally, the Tags screen now also supports search highlighting (click to enlarge):

All in all the new tags screen provides a powerful blend between browsing and searching for tags. Do you agree?

Tomorrow I will have a similar post, this time talking about user display modes.

Last week I spent an entire week of leave on JungleDragon development. This week I will be sharing the progress in little bits and pieces. Today’s topic is friendly URLs.

Friendly URLs are considered to be quite important nowadays, and for good reasons:

  • SEO (Search Engine Optimization). The more descriptive your URL, the better the indexing.
  • Usability. Friendly URLs are more usable, recognizable and memorable by users, also in bookmarks and print.
  • Architecture. Friendly URLs can hide the back-end technologies used for the web application.

Luckily, the framework that I am using to develop JungleDragon (CodeIgniter) supports friendly URLs out of the box. For example, a URL like this…

http://www.jungledragon.com/image/view/123456

Will call the “View” method of the “Image” controller and pass in the value “123456″. All of this is default behavior, which can be overruled and refined in the routes file. From there it is easy to make the above URL slightly better:

$route['image/(:any)'] = “image/view/$1″;

This makes the URL look like this:

http://www.jungledragon.com/image/123456

We have gotten rid of the unneccessary “View” URL segment. For long I stopped here. I knew it would be better to include the image title in the URL, but I had this unexplained worry that it would take a lot of effort to encode and decode that title to look up images, especially considering I am supporting UTF8.

This post from Jake Howlett was a breakthrough in my thinking. There is no need to substitute the numeric id with the title to look up images. We can simply combine them like so:

http://www.jungledragon.com/image/123456/eagle-in-mid-air.html

This can easily be accomplished with the following routing rules:

$route['image/(:any)/(:any).html'] = “image/view/$1″;

$route['image/(:any)'] = “image/view/$1″;

Basically, these rules say: “I do not care what you place behind the image id, the image id will always be used as the lookup key”. Therefore we can place the image title behind the key to create truly friendly URLs. Note that in CodeIgniter, there is a function to create URL safe titles: url_title().

I have implemented the above URL scheme for images, tags, users, pages and classes.

As previously announced, I’m currently working on the JungleDragon homepage. The current status is that it is nearing completion. Have a look at the screenshot below (click to enlarge):

Here’s whats going on:

  • The homepage shows images that are recently made popular.
  • A popular image is not just determined by its sorting. It is an official event. A scheduled service checks recent image behavior and when conditions are met, it is made popular. This also leads to a karma event and thus a reward for the image owner.
  • As discussed earlier, the homepage is set up Digg-style, however note that the first image in the list is shown large.
  • You can directly vote from the homepage, unless it is your own image or when you have already voted.
  • Each entry has basic image details visible. Note the mini users, combing their avatar and level.
  • The popular tab has 4 different filters to check for recent popular images, but also images popular in the last week, month and all time.
  • The second tab is called “fresh”. It shows the newest uploaded images, regardless of popularity.
  • The third tab is called “surprise”. This showcases a set of random images, no matter their date or popularity.
  • The right column shows a general JungleDragon intro, followed by the most popular tags and users.
  • The right column is context sensitive. If you switch to the “fresh” tab, you will get fresh tags and users. Likewise for the “surprise” tab.

You like?

The devil is in the details. That’s how I try to approach designing JungleDragon. One such detail is the “newness” indicator. The newsness indicator is a simple image decoration that is layed on top of all images that are newer than x seconds old (I can configure this, currently it is set to 1 day). The overlay sits in the corner, works on all image formats and is reasonably unintruisive:

Although this is a tiny design detail, it is actually quite useful. No matter the context of your image browsing, you can immediately distinguish new content from older content, whilst not wasting screen estate.

How it’s made

There is no need for me to explain in detail how this effect is accomplished, somebody else did it far better than I ever could: Decorate your images with CSS. The short version of that article:

  • Create the image you would like to overlay (most likely a png with alpha channel)
  • Include its markup below the image you would like to decorate
  • Set the positioning of the parent (most likely an a href link) to relative
  • Set the positioning of the decoration image to absolute and position it into place

Cool, eh?

In JungleDragon, you can vote comments up and down. The thinking behind this is that comments have a high chance of being rude, inappropriate, offtopic or spam. Just check the average Youtube comment thread to see what I mean. By allowing the community to downvote comments, inappropriate comments will be collapsed.

As for images, you can only vote those up. If an image is not good or popular, it will simply not get upvotes which will make it fall into oblivion. It will still be there, but it will typically not appear at the front of image lists.

User reporting

We all know from experience how trolls and spammers can ruin a community experience. Downvoting all their comments is laboursome and does not solve the issue in any structural way. That’s why I build in a “Report” function, where users can report other users for inappropriate behavior. Here’s how it works. When you visit another user’s profile, you will see the “Report” button:

When clicking on the report button, a lightbox dialog appears where the user can send the report:

As you can see, one can choose for one of the predefined reasons and add a remark. Sending a report like this is completely anonymous, the user you are reporting will not see it. It will also not have any effect on reputation. Instead, an administrator will manually check upon reports like this and take action where needed. Clearly, not liking another user is no valid reason for action, only when a user is seriously misbehaving action may be taken.

Image reporting

The user reporting functionality is designed to keep the community user base healthy. The image reporting functionality works in a similar way. However, it is there for an additional reason. The most important one is of a legal nature. It may be so that users are uploading images for which they have no license. The image report function will allow image owners to submit a takedown notice. It can also be used to report an image for other reasons:

As you can see, an image report can be submitted for various reasons. It is not intended to downvote images though. It is intended to report inappropriate images. Images that do not belong there. Like the user report function, the image report function is anonymous and has no effect on reputation.

JungleDragon news is slow recently. Rest assured, I’m pushing the project forward as much as I can. I am currently working on a cluster of features that cost me a lot of time and are hard to discuss before fully done. Hereby a quick teaser (click to enlarge):

You’re looking at an early implementation of the JungleDragon homepage:

  • As you can see, I have chosen for a Digg-like approach. The reason for this design is that I find that approach to be a proven solution for the showcasing of both new and popular content.
  • We’re currently looking at the upcoming tab, showing new images not yet made popular. Notice the detail in the vote control, user reputation and “new” indicator.
  • There is also a “popular” tab. Images become popular when they meet certain conditions. This is an “official” event, a scheduled service checks for new popular images and promotes them to the homepage. If your image becomes popular, karma is rewarded to you.
  • The third tab, called “random”, is a little gimmick that serves a random list of images. There’s a button “surprise me again” to serve a new random list. A fun and unexpected way to find content, no matter their popularity or age.
  • In the right sidebar you see a simple introduction block and a block with the most popular tags. This will be extended with recent user activity and/or most popular users, and perhaps a “tips” console.
  • Although users cannot vote down images (unlike comments), I will develop a way to report images. This will be useful to report spam, duplicates, copyright infringements, etc.

It is going to take me several weeks to implement this cluster of functionality. Yet, when done, I will be close to a first beta testing program.

I’m currently working on a part of JungleDragon that is really hard to explain or demonstrate, but I will give it an attempt nevertheless. It’s about the KarmaEngine.

What is the KarmaEngine?

The KarmaEngine is the part of JungleDragon that hands out rewards (karma points) to users based on their actions, both active and passive. You could see it as black box where you input an event and its parameters, and it will output the associated reward. This reward will determine a user’s level and class in the reputation system. A user’s place in the reputation system is their badge of honour, but also gives them a certain influence and access to exclusive features.

How the KarmaEngine works is best explained by a few example events.

Example I: The one-time event

A user joins the site and gets an initial reward of 100 karma points. This is the simplest event type. The action can occur only once and karma is handed out only once. The amount of karma to reward is fixed, not depending on context.

Example II: The one-time reward event

A user edits his profile and is rewarded 50 karma points. The user edits his profile again and earns 0 karma points. This is an event that can take place multiple times yet there is a cap on the handout of karma points. Unlike the previous event, the KarmaEngine needs to know the context of the event, in this case the number of times the user has edited his profile.

Example III: The parameterized event

A user uploads an image. His reward depends on the license type he has indicated for the image. This is a parameterized event. This event is different from the previous event in that the reward is repeatable. Still, here too the KarmaEngine has caps in place to prevent abuse. The user will face an upload quota that can be set per hour, per day and based on his reputation.

Example IV: Objects have karma too

Karma is designed to indicate a user’s reputation, but objects have karma too. The reason is simple. Imagine you upload an image and through votes and comments of other users you earn 500 karma points with it. Next, you delete the image. This is a karma leak. The KarmaEngine needs to have a memory so it can undo karma when needed.

The delete image scenario is reasonably simple, but other object karma scenario are not. For example, in JungleDragon it is possible for some users to edit the details of images of other users. However, an image owner can undo such an edit. In this case, the KarmaEngine needs to walk down the path of history to see who earned what karma and undo it. Believe me, you do not want to implement this seemingly simple case.

Example V: Passive events

The events discussed so far were active, triggered by the current user. However, passive events can earn you karma too, in fact they may earn you the most karma. Imagine you have uploaded an image and another user votes on it, comments on it or favorites it. This is a passive event for the image owner which earns him karma. The amount of karma handed out depends on the reputation of the active user.

In practice, a simple vote on an image is more complex then you might expect. Both the image owner and the voter gets karma. Yet, there are anti-gaming mechanisms at work too. Plus, the voter’s reputation is weighted in as well. And if this concerns a negative vote, the image owner’s vote defense power, which is based on his reputation, plays a role too.

Throttling and capping

Any reputation engine needs good anti-gaming alghorithms. When you hand out rewards, some will misuse and abuse that. There is no magical formula to completely get rid of the problem, but JungleDragon uses a combination of the following:

  • Administrator moderation. Manual.
  • Community moderation. Spammers and abusers will be voted down or reported. Manual, but many hands make light work.
  • Automated throttling, this is where the KarmaEngine steps in.

The KarmaEngine is flexible in its throttling. For example, let’s say I want to encourage user to make comments. I configure the KarmaEngine to hand out 5 karma points for each comment made. Without any throttling in place, some users may make a large quantity of comments for the sake of earning karma. Since I cannot automatically seperate “good” users from “bad” users I can set a maximum of comments per hour and per day. This will stop the extreme abusers. The rest will hopefully be picked up with the community by downvotes, undoing the false karma earned. Finally, administrators will be easily able to spot the trolls.

The cool thing about the KarmaEngine is that all of this can be configured. If the above strategy does not work in practice, I can reduce rewards (or even set it zero), tighten caps, or both.

The KarmaLog

As I mentioned, the KarmaEngine has a memory, although it is loosely coupled from the reward part. Every reward handed out, even if the reward is zero,is logged along with its details. This is not only needed for the sake of karma data consistency, it is also used in the UI. Similar to sites like Facebook and Twitter, JungleDragon has activity streams, sometimes called “rivers”:

These “rivers” are basically a formatted output from the KarmaLog, filtered by a user. I can use them on objects too, for example to show the activity stream of an image or tag.


The KarmaEngine in numbers

  • There are 23 different events currently. I expect this number to grow over time.
  • When you earn karma you will sometimes be promoted to the next level. There are 70 levels.
  • Every few levels you will be promoted to a higher class, giving you more influence and access to power features. There are 12 classes divided over the 70 levels.

I can completely configure all of the above using data only. I can make a linear or a curved reputation system.


How does it work really?

For those of you curious about the implementation of this KarmaEngine, here are some details. The KarmaEngine houses an enormous functional power and can lead to complex scenarios, but this is not reflected in its design. You will be unimpressed.

The KarmaEngine consists of two PHP class files. The first one, the actual KarmaEngine, is a dumb class containing many constants and formulas. It is dumb in that it does not know anything about where things are stored. It is up to the calling code to tell the KarmaEngine the context. Next, the KarmaEngine class answers with a reward. The second class is the KarmaLog class. This class is used to retrieve and write karma log entries.

Summarizing, this is the typical sequence of events:

  • A event takes place in the system
  • The controller has the logic to capture the event details and parameters
  • The controller asks the KarmaEngine the reward to assign
  • The controller uses the reward to call the KarmaLog class, which will persist the event and reward

It works surprisingly well. This design leads to more complexity in the calling code but that is entirely appropriate given the initimate complexity of the different event types. It feels good keeping the reward part entirely seperate.

The community design dashboard

Everything that I just talked about: rewards constants, formulas, throttling, class-based features, the distributions of levels and classes are all configurable from a single place. It has no UI, but it is a single file. I experiment with values outside the source code in a spreadsheet…

… and then set the constants in the actual KarmaEngine. When you think of it, this “dashboard” is a community design dashboard. It has the capability to promote desired behavior and prevent undesired behavior. Of course, you cannot create a community without actual users and content, but once you have that, this dashboard steers it.

This, my friends, is the KarmaEngine. I hope I did not bore you with it.