Merge pull request #281 from gre/upgrades-dec2020

Dec2020 libs upgrade
This commit is contained in:
Gaëtan Renaudeau 2020-12-23 22:30:27 +01:00 committed by GitHub
commit 8590e3cd2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
178 changed files with 12199 additions and 9016 deletions

View File

@ -17,17 +17,17 @@
"publish": "yarn && lerna run clean && yarn build && lerna publish --registry=https://registry.npmjs.org/"
},
"devDependencies": {
"@babel/cli": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"@babel/preset-flow": "^7.8.3",
"@babel/preset-react": "^7.8.3",
"browserify": "^16.5.0",
"@babel/cli": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/preset-env": "^7.12.11",
"@babel/preset-flow": "^7.12.1",
"@babel/preset-react": "^7.12.10",
"browserify": "^17.0.0",
"browserify-shim": "^3.8.12",
"documentation": "12.1.4",
"documentation": "13.1.0",
"flow-copy-source": "^2.0.9",
"lerna": "^3.20.2",
"prettier": "^1.19.1"
"lerna": "^3.22.1",
"prettier": "^2.2.1"
}
}

View File

@ -3,39 +3,41 @@
"version": "4.0.1",
"private": true,
"devDependencies": {
"babel-preset-react-app": "^9.1.0",
"raw-loader": "^3.1.0",
"react-scripts": "3"
"babel-preset-react-app": "^10.0.0",
"browserify": "^17.0.0",
"documentation": "13.1.0",
"raw-loader": "4.0.2",
"react-scripts": "4.0.1"
},
"dependencies": {
"animated": "^0.2.0",
"github-slugger": "^1.2.1",
"github-slugger": "^1.3.0",
"gl-react": "^4.0.1",
"gl-react-dom": "^4.0.1",
"gl-shader": "^4.2.1",
"gl-texture2d": "^2.1.0",
"gl-transitions": "^1.43.0",
"hoist-non-react-statics": "^3.3.1",
"lodash": "^4.17.15",
"hoist-non-react-statics": "^3.3.2",
"lodash": "^4.17.20",
"ndarray": "^1.0.19",
"ndarray-ops": "^1.2.2",
"prism-theme-one-dark": "^1.0.0",
"prismjs": "github:PrismJS/prism#16ce4b336d625e13065bfc12ab6d13ac862d6f50",
"prop-types": "^15.7.2",
"query-string": "^6.10.1",
"query-string": "^6.13.7",
"raf": "^3.4.1",
"react": "^16.12.0",
"react-color": "^2.18.0",
"react-dom": "^16.12.0",
"react": "^17.0.1",
"react-color": "^2.19.3",
"react-dom": "^17.0.1",
"react-gl-transition": "^1.19.2",
"react-json2d": "^0.3.0",
"react-motion": "^0.5.0",
"react-prism": "^4.0.0",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-sidebar": "^3.0.2",
"remark": "^11.0.2",
"remark-react": "^6.0.0"
"remark": "11",
"remark-react": "6"
},
"scripts": {
"start": "react-scripts start",

View File

@ -1,7 +1,8 @@
a {
color: inherit;
}
a:hover, a:focus {
a:hover,
a:focus {
color: inherit;
}
.menu {
@ -40,7 +41,7 @@ a:hover, a:focus {
.App > header {
height: 50px;
display: flex;
flexDirection: row;
flexdirection: row;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #000;
@ -68,13 +69,13 @@ a:hover, a:focus {
white-space: nowrap;
}
.App > header .logo .t1 {
color: #E24;
color: #e24;
}
.App > header .logo .t2 {
color: #000;
}
.App > header .logo .t3 {
color: #E24;
color: #e24;
}
.App > header .logo .v {
font-weight: normal;
@ -108,7 +109,8 @@ a:hover, a:focus {
.App > header select {
margin: 0 20px;
}
a.left, a.right {
a.left,
a.right {
font-size: 1.6em;
padding: 0.6em 0.4em;
background: #fff;
@ -118,7 +120,8 @@ a.left, a.right {
cursor: pointer;
user-select: none;
}
a.left:hover, a.right:hover {
a.left:hover,
a.right:hover {
opacity: 1;
}
a.left {
@ -174,7 +177,6 @@ a.right {
padding: 10px 0;
}
.desc em {
}
.desc pre {
display: inline-block;

View File

@ -16,7 +16,8 @@ import Dashboard from "./Dashboard";
const conf = {
version: process.env.REACT_APP_GL_VERSION,
githubprefix: "https://github.com/gre/gl-react/tree/master/packages/cookbook/"
githubprefix:
"https://github.com/gre/gl-react/tree/master/packages/cookbook/",
};
function triggerLink(linkRef) {
@ -28,7 +29,7 @@ const lenseSidebar = ({ location }) => {
const { menu, inspector } = queryString.parse(location.search);
return {
menu,
inspector
inspector,
};
};
@ -36,7 +37,7 @@ class MenuContext extends PureComponent<*> {
props: {
menu: boolean,
inspector: boolean,
currentExample: ?Object
currentExample: ?Object,
};
render() {
const { menu, inspector } = this.props;
@ -45,12 +46,12 @@ class MenuContext extends PureComponent<*> {
<div>
<h3>{all.length} Examples</h3>
<ul>
{all.map(key => (
{all.map((key) => (
<li key={key}>
<NavLink
to={{
pathname: "/" + key,
search: queryString.stringify({ menu, inspector })
search: queryString.stringify({ menu, inspector }),
}}
activeClassName="active"
className="example-link"
@ -71,7 +72,7 @@ class Header extends Component<*> {
props: {
currentExample: ?Object,
toToggleMenu: Object,
toToggleInspector: Object
toToggleInspector: Object,
};
render() {
const { currentExample, toToggleMenu, toToggleInspector } = this.props;
@ -115,10 +116,7 @@ class Header extends Component<*> {
class App extends Component<*> {
props: {
location: Object
};
static contextTypes = {
router: PropTypes.object.isRequired
location: Object,
};
componentDidMount() {
@ -185,16 +183,16 @@ class App extends Component<*> {
search: queryString.stringify({
...query,
menu: !menuOpened ? true : undefined,
...(!menuOpened ? { inspector: undefined } : null)
})
...(!menuOpened ? { inspector: undefined } : null),
}),
}}
toToggleInspector={{
pathname: location.pathname,
search: queryString.stringify({
...query,
inspector: !inspectorOpened ? true : undefined,
...(!inspectorOpened ? { menu: undefined } : null)
})
...(!inspectorOpened ? { menu: undefined } : null),
}),
}}
/>
@ -204,7 +202,7 @@ class App extends Component<*> {
className="left"
to={{
pathname: prev,
search: queryString.stringify({ menu, inspector })
search: queryString.stringify({ menu, inspector }),
}}
>
@ -217,7 +215,7 @@ class App extends Component<*> {
className="right"
to={{
pathname: next,
search: queryString.stringify({ menu, inspector })
search: queryString.stringify({ menu, inspector }),
}}
>
@ -227,12 +225,12 @@ class App extends Component<*> {
<div className="container">
<Switch>
<Route path="/" exact component={Dashboard} />
{Object.keys(examples).map(key => (
{Object.keys(examples).map((key) => (
<Route
path={"/" + key}
key={key}
isExample
render={props => (
render={(props) => (
<ExamplePage example={examples[key]} {...props} />
)}
/>

View File

@ -2,7 +2,7 @@ pre.cookbook-code a {
color: inherit;
}
pre.cookbook-code .js-template-string-glsl {
background: rgba(0,0,0,0.3);
background: rgba(0, 0, 0, 0.3);
padding: 4px 8px;
display: block;
max-height: 65vh;

View File

@ -19,24 +19,22 @@ Prism.languages.insertBefore("jsx", "string", {
"js-template-string-glsl": {
pattern: /[^`]*/,
inside: {
rest: Prism.languages.glsl
}
}
}
}
rest: Prism.languages.glsl,
},
},
},
},
});
export default class Code extends PureComponent {
props: {
children?: any
children?: any,
};
render() {
const { children } = this.props;
return (
<pre className="cookbook-code">
<PrismCode className="language-jsx">
{children}
</PrismCode>
<PrismCode className="language-jsx">{children}</PrismCode>
</pre>
);
}

View File

@ -30,13 +30,15 @@
flex-direction: column;
position: relative;
}
.dashboard .showcode, .dashboard .showunderthehood {
.dashboard .showcode,
.dashboard .showunderthehood {
opacity: 0.5;
cursor: pointer;
padding: 10px;
font-size: 10px;
}
.dashboard .showcode:hover, .dashboard .showunderthehood:hover {
.dashboard .showcode:hover,
.dashboard .showunderthehood:hover {
opacity: 1;
}
.dashboard .showcode {

View File

@ -20,7 +20,7 @@ void main () {
texture2D(backbuffer, uv),
persistence
).rgb, 1.0);
}`
}`,
},
HelloGL: {
// uniforms are variables from JS. We pipe blue uniform into blue output color
@ -30,7 +30,7 @@ varying vec2 uv;
uniform float red;
void main() {
gl_FragColor = vec4(red, uv.x, uv.y, 1.0);
}`
}`,
},
Rotate: {
frag: GLSL`
@ -45,8 +45,8 @@ void main() {
p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0
? vec4(0.0)
: texture2D(children, p);
}`
}
}`,
},
});
const MotionBlur = ({ children, persistence }) => (
@ -60,7 +60,7 @@ const MotionBlur = ({ children, persistence }) => (
// We can make a <HelloBlue blue={0.5} /> that will render the concrete <Node/>
class HelloGL extends Component {
props: {
red: number
red: number,
};
render() {
const { red } = this.props;
@ -72,7 +72,7 @@ class Rotate extends Component {
props: {
scale: number,
angle: number,
children: any
children: any,
};
render() {
const { angle, scale, children } = this.props;
@ -86,7 +86,7 @@ class Ex1 extends Component {
props: { time: number };
state = {
showCode: false,
showInspector: false
showInspector: false,
};
onShowCode = () => {
this.setState({ showCode: true });

View File

@ -1,6 +1,4 @@
gl-react API documentation
==========================
# gl-react API documentation
`gl-react` is a [React](https://facebook.github.io/react/) library to write and compose WebGL shaders.

View File

@ -12,16 +12,19 @@ import API from "../API.json";
import DocIntroMDBase64 from "../DocIntro.md";
const mdheader = "data:text/x-markdown;base64,";
const DocIntroMD = DocIntroMDBase64.indexOf(mdheader) === 0
? atob(DocIntroMDBase64.slice(mdheader.length))
: "";
const DocIntroMD =
DocIntroMDBase64.indexOf(mdheader) === 0
? atob(DocIntroMDBase64.slice(mdheader.length))
: "";
const paths = {
Component: "https://facebook.github.io/react/docs/react-component.html",
WebGLRenderingContext: "https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14",
WebGLContextAttributes: "https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2"
WebGLRenderingContext:
"https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14",
WebGLContextAttributes:
"https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2",
};
API.forEach(doc => {
API.forEach((doc) => {
paths[doc.name] = "#" + slug(doc.name);
});
@ -69,7 +72,7 @@ function visit(tree, type, visitor, reverse) {
}
function rerouteLinks(ast) {
visit(ast, "link", function(node) {
visit(ast, "link", function (node) {
if (
node.jsdoc &&
!node.url.match(/^(http|https|\.)/) &&
@ -208,7 +211,7 @@ function parameters(section, short) {
.concat(
section.params.map((param, i) => [
i === 0 ? "" : ", ",
parameter(param, short)
parameter(param, short),
])
)
.concat([")"]);
@ -232,7 +235,7 @@ function md(ast, inline) {
) {
ast = {
type: "root",
children: ast.children[0].children.concat(ast.children.slice(1))
children: ast.children[0].children.concat(ast.children.slice(1)),
};
}
if (ast) ast = rerouteLinks(ast);
@ -259,7 +262,9 @@ function signature(section) {
}
function isReactComponent(section) {
return section.augments && section.augments.some(a => a.name === "Component");
return (
section.augments && section.augments.some((a) => a.name === "Component")
);
}
function shortSignature(section) {
@ -267,13 +272,13 @@ function shortSignature(section) {
if (section.kind === "class") {
if (isReactComponent(section)) {
const props = (section.properties || [])
.filter(p => p.type && p.type.type !== "OptionalType")
.map(p => p.name);
.filter((p) => p.type && p.type.type !== "OptionalType")
.map((p) => p.name);
const attrs = props
.filter(name => name !== "children")
.map(name => " " + name + "={..}")
.filter((name) => name !== "children")
.map((name) => " " + name + "={..}")
.join("");
const hasChildren = props.some(name => name === "children");
const hasChildren = props.some((name) => name === "children");
return (
"<" +
section.name +
@ -301,9 +306,7 @@ class DocSectionList extends PureComponent {
{members.map((member, i) => (
<div key={i} className="member" id={member.namespace}>
<div className="member-title">
<code>
.{signature(member)}
</code>
<code>.{signature(member)}</code>
</div>
<DocSection section={member} nested />
</div>
@ -321,41 +324,37 @@ class DocSection extends PureComponent {
id={slug(section.namespace)}
className={"section " + (nested ? "nested" : "")}
>
{!nested || (section.context && section.context.github)
? <div>
{!nested
? <h3>
<a href={"#" + slug(section.namespace)}>{section.name}</a>
{!nested || (section.context && section.context.github) ? (
<div>
{!nested ? (
<h3>
<a href={"#" + slug(section.namespace)}>{section.name}</a>
{section.augments ? (
<span className="augments">
&nbsp;extends&nbsp;
{section.augments
? <span className="augments">
&nbsp;extends&nbsp;
{section.augments
? section.augments.map((tag, i) => (
<span key={i}>
{i === 0 ? "" : ", "}
{autolink(tag.name)}
</span>
))
: null}
</span>
? section.augments.map((tag, i) => (
<span key={i}>
{i === 0 ? "" : ", "}
{autolink(tag.name)}
</span>
))
: null}
</span>
) : null}
{section.context && section.context.github
? <a
className="github-link"
href={section.context.github}
>
{section.context.path}
</a>
: null}
</h3>
: null}
{section.context && section.context.github ? (
<a className="github-link" href={section.context.github}>
{section.context.path}
</a>
) : null}
</h3>
) : null}
{!nested ? highlight(shortSignature(section)) : null}
</div>
: null}
{!nested ? highlight(shortSignature(section)) : null}
</div>
) : null}
{md(section.description)}
@ -365,67 +364,75 @@ class DocSection extends PureComponent {
{section.copyright ? <div>Copyright: {section.copyright}</div> : null}
{section.since ? <div>Since: {section.since}</div> : null}
{section.params
? <div>
<h4>Parameters</h4>
<div>
{section.params.map((param, i) => (
<div key={i}>
<div>
<strong><code>{param.name}</code></strong>&nbsp;
<code className="type">
({formatType(param.type)}
{param.default
? <span>(default <code>{param.default}</code>)</span>
: null}
)
</code>
{md(param.description, true)}
</div>
{section.params ? (
<div>
<h4>Parameters</h4>
<div>
{section.params.map((param, i) => (
<div key={i}>
<div>
<strong>
<code>{param.name}</code>
</strong>
&nbsp;
<code className="type">
({formatType(param.type)}
{param.default ? (
<span>
(default <code>{param.default}</code>)
</span>
) : null}
)
</code>
{md(param.description, true)}
</div>
))}
</div>
</div>
))}
</div>
: null}
</div>
) : null}
{section.properties
? <div>
<h4>
{isReactComponent(section) ? "Props" : "Properties"}
</h4>
<ul className="props">
{section.properties.map((property, i) => (
<li key={i} className="prop">
<strong><code>{property.name}</code></strong>&nbsp;
<code className="type">({formatType(property.type)})</code>
{property.default
? <span>(default <code>{property.default}</code>)</span>
: null}
{property.description
? [": ", md(property.description, true)]
: null}
{property.properties
? <ul>
{property.properties.map((property, i) => (
<li key={i}>
<code>{property.name}</code>
&nbsp;
{formatType(property.type)}
{property.default
? <span>
(default <code>{property.default}</code>)
</span>
: null}
{md(property.description)}
</li>
))}
</ul>
: null}
</li>
))}
</ul>
</div>
: null}
{section.properties ? (
<div>
<h4>{isReactComponent(section) ? "Props" : "Properties"}</h4>
<ul className="props">
{section.properties.map((property, i) => (
<li key={i} className="prop">
<strong>
<code>{property.name}</code>
</strong>
&nbsp;
<code className="type">({formatType(property.type)})</code>
{property.default ? (
<span>
(default <code>{property.default}</code>)
</span>
) : null}
{property.description
? [": ", md(property.description, true)]
: null}
{property.properties ? (
<ul>
{property.properties.map((property, i) => (
<li key={i}>
<code>{property.name}</code>
&nbsp;
{formatType(property.type)}
{property.default ? (
<span>
(default <code>{property.default}</code>)
</span>
) : null}
{md(property.description)}
</li>
))}
</ul>
) : null}
</li>
))}
</ul>
</div>
) : null}
{section.returns
? section.returns.map((ret, i) => (
@ -437,59 +444,59 @@ class DocSection extends PureComponent {
))
: null}
{section.throws
? <div>
<h4>Throws</h4>
<ul>
{section.throws.map((throws, i) => (
<li key={i}>
{formatType(throws.type)}
{": "}
{md(throws.description, true)}
</li>
))}
</ul>
</div>
: null}
{section.examples
? <div>
<h4>Example{section.examples.length > 1 ? "s" : ""}</h4>
{section.examples.map((example, i) => (
<div key={i}>
{example.caption ? <p>{md(example.caption)}</p> : null}
{highlight(example.description)}
</div>
{section.throws ? (
<div>
<h4>Throws</h4>
<ul>
{section.throws.map((throws, i) => (
<li key={i}>
{formatType(throws.type)}
{": "}
{md(throws.description, true)}
</li>
))}
</div>
: null}
</ul>
</div>
) : null}
{section.members.static && section.members.static.length
? <div>
<h4>Static Members</h4>
<DocSectionList
members={section.members.static}
noun="Static Member"
/>
</div>
: null}
{section.examples ? (
<div>
<h4>Example{section.examples.length > 1 ? "s" : ""}</h4>
{section.examples.map((example, i) => (
<div key={i}>
{example.caption ? <p>{md(example.caption)}</p> : null}
{highlight(example.description)}
</div>
))}
</div>
) : null}
{section.members.instance && section.members.instance.length
? <div>
<h4>Instance Members</h4>
<DocSectionList
members={section.members.instance}
noun="Instance Member"
/>
</div>
: null}
{section.members.static && section.members.static.length ? (
<div>
<h4>Static Members</h4>
<DocSectionList
members={section.members.static}
noun="Static Member"
/>
</div>
) : null}
{section.members.events && section.members.events.length
? <div>
<h4>Events</h4>
<DocSectionList members={section.members.events} noun="Event" />
</div>
: null}
{section.members.instance && section.members.instance.length ? (
<div>
<h4>Instance Members</h4>
<DocSectionList
members={section.members.instance}
noun="Instance Member"
/>
</div>
) : null}
{section.members.events && section.members.events.length ? (
<div>
<h4>Events</h4>
<DocSectionList members={section.members.events} noun="Event" />
</div>
) : null}
</section>
);
}
@ -508,9 +515,8 @@ class DocBody extends Component {
<div className="intro" id="summary">
<DocIntro />
</div>
{API.map(
(s, i) =>
s.kind !== "note" ? <DocSection key={i} section={s} /> : null
{API.map((s, i) =>
s.kind !== "note" ? <DocSection key={i} section={s} /> : null
)}
</div>
);
@ -530,21 +536,17 @@ export class DocToc extends Component {
render() {
return (
<div className="documentation-toc">
<a href="#summary">
gl-react
</a>
<a href="#summary">gl-react</a>
<ul>
{API.map((doc, i) => (
<li
key={i}
className={[
"kind-" + doc.kind,
isReactComponent(doc) ? "react-component" : ""
isReactComponent(doc) ? "react-component" : "",
].join(" ")}
>
<a href={"#" + slug(doc.namespace)}>
{doc.name}
</a>
<a href={"#" + slug(doc.namespace)}>{doc.name}</a>
</li>
))}
</ul>

View File

@ -18,13 +18,11 @@
.documentation-toc li {
padding: 0;
overflow: visible;
}
.documentation-toc li a {
padding: 4px 20px;
position: relative;
display: block;
}
.documentation-toc li.react-component a {
color: #f56;
@ -131,7 +129,6 @@ a:hover {
}
.documentation .md {
}
.documentation .md blockquote {

View File

@ -1,9 +1,9 @@
import React, { Component } from "react";
import queryString from "query-string";
const encodeQueryValue = value => JSON.stringify(value);
const decodeQueryValue = value => JSON.parse(value);
const encodeQuery = obj => {
const encodeQueryValue = (value) => JSON.stringify(value);
const decodeQueryValue = (value) => JSON.parse(value);
const encodeQuery = (obj) => {
const values = {};
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
@ -12,7 +12,7 @@ const encodeQuery = obj => {
}
return values;
};
const decodeQuery = query => {
const decodeQuery = (query) => {
query = { ...query };
for (let k in query) {
if (query.hasOwnProperty(k)) {
@ -29,27 +29,29 @@ const decodeQuery = query => {
export default class ExamplePage extends Component {
setToolState = (obj: any) => {
const { location: { pathname, search } } = this.props;
const {
location: { pathname, search },
} = this.props;
this.props.history.replace({
pathname,
search: queryString.stringify({
...queryString.parse(search),
...encodeQuery(obj)
})
...encodeQuery(obj),
}),
});
};
onChangeField = prop => value => this.setToolState({ [prop]: value });
onChangeField = (prop) => (value) => this.setToolState({ [prop]: value });
render() {
const {
example: { toolbox, ToolboxFooter, Example, desc, descAfter },
location: { search }
location: { search },
} = this.props;
const props = {
setToolState: this.setToolState,
...Example.defaultProps,
...decodeQuery(queryString.parse(search))
...decodeQuery(queryString.parse(search)),
};
return (
<div className="example">

View File

@ -9,7 +9,7 @@ export default (
{ refreshRate = 60 }: { refreshRate?: number } = {}
): ReactClass<*> => {
class TL extends PureComponent {
static displayName = `timeLoop(${C.displayName||C.name||""})`;
static displayName = `timeLoop(${C.displayName || C.name || ""})`;
state: { time: number };
state = {
time: 0,
@ -37,10 +37,7 @@ export default (
raf.cancel(this._r);
}
render() {
return <C
{...this.props}
{...this.state}
/>;
return <C {...this.props} {...this.state} />;
}
}

View File

@ -51,7 +51,7 @@
position: relative;
width: 100%;
height: 100%;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AscDA0JcudXmQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABIElEQVR42u3cMQqAQAxE0YkK3v/Ago3gEULIe43lwvLZzqn0Ob/v4/wWd5IcYTUBCAABIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIABmqfx/qbLL5QUg1Xi2fYDe8+0DIAABuAIBIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIACmsQ+wl30A7ANsPt8+AAIQgCsQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJgGvsAe9kHwD7A5vPtAyAAAbgCASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAApql8f4niBWChF2e+DTF+hz42AAAAAElFTkSuQmCC');
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AscDA0JcudXmQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABIElEQVR42u3cMQqAQAxE0YkK3v/Ago3gEULIe43lwvLZzqn0Ob/v4/wWd5IcYTUBCAABIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIABmqfx/qbLL5QUg1Xi2fYDe8+0DIAABuAIBIAAEgAAQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIACmsQ+wl30A7ANsPt8+AAIQgCsQAAJAAAgAASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJgGvsAe9kHwD7A5vPtAyAAAbgCASAABIAAEAACQAAIAAEgAASAABAAAkAACAABIAAEgAAQAAJAAAgAASAApql8f4niBWChF2e+DTF+hz42AAAAAElFTkSuQmCC");
background-size: 64px 64px;
}
@ -65,12 +65,12 @@
}
.gl-react-inspector .box {
position: absolute;;
position: absolute;
display: flex;
flex-direction: column;
width: 180px;
border-radius: 2px;
box-shadow: 0px 0px 3px rgba(0,0,0,0);
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0);
border: 1px solid #eee;
background: #fff;
transition: 0.2s border-color;
@ -156,7 +156,9 @@
.gl-react-inspector .box.minimized .uniform .anchor-hook {
height: 12px;
}
.gl-react-inspector .box.minimized .uniform:not(.type-sampler2D):not(.type-array-sampler2D) {
.gl-react-inspector
.box.minimized
.uniform:not(.type-sampler2D):not(.type-array-sampler2D) {
display: none;
}
@ -197,7 +199,6 @@
text-overflow: ellipsis;
}
.gl-react-inspector .box .anchor-hook {
position: absolute;
left: -2px;
@ -323,7 +324,9 @@
}
.gl-react-inspector .preview canvas {
background: #f3f3f3 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAARklEQVRYw+3XwQkAIAwEwYvYf8uxBcE8fMwWEAbuleruDDd6cOXzAAEBAQEBAQEBAQFf2tM/RJIyMSAgICAgICAgICDgZQeYxgVOKu5KXQAAAABJRU5ErkJggg==) repeat;
background: #f3f3f3
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAARklEQVRYw+3XwQkAIAwEwYvYf8uxBcE8fMwWEAbuleruDDd6cOXzAAEBAQEBAQEBAQFf2tM/RJIyMSAgICAgICAgICDgZQeYxgVOKu5KXQAAAABJRU5ErkJggg==)
repeat;
background-size: 20px 20px;
border: 1px solid #666;
max-width: 100%;

View File

@ -7,7 +7,7 @@ import {
Node,
Bus,
Uniform,
listSurfaces
listSurfaces,
} from "gl-react";
import raf from "raf";
import type { Surface } from "gl-react-dom";
@ -47,10 +47,10 @@ const primitiveTypeAlias = {
bvec4: Array(4).fill("bool"),
mat2: Array(4).fill("float"),
mat3: Array(9).fill("float"),
mat4: Array(16).fill("float")
mat4: Array(16).fill("float"),
};
const classType = type => {
const classType = (type) => {
if (Array.isArray(type)) return "type-array-" + type[0];
return "type-" + type;
};
@ -99,7 +99,7 @@ class PreviewRenderer {
1.0,
-1.0,
1.0,
1.0
1.0,
]),
gl.STATIC_DRAW
);
@ -166,7 +166,7 @@ class UniformValue extends Component {
node: Object,
value: any,
type: any,
info: any
info: any,
};
render() {
let { id, node, value, type, info } = this.props;
@ -200,7 +200,7 @@ class UniformValue extends Component {
class Btn extends Component {
props: {
onClick: ?() => void,
children?: any
children?: any,
};
render() {
const { onClick, children } = this.props;
@ -209,7 +209,7 @@ class Btn extends Component {
className="btn"
onClick={onClick}
style={{
opacity: onClick ? 1 : 0.5
opacity: onClick ? 1 : 0.5,
}}
>
{children}
@ -225,11 +225,11 @@ class Btn extends Component {
class Anchor extends Component {
props: {
id: number,
drawCount: number
drawCount: number,
};
drawHistoryDates: Array<number> = [];
static contextTypes = {
inspector: PropTypes.object.isRequired
inspector: PropTypes.object.isRequired,
};
componentDidMount() {
this.context.inspector.addAnchor(this.props.id, this);
@ -278,10 +278,10 @@ class AnchorHook extends Component {
props: {
id: string,
nodeId: number,
anchorId: number
anchorId: number,
};
static contextTypes = {
inspector: PropTypes.object.isRequired
inspector: PropTypes.object.isRequired,
};
componentDidMount() {
this.context.inspector.addAnchorHook(this.props.anchorId, this);
@ -322,8 +322,8 @@ class MetaInfo extends Component {
obj: ?Object,
initialObj: ?Object,
dependency: ?Object,
textureOptions: ?Object
}
textureOptions: ?Object,
},
};
render() {
const { id, info, node } = this.props;
@ -374,7 +374,7 @@ const sharedRenderer = new PreviewRenderer();
class Preview extends Component {
props: {
capture: Function
capture: Function,
};
interval: number;
canvas: ?HTMLCanvasElement;
@ -395,7 +395,7 @@ class Preview extends Component {
sharedRenderer.copyToCanvas2D(ctx);
}
}, 100);
onCanvasRef = canvas => {
onCanvasRef = (canvas) => {
if (!canvas || this.ctx) return;
const ctx = canvas.getContext("2d");
if ("imageSmoothingEnabled" in ctx) {
@ -421,7 +421,7 @@ class Preview extends Component {
class PreviewNode extends PureComponent {
props: {
node: Object
node: Object,
};
capture = () => {
const { node } = this.props;
@ -436,7 +436,7 @@ class PreviewNode extends PureComponent {
class PreviewContent extends Component {
props: {
content: Object
content: Object,
};
capture = () => {
const { content } = this.props;
@ -449,7 +449,7 @@ class PreviewContent extends Component {
class DrawCount extends PureComponent {
props: {
drawCount: number
drawCount: number,
};
render() {
const { drawCount } = this.props;
@ -472,13 +472,13 @@ class InspectorBox extends Component {
grabbed?: boolean,
minimized: boolean,
onGrabStart: (id: number, e: MouseEvent) => void,
onMinimizeChange: (id: number, minimized: boolean) => void
onMinimizeChange: (id: number, minimized: boolean) => void,
};
static contextTypes = {
inspector: PropTypes.object.isRequired
inspector: PropTypes.object.isRequired,
};
state = {
recentDraw: false
recentDraw: false,
};
lastDrawCountTime: number;
_timeout: number;
@ -515,11 +515,11 @@ class InspectorBox extends Component {
});
}
};
onMouseDown = e => {
onMouseDown = (e) => {
e.preventDefault();
this.props.onGrabStart(this.props.glObject.id, e);
};
onClickMinimize = e => {
onClickMinimize = (e) => {
e.preventDefault();
this.props.onMinimizeChange(this.props.glObject.id, !this.props.minimized);
};
@ -536,7 +536,7 @@ class InspectorBox extends Component {
children,
grabbed,
cls,
minimized
minimized,
} = this.props;
return (
<div
@ -570,7 +570,7 @@ class InspectorBox extends Component {
}
}
const formatType = t => {
const formatType = (t) => {
if (Array.isArray(t)) return t[0] + "[]";
return t;
};
@ -578,14 +578,14 @@ const formatType = t => {
class Uniforms extends PureComponent {
props: {
node: Object,
preparedUniforms: ?Object
preparedUniforms: ?Object,
};
render() {
const { node, preparedUniforms } = this.props;
return (
<div className="uniforms">
{preparedUniforms &&
preparedUniforms.map(u => (
preparedUniforms.map((u) => (
<div key={u.key} className={"uniform " + classType(u.type)}>
<span
className="name"
@ -620,7 +620,7 @@ class SVGConnectionLine extends PureComponent {
anchorY: number,
onPathRef: Function,
reversedHook?: boolean,
recursive?: boolean
recursive?: boolean,
};
render() {
const {
@ -630,7 +630,7 @@ class SVGConnectionLine extends PureComponent {
hookY,
recursive,
onPathRef,
reversedHook
reversedHook,
} = this.props;
const dx = hookX - anchorX;
const dy = hookY - anchorY;
@ -671,10 +671,10 @@ class SVGConnection extends Component {
solid: number,
recursive?: boolean,
reversedHook?: boolean,
animated?: boolean
animated?: boolean,
};
state = {
draws: []
draws: [],
};
path: any;
_raf: any;
@ -694,10 +694,10 @@ class SVGConnection extends Component {
}
const length = path.getTotalLength();
this.setState({
draws: values.map(v => {
draws: values.map((v) => {
const { x, y } = path.getPointAtLength(v * length);
return [x.toFixed(1), y.toFixed(1)]; // round is too aggressive and great jump. but using full float is also more consuming
})
}),
});
};
this._raf = raf(loop);
@ -710,7 +710,7 @@ class SVGConnection extends Component {
componentWillUnmount() {
raf.cancel(this._raf);
}
onPathRef = ref => {
onPathRef = (ref) => {
this.path = ref;
};
render() {
@ -722,7 +722,7 @@ class SVGConnection extends Component {
tension,
solid,
recursive,
reversedHook
reversedHook,
} = this.props;
const { draws } = this.state;
return (
@ -753,7 +753,7 @@ class SVGStandaloneConnection extends Component {
anchorX: number,
anchorY: number,
hookX: number,
hookY: number
hookY: number,
};
render() {
const { animated, anchor, anchorX, anchorY, hookX, hookY } = this.props;
@ -782,7 +782,7 @@ class HookDrawer extends Component {
anchorPositions: *,
anchorHookPositions: *,
boxSizes: *,
grabbing: ?Object
grabbing: ?Object,
};
render() {
const {
@ -792,7 +792,7 @@ class HookDrawer extends Component {
anchorPositions,
anchorHookPositions,
boxSizes,
grabbing
grabbing,
} = this.props;
return (
<svg ref="svg" className="hook-drawer">
@ -817,7 +817,7 @@ class HookDrawer extends Component {
hookY={anchorPosition[1] + size[1] - 22}
/>
) : (
hooks.map(hook => {
hooks.map((hook) => {
const hookId = hook.getId();
const hookNodeId = hook.getNodeId();
const hookIsGrabbed = grabbing && grabbing.id === hookNodeId;
@ -868,10 +868,10 @@ export default class Inspector extends Component {
capture: false,
animated: true,
physics: false,
minimizeAll: false
minimizeAll: false,
};
static childContextTypes = {
inspector: PropTypes.object.isRequired
inspector: PropTypes.object.isRequired,
};
getChildContext() {
return { inspector: this };
@ -900,14 +900,14 @@ export default class Inspector extends Component {
grabbing: ?{
id: number,
initialPos: [number, number],
initialEventPos: [number, number]
initialEventPos: [number, number],
};
componentDidMount() {
Visitors.add(this);
this._startupTimeout = setTimeout(() => this.detectSurface(), 0);
let lastT;
const loop = t => {
const loop = (t) => {
this._raf = raf(loop);
if (!lastT) lastT = t;
const delta = Math.min(100, t - lastT);
@ -978,7 +978,7 @@ export default class Inspector extends Component {
onNodeDrawEnd(node: Node) {
this.nodeDrawCounts.set(node, (this.nodeDrawCounts.get(node) || 0) + 1);
node.dependencies.forEach(obj => {
node.dependencies.forEach((obj) => {
if (obj instanceof Bus) {
this.busDrawCounts.set(obj, (this.busDrawCounts.get(obj) || 0) + 1);
}
@ -1023,7 +1023,7 @@ export default class Inspector extends Component {
const pos = [
// FIXME TMP
60 + 240 * ((i + 1) % 2),
40 + 200 * Math.floor(i / 2)
40 + 200 * Math.floor(i / 2),
];
this.boxPos.set(id, pos);
this.boxMinimized.set(id, this.state.minimizeAll);
@ -1051,7 +1051,7 @@ export default class Inspector extends Component {
anchorHooksByAnchorId,
anchorHookPositions,
boxesById,
boxSizes
boxSizes,
} = this;
// FIXME only the Anchor and AnchorHook should be allow to "sync this"
// as soon as we make this local position, not global...
@ -1065,8 +1065,8 @@ export default class Inspector extends Component {
anchorPositions.set(id, [x, y]);
}
});
anchorHooksByAnchorId.forEach(anchorHooks => {
anchorHooks.forEach(anchorHook => {
anchorHooksByAnchorId.forEach((anchorHooks) => {
anchorHooks.forEach((anchorHook) => {
let [x, y] = anchorHook.getXY();
x = Math.round(x - offX);
y = Math.round(y - offY);
@ -1105,13 +1105,13 @@ export default class Inspector extends Component {
anchorsById,
anchorHooksByAnchorId,
boxPos,
boxSizes
boxSizes,
} = this;
anchorsById.forEach((anchor, anchorId) => {
const hooks = anchorHooksByAnchorId.get(anchorId) || [];
const anchorPos = anchorPositions.get(anchorId);
if (!anchorPos) return;
hooks.forEach(hook => {
hooks.forEach((hook) => {
const hookId = hook.getId();
const hookNodeId = hook.getNodeId();
if (anchorId !== hookNodeId) {
@ -1171,7 +1171,7 @@ export default class Inspector extends Component {
const size = boxSizes.get(id) || [0, 0];
v = [
(v[0] + a[0] * timestep) * damping,
(v[1] + a[1] * timestep) * damping
(v[1] + a[1] * timestep) * damping,
];
p = [p[0] + v[0] * timestep, p[1] + v[1] * timestep];
if (bounds) {
@ -1191,7 +1191,7 @@ export default class Inspector extends Component {
this.spring();
this.updateVelocityPosition(timestep);
var energy = 0.0;
this.boxVel.forEach(v => {
this.boxVel.forEach((v) => {
energy += v[0] * v[0] + v[1] * v[1];
});
if (energy > 0.00001) {
@ -1204,7 +1204,7 @@ export default class Inspector extends Component {
this.grabbing = {
id,
initialPos: boxPos,
initialEventPos: [e.clientX, e.clientY]
initialEventPos: [e.clientX, e.clientY],
};
this.forceUpdate();
};
@ -1334,7 +1334,7 @@ export default class Inspector extends Component {
grabbed: grabbing ? grabbing.id === id : false,
minimized,
onMinimizeChange: this.onMinimizeChange,
onGrabStart: this.onGrabStart
onGrabStart: this.onGrabStart,
};
if (n instanceof Node) {
const [width, height] = n.getGLSize();
@ -1428,7 +1428,7 @@ export default class Inspector extends Component {
<Btn key="ctx" onClick={this.loseContext}>
lose GL context
</Btn>
)
),
];
body = (
<div ref="body" className="body">
@ -1453,7 +1453,7 @@ export default class Inspector extends Component {
<div className="no-surface">
<h2>No Surface is currently inspected. Select one of these:</h2>
<ul>
{listSurfaces().map(surface => (
{listSurfaces().map((surface) => (
<li key={surface.id}>
<span onClick={() => this.setSurface(surface)}>
{surface.getGLName()}
@ -1482,7 +1482,7 @@ export default class Inspector extends Component {
onChange={this.onSelectChange}
>
<option value="">(none)</option>
{listSurfaces().map(surface => (
{listSurfaces().map((surface) => (
<option key={surface.id} value={surface.id}>
{surface.getGLName()}
</option>

View File

@ -4,7 +4,8 @@ import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import Animated from "animated";
const shaders = Shaders.create({
cursor: { frag: GLSL`
cursor: {
frag: GLSL`
precision lowp float; varying vec2 uv; uniform vec2 style;
void main() {
float dist = pow(1.0 - distance(style, uv), 8.0);
@ -12,12 +13,15 @@ void main() {
1.0 * dist + pow(1.0 - distance(style.y, uv.y), 16.0),
0.5 * dist + pow(1.0 - distance(style.y, uv.y), 32.0),
0.2 * dist + pow(1.0 - distance(style.x, uv.x), 32.0)), 1.0);
}` }
}`,
},
});
class Cursor extends Component {
render() {
const { style: { x, y } } = this.props;
return <Node shader={shaders.cursor} uniforms={{ style: [ x, y ] }} />;
const {
style: { x, y },
} = this.props;
return <Node shader={shaders.cursor} uniforms={{ style: [x, y] }} />;
}
}
// using "style" is a hack. see https://github.com/animatedjs/animated/issues/45
@ -25,7 +29,7 @@ const AnimatedCursor = Animated.createAnimatedComponent(Cursor);
export default class Example extends Component {
state = {
style: new Animated.ValueXY({ x: 0.5, y: 0.5 })
style: new Animated.ValueXY({ x: 0.5, y: 0.5 }),
};
onMouseMove = (e: any) => {
const rect = e.target.getBoundingClientRect();
@ -33,7 +37,7 @@ export default class Example extends Component {
toValue: {
x: (e.clientX - rect.left) / rect.width,
y: (rect.bottom - e.clientY) / rect.height,
}
},
}).start();
};
render() {
@ -43,4 +47,4 @@ export default class Example extends Component {
</Surface>
);
}
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -44,4 +44,4 @@ export default class Example extends Component {
);
}
};
`
`;

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ void main() {
color += texture2D(t, uv - (off2 / dim)) * 0.0702702703;
gl_FragColor = color;
}
`
`,
},
game: {
frag: GLSL`
@ -74,7 +74,7 @@ void main() {
)
* mix(1.0, smoothstep(1.0, 0.0, dd), 0.6), 1.0);
}
`
`,
},
glare: {
frag: GLSL`
@ -84,7 +84,7 @@ uniform sampler2D t;
void main() {
gl_FragColor = vec4(step(0.9, texture2D(t, uv).r));
}
`
`,
},
laser: {
frag: GLSL`
@ -102,7 +102,7 @@ void main() {
);
}
`
`,
},
persistence: {
frag: GLSL`
@ -117,7 +117,7 @@ void main() {
texture2D(t, uv).rgb,
1.0);
}
`
`,
},
player: {
frag: GLSL`
@ -208,8 +208,8 @@ void main() {
c *= 1.0 - 1.3 * distance(uv, vec2(0.5));
gl_FragColor = vec4(light * mix(env(), c.rgb, clamp(c.a, 0.0, 1.0)), 1.0);
}
`
}
`,
},
});
const Blur1D = ({ dim, dir, children: t }) => (
@ -234,15 +234,13 @@ export default class Example extends Component {
k: [0, 0],
W: 2,
H: 2,
S: 0
S: 0,
};
const dim = [W, H];
return (
<div style={{ background: "black" }} ref="container">
<Surface width={W} height={H} pixelRatio={1}>
<Bus ref="laser">
<Node
shader={shaders.laser}
@ -285,9 +283,10 @@ export default class Example extends Component {
<Blur1D dim={dim} dir={[1, 0]}>
<Blur1D dim={dim} dir={[-0.5, 0.5]}>
<Blur1D dim={dim} dir={[0.5, 0.5]}>
{() => this.refs.laser
//FIXME this should be glare instead.
//but i think there is a bug in gl-react!
{
() => this.refs.laser
//FIXME this should be glare instead.
//but i think there is a bug in gl-react!
}
</Blur1D>
</Blur1D>
@ -301,7 +300,7 @@ export default class Example extends Component {
backbuffering
uniforms={{
t: this.refs.glareBlurred,
r: Uniform.Backbuffer
r: Uniform.Backbuffer,
}}
/>
</Bus>
@ -316,7 +315,7 @@ export default class Example extends Component {
E: () => this.refs.player,
s,
F,
k
k,
}}
/>
</Surface>
@ -324,9 +323,7 @@ export default class Example extends Component {
<canvas id="c" ref="gameCanvas" hidden={!showCanvas} />
<div style={{ textAlign: "center", padding: 20 }}>
<button onClick={this.sendAsteroid}>
SEND ASTEROID!
</button>
<button onClick={this.sendAsteroid}>SEND ASTEROID!</button>
</div>
</div>
);
@ -345,6 +342,6 @@ export default class Example extends Component {
sendAsteroid = () => window._behindAsteroids_send();
static defaultProps = {
showCanvas: false
showCanvas: false,
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL, Bus, Uniform } from "gl-react";
import { Surface } from "gl-react-dom";
@ -348,4 +348,4 @@ export default class Example extends Component {
showCanvas: false
};
}
`
`;

View File

@ -3,16 +3,25 @@ import React from "react";
export const title = "Behind Asteroids (js13k 2015 greweb)";
export const toolbox = [
{ prop: "showCanvas",
{
prop: "showCanvas",
title: "Under the hood",
Editor:
({ value, onChange }) =>
<div>
<label>
<input type="checkbox" checked={value} onChange={e => onChange(e.target.checked)} />
Show the 2D Canvas rendered by the game
</label>
<p><em>The rest of the rendering is done in WebGL (ported in gl-react).</em></p>
</div>
Editor: ({ value, onChange }) => (
<div>
<label>
<input
type="checkbox"
checked={value}
onChange={(e) => onChange(e.target.checked)}
/>
Show the 2D Canvas rendered by the game
</label>
<p>
<em>
The rest of the rendering is done in WebGL (ported in gl-react).
</em>
</p>
</div>
),
},
];

View File

@ -5,12 +5,13 @@ import { Surface } from "gl-react-dom";
import { BlurXY } from "../blurxy";
import { images } from "./meta";
import timeLoop from "../../HOC/timeLoop";
import image from "./1.jpg";
const ContinuousBlur = timeLoop(BlurXY);
export default class Example extends Component {
state = {
buffering: false
buffering: false,
};
componentWillReceiveProps({ image, refreshId }: *) {
if (image !== this.props.image || refreshId !== this.props.refreshId) {
@ -43,8 +44,8 @@ export default class Example extends Component {
);
}
static defaultProps = {
image: require("./1.jpg"),
image,
factor: 0,
refreshId: 0
refreshId: 0,
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { NearestCopy, LinearCopy, Uniform } from "gl-react";
import { Surface } from "gl-react-dom";
@ -48,4 +48,4 @@ export default class Example extends Component {
refreshId: 0
};
}
`
`;

View File

@ -4,16 +4,16 @@ import ImagesPicker from "../../toolbox/ImagesPicker";
import makeFloatSlider from "../../toolbox/makeFloatSlider";
export const images = [
require("./1.jpg"),
require("./2.jpg"),
require("./3.jpg")
require("./1.jpg").default,
require("./2.jpg").default,
require("./3.jpg").default,
];
export const toolbox = [
{
prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2)
Editor: makeFloatSlider(0, 8, 0.2),
},
{
prop: "image",
@ -21,19 +21,20 @@ export const toolbox = [
Editor: ImagesPicker,
style: { width: 400 },
imageStyle: { maxWidth: 56, maxHeight: 56, marginBottom: 16 },
images
images,
},
{
prop: "refreshId",
title: "",
Editor: ({ onChange, value }) =>
Editor: ({ onChange, value }) => (
<button
style={{ fontSize: "1.4em", lineHeight: "1.4em" }}
onClick={() => onChange(value + 1)}
>
REFRESH
</button>
}
),
},
];
export const title = "Blur feedback";

View File

@ -30,7 +30,7 @@ void main() {
), 1.0);
float isText = 1.0 - texture2D(title, uv).r;
gl_FragColor = mix(bgColor, textColor, isText);
}`
}`,
},
TitleBlurMap: {
frag: GLSL`
@ -42,8 +42,8 @@ void main() {
gl_FragColor = vec4(
vec3(smoothstep(1.0, threshold, texture2D(t, uv).r)),
1.0);
}`
}
}`,
},
});
const AveragePixels = ({ children, quality }) => (
@ -68,7 +68,7 @@ const TitleBlurMap = ({ children: title, threshold }) => (
<Blur factor={4} passes={4} width={200} height={200}>
{title}
</Blur>
)
),
}}
width={64}
height={64}
@ -89,10 +89,10 @@ class Title extends PureComponent {
font: "bold 78px Didot,Georgia,serif",
fillStyle: "#000",
textBaseline: "top",
textAlign: "center"
textAlign: "center",
},
["fillText", children, width / 2, 10, 84]
]
["fillText", children, width / 2, 10, 84],
],
}}
</JSON2D>
</LinearCopy>
@ -106,7 +106,7 @@ class ImageTitleC extends Component {
height: PropTypes.number.isRequired,
children: PropTypes.any.isRequired,
text: PropTypes.string.isRequired,
colorThreshold: PropTypes.number.isRequired
colorThreshold: PropTypes.number.isRequired,
};
render() {
const { width, height, children: img, text, colorThreshold } = this.props;
@ -119,10 +119,9 @@ class ImageTitleC extends Component {
imgBlurred: () => this.refs.imgBlurred,
title: () => this.refs.title,
imgTone: () => this.refs.imgTone,
blurMap: () => this.refs.blurMap
blurMap: () => this.refs.blurMap,
}}
>
<Bus ref="title">
<Title width={width} height={height}>
{text}
@ -130,15 +129,11 @@ class ImageTitleC extends Component {
</Bus>
<Bus ref="blurMap">
<TitleBlurMap threshold={0.7}>
{() => this.refs.title}
</TitleBlurMap>
<TitleBlurMap threshold={0.7}>{() => this.refs.title}</TitleBlurMap>
</Bus>
<Bus ref="imgTone">
<AveragePixels quality={8}>
{img}
</AveragePixels>
<AveragePixels quality={8}>{img}</AveragePixels>
</Bus>
<Bus ref="imgBlurred">
@ -146,7 +141,6 @@ class ImageTitleC extends Component {
{img}
</BlurV>
</Bus>
</Node>
);
}
@ -168,6 +162,6 @@ export default class Example extends Component {
static defaultProps = {
title: "Hello\nSan Francisco\n☻",
colorThreshold: 0.6,
image: require("./sf-6.jpg")
image: require("./sf-6.jpg").default,
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { PureComponent, Component } from "react";
import PropTypes from "prop-types";
import { Shaders, Node, GLSL, Bus, LinearCopy, connectSize } from "gl-react";
@ -171,4 +171,4 @@ export default class Example extends Component {
image: require("./sf-6.jpg")
};
}
`
`;

View File

@ -5,7 +5,8 @@ import makeFloatSlider from "../../toolbox/makeFloatSlider";
export const title = "Dynamic Blur Image Title";
export const toolbox = [
{ prop: "title",
{
prop: "title",
title: "Title",
Editor: makeTextArea({
height: 140,
@ -15,22 +16,27 @@ export const toolbox = [
lineHeight: "42px",
fontWeight: "bold",
textAlign: "center",
}) },
{ prop: "colorThreshold",
}),
},
{
prop: "colorThreshold",
title: "Color Threshold",
Editor: makeFloatSlider(0, 1, 0.01) }, // FIXME black <-> white
{ prop: "image",
Editor: makeFloatSlider(0, 1, 0.01),
}, // FIXME black <-> white
{
prop: "image",
title: "Image",
Editor: ImagesPicker,
style: { width: 400 },
imageStyle: { maxWidth: 56, maxHeight: 56, marginBottom: 16, },
imageStyle: { maxWidth: 56, maxHeight: 56, marginBottom: 16 },
images: [
require("./sf-1.jpg"),
require("./sf-2.jpg"),
require("./sf-3.jpg"),
require("./sf-4.jpg"),
require("./sf-5.jpg"),
require("./sf-6.jpg"),
require("./sf-7.jpg"),
] },
require("./sf-1.jpg").default,
require("./sf-2.jpg").default,
require("./sf-3.jpg").default,
require("./sf-4.jpg").default,
require("./sf-5.jpg").default,
require("./sf-6.jpg").default,
require("./sf-7.jpg").default,
],
},
];

View File

@ -24,8 +24,8 @@ vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
}
void main() {
gl_FragColor = blur9(t, uv, resolution, direction * texture2D(map, uv).rg);
}`
}
}`,
},
});
// Same concept than Blur1D except it takes one more prop:
@ -41,12 +41,14 @@ export const BlurV1D = connectSize(
// And its N-pass version
export const BlurV = connectSize(({ children, factor, map, passes }) => {
const rec = pass =>
pass <= 0
? children
: <BlurV1D map={map} direction={directionForPass(pass, factor, passes)}>
{rec(pass - 1)}
</BlurV1D>;
const rec = (pass) =>
pass <= 0 ? (
children
) : (
<BlurV1D map={map} direction={directionForPass(pass, factor, passes)}>
{rec(pass - 1)}
</BlurV1D>
);
return rec(passes);
});
@ -64,6 +66,6 @@ export default class Example extends Component {
static defaultProps = {
factor: 2,
passes: 4,
map: StaticBlurMap.images[0]
map: StaticBlurMap.images[0],
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL, connectSize } from "gl-react";
import { Surface } from "gl-react-dom";
@ -67,4 +67,4 @@ export default class Example extends Component {
map: StaticBlurMap.images[0]
};
}
`
`;

View File

@ -9,13 +9,11 @@ export const descAfter = markdown`
We use a texture to map the depth of the Blur.
`;
export const toolbox = [
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2) },
{ prop: "passes",
title: value => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1) },
{ prop: "map",
title: "Blur Texture Map",
Editor: StaticBlurMap },
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0, 8, 0.2) },
{
prop: "passes",
title: (value) => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1),
},
{ prop: "map", title: "Blur Texture Map", Editor: StaticBlurMap },
];

View File

@ -2,7 +2,7 @@
import React, { Component } from "react";
import { Shaders, Node, Bus, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import {BlurV} from "../blurmap";
import { BlurV } from "../blurmap";
import timeLoop from "../../HOC/timeLoop";
const shaders = Shaders.create({
@ -15,14 +15,13 @@ void main () {
gl_FragColor = vec4(vec3(
mod(phase + atan(uv.x-0.5, uv.y-0.5)/(2.0*PI), 1.0)
), 1.0);
}` }
}`,
},
});
const ConicalGradiantLoop = timeLoop(({ time }) =>
<Node
shader={shaders.ConicalGradiant}
uniforms={{ phase: time/3000 }}
/>);
const ConicalGradiantLoop = timeLoop(({ time }) => (
<Node shader={shaders.ConicalGradiant} uniforms={{ phase: time / 3000 }} />
));
export default class Example extends Component {
render() {
@ -43,4 +42,4 @@ export default class Example extends Component {
factor: 6,
passes: 4,
};
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, Bus, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -44,4 +44,4 @@ export default class Example extends Component {
passes: 4,
};
};
`
`;

View File

@ -5,10 +5,10 @@ export const desc = markdown`
Any arbitrary shader can be used as a blur map!
`;
export const toolbox = [
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2) },
{ prop: "passes",
title: value => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1) },
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0, 8, 0.2) },
{
prop: "passes",
title: (value) => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1),
},
];

View File

@ -13,8 +13,8 @@ uniform sampler2D t;
uniform vec2 offset;
void main () {
gl_FragColor = texture2D(t, uv + offset);
}`
}
}`,
},
});
const Offset = ({ t, offset }) => (
@ -23,7 +23,7 @@ const Offset = ({ t, offset }) => (
export default class Example extends Component {
state = {
offset: [0, 0]
offset: [0, 0],
};
render() {
const { map } = this.props;
@ -55,12 +55,12 @@ export default class Example extends Component {
this.setState({
offset: [
-(e.clientX - rect.left - rect.width / 2) / rect.width,
(e.clientY - rect.top - rect.height / 2) / rect.height
]
(e.clientY - rect.top - rect.height / 2) / rect.height,
],
});
};
onMouseLeave = () => this.setState({ offset: [0, 0] });
static defaultProps = {
map: StaticBlurMap.images[0]
map: StaticBlurMap.images[0],
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, Bus, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -64,4 +64,4 @@ export default class Example extends Component {
map: StaticBlurMap.images[0]
};
}
`
`;

View File

@ -10,7 +10,5 @@ We want the "offset" framebuffer to be computed once,
we use gl-react [\`<Bus>\`](/api#bus) concept for this.
`;
export const toolbox = [
{ prop: "map",
title: "Blur Texture Map",
Editor: StaticBlurMap },
{ prop: "map", title: "Blur Texture Map", Editor: StaticBlurMap },
];

View File

@ -5,25 +5,34 @@ import { Surface } from "gl-react-dom";
import { Blur1D } from "../blurxy";
// empirical strategy to chose a 2d vector for a blur pass
const NORM = Math.sqrt(2)/2;
const NORM = Math.sqrt(2) / 2;
export const directionForPass = (p: number, factor: number, total: number) => {
const f = factor * 2 * Math.ceil(p / 2) / total;
switch ((p-1) % 4) { // alternate horizontal, vertical and 2 diagonals
case 0: return [f,0];
case 1: return [0,f];
case 2: return [f*NORM,f*NORM];
default: return [f*NORM,-f*NORM];
const f = (factor * 2 * Math.ceil(p / 2)) / total;
switch (
(p - 1) %
4 // alternate horizontal, vertical and 2 diagonals
) {
case 0:
return [f, 0];
case 1:
return [0, f];
case 2:
return [f * NORM, f * NORM];
default:
return [f * NORM, -f * NORM];
}
}
};
// recursively apply Blur1D to make a multi pass Blur component
export const Blur = connectSize(({ children, factor, passes }) => {
const rec = pass =>
pass <= 0
? children
: <Blur1D direction={directionForPass(pass, factor, passes)}>
{rec(pass-1)}
</Blur1D>;
const rec = (pass) =>
pass <= 0 ? (
children
) : (
<Blur1D direction={directionForPass(pass, factor, passes)}>
{rec(pass - 1)}
</Blur1D>
);
return rec(passes);
});

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { connectSize } from "gl-react";
import { Surface } from "gl-react-dom";
@ -43,4 +43,4 @@ export default class Example extends Component {
passes: 4,
};
}
`
`;

View File

@ -13,10 +13,10 @@ We also vary the intensity for each pass.
`;
export const toolbox = [
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2) },
{ prop: "passes",
title: passes => `Blur Passes (${passes})`,
Editor: makeFloatSlider(0, 8, 1) },
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0, 8, 0.2) },
{
prop: "passes",
title: (passes) => `Blur Passes (${passes})`,
Editor: makeFloatSlider(0, 8, 1),
},
];

View File

@ -20,7 +20,7 @@ export default class Example extends Component {
contrast,
saturation,
brightness,
map
map,
} = this.props;
return (
<Surface width={480} height={360} pixelRatio={1}>
@ -30,7 +30,7 @@ export default class Example extends Component {
saturation={saturation}
brightness={brightness}
>
{redraw => (
{(redraw) => (
<Video onFrame={redraw} autoPlay loop>
<source type="video/mp4" src={videoMP4} />
</Video>
@ -38,8 +38,10 @@ export default class Example extends Component {
</Saturate>
</Bus>
<BlurV map={map} passes={passes} factor={factor}>
{// as a texture, we give a function that resolve the video ref
() => this.refs.vid}
{
// as a texture, we give a function that resolve the video ref
() => this.refs.vid
}
</BlurV>
</Surface>
);
@ -51,6 +53,6 @@ export default class Example extends Component {
brightness: 1,
factor: 2,
passes: 4,
map: StaticBlurMap.images[0]
map: StaticBlurMap.images[0],
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Bus } from "gl-react";
import { Surface } from "gl-react-dom";
@ -54,4 +54,4 @@ export default class Example extends Component {
map: StaticBlurMap.images[0]
};
}
`
`;

View File

@ -2,23 +2,23 @@ import makeFloatSlider from "../../toolbox/makeFloatSlider";
import StaticBlurMap from "../../toolbox/StaticBlurMap";
export const toolbox = [
{ prop: "contrast",
title: "Contrast",
Editor: makeFloatSlider(0, 2, 0.05) },
{ prop: "saturation",
{ prop: "contrast", title: "Contrast", Editor: makeFloatSlider(0, 2, 0.05) },
{
prop: "saturation",
title: "Saturation",
Editor: makeFloatSlider(0, 2, 0.05) },
{ prop: "brightness",
Editor: makeFloatSlider(0, 2, 0.05),
},
{
prop: "brightness",
title: "Brightness",
Editor: makeFloatSlider(0, 2, 0.05) },
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2) },
{ prop: "passes",
title: value => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1) },
{ prop: "map",
title: "Blur Texture Map",
Editor: StaticBlurMap },
Editor: makeFloatSlider(0, 2, 0.05),
},
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0, 8, 0.2) },
{
prop: "passes",
title: (value) => `Blur Passes (${value})`,
Editor: makeFloatSlider(1, 8, 1),
},
{ prop: "map", title: "Blur Texture Map", Editor: StaticBlurMap },
];
export const title = "Video + multi-pass Blur + contrast/saturation/brightness";

View File

@ -1,11 +1,12 @@
//@flow
import React, { Component } from "react";
import {Shaders, Node, GLSL, connectSize} from "gl-react";
import { Shaders, Node, GLSL, connectSize } from "gl-react";
import { Surface } from "gl-react-dom";
const shaders = Shaders.create({
blur1D: { // blur9: from https://github.com/Jam3/glsl-fast-gaussian-blur
frag: GLSL`
blur1D: {
// blur9: from https://github.com/Jam3/glsl-fast-gaussian-blur
frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
@ -23,35 +24,34 @@ vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
}
void main() {
gl_FragColor = blur9(t, uv, resolution, direction);
}` }
}`,
},
});
// This implements a blur on a single direction (x or y axis for instance)
// connectSize will inject for us the width/height from context if not provided
export const Blur1D =
connectSize(({ children: t, direction, width, height }) =>
export const Blur1D = connectSize(
({ children: t, direction, width, height }) => (
<Node
shader={shaders.blur1D}
uniforms={{ t, resolution: [ width, height ], direction }}
/>);
uniforms={{ t, resolution: [width, height], direction }}
/>
)
);
// BlurXY is a basic blur that apply Blur1D on Y and then on X
export const BlurXY =
connectSize(({ factor, children }) =>
<Blur1D direction={[ factor, 0 ]}>
<Blur1D direction={[ 0, factor ]}>
{children}
</Blur1D>
</Blur1D>);
export const BlurXY = connectSize(({ factor, children }) => (
<Blur1D direction={[factor, 0]}>
<Blur1D direction={[0, factor]}>{children}</Blur1D>
</Blur1D>
));
export default class Example extends Component {
render() {
const { factor } = this.props;
return (
<Surface width={400} height={300}>
<BlurXY factor={factor}>
https://i.imgur.com/iPKTONG.jpg
</BlurXY>
<BlurXY factor={factor}>https://i.imgur.com/iPKTONG.jpg</BlurXY>
</Surface>
);
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import {Shaders, Node, GLSL, connectSize} from "gl-react";
import { Surface } from "gl-react-dom";
@ -59,4 +59,4 @@ export default class Example extends Component {
factor: 1,
};
}
`
`;

View File

@ -5,7 +5,7 @@ export const title = "simple Blur (2-passes)";
export const desc = markdown`
Implementing Blur efficiently isn't trivial.
This approach do 2 passes *(X and Y)*
This approach do 2 passes _(X and Y)_
`;
export const descAfter = markdown`
We apply a linear blur (9 gaussian lookup)
@ -16,7 +16,5 @@ We can see the blur quality isn't perfect,
`;
export const toolbox = [
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0, 8, 0.2) },
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0, 8, 0.2) },
];

View File

@ -1,8 +1,8 @@
//@flow
import React, { Component } from "react";
import {LinearCopy} from "gl-react";
import { LinearCopy } from "gl-react";
import { Surface } from "gl-react-dom";
import {BlurXY} from "../blurxy";
import { BlurXY } from "../blurxy";
export default class Example extends Component {
render() {
@ -15,7 +15,7 @@ export default class Example extends Component {
</BlurXY>
</LinearCopy>
</Surface>
// we have to wrap this in a <LinearCopy> so it upscales to the Surface size.
// we have to wrap this in a <LinearCopy> so it upscales to the Surface size.
);
}
static defaultProps = {

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import {LinearCopy} from "gl-react";
import { Surface } from "gl-react-dom";
@ -22,4 +22,4 @@ export default class Example extends Component {
factor: 0.5,
};
}
`
`;

View File

@ -3,7 +3,8 @@ import makeFloatSlider from "../../toolbox/makeFloatSlider";
export const title = "simple Blur + downscale";
export const desc = markdown`
[BlurXY](/blurxy) allows to override width/height (\`connectSize\`),
we can downscale the Blur to accentuate the Blur effect.`;
we can downscale the Blur to accentuate the Blur effect.
`;
export const descAfter = markdown`
It also bring better performance (less pixels to process).
But it's still a quality tradeoff and a balance to found.
@ -12,7 +13,5 @@ But it's still a quality tradeoff and a balance to found.
`;
export const toolbox = [
{ prop: "factor",
title: "Blur",
Editor: makeFloatSlider(0.2, 0.8, 0.02) },
{ prop: "factor", title: "Blur", Editor: makeFloatSlider(0.2, 0.8, 0.02) },
];

View File

@ -15,7 +15,8 @@ void main() {
vec4(0.0),
step(1.0, d)
);
}` }
}`,
},
});
class ColoredDisc extends Component {
@ -23,10 +24,7 @@ class ColoredDisc extends Component {
// fromColor/toColor must be array of 3 numbers because defined as vec3 type.
const { fromColor, toColor } = this.props;
return (
<Node
shader={shaders.ColoredDisc}
uniforms={{ fromColor, toColor }}
/>
<Node shader={shaders.ColoredDisc} uniforms={{ fromColor, toColor }} />
);
}
}
@ -41,7 +39,7 @@ export default class Example extends Component {
);
}
static defaultProps = {
fromColor: [ 1, 0, 1 ],
toColor: [ 1, 1, 0 ],
fromColor: [1, 0, 1],
toColor: [1, 1, 0],
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -45,4 +45,4 @@ export default class Example extends Component {
toColor: [ 1, 1, 0 ],
};
}
`
`;

View File

@ -2,12 +2,14 @@ import Vec3ColorPicker from "../../toolbox/Vec3ColorPicker";
import markdown from "../../markdown";
export const toolbox = [
{ prop: "fromColor", title: "fromColor", Editor: Vec3ColorPicker },
{ prop: "toColor", title: "toColor", Editor: Vec3ColorPicker },
{ prop: "toColor", title: "toColor", Editor: Vec3ColorPicker },
];
export const title = "Colored Disc {fromColor, toColor} uniforms";
export const desc = markdown`Implement a simple radial gradient.`;
export const desc = markdown`
Implement a simple radial gradient.
`;
export const descAfter = markdown`
Learn more GLSL built-in functions:

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,8 @@
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import colorScales from "./colorScales"; export {colorScales};
import colorScales from "./colorScales";
export { colorScales };
const shaders = Shaders.create({
colorify: {
@ -15,26 +16,27 @@ void main() {
vec4 original = texture2D(children, uv);
vec4 newcolor = texture2D(colorScale, vec2(greyscale(original.rgb), 0.5));
gl_FragColor = vec4(newcolor.rgb, original.a * newcolor.a);
}` }
}`,
},
});
export const Colorify =
({ children, colorScale, interpolation }) =>
export const Colorify = ({ children, colorScale, interpolation }) => (
<Node
shader={shaders.colorify}
uniformsOptions={{ colorScale: { interpolation } }}
uniforms={{ colorScale, children }}
/>;
/>
);
export default class Example extends Component {
render() {
const { interpolation, color } = this.props;
return (
<Surface width={400} height={300}>
<Colorify colorScale={colorScales[color]} interpolation={interpolation}>
https://i.imgur.com/iPKTONG.jpg
</Colorify>
</Surface>
<Surface width={400} height={300}>
<Colorify colorScale={colorScales[color]} interpolation={interpolation}>
https://i.imgur.com/iPKTONG.jpg
</Colorify>
</Surface>
);
}
static defaultProps = {

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -42,4 +42,4 @@ export default class Example extends Component {
color: Object.keys(colorScales)[0],
};
}
`
`;

View File

@ -13,20 +13,28 @@ of the image greyscale.
`;
export const toolbox = [
{ prop: "color",
{
prop: "color",
title: "color scale",
Editor: makeSelect(Object.keys(colorScales).map(cs =>
({ key: cs, label: cs }))) },
{ prop: "interpolation",
Editor: makeSelect(
Object.keys(colorScales).map((cs) => ({ key: cs, label: cs }))
),
},
{
prop: "interpolation",
Editor: makeRadios([
{ key: "linear", label: "linear interpolation" },
{ key: "nearest", label: "nearest interpolation" },
]) }
]),
},
];
export const ToolboxFooter = ({ color, interpolation }) =>
export const ToolboxFooter = ({ color, interpolation }) => (
<Surface style={{ minWidth: "100%" }} width={400} height={20}>
{ interpolation==="linear"
? <LinearCopy>{colorScales[color]}</LinearCopy>
: <NearestCopy>{colorScales[color]}</NearestCopy> }
</Surface>;
{interpolation === "linear" ? (
<LinearCopy>{colorScales[color]}</LinearCopy>
) : (
<NearestCopy>{colorScales[color]}</NearestCopy>
)}
</Surface>
);

View File

@ -7,7 +7,7 @@ import shadertoyTex17jpg from "./shadertoy-tex17.jpg";
const shaders = Shaders.create({
desertPassage: {
// from https://www.shadertoy.com/view/XtyGzc
// from https://www.shadertoy.com/view/XtyGzc
frag: GLSL`
precision mediump float;
varying vec2 uv;
@ -206,10 +206,11 @@ void main() {
u = uv;
col = min(col, 1.)*pow( 16.0*u.x*u.y*(1.0-u.x)*(1.0-u.y) , .125);
gl_FragColor = vec4(sqrt(clamp(col, 0., 1.)), 1);
}` }
}`,
},
});
const DesertPassage = ({ time }) =>
const DesertPassage = ({ time }) => (
<Node
shader={shaders.desertPassage}
uniforms={{
@ -217,10 +218,12 @@ const DesertPassage = ({ time }) =>
iChannel0: shadertoyTex17jpg,
}}
/>
);
export const DesertPassageLoop = timeLoop(DesertPassage, { frameRate: 30 });
export default() =>
export default () => (
<Surface width={400} height={400}>
<DesertPassageLoop />
</Surface>
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -224,4 +224,4 @@ export default() =>
<Surface width={400} height={400}>
<DesertPassageLoop />
</Surface>
`
`;

View File

@ -1,13 +1,13 @@
//@flow
import React, { Component, PureComponent } from "react";
import {Shaders, Node, GLSL, Bus, connectSize} from "gl-react";
import { Shaders, Node, GLSL, Bus, connectSize } from "gl-react";
import { Surface } from "gl-react-dom";
import {DesertPassageLoop} from "../demodesert";
import { DesertPassageLoop } from "../demodesert";
import "./index.css";
const shaders = Shaders.create({
crt: {
// adapted from http://bit.ly/2eR1iKi
// adapted from http://bit.ly/2eR1iKi
frag: GLSL`
precision highp float;
varying vec2 uv;
@ -58,16 +58,17 @@ void main()
mul_res *= dotMaskWeights;
mul_res = pow(mul_res, vec3(1.0 / (2.0 * inputGamma - outputGamma)));
gl_FragColor = vec4(mul_res, 1.0);
}` },
copy: {
frag: GLSL`
}`,
},
copy: {
frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
void main(){
gl_FragColor=texture2D(t,uv);
}`,
}
},
});
class CRT extends Component {
@ -80,16 +81,18 @@ class CRT extends Component {
};
render() {
const { children, inSize, outSize, texSize, distortion } = this.props;
return <Node
shader={shaders.crt}
uniforms={{
rubyTexture: children,
rubyInputSize: inSize,
rubyOutputSize: outSize,
rubyTextureSize: texSize,
distortion,
}}
/>;
return (
<Node
shader={shaders.crt}
uniforms={{
rubyTexture: children,
rubyInputSize: inSize,
rubyOutputSize: outSize,
rubyTextureSize: texSize,
distortion,
}}
/>
);
}
}
@ -97,10 +100,12 @@ const Desert = connectSize(DesertPassageLoop);
class ShowCaptured extends PureComponent {
render() {
const {t} = this.props;
return <Surface width={200} height={200}>
<Node shader={shaders.copy} uniforms={{ t }} />
</Surface>;
const { t } = this.props;
return (
<Surface width={200} height={200}>
<Node shader={shaders.copy} uniforms={{ t }} />
</Surface>
);
}
}
@ -120,38 +125,40 @@ export default class Example extends Component {
const { distortion } = this.props;
const { surfacePixels, desertPixels } = this.state;
return (
<div>
<Surface ref="surface"
width={400}
height={400}
webglContextAttributes={{ preserveDrawingBuffer: true }}>
<div>
<Surface
ref="surface"
width={400}
height={400}
webglContextAttributes={{ preserveDrawingBuffer: true }}
>
<Bus ref="desert">
{/* we use a Bus to have a ref for capture */}
<Desert width={128} height={128} />
</Bus>
<Bus ref="desert">{/* we use a Bus to have a ref for capture */}
<Desert width={128} height={128} />
</Bus>
<CRT
distortion={distortion}
texSize={[128, 128]}
inSize={[128, 128]}
outSize={[400, 400]}
>
{() => this.refs.desert}
</CRT>
</Surface>
<CRT
distortion={distortion}
texSize={[ 128, 128 ]}
inSize={[ 128, 128 ]}
outSize={[ 400, 400 ]}>
{() => this.refs.desert}
</CRT>
</Surface>
<div className="buttons">
<button onClick={this.onCapture}>capture</button>
</div>
<div className="snaps">
<ShowCaptured t={surfacePixels} />
<ShowCaptured t={desertPixels} />
</div>
</div>
<div className="buttons">
<button onClick={this.onCapture}>capture</button>
</div>
<div className="snaps">
<ShowCaptured t={surfacePixels} />
<ShowCaptured t={desertPixels} />
</div>
</div>
);
}
static defaultProps = {
distortion: 0.2
distortion: 0.2,
};
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component, PureComponent } from "react";
import {Shaders, Node, GLSL, Bus, connectSize} from "gl-react";
import { Surface } from "gl-react-dom";
@ -155,4 +155,4 @@ export default class Example extends Component {
distortion: 0.2
};
};
`
`;

View File

@ -3,7 +3,9 @@ import makeFloatSlider from "../../toolbox/makeFloatSlider";
export const title = "Desert Shadertoy + CRT effect + snapshot()";
export const toolbox = [
{ prop: "distortion",
{
prop: "distortion",
title: "Distortion",
Editor: makeFloatSlider(0, 1, 0.01) },
Editor: makeFloatSlider(0, 1, 0.01),
},
];

View File

@ -6,7 +6,7 @@ import timeLoop from "../../HOC/timeLoop";
const shaders = Shaders.create({
squareTunnel: {
// from https://en.wikipedia.org/wiki/Shadertoy
// from https://en.wikipedia.org/wiki/Shadertoy
frag: GLSL`
precision highp float;
varying vec2 uv;
@ -20,18 +20,18 @@ void main() {
vec3 col = 0.5 + 0.5*sin( 3.1416*f + vec3(0.0,0.5,1.0) );
col = col*r;
gl_FragColor = vec4( col, 1.0 );
}` }
}`,
},
});
const SquareTunnel = ({ time }) =>
<Node
shader={shaders.squareTunnel}
uniforms={{ iGlobalTime: time / 1000 }}
/>
const SquareTunnel = ({ time }) => (
<Node shader={shaders.squareTunnel} uniforms={{ iGlobalTime: time / 1000 }} />
);
const DesertPassageLoop = timeLoop(SquareTunnel);
export default() =>
export default () => (
<Surface width={400} height={400}>
<DesertPassageLoop />
</Surface>
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -35,4 +35,4 @@ export default() =>
<Surface width={400} height={400}>
<DesertPassageLoop />
</Surface>
`
`;

View File

@ -13,19 +13,18 @@ varying vec2 uv;
uniform float red;
void main() {
gl_FragColor = vec4(red, uv.x, uv.y, 1.0);
}` }
}`,
},
});
const HelloGLAnimated = timeLoop( ({ time }) =>
<Node
shader={shaders.helloRed}
uniforms={{ red: Math.cos(time / 100) }}
/>
);
const HelloGLAnimated = timeLoop(({ time }) => (
<Node shader={shaders.helloRed} uniforms={{ red: Math.cos(time / 100) }} />
));
export default () =>
export default () => (
<Surface width={300} height={300}>
<DiamondCrop>
<HelloGLAnimated blue={0.8} />
</DiamondCrop>
</Surface>;
</Surface>
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -29,4 +29,4 @@ export default () =>
<HelloGLAnimated blue={0.8} />
</DiamondCrop>
</Surface>;
`
`;

View File

@ -4,7 +4,7 @@ import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
const shaders = Shaders.create({
DiamondCrop: {
frag: GLSL`
frag: GLSL`
precision highp float;
varying vec2 uv;
uniform sampler2D t;
@ -14,20 +14,20 @@ gl_FragColor = mix(
vec4(0.0),
step(0.5, abs(uv.x - 0.5) + abs(uv.y - 0.5))
);
}` },
}`,
},
});
export const DiamondCrop = ({ children: t }) =>
<Node shader={shaders.DiamondCrop} uniforms={{ t }} />;
export const DiamondCrop = ({ children: t }) => (
<Node shader={shaders.DiamondCrop} uniforms={{ t }} />
);
export default class Example extends Component {
render() {
return (
<Surface width={300} height={300}>
<DiamondCrop>
https://i.imgur.com/5EOyTDQ.jpg
</DiamondCrop>
<DiamondCrop>https://i.imgur.com/5EOyTDQ.jpg</DiamondCrop>
</Surface>
);
}
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -31,4 +31,4 @@ export default class Example extends Component {
);
}
};
`
`;

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Surface } from "gl-react-dom";
import { DiamondCrop } from "../diamondcrop";
@ -15,4 +15,4 @@ export default class Example extends Component {
);
}
}
`
`;

View File

@ -33,34 +33,33 @@ void main() {
texture2D(t, lookup(-colorSeparation * orientation, amp2)).g,
texture2D(t, lookup(vec2(0.0), amp2)).b),
1.0);
}` }
}`,
},
});
const Vignette = timeLoop(({ children: t, time, mouse }) =>
const Vignette = timeLoop(({ children: t, time, mouse }) => (
<Node
shader={shaders.vignetteColorSeparationDistortion}
uniforms={{
t,
time: time / 1000, // seconds is better for float precision
mouse,
freq: 10 + 2 * Math.sin(0.0007*time),
amp: 0.05 + Math.max(0, 0.03*Math.cos(0.001 * time)),
freq: 10 + 2 * Math.sin(0.0007 * time),
amp: 0.05 + Math.max(0, 0.03 * Math.cos(0.001 * time)),
moving: 0,
}}
/>);
/>
));
export default class Example extends Component {
state = {
mouse: [ 0.5, 0.5 ]
mouse: [0.5, 0.5],
};
render() {
const { mouse } = this.state;
return (
<Surface width={500} height={400} onMouseMove={this.onMouseMove}>
<Vignette mouse={mouse}>
https://i.imgur.com/2VP5osy.jpg
</Vignette>
<Vignette mouse={mouse}>https://i.imgur.com/2VP5osy.jpg</Vignette>
</Surface>
);
}
@ -70,7 +69,7 @@ export default class Example extends Component {
mouse: [
(e.clientX - rect.left) / rect.width,
(rect.bottom - e.clientY) / rect.height,
]
],
});
}
};
};
}

View File

@ -1,4 +1,4 @@
module.exports=`import React, { Component } from "react";
module.exports = `import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
@ -74,4 +74,4 @@ export default class Example extends Component {
});
}
};
`
`;

View File

@ -1,12 +1,10 @@
import markdown from "../../markdown";
export const title = "Vignette color separation distortion + mouse";
export const desc =
markdown`
export const desc = markdown`
Crazy distortion effect on an image
`;
export const descAfter =
markdown`
export const descAfter = markdown`
We can listen to mouse events on the \`<Surface>\`.
Remember that \`<Surface>\` is rendering a \`<canvas>\`
and just forward the same React callbacks to it.

View File

@ -12,7 +12,7 @@
color: #c22;
font-size: 10px;
line-height: 18px;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

View File

@ -4,18 +4,20 @@ import { Node, Visitor, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
const Preview = timeLoop(({ frag, visitor, time }) =>
const Preview = timeLoop(({ frag, visitor, time }) => (
<Surface width={500} height={200} visitor={visitor}>
<Node shader={{ frag }} uniforms={{ time: time / 1000 }} />
</Surface>);
</Surface>
));
class DisplayError extends Component {
render() {
const {error} = this.props;
if (!error) return <div className="compile success">Compilation success!</div>;
const { error } = this.props;
if (!error)
return <div className="compile success">Compilation success!</div>;
let err = error.message;
const i = err.indexOf("ERROR:");
if (i!==-1) err = "line "+err.slice(i + 9);
if (i !== -1) err = "line " + err.slice(i + 9);
return <div className="compile error">{err}</div>;
}
}
@ -30,22 +32,23 @@ export default class Example extends Component {
};
visitor.onSurfaceDrawEnd = () => this.setState({ error: null });
this.state = { error: null, visitor };
};
}
render() {
const { frag } = this.props;
const { error, visitor } = this.state;
return (
<div>
<Preview frag={frag} visitor={visitor} />
<DisplayError error={error} />
</div>
<div>
<Preview frag={frag} visitor={visitor} />
<DisplayError error={error} />
</div>
);
}
props: { frag: string };
state: { error: ?Error, visitor: Visitor };
static defaultProps = { // adapted from http://glslsandbox.com/e#27937.0
static defaultProps = {
// adapted from http://glslsandbox.com/e#27937.0
frag: GLSL`precision highp float;
varying vec2 uv;
@ -67,6 +70,6 @@ void main() {
}
gl_FragColor = cbuff;
}
`
`,
};
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Node, Visitor, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -70,4 +70,4 @@ void main() {
\`
};
}
`
`;

View File

@ -16,7 +16,7 @@ export const toolbox = [
color: "#ABB2BF",
fontSize: 10,
lineHeight: 1.5,
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace"
})
}
fontFamily: "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
}),
},
];

View File

@ -17,7 +17,7 @@ float random (vec2 uv) {
// i
void main() {
gl_FragColor = vec4(vec3(step(0.5, random(uv))), 1.0);
}`
}`,
},
GameOfLife: {
// implement Game Of Life.
@ -40,8 +40,8 @@ void main() {
step(0.5, texture2D(t, uv + vec2( 0.0, -1.0)*c).r);
float next = prev==1.0 && sum >= 2.0 && sum <= 3.0 || sum == 3.0 ? 1.0 : 0.0;
gl_FragColor = vec4(vec3(next), 1.0);
}`
}
}`,
},
});
const refreshEveryTicks = 20;
@ -52,25 +52,27 @@ export const GameOfLife = ({ tick }) => {
// However, we can conditionally change shader/uniforms,
// React reconciliation will preserve the same <Node> instance,
// and our Game of Life state will get preserved!
return tick % refreshEveryTicks === 0
? <Node
shader={shaders.InitGameOfLife}
width={size}
height={size}
backbuffering // makes Node holding 2 fbos that get swapped each draw time
sync // force <Node> to draw in sync each componentDidUpdate time
/>
: <Node
shader={shaders.GameOfLife}
width={size}
height={size}
backbuffering
sync
uniforms={{
t: Uniform.Backbuffer, // Use previous frame buffer as a texture
size
}}
/>;
return tick % refreshEveryTicks === 0 ? (
<Node
shader={shaders.InitGameOfLife}
width={size}
height={size}
backbuffering // makes Node holding 2 fbos that get swapped each draw time
sync // force <Node> to draw in sync each componentDidUpdate time
/>
) : (
<Node
shader={shaders.GameOfLife}
width={size}
height={size}
backbuffering
sync
uniforms={{
t: Uniform.Backbuffer, // Use previous frame buffer as a texture
size,
}}
/>
);
};
const GameOfLifeLoop = timeLoop(GameOfLife, { refreshRate: 20 });

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Uniform, Shaders, Node, GLSL, NearestCopy } from "gl-react";
import { Surface } from "gl-react-dom";
@ -82,4 +82,4 @@ export default () => (
</NearestCopy>
</Surface>
);
`
`;

View File

@ -11,5 +11,5 @@ gl-react have a \`Backbuffer\` Symbol we can pass
as texture uniform to access previously drawn frame.
> gl-react hooks React lifecycle to GL draws.
\`componentDidUpdate => gl.draw\`
> \`componentDidUpdate => gl.draw\`
`;

View File

@ -16,7 +16,7 @@ const GameOfLifeLoop = timeLoop(
sync
uniforms={{
t: tick === 0 ? gliderGunImage : Uniform.Backbuffer,
size
size,
}}
/>
),
@ -31,7 +31,7 @@ export default class Example extends Component {
height={500}
preload={[
// preload textures before starting rendering
gliderGunImage
gliderGunImage,
]}
>
<NearestCopy>

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Uniform, Node, NearestCopy } from "gl-react";
import { Surface } from "gl-react-dom";
@ -41,4 +41,4 @@ export default class Example extends Component {
);
}
}
`
`;

View File

@ -8,7 +8,7 @@ export const desc = markdown`
`;
export const descAfter = markdown`
Initial image state inspired from [wikipedia](https://en.wikipedia.org/wiki/Conway's_Game_of_Life).
${<br />}
${(<br />)}
${(
<a href={gliderGun64png}>
<img

View File

@ -3,7 +3,7 @@ import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
import {GameOfLife} from "../gol";
import { GameOfLife } from "../gol";
const shaders = Shaders.create({
Rotating: {
@ -19,27 +19,32 @@ void main() {
p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0
? vec4(0.0)
: texture2D(children, p);
}` }
}`,
},
});
export const Rotating = ({ angle, scale, children }) =>
export const Rotating = ({ angle, scale, children }) => (
<Node
shader={shaders.Rotating}
uniformsOptions={{ children: { interpolation: "nearest" } }}
uniforms={{ angle, scale, children }}
/>;
/>
);
const RotatingLoop = timeLoop(({ time, children }) => Rotating({
angle: (time / 1000) % (2 * Math.PI),
scale: 0.6 + 0.15 * Math.cos(time / 500),
children,
}));
const RotatingLoop = timeLoop(({ time, children }) =>
Rotating({
angle: (time / 1000) % (2 * Math.PI),
scale: 0.6 + 0.15 * Math.cos(time / 500),
children,
})
);
const GameOfLifeLoop = timeLoop(GameOfLife, { refreshRate: 5 });
export default () =>
export default () => (
<Surface width={500} height={500}>
<RotatingLoop>
<GameOfLifeLoop />
</RotatingLoop>
</Surface>;
</Surface>
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -43,4 +43,4 @@ export default () =>
<GameOfLifeLoop />
</RotatingLoop>
</Surface>;
`
`;

View File

@ -2,11 +2,12 @@ import markdown from "../../markdown";
export const title = "Rotating GameOfLife. 2 loops";
export const desc = markdown`
Compose [Game of Life][/gol] with Rotation
\`\`\`
~~~
<RotatingLoop>
<GameOfLifeLoop />
</RotatingLoop>
\`\`\`
~~~
`;
export const descAfter = markdown`
GameOfLifeLoop runs at 5fps, RotatingLoop runs at full speed (60fps).

View File

@ -2,11 +2,12 @@
import React, { Component } from "react";
import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
import {GameOfLife} from "../gol";
import {Rotating} from "../golrot";
import { GameOfLife } from "../gol";
import { Rotating } from "../golrot";
class PureGameOfLife extends Component {
shouldComponentUpdate ({ tick }) { // only tick should trigger redraw
shouldComponentUpdate({ tick }) {
// only tick should trigger redraw
return tick !== this.props.tick;
}
render() {
@ -14,14 +15,14 @@ class PureGameOfLife extends Component {
}
}
const RotatingGameOfLife = ({ time }) =>
const RotatingGameOfLife = ({ time }) => (
<Rotating
angle={(time / 1000) % (2 * Math.PI)}
scale={0.6 + 0.15 * Math.cos(time / 500)}>
scale={0.6 + 0.15 * Math.cos(time / 500)}
>
<PureGameOfLife tick={Math.floor(time / 200)} />
</Rotating>;
</Rotating>
);
export const RotatingGameOfLifeLoop = timeLoop(RotatingGameOfLife);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
@ -34,4 +34,4 @@ export default class Example extends Component {
);
}
}
`
`;

View File

@ -28,22 +28,23 @@ void main () {
1.0);
}
}
`
}
`,
},
});
const Display = ({ gol, webcam }) =>
const Display = ({ gol, webcam }) => (
<Node
shader={extraShaders.Display}
uniformsOptions={{ gol: { interpolation: "nearest" } }}
uniforms={{
gol,
webcam,
webcamRatio: Uniform.textureSizeRatio(webcam)
webcamRatio: Uniform.textureSizeRatio(webcam),
}}
/>;
/>
);
const GameOfLife = ({ size, reset, resetTexture }) =>
const GameOfLife = ({ size, reset, resetTexture }) => (
<Node
shader={shaders.GameOfLife}
width={size}
@ -52,12 +53,13 @@ const GameOfLife = ({ size, reset, resetTexture }) =>
sync
uniforms={{
t: reset ? resetTexture : Uniform.Backbuffer,
size
size,
}}
/>;
/>
);
const GameOfLifeLoop = timeLoop(GameOfLife, {
refreshRate: 4
refreshRate: 4,
});
export default class Example extends Component {
@ -73,10 +75,11 @@ export default class Example extends Component {
onMouseUp={this.onMouseUp}
>
<Bus ref="webcam">
{redraw =>
{(redraw) => (
<Video onFrame={redraw} autoPlay>
<WebCamSource />
</Video>}
</Video>
)}
</Bus>
<Display
@ -95,7 +98,7 @@ export default class Example extends Component {
onMouseDown = () =>
this.setState({
reset: true,
size: Math.floor(10 + 200 * Math.random() * Math.random())
size: Math.floor(10 + 200 * Math.random() * Math.random()),
});
onMouseUp = () => this.setState({ reset: false });
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Bus, Uniform, Node, Shaders, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -99,4 +99,4 @@ export default class Example extends Component {
});
onMouseUp = () => this.setState({ reset: false });
}
`
`;

View File

@ -5,7 +5,8 @@ import { Surface } from "gl-react-dom";
import timeLoop from "../../HOC/timeLoop";
const shaders = Shaders.create({
gradients: { frag: GLSL`
gradients: {
frag: GLSL`
precision highp float;
varying vec2 uv;
uniform vec4 colors[3];
@ -23,33 +24,36 @@ void main () {
sum.a = 1.0;
}
gl_FragColor = vec4(sum.a * sum.rgb, 1.0);
}`}
}`,
},
});
// Alternative syntax using React stateless function component
const Gradients = ({ time }) =>
const Gradients = ({ time }) => (
<Node
shader={shaders.gradients}
uniforms={{
colors: [
[ Math.cos(0.002*time), Math.sin(0.002*time), 0.2, 1 ],
[ Math.sin(0.002*time), -Math.cos(0.002*time), 0.1, 1 ],
[ 0.3, Math.sin(3+0.002*time), Math.cos(1+0.003*time), 1 ]
[Math.cos(0.002 * time), Math.sin(0.002 * time), 0.2, 1],
[Math.sin(0.002 * time), -Math.cos(0.002 * time), 0.1, 1],
[0.3, Math.sin(3 + 0.002 * time), Math.cos(1 + 0.003 * time), 1],
],
particles: [
[ 0.3, 0.3 ],
[ 0.7, 0.5 ],
[ 0.4, 0.9 ]
]
[0.3, 0.3],
[0.7, 0.5],
[0.4, 0.9],
],
}}
/>;
/>
);
const GradientsLoop = timeLoop(Gradients);
export default () =>
export default () => (
<Surface width={300} height={300}>
<GradientsLoop />
</Surface>;
</Surface>
);
// NB: don't abuse the uniforms array:
// it's not meant to be used with lot of objects.

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -54,4 +54,4 @@ export default () =>
// NB: don't abuse the uniforms array:
// it's not meant to be used with lot of objects.
// GLSL 1 also don't support variable length in loops.
`
`;

View File

@ -2,10 +2,11 @@
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
import {Motion, spring} from "react-motion";
import { Motion, spring } from "react-motion";
const shaders = Shaders.create({
Heart: { // inspired from http://glslsandbox.com/e#29521.0
Heart: {
// inspired from http://glslsandbox.com/e#29521.0
frag: GLSL`
precision highp float;
varying vec2 uv;
@ -16,7 +17,7 @@ void main() {
float scale = 1.0 - 0.1 * over - 0.8 * toggle;
vec2 offset = vec2(0.0, -0.3 - 0.1 * over - 0.7 * toggle);
vec2 p = scale * (2.0 * uv - 1.0 + offset);
float a = atan(p.x, p.y) / ${Math.PI/* \o/ */};
float a = atan(p.x, p.y) / ${Math.PI /* \o/ */};
float r = length(p);
float h = abs(a);
float d = (13.0*h - 22.0*h*h + 10.0*h*h*h - 0.3 * (1.0-over))/(6.0-5.0*h);
@ -24,8 +25,8 @@ void main() {
vec3 t = texture2D(image, uv).rgb;
vec3 c = mix(color * (1.0 + 0.6 * t), t, min(0.8 * over + toggle, 1.0));
gl_FragColor = vec4(mix(vec3(1.0), c, f), 1.0);
}`
}
}`,
},
});
class InteractiveHeart extends Component {
@ -37,28 +38,32 @@ class InteractiveHeart extends Component {
const { color, image } = this.props;
const { over, toggle } = this.state;
return (
<Surface width={300} height={300}
<Surface
width={300}
height={300}
onClick={this.onClick}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}>
onMouseLeave={this.onMouseLeave}
>
<Motion
defaultStyle={{ over, toggle }}
style={{
over: spring(over, [150, 15]),
toggle: spring(toggle, [150, 15])
}}>{ ({ over, toggle }) =>
<Node
shader={shaders.Heart}
uniforms={{ color, image, over, toggle }}
/>
}</Motion>
toggle: spring(toggle, [150, 15]),
}}
>
{({ over, toggle }) => (
<Node
shader={shaders.Heart}
uniforms={{ color, image, over, toggle }}
/>
)}
</Motion>
</Surface>
);
}
}
export default () =>
<InteractiveHeart
color={[ 1, 0, 0 ]}
image="https://i.imgur.com/GQo1KWq.jpg"
/>;
export default () => (
<InteractiveHeart color={[1, 0, 0]} image="https://i.imgur.com/GQo1KWq.jpg" />
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -16,7 +16,7 @@ void main() {
float scale = 1.0 - 0.1 * over - 0.8 * toggle;
vec2 offset = vec2(0.0, -0.3 - 0.1 * over - 0.7 * toggle);
vec2 p = scale * (2.0 * uv - 1.0 + offset);
float a = atan(p.x, p.y) / ${Math.PI/* \\o/ */};
float a = atan(p.x, p.y) / ${Math.PI /* \\o/ */};
float r = length(p);
float h = abs(a);
float d = (13.0*h - 22.0*h*h + 10.0*h*h*h - 0.3 * (1.0-over))/(6.0-5.0*h);
@ -62,4 +62,4 @@ export default () =>
color={[ 1, 0, 0 ]}
image="https://i.imgur.com/GQo1KWq.jpg"
/>;
`
`;

View File

@ -4,7 +4,8 @@ export const title = "Heart animation";
export const desc = markdown`
gl-react can be used with any React library.
For instance, [react-motion](https://github.com/chenglou/react-motion)'s spring animation.`;
For instance, [react-motion](https://github.com/chenglou/react-motion)'s spring animation.
`;
export const descAfter = markdown`
If you click fastly on the Heart, react-motion nicely

View File

@ -5,14 +5,15 @@ import { Surface } from "gl-react-dom";
const shaders = Shaders.create({
helloBlue: {
// uniforms are variables from JS. We pipe blue uniform into blue output color
// uniforms are variables from JS. We pipe blue uniform into blue output color
frag: GLSL`
precision highp float;
varying vec2 uv;
uniform float blue;
void main() {
gl_FragColor = vec4(uv.x, uv.y, blue, 1.0);
}` }
}`,
},
});
// We can make a <HelloBlue blue={0.5} /> that will render the concrete <Node/>

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -34,4 +34,4 @@ export default class Example extends Component {
}
static defaultProps = { blue: 0.5 };
}
`
`;

View File

@ -2,16 +2,11 @@ import makeFloatSlider from "../../toolbox/makeFloatSlider";
export const title = "Hello GL blue";
export const desc =
``;
export const desc = ``;
export const descAfter =
`^ Examples can have properties.
export const descAfter = `^ Examples can have properties.
They are injected as React props.`;
export const toolbox = [
{ prop: "blue",
title: "Blue Color",
Editor: makeFloatSlider(0, 1, 0.01) },
{ prop: "blue", title: "Blue Color", Editor: makeFloatSlider(0, 1, 0.01) },
];

View File

@ -9,13 +9,15 @@ import { HelloBlue } from "../helloblue";
// in a requestAnimationFrame loop and provide a time and tick prop
import timeLoop from "../../HOC/timeLoop";
export default timeLoop(class Example extends Component {
render() {
const { time } = this.props;
return (
<Surface width={300} height={300}>
<HelloBlue blue={0.5 + 0.5 * Math.cos(time / 500)} />
</Surface>
);
export default timeLoop(
class Example extends Component {
render() {
const { time } = this.props;
return (
<Surface width={300} height={300}>
<HelloBlue blue={0.5 + 0.5 * Math.cos(time / 500)} />
</Surface>
);
}
}
});
);

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Surface } from "gl-react-dom";
@ -19,4 +19,4 @@ export default timeLoop(class Example extends Component {
);
}
});
`
`;

View File

@ -1,8 +1,8 @@
import markdown from "../../markdown";
export const title = "Hello GL blue animated (node re-render)";
export const desc =
markdown`Let's animate *helloblue* !`;
export const descAfter =
`Not lost yet?
export const desc = markdown`
Let's animate _helloblue_ !
`;
export const descAfter = `Not lost yet?
We will re-use some examples,
try to not skip one!`;

View File

@ -6,19 +6,19 @@ import { Surface } from "gl-react-dom";
// in gl-react you need to statically define "shaders":
const shaders = Shaders.create({
helloGL: {
// This is our first fragment shader in GLSL language (OpenGL Shading Language)
// (GLSL code gets compiled and run on the GPU)
// This is our first fragment shader in GLSL language (OpenGL Shading Language)
// (GLSL code gets compiled and run on the GPU)
frag: GLSL`
precision highp float;
varying vec2 uv;
void main() {
gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);
}`
// the main() function is called FOR EACH PIXELS
// the varying uv is a vec2 where x and y respectively varying from 0.0 to 1.0.
// we set in output the pixel color using the vec4(r,g,b,a) format.
// see [GLSL_ES_Specification_1.0.17](http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf)
}
}`,
// the main() function is called FOR EACH PIXELS
// the varying uv is a vec2 where x and y respectively varying from 0.0 to 1.0.
// we set in output the pixel color using the vec4(r,g,b,a) format.
// see [GLSL_ES_Specification_1.0.17](http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf)
},
});
export default class Example extends Component {
@ -28,7 +28,7 @@ export default class Example extends Component {
<Node shader={shaders.helloGL} />
</Surface>
);
// Surface creates the canvas, an area of pixels where you can draw.
// Node instanciates a "shader program" with the fragment shader defined above.
// Surface creates the canvas, an area of pixels where you can draw.
// Node instanciates a "shader program" with the fragment shader defined above.
}
}

View File

@ -1,4 +1,4 @@
module.exports=`//@flow
module.exports = `//@flow
import React, { Component } from "react";
import { Shaders, Node, GLSL } from "gl-react";
import { Surface } from "gl-react-dom";
@ -32,4 +32,4 @@ export default class Example extends Component {
// Node instanciates a "shader program" with the fragment shader defined above.
}
}
`
`;

Some files were not shown because too many files have changed in this diff Show More