Repository: dimitrinicolas/midi-controller-css Branch: master Commit: 6b0850131152 Files: 11 Total size: 32.6 KB Directory structure: gitextract_4zadc2mu/ ├── .gitignore ├── lib/ │ ├── actions.js │ ├── add-line.js │ ├── delete-line.js │ ├── focus-selector.js │ ├── get-focus-node.js │ ├── index.js │ └── order.js ├── license.md ├── package.json └── readme.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store npm-debug.log node_modules logs *.log* tmp ================================================ FILE: lib/actions.js ================================================ 'use babel'; import path from 'path'; import play from 'play'; let tickSound = path.resolve(__dirname, '../assets/sounds/1.wav'); let tickSound2 = path.resolve(__dirname, '../assets/sounds/2.wav'); let lastValue = null; let lastTime = 0; let tick = (value, accent) => { if (lastValue != value) { let now = Date.now(); if (accent || now - lastTime > 50) { lastTime = now; lastValue = value; if (accent) { play.sound(tickSound); } else { play.sound(tickSound2); } } } }; export default function actions(message) { // console.log(message.data); // TODO // col 1 : @media with current media indicator // % / px // col 6 : bg color img linear gradient // col 8 : all value if (message.data[0] === 176 && message.data[1] === 42 && message.data[2] === 127) { // STOP this.deleteLine(); } if (message.data[0] === 176 && message.data[1] === 58 && message.data[2] === 127) { // LEFT this.focusSelector(-1); } if (message.data[0] === 176 && message.data[1] === 59 && message.data[2] === 127) { // RIGHT this.focusSelector(1); } if (message.data[0] === 176 && message.data[2] === 127) { // COLUMN 2 BUTTONS POSITION var values = { 33: 'absolute', 49: 'relative', 65: 'absolute' }; var position = values[message.data[1]]; if (message.data[1] === 65) { this.addLine('position', function(node) { return 'absolute 50% auto auto 50%'; }, { focus: true, cb: function() { this.addLine('transform', function(node) { return 'translateX(-50%) translateY(-50%)'; }, { focus: true }); }.bind(this)}); } else if (position) { this.getFocusNode(function(node) { if (node && node.type === 'decl' && node.prop === 'position' && node.value.split(' ')[0] === position) { this.addLine('position', function() { return position; }, { focus: true }); } else { this.addLine('position', function(node) { var value = ''; if (node) { value = node.value.split(' '); value.shift(); value = value.join(' '); } if (value) { value = ' ' + value; } return position + value; }, { focus: true }); } }.bind(this)); } } if (message.data[0] === 176 && message.data[1] === 1) { // COLUMN 2 SLIDER POSITION var px = Math.round(message.data[2] / 127 * 64); this.addLine('position', function(node) { var position = !node ? 'relative' : node.value.split(' ')[0]; px = px !== 0 ? px + 'px' : px; tick(position + ' ' + px, px === 0); return position + ' ' + px; }); } // if (message.data[0] === 176 && message.data[1] === 17) { // // COLUMN 2 ORIENTATION POSITION // // TODO // // if (message.data[2] === 127) { // // LEFT // // this.addLine('position', function(node) { // var position = !node ? 'relative' : node.value.split(' ')[0]; // var value = ''; // if (node) { // value = node.value.split(' '); // value.shift(); // if (value.length === 0) { // value = '0 0'; // } // else if (value.length === 1) { // value = value[0] + ' ' + value[0]; // } // else { // value = value[0] + ' ' + value[1]; // } // } // if (value) { // value = ' ' + value; // } // return position + value; // }); // } // if (message.data[2] === 1 || message.data[2] === 65) { // // MIDDLE // // this.addLine('position', function(node) { // var position = !node ? 'relative' : node.value.split(' ')[0]; // var value = ''; // if (node) { // value = node.value.split(' '); // value.shift(); // if (value.length === 0) { // value = '0'; // } // else { // value = value[0]; // } // } // if (value) { // value = ' ' + value; // } // return position + value; // }); // } // if (message.data[2] === 63) { // // RIGHT // // this.addLine('position', function(node) { // var position = !node ? 'relative' : node.value.split(' ')[0]; // var value = ''; // if (node) { // value = node.value.split(' '); // value.shift(); // if (value.length === 0) { // value = '0 0'; // } // else if (value.length === 1) { // value = value[0] + ' ' + value[0]; // } // else { // value = value[0] + ' ' + value[1]; // } // } // if (value) { // value = ' ' + value; // } // return position + value; // }); // } // // } if (message.data[0] === 176 && message.data[2] === 127) { // COLUMN 3 BUTTONS DISPLAY var values = { 34: 'block', 50: 'inline-block', 66: 'flex' }; var display = values[message.data[1]]; if (display) { this.addLine('display', function() { return display; }, { focus: true }); } } if (message.data[0] === 176 && message.data[1] === 2) { // COLUMN 3 SLIDER DISPLAY var px = Math.round(message.data[2] / 127 * 66); if (px >= 65) { px = '100%'; } else if (px !== 0) { px = px + 'px'; } tick(px, (px === 0 || px === '100%')); this.addLine('size', function(node) { return px; }); } if (message.data[0] === 176 && message.data[2] === 127) { // COLUMN 4 BUTTONS MARGIN/PADDING var props = { 35: 'margin', 51: 'padding' }; var prop = props[message.data[1]]; if (prop) { this.addLine(prop, function(node) { var value = !node ? '0' : node.value; return value; }, { focus: true }); } } if (message.data[0] === 176 && message.data[1] === 3) { // COLUMN 4 SLIDER MARGIN/PADDING var px = Math.round(message.data[2] / 127 * 64); px = px !== 0 ? px + 'px' : px; this.getFocusNode(function(node) { if (node && node.type === 'decl') { if (node.prop === 'margin' || node.prop === 'padding') { tick(px, (px === 0)); this.addLine(node.prop, function() { return px; }); } } }.bind(this)); } if (message.data[0] === 176 && message.data[2] === 127) { // COLUMN 5 BUTTONS FONTS WEIGHT var values = { 36: '500', 52: '400', 68: '300' }; var weight = values[message.data[1]]; if (weight) { this.getFocusNode(function(node) { if (node && node.type === 'decl' && node.prop === 'position' && node.value.split(' ')[0] === position) { this.addLine('font', function() { return 'title ' + weight + ' 16px'; }, { focus: true }); } else { this.addLine('font', function(node) { var px = '16px'; if (node) { var splitted = node.value.split(' '); px = splitted[splitted.length - 1]; } return 'title ' + weight + ' ' + px; }, { focus: true }); } }.bind(this)); } } if (message.data[0] === 176 && message.data[1] === 4) { // COLUMN 5 SLIDER FONT SIZE var px = Math.round(message.data[2] / 127 * 10) + 12; px = px !== 0 ? px + 'px' : px; this.addLine('font', function(node) { var font = ['title', 'regular', 0]; if (node) { font = node.value.split(' '); } font[font.length - 1] = px; let result = font.join(' '); tick(result, (px === 0)); return result; }); } if (message.data[0] === 176 && message.data[2] === 127) { // COLUMN 6 BUTTONS TRANSITION var values = { 37: '0.1s', 53: '0.2s', 69: '0.3s' }; var transition = values[message.data[1]]; if (transition) { this.addLine('transition', function() { return transition; }, { focus: true }); } } if (message.data[0] === 176 && message.data[1] === 5) { // COLUMN 6 SLIDER TRANSITION var sec = Math.round(Math.round(message.data[2] / 127 * 3 / 10 * 100) * 0.02 * 100) / 100; sec = sec !== 0 ? sec + 's' : sec; tick(sec, (sec === 0)); this.addLine('transition', function(node) { return sec; }); } }; ================================================ FILE: lib/add-line.js ================================================ 'use babel'; var emptyLine = false; import postcss from 'postcss'; import order from './order'; var timer = {}; function timeout(prop) { if (timer[prop].prop, timer[prop].value) { set(timer[prop].prop, timer[prop].value, timer[prop].options); timer[prop] = { time: Date.now() + 100, prop: null, value: null, options: null, timeout: null }; } } export default function focusSelector(prop, value, options) { if (!timer[prop]) { set(prop, value, options); timer[prop] = { time: Date.now() + 100, prop: null, value: null, options: null, timeout: null }; } else { var rel = timer[prop].time - Date.now(); if (rel > 0) { timer[prop].prop = prop; timer[prop].value = value; if (timer[prop].timeout) { clearTimeout(timer[prop].timeout); } timer[prop].timeout = setTimeout(timeout.bind(null, prop), rel); } else { set(prop, value, options); timer[prop] = { time: Date.now() + 100, prop: null, value: null, options: null, timeout: null }; } } }; function set(prop, value, opts) { var options = opts || {}; var editor = atom.workspace.getActiveTextEditor(); if (!editor) { return; } var cursor = editor.cursors[0]; var cursorPosition = editor.getCursorBufferPosition(); var css = editor.getText(); postcss([]).process(css, { from: undefined }).then(function(res) { var currentNode = null; var propPos = [0, 0]; for (var h = 0; h < order.length; h++) { var index = order[h].indexOf(prop); if (index > -1) { propPos = [h, index]; break; } } var propDist = (propPos[0] * 100 + propPos[1]); for (var i = 0; i < res.root.nodes.length; i++) { var node = res.root.nodes[i]; if (typeof node.selector === 'string') { node.selectorHeight = node.selector.split("\n").length; if (node.nodes[0]) { node.startWhiteLine = node.nodes[0].source.start.line - (node.source.start.line + node.selectorHeight); } else { node.startWhiteLine = 0; } if (node.nodes[node.nodes.length - 1]) { node.endWhiteLine = (node.source.end.line - 1) - node.nodes[node.nodes.length - 1].source.end.line; } else { node.endWhiteLine = 0; } node.properties = {}; for (var j = 0; j < node.nodes.length; j++) { if (node.nodes[j].type === 'decl') { node.properties[node.nodes[j].prop] = j; } } if (cursorPosition.row >= node.source.start.line && cursorPosition.row <= node.source.end.line) { currentNode = i; } } } if (currentNode !== null) { currentNode = res.root.nodes[currentNode]; var dist = null; var dest = null; var toLine = 1; if (typeof currentNode.properties[prop] !== 'undefined') { var node = currentNode.nodes[currentNode.properties[prop]]; var newValue = value(node); if (node.value == newValue && !options.focus) { timer[prop].time = 0; if (options.cb) { options.cb(); } return; } var diff = (node.source.end.line - 1) - cursorPosition.row; if (diff > 0) { cursor.moveDown(diff); } else if (diff < 0) { cursor.moveUp(Math.abs(diff)); } cursor.moveToEndOfLine(); editor.deleteToBeginningOfLine(); var newCursorPosition = editor.getCursorBufferPosition(); var tab = newCursorPosition.column === 0 ? "\t" : ''; editor.insertText(tab + prop + ': ' + newValue + ';'); editor.moveLeft(); if (options.cb) { options.cb(); } } else { for (var a = 0; a < order.length; a++) { for (var b = 0; b < order[a].length; b++) { var item = order[a][b]; if (typeof currentNode.properties[item] !== 'undefined') { for (var h = 0; h < order.length; h++) { var index = order[h].indexOf(item); if (index > -1) { var newDist = [h, index]; break; } } if (dist === null || Math.abs(propDist - (dist[0] * 100 + dist[1])) > Math.abs(propDist - (newDist[0] * 100 + newDist[1]))) { dist = [newDist[0], newDist[1]]; dest = item; } } } } if (dist) { if ((dist[0] * 100 + dist[1]) < propDist) { toLine = 1; } else { toLine = -1; } var insertLine = propPos[0] === dist[0] ? false : true; } else { toLine = 0; } var ref; if (dest) { var ref = currentNode.nodes[currentNode.properties[dest]]; } else { ref = { source: { start: { line: currentNode.source.start.line - 1 }, end: { line: currentNode.source.start.line + 1 } } }; } var diff; if (toLine < 0) { diff = (ref.source.start.line - 2) - cursorPosition.row; } else { diff = (ref.source.end.line - 1) - cursorPosition.row; } if (currentNode.selectorHeight && !currentNode.nodes.length) { diff += currentNode.selectorHeight - 1; } if (diff > 0) { cursor.moveDown(diff); } else if (diff < 0) { cursor.moveUp(Math.abs(diff)); } cursor.moveToEndOfLine(); if (currentNode.nodes.length || emptyLine) { editor.insertNewlineBelow(); } if (insertLine && toLine < 0 && emptyLine) { editor.insertNewlineBelow(); cursor.moveUp(); } if (insertLine && toLine > 0 && emptyLine) { editor.insertNewlineBelow(); } var newCursorPosition = editor.getCursorBufferPosition(); var tab = newCursorPosition.column === 0 ? "\t" : ''; editor.insertText(tab + prop + ': ' + value(null) + ';'); editor.moveLeft(); if (options.cb) { options.cb(); } } } }); } ================================================ FILE: lib/delete-line.js ================================================ 'use babel'; export default function deleteLine() { var editor = atom.workspace.getActiveTextEditor(); if (editor) { var cursor = editor.cursors[0]; cursor.moveToEndOfLine(); editor.deleteToBeginningOfLine(); editor.delete(); } }; ================================================ FILE: lib/focus-selector.js ================================================ 'use babel'; import postcss from 'postcss'; export default function focusSelector(index) { var editor = atom.workspace.getActiveTextEditor(); if (!editor) { return; } var cursor = editor.cursors[0]; var cursorPosition = editor.getCursorBufferPosition(); var css = editor.getText(); postcss([]).process(css, { from: undefined }).then(function(res) { var currentNode = 0; for (var i = 0; i < res.root.nodes.length; i++) { var node = res.root.nodes[i]; if (cursorPosition.row >= node.source.start.line && cursorPosition.row <= node.source.end.line) { currentNode = i; break; } } var focusNode = currentNode + index; if (typeof res.root.nodes[focusNode] !== 'undefined') { var node = res.root.nodes[focusNode]; var dest = node.source.end.line; if (node.nodes[0]) { dest = node.nodes[0].source.start.line; } var diff = (dest - 1) - cursorPosition.row; if (diff > 0) { cursor.moveDown(diff); } else if (diff < 0) { cursor.moveUp(Math.abs(diff)); } cursor.moveToEndOfLine(); } }); }; ================================================ FILE: lib/get-focus-node.js ================================================ 'use babel'; import postcss from 'postcss'; export default function getFocusNode(cb) { var editor = atom.workspace.getActiveTextEditor(); if (!editor) { return; } var cursor = editor.cursors[0]; var cursorPosition = editor.getCursorBufferPosition(); var css = editor.getText(); postcss([]).process(css, { from: undefined }).then(function(res) { var currentNode = 0; for (var i = 0; i < res.root.nodes.length; i++) { var node = res.root.nodes[i]; if (cursorPosition.row >= node.source.start.line && cursorPosition.row <= node.source.end.line) { currentNode = i; break; } } currentNode = res.root.nodes[currentNode]; var focused = null; for (var i = 0; i < currentNode.nodes.length; i++) { var node = currentNode.nodes[i]; if (cursorPosition.row + 1 >= node.source.start.line && cursorPosition.row + 1 <= node.source.end.line) { focused = node; break; } } cb(focused); }); }; ================================================ FILE: lib/index.js ================================================ 'use babel'; import { CompositeDisposable } from 'atom'; import actions from './actions'; import getFocusNode from './get-focus-node'; import focusSelector from './focus-selector'; import addLine from './add-line'; import deleteLine from './delete-line'; var finalOutput; export default { subscriptions: null, midi: null, activate(state) { this.subscriptions = new CompositeDisposable(); this.subscriptions.add(atom.commands.add('atom-workspace', { 'midi:convert': () => this.convert() })); if (navigator.requestMIDIAccess) { navigator.requestMIDIAccess({ sysex: true }).then(function(midiAccess) { var inputs = midiAccess.inputs.values(); for (var input = inputs.next(); input && !input.done; input = inputs.next()) { input.value.onmidimessage = actions.bind(this); } var outputs = midiAccess.outputs.values(); for (var output = outputs.next(); output && !output.done; output = outputs.next()) { finalOutput = output; // Inquiry Message Request finalOutput.value.send([0xF0,0x7E,0x7F,0x06,0x01,0xF7]); // (4) Mode Request finalOutput.value.send([0xF0,0x42,0x40,0x00,0x01,0x13,0x00,0x1F,0x12,0x00,0xF7]); // Inquiry Message Request finalOutput.value.send([0xF0,0x7E,0x7F,0x06,0x01,0xF7]); // (5) Current Scene Data Dump finalOutput.value.send([0xF0,0x42,0x40,0x00,0x01,0x13,0x00,0x7F,0x7F,0x02,0x03,0x05,0x40,0x00,0x00,0x00, 0x01,0x10,0x01,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0x00,0x10,0x00,0x00,0x7F,0x00, 0x01,0x00,0x20,0x00,0x7F,0x00,0x00,0x01,0x00,0x30,0x00,0x7F,0x00,0x00,0x01,0x00, 0x40,0x00,0x7F,0x00,0x10,0x00,0x01,0x00,0x01,0x00,0x7F,0x00,0x01,0x00,0x00,0x11, 0x00,0x7F,0x00,0x01,0x00,0x00,0x21,0x00,0x7F,0x00,0x01,0x00,0x31,0x00,0x00,0x7F, 0x00,0x01,0x00,0x41,0x00,0x00,0x7F,0x00,0x10,0x01,0x00,0x02,0x00,0x00,0x7F,0x00, 0x01,0x00,0x12,0x00,0x7F,0x00,0x00,0x01,0x00,0x22,0x00,0x7F,0x00,0x00,0x01,0x00, 0x32,0x00,0x7F,0x00,0x01,0x00,0x00,0x42,0x00,0x7F,0x00,0x10,0x01,0x00,0x00,0x03, 0x00,0x7F,0x00,0x01,0x00,0x00,0x13,0x00,0x7F,0x00,0x01,0x00,0x23,0x00,0x00,0x7F, 0x00,0x01,0x00,0x33,0x00,0x00,0x7F,0x00,0x01,0x00,0x43,0x00,0x7F,0x00,0x00,0x10, 0x01,0x00,0x04,0x00,0x7F,0x00,0x00,0x01,0x00,0x14,0x00,0x7F,0x00,0x00,0x01,0x00, 0x24,0x00,0x7F,0x00,0x01,0x00,0x00,0x34,0x00,0x7F,0x00,0x01,0x00,0x00,0x44,0x00, 0x7F,0x00,0x10,0x01,0x00,0x00,0x05,0x00,0x7F,0x00,0x01,0x00,0x15,0x00,0x00,0x7F, 0x00,0x01,0x00,0x25,0x00,0x00,0x7F,0x00,0x01,0x00,0x35,0x00,0x7F,0x00,0x00,0x01, 0x00,0x45,0x00,0x7F,0x00,0x00,0x10,0x01,0x00,0x06,0x00,0x7F,0x00,0x00,0x01,0x00, 0x16,0x00,0x7F,0x00,0x01,0x00,0x00,0x26,0x00,0x7F,0x00,0x01,0x00,0x00,0x36,0x00, 0x7F,0x00,0x01,0x00,0x46,0x00,0x00,0x7F,0x00,0x10,0x01,0x00,0x07,0x00,0x00,0x7F, 0x00,0x01,0x00,0x17,0x00,0x00,0x7F,0x00,0x01,0x00,0x27,0x00,0x7F,0x00,0x00,0x01, 0x00,0x37,0x00,0x7F,0x00,0x00,0x01,0x00,0x47,0x00,0x7F,0x00,0x10,0x00,0x01,0x00, 0x3A,0x00,0x7F,0x00,0x01,0x00,0x00,0x3B,0x00,0x7F,0x00,0x01,0x00,0x00,0x2E,0x00, 0x7F,0x00,0x01,0x00,0x3C,0x00,0x00,0x7F,0x00,0x01,0x00,0x3D,0x00,0x00,0x7F,0x00, 0x01,0x00,0x3E,0x00,0x7F,0x00,0x00,0x01,0x00,0x2B,0x00,0x7F,0x00,0x00,0x01,0x00, 0x2C,0x00,0x7F,0x00,0x01,0x00,0x00,0x2A,0x00,0x7F,0x00,0x01,0x00,0x00,0x29,0x00, 0x7F,0x00,0x01,0x00,0x2D,0x00,0x00,0x7F,0x00,0x7F,0x7F,0x7F,0x7F,0x00,0x7F,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xF7]); // Inquiry Message Request finalOutput.value.send([0xF0,0x7E,0x7F,0x06,0x01,0xF7]); // (2) Scene Write Request finalOutput.value.send([0xF0,0x42,0x40,0x00,0x01,0x13,0x00,0x1F,0x11,0x00,0xF7]); for (var i = 0; i < 8; i++) { setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 32 + i, 0x7F])); }.bind(null, i), 1000 + i * 70); setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 32 + i, 0x00])); }.bind(null, i), 1200 + i * 70); setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 48 + i, 0x7F])); }.bind(null, i), 1000 + 100 + i * 70); setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 48 + i, 0x00])); }.bind(null, i), 1200 + 100 + i * 70); setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 64 + i, 0x7F])); }.bind(null, i), 1000 + 100 * 2 + i * 70); setTimeout(function(i) { finalOutput.value.send(new Uint8Array([176, 64 + i, 0x00])); }.bind(null, i), 1200 + 100 * 2 + i * 70); } } }.bind(this), function() { console.error("No access to MIDI devices"); }); } else { console.error("No MIDI support"); } }, getFocusNode: getFocusNode, focusSelector: focusSelector, addLine: addLine, deleteLine: deleteLine }; ================================================ FILE: lib/order.js ================================================ 'use babel'; export default [ [ 'position', 'top', 'right', 'bottom', 'left', 'z-index', ], [ 'display', 'visibility', 'flex', 'flex-grow', 'flex-shrink', 'flex-basis', 'flex-direction', 'flex-flow', 'flex-wrap', 'align-content', 'align-items', 'align-self', 'justify-content', 'order', 'float', 'size', 'width', 'min-width', 'max-width', 'height', 'min-height', 'max-height', 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'vertical-align', 'overflow', 'overflow-x', 'overflow-y', 'box-sizing', ], [ 'font', 'font-weight', 'font-style', 'font-variant', 'font-size-adjust', 'font-stretch', 'font-size', 'font-family', 'color', 'text-decoration', 'text-transform', 'text-align', 'text-justify', 'text-outline', 'text-shadow', 'line-height', 'white-space', 'word-spacing', 'word-wrap', 'word-break', 'tab-size', 'hyphens', 'letter-spacing', ], [ 'opcaity', 'outline', 'outline-width', 'outline-style', 'outline-color', 'outline-offset', 'list-style', 'list-style-position', 'list-style-type', 'list-style-image', 'border', 'border-spacing', 'border-collapse', 'border-width', 'border-style', 'border-color', 'border-top', 'border-top-width', 'border-top-style', 'border-top-color', 'border-right', 'border-right-width', 'border-right-style', 'border-right-color', 'border-bottom', 'border-bottom-width', 'border-bottom-style', 'border-bottom-color', 'border-left', 'border-left-width', 'border-left-style', 'border-left-color', 'border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius', 'border-image', 'border-image-source', 'border-image-slice', 'border-image-width', 'border-image-outset', 'border-image-repeat', 'border-top-image', 'border-right-image', 'border-bottom-image', 'border-left-image', 'border-corner-image', 'border-top-left-image', 'border-top-right-image', 'border-bottom-right-image', 'border-bottom-left-image', 'background', 'background-color', 'background-image', 'background-attachment', 'background-position', 'background-position-x', 'background-position-y', 'background-clip', 'background-origin', 'background-size', 'background-repeat', 'background-blend-mode', 'box-shadow', 'filter', 'resize', 'cursor', 'transform', 'transition', 'transition-delay', 'transition-timing-function', 'transition-duration', 'transition-property', 'transform', 'transform-origin', 'animation', 'animation-name', 'animation-duration', 'animation-play-state', 'animation-timing-function', 'animation-delay', 'animation-iteration-count', 'animation-direction', 'animation-fill-mode', ] ]; ================================================ FILE: license.md ================================================ Copyright (c) 2016 NICOLAS Dimitri Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: package.json ================================================ { "name": "midi-controller-css", "main": "./lib/index", "version": "1.2.0", "description": "Use Korg NanoKontrol 2 to edit your css files", "keywords": [ "midi", "controller", "css", "atom", "atom-package", "korg", "nanokontrol" ], "repository": "https://github.com/dimitrinicolas/midi-controller-css", "license": "MIT", "engines": { "atom": ">=1.0.0 <2.0.0" }, "dependencies": { "play": "^0.5.0", "postcss": "^6.0.19" } } ================================================ FILE: readme.md ================================================ # Midi Controller Css I type a lot of css, so I bought a Korg NanoKontrol 2 and built this lovely Atom package. Each column of buttons controls the values of one css property, and each slider sets the px/percent/... values. Ordinary snippets are outdated, go midi snippets! ![Demo](assets/readme/demo.gif) This usb midi controller is costless and very complete for its size. I bought a used one for 20€ ($25). You can have a look at [lib/actions.js](lib/actions.js) for a complete list of features. PS: Most of the snippets only works with some popular PostCSS plugins, you can check my list on my [personnal front-end framework](https://github.com/dimitrinicolas/front-end-stack/blob/master/build/postcss.config.js). ![Korg NanoKontrol 2](assets/readme/photo.jpg) With some helpers: ![Korg NanoKontrol 2](assets/readme/photo2.jpg)