├── .gitignore ├── .jshintrc ├── .tern-project ├── README.md ├── bin ├── framer-new.js ├── framer-preview.js ├── framer-update.js └── framer.js ├── boilerplate ├── module │ ├── .framer.json │ ├── .gitignore │ ├── .jshintrc │ ├── .tern-project │ ├── Makefile │ ├── README.md │ ├── index.js │ ├── package.json │ └── test.html └── project │ ├── .framer │ └── framer.json │ ├── .gitignore │ ├── .jshintrc │ ├── .tern-project │ ├── Makefile │ ├── README.md │ ├── images │ └── framer-icon.png │ ├── index.html │ ├── index.js │ ├── modules │ └── myModule │ │ ├── background.png │ │ ├── data.json │ │ └── index.js │ └── package.json ├── lib └── framer_test.js ├── package.json └── preview.png /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "node": true, 4 | "esnext": true, 5 | "forin": true, 6 | "latedef": "nofunc", 7 | "supernew": true, 8 | "unused": true 9 | } 10 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "complete_strings": {}, 4 | "node": {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Framer CLI 2 | 3 | > Providing most of the functionality of Framer Studio, but from the comfort of 4 | > your terminal. 5 | 6 | Screenshot 7 | 8 | Framer CLI is in its infancy, but the aim is to create a decent way to build 9 | quick prototypes/dynamic layouts in code from the editor of your choice. The 10 | current implementation of this tool requires [Node][1]. 11 | 12 | ## Who is this for? 13 | 14 | This is not a replacement to [Framer Studio][2] and is best suited for those 15 | who are comfortable with Framer's API and using the command line. 16 | 17 | ## Features 18 | 19 | - CoffeeScript & ECMAScript 6 JS. It will handle CoffeeScript, es6-compliant 20 | JavaScript, or a mix of the two. 21 | - Local server for previewing/debugging. 22 | - Handles true [Node-style modules][3]. Place any code, assets, etc. that you 23 | want in the `modules` folder and `require` them in your main `index.js` file. 24 | Make use of Node modules and third-party Framer modules as well. 25 | - Live reloading when any of the files in your dependency tree change. 26 | - **WIP:** Intelligent completions that are scoped appropriately. This uses 27 | [Tern][4] and requires using an editor with a [Tern plugin][5]. 28 | - Quickly generate project and module boilerplate. 29 | 30 | ## Usage 31 | 32 | ```bash 33 | $ npm install -g peteschaffner/framer-cli 34 | $ framer path/to/my/project & 35 | $ vim path/to/my/project/index.js 36 | ``` 37 | 38 | The best way to learn is probably to poke around the project and module 39 | boilerplate that `framer(1)` generates. For more detailed instructions, 40 | `framer -h`. 41 | 42 | [1]: https://nodejs.org/ 43 | [2]: http://framerjs.com/ 44 | [3]: https://nodejs.org/api/modules.html#modules_folders_as_modules 45 | [4]: http://ternjs.net/ 46 | [5]: http://ternjs.net/#plugins 47 | -------------------------------------------------------------------------------- /bin/framer-new.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var colors = require('colors/safe'); 8 | var exec = require('child_process').exec; 9 | var fs = require('fs-extra'); 10 | var path = require('path'); 11 | var program = require('commander'); 12 | 13 | program 14 | .description('Create a project.') 15 | .arguments('[dir]') 16 | .option('-m, --module', 'create a module') 17 | .parse(process.argv); 18 | 19 | var directory = path.resolve(program.args[0] || '.'); 20 | var projectType = require('../lib/framer_test.js')(directory); 21 | 22 | // create [dir] if it doesn't exist 23 | if (!projectType) fs.mkdirpSync(directory); 24 | 25 | // scaffold project/module if [dir] is empty 26 | if (!!!fs.readdirSync(directory).length) { 27 | var projectType = program.module ? 'module' : 'project'; 28 | var toPath = '../boilerplate/' + projectType; 29 | 30 | console.log(colors.grey('Creating %s...'), projectType); 31 | fs.copySync(path.resolve(__dirname, toPath), directory); 32 | 33 | // move into [dir] 34 | process.chdir(directory); 35 | 36 | console.log(colors.grey('Installing project dependencies...')); 37 | exec('framer update'); 38 | exec('npm install --production'); 39 | } else console.warn(colors.red('Error: ') + directory + ' is not empty'); 40 | 41 | -------------------------------------------------------------------------------- /bin/framer-preview.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var auth = require('basic-auth'); 8 | var babelify = require('babelify'); 9 | var browserify = require('browserify'); 10 | var chokidar = require('chokidar'); 11 | var coffeeify = require('coffeeify'); 12 | var colors = require('colors/safe'); 13 | var connect = require('connect'); 14 | var exec = require('child_process').exec; 15 | var fs = require('fs-extra'); 16 | var livereload = require('connect-livereload'); 17 | var livereloadServer = require('tiny-lr'); 18 | var path = require('path'); 19 | var program = require('commander'); 20 | var serveIndex = require('serve-index'); 21 | var serveStatic = require('serve-static'); 22 | var watchify = require('watchify'); 23 | 24 | 25 | program 26 | .description('Preview your project.') 27 | .arguments('[dir]') 28 | .option('-p, --port ', 'specify the port [3000]', Number, 3000) 29 | .parse(process.argv); 30 | 31 | var directory = path.resolve(program.args[0] || '.'); 32 | var projectType = require('../lib/framer_test.js')(directory); 33 | 34 | if (!projectType) { 35 | console.warn(colors.red('Error: ') + 'not a "framer-cli" project'); 36 | process.exit(1); 37 | } 38 | 39 | // move into [dir] 40 | process.chdir(directory); 41 | 42 | // setup the server 43 | var server = connect(); 44 | 45 | // watch files 46 | chokidar 47 | .watch(directory, { ignored: /node_modules|[\/\\]\./ }) 48 | .on('all', function(event, file) { 49 | livereloadServer.changed(file); 50 | }); 51 | 52 | // inject livereload.js 53 | if (process.env.NODE_ENV !== 'production') { 54 | server.use(livereload({ port: program.port })); 55 | } 56 | 57 | // http basic auth 58 | if (process.env.NODE_ENV === 'production') { 59 | server.use(function(req, res, next) { 60 | var creds = auth(req); 61 | var name = process.env.NAME || ''; 62 | var pass = process.env.PASS || ''; 63 | 64 | if (!creds || creds.name !== name || creds.pass !== pass) { 65 | res.writeHead(401, { 66 | 'WWW-Authenticate': 'Basic realm="You have to pay the troll toll"' 67 | }); 68 | res.end(); 69 | } else { 70 | next(); 71 | } 72 | }); 73 | } 74 | 75 | // browserify 76 | var b = browserify({ 77 | basedir: directory, 78 | cache: {}, 79 | debug: true, 80 | extensions: ['.coffee'], 81 | packageCache: {}, 82 | paths: [directory + '/modules'] 83 | }); 84 | 85 | b.transform(coffeeify, { global: true }); 86 | b.transform(babelify, { global: true }); 87 | b.add('index'); 88 | if (projectType === 'module') b.require('./index', { expose: '.' }); 89 | var w = watchify(b); 90 | 91 | // create build file for distribution 92 | if (process.env.NODE_ENV !== 'production') { 93 | w.on('bundle', function(bundle) { 94 | var bundleFile = fs.createWriteStream(directory + '/.bundle.js'); 95 | 96 | bundle.pipe(bundleFile); 97 | }); 98 | } 99 | 100 | // bundle on request 101 | server.use(function(req, res, next) { 102 | if (req.url !== '/.bundle.js') return next(); 103 | 104 | w.bundle() 105 | .on('error', function(err) { 106 | console.error(colors.red('\nError: ') + err.message); 107 | res.end('console.error("' + err.message + '")'); 108 | this.emit('end'); 109 | }) 110 | .pipe(res); 111 | }); 112 | 113 | // static files 114 | server.use(serveStatic(directory)); 115 | server.use(serveIndex(directory)); 116 | 117 | // livereload server 118 | if (process.env.NODE_ENV !== 'production') { 119 | server.use(livereloadServer.middleware({ app: server })); 120 | } 121 | 122 | // start the server 123 | server.listen(process.env.PORT || program.port, function () { 124 | var htmlFile = (projectType === 'module') ? 'test.html' : ''; 125 | 126 | console.log( 127 | colors.grey('%s running at ') + colors.cyan('http://localhost:%s/%s'), 128 | projectType.charAt(0).toUpperCase() + projectType.slice(1), 129 | program.port, 130 | htmlFile 131 | ); 132 | 133 | exec('open "http://localhost:' + program.port + '/' + htmlFile + '"'); 134 | }); 135 | 136 | 137 | -------------------------------------------------------------------------------- /bin/framer-update.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var colors = require('colors/safe'); 8 | var fs = require('fs-extra'); 9 | var path = require('path'); 10 | var program = require('commander'); 11 | var request = require('sync-request'); 12 | 13 | program 14 | .description('Update Framer.js framework.') 15 | .arguments('[dir]') 16 | .parse(process.argv); 17 | 18 | var directory = path.resolve(program.args[0] || '.'); 19 | var projectType = require('../lib/framer_test.js')(directory); 20 | 21 | if (!projectType) { 22 | console.warn(colors.red('Error: ') + 'not a "framer-cli" project'); 23 | process.exit(1); 24 | } else if (projectType === 'module') process.exit(1); 25 | 26 | console.log(colors.grey('Updating Framer.js...')); 27 | 28 | ['framer.js', 'framer.js.map'].forEach(function(file) { 29 | var res = request('GET', 'http://builds.framerjs.com/latest/' + file); 30 | 31 | fs.writeFileSync(directory + '/.framer/' + file, res.getBody()); 32 | }); 33 | -------------------------------------------------------------------------------- /bin/framer.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var program = require('commander'); 8 | 9 | program 10 | .version(require('../package.json').version) 11 | .description('A Framer.js CLI for quickly building modular prototypes.') 12 | .command('new [dir]', 'create a project') 13 | .command('preview [dir]', 'preview a project') 14 | .command('update [dir]', 'update Framer.js framework') 15 | .parse(process.argv); 16 | 17 | -------------------------------------------------------------------------------- /boilerplate/module/.framer.json: -------------------------------------------------------------------------------- 1 | { 2 | "!name": "framer", 3 | "print": { 4 | "!doc": "Printing allows you to inspect variables on runtime. It works similarly to console.log, only when using print, the output is shown directly within your prototype.", 5 | "!url": "http://framerjs.com/docs/#print", 6 | "!type": "fun(text: string) -> string" 7 | }, 8 | "Framer": { 9 | "Defaults": { 10 | "!doc": "The Framer.Defaults allows you to override the default properties for Layers and Animations when they are created.", 11 | "!url": "http://framerjs.com/docs/#defaults.defaults", 12 | "Animation": { 13 | "curve": "string", 14 | "time": "number" 15 | }, 16 | "Layer": { 17 | "backgroundColor": "string", 18 | "height": "number", 19 | "width": "number" 20 | } 21 | } 22 | }, 23 | "Canvas": { 24 | "!doc": "The Canvas object contains the size for the current entire document in pixels. It will change if you resize your document by resizing the window it is in.", 25 | "!url": "http://framerjs.com/docs/#canvas.canvas", 26 | "width": { 27 | "!doc": "The width of the current entire document in pixels. This property is read-only.", 28 | "!url": "http://framerjs.com/docs/#canvas.width", 29 | "!type": "number" 30 | }, 31 | "height": { 32 | "!doc": "The height of the current entire document in pixels. This property is read-only.", 33 | "!url": "http://framerjs.com/docs/#canvas.height", 34 | "!type": "number" 35 | }, 36 | "size": { 37 | "!doc": "The width and height of the current entire document in pixels. This property is read-only.", 38 | "!url": "http://framerjs.com/docs/#canvas.size", 39 | "width": "Canvas.width", 40 | "height": "Canvas.height" 41 | } 42 | }, 43 | "Screen": { 44 | "!doc": "The Screen object contains the size for the current device screen. The size will change when you update to a different device. If the device is full screen, it will be equal to the Canvas size.", 45 | "!url": "http://framerjs.com/docs/#screen.screen", 46 | "width": { 47 | "!doc": "The width of the current device screen in pixels. This property is read-only.", 48 | "!url": "http://framerjs.com/docs/#screen.width", 49 | "!type": "number" 50 | }, 51 | "height": { 52 | "!doc": "The height of the current device screen in pixels. This property is read-only.", 53 | "!url": "http://framerjs.com/docs/#screen.height", 54 | "!type": "number" 55 | }, 56 | "size": { 57 | "!doc": "The width and height of the current device screen in pixels. This property is read-only.", 58 | "!url": "http://framerjs.com/docs/#screen.size", 59 | "width": "Screen.width", 60 | "height": "Screen.height" 61 | } 62 | }, 63 | "Layer": { 64 | "!doc": "Layers are the basic containers for Framer. They have positioning, size, visual properties and a hierarchy. They can contain images, videos, text or even arbitrary html.", 65 | "!url": "http://framerjs.com/docs/#layer.layer", 66 | "!type": "fn(options: object)", 67 | "prototype": { 68 | "id": { 69 | "!doc": "A unique identification number for this layer. No other layer will have this number. The layer id is read only and cannot be changed.", 70 | "!url": "http://framerjs.com/docs/index.html#layer.id", 71 | "!type": "number" 72 | }, 73 | "name": { 74 | "!doc": "The layer name. This is not set by default but you can set it yourself. Imported layers from Sketch and Photoshop will have the source layer group set.", 75 | "!url": "http://framerjs.com/docs/index.html#layer.name", 76 | "!type": "string" 77 | }, 78 | "x": { 79 | "!doc": "The x property of a layer defines its x position relative to the top left corner.", 80 | "!url": "http://framerjs.com/docs/index.html#layer.x", 81 | "!type": "number" 82 | }, 83 | "y": "number", 84 | "z": "number", 85 | "width": "number", 86 | "height": "number" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /boilerplate/module/.gitignore: -------------------------------------------------------------------------------- 1 | .bundle.js 2 | node_modules 3 | -------------------------------------------------------------------------------- /boilerplate/module/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "browser": true, 4 | "browserify": true, 5 | "esnext": true, 6 | "forin": true, 7 | "latedef": "nofunc", 8 | "supernew": true, 9 | "unused": true, 10 | 11 | "globals": { 12 | "Framer": true, 13 | "Layer": true, 14 | "Utils": true, 15 | "BackgroundLayer": true, 16 | "Canvas": true, 17 | "Screen": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /boilerplate/module/.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "libs": [ 3 | "browser", 4 | "ecma6", 5 | "underscore", 6 | ".framer" 7 | ], 8 | "plugins": { 9 | "complete_strings": {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /boilerplate/module/Makefile: -------------------------------------------------------------------------------- 1 | start: node_modules 2 | npm start 3 | 4 | node_modules: package.json 5 | npm install 6 | 7 | clean: 8 | rm -rf .bundle.js node_modules 9 | 10 | .PHONY: clean 11 | -------------------------------------------------------------------------------- /boilerplate/module/README.md: -------------------------------------------------------------------------------- 1 | # My Framer.js module 2 | 3 | A quick description of my module. 4 | 5 | ## API 6 | 7 | A quick description of the API. 8 | 9 | ## Development 10 | 11 | If you have `framer-cli` installed, `$ framer preview [path/to/this/module] &` 12 | or `$ cd path/to/this/module && make &`. 13 | -------------------------------------------------------------------------------- /boilerplate/module/index.js: -------------------------------------------------------------------------------- 1 | 2 | var UILabel = require('framer-uilabel') 3 | 4 | module.exports = class RainbowLabel extends UILabel { 5 | constructor(opts={}) { 6 | super(opts); 7 | 8 | this.style.background = `linear-gradient( 9 | to right, 10 | red, 11 | orange, 12 | yellow, 13 | green, 14 | blue, 15 | indigo, 16 | violet 17 | )`; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /boilerplate/module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framer-module", 3 | "version": "0.0.1", 4 | "description": "My Framer.js module.", 5 | "keywords": [ 6 | "prototyping", 7 | "framerjs" 8 | ], 9 | "main": "index.js", 10 | "dependencies": { 11 | "framer-uilabel": "^0.1.0" 12 | }, 13 | "devDependencies": { 14 | "framer-cli": "^0.1.0" 15 | }, 16 | "scripts": { 17 | "start": "framer preview" 18 | }, 19 | "framer": { "type": "module" } 20 | } 21 | -------------------------------------------------------------------------------- /boilerplate/module/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /boilerplate/project/.framer/framer.json: -------------------------------------------------------------------------------- 1 | { 2 | "!name": "framer", 3 | "print": { 4 | "!doc": "Printing allows you to inspect variables on runtime. It works similarly to console.log, only when using print, the output is shown directly within your prototype.", 5 | "!url": "http://framerjs.com/docs/#print", 6 | "!type": "fun(text: string) -> string" 7 | }, 8 | "Framer": { 9 | "Defaults": { 10 | "!doc": "The Framer.Defaults allows you to override the default properties for Layers and Animations when they are created.", 11 | "!url": "http://framerjs.com/docs/#defaults.defaults", 12 | "Animation": { 13 | "curve": "string", 14 | "time": "number" 15 | }, 16 | "Layer": { 17 | "backgroundColor": "string", 18 | "height": "number", 19 | "width": "number" 20 | } 21 | } 22 | }, 23 | "Canvas": { 24 | "!doc": "The Canvas object contains the size for the current entire document in pixels. It will change if you resize your document by resizing the window it is in.", 25 | "!url": "http://framerjs.com/docs/#canvas.canvas", 26 | "width": { 27 | "!doc": "The width of the current entire document in pixels. This property is read-only.", 28 | "!url": "http://framerjs.com/docs/#canvas.width", 29 | "!type": "number" 30 | }, 31 | "height": { 32 | "!doc": "The height of the current entire document in pixels. This property is read-only.", 33 | "!url": "http://framerjs.com/docs/#canvas.height", 34 | "!type": "number" 35 | }, 36 | "size": { 37 | "!doc": "The width and height of the current entire document in pixels. This property is read-only.", 38 | "!url": "http://framerjs.com/docs/#canvas.size", 39 | "width": "Canvas.width", 40 | "height": "Canvas.height" 41 | } 42 | }, 43 | "Screen": { 44 | "!doc": "The Screen object contains the size for the current device screen. The size will change when you update to a different device. If the device is full screen, it will be equal to the Canvas size.", 45 | "!url": "http://framerjs.com/docs/#screen.screen", 46 | "width": { 47 | "!doc": "The width of the current device screen in pixels. This property is read-only.", 48 | "!url": "http://framerjs.com/docs/#screen.width", 49 | "!type": "number" 50 | }, 51 | "height": { 52 | "!doc": "The height of the current device screen in pixels. This property is read-only.", 53 | "!url": "http://framerjs.com/docs/#screen.height", 54 | "!type": "number" 55 | }, 56 | "size": { 57 | "!doc": "The width and height of the current device screen in pixels. This property is read-only.", 58 | "!url": "http://framerjs.com/docs/#screen.size", 59 | "width": "Screen.width", 60 | "height": "Screen.height" 61 | } 62 | }, 63 | "Layer": { 64 | "!doc": "Layers are the basic containers for Framer. They have positioning, size, visual properties and a hierarchy. They can contain images, videos, text or even arbitrary html.", 65 | "!url": "http://framerjs.com/docs/#layer.layer", 66 | "!type": "fn(options: object)", 67 | "prototype": { 68 | "id": { 69 | "!doc": "A unique identification number for this layer. No other layer will have this number. The layer id is read only and cannot be changed.", 70 | "!url": "http://framerjs.com/docs/index.html#layer.id", 71 | "!type": "number" 72 | }, 73 | "name": { 74 | "!doc": "The layer name. This is not set by default but you can set it yourself. Imported layers from Sketch and Photoshop will have the source layer group set.", 75 | "!url": "http://framerjs.com/docs/index.html#layer.name", 76 | "!type": "string" 77 | }, 78 | "x": { 79 | "!doc": "The x property of a layer defines its x position relative to the top left corner.", 80 | "!url": "http://framerjs.com/docs/index.html#layer.x", 81 | "!type": "number" 82 | }, 83 | "y": "number", 84 | "z": "number", 85 | "width": "number", 86 | "height": "number" 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /boilerplate/project/.gitignore: -------------------------------------------------------------------------------- 1 | .bundle.js 2 | framer.js 3 | framer.js.map 4 | node_modules 5 | -------------------------------------------------------------------------------- /boilerplate/project/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "browser": true, 4 | "browserify": true, 5 | "esnext": true, 6 | "forin": true, 7 | "latedef": "nofunc", 8 | "supernew": true, 9 | "unused": true, 10 | 11 | "globals": { 12 | "Framer": true, 13 | "Layer": true, 14 | "Utils": true, 15 | "BackgroundLayer": true, 16 | "Canvas": true, 17 | "Screen": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /boilerplate/project/.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "libs": [ 3 | "browser", 4 | "ecma6", 5 | "underscore", 6 | "framer/framer" 7 | ], 8 | "plugins": { 9 | "complete_strings": {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /boilerplate/project/Makefile: -------------------------------------------------------------------------------- 1 | start: node_modules 2 | npm start 3 | 4 | node_modules: package.json 5 | npm install 6 | 7 | clean: 8 | rm -rf .framer/framer.{js,js.map} .bundle.js node_modules 9 | 10 | .PHONY: clean 11 | -------------------------------------------------------------------------------- /boilerplate/project/README.md: -------------------------------------------------------------------------------- 1 | # My Framer.js project 2 | 3 | A quick description of my project. 4 | 5 | ## For developers 6 | 7 | The idea here is to create self-documenting designs/prototypes, and thus it will 8 | be beneficial to know where to look in the source. 9 | 10 | - `index.html`: open this in your browser to view and interact with the 11 | prototype 12 | - `index.js`: the main project file that holds design/interaction logic 13 | - `/images`: project-specific graphics and assets 14 | - `/modules`: project-specific components and design patterns that have been 15 | abstracted away either to keep `index.js` more readable or because they are 16 | not required for implementation 17 | - `/node_modules`: holds third-party components that may or may not be relevant 18 | for implementation 19 | - `package.json`: required for developing this prototype and lists third-party 20 | module dependencies 21 | - `Makefile`: used for development (assumes [Node][1] is installed) 22 | 23 | [1]: https://nodejs.org/ 24 | -------------------------------------------------------------------------------- /boilerplate/project/images/framer-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peteschaffner/framerjs-cli/9cb27f5112d438d5d5d65371eb90c63a4bd84b66/boilerplate/project/images/framer-icon.png -------------------------------------------------------------------------------- /boilerplate/project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /boilerplate/project/index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Welcome to Framer 4 | * 5 | * Learn how to prototype: 6 | * - http://framerjs.com/learn 7 | * - https://github.com/peteschaffner/framer-cli 8 | */ 9 | 10 | var Device = require('framer-device') 11 | var UIStatusBar = require('framer-uistatusbar') 12 | var myModule = require('myModule') 13 | 14 | new Device({ deviceType: 'iphone-6-silver' }) 15 | new UIStatusBar({ style: 'light' }) 16 | 17 | var background = new BackgroundLayer({ 18 | image: myModule.image 19 | }) 20 | 21 | Utils.labelLayer(background, myModule.data.title) 22 | 23 | var iconLayer = new Layer({ 24 | width: 256/2, 25 | height: 256/2, 26 | image: 'images/framer-icon.png' 27 | }) 28 | iconLayer.center() 29 | 30 | // Define a set of states with names (the original state is 'default') 31 | iconLayer.states.add({ 32 | second: { y: 100, scale: 0.6, rotationZ: 100 }, 33 | third: { y: 300, scale: 1.3, blur: 4 }, 34 | fourth: { y: 200, scale: 0.9, blur: 2, rotationZ: 200 } 35 | }) 36 | 37 | // Set the default animation options 38 | iconLayer.states.animationOptions = { curve: 'spring(500,12,0)' } 39 | 40 | 41 | // On a click, go to the next state 42 | iconLayer.on(Events.Click, () => iconLayer.states.next()) 43 | -------------------------------------------------------------------------------- /boilerplate/project/modules/myModule/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peteschaffner/framerjs-cli/9cb27f5112d438d5d5d65371eb90c63a4bd84b66/boilerplate/project/modules/myModule/background.png -------------------------------------------------------------------------------- /boilerplate/project/modules/myModule/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "My Data" 3 | } 4 | -------------------------------------------------------------------------------- /boilerplate/project/modules/myModule/index.js: -------------------------------------------------------------------------------- 1 | 2 | // Add the following line to your project in Framer Studio. 3 | // myModule = require 'myModule' 4 | // Reference the contents by name, like myModule.myFunction() or myModule.myVar 5 | 6 | exports.data = require('./data.json') 7 | 8 | exports.image = 'background.png' 9 | 10 | exports.myVar = 'myVariable' 11 | 12 | exports.myFunction = () => print('myFunction is running') 13 | 14 | exports.myArray = [1, 2, 3] 15 | -------------------------------------------------------------------------------- /boilerplate/project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framer-project", 3 | "version": "0.0.1", 4 | "description": "My Framer.js project.", 5 | "private": true, 6 | "main": "index.js", 7 | "dependencies": { 8 | "framer-device": "^0.1.0", 9 | "framer-uistatusbar": "^0.1.0" 10 | }, 11 | "devDependencies": { 12 | "framer-cli": "^0.1.0" 13 | }, 14 | "scripts": { 15 | "start": "framer preview" 16 | }, 17 | "framer": { "type": "project" } 18 | } 19 | -------------------------------------------------------------------------------- /lib/framer_test.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | module.exports = function (dir) { 7 | try { 8 | return require(dir + '/package.json').framer.type; 9 | } 10 | catch (err) { 11 | return false; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framer-cli", 3 | "version": "0.2.3", 4 | "description": "A Framer.js CLI for quickly building modular prototypes.", 5 | "author": { 6 | "name": "Pete Schaffner", 7 | "email": "pjschaffner@gmail.com" 8 | }, 9 | "homepage": "https://github.com/peteschaffner/framer-cli", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+ssh://git@github.com/peteschaffner/framer-cli.git" 13 | }, 14 | "keywords": [ 15 | "prototyping", 16 | "framerjs" 17 | ], 18 | "license": "MIT", 19 | "bin": { 20 | "framer": "bin/framer.js" 21 | }, 22 | "dependencies": { 23 | "babelify": "^6.0.2", 24 | "basic-auth": "^1.0.1", 25 | "browserify": "^10.2.0", 26 | "chokidar": "^1.0.1", 27 | "coffeeify": "^1.1.0", 28 | "colors": "^1.1.0", 29 | "commander": "^2.8.1", 30 | "connect": "^3.3.5", 31 | "connect-livereload": "^0.5.3", 32 | "fs-extra": "^0.18.3", 33 | "serve-index": "^1.6.4", 34 | "serve-static": "^1.9.3", 35 | "sync-request": "^2.0.1", 36 | "tiny-lr": "^0.1.5", 37 | "watchify": "^3.2.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peteschaffner/framerjs-cli/9cb27f5112d438d5d5d65371eb90c63a4bd84b66/preview.png --------------------------------------------------------------------------------