Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Gregory O. Voronin
Published © MIT

Voronoi101: Light Your Lamp!

Create a Voronoi tessellated lamp with a 24 NeoPixel Ring and control it with an Arduino/Genuino101 over Bluetooth Low Energy!

IntermediateFull instructions provided4 hours12,521
Voronoi101: Light Your Lamp!

Things used in this project

Hardware components

Arduino 101
Arduino 101
×1
NeoPixel Ring: WS2812 5050 RGB LED
Adafruit NeoPixel Ring: WS2812 5050 RGB LED
The actual Part I used was NeowPixel Ring - 24x RGBW Cool LED Adafruit Part #2863
×1
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Android device
Android device
×1

Software apps and online services

Evothings Studio
Evothings Studio
Fusion
Autodesk Fusion

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
I used a Lulzbot mini with HIPS filament for the base and Taulman Bridge Nylon for the lamp shade.

Story

Read more

Schematics

Fritzing Diagram/Schematic

Code

The Arduino/Genuino101 Sketch

Arduino
This will be uploaded to the Arduino/Genuino101 with the Arduino IDE
#include <CurieBLE.h>
#include <Adafruit_NeoPixel.h>

/**
* This project demonstrates how to control an adafruit industries NeoPixel Ring over BLE using an arduino/genuino101.
* This projct is derived from the Cproject in Chapter 7 of Make: Bluetooth: Bluetooth LE Projects with Arduino, Raspberry Pi, 
* and Smartphones and the project by the Ruiz brothers from Adafruit entitled,(http://www.thingiverse.com/thing:1343925) 
*/

/**
* Setup our BLE service and characteristics here
*/
BLEPeripheral blePeripheral;       // BLE Peripheral Device (the board you're programming)
BLEService lampService("917649A0-D98E-11E5-9EEC-0002A5D5C51B"); // Custom UUID
BLEUnsignedCharCharacteristic switchCharacteristic("917649A1-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite);
BLEUnsignedCharCharacteristic brightnessCharacteristic("917649A2-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite);
BLECharacteristic colorCharacteristic("917649A3-D98E-11E5-9EEC-0002A5D5C51B", BLERead | BLEWrite,3);
BLEDescriptor lampDescriptor("2902", "lamp");

/**
 * establish which pin the NeoPixel ring is attachd to on the Arduino/Genuino101, and the
 * number of NeoPixels on the ring.
 * 
*/
#define PIN            6
#define NUMPIXELS      24
/* 
 *  When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
 *  Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
 *  example for more information on possible values.
*/

Adafruit_NeoPixel ring = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGBW + NEO_KHZ800);
// Adafruit_NeoPixel pixels;
int delayTime = 150; // delay used for NeoPixel light effects.

// Lamp state structure

struct LampStateStructure
{
  boolean lampOn;
  int brightness;
  int green;
  int red;
  int blue;
};

struct LampStateStructure lampState;

void setup() {

  /** Serial 
  * Serial communication is not necessary for this project to work, but
  * is very useful for debugging. All serial references could be 
  * commented out if desried.
  */
  Serial.begin(9600); // initialize Serial communication
  while (!Serial);    // wait for the serial port to open
 
  Serial.println("Arduino101/IntelCurie/NeoPixel-Voroni-Lamp/Evothings Example Started");
  Serial.println("Serial rate set to 9600");

  // initilize the ble service, characterisitcs and advertising
  blePeripheral.setLocalName("voronoi");
  blePeripheral.setAdvertisedServiceUuid(lampService.uuid());
  blePeripheral.addAttribute(lampService);
  blePeripheral.addAttribute(switchCharacteristic);
  blePeripheral.addAttribute(brightnessCharacteristic);
  blePeripheral.addAttribute(colorCharacteristic);
  blePeripheral.addAttribute(lampDescriptor);

  // add event handlers here
  blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  brightnessCharacteristic.setEventHandler(BLEWritten, brightnessCharacteristicWritten);
  colorCharacteristic.setEventHandler(BLEWritten, colorCharacteristicWritten);

  // set an initial values for the characteristics
  switchCharacteristic.setValue(-1);
  brightnessCharacteristic.setValue(0);
  
  /** 
   * the color characterisitc consists of the 3 GREEN,RED and BLUE values sent
   * from the mobile device as a single characterisitic of 3 bytes, each a 
   * value from 0..255
  */
  
  const unsigned char initialColor[3] = {0,0,0};
  colorCharacteristic.setValue(initialColor,3);
  
  // advertise the service
  blePeripheral.begin();
  Serial.println(("Bluetooth device active, waiting for connections..."));

  // setup the lamp state variable strucutre and set to intial values
  
  lampState.lampOn = false;
  lampState.brightness = 200;
  lampState.green = 250;
  lampState.red = 250;
  lampState.blue = 250;


  // This initializes the NeoPixel, read the code in the NeoPixellibrary to understand what it does.
  ring.begin(); 
}

void loop() {


  // continual poll the ble device for activity, connection, disconnect, characterisitc cahgnes, etc.
  blePeripheral.poll();
  
} // end loop

/**
 * BLE Event Handlers are defined in the fucntions below
 */
 
void blePeripheralConnectHandler(BLECentral& central) 
{
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLECentral& central) 
{
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic)
{
  /**
   * We will use a switch/case statement here so that we can expand the functionality of the app 
   * in the future; This will allow us to accept values up to 255 on the switch characteristic
   * and not permanently tie the characteritis to just turning the lamp on/off;
   */

   int switchValue = switchCharacteristic.value();
   Serial.print("Switch Value: "); Serial.println(switchValue);

   switch(switchValue)
   {
      case 0:
        // Turn lamp on/off
        lamp();
        break;
      case 1:
        // for debugging/expanded functionality later
        break;
      case 2:    
        // for debugging/expanded functionality later
        break;
      case 3:
        // for debugging/expanded functionality later
        break;  
   }   
}
void brightnessCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic)
{

  lampState.brightness = brightnessCharacteristic.value();
  ring.setBrightness(lampState.brightness);
  ring.show();
  
}
void colorCharacteristicWritten(BLECentral& central, BLECharacteristic& characteristic)
{
  // The colors on this neopixel are speciifed GRB not RGB!
  const unsigned char* colors = colorCharacteristic.value();
  lampState.green = colors[0];
  lampState.red = colors[1];
  lampState.blue = colors[2];
  for (int i=0;i<NUMPIXELS;i++)
  {
    ring.setPixelColor( i, ring.Color(lampState.green,lampState.red,lampState.blue));
  }
  ring.show();
}

void lamp()
{
  if (lampState.lampOn)
  {
    /** do not set the lamp state variable lampState.brightness to 0 
     *  as the expectation of turning the lamp back on will be 
     *  for the lamp to turn back on to the same brightness
     *  as before turnng off. 
     *        Consider adding a dimming effect here.
     */
    ring.setBrightness(0);
    ring.show();
    lampState.lampOn = false;
  } 
  else
  {
    ring.setBrightness( lampState.brightness );
    for (int i=0;i<NUMPIXELS;i++)
    {
      ring.setPixelColor( i, ring.Color(lampState.green,lampState.red,lampState.blue));
    }
    ring.show();
    lampState.lampOn = true;
  }
}

index.html

HTML
This is the index.html file for the mobile app, it includes Javascript as well. . .
<!DOCTYPE html>
<html>
<!--
This is an app that demonstrates how to control a NeoPixel ring Lamp
using BLE (Bluetooth Low Energy).
-->
<head>

	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, user-scalable=no
		initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />

	<title>Arduino/Genuino101 Voronoi Lamp</title>

	<style>
		@import 'ui/css/evothings-app.css';
	</style>

	<script>
	// Redirect console.log to Evothings Workbench.
	if (window.hyper && window.hyper.log) { console.log = hyper.log }
	window.onerror = function(msg, url, line)
	{
		console.log(msg + ": " + url + ":" + line);
	};
	</script>

	<script src="cordova.js"></script>
	<script src="libs/jquery/jquery.js"></script>
	<script src="libs/evothings/evothings.js"></script>
	<script src="libs/evothings/ui/ui.js"></script>
	<script src="libs/evothings/arduinoble/arduinoble.js"></script>

</head>

<body ontouchstart=""><!-- ontouchstart="" enables low-delay CSS transitions. -->

	<header>
		<button class="back" onclick="history.back()">
			<img src="ui/images/arrow-left.svg" />
		</button>

		<img class="logotype" src="ui/images/logo.svg" alt="Evothings" />

		<!--<button class="menu" onclick=""><img src="ui/images/menu.svg" /></button>-->
	</header>

	<h1>Voronoi 101 Lamp</h1>
 
	<p id="info">Initializing...</p>

        <button class="blue wide" onclick="app.connect()">BLE CONNECT</button>
        <canvas id="picker" width="500" height="300"></canvas>
        <button class="green wide" onclick="app.lampSwitch()">LAMP</button>
        <label for="brightness">Brightness</label>
        <input type="range" id="brightness" value="127" min="0" max="255" oninput="brightnessSelect()">
          
    <!-- ColorPicker javascript, see...
     The Color Wheel png file comes from this URL.
     The image file will need to be in the same directory as
     this index.html file and named colorWheel4.png in order
     to render the graphic in the UI.

     
     https://commons.wikimedia.org/wiki/File:Color_Wheel.PNG
     
     -->
    <script>
        /**
         * The following JavaScript code allows us to get the color value
         * as the selected point on rendered image on the UI.
         */
        var canvas = document.getElementById('picker').getContext('2d');
        var img = new Image();
        img.src = 'colorWheel4.png';
        // img.src = 'lizard.png';
        $(img).load(function(){ canvas.drawImage(img,100,5,295,295);});
        $('#picker').click(function(event)
        {
            var x = event.pageX - this.offsetLeft;
            var y = event.pageY - this.offsetTop;
            var imgData = canvas.getImageData(x,y,1,1).data;
            var R = imgData[0];
            var G = imgData[1];
            var B = imgData[2];
            app.changeLampColor( new Uint8Array([G,R,B]));
        });
    </script>
 
    <!-- brightness slider -->
    <script>
        function brightnessSelect() {
            var x = document.getElementById("brightness").value;
            app.changeLampBrightness(new Uint8Array([x]));
            // console.log( 'brightness: ' + x);
        }
    </script>
    <!-- BLE connectivity javascript, see... -->
	<script>
	// Application object.
	var app = {}

	// Connected device.
	app.device = null;

    /**
     * The following functions are connected to our UI and serve to pass data to the proper 
     * characteristic uuid. To improve the reability and ease of future modifications of this 
     * code, it would beneficial to create literals for each of these characteristic uuid's.
     */

	// Turn NeoPixel Lamp On/Off.
	app.lampSwitch = function()
	{
		app.device && app.device.writeLampCharacteristic(new Uint8Array([0]), '917649a1-d98e-11e5-9eec-0002a5d5c51b');
	}

    app.changeLampColor = function(color)
    {
        /*
         * The variable color is sent to this function as an array of 3 bytes reflecting the RGB values the
         * user has slected from the image on the UI. See lines 64-79 above.
         */
        
        app.device && app.device.writeLampCharacteristic(color, '917649a3-d98e-11e5-9eec-0002a5d5c51b');
    }
    
    app.changeLampBrightness = function(brightness)
    {
        app.device && app.device.writeLampCharacteristic(brightness, '917649a2-d98e-11e5-9eec-0002a5d5c51b');

    }
	app.showMessage = function(info)
	{
		document.getElementById('info').innerHTML = info
	};

	// Called when BLE and other native functions are available.
	app.onDeviceReady = function()
	{
		app.showMessage('Touch the connect button to begin.');
	};

	app.connect = function()
	{
		evothings.arduinoble.close();
		app.showMessage('Connecting...');

		evothings.arduinoble.connect(
			'voronoi', /* Advertised name of BLE device as specified in out Arduino sketch */
			function(device)
			{
				app.device = device;
				app.showMessage('Connected! Touch buttons to turn LED on/off.');
			},
			function(errorCode)
			{
				app.showMessage('Connect error: ' + errorCode + '.');
			});
	};

	document.addEventListener(
		'deviceready',
		function() { evothings.scriptsLoaded(app.onDeviceReady) },
		false);
	</script>

</body>

</html>

arduinoble.js

JavaScript
This is javascript to communicate over BLE. Only one function is changed here.
// File: arduinoble.js

// Load library EasyBLE.
evothings.loadScript('libs/evothings/easyble/easyble.js');

/**
 * @namespace
 * @author Mikael Kindborg
 * @description <p>Functions for communicating with an Arduino BLE shield.</p>
 * <p>It is safe practise to call function {@link evothings.scriptsLoaded}
 * to ensure dependent libraries are loaded before calling functions
 * in this library.</p>
 *
 * @todo This is a very simple library that has only write capability,
 * read and notification functions should be added.
 *
 * @todo Add function to set the write characteristic UUID to make
 * the code more generic.
 */

/**
 * This file was modifed by GV 7/1/2016 to commuincate over the onboard BLE on the
 * Arduino/Genuino101 to run the voronoi101 NeoPixel Lamp project.
 */
 evothings.arduinoble = {};

;(function()
{
	// Internal functions.
	var internal = {};

	/**
	 * Stop any ongoing scan and disconnect all devices.
	 * @public
	 */
	evothings.arduinoble.close = function()
	{
		evothings.easyble.stopScan();
		evothings.easyble.closeConnectedDevices();
	};

	/**
	 * Called when you've connected to an Arduino BLE shield.
	 * @callback evothings.arduinoble.connectsuccess
	 * @param {evothings.arduinoble.ArduinoBLEDevice} device -
	 * The connected BLE shield.
	 */

	/**
	 * Connect to a BLE-shield.
	 * @param deviceName BLE name if the shield.
	 * @param {evothings.arduinoble.connectsuccess} success -
	 * Success callback: success(device)
	 * @param {function} fail - Error callback: fail(errorCode)
	 * @example
	 * evothings.arduinoble.connect(
	 *   'arduinoble', // Name of BLE shield.
	 *   function(device)
	 *   {
	 *     console.log('connected!');
	 *     device.writeDataArray(new Uint8Array([1]));
	 *     evothings.arduinoble.close();
	 *   },
	 *   function(errorCode)
	 *   {
	 *     console.log('Error: ' + errorCode);
	 *   });
	 * @public
	 */
	evothings.arduinoble.connect = function(deviceName, success, fail)
	{
		evothings.easyble.startScan(
			function(device)
			{
				if (device.name == deviceName)
				{
					evothings.easyble.stopScan();
					internal.connectToDevice(device, success, fail);
				}
			},
			function(errorCode)
			{
				fail(errorCode);
			});
	};

	/**
	 * Connect to the BLE shield.
	 * @private
	 */
	internal.connectToDevice = function(device, success, fail)
	{
		device.connect(
			function(device)
			{
				// Get services info.
				internal.getServices(device, success, fail);
			},
			function(errorCode)
			{
				fail(errorCode);
			});
	};

	/**
	 * Read all services from the device.
	 * @private
	 */
	internal.getServices = function(device, success, fail)
	{
		device.readServices(
			null, // null means read info for all services
			function(device)
			{
				internal.addMethodsToDeviceObject(device);
				success(device);
			},
			function(errorCode)
			{
				fail(errorCode);
			});
	};

	/**
	 * Add instance methods to the device object.
	 * @private
	 */
	internal.addMethodsToDeviceObject = function(device)
	{
		/**
		 * Object that holds info about an Arduino BLE shield.
		 * @namespace evothings.arduinoble.ArduinoBLEDevice
		 */

		/**
         * The only function we need as the data and characteristics
         * are passed in here from the functions in <script>
         * sections of the index.html file
         */
  
  
        device.writeLampCharacteristic = function(uint8array,uuid)
        {
            device.writeCharacteristic(
                uuid,
                uint8array,
                function()
                {
                    console.log('write color char sucess');
                },
                    function(errorCode)
                {
                    console.log('write color char error' + errorCode);
                });
        };

  
  
  
  
	};
})();

evothings-app.css

CSS
The CSS file for the mobile app.
/* Common styles for Evothings examples and client. */

@import '../fonts/ProximaNova.css';

html, body {
	height: 100%;
	margin: 0;
	padding: 0;

	font-family: 'Proxima Nova Regular', sans-serif;
	font-weight: normal;

	background: rgb(255,255,255);

	-webkit-touch-callout: none;
	-webkit-user-select: none;
	-khtml-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
	-webkit-tap-highlight-color: rgba(0,0,0,0);
}
body {
	margin: 0 0.9em 0 0.9em;
	font-size: 150%;
	font-size: 7.5vw;
}

/* Add a top margin to the content corresponding to the height of the header. */
body::before,
section::before {
	display: block;
	width: 100%;
	height: 1.1em; /* Should correspond to header's height. */
	margin-bottom: 0.4em;

	content: '\0000a0'; /* Non-breaking space (&nbsp;) */
	font-size: 180%; /* Same as the header's font size. */
	line-height: 200%; /* Slighly more than the header's line-height. */
}

/* Add a bottom margin. */
body::after,
section::after {
	display:block;
	content: '';
	height: 1em;
}




/*  ----------------------------------------------------------
								GENERAL
	---------------------------------------------------------- */

.hidden {
	display: none;
}




/*  ----------------------------------------------------------
								HEADER
	---------------------------------------------------------- */

/* The header's height is determined by the contained text's font size. */
header {
	box-sizing: border-box; /* Width & height includes padding & border. */

	position: fixed;
	top: 0;
	left: 0;
	right: 0;

	width: 100%;
	height: 1.1em;

	/* Left and right margins should correspond to body margins. */
	margin: 0 0 3.45% 0;
	/* Left padding should correspond to the back button's width. */
	padding: 1% 2% 1% 2%;

	font-size: 180%;
	line-height: 100%;
	text-align: center;
	vertical-align: middle;

	background: #f3f3f3;

	z-index: 1000;
}
header button {
	display: block;
	position: absolute;
	top: 50%;
	max-height: 70%;

	margin: 0;

	font-size: 30%;

	-webkit-transform: translateY(-50%);
	-ms-transform: translateY(-50%);
	transform: translateY(-50%);
}
header button.back {
	position: absolute;
	left: 0;

	height: 100%;
	margin: 0;
	padding: 0 0.9em;

	/* Font size is percentage of the header's font size. */
	font-size: 50%;
	color: #000;

	text-align: left;

	background: none;

	border-radius: 0;
	border: none;

	box-shadow: none;
}
header button.back img {
	height: 0.5em;
}
header img.logotype {
	position: absolute;
	top: 50%;
	left: 0;
	right: 0;

	height: 60%;

	margin: 0 auto;

	-webkit-transform: translateY(-50%);
	-ms-transform: translateY(-50%);
	transform: translateY(-50%);
}




/*  ----------------------------------------------------------
								MENU
	---------------------------------------------------------- */

header button#menu-button {
	position: absolute;
	right: 0;

	width: 3em;
	height: 100%;
	max-height: 100%;
	margin: 0;
	padding: 0 0.9em;

	/* Font size is percentage of the header's font size. */
	font-size: 50%;
	color: #000;

	text-align: right;

	background: none;

	border-radius: 0;
	border: none;

	box-shadow: none;
}
header button#menu-button img {
	height: 34%;
}
header button#menu-button:focus {
	pointer-events: none;
	outline: none;
}
header button#menu-button:focus::-moz-focus-inner {
	border: 0;
}
header button#menu-button:focus + menu {
	opacity: 1;
	visibility: visible;
}
header menu {
	display: block;
	position: absolute;
	top: 100%;
	right: 0;

	margin: 0;
	padding: 0;

	background: #f3f3f3;

	opacity: 0;
	visibility: hidden;
	transition: visibility 0.5s;
}

header menu > * {
	display: block;

	padding: 0 1em 0 1em;

	font-family: 'Proxima Nova Bold';
	font-size: 35%;
	text-align: right;
}
header menu a {
	color: #000;
	text-decoration: none;
}

header h1 {
	width: 100%;
	margin: 0;
	padding: 0;

	font-size: inherit;
	line-height: inherit;
	font-weight: normal;
	text-align: center;
	vertical-align: middle;
	color: #eee;

	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}




/*  ----------------------------------------------------------
								SECTIONS
	---------------------------------------------------------- */

main {
	z-index: 0;
}

main footer {
	box-sizing: border-box; /* Width & height includes padding & border. */

	position: fixed;
	bottom: 0;

	width: 100%;

	margin: 0 -5% 0 -5%;
	padding: 0 5% 0 5%;

	background-color: #fff;

	box-shadow: inset 0 5px 9px -9px #000;

	z-index: 2;
}

section {
	display: none;

	box-sizing: border-box; /* Width & height includes padding & border. */

	position: absolute;

	top: 0;
	right: 0;
	bottom: 0;
	left: 0;

	width: 100%;

	padding: 0 0.9em 0 0.9em;

	background-color: #fff;

	z-index: 2;

}

section:target {
	display: block;
}



/*  ----------------------------------------------------------
							INPUT FIELDS
	---------------------------------------------------------- */

input {
	margin: 0;
	padding: 0;

	border: none;

	font-family: inherit;
	font-size: 63%;
}

input[type="text"],input[type="url"],input[type="tel"],input[type="password"],
input[type="email"],input[type="search"],input[type="number"],
input[type="date"],input[type="month"],input[type="week"],input[type="time"] {
	width: 50%;

	padding: 7px 14px 7px 14px;

	font-family: inherit;
	font-size: 63%;
	color: #000;

	border-radius: 4px;
	border: none;

	background-color: #f3f3f3; /* Default color: "Arctic". */
}

textarea {
	box-sizing: border-box; /* Width & height includes padding & border. */
	width: 100%;

	padding: 7px 14px 7px 14px;

	border-radius: 4px;
	border: none;

	font-family: inherit;
	font-size: 63%;
	line-height: 1.5;

	background-color: #f3f3f3; /* Default color: "Arctic". */
}

input[type=range]:focus {
    outline: none;
}
input[type=range]{
    -webkit-appearance: none;
    width: 100%;
    height: 25px;
    cursor: pointer;
    animate: 0.5s;
    box-shadow: 1px 1px 1px #50555C;
    background: #AAB7B8;
    border-radius: 19px;
    border: 2px solid #000000;
}
input[type=range]::-webkit-slider-thumb {
    -webkit-apperance: none;
    box-shadow: 0px 0px 0px #000000;
    border: 2px solid #000000;
    height: 25px;
    width: 36px;
    border-radius: 15px;
    background: #529DE1;
    cursor: pointer;
    -webkit-appearance: none;
    margin-top: 0px;
}



/*  ----------------------------------------------------------
								BUTTONS
	---------------------------------------------------------- */

button.clear {
	margin-left: 1%;
	background-color: #e15a64; /* Default color: "Soft Red". */
}

button,
input.btn-group + label,
.button {
	display: inline-block;
	box-sizing: border-box; /* Width & height includes padding & border. */

	font-family: 'Proxima Nova Black';
	font-size: inherit;
	line-height: 100%;
	text-align: center;
	text-transform: uppercase;

	color: #fff;

	margin: 0.5em 0 0.5em 0;
	padding: 9px 13px 8px 13px;

	border-radius: 4px;
	border: none;

	box-shadow: none;

	background-color: #b9b9b9; /* Default color: "Charcoal" */
}
body > button,
body > input.btn-group + label,
main > button,
main > input.btn-group + label {
	font-size: 63% !important;
}
button:active, button.pressed,
input.btn-group:active + label, input.btn-group + label:active,
input.btn-group:checked + label {
	box-shadow: inset 0 8px 9px -9px #000;
	background-color: #9d9d9d; /* Default color: "Charcoal" */
}
button:focus,
input.btn-group:focus {
	outline: none;
}

button.half,
input.btn-group.half + label,
input.btn-group + label.half {
	float: left;
	width: 50%; /* Fallback in case calc() is unsupported. */
	width: calc(50% - 4px);
	margin-left: 2px;
	margin-right: 2px;
}

button.third,
input.btn-group.third + label,
input.btn-group + label.third {
	float: left;
	width: 33%; /* Fallback in case calc() is unsupported. */
	width: calc(33% - 4px);
	margin-left: 2px;
	margin-right: 2px;
}

button.quarter,
input.btn-group.quarter + label,
input.btn-group + label.quarter {
	float: left;
	width: 25%; /* Fallback in case calc() is unsupported. */
	width: calc(25% - 4px);
	margin-left: 2px;
	margin-right: 2px;
}

button.wide,
input.btn-group.wide + label,
input.btn-group + label.wide {
	width: 100%;
}

button.big,
input.btn-group.big + label,
input.btn-group + label.big {
	font-size: 150%;
	line-height: 3.0;
}

/*  Input with class btn-group should be accompanied by a label acting as a
	button. */
input.btn-group {
	display: none;
}




/*  ----------------------------------------------------------
							VARIOUS ELEMENTS
	---------------------------------------------------------- */

canvas {
	padding: 7px;

	border-radius: 4px;
	border: none;

	/* background-color: #f3f3f3; /* Default color: "Arctic" */
}

figcaption {
	font-size: 63%;
}

h1 {
	padding: 0;
	margin: 1em 0 0 0;

	font-family: 'Proxima Nova Black';
	font-size: 100%;
	line-height: 1.5;

	vertical-align: middle;
}
header + h1, body h1:first-child, main h1:first-child, article h1:first-child {
	margin-top: 0;
}

h2,h3,h4,h5,h6 {
	margin: 1em 0 0 0;
	padding: 0;

	font-family: 'Proxima Nova Bold';
	font-size: 63%;

	line-height: 1.5;

	vertical-align: middle;
}

a {
	color: #52afb8; /* Default color: "Blue Hue" (dark variant) */
}

p {
	margin: 0.4em 0 0.4em 0;
	padding: 0;

	font-size: 63%;
	line-height: 1.5;
}

table {
	table-layout: fixed;
	width: 100%;
	font-size: 63%;
	text-align: left;
}
thead {
	font-family: 'Proxima Nova Bold';
}

strong {
	font-family: 'Proxima Nova Bold';
}

code {
	font-size: inherit;
}

ol,ul {
	list-style-type: none;
	list-style-position: inside;
	counter-reset: item;

	margin: 0.5em 0 0 0;
	padding: 0;

	font-size: 63%;
}
ol li, ul li {
	padding: 0.5em 0 0.5em 0;

	font-size: inherit;
	line-height: 1.5;
}
ol li:before {
	content: counter(item) ". ";
	counter-increment: item;
	font-family: 'Proxima Nova Bold';
}
ul.dynamic {
	list-style-type: none;
	padding: 0;
}
ul.dynamic li {
	padding: 4% 15% 4% 4%;

	border-radius: 4px;
	border: none;

	box-shadow: inset 0 -7px 12px -12px #000;

	background-color: #f3f3f3;
}
ul.dynamic li:last-child {
	box-shadow: none;
}
ul.dynamic li a {
	color: #000;
}
ul.dynamic.arrow li,
ul.dynamic li.arrow {
	background-image: url('../images/arrow-right.svg');
	background-position: 94% center; /* CSS 2 fallback */
	background-position: right 5% center; /* requires CSS 3 */
	background-size: 1em auto;
	background-repeat: no-repeat;
}

article {
	display: none;
	z-index: 2;

	font-size: 100%;
}




/*  ----------------------------------------------------------
								COLORS
	---------------------------------------------------------- */

/*  Color: "Soft Red"
	Class name: red
    ---------------- */
.color_softred { color: #e15a64; }
.bg_red, input.red, button.red, ul.red li, label.red,
input.red + label {
	background-color: #e15a64;
}
/* Downpressed button. */
button.red:active, button.red.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.red,
input.btn-group.red:active + label,
input.btn-group:checked + label.red,
input.btn-group.red:checked + label {
	background-color: #cb414b;
}

/*  Color: "Bright Light"
	Class name: yellow
    -------------------- */
.color_brightlight { color: #ecd53b; }
.bg_yellow, input.yellow, button.yellow, ul.yellow li, label.yellow,
input.yellow + label {
	background-color: #ecd53b;
}
/* Downpressed button. */
button.yellow:active, button.yellow.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.yellow,
input.btn-group.yellow:active + label,
input.btn-group:checked + label.yellow,
input.btn-group.yellow:checked + label {
	background-color: #d9c022;
}

/*  Color: "Wave Green"
	Class name: green
    ------------------ */
.color_wavegreen { color: #54dfb3; }
.bg_green, input.green, button.green, ul.green li, label.green,
input.green + label {
	background-color: #54dfb3;
}
/* Downpressed button. */
button.green:active, button.green.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.green,
input.btn-group.green:active + label,
input.btn-group:checked + label.green,
input.btn-group.green:checked + label {
	background-color: #3aca9c;
}

/*  Color: "Blue Hue"
	Clas name: blue
    ------------------ */
.color_bluehue { color: #6bc6ce; }
.bg_blue, input.blue, button.blue, ul.blue li, label.blue,
input.blue + label {
	background-color: #6bc6ce;
}
/* Downpressed button. */
button.blue:active, button.blue.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.blue,
input.btn-group.blue:active + label,
input.btn-group:checked + label.blue,
input.btn-group.blue:checked + label {
	background-color: #52afb8;
}

/*  Color: "Indigo"
	Class name: indigo
    ------------------ */
.color_indigo { color: #b48b9b; }
.bg_indigo, input.indigo, button.indigo, ul.indigo li, label.indigo,
input.indigo + label {
	background-color: #b48b9b;
}
/* Downpressed button. */
button.indigo:active, button.indigo.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.indigo,
input.btn-group.indigo:active + label,
input.btn-group:checked + label.indigo,
input.btn-group.indigo:checked + label {
	background-color: #9c7283;
}

/*  Color: "Arctic"
	Class name: arctic
    ------------------ */
.color_arctic { color: #f3f3f3; }
.bg_arctic, input.arctic, button.arctic, ul.arctic li,
input.arctic + label {
	background-color: #f3f3f3;
}
/* Downpressed button. */
button.arctic:active, button.arctic.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.arctic,
input.btn-group.arctic:active + label,
input.btn-group:checked + label.arctic,
input.btn-group.arctic:checked + label {
	background-color: #656565;
}

/*  Color: "Aluminium"
	Class name: aluminium
    ------------------ */
.color_aluminium { color: #e2e2e2 }
.bg_aluminium, input.aluminium, button.aluminium, ul.aluminium li,
input.aluminium + label {
	background-color: #e2e2e2;
}
/* Downpressed button. */
button.aluminium:active, button.aluminium.pressed,
 /* Input element with adjacent label. */
input.btn-group:active + label.aluminium,
input.btn-group.aluminium:active + label,
input.btn-group:checked + label.aluminium,
input.btn-group.aluminium:checked + label {
	background-color: #c0c0c0;
}

/*  Color: "Charcoal"
	Class name: charcoal
    ------------------ */
.color_charcoal { color: #b9b9b9; }
.bg_charcoal, input.charcoal, button.charcoal, ul.charcoal li,
input.charcoal + label {
	background-color: #b9b9b9;
}
/* Downpressed button. */
button.charcoal:active, button.charcoal.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.charcoal,
input.btn-group.charcoal:active + label,
input.btn-group:checked + label.charcoal,
input.btn-group.charcoal:checked + label {
	background-color: #9d9d9d;
}

/*  Color: "Stone"
	Class name: stone
    ------------------ */
.color_stone { color: #777777 }
.bg_stone, input.stone, button.stone, ul.stone li,
input.stone + label {
	background-color: #777777;
}
/* Downpressed button. */
button.stone:active, button.stone.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.stone,
input.btn-group.stone:active + label,
input.btn-group:checked + label.stone,
input.btn-group.stone:checked + label {
	background-color: #656565;
}

/*  Color: "Jet Black"
	Class name: jetblack
    ------------------ */
.color_black { color: #070707 }
.bg_black, input.black, button.black, ul.black li,
input.black + label {
	background-color: #070707;
}
/* Downpressed button. */
button.black:active, button.black.pressed,
/* Input element with adjacent label. */
input.btn-group:active + label.black,
input.btn-group.black:active + label,
input.btn-group:checked + label.black,
input.btn-group.black:checked + label {
	background-color: #000000;
}

@media	screen and (orientation: landscape) and (-webkit-min-device-pixel-ratio : 2),
		screen and (orientation: landscape) and (min--moz-device-pixel-ratio: 2),
		screen and (orientation: landscape) and (min-device-pixel-ratio : 2) {
	body { font-size: 4.5vw; }
}

Credits

Gregory O. Voronin
12 projects • 107 followers
biomedical researcher - hope & cures through research; making in my spare time - don't hesitate to reach out!

Comments