Index: resources/sprite/manifest/projects.json
===================================================================
--- resources/sprite/manifest/projects.json
+++ resources/sprite/manifest/projects.json
@@ -1,284 +1,284 @@
 {
   "version" : 1,
   "sprites" : {
-    "projects_8ball"         : {
-      "name" : "projects_8ball",
-      "rule" : ".projects_8ball",
+    "projects-8ball"         : {
+      "name" : "projects-8ball",
+      "rule" : ".projects-8ball",
       "hash" : "1571c4d51926d3af7711b825c5816e2e"
     },
-    "projects_alien"         : {
-      "name" : "projects_alien",
-      "rule" : ".projects_alien",
+    "projects-alien"         : {
+      "name" : "projects-alien",
+      "rule" : ".projects-alien",
       "hash" : "384f920ae335dca04edaf29663d3a074"
     },
-    "projects_annouce"       : {
-      "name" : "projects_annouce",
-      "rule" : ".projects_annouce",
-      "hash" : "38abd2ff32e7c145e44c020ee4e6f2f1"
+    "projects-announce"      : {
+      "name" : "projects-announce",
+      "rule" : ".projects-announce",
+      "hash" : "94329cedd509fc27a6fb577927581118"
     },
-    "projects_art"           : {
-      "name" : "projects_art",
-      "rule" : ".projects_art",
+    "projects-art"           : {
+      "name" : "projects-art",
+      "rule" : ".projects-art",
       "hash" : "85c545e5130f00ff1b93c0af0d540974"
     },
-    "projects_award"         : {
-      "name" : "projects_award",
-      "rule" : ".projects_award",
+    "projects-award"         : {
+      "name" : "projects-award",
+      "rule" : ".projects-award",
       "hash" : "fad6d89e4938e16f22f3c9db7cf5d696"
     },
-    "projects_bacon"         : {
-      "name" : "projects_bacon",
-      "rule" : ".projects_bacon",
+    "projects-bacon"         : {
+      "name" : "projects-bacon",
+      "rule" : ".projects-bacon",
       "hash" : "f6300cdfa5a96a223f53f13dd0d3acc3"
     },
-    "projects_bandaid"       : {
-      "name" : "projects_bandaid",
-      "rule" : ".projects_bandaid",
+    "projects-bandaid"       : {
+      "name" : "projects-bandaid",
+      "rule" : ".projects-bandaid",
       "hash" : "c463dffa161997277fc6697155f4085b"
     },
-    "projects_beer"          : {
-      "name" : "projects_beer",
-      "rule" : ".projects_beer",
+    "projects-beer"          : {
+      "name" : "projects-beer",
+      "rule" : ".projects-beer",
       "hash" : "81c7580f322d9fb40c77db56cd92d61d"
     },
-    "projects_bomb"          : {
-      "name" : "projects_bomb",
-      "rule" : ".projects_bomb",
+    "projects-bomb"          : {
+      "name" : "projects-bomb",
+      "rule" : ".projects-bomb",
       "hash" : "1123da7cc56313891c9979b004cc02f7"
     },
-    "projects_briefcase"     : {
-      "name" : "projects_briefcase",
-      "rule" : ".projects_briefcase",
+    "projects-briefcase"     : {
+      "name" : "projects-briefcase",
+      "rule" : ".projects-briefcase",
       "hash" : "9b4b413ddb250ce1d3fbe18a5a5698cd"
     },
-    "projects_bug"           : {
-      "name" : "projects_bug",
-      "rule" : ".projects_bug",
+    "projects-bug"           : {
+      "name" : "projects-bug",
+      "rule" : ".projects-bug",
       "hash" : "9678702aed00c4779759ebbdfe97fe48"
     },
-    "projects_calendar"      : {
-      "name" : "projects_calendar",
-      "rule" : ".projects_calendar",
+    "projects-calendar"      : {
+      "name" : "projects-calendar",
+      "rule" : ".projects-calendar",
       "hash" : "e7dc5d1b11fc55ed239fcbfe527ed0e7"
     },
-    "projects_cloud"         : {
-      "name" : "projects_cloud",
-      "rule" : ".projects_cloud",
+    "projects-cloud"         : {
+      "name" : "projects-cloud",
+      "rule" : ".projects-cloud",
       "hash" : "d38bf58580b3c36fbd3149a13f7d0e5e"
     },
-    "projects_coffee"        : {
-      "name" : "projects_coffee",
-      "rule" : ".projects_coffee",
+    "projects-coffee"        : {
+      "name" : "projects-coffee",
+      "rule" : ".projects-coffee",
       "hash" : "a9c10862139d8e7f56c9f892496f9666"
     },
-    "projects_creditcard"    : {
-      "name" : "projects_creditcard",
-      "rule" : ".projects_creditcard",
+    "projects-creditcard"    : {
+      "name" : "projects-creditcard",
+      "rule" : ".projects-creditcard",
       "hash" : "db2c179cb4935da8b9950ac30da8c0d1"
     },
-    "projects_death"         : {
-      "name" : "projects_death",
-      "rule" : ".projects_death",
+    "projects-death"         : {
+      "name" : "projects-death",
+      "rule" : ".projects-death",
       "hash" : "cdea72dfdcb3fc64873b9fff78addb3c"
     },
-    "projects_desktop"       : {
-      "name" : "projects_desktop",
-      "rule" : ".projects_desktop",
+    "projects-desktop"       : {
+      "name" : "projects-desktop",
+      "rule" : ".projects-desktop",
       "hash" : "19d2ef34e3dd53615cdad91eb987d6fe"
     },
-    "projects_dropbox"       : {
-      "name" : "projects_dropbox",
-      "rule" : ".projects_dropbox",
+    "projects-dropbox"       : {
+      "name" : "projects-dropbox",
+      "rule" : ".projects-dropbox",
       "hash" : "10231bf468769b96ed40cf983abfa269"
     },
-    "projects_education"     : {
-      "name" : "projects_education",
-      "rule" : ".projects_education",
+    "projects-education"     : {
+      "name" : "projects-education",
+      "rule" : ".projects-education",
       "hash" : "ce3d0ca75d519b2ac427a690d30475f8"
     },
-    "projects_experimental"  : {
-      "name" : "projects_experimental",
-      "rule" : ".projects_experimental",
+    "projects-experimental"  : {
+      "name" : "projects-experimental",
+      "rule" : ".projects-experimental",
       "hash" : "311ef712f8daca057c20c8fd78fa77ce"
     },
-    "projects_facebook"      : {
-      "name" : "projects_facebook",
-      "rule" : ".projects_facebook",
+    "projects-facebook"      : {
+      "name" : "projects-facebook",
+      "rule" : ".projects-facebook",
       "hash" : "16581191e4ce9e0115d447b479c886cb"
     },
-    "projects_facility"      : {
-      "name" : "projects_facility",
-      "rule" : ".projects_facility",
+    "projects-facility"      : {
+      "name" : "projects-facility",
+      "rule" : ".projects-facility",
       "hash" : "d8893f9d2b75ec047b6f3898a386055c"
     },
-    "projects_film"          : {
-      "name" : "projects_film",
-      "rule" : ".projects_film",
+    "projects-film"          : {
+      "name" : "projects-film",
+      "rule" : ".projects-film",
       "hash" : "57497050fa09ba1533d981a9c1550ba9"
     },
-    "projects_forked"        : {
-      "name" : "projects_forked",
-      "rule" : ".projects_forked",
+    "projects-forked"        : {
+      "name" : "projects-forked",
+      "rule" : ".projects-forked",
       "hash" : "f575428e1079981840297bd444e51c43"
     },
-    "projects_games"         : {
-      "name" : "projects_games",
-      "rule" : ".projects_games",
+    "projects-games"         : {
+      "name" : "projects-games",
+      "rule" : ".projects-games",
       "hash" : "b802cff3e76051675b37165bd9702088"
     },
-    "projects_ghost"         : {
-      "name" : "projects_ghost",
-      "rule" : ".projects_ghost",
+    "projects-ghost"         : {
+      "name" : "projects-ghost",
+      "rule" : ".projects-ghost",
       "hash" : "7c8622cad29bddc5179f6a6d5f15fbe9"
     },
-    "projects_gift"          : {
-      "name" : "projects_gift",
-      "rule" : ".projects_gift",
+    "projects-gift"          : {
+      "name" : "projects-gift",
+      "rule" : ".projects-gift",
       "hash" : "f2ca678906a6806f421b60abddaa6cae"
     },
-    "projects_globe"         : {
-      "name" : "projects_globe",
-      "rule" : ".projects_globe",
+    "projects-globe"         : {
+      "name" : "projects-globe",
+      "rule" : ".projects-globe",
       "hash" : "87515a83cc0c840804aca594677d1eae"
     },
-    "projects_golf"          : {
-      "name" : "projects_golf",
-      "rule" : ".projects_golf",
+    "projects-golf"          : {
+      "name" : "projects-golf",
+      "rule" : ".projects-golf",
       "hash" : "1ee7556fab3d46d925deb00322dad858"
     },
-    "projects_heart"         : {
-      "name" : "projects_heart",
-      "rule" : ".projects_heart",
+    "projects-heart"         : {
+      "name" : "projects-heart",
+      "rule" : ".projects-heart",
       "hash" : "3da64839e37ee245333017d0a310cc2e"
     },
-    "projects_intergalactic" : {
-      "name" : "projects_intergalactic",
-      "rule" : ".projects_intergalactic",
+    "projects-intergalactic" : {
+      "name" : "projects-intergalactic",
+      "rule" : ".projects-intergalactic",
       "hash" : "94dca756cb267bdb4e0ed58467320780"
     },
-    "projects_lock"          : {
-      "name" : "projects_lock",
-      "rule" : ".projects_lock",
+    "projects-lock"          : {
+      "name" : "projects-lock",
+      "rule" : ".projects-lock",
       "hash" : "9d4c8ad3a4ac4163f284461da7df2763"
     },
-    "projects_mail"          : {
-      "name" : "projects_mail",
-      "rule" : ".projects_mail",
+    "projects-mail"          : {
+      "name" : "projects-mail",
+      "rule" : ".projects-mail",
       "hash" : "963f5ce26c6caf86e72d754f7b6e8865"
     },
-    "projects_martini"       : {
-      "name" : "projects_martini",
-      "rule" : ".projects_martini",
+    "projects-martini"       : {
+      "name" : "projects-martini",
+      "rule" : ".projects-martini",
       "hash" : "24d4d5fb5c334621ece4c35a9196471e"
     },
-    "projects_medical"       : {
-      "name" : "projects_medical",
-      "rule" : ".projects_medical",
+    "projects-medical"       : {
+      "name" : "projects-medical",
+      "rule" : ".projects-medical",
       "hash" : "e0cb3ef5557321d166e8eb49c10d3599"
     },
-    "projects_mobile"        : {
-      "name" : "projects_mobile",
-      "rule" : ".projects_mobile",
+    "projects-mobile"        : {
+      "name" : "projects-mobile",
+      "rule" : ".projects-mobile",
       "hash" : "37dec95d1a4a937743d52acac319c3b6"
     },
-    "projects_music"         : {
-      "name" : "projects_music",
-      "rule" : ".projects_music",
+    "projects-music"         : {
+      "name" : "projects-music",
+      "rule" : ".projects-music",
       "hash" : "e7a814194685ac25be0db05b04074607"
     },
-    "projects_news"          : {
-      "name" : "projects_news",
-      "rule" : ".projects_news",
+    "projects-news"          : {
+      "name" : "projects-news",
+      "rule" : ".projects-news",
       "hash" : "6861f3ee827d09b0592166514f4941e8"
     },
-    "projects_orgchart"      : {
-      "name" : "projects_orgchart",
-      "rule" : ".projects_orgchart",
+    "projects-orgchart"      : {
+      "name" : "projects-orgchart",
+      "rule" : ".projects-orgchart",
       "hash" : "20c51c59788fb2bc8184fdd5687d33dc"
     },
-    "projects_peoples"       : {
-      "name" : "projects_peoples",
-      "rule" : ".projects_peoples",
+    "projects-peoples"       : {
+      "name" : "projects-peoples",
+      "rule" : ".projects-peoples",
       "hash" : "c949ba6d09e68317a9a11482e75e5140"
     },
-    "projects_piechart"      : {
-      "name" : "projects_piechart",
-      "rule" : ".projects_piechart",
+    "projects-piechart"      : {
+      "name" : "projects-piechart",
+      "rule" : ".projects-piechart",
       "hash" : "051138560e30982a029aa5e4ea87bc17"
     },
-    "projects_poison"        : {
-      "name" : "projects_poison",
-      "rule" : ".projects_poison",
+    "projects-poison"        : {
+      "name" : "projects-poison",
+      "rule" : ".projects-poison",
       "hash" : "56ddafd138e421f198b9cb38e5dc7455"
     },
-    "projects_putabirdonit"  : {
-      "name" : "projects_putabirdonit",
-      "rule" : ".projects_putabirdonit",
+    "projects-putabirdonit"  : {
+      "name" : "projects-putabirdonit",
+      "rule" : ".projects-putabirdonit",
       "hash" : "ee298fff82c34341b986a3e1b77bea11"
     },
-    "projects_radiate"       : {
-      "name" : "projects_radiate",
-      "rule" : ".projects_radiate",
+    "projects-radiate"       : {
+      "name" : "projects-radiate",
+      "rule" : ".projects-radiate",
       "hash" : "9cfb918089b3de8506a5d270a119052c"
     },
-    "projects_savings"       : {
-      "name" : "projects_savings",
-      "rule" : ".projects_savings",
+    "projects-savings"       : {
+      "name" : "projects-savings",
+      "rule" : ".projects-savings",
       "hash" : "9e92bc5e64f79d2f4842ac24a8b57fcb"
     },
-    "projects_search"        : {
-      "name" : "projects_search",
-      "rule" : ".projects_search",
+    "projects-search"        : {
+      "name" : "projects-search",
+      "rule" : ".projects-search",
       "hash" : "a42c1c31f2929838b0f181f417c0b6a4"
     },
-    "projects_shield"        : {
-      "name" : "projects_shield",
-      "rule" : ".projects_shield",
+    "projects-shield"        : {
+      "name" : "projects-shield",
+      "rule" : ".projects-shield",
       "hash" : "40c6e1bec7c07c165668ac45c218847a"
     },
-    "projects_speed"         : {
-      "name" : "projects_speed",
-      "rule" : ".projects_speed",
+    "projects-speed"         : {
+      "name" : "projects-speed",
+      "rule" : ".projects-speed",
       "hash" : "2b70c194d07f5a9d95abc51d84fb22ed"
     },
-    "projects_sprint"        : {
-      "name" : "projects_sprint",
-      "rule" : ".projects_sprint",
+    "projects-sprint"        : {
+      "name" : "projects-sprint",
+      "rule" : ".projects-sprint",
       "hash" : "655ef9a3043eab23eac1da21baeb36b3"
     },
-    "projects_star"          : {
-      "name" : "projects_star",
-      "rule" : ".projects_star",
+    "projects-star"          : {
+      "name" : "projects-star",
+      "rule" : ".projects-star",
       "hash" : "a46e3c18f68bc13a65b410496e27b5d7"
     },
-    "projects_storage"       : {
-      "name" : "projects_storage",
-      "rule" : ".projects_storage",
+    "projects-storage"       : {
+      "name" : "projects-storage",
+      "rule" : ".projects-storage",
       "hash" : "bb19baa77bb7596f43f77e5dbbddb006"
     },
-    "projects_tablet"        : {
-      "name" : "projects_tablet",
-      "rule" : ".projects_tablet",
+    "projects-tablet"        : {
+      "name" : "projects-tablet",
+      "rule" : ".projects-tablet",
       "hash" : "830dcf6637288ca122c8f5034cae3769"
     },
-    "projects_travel"        : {
-      "name" : "projects_travel",
-      "rule" : ".projects_travel",
+    "projects-travel"        : {
+      "name" : "projects-travel",
+      "rule" : ".projects-travel",
       "hash" : "86ec4dcd025879a43435b101fd542a1b"
     },
-    "projects_twitter"       : {
-      "name" : "projects_twitter",
-      "rule" : ".projects_twitter",
+    "projects-twitter"       : {
+      "name" : "projects-twitter",
+      "rule" : ".projects-twitter",
       "hash" : "75b8680dd1e4ecce4ca3a39c87e1ed80"
     },
-    "projects_warning"       : {
-      "name" : "projects_warning",
-      "rule" : ".projects_warning",
+    "projects-warning"       : {
+      "name" : "projects-warning",
+      "rule" : ".projects-warning",
       "hash" : "3ac48b6f963675e1f4bb4ac75aad936f"
     },
-    "projects_whale"         : {
-      "name" : "projects_whale",
-      "rule" : ".projects_whale",
+    "projects-whale"         : {
+      "name" : "projects-whale",
+      "rule" : ".projects-whale",
       "hash" : "569b584c7e80a0a9b965280abd27c723"
     }
   },
Index: src/__celerity_resource_map__.php
===================================================================
--- src/__celerity_resource_map__.php
+++ src/__celerity_resource_map__.php
@@ -1791,6 +1791,18 @@
     ),
     'disk' => '/rsrc/js/core/behavior-history-install.js',
   ),
+  'javelin-behavior-icon-composer' =>
+  array(
+    'uri' => '/res/0be5c462/rsrc/js/application/files/behavior-icon-composer.js',
+    'type' => 'js',
+    'requires' =>
+    array(
+      0 => 'javelin-behavior',
+      1 => 'javelin-dom',
+      2 => 'javelin-stratcom',
+    ),
+    'disk' => '/rsrc/js/application/files/behavior-icon-composer.js',
+  ),
   'javelin-behavior-konami' =>
   array(
     'uri' => '/res/b7bb7c24/rsrc/js/core/behavior-konami.js',
@@ -1802,6 +1814,18 @@
     ),
     'disk' => '/rsrc/js/core/behavior-konami.js',
   ),
+  'javelin-behavior-launch-icon-composer' =>
+  array(
+    'uri' => '/res/202488ac/rsrc/js/application/files/behavior-launch-icon-composer.js',
+    'type' => 'js',
+    'requires' =>
+    array(
+      0 => 'javelin-behavior',
+      1 => 'javelin-dom',
+      2 => 'javelin-workflow',
+    ),
+    'disk' => '/rsrc/js/application/files/behavior-launch-icon-composer.js',
+  ),
   'javelin-behavior-lightbox-attachments' =>
   array(
     'uri' => '/res/72b4d3a8/rsrc/js/core/behavior-lightbox-attachments.js',
@@ -3062,7 +3086,7 @@
   ),
   'people-profile-css' =>
   array(
-    'uri' => '/res/d50d9502/rsrc/css/application/people/people-profile.css',
+    'uri' => '/res/f1da102e/rsrc/css/application/people/people-profile.css',
     'type' => 'css',
     'requires' =>
     array(
@@ -4227,7 +4251,7 @@
   ),
   'sprite-projects-css' =>
   array(
-    'uri' => '/res/3ff34b69/rsrc/css/sprite-projects.css',
+    'uri' => '/res/40eacbfb/rsrc/css/sprite-projects.css',
     'type' => 'css',
     'requires' =>
     array(
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1209,6 +1209,7 @@
     'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
     'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php',
     'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php',
+    'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php',
     'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php',
     'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php',
     'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
@@ -1523,6 +1524,7 @@
     'PhabricatorProjectProfile' => 'applications/project/storage/PhabricatorProjectProfile.php',
     'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
     'PhabricatorProjectProfileEditController' => 'applications/project/controller/PhabricatorProjectProfileEditController.php',
+    'PhabricatorProjectProfilePictureController' => 'applications/project/controller/PhabricatorProjectProfilePictureController.php',
     'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php',
     'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php',
     'PhabricatorProjectSearchIndexer' => 'applications/project/search/PhabricatorProjectSearchIndexer.php',
@@ -3397,6 +3399,7 @@
       3 => 'PhabricatorPolicyInterface',
     ),
     'PhabricatorFileCommentController' => 'PhabricatorFileController',
+    'PhabricatorFileComposeController' => 'PhabricatorFileController',
     'PhabricatorFileController' => 'PhabricatorController',
     'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
     'PhabricatorFileDataController' => 'PhabricatorFileController',
@@ -3739,6 +3742,7 @@
     'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
     'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
     'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
+    'PhabricatorProjectProfilePictureController' => 'PhabricatorProjectController',
     'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
     'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine',
     'PhabricatorProjectSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
Index: src/applications/files/application/PhabricatorApplicationFiles.php
===================================================================
--- src/applications/files/application/PhabricatorApplicationFiles.php
+++ src/applications/files/application/PhabricatorApplicationFiles.php
@@ -51,6 +51,7 @@
         '(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController',
         'upload/' => 'PhabricatorFileUploadController',
         'dropupload/' => 'PhabricatorFileDropUploadController',
+        'compose/' => 'PhabricatorFileComposeController',
         'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorFileCommentController',
         'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
         'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
Index: src/applications/files/controller/PhabricatorFileComposeController.php
===================================================================
--- /dev/null
+++ src/applications/files/controller/PhabricatorFileComposeController.php
@@ -0,0 +1,249 @@
+<?php
+
+final class PhabricatorFileComposeController
+  extends PhabricatorFileController {
+
+  public function processRequest() {
+    $request = $this->getRequest();
+    $viewer = $request->getUser();
+
+    $colors = array(
+      'red' => pht('Verbillion'),
+      'orange' => pht('Navel Orange'),
+      'yellow' => pht('Prim Goldenrod'),
+      'green' => pht('Lustrous Verdant'),
+      'blue' => pht('Tropical Deep'),
+      'sky' => pht('Wide Open Sky'),
+      'indigo' => pht('Pleated Khaki'),
+      'violet' => pht('Aged Merlot'),
+      'charcoal' => pht('Gemstone'),
+      'backdrop' => pht('Driven Snow'),
+    );
+
+    $manifest = PHUIIconView::getSheetManifest(PHUIIconView::SPRITE_PROJECTS);
+
+    if ($request->isFormPost()) {
+      $icon = $request->getStr('icon');
+      $color = $request->getStr('color');
+
+      if (isset($colors[$color]) && isset($manifest['projects-'.$icon])) {
+        $root = dirname(phutil_get_library_root('phabricator'));
+        $icon_file = $root.'/resources/sprite/projects_1x/'.$icon.'.png';
+        $icon_data = Filesystem::readFile($icon_file);
+
+
+        $data = $this->composeImage($color, $icon_data);
+
+        $file = PhabricatorFile::buildFromFileDataOrHash(
+          $data,
+          array(
+            'name' => 'project.png',
+          ));
+
+        $content = array(
+          'phid' => $file->getPHID(),
+        );
+
+        return id(new AphrontAjaxResponse())->setContent($content);
+      }
+    }
+
+    $value_color = head_key($colors);
+    $value_icon = head_key($manifest);
+    $value_icon = substr($value_icon, strlen('projects-'));
+
+    require_celerity_resource('people-profile-css');
+
+    $buttons = array();
+    foreach ($colors as $color => $name) {
+      $buttons[] = javelin_tag(
+        'button',
+        array(
+          'class' => 'grey profile-image-button',
+          'sigil' => 'has-tooltip compose-select-color',
+          'style' => 'margin: 0 8px 8px 0',
+          'meta' => array(
+            'color' => $color,
+            'tip' => $name,
+          ),
+        ),
+        id(new PHUIIconView())
+          ->addClass('compose-background-'.$color));
+    }
+
+    $icons = array();
+
+    $icon_quips = array(
+      '8ball' => pht('Take a Risk'),
+      'alien' => pht('Foreign Interface'),
+      'announce' => pht('Louder is Better'),
+      'art' => pht('Unique Snowflake'),
+      'award' => pht('Shooting Star'),
+      'bacon' => pht('Healthy Vegetables'),
+      'bandaid' => pht('Durable Infrastructure'),
+      'beer' => pht('Healthy Vegetable Juice'),
+      'bomb' => pht('Imminent Success'),
+      'briefcase' => pht('Adventure Pack'),
+      'bug' => pht('Costumed Egg'),
+      'calendar' => pht('Everyone Loves Meetings'),
+      'cloud' => pht('Water Cycle'),
+      'coffee' => pht('Half-Whip Nonfat Soy Latte'),
+      'creditcard' => pht('Expense It'),
+      'death' => pht('Calcium Promotes Bone Health'),
+      'desktop' => pht('Magical Portal'),
+      'dropbox' => pht('Cardboard Box'),
+      'education' => pht('Debt'),
+      'experimental' => pht('CAUTION: Dangerous Chemicals'),
+      'facebook' => pht('Popular Social Network'),
+      'facility' => pht('Pollution Solves Problems'),
+      'film' => pht('Actual Physical Film'),
+      'forked' => pht('You Can\'t Eat Soup'),
+      'games' => pht('Serious Business'),
+      'ghost' => pht('Haunted'),
+      'gift' => pht('Surprise!'),
+      'globe' => pht('Scanner Sweep'),
+      'golf' => pht('Business Meeting'),
+      'heart' => pht('Undergoing a Major Surgery'),
+      'intergalactic' => pht('Jupiter'),
+      'lock' => pht('Extremely Secret'),
+      'mail' => pht('Oragami'),
+      'martini' => pht('Healthy Olive Drink'),
+      'medical' => pht('Medic!'),
+      'mobile' => pht('Cellular Telephone'),
+      'music' => pht("\xE2\x99\xAB"),
+      'news' => pht('Actual Physical Newspaper'),
+      'orgchart' => pht('It\'s Good to be King'),
+      'peoples' => pht('Angel and Devil'),
+      'piechart' => pht('Actual Physical Pie'),
+      'poison' => pht('Healthy Bone Juice'),
+      'putabirdonit' => pht('Put a Bird On It'),
+      'radiate' => pht('Radiant Beauty'),
+      'savings' => pht('Oink Oink'),
+      'search' => pht('Sleuthing'),
+      'shield' => pht('Royal Crest'),
+      'speed' => pht('Slow and Steady'),
+      'sprint' => pht('Fire Exit'),
+      'star' => pht('The More You Know'),
+      'storage' => pht('Stack of Pancakes'),
+      'tablet' => pht('Cellular Telephone For Giants'),
+      'travel' => pht('Pretty Clearly an Airplane'),
+      'twitter' => pht('Bird Stencil'),
+      'warning' => pht('No Caution Required, Everything Looks Safe'),
+      'whale' => pht('Friendly Walrus'),
+    );
+
+    foreach ($manifest as $icon => $spec) {
+      $icon = substr($icon, strlen('projects-'));
+
+      $icons[] = javelin_tag(
+        'button',
+        array(
+          'class' => 'grey profile-image-button',
+          'sigil' => 'has-tooltip compose-select-icon',
+          'style' => 'margin: 0 8px 8px 0',
+          'meta' => array(
+            'icon' => $icon,
+            'tip' => idx($icon_quips, $icon, $icon),
+          ),
+        ),
+        id(new PHUIIconView())
+          ->setSpriteIcon($icon)
+          ->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS));
+    }
+
+    $dialog_id = celerity_generate_unique_node_id();
+    $color_input_id = celerity_generate_unique_node_id();;
+    $icon_input_id = celerity_generate_unique_node_id();
+    $preview_id = celerity_generate_unique_node_id();
+
+    $preview = id(new PHUIIconView())
+      ->setID($preview_id)
+      ->addClass('compose-background-'.$value_color)
+      ->setSpriteIcon($value_icon)
+      ->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS);
+
+    $color_input = javelin_tag(
+      'input',
+      array(
+        'type' => 'hidden',
+        'name' => 'color',
+        'value' => $value_color,
+        'id' => $color_input_id,
+      ));
+
+    $icon_input = javelin_tag(
+      'input',
+      array(
+        'type' => 'hidden',
+        'name' => 'icon',
+        'value' => $value_icon,
+        'id' => $icon_input_id,
+      ));
+
+    Javelin::initBehavior('phabricator-tooltips');
+    Javelin::initBehavior(
+      'icon-composer',
+      array(
+        'dialogID' => $dialog_id,
+        'colorInputID' => $color_input_id,
+        'iconInputID' => $icon_input_id,
+        'previewID' => $preview_id,
+        'defaultColor' => $value_color,
+        'defaultIcon' => $value_icon,
+      ));
+
+    $dialog = id(new AphrontDialogView())
+      ->setUser($viewer)
+      ->setFormID($dialog_id)
+      ->setClass('compose-dialog')
+      ->setTitle(pht('Compose Image'))
+      ->appendChild(
+        phutil_tag(
+          'div',
+          array(
+            'class' => 'compose-header',
+          ),
+          pht('Choose Background Color')))
+      ->appendChild($buttons)
+      ->appendChild(
+        phutil_tag(
+          'div',
+          array(
+            'class' => 'compose-header',
+          ),
+          pht('Choose Icon')))
+      ->appendChild($icons)
+      ->appendChild(
+        phutil_tag(
+          'div',
+          array(
+            'class' => 'compose-header',
+          ),
+          pht('Preview')))
+      ->appendChild($preview)
+      ->appendChild($color_input)
+      ->appendChild($icon_input)
+      ->addCancelButton('/')
+      ->addSubmitButton(pht('Save Image'));
+
+    return id(new AphrontDialogResponse())->setDialog($dialog);
+  }
+
+  private function composeImage($color, $icon_data) {
+    $icon_img = imagecreatefromstring($icon_data);
+
+    $map = CelerityResourceTransformer::getCSSVariableMap();
+    $color_string = idx($map, $color, '#ff00ff');
+    $color_const = hexdec(trim($color_string, '#'));
+
+    $canvas = imagecreatetruecolor(50, 50);
+    imagefill($canvas, 0, 0, $color_const);
+
+    imagecopy($canvas, $icon_img, 0, 0, 0, 0, 50, 50);
+
+    return PhabricatorImageTransformer::saveImageDataInAnyFormat(
+      $canvas,
+      'image/png');
+  }
+
+}
Index: src/applications/project/application/PhabricatorApplicationProject.php
===================================================================
--- src/applications/project/application/PhabricatorApplicationProject.php
+++ src/applications/project/application/PhabricatorApplicationProject.php
@@ -42,6 +42,8 @@
           => 'PhabricatorProjectMembersEditController',
         'view/(?P<id>[1-9]\d*)/(?:(?P<page>\w+)/)?'
           => 'PhabricatorProjectProfileController',
+        'picture/(?P<id>[1-9]\d*)/' =>
+          'PhabricatorProjectProfilePictureController',
         'create/' => 'PhabricatorProjectCreateController',
         'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
           => 'PhabricatorProjectUpdateController',
Index: src/applications/project/controller/PhabricatorProjectProfileController.php
===================================================================
--- src/applications/project/controller/PhabricatorProjectProfileController.php
+++ src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -216,6 +216,14 @@
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
+    $view->addAction(
+      id(new PhabricatorActionView())
+        ->setName(pht('Edit Picture'))
+        ->setIcon('image')
+        ->setHref($this->getApplicationURI("picture/{$id}/"))
+        ->setDisabled(!$can_edit)
+        ->setWorkflow(!$can_edit));
+
 
     $action = null;
     if (!$project->isUserMember($viewer->getPHID())) {
Index: src/applications/project/controller/PhabricatorProjectProfileEditController.php
===================================================================
--- src/applications/project/controller/PhabricatorProjectProfileEditController.php
+++ src/applications/project/controller/PhabricatorProjectProfileEditController.php
@@ -29,14 +29,9 @@
     }
 
     $profile = $project->getProfile();
-    $img_src = $profile->getProfileImageURI();
-
     $options = PhabricatorProjectStatus::getStatusMap();
 
-    $supported_formats = PhabricatorFile::getTransformableImageFormats();
-
     $e_name = true;
-    $e_image = null;
 
     $errors = array();
     if ($request->isFormPost()) {
@@ -89,37 +84,6 @@
         $e_name = null;
       }
 
-      $default_image = $request->getExists('default_image');
-      if ($default_image) {
-        $profile->setProfileImagePHID(null);
-      } else if (!empty($_FILES['image'])) {
-        $err = idx($_FILES['image'], 'error');
-        if ($err != UPLOAD_ERR_NO_FILE) {
-          $file = PhabricatorFile::newFromPHPUpload(
-            $_FILES['image'],
-            array(
-              'authorPHID' => $user->getPHID(),
-            ));
-          $okay = $file->isTransformableImage();
-          if ($okay) {
-            $xformer = new PhabricatorImageTransformer();
-            $xformed = $xformer->executeThumbTransform(
-              $file,
-              $x = 50,
-              $y = 50);
-
-            $profile->setProfileImagePHID($xformed->getPHID());
-            $xformed->attachToObject($user, $project->getPHID());
-
-          } else {
-            $e_image = pht('Not Supported');
-            $errors[] =
-              pht('This server only supports these image formats:').' '.
-              implode(', ', $supported_formats).'.';
-          }
-        }
-      }
-
       if (!$errors) {
         $project->save();
         $profile->setProjectPHID($project->getPHID());
@@ -150,7 +114,6 @@
       ->setID('project-edit-form')
       ->setUser($user)
       ->setAction($action)
-      ->setEncType('multipart/form-data')
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setLabel(pht('Name'))
@@ -199,22 +162,6 @@
           ->setPolicies($policies)
           ->setCapability(PhabricatorPolicyCapability::CAN_JOIN))
       ->appendChild(
-        id(new AphrontFormMarkupControl())
-          ->setLabel(pht('Profile Image'))
-          ->setValue(
-            phutil_tag(
-              'img',
-              array(
-                'src' => $img_src,
-              ))))
-      ->appendChild(
-        id(new AphrontFormImageControl())
-          ->setLabel(pht('Change Image'))
-          ->setName('image')
-          ->setError($e_image)
-          ->setCaption(
-            pht('Supported formats:').' '.implode(', ', $supported_formats)))
-      ->appendChild(
         id(new AphrontFormSubmitControl())
           ->addCancelButton('/project/view/'.$project->getID().'/')
           ->setValue(pht('Save')));
Index: src/applications/project/controller/PhabricatorProjectProfilePictureController.php
===================================================================
--- /dev/null
+++ src/applications/project/controller/PhabricatorProjectProfilePictureController.php
@@ -0,0 +1,274 @@
+<?php
+
+final class PhabricatorProjectProfilePictureController
+  extends PhabricatorProjectController {
+
+  private $id;
+
+  public function willProcessRequest(array $data) {
+    $this->id = $data['id'];
+  }
+
+  public function processRequest() {
+    $request = $this->getRequest();
+    $viewer = $request->getUser();
+
+    $project = id(new PhabricatorProjectQuery())
+      ->setViewer($viewer)
+      ->withIDs(array($this->id))
+      ->needProfiles(true)
+      ->requireCapabilities(
+        array(
+          PhabricatorPolicyCapability::CAN_VIEW,
+          PhabricatorPolicyCapability::CAN_EDIT,
+        ))
+      ->executeOne();
+    if (!$project) {
+      return new Aphront404Response();
+    }
+
+    $project_uri = $this->getApplicationURI('view/'.$project->getID().'/');
+
+    $supported_formats = PhabricatorFile::getTransformableImageFormats();
+    $e_file = true;
+    $errors = array();
+
+    if ($request->isFormPost()) {
+      $phid = $request->getStr('phid');
+      $is_default = false;
+      if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
+        $phid = null;
+        $is_default = true;
+      } else if ($phid) {
+        $file = id(new PhabricatorFileQuery())
+          ->setViewer($viewer)
+          ->withPHIDs(array($phid))
+          ->executeOne();
+      } else {
+        if ($request->getFileExists('picture')) {
+          $file = PhabricatorFile::newFromPHPUpload(
+            $_FILES['picture'],
+            array(
+              'authorPHID' => $viewer->getPHID(),
+            ));
+        } else {
+          $e_file = pht('Required');
+          $errors[] = pht(
+            'You must choose a file when uploading a new project picture.');
+        }
+      }
+
+      if (!$errors && !$is_default) {
+        if (!$file->isTransformableImage()) {
+          $e_file = pht('Not Supported');
+          $errors[] = pht(
+            'This server only supports these image formats: %s.',
+            implode(', ', $supported_formats));
+        } else {
+          $xformer = new PhabricatorImageTransformer();
+          $xformed = $xformer->executeProfileTransform(
+            $file,
+            $width = 50,
+            $min_height = 50,
+            $max_height = 50);
+        }
+      }
+
+      if (!$errors) {
+        $profile = $project->getProfile();
+        if ($is_default) {
+          $profile->setProfileImagePHID(null);
+        } else {
+          $profile->setProfileImagePHID($xformed->getPHID());
+          $xformed->attachToObject($viewer, $project->getPHID());
+        }
+        $profile->save();
+        return id(new AphrontRedirectResponse())->setURI($project_uri);
+      }
+    }
+
+    $title = pht('Edit Project Picture');
+    $crumbs = $this->buildApplicationCrumbs();
+    $crumbs->addCrumb(
+      id(new PhabricatorCrumbView())
+        ->setName($project->getName())
+        ->setHref($project_uri));
+    $crumbs->addCrumb(
+      id(new PhabricatorCrumbView())
+        ->setName($title));
+
+    $form = id(new PHUIFormLayoutView())
+      ->setUser($viewer);
+
+    $default_image = PhabricatorFile::loadBuiltin($viewer, 'project.png');
+
+    $images = array();
+
+    $current = $project->getProfile()->getProfileImagePHID();
+    $has_current = false;
+    if ($current) {
+      $files = id(new PhabricatorFileQuery())
+        ->setViewer($viewer)
+        ->withPHIDs(array($current))
+        ->execute();
+      if ($files) {
+        $file = head($files);
+        if ($file->isTransformableImage()) {
+          $has_current = true;
+          $images[$current] = array(
+            'uri' => $file->getBestURI(),
+            'tip' => pht('Current Picture'),
+          );
+        }
+      }
+    }
+
+    $images[PhabricatorPHIDConstants::PHID_VOID] = array(
+      'uri' => $default_image->getBestURI(),
+      'tip' => pht('Default Picture'),
+    );
+
+    require_celerity_resource('people-profile-css');
+    Javelin::initBehavior('phabricator-tooltips', array());
+
+    $buttons = array();
+    foreach ($images as $phid => $spec) {
+      $button = javelin_tag(
+        'button',
+        array(
+          'class' => 'grey profile-image-button',
+          'sigil' => 'has-tooltip',
+          'meta' => array(
+            'tip' => $spec['tip'],
+            'size' => 300,
+          ),
+        ),
+        phutil_tag(
+          'img',
+          array(
+            'height' => 50,
+            'width' => 50,
+            'src' => $spec['uri'],
+          )));
+
+      $button = array(
+        phutil_tag(
+          'input',
+          array(
+            'type'  => 'hidden',
+            'name'  => 'phid',
+            'value' => $phid,
+          )),
+        $button);
+
+      $button = phabricator_form(
+        $viewer,
+        array(
+          'class' => 'profile-image-form',
+          'method' => 'POST',
+        ),
+        $button);
+
+      $buttons[] = $button;
+    }
+
+    if ($has_current) {
+      $form->appendChild(
+        id(new AphrontFormMarkupControl())
+          ->setLabel(pht('Current Picture'))
+          ->setValue(array_shift($buttons)));
+    }
+
+    $form->appendChild(
+      id(new AphrontFormMarkupControl())
+        ->setLabel(pht('Use Picture'))
+        ->setValue($buttons));
+
+    $launch_id = celerity_generate_unique_node_id();
+    $input_id = celerity_generate_unique_node_id();
+
+    Javelin::initBehavior(
+      'launch-icon-composer',
+      array(
+        'launchID' => $launch_id,
+        'inputID' => $input_id,
+      ));
+
+    $compose_button = javelin_tag(
+      'button',
+      array(
+        'class' => 'grey',
+        'id' => $launch_id,
+        'sigil' => 'icon-composer',
+      ),
+      pht('Choose Icon and Color...'));
+
+    $compose_input = javelin_tag(
+      'input',
+      array(
+        'type' => 'hidden',
+        'id' => $input_id,
+        'name' => 'phid',
+      ));
+
+    $compose_form = phabricator_form(
+      $viewer,
+      array(
+        'class' => 'profile-image-form',
+        'method' => 'POST',
+      ),
+      array(
+        $compose_input,
+        $compose_button,
+      ));
+
+    $form->appendChild(
+      id(new AphrontFormMarkupControl())
+        ->setLabel(pht('Quick Create'))
+        ->setValue($compose_form));
+
+    $form_box = id(new PHUIObjectBoxView())
+      ->setHeaderText($title)
+      ->setFormError($errors)
+      ->setForm($form);
+
+    $upload_form = id(new AphrontFormView())
+      ->setUser($viewer)
+      ->setEncType('multipart/form-data')
+      ->appendChild(
+        id(new AphrontFormFileControl())
+          ->setName('picture')
+          ->setLabel(pht('Upload Picture'))
+          ->setError($e_file)
+          ->setCaption(
+            pht('Supported formats: %s', implode(', ', $supported_formats))))
+      ->appendChild(
+        id(new AphrontFormSubmitControl())
+          ->addCancelButton($project_uri)
+          ->setValue(pht('Upload Picture')));
+
+    if ($errors) {
+      $errors = id(new AphrontErrorView())->setErrors($errors);
+    }
+
+    $form_box = id(new PHUIObjectBoxView())
+      ->setHeaderText($title)
+      ->setFormError($errors)
+      ->setForm($form);
+
+    $upload_box = id(new PHUIObjectBoxView())
+      ->setHeaderText(pht('Upload New Picture'))
+      ->setForm($upload_form);
+
+    return $this->buildApplicationPage(
+      array(
+        $crumbs,
+        $form_box,
+        $upload_box,
+      ),
+      array(
+        'title' => $title,
+        'device' => true,
+      ));
+  }
+}
Index: src/applications/project/query/PhabricatorProjectQuery.php
===================================================================
--- src/applications/project/query/PhabricatorProjectQuery.php
+++ src/applications/project/query/PhabricatorProjectQuery.php
@@ -142,7 +142,7 @@
             if (!$default) {
               $default = PhabricatorFile::loadBuiltin(
                 $this->getViewer(),
-                'profile.png');
+                'project.png');
             }
             $file = $default;
           }
@@ -156,7 +156,7 @@
           if (!$default) {
             $default = PhabricatorFile::loadBuiltin(
               $this->getViewer(),
-              'profile.png');
+              'project.png');
           }
           $profile = id(new PhabricatorProjectProfile())
             ->setProjectPHID($project->getPHID())
Index: src/infrastructure/celerity/CelerityResourceTransformer.php
===================================================================
--- src/infrastructure/celerity/CelerityResourceTransformer.php
+++ src/infrastructure/celerity/CelerityResourceTransformer.php
@@ -129,8 +129,8 @@
       $data);
   }
 
-  public function replaceCSSVariable($matches) {
-    static $map = array(
+  public static function getCSSVariableMap() {
+    return array(
       // Base Colors
       'red'           => '#c0392b',
       'lightred'      => '#f4dddb',
@@ -148,6 +148,8 @@
       'lightindigo'   => '#f5e2ef',
       'violet'        => '#8e44ad',
       'lightviolet'   => '#ecdff1',
+      'charcoal'      => '#4b4d51',
+      'backdrop'      => '#c4cde0',
 
       // Base Greys
       'lightgreyborder'     => '#C7CCD9',
@@ -170,6 +172,13 @@
       'bluetext'            => '#6B748C',
       'darkbluetext'        => '#464C5C',
     );
+  }
+
+  public function replaceCSSVariable($matches) {
+    static $map;
+    if (!$map) {
+      $map = self::getCSSVariableMap();
+    }
 
     $var_name = $matches[1];
     if (empty($map[$var_name])) {
Index: src/infrastructure/celerity/CeleritySpriteGenerator.php
===================================================================
--- src/infrastructure/celerity/CeleritySpriteGenerator.php
+++ src/infrastructure/celerity/CeleritySpriteGenerator.php
@@ -347,14 +347,14 @@
       ->setSourceSize(50, 50);
 
     $sprites = array();
-    $prefix = 'projects_';
+    $prefix = 'projects-';
     foreach ($icons as $icon) {
       $sprite = id(clone $template)
         ->setName($prefix.$icon)
         ->setTargetCSS('.'.$prefix.$icon);
 
       foreach ($scales as $scale_key => $scale) {
-        $path = $this->getPath($prefix.$scale_key.'/'.$icon.'.png');
+        $path = $this->getPath('projects_'.$scale_key.'/'.$icon.'.png');
         $sprite->setSourceFile($path, $scale);
       }
       $sprites[] = $sprite;
Index: src/view/phui/PHUIIconView.php
===================================================================
--- src/view/phui/PHUIIconView.php
+++ src/view/phui/PHUIIconView.php
@@ -10,6 +10,7 @@
   const SPRITE_ICONS = 'icons';
   const SPRITE_LOGIN = 'login';
   const SPRITE_STATUS = 'status';
+  const SPRITE_PROJECTS = 'projects';
 
   const HEAD_SMALL = 'phuihead-small';
   const HEAD_MEDIUM = 'phuihead-medium';
Index: webroot/rsrc/css/application/people/people-profile.css
===================================================================
--- webroot/rsrc/css/application/people/people-profile.css
+++ webroot/rsrc/css/application/people/people-profile.css
@@ -11,3 +11,69 @@
   padding: 4px;
   margin: 0;
 }
+
+.compose-dialog button.profile-image-button-selected {
+  background-image: none;
+  background-color: {$lightblue};
+  border-color: {$blueborder};
+}
+
+.compose-header {
+  color: {$bluetext};
+  border-bottom: 1px solid {$lightblueborder};
+  padding: 4px 0;
+  margin: 0 0 8px;
+}
+
+form.compose-dialog {
+  width: 80%;
+}
+
+.compose-dialog .phui-icon-view {
+  display: block;
+  position: relative;
+  width: 50px;
+  height: 50px;
+  background-color: {$darkgreytext};
+}
+
+.compose-dialog .compose-background-red {
+  background-color: {$red};
+}
+
+.compose-dialog .compose-background-orange {
+  background-color: {$orange};
+}
+
+.compose-dialog .compose-background-yellow {
+  background-color: {$yellow};
+}
+
+.compose-dialog .compose-background-green {
+  background-color: {$green};
+}
+
+.compose-dialog .compose-background-blue {
+  background-color: {$blue};
+}
+
+.compose-dialog .compose-background-sky {
+  background-color: {$sky};
+}
+
+.compose-dialog .compose-background-indigo {
+  background-color: {$indigo};
+}
+
+.compose-dialog .compose-background-violet {
+  background-color: {$violet};
+}
+
+.compose-dialog .compose-background-charcoal {
+  background-color: {$charcoal};
+}
+
+.compose-dialog .compose-background-backdrop {
+  background-color: {$backdrop};
+}
+
Index: webroot/rsrc/css/phui/phui-workpanel-view.css
===================================================================
--- webroot/rsrc/css/phui/phui-workpanel-view.css
+++ webroot/rsrc/css/phui/phui-workpanel-view.css
@@ -15,7 +15,7 @@
 }
 
 .phui-workpanel-view .phui-workpanel-body {
-  background: #c4cde0;
+  background: {$backdrop};
   padding: 5px 5px 1px 5px;
   border-bottom-left-radius: 5px;
   border-bottom-right-radius: 5px;
Index: webroot/rsrc/css/sprite-projects.css
===================================================================
--- webroot/rsrc/css/sprite-projects.css
+++ webroot/rsrc/css/sprite-projects.css
@@ -18,226 +18,226 @@
 }
 
 
-.projects_8ball {
+.projects-8ball {
   background-position: 0px 0px;
 }
 
-.projects_alien {
+.projects-alien {
   background-position: -51px 0px;
 }
 
-.projects_annouce {
+.projects-announce {
   background-position: -102px 0px;
 }
 
-.projects_art {
+.projects-art {
   background-position: -153px 0px;
 }
 
-.projects_award {
+.projects-award {
   background-position: -204px 0px;
 }
 
-.projects_bacon {
+.projects-bacon {
   background-position: -255px 0px;
 }
 
-.projects_bandaid {
+.projects-bandaid {
   background-position: -306px 0px;
 }
 
-.projects_beer {
+.projects-beer {
   background-position: 0px -51px;
 }
 
-.projects_bomb {
+.projects-bomb {
   background-position: -51px -51px;
 }
 
-.projects_briefcase {
+.projects-briefcase {
   background-position: -102px -51px;
 }
 
-.projects_bug {
+.projects-bug {
   background-position: -153px -51px;
 }
 
-.projects_calendar {
+.projects-calendar {
   background-position: -204px -51px;
 }
 
-.projects_cloud {
+.projects-cloud {
   background-position: -255px -51px;
 }
 
-.projects_coffee {
+.projects-coffee {
   background-position: -306px -51px;
 }
 
-.projects_creditcard {
+.projects-creditcard {
   background-position: 0px -102px;
 }
 
-.projects_death {
+.projects-death {
   background-position: -51px -102px;
 }
 
-.projects_desktop {
+.projects-desktop {
   background-position: -102px -102px;
 }
 
-.projects_dropbox {
+.projects-dropbox {
   background-position: -153px -102px;
 }
 
-.projects_education {
+.projects-education {
   background-position: -204px -102px;
 }
 
-.projects_experimental {
+.projects-experimental {
   background-position: -255px -102px;
 }
 
-.projects_facebook {
+.projects-facebook {
   background-position: -306px -102px;
 }
 
-.projects_facility {
+.projects-facility {
   background-position: 0px -153px;
 }
 
-.projects_film {
+.projects-film {
   background-position: -51px -153px;
 }
 
-.projects_forked {
+.projects-forked {
   background-position: -102px -153px;
 }
 
-.projects_games {
+.projects-games {
   background-position: -153px -153px;
 }
 
-.projects_ghost {
+.projects-ghost {
   background-position: -204px -153px;
 }
 
-.projects_gift {
+.projects-gift {
   background-position: -255px -153px;
 }
 
-.projects_globe {
+.projects-globe {
   background-position: -306px -153px;
 }
 
-.projects_golf {
+.projects-golf {
   background-position: 0px -204px;
 }
 
-.projects_heart {
+.projects-heart {
   background-position: -51px -204px;
 }
 
-.projects_intergalactic {
+.projects-intergalactic {
   background-position: -102px -204px;
 }
 
-.projects_lock {
+.projects-lock {
   background-position: -153px -204px;
 }
 
-.projects_mail {
+.projects-mail {
   background-position: -204px -204px;
 }
 
-.projects_martini {
+.projects-martini {
   background-position: -255px -204px;
 }
 
-.projects_medical {
+.projects-medical {
   background-position: -306px -204px;
 }
 
-.projects_mobile {
+.projects-mobile {
   background-position: 0px -255px;
 }
 
-.projects_music {
+.projects-music {
   background-position: -51px -255px;
 }
 
-.projects_news {
+.projects-news {
   background-position: -102px -255px;
 }
 
-.projects_orgchart {
+.projects-orgchart {
   background-position: -153px -255px;
 }
 
-.projects_peoples {
+.projects-peoples {
   background-position: -204px -255px;
 }
 
-.projects_piechart {
+.projects-piechart {
   background-position: -255px -255px;
 }
 
-.projects_poison {
+.projects-poison {
   background-position: -306px -255px;
 }
 
-.projects_putabirdonit {
+.projects-putabirdonit {
   background-position: 0px -306px;
 }
 
-.projects_radiate {
+.projects-radiate {
   background-position: -51px -306px;
 }
 
-.projects_savings {
+.projects-savings {
   background-position: -102px -306px;
 }
 
-.projects_search {
+.projects-search {
   background-position: -153px -306px;
 }
 
-.projects_shield {
+.projects-shield {
   background-position: -204px -306px;
 }
 
-.projects_speed {
+.projects-speed {
   background-position: -255px -306px;
 }
 
-.projects_sprint {
+.projects-sprint {
   background-position: -306px -306px;
 }
 
-.projects_star {
+.projects-star {
   background-position: 0px -357px;
 }
 
-.projects_storage {
+.projects-storage {
   background-position: -51px -357px;
 }
 
-.projects_tablet {
+.projects-tablet {
   background-position: -102px -357px;
 }
 
-.projects_travel {
+.projects-travel {
   background-position: -153px -357px;
 }
 
-.projects_twitter {
+.projects-twitter {
   background-position: -204px -357px;
 }
 
-.projects_warning {
+.projects-warning {
   background-position: -255px -357px;
 }
 
-.projects_whale {
+.projects-whale {
   background-position: -306px -357px;
 }
Index: webroot/rsrc/js/application/files/behavior-icon-composer.js
===================================================================
--- /dev/null
+++ webroot/rsrc/js/application/files/behavior-icon-composer.js
@@ -0,0 +1,76 @@
+/**
+ * @provides javelin-behavior-icon-composer
+ * @requires javelin-behavior
+ *           javelin-dom
+ *           javelin-stratcom
+ */
+
+JX.behavior('icon-composer', function(config) {
+
+  var nodes = {
+    root: JX.$(config.dialogID),
+    colorInput: JX.$(config.colorInputID),
+    iconInput: JX.$(config.iconInputID),
+    preview: JX.$(config.previewID)
+  };
+
+  var selected = {
+    color: config.defaultColor,
+    icon: config.defaultIcon
+  };
+
+  var redraw = function() {
+    var ii;
+
+    var colors = JX.DOM.scry(nodes.root, 'button', 'compose-select-color');
+    for (ii = 0; ii < colors.length; ii++) {
+      JX.DOM.alterClass(
+        colors[ii],
+        'profile-image-button-selected',
+        (JX.Stratcom.getData(colors[ii]).color == selected.color));
+    }
+
+    var icons = JX.DOM.scry(nodes.root, 'button', 'compose-select-icon');
+    for (ii = 0; ii < icons.length; ii++) {
+      JX.DOM.alterClass(
+        icons[ii],
+        'profile-image-button-selected',
+        (JX.Stratcom.getData(icons[ii]).icon == selected.icon));
+    }
+
+    nodes.colorInput.value = selected.color;
+    nodes.iconInput.value = selected.icon;
+
+    var classes = ['phui-icon-view', 'sprite-projects'];
+    classes.push('compose-background-' + selected.color);
+    classes.push('projects-' + selected.icon);
+
+    nodes.preview.className = classes.join(' ');
+  };
+
+  JX.DOM.listen(
+    nodes.root,
+    'click',
+    'compose-select-color',
+    function (e) {
+      e.kill();
+
+      selected.color = e.getNodeData('compose-select-color').color;
+      redraw();
+    });
+
+  JX.DOM.listen(
+    nodes.root,
+    'click',
+    'compose-select-icon',
+    function (e) {
+      e.kill();
+
+      selected.icon = e.getNodeData('compose-select-icon').icon;
+      redraw();
+    });
+
+  redraw();
+
+});
+
Index: webroot/rsrc/js/application/files/behavior-launch-icon-composer.js
===================================================================
--- /dev/null
+++ webroot/rsrc/js/application/files/behavior-launch-icon-composer.js
@@ -0,0 +1,25 @@
+/**
+ * @provides javelin-behavior-launch-icon-composer
+ * @requires javelin-behavior
+ *           javelin-dom
+ *           javelin-workflow
+ */
+
+JX.behavior('launch-icon-composer', function(config) {
+
+  JX.DOM.listen(
+    JX.$(config.launchID),
+    'click',
+    null,
+    function(e) {
+      e.kill();
+      new JX.Workflow('/file/compose/')
+        .setHandler(function(r) {
+          JX.$(config.inputID).value = r.phid;
+          JX.DOM.findAbove(e.getTarget(), 'form').submit();
+        })
+        .start();
+    });
+
+});
+