diff --git a/Resources/Plugins/emoji-keyboard/browser.js b/Resources/Plugins/emoji-keyboard/browser.js
index 04b270a9..34112f21 100644
--- a/Resources/Plugins/emoji-keyboard/browser.js
+++ b/Resources/Plugins/emoji-keyboard/browser.js
@@ -1,14 +1,40 @@
-enabled(){  
-  this.emojiHTML = "";
+enabled(){
+  this.selectedSkinTone = "";
+  
+  this.skinToneList = [
+    "", "1F3FB", "1F3FC", "1F3FD", "1F3FE", "1F3FF"
+  ];
+  
+  this.skinToneNonDefaultList = [
+    "1F3FB", "1F3FC", "1F3FD", "1F3FE", "1F3FF"
+  ];
+  
+  this.skinToneData = [
+    [ "", "#FFDD67" ],
+    [ "1F3FB", "#FFE1BD" ],
+    [ "1F3FC", "#FED0AC" ],
+    [ "1F3FD", "#D6A57C" ],
+    [ "1F3FE", "#B47D56" ],
+    [ "1F3FF", "#8A6859" ],
+  ];
+  
+  this.emojiHTML1 = ""; // no skin tones, prepended
+  this.emojiHTML2 = {}; // contains emojis with skin tones
+  this.emojiHTML3 = ""; // no skin tones, appended
   
   var me = this;
   
   // styles
   
   this.css = window.TDPF_createCustomStyle(this);
-  this.css.insert(".emoji-keyboard { position: absolute; width: 15.35em; height: 11.2em; background-color: white; overflow-y: auto; padding: 0.1em; box-sizing: border-box; border-radius: 2px; font-size: 24px; z-index: 9999 }");
-  this.css.insert(".emoji-keyboard .separator { height: 26px; }");
-  this.css.insert(".emoji-keyboard .emoji { padding: 0.1em !important; cursor: pointer }");
+  this.css.insert(".emoji-keyboard { position: absolute; width: 15.35em; background-color: white; border-radius: 2px 2px 3px 3px; font-size: 24px; z-index: 9999 }");
+  this.css.insert(".emoji-keyboard-list { height: 10.14em; padding: 0.1em; box-sizing: border-box; overflow-y: auto }");
+  this.css.insert(".emoji-keyboard-list .separator { height: 26px }");
+  this.css.insert(".emoji-keyboard-list .emoji { padding: 0.1em !important; cursor: pointer }");
+  this.css.insert(".emoji-keyboard-skintones { height: 1.3em; text-align: center; background-color: #292f33; border-radius: 0 0 2px 2px }");
+  this.css.insert(".emoji-keyboard-skintones div { width: 0.8em; height: 0.8em; margin: 0.25em 0.1em; border-radius: 50%; display: inline-block; box-sizing: border-box; cursor: pointer }");
+  this.css.insert(".emoji-keyboard-skintones .sel { border: 2px solid rgba(0, 0, 0, 0.35); box-shadow: 0 0 2px 0 rgba(255, 255, 255, 0.65), 0 0 1px 0 rgba(255, 255, 255, 0.4) inset }");
+  this.css.insert(".emoji-keyboard-skintones :hover { border: 2px solid rgba(0, 0, 0, 0.25); box-shadow: 0 0 1px 0 rgba(255, 255, 255, 0.65), 0 0 1px 0 rgba(255, 255, 255, 0.25) inset }");
   
   // layout
   
@@ -34,16 +60,29 @@ enabled(){
     $(".emoji-keyboard-popup-btn").removeClass("is-selected");
   };
   
-  this.generateKeyboardFor = (input, left, top) => {
-    var created = document.createElement("div");
-    document.body.appendChild(created);
+  var generateEmojiHTML = skinTone => {
+    return this.emojiHTML1+this.emojiHTML2[skinTone]+this.emojiHTML3;
+  };
+  
+  var selectSkinTone = skinTone => {
+    let selectedEle = this.currentKeyboard.children[1].querySelector("[data-tone='"+this.selectedSkinTone+"']");
+    selectedEle && selectedEle.classList.remove("sel");
     
-    created.classList.add("emoji-keyboard");
-    created.style.left = left+"px";
-    created.style.top = top+"px";
-    created.innerHTML = this.emojiHTML;
+    this.selectedSkinTone = skinTone;
+    this.currentKeyboard.children[0].innerHTML = generateEmojiHTML(skinTone);
+    this.currentKeyboard.children[1].querySelector("[data-tone='"+this.selectedSkinTone+"']").classList.add("sel");
+  };
+  
+  this.generateKeyboard = (input, left, top) => {
+    var outer = document.createElement("div");
+    outer.classList.add("emoji-keyboard");
+    outer.style.left = left+"px";
+    outer.style.top = top+"px";
     
-    created.addEventListener("click", function(e){
+    var keyboard = document.createElement("div");
+    keyboard.classList.add("emoji-keyboard-list");
+    
+    keyboard.addEventListener("click", function(e){
       if (e.target.tagName === "IMG"){
         input.val(input.val()+e.target.getAttribute("alt"));
         input.trigger("change");
@@ -53,7 +92,24 @@ enabled(){
       e.stopPropagation();
     });
     
-    return created;
+    var skintones = document.createElement("div");
+    skintones.innerHTML = me.skinToneData.map(entry => "<div data-tone='"+entry[0]+"' style='background-color:"+entry[1]+"'></div>").join("");
+    skintones.classList.add("emoji-keyboard-skintones");
+    
+    skintones.addEventListener("click", function(e){
+      if (e.target.hasAttribute("data-tone")){
+        selectSkinTone(e.target.getAttribute("data-tone") || "");
+      }
+      
+      e.stopPropagation();
+    });
+    
+    outer.appendChild(keyboard);
+    outer.appendChild(skintones);
+    document.body.appendChild(outer);
+    
+    this.currentKeyboard = outer;
+    selectSkinTone(this.selectedSkinTone);
   };
   
   this.prevTryPasteImage = window.TDGF_tryPasteImage;
@@ -75,7 +131,7 @@ enabled(){
     }
     else{
       var pos = $(this).offset();
-      me.currentKeyboard = me.generateKeyboardFor($(".js-compose-text").first(), pos.left, pos.top+$(this).outerHeight()+8);
+      me.generateKeyboard($(".js-compose-text").first(), pos.left, pos.top+$(this).outerHeight()+8);
       
       $(this).addClass("is-selected");
     }
@@ -123,38 +179,93 @@ ready(){
   };
   
   $TDP.readFileRoot(this.$token, "emoji-ordering.txt").then(contents => {
-    let generated = [];
+    let generated1 = [];
+    let generated2 = {};
+    let generated3 = [];
     
-    let addDeclaration = decl => {
-      generated.push(decl.split(" ").map(pt => convUnicode(parseInt(pt, 16))).join(""));
+    for(let skinTone of this.skinToneList){
+      generated2[skinTone] = [];
+    }
+    
+    // declaration inserters
+    
+    let addDeclaration1 = decl => {
+      generated1.push(decl.split(" ").map(pt => convUnicode(parseInt(pt, 16))).join(""));
     };
     
-    let skinTones = [
-      "1F3FB", "1F3FC", "1F3FD", "1F3FE", "1F3FF"
-    ];
+    let addDeclaration2 = (tone, decl) => {
+      let gen = decl.split(" ").map(pt => convUnicode(parseInt(pt, 16))).join("");
+      
+      if (tone === null){
+        for(let skinTone of this.skinToneList){
+          generated2[skinTone].push(gen);
+        }
+      }
+      else{
+        generated2[tone].push(gen);
+      }
+    };
+    
+    let addDeclaration3 = decl => {
+      generated3.push(decl.split(" ").map(pt => convUnicode(parseInt(pt, 16))).join(""));
+    };
+    
+    // line reading
+                      
+    let skinToneState = 0;
     
     for(let line of contents.split("\n")){
       if (line[0] === '@'){
-        generated.push("___");
+        switch(skinToneState){
+          case 0: generated1.push("___"); break;
+          case 1: this.skinToneList.forEach(skinTone => generated2[skinTone].push("___")); break;
+          case 2: generated3.push("___"); break;
+        }
+        
+        if (line[1] === '1'){
+          skinToneState = 1;
+        }
+        else if (line[1] === '2'){
+          skinToneState = 2;
+        }
       }
-      else{
-        let decl = line.slice(0, line.indexOf(";"));
+      else if (skinToneState === 1){
+        let decl = line.slice(0, line.indexOf(';'));
         let skinIndex = decl.indexOf('$');
 
         if (skinIndex !== -1){
           let declPre = decl.slice(0, skinIndex);
           let declPost = decl.slice(skinIndex+1);
-
-          skinTones.map(skinTone => declPre+skinTone+declPost).forEach(addDeclaration);
+          
+          for(let skinTone of this.skinToneNonDefaultList){
+            generated2[skinTone].pop();
+            addDeclaration2(skinTone, declPre+skinTone+declPost);
+          }
         }
         else{
-          addDeclaration(decl);
+          addDeclaration2(null, decl);
         }
       }
+      else if (skinToneState === 2){
+        addDeclaration3(line.slice(0, line.indexOf(';')));
+      }
+      else if (skinToneState === 0){
+        addDeclaration1(line.slice(0, line.indexOf(';')));
+      }
     }
     
+    // final processing
+    
+    let replaceSeparators = str => str.replace(/___/g, "<div class='separator'></div>");
+    
     let start = "<p style='font-size:13px;color:#444;margin:4px;text-align:center'>Please, note that most emoji will not show up properly in the text box above, but they will display in the tweet.</p>";
-    this.emojiHTML = start+TD.util.cleanWithEmoji(generated.join("")).replace(/___/g, "<div class='separator'></div>");
+    this.emojiHTML1 = start+replaceSeparators(TD.util.cleanWithEmoji(generated1.join("")));
+    
+    for(let skinTone of this.skinToneList){
+      this.emojiHTML2[skinTone] = replaceSeparators(TD.util.cleanWithEmoji(generated2[skinTone].join("")));
+    }
+    
+    this.emojiHTML3 = replaceSeparators(TD.util.cleanWithEmoji(generated3.join("")));
   }).catch(err => {
     $TD.alert("error", "Problem loading emoji keyboard: "+err.message);
   });
diff --git a/Resources/Plugins/emoji-keyboard/emoji-ordering.txt b/Resources/Plugins/emoji-keyboard/emoji-ordering.txt
index 8da966aa..f9891e78 100644
--- a/Resources/Plugins/emoji-keyboard/emoji-ordering.txt
+++ b/Resources/Plugins/emoji-keyboard/emoji-ordering.txt
@@ -96,7 +96,7 @@
 1F648; ๐Ÿ™ˆ see-no-evil monkey
 1F649; ๐Ÿ™‰ hear-no-evil monkey
 1F64A; ๐Ÿ™Š speak-no-evil monkey
-@
+@1 enable skin tones
 1F466; ๐Ÿ‘ฆ boy
 1F466 $; ๐Ÿ‘ฆ๐Ÿป boy
 1F467; ๐Ÿ‘ง girl
@@ -402,6 +402,10 @@
 1F939 $ 200D 2642 FE0F; ๐Ÿคน๐Ÿปโ€โ™‚๏ธ man juggling
 1F939 200D 2640 FE0F; ๐Ÿคนโ€โ™€๏ธ woman juggling
 1F939 $ 200D 2640 FE0F; ๐Ÿคน๐Ÿปโ€โ™€๏ธ woman juggling
+1F6CC; ๐Ÿ›Œ person in bed !! moved
+1F6CC $; ๐Ÿ›Œ๐Ÿป person in beh !! moved
+1F6C0; ๐Ÿ›€ person taking bath !! moved
+1F6C0 $; ๐Ÿ›€๐Ÿป person taking bath !! moved
 1F46B; ๐Ÿ‘ซ man and woman holding hands
 1F46C; ๐Ÿ‘ฌ two men holding hands
 1F46D; ๐Ÿ‘ญ two women holding hands
@@ -439,7 +443,7 @@
 1F469 200D 1F467; ๐Ÿ‘ฉโ€๐Ÿ‘ง family
 1F469 200D 1F467 200D 1F466; ๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ family
 1F469 200D 1F467 200D 1F467; ๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง family
-@ !! removed skin tone modifiers
+@
 1F4AA; ๐Ÿ’ช flexed biceps
 1F4AA $; ๐Ÿ’ช๐Ÿป flexed biceps
 1F933; ๐Ÿคณ selfie
@@ -505,7 +509,6 @@
 1F443; ๐Ÿ‘ƒ nose
 1F443 $; ๐Ÿ‘ƒ๐Ÿป nose
 1F91D; ๐Ÿค handshake !! moved
-@
 1F463; ๐Ÿ‘ฃ footprints
 1F440; ๐Ÿ‘€ eyes
 1F441; ๐Ÿ‘ eye
@@ -570,7 +573,7 @@
 1F484; ๐Ÿ’„ lipstick
 1F48D; ๐Ÿ’ ring
 1F48E; ๐Ÿ’Ž gem stone
-@
+@2 no more skin tones beyond this point
 1F435; ๐Ÿต monkey face
 1F412; ๐Ÿ’ monkey
 1F98D; ๐Ÿฆ gorilla
@@ -895,14 +898,10 @@
 1F6F0; ๐Ÿ›ฐ satellite
 1F6CE; ๐Ÿ›Ž bellhop bell
 1F6AA; ๐Ÿšช door
-1F6CC; ๐Ÿ›Œ person in bed
-1F6CC $; ๐Ÿ›Œ๐Ÿป person in bed
 1F6CF; ๐Ÿ› bed
 1F6CB; ๐Ÿ›‹ couch and lamp
 1F6BD; ๐Ÿšฝ toilet
 1F6BF; ๐Ÿšฟ shower
-1F6C0; ๐Ÿ›€ person taking bath
-1F6C0 $; ๐Ÿ›€๐Ÿป person taking bath
 1F6C1; ๐Ÿ› bathtub
 @
 231B; โŒ› hourglass