
I have always been interested in various “buns” for social networks in terms of marketing. Namely, how quickly this next nonsense will go into mass use and how much effort will be spent to achieve this effect. Below I will tell the result of what I learned from the example of our last work,
vkomg.comFor several years I have been working as a freelance in an American web development company. The work is quite standard for the average freelance desktop: refinement of the curved code inherited from the past developers of the project, buns and plugins for CMS, sometimes quite large-scale startups. All this, of course, is good. But it has long been known that small, seemingly useless things do not bring the return much more. Therefore, one day, after seeing new profiles on Facebook, we developed a service for creating the next
useless funny avatar effect.

A couple of days ago, when I saw that exactly the same block appeared on my native VKontakte with photos near the main photo, we had the idea to remake the existing Facebook project
on VKontakte on the very first day.
Having achieved quite interesting results in the United States, without having laid out any funds from one’s own pocket for promotion, starting with just one link in one’s own profile, it became very interesting what results Russia would show.
Specific figures, history, results and pieces of code in the continuation of the post.
UPD: Habraeffekt in action. We swear with technical support for non-compliance with the promised maximum load of reality.UPD2: Hoster corrected. The server is in full health.')
Where to begin?
PHP was chosen as the language for developing the first Facebook version. Already had the baggage of ready-made pieces of code, and the launch of previously other analogues was one of the main requirements. This was the main reason for choosing this language.
The main features and requirements were:
- Ajax download photo file with progress indicator;
- Preloading interface elements for greater user convenience;
- Easy opportunity to position the mask on the photo;
- Preview;
- The ability to download finished photos in one archive;
- The ability to display photos horizontally without reloading the page;
- The absence of any material investment in advertising.
Mask and file format
The heart, of course, is far from the crop photo script, but the JS mask, which allows the user to visually select exactly that piece of the picture that will be used as a future userpic.

Of course, like any other lazy developers, we rushed to look for ready-made scripts that could be refined to exactly the functionality that we need. After viewing a few dozen pages issued by various search engines, it became clear that you would have to write your own mask from scratch. All ready-made solutions were either very crooked, or they required no less time to finalize them than writing their own script from scratch. Everything was done in a crazy rush, so about the design of the mask in the form of a normal, adequate plug-in for jQuery could not speak. After the main functionality is completed, I plan to rewrite the script from scratch in the form of a normal jQuery plugin with the possibility of easy use in subsequent products.
The next interesting, but rather simple task in solving the problem was to flip the photo horizontally. It was necessary to do this without reloading the page and, without any additional preprocessing of the photo on the server and with the support of all browsers. The solution came pretty quickly. Reflection is done by simply adding this css class to the photo container.
.flip-x {
-moz-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
-o-transform: scaleX(-1); /* Opera */
transform: scaleX(-1);
filter: fliph; /* IE */
}
In practice, I easily made sure that this method works fine in all browsers, including Opera and IE. Nevertheless, this method has one major, but very insignificant disadvantage. If you apply this class to the img tag, then when you try to save a picture with the browser, the unreflected original will be saved.
All server image conversions are performed using
ImageMagick . Horizontal reflection, for example, is performed as follows:
system("convert -flop /path/to/file/original.jpg /path/to/file/tmp.jpg");
Also, thanks to ImageMagick, it's easy to get support for a huge number of formats. Not only standard jpg, gif and png. Since the user receives jpg as a result, it makes sense to use the converter at the photo upload stage.
system("convert /path/to/file/original.ext /path/to/file/out.jpg",$result);
if ($result===0) {
// .
}
Loader
The process of uploading photos is also an important point that should be given enough attention. Since everything was created in a terrible hurry, the first version of the bootloader was an elementary enctype = "multipart / form-data" form containing two elements: a file selection field and a submit button. Already on the first day, we started receiving messages from users complaining about the inability to download the file. After analyzing the messages, it turned out that they can be divided into 2 categories:
- "I click to download the file, but it writes to me that you first need to choose a file, but how can I choose it, if I can't even download anything?" (Yes, yes ... utter nonsense, but do not underestimate the folly of users, these people clicked the submit button, not selecting the file in the first field. They believed that you first had to click the “Upload photo” button, which led to an inevitable error, which they were unable to comprehend)
- “I select the file, click on“ Upload photo ”and everything hangs. Why? (The user is trying to upload a file that is too large in size, or its connection speed is rather low)
The solution to this problem is obvious. The fact that the lack of a normal bootloader will undermine usability was also obvious from the beginning, but haste, as always, spoils everything. Unimportant, at first glance, moments will cause many problems in the future.
To fix the situation, a jQuery plugin called
Uploadify was used .

The plugin makes it easy to implement file loading with an indicator of the loading process. The method is fairly standard: using an element on flash for asynchronous data transfer. The main advantage of this plugin is ease of configuration (a huge number of parameters and callbacks) and the ability to customize the appearance using CSS

It should also provide a use case for haters flush. (using the same standard form for users without Flash). The first query to the search engine gives an interesting result: a
library for determining the version of Flash with all sorts of unthinkable methods.
HTML contains two forms at once: the usual multipart and a form with flash elements. The default flash form is hidden from the user's eyes.
if(FlashDetect.installed) {
$('#plainform').hide();
$('#ajaxform').show();
}
Thus, the regular form is easily replaced by the Uploadify form, provided that the end user has Flash.
Preview

Preview is another thing that makes life easier for a simple user. The idea is simple: generate pictures, position pictures with CSS on a universal blank for the background. I will not go into details. The only thing worth mentioning here is the popup script. Most recently, I ran into a product called
TopUp , which showed itself quite convincingly and over the long history of use did not cause any problems.
Preload
To improve the user experience on the form page, it was decided to preload all the pictures used on the mask page (for example, all the TopUp media resources so that the pop-up window appears instantly, without loading before the user's eyes). Moreover, the loading of these elements should not affect the rendering speed of the page with the loader. The first thing that came to mind was uploading images using JS:
function preload(sources)
{
var images = [];
for (i = 0, length = sources.length; i < length; ++i) {
images[i] = new Image();
images[i].src = sources[i];
}
}
$(window).load(function() {
$("#preload").attr('src','preload-step2.php');
preload([
"res/images/preview.png",
"res/images/top_up/dashboard/sprite.png",
"res/images/top_up/dashboard/close_link.png",
"res/images/top_up/dashboard/bottom_left.png",
"res/images/top_up/dashboard/top_right.png",
"res/images/top_up/dashboard/bottom_right.png",
..........................
..........................
"res/images/btn-flip.gif"]
)
});
Watermark
Next came the question of creating a translucent watermark. Remembering how many manipulations are required to implement a watermark with GD, I decided to use the same ImageMagick for this purpose.
system("composite -gravity south -alpha on /path/to/file/watermark.png /path/to/file/profile.jpg /path/to/file/profile.jpg');

Deleting obsolete files
Since the user will take the archive with the result not immediately, but after some time, it is necessary to provide a script for deleting obsolete temporary files. For each user, a temporary directory is created containing all the files for this session. Task: daily delete all directories created more than 24 hours ago.
#!/bin/bash
for i in `find /path/to/dirs/ -maxdepth 1 -type d -mtime +1 -print`; do rm -rf $i; done
Numbers
And now, the most interesting is the result.
No effort or money was spent on promoting the Facebook original. All we did was change our own userpics and published the url in the news feed for our friends to see. However, the Facebook original yesterday reached a traffic of 4,000 unique visitors per day (a very immodest result, for a project less than a month old).

VkOMG began likewise. Change your own avatar and publish your status from a URL + one target advertisement with a budget of 25 rubles, which brought only 50 referrals to the official VKontakte page (namely to the VK page, and not to an external url).
Nevertheless, here are our modest results for 4 days of work:
- 1st day - 24 unique visitors, 56 avatars created.
- 2nd day - 246 users, 542 avatars created.
- 3rd day - 440 unique users, 1408 avatars created
- 4th day - 890 users - 2486 avatars was created.