Quick Tip: How to Use Zeplin to Generate Style Guides

We previously covered how designers can collaborate with the dev team using Zeplin, but there’s a bit more to it; Zeplin is a great tool for generating style guides too. It makes sure your team creates consistent experiences by having an up-to-date online guide accessible to everyone from anywhere. 

It allows you to save and rename fonts and colour information, and even export CSS. The style guide and the inspect feature will save a lot of effort when the time comes for QA (quality assurance). Let’s quickly see how it works!

Adding Styles

First, select a screen from the project dashboard.

Then select the element whose properties you want to add to the style guide (for example: select H1 title to add its font family, size and colour).

Next, hover over the inspector tool and look for the icon Aa+ which will appear by the text styles to add them to the font book:

selected titles properties in zeplin
Selected title and its properties in the inspector

Adding colours works in a similar way. Click the drop icon next to each one to build your colour palette:

same deal with colours
Same deal, with colours

Your Style Guide

To see your style guide in action, select the second tab Styleguide at the top of the page:

All the previously added elements will be there. You can now go ahead and give each one a more suitable name. To do this, hover over the default colour name and click to change it.

Note: use names and naming conventions which are familiar to the entire team):

Do the same for fonts; update them with a name which designers and devs will both be familiar with. Don’t forget you’re helping with the dev handover, but also creating a repository for other designers to use.

What you’ll end up with is something like this:


At this point, if you’re part of the dev operation, you might want to copy the CSS from the right-hand side column. You’ll find it’s available in whichever syntax you prefer; Sass, LESS, Stylus, or plain CSS.

Each rule can be individually selected for download, whilst Command + A will select everything for copying and pasting. 


No more outdated style guides saved somewhere no one can find, no more chains of emails to find out the latest colour; Zeplin can help your whole team design efficiently. Cheers to productivity!

Download Quick Tip: How to Use Zeplin to Generate Style Guides

New Course: How to Record Better Travel Videos

You often see amazing sights when you travel, but creating a video that other people want to watch is harder than it seems.

In our new course, How to Record Better Travel Videos, you’ll learn how to prepare for and capture the highlights of your trip and tell video stories that are worth watching and sharing! 

What You’ll Learn

Cindy Burgess has been telling stories with video for more than 20 years, and in this course she’ll teach you all about must-pack items, proper recording techniques, how to tell a story through characters, setting and natural sound, how to deal with local customs and culture, how to protect your gear from the elements, and more!

Watch the Introduction

Start Learning With a Free Trial

You can take our new course straight away with a free 10-day trial of our monthly subscription. If you decide to continue, it costs just $15 a month, and you’ll get access to hundreds of courses, with new ones added every week.

You can also find some useful resources for improving your travel videos on Envato Market. There are thousands of professional-looking transitions, backgrounds, overlays, and more.

Download New Course: How to Record Better Travel Videos

Take Our New Course on Dynamic Gesture Drawing

Final product image
What You’ll Be Creating

Want to improve your drawing technique? In our new course, Dynamic Gesture Drawing, digital artist Brian Lee will teach you the fundamentals of gesture drawing step by step. 

You will learn the importance of refining gestures into lines of action and simple shapes, creating strong silhouettes, effectively using negative space, and projecting ideas from a pose rather than just structural anatomy. Finally, you’ll learn how to tell stories with different gestures. By the end of this course you should be able to draw any gesture you want.

You can take our new course straight away with a free 10-day trial of our monthly subscription. If you decide to continue, it costs just $15 a month, and you’ll get access to hundreds of courses, with new ones added every week.

Download Take Our New Course on Dynamic Gesture Drawing

How to Use Ajax With OpenCart

The inclusion of jQuery libraries in the core of OpenCart makes Ajax implementation a breeze and more than a pleasant experience. In fact, you’ll find several snippets spread across the whole framework that show the heavy use of jQuery, if you try to dig into the view files specifically.

Throughout the course of this article, we’ll build a custom page to demonstrate the use of Ajax in OpenCart. It’ll be a simple interface that allows you to select a product from the drop-down box and displays a nice product summary block of the selected product. The interesting part of the use-case is the way the product summary block is built—it’ll be prepared using Ajax on-the-fly. Of course, it’s not something that makes it an out of the world example, but I guess it’ll serve the basic purpose of showing how things work in OpenCart.

I assume that you’re using the latest version of OpenCart, which is 2.1.x.x! Also, the primary discussion of this article concentrates on Ajax with OpenCart, so I’ll skid through the basics of custom module development in OpenCart. However, if you’re not familiar with it, a quick explanation of the code snippets in between makes sure that you can follow till the end!

A Quick Glance at File Organization

Let’s quickly go through the file setup required for our custom page.

  • catalog/controller/ajax/index.php: It’s a controller file that provides the application logic of the usual controller in OpenCart.
  • catalog/language/english/ajax/index.php: It’s a language file that helps set up language labels.
  • catalog/view/theme/default/template/ajax/index.tpl: It’s a view template file that holds the XHTML of the custom page.
  • catalog/view/theme/default/template/ajax/product.tpl: It’s a view template file that holds the XHTML of the AJAX response.

So, that’s a quick list of the files we’re going to implement today.

Create Module Files

Go ahead and create a file catalog/controller/ajax/index.php with the following contents.

// catalog/controller/ajax/index.php
class ControllerAjaxIndex extends Controller {
  public function index() {
    // load all products
    $products = $this->model_catalog_product->getProducts();
    $data['products'] = $products;
    $data['breadcrumbs'] = array();

    $data['breadcrumbs'][] = array(
      'href' => $this->url->link('common/home'),
      'text' => $this->language->get('text_home')

    $data['breadcrumbs'][] = array(
      'href' => $this->url->link('ajax/index'),
      'text' => $this->language->get('heading_title')

    $data['heading_title'] = $this->language->get('heading_title');
    $data['text_product_dropdown_label'] = $this->language->get('text_product_dropdown_label');

    $data['column_left'] = $this->load->controller('common/column_left');
    $data['column_right'] = $this->load->controller('common/column_right');
    $data['content_top'] = $this->load->controller('common/content_top');
    $data['content_bottom'] = $this->load->controller('common/content_bottom');
    $data['footer'] = $this->load->controller('common/footer');
    $data['header'] = $this->load->controller('common/header');

    if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/ajax/index.tpl')) {
      $this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/ajax/index.tpl', $data));
    } else {
      $this->response->setOutput($this->load->view('default/template/ajax/index.tpl', $data));
  // ajax call method
  public function ajaxGetProduct() {
    if (isset($this->request->get['product_id'])) {
      $product_id = (int) $this->request->get['product_id'];

      if ($product_id > 0) {
        // load the particular product requested in ajax
        $product = $this->model_catalog_product->getProduct($product_id);
        $data['product'] = $product;
        // prepare thumb image
        if ($product['image']) {
          $data['thumb'] = $this->model_tool_image->resize($product['image'], $this->config->get('config_image_thumb_width'), $this->config->get('config_image_thumb_height'));
        // format price
        $data['price'] = $this->currency->format($this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax')));
        $data['text_manufacturer'] = $this->language->get('text_manufacturer');
        $data['text_model'] = $this->language->get('text_model');
        $data['text_note'] = $this->language->get('text_note');
        $data['tab_description'] = $this->language->get('tab_description');
        if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/ajax/product.tpl')) {
          $this->response->setOutput($this->load->view($this->config->get('config_template') . '/template/ajax/product.tpl', $data));
        } else {
          $this->response->setOutput($this->load->view('default/template/ajax/product.tpl', $data));

To start with, the index method of the controller is used to load the language and model files and set up the common variables for the usual OpenCart template. We’re loading the product model available in the core itself, so we don’t have to duplicate the code to fetch the product information.

After loading the product model, we’re using the getProducts method to load all the products. Finally, we conclude the index method by setting index.tpl as our main template file.

Next is the important ajaxGetProduct method, which is used to build a product summary block based on the product id passed in the Ajax call, as we’ll see soon in the template file. It loads the same product model as we did in the index method, and calls the getProduct method to fetch specific product information based on the product id.

At the end, the product.tpl template is set as a template for this method. Specific to the requirements in our case, we’re using the template to build our Ajax output, but you could also send the JSON response instead.

Moving ahead, let’s create a language file catalog/language/english/ajax/index.php to hold the static label information.

// catalog/language/english/ajax/index.php
// Heading
$_['heading_title']            = 'Simple Ajax Example';
$_['text_product_dropdown_label']   = 'Select Product';

The view template file, one of the most important files in the context of this tutorial, should be created at catalog/view/theme/default/template/ajax/index.tpl with the following contents.

<!-- catalog/view/theme/default/template/ajax/index.tpl -->
<?php echo $header; ?>
<div class="container">
  <ul class="breadcrumb">
    <?php foreach ($breadcrumbs as $breadcrumb) { ?>
    <li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
    <?php } ?>
  <div class="row"><?php echo $column_left; ?>
    <?php if ($column_left && $column_right) { ?>
    <?php $class = 'col-sm-6'; ?>
    <?php } elseif ($column_left || $column_right) { ?>
    <?php $class = 'col-sm-9'; ?>
    <?php } else { ?>
    <?php $class = 'col-sm-12'; ?>
    <?php } ?>
    <div id="content" class="<?php echo $class; ?>"><?php echo $content_top; ?>
      <h2><?php echo $heading_title; ?></h2>
      <fieldset id="account">
        <label class="col-sm-2 control-label" for="product"><?php echo $text_product_dropdown_label; ?></label>
        <div class="col-sm-10">
          <select name="product" class="form-control" id="product">
            <option>-- <?php echo $text_product_dropdown_label; ?> --</option>
            <?php foreach ($products as $product) { ?>
              <option value="<?php echo $product['product_id']; ?>"><?php echo $product['name']; ?></option>
            <?php } ?>
      <div id="product_summary"></div>
      <?php echo $content_bottom; ?></div>
    <?php echo $column_right; ?></div>
<?php echo $footer; ?>

<script type="text/javascript">
  $('#product').on('change', function() {
      url: 'index.php?route=ajax/index/ajaxGetProduct&product_id=' + this.value,
      dataType: 'html',
      success: function(htmlText) {
      error: function(xhr, ajaxOptions, thrownError) {
        alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);

The snippet of our interest is at the end of index.tpl, the JavaScript code that makes use of jQuery methods to bind change and Ajax events. When the user selects a product from the drop-down box, the change event is fired that eventually makes an Ajax call. In the Ajax call, we’re sending the product_id appended as a GET query-string variable.

On the other hand, as we’ve already discussed in the controller setup, the ajaxGetProduct sends the XHTML of the product summary block based on the product_id query-string variable. In the success method, we append the XHTML response to the div tag that has the id attribute set to product_summary.

Finally, go ahead and make a template file catalog/view/theme/default/template/ajax/product.tpl with the following contents for an Ajax call.

<!-- catalog/view/theme/default/template/ajax/product.tpl -->
<div style="border: 1px solid #CCC;padding:10px;margin:10px;">
  <h3><?php echo $product['name']; ?> - <?php echo $price; ?></h3>
  <p><img src="<?php echo $thumb; ?>"/></p>
  <p><b><?php echo $text_manufacturer; ?></b>&nbsp;<?php echo $product['manufacturer']; ?></p>
  <p><b><?php echo $text_model; ?></b>&nbsp;<?php echo $product['model']; ?></p>

Nothing fancy here—We’ve just included a basic product summary block XHTML.

So, that’s it as far as the file setup is concerned. In our next section, we’ll go through the front-end to test what we’ve built so far.

Front-End Testing

So we’ve done all the hard work, and now it’s time for some testing! Head over to the front-end of OpenCart and visit the URL http://www.yourstore.com/index.php?route=ajax/index. It should display a nice-looking interface as shown in the following screenshot.

Custom Page Drop-Down

It’s our custom page, and it’s displaying a drop-down box containing the list of all products. Now, let’s try to select a product from the select box, and it’ll make an Ajax call in the background.

As a result, you should see a nice product summary block displayed right under the drop-down box as shown in the following screenshot.

AJAX Preview

If you’ve followed the tutorial and implemented all the files as explained, it should work smoothly for you as well as it did for me! Of course, that was a pretty simple demonstration of how Ajax works in OpenCart, but you could stretch it to the next level as per your requirements.

Go ahead and play with it, and try to make some interactive stuff using Ajax as it’s the best way to learn. So, that’s it for today, and I’ll be back soon with some more exciting stuff.


It was Ajax with OpenCart that was the central attraction of today’s article. As usual, we took a custom module approach to demonstrate it and made a simple yet effective use-case. I hope that it was informative and useful, and don’t hesitate to leave your queries and comments!

Download How to Use Ajax With OpenCart

How to Master Proper Business Email Format – and Avoid Professional Disaster

Email has become the main way that many business professionals communicate. Most of us send out more business emails than any other form of business communication. 

Every day you have email going out to your boss, your clients, your vendors, and your professional contacts.

Your emails are important. A good email can lead to business success. While a bad email can harm a professional relationship, sidetrack your project, or cause damage to your reputation.

Despite its importance, email formatting is often ignored. Proper formatting improves the chances that a recipient will read, respond, and react positively to your email. 

In this tutorial, you’ll learn how to create professional business emails by using proper business email format. I’ll also provide you with examples of good and bad business emails which you an apply to your own communications. 

1. Find Your Business Email Audience

Not all email audiences are the same. For that reason, not all business email should be formatted and written in the same way. Some business email should be structured in a more formal style. But, if you’re more familiar with your recipient, it’s okay to structure your email in a less formal style.

The email style you choose determines your email opening and closing. It can also determine the language you use and the tone of the email. To learn more about formal and informal email style read my recent post:

Here’s a quick summary of some general rules about when to use a formal versus informal email style.

Use a formal email style:

  • if it is required in your organization
  • if the recipients are not well known to you
  • when sending an email to someone who is above you in authority such as your boss or a teacher

 Use an informal email style:

  • if it is encouraged in your organization (your boss and others use an informal style)
  • for a business colleague who is well-known to you and/or on friendly terms
  • for personal emails that may contain both business and non-business topics

The choice between formal and informal style varies from company to company. That’s why it’s important to know what’s accepted in your company. If you’re not sure whether you should use a formal email structure or an informal email structure, it’s often safer to use a more formal style.

2. Know the Structure of a Business Email

How you format your business email makes a difference. A good business email structure helps communicate your message clearly. A badly formatted email can leave a poor impression.

All good business emails should have at least these parts:

  • Subject Line. The subject line is the first part of the email your reader sees. It can determine whether your reader opens the email. Most experts agree that subject lines should be short (six to ten words) and specific.
  • Salutation. The salutation is how you great the reader. It’s important that you understand whether you are addressing a formal or informal audience.
  • Body Text. The body text conveys the main message of the email. It should also include an introduction and conclusion. It should be written in short paragraphs of one to two sentences. Where it will add clarity, use bulleted or numbered lists.
  • Signature. Your signature can be formal or informal, depending on your audience. A good email signature template helps your reader find all the information about you that they need. Enavto Market has helpful signature templates to make your email signature more professional.

Use a proper email format. Structure your email so that the first few sentences of the body text explain what the email is about. The last few sentences should be a conclusion that summarizes the business email. The conclusion is also a good place to include a call to action. A call to action tells the email reader what to do next and how to do it. 

3. The Problem With Most Emails

Many of us never learned the right way to structure a business email. That is why so many people just throw an email together and hope for the best. Sadly, those hasty emails often do more harm to our professional reputation than good.

In this section I dissect two poorly written and poorly formatted email samples We’ll look at both examples and I’ll explain what’s wrong with each of them. In the next section, I’ll do a make over on each of these emails and show you how to improve them.

Formal Email Example – Before

Here is an example of a formal email that was not formatted or written well. Take a minute to look at the example and see if you can tell what’s wrong with it. I’ll detail the problems with this email below.

Let’s look at this business email carefully to determine what’s wrong. Here are some of the problems:

  • Subject Line. The subject line “Stuff” is too short and too vague. It consists of only a single word. With this subject line, some email systems may even send it straight to the spam filter.
  • Salutation. The salutation of “Hey” is too informal for an introductory message like this. The email author mentions they’ve never met some of the team members.
  • Body Text. The body of this email is one giant paragraph. That makes it hard for the average reader to follow. The body also includes items that would be better if they were formatted as a list.
  • Typos and Grammar Problems. The body text includes several poorly worded phrases. There are some run-on sentences. There are also typos and even a repeated word, “make make.”
  • Poor or No Closing. “Catch you on the flip side” is too casual of a closing for most business emails.
  • Signature. There’s no signature for this email. If the team is a new one, they might wonder who the sender is.

It’s likely that the recipients of this email would miss some of the points being made due to the way it is formatted and worded. Plus, it looks sloppy and poorly organized. All in all, this email is not a good way to represent a business organization.

Many businesses would find the above email embarrassing. Yet it’s not unusual for a business professional to write emails quickly and without thinking. Some of those rushed emails include some of the same problems as our example email.

Informal Email Example – Before

Here is an example of an informal email that was badly formatted and poorly worded. Take a minute to look at it and see if you can tell what’s wrong. I’ll detail the problems with this email below.

Let’s look at each part of the email carefully to determine what’s wrong. Here are some of the problems:

  • Subject Line. The subject line “Get It Together!!!” is a little bit too short. It’s also vague and accusatory.
  • Salutation. The salutation of the person’s name is not horrible for an informal email. However, the three exclamation points add an unneeded angry or upset tone.
  • Introduction. There is no introductory paragraph in this email.
  • Body Text. The body text is all one paragraph. It is written in an angry tone with phrases like “Grrr” which aren’t helpful. It also includes emoticons, which are not generally acceptable in a business email.
  • Conclusion. There’s no concluding sentence. The recipient may be unsure of what to do next.
  • Signature. There’s no signature in this email.

Not only is this email poorly formatted, it also conveys an unprofessional, negative tone. Rather than getting the results the sender wants, it’s likely that the reader would become angry and defensive.

4. Now to Properly Format These Business Emails

Bad emails can be improved with effective editing and formatting. Let’s remake the previous emails to make them more effective. I’ll change the formatting and wording to show you how to fix the poor email examples.

Formal Email Example – After

Here is an example of the formal email, rewritten and reformatted to convey a more professional image.

Let’s look at what we did to improve the email:

  • Subject Line. The subject line is the ideal length, six to ten words. It’s also more specific. It identifies the project by name and describes the topic of the email.
  • Salutation. The new salutation makes it clear that this email is for the project team members.
  • Introduction. The introductory sentence tells the reader what the email is about. It also conveys a positive tone by using the word “Welcome.”
  • Body Text. The body text is neatly organized in short paragraphs of no more than three sentences. It also includes a numbered list that can be quickly scanned for easy comprehension.
  • Conclusion. The conclusion summarizes the post. It includes the call to action “Let me know if you have any questions.”
  • Signature. The signature block identifies the sender as the project team lead.

The revised email is a business communication that any organization would be proud of. It’s been reworked with a professional email format. It also conveys the message clearly and succinctly in a 

businesslike manner.

Tip: The email could be improved even further by including a professional email signature template such as the ones found in Envato Market  Here are three examples of how a professional email signature template could be used:

Corporate Email Signature Template
Corporate Email Signature template examples

Learn more about how to craft a professional email signature: 

Informal Email Example – After

Here is an example of an informal email, rewritten and reformatted to convey a more professional image:


 What changed? Let’s take a look:

  • Subject line. The subject line is more specific, without being accusatory. It also includes the words “Please Reply.” Many experts agree that including phrases like “Please Reply” or “Response Needed” make it more likely that an email recipient will respond.
  • Salutation. By adding the word “Hi” to the salutation we’ve softened the tone of the email. The reader is less likely to be defensive.
  • Introduction. The introduction explains what the email is about in two sentences.
  • Body Text. The tone in the body text is much more friendly. The aim is to get the project back on track, not to make the reader angry.
  • Conclusion. The conclusion encourages the reader to respond.
  • Signature. The simple signature is fine for an informal business email.

As you can see, friendly wording and better formatting leave the reader with a more positive impression. The reader of this email is much more likely to respond and the problem is more likely to be solved.

You can learn even more about composing effective emails in this Tuts+ tutorial from David Masters: 

5. How to Avoid Email Disaster

So how do you avoid email disaster? With considered planning you can master proper business email format and create an email that conveys your message without ruining your business reputation.

Here are four easy guidelines to writing proper business emails:

  1. Don’t Rush. A hurried email is often a badly formatted, badly written email. Allow yourself enough time to properly format every email you write.
  2. Avoid Emotion. It’s never a good idea to send out an email when you’re upset. Instead, wait until you have calmed down.
  3. Be Concise. Use short sentences and short paragraphs. If appropriate, make use of bulleted or numbered lists.
  4. Review. Double-check your email for typos, grammar mistakes, and other errors. It’s also a good idea to make sure all the parts of the email are included.


Your business emails can make the difference between achieving your business goal or making your company look bad. Put some thought into how your emails are worded and formatted.

Your emails are important! Set a goal to work on properly formatting all your business emails. To learn even more about writing effective business emails review our guide to Writing Effective Business Emails, or get started with the first tutorial in the multi-part series: 

Download How to Master Proper Business Email Format – and Avoid Professional Disaster

Deploy Your PHP Application With Rocketeer

There used to be a time when PHP developers had to use deployment tools that were aimed at general web applications. You can see this in Johannes Schickling’s tutorial on deploying Laravel applications with Capistrano, for example. It’s a Ruby tool, and you need to write Ruby code. These tools get the job done but have limited integration with PHP applications. This can result in hacky solutions for certain scenarios. 

But nowadays, we’re blessed with a few deployment tools written in our language that enable deeper integration. One of these tools is Rocketeer, a tool that takes inspiration from Capistrano and the Laravel framework.

Rocketeer is a modern tool that brings a great approach for your deployment needs. That is to run tasks and manage your application across different environments and servers. On top of that, it also has some magic in it, like installing Composer dependencies if it detects a composer.json file. You get sane defaults and automation of common tasks for a modern PHP application. And you have the ability to customise and extend everything.

You could describe it as an SSH task runner that runs client-side. The commands execute on servers through an SSH connection. If you use a shared hosting provider with only FTP access, you’re out of luck, unfortunately. What you also need is a remote repository where the tool can fetch your code from. There is support for Git and SVN by default. Need support for another version control system? Write your own implementation with the provided interfaces.


You can install Rocketeer in two different ways. Either you download the phar file and make it executable or you install it through Composer. I’m a supporter of the latter. Having it as a dependency allows for easy installation when cloning the repository. This can benefit anyone cloning the repository to get them up and running.

Installing with Composer:

$ composer require anahkiasen/rocketeer --dev

I don’t recommend that you install it globally. Keeping it on the repository level will ensure that each person deploying is running the same version. What I do recommend is that you add vendor/bin to your PATH. Then you can use the binary by typing rocketeer in your project root.


Let’s get started! First you bootstrap the directories and files for configuration. You do this by running rocketeer ignite in the root of your project.

When your application ignites, the tool creates a .rocketeer folder in your project. The contents of the directory will look like this:

| .rocketeer
| -- config.php
| -- hooks.php
| -- paths.php
| -- remote.php
| -- scm.php
| -- stages.php
| -- strategies.php

These are all the configuration files you need to start setting up your deployments. Whenever I refer to a configuration file from here on out, it exists in the .rocketeer/ directory.

Remote Folder Structure

It’s important to understand how Rocketeer manages its folder structure on the server side, since it’s a bit different to a regular setup. It uses a few directories for managing certain aspects of the deployment, so it can be effective at what it does. You specify a path to where you want to deploy your application on your server, and the tool will take care of the rest. That folder will look like this, if you have /var/www/app as your application directory.

| /var/www/app
|  | -- current => /var/www/app/releases/20160103183754
|  | -- releases
|  |  | -- 20160101161243
|  |  |  |-- uploads => /var/www/app/shared/uploads
|  |  | -- 20160103183754
|  |  |  |-- uploads => /var/www/app/shared/uploads
|  | -- shared
|  |  | -- uploads

The most important folder is current, which points to your latest release. That is where your web server’s document root should be set to. So what happens when you deploy?

  1. The tool creates a time-stamped folder in the releases directory.
  2. Completes all tasks to make a ready release.
  3. Updates the symbolic link current to the new release.

This process makes your deployment transparent to the user. The switch between releases is almost instant, usually referred to as atomic deployments.

Some data should be persistent between your deployments. This can be file uploads, user sessions and logs, for example. Those files or folders go into the shared directory. The tool creates symbolic links inside each release for the ones you’ve configured.


Events drive the tool, and all strategies and tasks fire a before and after event when they run. They also provide a special halt event when a task fails. This could be for example dependencies.halt, or deploy.halt for general failure. This allows us to hook into the process where we need to.

The default events that happen during a deployment are:

  • deploy.before: before anything happens.
  • create-release.before: before it creates a new release directory.
  • create-release.after: after creating a new release directory.
  • dependencies.before: before installing or updating dependencies.
  • dependencies.after: after installing or updating dependencies. Perhaps make sure that binaries in your vendor folder are executable.
  • test.before: before running tests.
  • test.after: after running tests.
  • migrate.before: before running database migrations. Maybe you want to do a backup of your database?
  • migrate.after: after running database migrations.
  • deploy.before-symlink: before symlinking the release as our current release.
  • deploy.after: completed. You could notify people that everything was smooth sailing or otherwise.

We can also create our own events that we can fire and listen to. For now, we’ll stick with these events provided for us. They will be enough for us right now.


At the heart of Rocketeer, we find a concept called tasks. Most of what is happening under the hood are core tasks. The definition of a task could be a set of instructions to perform as a step in a deployment. If we look at some of the classes that the tool provides, we can get a general feel of what tasks are: classes such as DeploySetupMigrateRollback, and Dependencies. When you deploy, the deploy command itself is a task with sub-tasks.

Types of Tasks

This is where you’ll start to see how integrated the tool is with PHP, since you’ll write tasks in the language. You can create your own tasks in three different ways:

Arbitrary terminal commands. These are one-liners that you want to run on your server. Can be useful for a lot of things, like running gulp build  ---production for example.

Closures. If you need a bit more flexibility or complexity, you can write a task as a closure (anonymous function). Say you’d like to generate documentation for an API during your deployment.

function($task) {
    return $task->runForCurrentRelease('apigen generate  source src  destination api');

Classes. For more complex tasks, you should utilise the option to create classes for tasks. You create a class and extend Rocketeer\Abstracts\AbstractTask. Then you must provide at least a description and an execute() method. Here’s a completely useless example just to show the structure of a task class:

namespace MyDeployableApp\Deploy\Tasks;

class HelloWorld extends \Rocketeer\Abstracts\AbstractTask
     * Description of the Task
     * @var string
    protected $description = 'Says hello to the world';

     * Executes the Task
     * @return void
    public function execute() {
        $this->explainer->line('Hello world!');

        return true;

Note that you have to register task classes yourself. Either you do this through the hooks.php file and add it to the custom array…

'custom' => array('MyDeployableApp\Deploy\Tasks\HelloWorld',),

… or you can do this through the facade:


Once you register it, you can execute it:

$ rocketeer hello:world
staging/0 | HelloWorld (Says hello to the world)
staging/0 |=> Hello world!
Execution time: 0.004s

Defining Tasks

We discussed events first because we hook tasks in where we need them in the process. You can do this in a few ways. Go with the one you like and that meets requirements for your level of complexity.

The easiest way of defining your tasks is in the hooks.php file. It provides two arrays for this, specifying task execution before or after certain events.

'before' => [
    'setup' => [],
    'deploy' => ['hello:world'],
    'cleanup' => [],


You might be able to tell already that the tasks provided are quite generic. Take Dependencies, for example. What kind of dependencies are we talking about and which package manager? 

This is where strategies come into play. A strategy is a specific implementation of a task, such as running tests with Behat or using Gulp for building your front-end. Tasks have a default strategy with the option of running the other strategies through the CLI. We can list the strategies available like this:

$ rocketeer strategies
| Strategy     | Implementation | Description                                                           |
| check        | Php            | Checks if the server is ready to receive a PHP application            |
| check        | Ruby           | Checks if the server is ready to receive a Ruby application           |
| check        | Node           | Checks if the server is ready to receive a Node application           |
| deploy       | Clone          | Clones a fresh instance of the repository by SCM                      |
| deploy       | Copy           | Copies the previously cloned instance of the repository and update it |
| deploy       | Sync           | Uses rsync to create or update a release from the local files         |
| test         | Phpunit        | Run the tests with PHPUnit                                            |
| migrate      | Artisan        | Migrates your database with Laravel's Artisan CLI                     |
| dependencies | Composer       | Installs dependencies with Composer                                   |
| dependencies | Bundler        | Installs dependencies with Bundler                                    |
| dependencies | Npm            | Installs dependencies with NPM                                        |
| dependencies | Bower          | Installs dependencies with Bower                                      |
| dependencies | Polyglot       | Runs all of the above package managers if necessary                   |

Creating Your Own Strategies

Say you’re doing BDD With Behat for your application instead of TDD. Then you want to run your tests with Behat instead of PHPUnit. Since it is a test runner, there is already a strategy namespace for that, but no implementation. Create the directory .rocketeer/strategies/ and place your new BehatStrategy.php in there.

namespace MyDeployableApp\Deploy\Strategies;

use Rocketeer\Abstracts\Strategies\AbstractStrategy;use Rocketeer\Interfaces\Strategies\TestStrategyInterface;

class BehatStrategy extends AbstractStrategy implements TestStrategyInterface
    public function test() {
        return $this->binary('vendor/bin/behat')->runForCurrentRelease();

You can now switch out your test strategy to the new implementation in strategies.php.

'test' => 'Behat',

Connections & Stages

It doesn’t matter if you have an infrastructure in place or have one in mind. It doesn’t matter if your application deploys to many environments across many servers. Rocketeer will be there for you. You can even have many varying locations on the same server. This is where the terms connections and stages enter.

connection is a server where you deploy your application to. This is often called an environment, and production and staging are examples of this. Configuring these connections is a breeze in the tool. Either you do it through a nested array or by keeping separate files for each connection. Each connection can also have multiple servers in it.

Stages are like connections inside connections, a kind of “connectionception”. You could set up a staging and a production environment on a single server with the use of stages. So instead of having two separate connections, you have one connection with two stages in it.


A great feature is that we can extend our process using plugins. There are a few official ones for integration with LaravelSlackHipChat and Campfire. Then there are a few, but not that many, on Packagist. Installing plugins is an easy task through the CLI:

$ rocketeer plugin:install rocketeers/rocketeer-slack

Even though there’s a limited number of plugins, it leaves room for developing plugins in the future. It tells of a good philosophy. And why not develop one of your own?

Setting Up Your Deployment

To get your application off of the ground, you need some basic configuration. You need to tell Rocketeer where to find your application and where it should deploy it to. Let’s start by setting an application name and configuring a production server in config.php.

'application_name' => 'my-deployable-app',

// [...]

'connections' => [
    'staging' => [
        'host' => 'staging.my-deployable-app.com',
        'username' => '',
        'password' => '',
        'key' => '/Users/niklas/.ssh/id_rsa',
        'keyphrase' => '',
        'agent' => '',
        'db_role' => true,
    'production' => [
        'host' =>
        'username' => '',
        'password' => '',
        'key' => '/Users/niklas/.ssh/id_rsa',
        'keyphrase' => '',
        'agent' => '',
        'db_role' => true,

You now have an application name and a server to deploy your application to. This setup uses SSH key authentication, but you can connect with a username and password also. To get prompted for username and password, set 'key' => ''. The tool will store the credentials on your local machine and use them each time later on. I don’t recommend setting a username and a password in the config file, because you never want credentials committed to your repository.

What you should now do is change the default connection that you deploy to. Having the default set to production is not ideal. You don’t want to deploy to production by accident. So in the same file, look for the default key and change the value to staging instead.

'default' => ['staging'],

The application name itself isn’t that important. But if you don’t specify a folder to deploy to, it will use this as the folder name in the root directory. By default, the root is set to /home/www. With this application name, it will deploy it to /home/www/my-deployable-app. If you want to change your root directory, you can change this in remote.php.

// Deploys to /var/www/my-deployable-app/
'root_directory' => '/var/www/',

In the same file, you have the ability to override the application name and specify a directory for your application.

// Deploys to /var/www/tutsplus-tutorial
'app_directory' => 'tutsplus-tutorial',

Now you have a receiving end of the deployment, but you also need to set up the location of your code so it can be fetched. You do this by setting up your remote repository in scm.php. By default it uses Git, but it has support for SVN also. You tell it the address of our repository and supply credentials if needed. I suggest you use SSH key authentication here as well, and leave the username and password empty.

'repository' => [email protected]:owner/name.git',
'username'   => '',
'password'   => '',
'branch'     => 'master',

Since you added a connection to the production server, you want to deploy the master branch.

Connection & Stages Specific Configuration

In most cases, you don’t want the same configuration option for all your connections or stages. Say, for example, you want to deploy another branch to the staging environment. Rocketeer allows you to override configuration values for connections and stages using config.php. To deploy a branch called staging on your staging connection, you do this:

'on' => [
    'connections' => [
        'staging' => [
            'scm' => [
                'branch' => 'staging',

It uses a nested array to override configuration values. Under the staging key, find the corresponding key in the file you want to change. In this case it’s branch in scm.php.

Deploy, Lift Off!

Now you have everything set up to make a successful deployment. You haven’t met your requirements for a complete deployment, but it’s enough to get your application cloned to your server and served to the end users. First you can execute the check strategy to see if your server meets the requirements.

$ rocketeer check

If everything is okay, you can deploy by running:

$ rocketeer deploy

Since this was your first deployment, Rocketeer will make sure everything is up to par. The tool creates the directories it needs and that our application will live in. If everything is smooth sailing, you should have a complete build of your application on the server.

If you changed the default connection to staging in the previous section, it will always deploy to staging. That is, of course, unless you tell it to deploy to somewhere else. When you want to deploy on a different connection or more than one, you use the --on switch.

# Deploy to production
$ rocketeer deploy --on="production"

# Deploy to staging and production
$ rocketeer deploy --on="staging,production"

Want to have a look at what will happen on your server once you hit the button? Use the --pretend flag to let the tool tell you what it will execute on the server.

$ rocketeer deploy --pretend

Houston, We Got a Problem. We Need a Rollback.

Unfortunately we need to take care of deployments that break functionality or wreak havoc in the infrastructure.  Then you need to make a quick rollback to your latest release. Luckily it’s a simple operation—just run the command:

$ rocketeer rollback

Since it stores a number of builds, performing a rollback is fast. It changes the symbolic link of current to the previous release.

Shared Directories

Setting up shared directories is simple—just add them to the shared array found in remote.php. Rocketeer will create and link these folders for you in the deployments after. The specified paths should be relative to your root folder.

'shared' => [

Writable Directories

Most shared directories will also need the web server to be able to write to them. Writing logs, sessions or file uploads is often a task performed by any application. These you add to the permissions.files array in remote.php.

'permissions' => [
    'files' => [
    // [...]

Install or Update Dependencies

Installing or updating dependencies is something you need if the application relies on any kind of dependencies. The tool comes with support for the most popular package managers. Configuring anything is not necessary if you have the default setup for them. It will detect and install or update dependencies for ComposerNpmBower and Bundler. The default strategy for dependencies is set to Polyglot. This is the tool’s way of detecting and installing dependencies for the different package managers.

But let’s say that you want to install all dependencies on staging, and the tool uses the --no-dev flag by default. Perhaps you want to install PHPUnit for running tests, which is a development dependency. In strategies.php, you can find the composer key, which tells the tool how to execute Composer. You can then override this in config.php:

use Rocketeer\Binaries\PackageManagers\Composer;

// [...]

'on' => [
    // [...]
    'connections' => [
        'staging' => [
            'strategies' => [
                'composer' => [
                    'install' => function (Composer $composer, $task) {
                        return $composer->install([], ['--no-interaction' => null, '--prefer-dist' => null]);

Database Migrations

Migrating databases is often something you want to do when you have a complete release, just before it symlinks to current. Whatever tool you use, you can tell it to run before the deploy.before-symlink. This hook is not a regular one, but an internal hook. You then need to register it someplace else than hooks.php. You can this do this in events.php, which you can create if it doesn’t exist already.

use Rocketeer\Facades\Rocketeer;

// Laravel
Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) {
    $task->runForCurrentRelease('php artisan migrate');

// Symfony2
Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) {
    $task->runForCurrentRelease('php app/console doctrine:migrations:migrate');

// Stand-alone Doctrine
Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) {
    $task->runForCurrentRelease('doctrine migrations:migrate --no-interaction');

Running Tests

Running tests in a deployment process is a great way of ensuring that no broken code or tests slip through the cracks. By default, the tool uses PHPUnit, and you can hook the test runner to run after dependencies are installed or updated.

'after' => [
    'setup'        => [],
    'deploy'       => [],
    'dependencies' => ['test'],
    'cleanup'      => [],

We should now see it’s executing PHPUnit on each deployment, and in case of any failing tests it will abort. Make sure you see output from it, otherwise it might have a problem with finding a PHPUnit binary or your test suite.

staging/0 |---- Test (Run the tests on the server and displays the output) fired by dependencies.after
staging/0 |------ Test/Phpunit (Run the tests with PHPUnit)
$ cd /var/www/my-deployable-app/releases/20160129220251$ /var/www/my-deployable-app/releases/20160129220251/vendor/bin/phpunit --stop-on-failure
[[email protected]] (staging) PHPUnit 4.8.21 by Sebastian Bergmann and contributors.
[[email protected]] (staging)
[[email protected]] (staging) .
[[email protected]] (staging) Time: 4.79 seconds, Memory: 6.00Mb
[[email protected]] (staging) OK (1 test, 1 assertion)
[[email protected]] (staging)staging/0 |=====> Tests passed successfully

Front-End Build Tools

Often our applications are not only a back end, unless they are a REST API for example. Running build tools for our front end is a common task with tools such as GruntGulp or Webpack. Making this part of our deployment process is nothing fancier than using a hook to run the commands such as:

'after' => [
    'setup'        => [],
    'deploy'       => [],
    'dependencies' => ['gulp build'],
    'cleanup'      => [],

A front end often relies on dependencies as well, so run tools after installing or updating them.

Tips & Tricks

Running Updates

If you do not want to create a new release when you deploy, you have the option of running an update. Be cautious when doing this since you won’t be able to roll back to the previous version, only the previous release. But it is a quick and simple way of updating your application with the latest changes with:

$ rocketeer update

Local Tasks

Sometimes it can be nice to run tasks in your local environment. Say you want to run a PHPCS check or build your static assets and upload them to the server, removing the need of certain binaries on the server. If you create a task class, you can set the protected variable $local to true.

class MyTask extends Rocketeer\Abstracts\AbstractTask
    protected $local = true;

    // [...]


The deployment process is an important part of an application’s lifecycle. Tools like Rocketeer allow you with ease to make this an uncomplicated matter. This is especially true when using it for a PHP application since it integrates so well with it.

Writing an introductory tutorial to Rocketeer turned out to be a hard task. The tool is so flexible that drawing the lines on where to stop isn’t easy. I hope I got across the possibilities in using this tool and how it can benefit you and your application. If you want to dig deeper, I suggest reading the full documentation. There’s much more to the tool than what I could cover in this article.

Download Deploy Your PHP Application With Rocketeer

How to Create Nature-Inspired, Decorative Arrows in Adobe Illustrator

Final product image
What You’ll Be Creating

In this tutorial, you will learn how to create fancy, decorated arrows.
We will use basic shapes and then apply Warp, Roughen, and Zig-Zag
effects. You will also learn how to create different feathers from basic

Before we begin, you can check out Envato Market for more
inspiration. I promise that you’ll find so many beautiful decorative
made by many talented illustrators.

And now—let’s get started with our tutorial!

1. Create the First Arrow

Step 1

Let’s start out by creating our first arrow from a regular rectangle. Take
the Rectangle Tool (M) and draw a long rectangle. The fill color you
can see in the image below. 

Since we want to create colorful, ornamental
arrows which we see on Pinterest rather than those that we see in Game
of Thrones, we will decorate our arrows. So let’s make a copy of the
light brown rectangle that we just created in front (Control-C,
), make it shorter, and change the fill color to blue. 

the Alt and Shift keys on your keyboard, move the blue rectangle to the
left and you will see that you now have two blue rectangles. Change the
fill color of the newly created rectangle to yellow. Again, holding the
Alt and Shift keys, create a copy of the yellow rectangle and change the
fill color to red. 

You should now have four different colored rectangles. We just created the wooden shaft of the arrow.

creating the wooden shaft of the first arrow

Step 2

Let’s move on to the tip of the arrow, known as the arrowhead.

Start with the Ellipse Tool (L) and draw an ellipse. Then hit the
Convert Anchor Point Tool (Shift-C) and click on the right anchor
point—you’ll end up with a sharp point. Using the Direct Selection Tool
, select the top and bottom anchor points and move them to the left
by pressing the left arrow keys on your keyboard. Add a rectangle using the Rectangle Tool (M) with the same fill color, and your arrowhead is done.

creating the arrowhead

Place the arrowhead on the shaft.

placing the arrowhead

Step 3

Let’s start adding some decorations—we’ll start with a feather. Some
time ago, someone asked me to create a tutorial on drawing feathers.
Your wish has been granted!

Draw an ellipse using the Ellipse Tool (L). While keeping it selected,
go to Effect > Warp > Arc and apply the options you see below.
Expand the shape (Object > Expand Appearance). For the stem of the
feather, we will use a copy of this shape. Just make the copy darker and
narrower. Place the stem in front of the first ellipse and centered in the middle.

creating the violet feather

Step 4

Hold your horses—our feather is not done yet. Let’s add some details.
Take the Polygon Tool and click on your artboard. In the new dialogue
window, enter 3 Sides with any Radius and press OK. Rotate the triangle
to the right. 

A little trick: if you want to rotate a shape exactly 90
, select the shape, hit the Shift key and start rotating. You’ll
notice that you are rotating exactly in 45 or 90 degree increments.

Make the rotated triangle very narrow, and then apply the warp options. Go to go
to Effect > Warp > Flag. Enter the options shown below. We will
call it “a flag shape”. Save a copy of this flag shape for later.

creating the flag shape

Step 5

Make a few copies of the flag shape and place them on the feather shape.
First, place them on the left side. Then make a reflection of them by
right-clicking the mouse, Transform > Reflect. Check Vertical, Angle
90 degrees
in the dialogue window and click Copy. Place them on
the right side of the feather. 

When you are satisfied with the result,
select all these little flag shapes along with the feather, but not the
stem. Go to the Pathfinder panel and press the Minus Front button. Now,
select the stem and put it in the front (Control-X, Control-F).

creating the violet feather

Step 6

Place the feather on the arrow and warp it: go to Effect > Warp >
. Expand the feather (Object > Expand Appearance).

placing the violet feather

Step 7

Now we will create another feather. Instead of a feather with a narrow top and wide
bottom, we will make one with a wide top and narrow bottom. Take the stem from the previous feather and recolor it blue
(see fill color below). Then add a light blue ellipse in the back. 

the Direct Selection Tool (A), select the left and right Anchor Points
of the light blue ellipse and move them up. Remember the flag shapes?
Bring those and place them on it. Select all the flag shapes along with
light blue ellipse and press Minus Front in Pathfinder. Be sure to put
the stem in front (Control-X, Control-F).

creating the blue feather

Place the feather close to the previous feather that we created before.

placing the blue feather

Step 8

To finish off our arrow, we will decorate it with a wavy green branch.
Delete the fill color and set the stroke color as shown below. Take the
Line Segment Tool (\)
and draw a line over the shaft. Adjust the stroke
Weight on the Stroke panel as you want. While keeping it, selected go to
Effect > Distort & Transform > Zig Zag… and enter the
options you see in the image below.

creating the green waving branch

Step 9

Now, choose the previous stroke color as the fill color and draw an
ellipse. Take the Convert Anchor Point Tool (Shift-C) and click on the
left and right anchor points to make them sharp. This will be our leaf.

creating the leaf

Step 10

Create a bunch of the leaves and place them on the wavy branch. Our first arrow is done!

placing green leaves

2. Create the Second Arrow

Step 1

The shaft of the second arrow will be the same fill color as the first one.
Draw a tiny dark gray rectangle on the right side of the arrow. While
holding down the Alt and Shift keys, move it to the left. Keep pressing
, and a copy of this tiny rectangle will move further. Change
the fill color of every second tiny rectangle to light gray.

A quick side note: All the decorations that I’m adding are just examples—feel free to decorate these arrows to your taste!

creating the wooden shaft of the second arrow

Step 2

Now the arrowhead. Let’s first place a gray rectangle on the left side
of the arrow shaft. Then draw a little square. While holding down the
Shift key, rotate it 45 degrees. Take the Direct Selection Tool (A)
and move the left anchor point of the square to the left. Can you see
the pointy arrowhead now?

creating the arrowhead

Step 3

Using the Rounded Rectangle Tool, create three identical tiny rounded
rectangles as marked with the black arrow. 

Remember the violet feather
that we created for the first arrow? Make a copy of it, and change the fill
color to yellow—we’ll use it for the second arrow. To make it little bit
different, create a horizontal reflection of this yellow feather:
 > Transform > Reflect and check Horizontal,
Angle 0 degrees
and press OK. Place it as shown below, but remember to
place it behind those three tiny rounded rectangles.

creating and placing the yellow feather

Step 4

Let’s continue decorating. In the next few steps, we will make a green
branch. In a newly created green ellipse, move the left and right anchor
points up. That’s our simple leaf.

creating the leaf

Step 5

Set the stroke color to the same color and delete the fill color. Using
the Line Segment Tool (\), draw a stalk. Place the previously created
leaf on top. Make a copy of this leaf, rotate it 45 degrees and place it as
shown in the third image below. 

Holding together Shift (for moving
it straight) and Alt (for making a copy), move that leaf down a little bit. Keep pressing Control-D to repeat your last movement until you
finish filling in the stalk on the left side. Then select all the
leaves on the left side and make a vertical reflection: right-click > Transform > Reflect. In the new dialogue window, enter
Vertical, Angle 90 degrees and press Copy. Move it to the right. Our
green branch is almost ready.

creating the green branch

Step 6

Let’s show that the branch is flexible. Just go to Effect > Warp >
and enter the options you see below. Don’t forget to expand the
branch (Object > Expand Appearance). We are expanding the shapes all
the time because we want to rotate them without distorting.

warping the green branch

Put the green branch close to the yellow feather.

placing the branch

Step 7

Delete the fill color and set the stroke color. Go to the Stroke panel
and make the stroke Weight thick, and check Round Cap. Using the Line
Segment Tool (\)
, draw a brown branch. To make it more realistic, go to
Effect > Distort and Transform > Roughen and enter the options
shown below. Expand the branch.

creating the brown branch

Place the branch between the green leaves and yellow feather.

placing the brown branch

Step 8

Let’s create one more feather. Be sure to delete the stroke color and
set the fill color. Draw a dark gray ellipse and move up the left and
right anchor points. Add a stem (just take a copy from some previous
feather) and change its fill color. 

Remember the flag shape? Take a copy
of it and place it on the stem as shown below. Make a few of them and then
reflect them on the other side as well.

creating the gray feather

Step 9

The last detail we want to add is the stains. Draw a few light gray ellipses
and then apply a Roughen effect to them (Effect > Distort and
Transform > Roughen
). The options will depend on the size of your

creating the stains on the gray feather

Place this dark gray feather on the arrow.

placing the gray feather

3. Create the Third Arrow

Step 1

So here is where it gets easy. I took the first arrow and changed the arrowhead—I created it from a triangle, using the Polygon Tool.

creating the shaft and arrowhead of the third arrow

Step 2 

Now, let’s have a quick practice—create a pink feather just following the image shown below. Try it—don’t be afraid!

creating the pink feather

Step 3

Place your beautiful feather on the arrow and warp it. Select the
feather, go to Effect > Warp > Arc and in the new window, move the
slider in the Bend section to your taste. When it looks good, click OK.
Expand the feather.

placing the pink feather

Step 4

Let’s create a green ellipse. Make the top and bottom anchor points
sharp. Go to Effect > Distort & Transform > Zig Zag… and enter
in the new dialogue window the options you see below. Your options can be
different than mine—just try to find what suits you best.

creating the green leaf

Place this new leaf close to the pink feather.

placing the leaf

Step 5

Delete the fill color and set the stroke color as you see in the image
below. Draw three stalks using the Line Segment Tool (\). Now—remember
our first arrow when you created sharp cornered leaves? Make three
copies of it, and place them on the stalk we just created.

creating the green branch

Place it on the arrow.

placing the branch

Step 6

Take the Spiral Tool and click on your artboard. A new dialogue window
will pop up; enter the options you see below. Then take the Direct
Selection Tool (A)
and move the handles of the anchor points to achieve
a shape that looks like this:

creating the green swirl

Make a copy of it and place both of these on the arrow.

placing the swirl

Step 7 

Let’s create a flower, something like a ranunculus, a peony, or even a
rose—it all depends on the options you enter later. 

First, draw a
circle and go to Effect > Distort and Transform > Roughen. Check
Points Smooth, and move the sliders in the Options section how you like.
After that, create a smaller and darker circle in the front, and again apply Roughen effect options to it. And then again a smaller and darker
circle and apply the Roughen effect. In the end, draw a few tiny circles inside the
flower, and it’s complete.

creating the pink flower

Place the flower on the third arrow.

placing the pink flower

Step 8

Move up the left and right anchor points in the newly created blue
ellipse. Create a copy in back and make it darker. Rotate it slightly to
the left. Right-click the mouse and Transform > Reflect. In the new
window, enter Vertical, Angle 90 degrees, Copy. Then make a green Ellipse in the back and add a curve using the Arc Tool (no Fill color,
stroke color shown below). The blue flower is ready.

creating the blue flower

Step 9

We want to add some leaves too. Remember the green branch we made for
the third arrow before? Take a copy of it, but let’s change the stalk:
instead of a straight one, make a stalk using the Arc Tool. Be sure to
check Round Cap on the Stroke panel.

creating the branch

Step 10

Place the blue flower with the leaves on the third arrow closer to the
arrowhead. Then use the Rounded Rectangle Tool to create three tiny
rounded rectangles, to show that the flower is fixed to the arrow.

placing the branch

4. Create the Background

Step 1

Now that we have completed three decorative arrows, let’s arrange them as you want or place them like this:

placing all the arrows together

Step 2

Be sure to delete the fill color and set the stroke color to blue. With the Rectangle Tool, draw a thick stroked frame for your illustration.

creating the frame

Step 3

Keep the frame selected and make a copy in front (Control-C, Control-F). Change the stroke color and now make the stroke weight thin.

continue to make the frame

Step 4

Go to Effect > Distort & Transform > Zig Zag… and enter the
options you see in the image below or just make your own.

Zig-Zag effect options


applying Zig-Zag effect to the frame

Fantastic, You’re Done!

Awesome work! Now you know how to create feathers, different branches, leaves, and flowers. You’ve learned how to make arrows with different arrowheads. After this tutorial you will be familiar with the Roughen and Zig-Zag effects, as well as the Warp effect and moving anchor points in basic shapes.

I hope you enjoyed this tutorial and got a lot more ideas to create thousands of arrows!

End result

Download How to Create Nature-Inspired, Decorative Arrows in Adobe Illustrator

From Lightroom to WordPress: How to Create SEO-Optimized Images

WordPress is a piece of software that powers as much as 25% of the web’s websites. Major websites like The New York Times, CNN, and Forbes all use WordPress to power their websites.

What WordPress is to web developers, Adobe Lightroom is to photographers. In this tutorial you’ll learn how to use these two powerful tools together. You’ll learn how to take your images from Lightroom and into a WordPress driven site quickly and easily. Most importantly, we’ll do it in a way that’s SEO-friendly so that your images get discovered.

Image SEO For Beginners

Search engine optimization (also known as SEO) is a set of inter-related design, publishing, and data management practices that help web pages to be found. The truth is, there isn’t really any magic to SEO when it comes to images. It all boils down to adding context to your pictures in a way that that makes sense to computers.

Semantic Information

Think of it this way: you enter a search query into the search engine of your choice. The search engine shows you a list of pages that match what it thinks you’re looking for. Search engines use crawlers—computer programs and algonrhithms— that explore the web automatically and build listings of sites that match keywords. 

A search engine can tell that images are on a webpage, but it can’t easily determine what’s an image depicts, so we need to supplement it with additional data, a kind that it can understand. This kind of data is called semantic information: it’s information that helps build meaning for individual photographs in context to each other and the rest of the webpage. We use metadata fields to transmit this sematic data.

Google looks to some of the tags hidden in our HTML to help find images. We can add things like titles, tags, and alt text in our website’s code to help a search engine index our site as easily as possible. There’s no guarantee that by adding sematic informating you’ll be able
to move your site to the first page of Google’s results, but taking a
few basic SEO steps can definitely help your chances. It’s also just good data hygene!

Here are four key pieces of SEO optimization information to add to your images:

File names

If you do nothing else, make sure that you rename your images in a way that describes them. A simple filename like “resizing-images-tutorial.jpg” is a massive improvement over “IMG_9052.cr2.” Using a filename with some words that describe it will improve its chances of being found.

When exporting from Lightroom, my favorite way to do this is to use the “File Naming” section of the export window. Keep in mind that we want to rename the exported image, not the original file. Find the File Naming section and check the Rename To box. Then choose a dropdown option that includes “custom name” so that we can add our own custom text.

The last step is to add the custom text.  For the web, it’s best to separate the words in a filename using dashes instead of spaces. Customize each image’s file name for the best results. 

Custom Name - Sequence
Use a custom name option to give your file names a better chance of being found. A few words that describe the contents of an image go a long way!

Alt Text

Alternative text, or “alt text”, is used to provide a text description of the contents of an image. Remember that a search engine can’t determine what’s in an image (yet) so we need to help it by using alt text.

You’ll probably never see alt text; the important part is that a search engine will.

Image alt text
An image’s alt text should also be set in HTML. The alt text should briefly describe the image. We can set this alt text in the WordPress Media Library, and WordPress will automatically add it.

Alt text is placed in the same bit of HTML that contains your images. Use it to add a description of the image. A short description of the contents of an image is critical for SEO-friendliness. If writing code isn’t you’re thing, no worries; we’ll look at how to add this alt text using WordPress in the next section of this guide.

Having alt text for your images is also crucial to the visually impaired. Screen reading software designed to help those who have full or partial loss of sight will read the alt text in place of an image. Amherst College has a great guide to optimizing your web pages for accessibility.


An image’s title should also be contained in the HTML tag. The title should be an even shorter version of the description, with only a few words that signal the content of an image.

Image title text
You should also set an image title in HTML with the “title=” tag in the same image block. Again, WordPress makes this easy to add.

Titles are another piece of the puzzle for helping search engines index our site. WordPress contains a title field that will help our SEO efforts.


Think of a caption as the text that shows immediately after an image that provides further commentary. Captions aren’t added directly to an image tag directly, but certainly do supplement it. In HTML5, the <figcaption> tag is part of the <figure> group, which is even better. You can learn more about how to write effective captions in Dawn Oosterhoff’s Caption, Description, Title, ALT: How to Add Semantic Information to Images. Writing a strong caption is one of the most under-rated skills, one that’s useful for every photographer!

Mapping Metadata from Lightroom to WordPress

Now that we understand the pillars of image SEO, let’s look at how to add them easily and quickly to our WordPress-driven site. We can carry forward an image’s title and caption from our Lightroom catalog to WordPress.

In the Lightroom Library module, find the metadata panel on the right side. You can see the image title and caption. 

When you’re exporting an image from Lightroom, make sure that you’re including “all metadata.” This will ensure that the title and caption are saved to the JPEG image and will be read and included by WordPress.

Include metadata on export
Make sure that when exporting an image, you include metadata in the file. This will make that metadata available in WordPress.

Upload to WordPress

Once you’ve exported a neatly named image file with a title and caption set, you’re ready to upload it to WordPress. Go to the WordPress Media Library and upload this image as you normally would. The uploaded image will carry through the same title and caption that we set in the Lightroom metadata panel!

Image Uploaded to WordPress
Finally, the fruits of our labor! The title and caption that we

You’ll need to manually add alt text to images once they reach WordPress. Unfortunately, there isn’t a field in Lightroom that maps to “alternative text” in WordPress. Remember that this is the text hidden in the HTML code that will help search engines find and index our images.

Alt text
Alt text will need to be added to images within the WordPress Media Library.

After setting the alt text, press Update to save the image. When you insert it into a post or page, WordPress will carry through the metadata and include the metadata we’ve added in the HTML code.

These steps are a major aid for optimizing an image for the web. We can also go one step further by resizing and compressing images for the web.

Resizing for the Web

Getting images ready for the web is about more than just loading them up with keywords and dropping them in WordPress. We also need to think about the file size and dimensions. Remember that a huge portion of the internet connected population isn’t lucky enough to be on a great broadband connection, and we should consider their experience as well.

mobiForge recently wrote that the average webpage file size is larger than the entire 1993 classic video game Doom. This isn’t inherently a bad thing, but is a great reminder that webpages are more full of multimedia and large images than they’ve ever been. It serves as a great reminder that we should always optimize your image file sizes. 

When we’re ready to send images to the web, there are two key factors to optimize for: dimensions, and quality. Let’s look at how to perfect both.


The dimensions of a digital image are the length and width of the image, measured in pixels. An image said to be “600 by 400 pixels” is inferred to be 600 pixels in width and 400 pixels in height. 

Images captured with my Canon 6D are 5472 x 3648 pixels. By the time you see them on Tuts+, they’re constrained in the layout to 850 pixels on the long side. Theoretically, I could upload the full image, but no matter what it’s going to appear at a maximum of 850 pixels. 

This effect is exactly why I always resize my images to a web-friendly format. My viewers don’t have monitors that show every single pixel, so it only makes sense to resize the image and save them the load time.

Web Size Simulation
This simulation illustrates just how large an original 10 megapixel image is versus how it will appear on the web. The large image preview you see is scaled version of the full, 10 megapixel image I captured. In the inset, the size has been compared to how it appears on Tuts+. A full-width 10 megapixel image is over 4000 pixels in width, while it appears in Tuts+ articles at just 850 pixels on the long side. This is a great illustration of why resizing is so important.

What’s the correct dimensions for an image on the web? The answer is, “it depends on where it’s going.” If you’re using WordPress, check the documentation for your theme for the image widths supported. The developer determines how images will appear in a WordPress theme. If documentation isn’t available, try out a site like PiliApp to do your own measurements on an image on the site you’ll be publishing to.


High quality images use more disk space. The more detailed and colorful an image is, the larger the file will be. Although our image archive should include these full quality images, preparing an image for the web means making trade-offs between quality and file size. Giving up a bit of quality leads to a much faster load time for the viewer.

When exporting in Lightroom, you can use the Quality slider to adjust the output quality of an image. It’s a 0-100 scale, with a 0 quality image rendering the smallest file size. A 100 quality image maximizes both quality and file size.

Image quality comparison
This image quality comparison shows some subtle difference between the various quality settings. Some differences can be observed in the finer details, as well as the colors in the sky. Note that in the lowest quality image, there’s some “banding” in the sky (subtle lines) while the higher quality images. The 25 quality image gave me a 91kb image, while 100 quality image was a 366kb image. It’s all about finding the balance of quality and file size.

One of my favorite ways to control file size is to use the “Limit File Size To” optionI frequently use this option when I’m exporting images to publish on Tuts+, given that Tuts+ has a limit of 150 kilobytes for images in articles.

Using the “Limit File Size To” option bypasses the quality slider altogether. Instead of choosing a quality between 0 and 100, you can simply set a maximum file size (in kilobytes) and Lightroom will choose a quality setting for you.

Limit File Size screenshot
The “Limit File Size To” box can be used instead of the quality slider. When you check the box in the export window, choose the maximum file size for your image and Lightroom will make it work.

From my experience, when using the quality slider for web images, I typically will leave the quality setting in the 60-75 range. This seems to be the sweet spot for file size and image quality. Increasing the slider far beyond that yields a much larger file without much visual difference.

If you want to learn more about the keys to resizing images for the web, check out my write-up from last year, How to Export JPGs for the Web from Adobe Photoshop Lightroom. While the focus of this tutorial is the metadata for SEO, image size is still an essential part of being search-friendly. 

Recap & Keep Learning

In this tutorial, we’ve covered how to pick the low-hanging fruit for exporting images from Lightroom to a WordPress website. Make no mistake; this won’t instantly shoot your site to the top of Google for common terms, but it will go a long way in helping someone find your images.

It’s worth noting that there are several WordPress plugins, or add-on’s, that can automate this process. However, plugins that aren’t frequently updated can open your site to security vulnerabilities. You also have to count on a developer maintaining the plugin’s compatibility with new versions of WordPress. Two popular plugins include WP/LR Sync and LR/Blog.

If you want to learn more about WordPress, the Tuts+ code section has a wealth of content for modifying and extending WordPress. The photo and video section also has some extensive coverage of Adobe Lightroom if you want to sharpen those skills.

Finally, SEO is an ever-changing area of research. Google constantly updates their algorithm used to find the pages that they think match the search query the best. There’s a ton of bad advice and “tips” for SEO out there. My go-to source for SEO is the Moz Blog. The geniuses at Smashing Magazine also have a great write-up on how to build an SEO optimized website.

What are you doing to get your images ready for the web? Let me know in the comments section.

Download From Lightroom to WordPress: How to Create SEO-Optimized Images

Magma Skybox Pack Vol.I (Skies)

This item includes 3 equirectangular high quality skydome/skybox images artificially created in a resolution of 12866×6433.

The spherical cubemap-compatible images are available as Photoshop-files (.psd), TIFF-files (.tif) and PNG-files (.png) and are essential for image-based lighting (IBL), professional rendering, architectural visualisation or for (mobile) games. The images can be used as Skydomes or Skyboxes in programs like Unity to create a sky background for 3D scenes.

Download Magma Skybox Pack Vol.I (Skies)

HDRI Pack 7 (Exterior)

Set of 5 different skydome panoramas to be used as spherical environments or as a light source in 3d scenes. This product is ideal for realistic architectural renders or 3D animations.

It includes five 6000×3000 pixels High Dynamic Range Images (HDRI) and five 3000×1500 pixels JPGs to be used as a reflection map.

The items included in this pack are also available as individual files:

– Cloudy Ocean Day – HDRI: http://3docean.net/item/cloudy-ocean-day-hdri/11080008?s_rank=1
– Golden Hour 2 – HDRI: http://3docean.net/item/golden-hour-2-hdri/12099204?s_rank=1
– Ocean Bright Day 3 – HDRI: http://3docean.net/item/ocean-bright-day-3-hdri/11984547?s_rank=2
– Ocean Clear Sky – HDRI: http://3docean.net/item/ocean-clear-sky-hdri/12450488?s_rank=1
– Tropical Water – HDRI: http://3docean.net/item/tropical-water-hdri/10676921?s_rank=1

Download HDRI Pack 7 (Exterior)