├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── example └── src │ ├── .gitignore │ ├── example.js │ ├── example.less │ └── index.html ├── gulpfile.js ├── package.json └── src ├── ReactRegl.js ├── components ├── Rectangle.js ├── Surface.js └── Triangle.js └── renderers └── triangle.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = false 9 | insert_final_newline = true 10 | indent_style = tab 11 | 12 | [*.json] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .publish/* 2 | dist/* 3 | example/dist/* 4 | lib/* 5 | node_modules/* 6 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "plugins": [ 8 | "react" 9 | ], 10 | "rules": { 11 | "curly": [2, "multi-line"], 12 | "quotes": [2, "single", "avoid-escape"], 13 | "react/display-name": 0, 14 | "react/jsx-boolean-value": 1, 15 | "react/jsx-quotes": 1, 16 | "react/jsx-no-undef": 1, 17 | "react/jsx-sort-props": 0, 18 | "react/jsx-sort-prop-types": 1, 19 | "react/jsx-uses-react": 1, 20 | "react/jsx-uses-vars": 1, 21 | "react/no-did-mount-set-state": 1, 22 | "react/no-did-update-set-state": 1, 23 | "react/no-multi-comp": 1, 24 | "react/no-unknown-property": 1, 25 | "react/prop-types": 1, 26 | "react/react-in-jsx-scope": 1, 27 | "react/self-closing-comp": 1, 28 | "react/wrap-multilines": 1, 29 | "semi": 2, 30 | "strict": 0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage tools 11 | lib-cov 12 | coverage 13 | coverage.html 14 | .cover* 15 | 16 | # Dependency directory 17 | node_modules 18 | 19 | # Example build directory 20 | example/dist 21 | .publish 22 | 23 | # Editor and other tmp files 24 | *.swp 25 | *.un~ 26 | *.iml 27 | *.ipr 28 | *.iws 29 | *.sublime-* 30 | .idea/ 31 | *.DS_Store 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Matthew Conlen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Regl 2 | 3 | React bindings to [regl](https://github.com/mikolalysenko/regl) 4 | 5 | ## Demo & Examples 6 | 7 | Live demo: [mathisonian.github.io/react-regl](http://mathisonian.github.io/react-regl/) 8 | 9 | To build the examples locally, run: 10 | 11 | ``` 12 | npm install 13 | npm start 14 | ``` 15 | 16 | Then open [`localhost:8000`](http://localhost:8000) in a browser. 17 | 18 | 19 | ## Installation 20 | 21 | The easiest way to use react-regl is to install it from NPM and include it in your own React build process (using [Browserify](http://browserify.org), [Webpack](http://webpack.github.io/), etc). 22 | 23 | You can also use the standalone build by including `dist/react-regl.js` in your page. If you use this, make sure you have already included React, and it is available as a global variable. 24 | 25 | ``` 26 | npm install react-regl --save 27 | ``` 28 | 29 | 30 | ## Usage 31 | 32 | Example: 33 | 34 | ```js 35 | var React = require('react'); 36 | var ReactDOM = require('react-dom'); 37 | var { Surface, Triangle } = require('react-regl'); 38 | var Victory = require('victory'); 39 | 40 | var App = React.createClass({ 41 | 42 | getInitialState () { 43 | return { 44 | x: 0 45 | } 46 | }, 47 | 48 | toggleState () { 49 | this.setState({ 50 | x: 2 * Math.PI - this.state.x 51 | }) 52 | }, 53 | 54 | componentDidMount () { 55 | this.toggleState(); 56 | }, 57 | 58 | render () { 59 | return ( 60 |
61 | 62 | { 63 | (tweened) => { 64 | return ( 65 | 66 | 69 | 70 | ) 71 | } 72 | } 73 | 74 |
75 | ); 76 | } 77 | }); 78 | 79 | ReactDOM.render(, document.getElementById('app')); 80 | ``` 81 | 82 | ### Properties 83 | 84 | * __DOCUMENT PROPERTIES HERE__ 85 | 86 | ### Notes 87 | 88 | __ADDITIONAL USAGE NOTES__ 89 | 90 | 91 | ## Development (`src`, `lib` and the build process) 92 | 93 | **NOTE:** The source code for the component is in `src`. A transpiled CommonJS version (generated with Babel) is available in `lib` for use with node.js, browserify and webpack. A UMD bundle is also built to `dist`, which can be included without the need for any build system. 94 | 95 | To build, watch and serve the examples (which will also watch the component source), run `npm start`. If you just want to watch changes to `src` and rebuild `lib`, run `npm run watch` (this is useful if you are working with `npm link`). 96 | 97 | ## License 98 | 99 | MIT 100 | 101 | Copyright (c) 2016 Matthew Conlen. 102 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-regl", 3 | "version": "0.0.0", 4 | "description": "React Regl", 5 | "main": "dist/react-regl.min.js", 6 | "homepage": "https://github.com/mathisonian/react-regl", 7 | "authors": [ 8 | "Matthew Conlen" 9 | ], 10 | "moduleType": [ 11 | "amd", 12 | "globals", 13 | "node" 14 | ], 15 | "keywords": [ 16 | "react", 17 | "react-component" 18 | ], 19 | "license": "MIT", 20 | "ignore": [ 21 | ".editorconfig", 22 | ".gitignore", 23 | "package.json", 24 | "src", 25 | "node_modules", 26 | "example", 27 | "test" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /example/src/.gitignore: -------------------------------------------------------------------------------- 1 | ## This file is here to ensure it is included in the gh-pages branch, 2 | ## when `gulp deploy` is used to push updates to the demo site. 3 | 4 | # Dependency directory 5 | node_modules 6 | -------------------------------------------------------------------------------- /example/src/example.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var ReactDOM = require('react-dom'); 3 | var { Surface, Triangle, Rectangle } = require('react-regl'); 4 | var Victory = require('victory'); 5 | 6 | var App = React.createClass({ 7 | 8 | getInitialState () { 9 | return { 10 | x: 0 11 | } 12 | }, 13 | 14 | toggleState () { 15 | this.setState({ 16 | x: 2 * Math.PI - this.state.x 17 | }) 18 | }, 19 | 20 | componentDidMount () { 21 | this.toggleState(); 22 | setInterval(() => { this.toggleState(); }, 500); 23 | }, 24 | 25 | render () { 26 | 27 | var points = []; 28 | for (var i = 0; i < 1000; i ++) { 29 | points.push({ 30 | x: Math.random() * 2 - 1, 31 | y: Math.random() * 2 - 1 32 | }); 33 | } 34 | return ( 35 |
36 | 37 | { 38 | points.map((d, i) => { 39 | return ( 40 | 41 | ); 42 | }) 43 | } 44 | 45 |
46 | ); 47 | } 48 | }); 49 | 50 | ReactDOM.render(, document.getElementById('app')); 51 | -------------------------------------------------------------------------------- /example/src/example.less: -------------------------------------------------------------------------------- 1 | /* 2 | // Examples Stylesheet 3 | // ------------------- 4 | */ 5 | 6 | body { 7 | font-family: Helvetica Neue, Helvetica, Arial, sans-serif; 8 | font-size: 14px; 9 | color: #333; 10 | margin: 0; 11 | padding: 0; 12 | } 13 | 14 | a { 15 | color: #08c; 16 | text-decoration: none; 17 | } 18 | 19 | a:hover { 20 | text-decoration: underline; 21 | } 22 | 23 | .container { 24 | margin-left: auto; 25 | margin-right: auto; 26 | max-width: 720px; 27 | padding: 1em; 28 | } 29 | 30 | .footer { 31 | margin-top: 50px; 32 | border-top: 1px solid #eee; 33 | padding: 20px 0; 34 | font-size: 12px; 35 | color: #999; 36 | } 37 | 38 | h1, h2, h3, h4, h5, h6 { 39 | color: #222; 40 | font-weight: 100; 41 | margin: 0.5em 0; 42 | } 43 | 44 | label { 45 | color: #999; 46 | display: inline-block; 47 | font-size: 0.85em; 48 | font-weight: bold; 49 | margin: 1em 0; 50 | text-transform: uppercase; 51 | } 52 | 53 | .hint { 54 | margin: 15px 0; 55 | font-style: italic; 56 | color: #999; 57 | } 58 | -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Regl 4 | 5 | 6 | 7 |
8 |

React Regl

9 |

View project on GitHub

10 | 11 |
12 |
13 | 14 |
15 | 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var initGulpTasks = require('react-component-gulp-tasks'); 3 | 4 | /** 5 | * Tasks are added by the react-component-gulp-tasks package 6 | * 7 | * See https://github.com/JedWatson/react-component-gulp-tasks 8 | * for documentation. 9 | * 10 | * You can also add your own additional gulp tasks if you like. 11 | */ 12 | 13 | var taskConfig = { 14 | 15 | component: { 16 | name: 'ReactRegl', 17 | dependencies: [ 18 | 'classnames', 19 | 'react', 20 | 'react-dom' 21 | ], 22 | lib: 'lib' 23 | }, 24 | 25 | example: { 26 | src: 'example/src', 27 | dist: 'example/dist', 28 | files: [ 29 | 'index.html', 30 | '.gitignore' 31 | ], 32 | scripts: [ 33 | 'example.js' 34 | ], 35 | less: [ 36 | 'example.less' 37 | ] 38 | } 39 | 40 | }; 41 | 42 | initGulpTasks(gulp, taskConfig); 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-regl", 3 | "version": "1.0.0", 4 | "description": "React Regl", 5 | "main": "lib/ReactRegl.js", 6 | "author": "Matthew Conlen", 7 | "homepage": "https://github.com/mathisonian/react-regl", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/mathisonian/react-regl.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/mathisonian/react-regl/issues" 14 | }, 15 | "dependencies": { 16 | "classnames": "^2.1.2", 17 | "react": "^15.0.2", 18 | "react-dom": "^15.0.2", 19 | "regl": "^0.4.0" 20 | }, 21 | "devDependencies": { 22 | "babel-eslint": "^4.1.3", 23 | "eslint": "^1.6.0", 24 | "eslint-plugin-react": "^3.5.1", 25 | "gulp": "^3.9.0", 26 | "react-component-gulp-tasks": "^0.7.6", 27 | "victory": "^0.7.0" 28 | }, 29 | "peerDependencies": { 30 | "react": "^0.14.0" 31 | }, 32 | "browserify-shim": { 33 | "react": "global:React" 34 | }, 35 | "scripts": { 36 | "build": "gulp clean && NODE_ENV=production gulp build", 37 | "examples": "gulp dev:server", 38 | "lint": "eslint ./; true", 39 | "publish:site": "NODE_ENV=production gulp publish:examples", 40 | "release": "NODE_ENV=production gulp release", 41 | "start": "gulp dev", 42 | "test": "echo \"no tests yet\" && exit 0", 43 | "watch": "gulp watch:lib" 44 | }, 45 | "keywords": [ 46 | "react", 47 | "react-component" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src/ReactRegl.js: -------------------------------------------------------------------------------- 1 | import Surface from './components/Surface'; 2 | import Triangle from './components/Triangle'; 3 | import Rectangle from './components/Rectangle'; 4 | 5 | export { Surface, Triangle, Rectangle }; 6 | -------------------------------------------------------------------------------- /src/components/Rectangle.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | 3 | var Rectangle = React.createClass({ 4 | 5 | getInitialState () { 6 | return { 7 | 8 | }; 9 | }, 10 | 11 | initialize(regl) { 12 | this.setState({ 13 | regl: regl, 14 | renderer: this.props.getRenderer('triangle') 15 | }); 16 | }, 17 | 18 | componentDidMount () { 19 | var regl = this.props.getRegl(); 20 | if (!regl) { 21 | return; 22 | } 23 | 24 | if (!this.state.renderer) { 25 | this.initialize(regl); 26 | } 27 | 28 | this.paint(this.state.renderer); 29 | }, 30 | 31 | componentDidUpdate () { 32 | var regl = this.props.getRegl(); 33 | if (!regl) { 34 | return; 35 | } 36 | if (!this.state.renderer) { 37 | this.initialize(regl); 38 | } 39 | 40 | this.paint(this.state.renderer); 41 | }, 42 | 43 | paint (renderer) { 44 | if (!renderer) { 45 | return; 46 | } 47 | 48 | var x = this.props.x; 49 | var y = this.props.y; 50 | var width = this.props.width; 51 | var height = this.props.height; 52 | 53 | renderer(() => { 54 | var scopedRenderer = this.state.regl({ 55 | uniforms: { 56 | color: this.props.color 57 | } 58 | }); 59 | 60 | scopedRenderer(() => { 61 | var first = this.state.regl({ 62 | attributes: { 63 | position: this.state.regl.buffer([[x, y], [x, y + height], [x + width, y + height]]) 64 | }, 65 | }); 66 | var second = this.state.regl({ 67 | attributes: { 68 | position: this.state.regl.buffer([[x, y], [x + width, y], [x + width, y + height]]) 69 | }, 70 | }); 71 | 72 | first(); 73 | second(); 74 | }); 75 | }); 76 | }, 77 | 78 | render () { 79 | return null; 80 | } 81 | }); 82 | 83 | export default Rectangle; 84 | -------------------------------------------------------------------------------- /src/components/Surface.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var TriangleRenderer = require('../renderers/triangle'); 3 | var renderers = { 4 | triangle: TriangleRenderer 5 | }; 6 | 7 | var Surface = React.createClass({ 8 | 9 | getInitialState () { 10 | return { 11 | rendererCache: {} 12 | }; 13 | }, 14 | 15 | componentDidMount () { 16 | var regl = require('regl')(this.refs.canvas); 17 | this.setState({ 18 | regl: regl 19 | }); 20 | }, 21 | 22 | getRenderer (name) { 23 | if (!this.state.regl) { 24 | return; 25 | } 26 | 27 | if (!this.state.rendererCache[name]) { 28 | this.state.rendererCache[name] = renderers[name](this.state.regl); 29 | } 30 | 31 | return this.state.rendererCache[name]; 32 | }, 33 | 34 | componentDidUpdate: function() { 35 | if (!this.state.regl) { 36 | return; 37 | } 38 | 39 | var children = Object.keys(this.refs).filter(k => k !== 'canvas').map(k => this.refs[k]); 40 | children.forEach((child) => { 41 | child.paint(); 42 | }); 43 | }, 44 | 45 | getRegl () { 46 | return this.state.regl; 47 | }, 48 | 49 | render () { 50 | var regl = this.refs.canvas; 51 | var children = React.Children.map(this.props.children, (child, i) => { 52 | return React.cloneElement(child, { 53 | getRegl: this.getRegl, 54 | getRenderer: this.getRenderer, 55 | ref: 'child' + i 56 | }); 57 | }, this); 58 | 59 | return ( 60 | 61 | {children} 62 | 63 | ); 64 | } 65 | }); 66 | 67 | export default Surface; 68 | -------------------------------------------------------------------------------- /src/components/Triangle.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | 3 | var Triangle = React.createClass({ 4 | 5 | getInitialState () { 6 | return { 7 | 8 | }; 9 | }, 10 | 11 | initialize(regl) { 12 | this.setState({ 13 | regl: regl, 14 | renderer: this.getRenderer(regl) 15 | }); 16 | }, 17 | 18 | componentDidMount () { 19 | var regl = this.props.getRegl(); 20 | if (!regl) { 21 | return; 22 | } 23 | 24 | if (!this.state.renderer) { 25 | this.initialize(regl); 26 | } 27 | 28 | this.paint(this.state.renderer); 29 | }, 30 | 31 | componentDidUpdate () { 32 | var regl = this.props.getRegl(); 33 | if (!regl) { 34 | return; 35 | } 36 | if (!this.state.renderer) { 37 | this.initialize(regl); 38 | } 39 | 40 | this.paint(this.state.renderer); 41 | }, 42 | 43 | getRenderer (regl) { 44 | return regl({ 45 | frag: ` 46 | precision mediump float; 47 | uniform vec4 color; 48 | void main () { 49 | gl_FragColor = color; 50 | } 51 | `, 52 | vert: ` 53 | precision mediump float; 54 | attribute vec2 position; 55 | void main () { 56 | gl_Position = vec4(position.x, position.y, 0, 1); 57 | } 58 | `, 59 | count: 3 60 | }); 61 | }, 62 | 63 | paint (renderer) { 64 | if (!renderer) { 65 | return; 66 | } 67 | 68 | renderer(() => { 69 | var scopedRenderer = this.state.regl({ 70 | attributes: { 71 | position: this.state.regl.buffer(this.props.position) 72 | }, 73 | uniforms: { 74 | color: this.props.color 75 | } 76 | }); 77 | 78 | scopedRenderer(); 79 | }); 80 | }, 81 | 82 | render () { 83 | return null; 84 | } 85 | }); 86 | 87 | export default Triangle; 88 | -------------------------------------------------------------------------------- /src/renderers/triangle.js: -------------------------------------------------------------------------------- 1 | export default (regl) => { 2 | return regl({ 3 | frag: ` 4 | precision mediump float; 5 | uniform vec4 color; 6 | void main () { 7 | gl_FragColor = color; 8 | } 9 | `, 10 | vert: ` 11 | precision mediump float; 12 | attribute vec2 position; 13 | void main () { 14 | gl_Position = vec4(position.x, position.y, 0, 1); 15 | } 16 | `, 17 | count: 3 18 | }); 19 | }; 20 | --------------------------------------------------------------------------------