krasimir / absurd Goto Github PK
View Code? Open in Web Editor NEWA JavaScript library with superpowers
Home Page: http://absurdjs.krasimirtsonev.com/
License: MIT License
A JavaScript library with superpowers
Home Page: http://absurdjs.krasimirtsonev.com/
License: MIT License
api.add({
'.test': {
position: 'absolute',
top: "20px"
}
});
results in this error:
RangeError: Maximum call stack size exceeded
at String.match (native)
at prefixExtract (http://krasimir.github.io/absurd/js/absurd.js:1071:18)
at Object.lib.helpers.Prefixes.nonPrefixProp (http://krasimir.github.io/absurd/js/absurd.js:1101:11)
at checkAndExecutePlugin (http://krasimir.github.io/absurd/js/absurd.js:634:25)
at addRule (http://krasimir.github.io/absurd/js/absurd.js:682:8)
at checkAndExecutePlugin (http://krasimir.github.io/absurd/js/absurd.js:639:5)
at addRule (http://krasimir.github.io/absurd/js/absurd.js:682:8)
at checkAndExecutePlugin (http://krasimir.github.io/absurd/js/absurd.js:639:5)
at addRule (http://krasimir.github.io/absurd/js/absurd.js:682:8)
at checkAndExecutePlugin (http://krasimir.github.io/absurd/js/absurd.js:639:5)
at addRule (http://krasimir.github.io/absurd/js/absurd.js:682:8)
If I remove the top: "20px"
portion, it compiles fine. Or if I replace top
with left
, bottom
, or right
, it works fine as well.
Any ideas on what's going on? Thanks!
Hi, would you please take a look?
api.add({
body: [{
width: '80px'
}, {
span: {
display: 'inline'
}
}]
});
gives
body {
width: 80px;
span: [object Object];
}
body span {
display: inline;
}
You seem to allow arrays, but nested objects inside arrays don't work.
Hi, this project looks great. I would be nice if existing css files can be imported/translated to be used as mixins ....
YAML Ain't Markup Language
human-readable data serialization format
I have been using absurd with YAML.js for a while now, so, much of my stylesheets are written in YAML. each have to be converted to json/js object before it is fed to absurd.
would be great if absurd can support YAML as well.
@font-face
should not be split apart, regardless of anything since it specifies a rule block. I don't know all css special @
rules, but I'm assuming font-face
is not the only one affected by this
Example:
api.add({
'@font-face': {
fontFamily: 'MuseoSans',
src: "url('/fonts/Museo Sans/MuseoSans_500.otf')",
},
'body': {
fontFamily: 'MuseoSans',
fontSize: '10pt',
},
}).compile(function (err, css) { console.log(css) })
produces
@font-face, body {
font-family: MuseoSans;
}
@font-face {
src: url('/fonts/Museo Sans/MuseoSans_500.otf');
}
body {
font-size: 10pt;
}
Currently, trying to do something like this won't work:
var foo = function(x){
return {
classify: true,
toJSON: function(){
return{
width: 200 + x + 'px'
}
}
};
};
api.add({
'.foo': foo(10)
});
This returns:
.foo toJSON {
width: 210px;
}
I'm not sure if there is a reason for doing things this way, but its causing a bit of trouble with some of the code I'm writing.
Simply adding another check right before processing props in the 'add' method seems to do the trick. Something like:
// Added this:
if(props.classify != 'undefined' && props.classify === true){
props = typeof props.toJSON != 'undefined' ? props.toJSON() : props.toString();
}
// back to the original code...
// processing props
for(var prop in props) {
// ... etc.
/* Now it returns: */
.foo {
width: 210px;
}
Thoughts?
similar to #55, multiple @font-face
should not be overwritten and should be considered two different entities
Example
api.add({
'@font-face': {
fontFamily: 'MuseoSans',
src: "url('/fonts/Museo Sans/MuseoSans_500.otf')", },
});
api.add({
'@font-face': {
fontFamily: 'MuseoSans',
fontStyle: 'italic, oblique',
src: "url('/fonts/Museo Sans/MuseoSans_500_italic.otf')", }
});
wrong output:
@font-face {
font-family: MuseoSans;
src: url('/fonts/Museo Sans/MuseoSans_500_italic.otf');
font-style: italic, oblique;
}
When I use the following code:
transform: "rotate(-20deg)",
the vendor prefix is not populating ('webkit-transform': rotate(-20deg)
)
I am happy to fork and take a look if this issue is not already being resolved.
I've installed AbsurdJS:
apt-get install nodejs
apt-get install npm
npm install -g absurd
then when I try to compile a js file I get:
j@Desktop:~/absurd-test$ absurd -s ./main.js -o ./main.css
: No such file or directory
I'm using Ubuntu 13.10 and all the installation process was done without any problem. I've tried in Fedora 19 as well but the problem is the same.
I noticed you're requiring the underscore
package but only using the _.extend
method and thought you might dig that it's available as an individual package via lodash.assign.
If you'd like a PR just let me know.
Modified Demo: http://krasimir.github.io/absurd/?demo=5
// single value
api.storage("fontsize", "16px");
// multiple values
api.storage({
color: "red",
theme: function(color) {
return {
color: color,
background: api.lighten(color, 50)
}
}
});
api.add({
body: {
background: api.storage("color"),
"section a, section div": [
api.storage("theme")("#999"),
{ marginTop: "20px" },
{ fontSize: api.storage("fontsize") }
]
}
});
Result
body {
background: red;
}
body section a 0, body section div 0 {
background: #e6e6e6;
color: #999;
}
body section a 1, body section div 1 {
margin-top: 20px;
}
body section a 2, body section div 2 {
font-size: 16px;
}
Expected Result
body {
background: red;
}
body section a, body section div {
background: #e6e6e6;
color: #999;
margin-top: 20px;
font-size: 16px;
}
The index.js is formatted with dos-style line endings.
I was able to fix it using this issue as ref: colorhook/node-smushit#4
$ brew install dos2unix
$ dos2unix ~/.nvm/v0.11.5/lib/node_modules/absurd/index.js
like in uglify for example. Watch for directory and if file created, create output file in output folder.
Hi;
How to import css string in absurd.js ?
Example: api.import(" test { position: absolute } ");
Thanks.
Would be nice if we could use this library on the browser, we could create angular module that doesn't need external CSS files anymore, so just a copy paste of one line of javascript and... done !
Hi, I read a an article and I think it's very good and crazy idea in the same time :). Absurd
handle a lot of problems but there is thing that I could not understand. I valid json we could not use one property name a couple times, it would be overridden. But what If we need use same tag names in one component? Is it possible to handle it in some way?
var absurd = Absurd();
absurd.component('MyComp', {
// html template
html: {
section: {
h1: 'Hello world',
hr: '',
p: 'I\'m an AbsurdJS component.', /* p first time */
h2: 'hello world', /* h2 first time */
p: 'why not?', /* p second time */
h2: 'this would not work out' /* h2 second time */
}
},
// css applied on the page
css: {
body: { ff: 'Verdana' },
h1: { fz: '20px', mar: 0, color: '#009f00' },
hr: { bdt: 'n', bdb: 'dotted 1px #999' }
},
// called on DOM ready
ready: function(dom) {
this
// saying where the element
// will be attached
.set('parent', dom('body').el)
// compiling the css and html
.populate();
}
})();
This will allow support of @media queries and @Keyframes in the pure CSS source files.
CSS allows you to write something like:
body {
color: rgb(0,0,0);
color: rgba(0,0,0,0.5);
}
This is a common way to have a rule for both browsers supporting rgba() and browsers that don't (like IE8).
But absurd.js uses the key of JS Objects, which (of course) only support the property once.
To overcome this limitation we could add a prefix that is just ignored:
api.add({
body: {
color: "rgb(0,0,0)",
_color: "rgba(0,0,0,0.5)"
},
});
But this relies on the fact that most JS Engines return the object in the same order as specified, which is not guaranteed.
Another solution would be the use of arrays which provide the ordering and objects for the properties:
api.add({
body: {
'&': [{color: "rgb(0,0,0)"},
{color: "rgba(0,0,0,0.5)"}]
},
});
But this doesn't work, as absurd.js merges them:
body {
color: rgba(0,0,0,0.5);
}
Create a div
element by default. Even if only attributes are passed:
'[class="bla"]': 'test'
should produce:
<div class="bla">test</div>
Consider:
api.add({
body: {
marginTop: "20px",
width: "100%"
},
header: {
width: "100%",
'&, .cls2': {
color: "red"
}
}
});
Output
body {
margin-top: 20px;
}
body, header {
width: 100%;
}
header, .cls2 {
color: red;
}
But it should be:
body {
margin-top: 20px;
}
body, header {
width: 100%;
}
header, header .cls2 { /* <-- missing header after comma */
color: red;
}
Tested with 0.2.65
Allow combineSelectors in CLI
I got this error when trying to launch absurd from command line:
env: node\r: No such file or directory
The reason is that ../node_modules/absurd/index.js is saved with Windows line endings. Saving with Unix line endings solved that problem.
Being able to output to different formats other than CSS would be very useful.
The main use case I'm thinking of would be to ease migration from CSS/LESS/SASS/other to another format e.g. JS/JSON/YAML/other
The cleanest way would probably be to have input/output plugins, that way things like #7 would become a lot easier.
Here is what I installed:
[email protected] /usr/lib/node_modules/absurd
├── [email protected]
├── [email protected]
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected], [email protected], [email protected])
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected])
This is what happens when I typed the absurd
command: : No such file or directory
I have installed and reinstalled absurd 3 times with the same results.
HTML:
<button class="UIButton" data-absurd-event="click:linkClicked" data-id="<% this.id %>"><% this.name %></button>
JavaScript:
var UIButton = absurd.component("UIButton", {
css: {
'#loading': {
background: "#000000",
h1: {
color: '#F00',
}
},
".hidden": {
display: "none"
}
},
linkClicked: someEventFn,
html: ".UIButton",
constructor: function(name, id) {
this.name = name;
this.id = id;
this.populate();
}
});
However this code will take that HTML element, and replace the data, preventing it from being reused.
I've tried cloning the html element myself, but then this happens:
UIButton("Small Structure", 256);
// <button class="UIButton" data-absurd-event="click:linkClicked" data-id="256">Small Structure</button>
UIButton("Small Structure", 257);
// <button class="UIButton" data-absurd-event="click:linkClicked" data-id="256">Small Structure</button>
I end up with the same element, even though the input is different. I can confirm that the resulting object from the component does have different "id" and "name" values, but for some reason it isn't populating correctly.
Hi, we need keepCamelCase
to work with HTML as well.
The thing is, we use AbsurdJS to generate CSS and SVG. SVG is case-sensitive, but AbsurdJS turns feColorMatrix
into fe-color-matrix
, tableValues
into table-values
, etc.
This shouldn't be hard to do. In fact, I implemented it by passing options
around and calling transformUppercase
conditionally.
I made my changes (to the absurd.js
output file) available as a gist if they may help with the implementation:
https://gist.github.com/gaearon/7779132/revisions
I didn't submit the PR because I don't have much time, but it should be trivial to introduce these changes.
Thanks!
The current workflow for absurd is:
var api = Absurd();
// Define plugins on the api instance
api.plugin(...);
// Define fancy methods on the api instance
api.register(...);
// Add your styles to the api instance, compile and add to the DOM
api.add(...).compile(...)
// repeat for every file
While that is ok, and it's really great that you can have multiple api instances, the workflow I end up having most of the time is:
var api = Absurd();
and have all other files assume this existsUnless I'm understanding how this should be done properly, this is not entirely ideal.
There should be some mechanism of adding the plugins/extensions globally as most of the time you would like to reuse them in multiple files rather than have them bound to individual api instances.
Hi,
Not sure if it’s a bug or not. I tried to do this, with 2.3 version of bootstrap, on an existing project :
@import “bootstrap-responsive.css”;
@import “bootstrap.css”;
@import “text.css”;
/* Some more CSS */
For that, I wrote :
var cwd = __dirname,
cwdArr = __dirname.split(“\”),
rootCwd = cwdArr.slice(0, cwdArr.length-2).join(“/”);
api.import([
rootCwd + '/css/bootstrap-responsive.css',
rootCwd + '/css/bootstrap.css',
rootCwd + '/css/text.css'
]);
/* more code here, well generated to css*/
But in the end, I end up with lines that were reordered. It’s not written :
@import “bootstrap-responsive.css”;
@import “bootstrap.css”;
@import “text.css”;
…
It preprocessed all the files to be imported, it reordered all lines, and in the end, it’s not making working fine.
Is there a way to tell Absurd :
Thanks by advance.
It would be nice if absurd would check if the values are actually object literals before proceeding to consider them as a collection of properties. (aka check if (obj.toString() === '[object Object]') {}
or something similar)
This would be extremely helpful in allowing you to create custom classes which evaluate to strings. For example, I want to implement a px
class which at its core just appends 'px' to any number, but you can also add px-els:
var px = function (value) {
var tmp = function () {};
tmp.prototype = {
val: value,
add: function (obj) {
this.val += (typeof obj == 'number' ? obj : obj.val);
return this;
},
toString: function () { return this.val + 'px'; },
toJSON: function () { return this.toString(); },
};
return new tmp();
};
so then I would be able to do things like this in absurd:
var elementSize = 50;
var margin = 10;
return {
body: { width: px(elementSize).add(margin), },
};
and have it be evaluated to:
body {
width: 60px;
}
Currently it just takes the object and does ungodly things to it and you get stuff like:
.tag test {
0: [;
1: o;
2: b;
3: j;
4: e;
5: c;
6: t;
7: ;
8: U;
9: n;
10: d;
11: e;
12: f;
13: i;
14: n;
15: e;
16: d;
17: ];
to-j-s-o-n: 10px;
}
I'm using Absurd to morph some form elements and there is a small issue / unexpected error:
'form' : {
'input#myId.clas1.clas2' : null
}
Produces the error: Cannot read property 'length' of null
It works if I replaced null
with an empty string. Seems like, intuitively, null
would work in this case. At any rate, the error is a bit hard to debug as is.
Otherwise, great work. Absurd is working extremely well for CSS on my project!
api.add({
body: {
marginTop: null,
width: "100%"
},
header: {
width: "100%"
}
});
Results in an error:
TypeError: Cannot read property 'length' of null
at addRule (http://krasimir.github.io/absurd/js/absurd.js:814:18)
at addRule (http://krasimir.github.io/absurd/js/absurd.js:892:5)
at Object.add (http://krasimir.github.io/absurd/js/absurd.js:920:4)
at Object.add (http://krasimir.github.io/absurd/js/absurd.js:701:16)
at HTMLAnchorElement.eval (eval at (http://krasimir.github.io/absurd/:1456:11), :1:5)
at HTMLAnchorElement.compile (http://krasimir.github.io/absurd/:1456:6)
at HTMLAnchorElement.x.event.dispatch (http://krasimir.github.io/absurd/js/jquery-1.10.2.min.js:5:14129)
at HTMLAnchorElement.v.handle (http://krasimir.github.io/absurd/js/jquery-1.10.2.min.js:5:10866)
But it would be better if the rule is just ignored. This is particular useful when using JS vars.
In the online demo, adding this:
api.add({
'html, body': { color:'red', },
'body': { background:'blue', },
'html': { background:'pink', },
});
results in this:
body, html {
color: red;
}
overwriting the individual body and html blocks. It should be compiled to this:
body, html { color: red; }
body: { background: blue; }
html: { background: pink; }
If you have in the online compiler:
api.add({
'@media screen and (max-width: 767px)': {
a: { color:'red', },
div: { color:'blue', },
'.some-class': { color:'green' },
}
});
it gets compiled to:
@media screen and (max-width: 767px) a {
color: red;
}
@media screen and (max-width: 767px) div {
color: blue;
}
@media screen and (max-width: 767px) .some-class {
color: green;
}
Which is not wrong per say, but it would be much better for readability and compression if it would be compiled as:
@media screen and (max-width: 767px) {
a { color: red; }
div { color: blue; }
.some-class { color: green; }
}
In other words, don't prefix the media query to all sub-selectors as it can simply work as a closure
Would be cool if absurd has support for property merging like:
// first call
api.add({
body: {
"text-shadow+": "0px 0px 3px red",
"color": "green"
},
});
// second call
api.add({
body: {
"text-shadow+": "0px 0px 7px blue"
},
});
/* Actual result:
body {
text-shadow+: 0px 0px 7px blue;
color: green;
}
*/
/* Expected result:
body {
text-shadow: 0px 0px 3px red, 0px 0px 7px blue;
color: green;
}
*/
This is a less feature. Not sure if SCSS has something similar. For us it would be really helpful. The syntax could be totally different of course. May be this could also be implemented using a plugin, hook or similar, but i'm new to absurd.js and not sure how to do it. Any hints are welcome.
Bug: less/less.js#1742
Test Cases:
https://github.com/less/less.js/blob/master/test/less/merge.less
https://github.com/less/less.js/blob/master/test/css/merge.css
This a a media query block generated by absurd:
@media (max-width: 930px) {
#productInfo {
display: block;
width: auto;
}
#productInfo .content {
display: none;
}
#productInfo .actions {
display: none;
}
}
it would be much easier to read if its content would be indented once:
@media (max-width: 930px) {
#productInfo {
display: block;
width: auto;
}
#productInfo .content {
display: none;
}
#productInfo .actions {
display: none;
}
}
so you can clearly see where the media tag ends and what's inside it
Ideally you would want when running combineSelectors:true
for absurd to output the rules exactly as you define them, but instead it breaks them apart.
Lets take for example twitter bootstrap's .clearfix
definition in absurd:
css['.clearfix'] = {
'*zoom': 1,
'&:before, &:after': {
display: 'table',
content: '',
lineHeight: 0,
},
'&:after': {
clear: 'both',
},
};
Using combineSelectors:true
everything is ok:
.clearfix {
*zoom: 1;
}
.clearfix:before, .clearfix:after {
display: table;
content: "";
line-height: 0;
}
.clearfix:after {
clear: both;
}
Using combineSelectors:false
you would expect that the rule '&:before, &:after': {}
would also be computed in one block, but instead it gets split up (as in, it acts as an "force" don't combineSelectors)
.clearfix {
*zoom: 1;
}
.clearfix:before {
display: table;
content: "";
line-height: 0;
}
.clearfix:after {
display: table;
content: "";
line-height: 0;
clear: both;
}
It would be very useful if the combination only happen when requested and otherwise the structure you put in to be compiled in the same format, it helps with testing and debugging a lot more.
In other words, I would have expected that in this particular example, the output from combineSelectors:true
and combineSelectors:false
to be the same given that my structure already combines the selectors.
I would be great to have a standard library of mixins/helpers. Something like Compass
Hi! Running
api.add({
"p, span": {
"b, i": {
"font-size": '20px'
}
}
});
gives me
p, span b, i {
font-size: 20px;
}
which is wrong.
(Should be
p b, p i, span b, span i {
font-size: 20px;
}
)
I'd love to require absurd from bower (http://bower.io/) whenever i'm doing a quick project and I only want to use it on the client side. I'm sure many other people would too
Source map is needed so the developers could find the exact styles in a specific js file.
api.plugin("plugin1", function(api, color) {
return {
":hover": {
color: color
}
};
});
api.plugin("plugin2", function(api, color) {
return {
".myCls": {
color: color
}
};
});
api.add({
a: [
{"plugin1": "red"},
{"plugin2": "green"},
{"plugin1": "blue"}
]
});
Result
a {
plugin1: blue;
plugin2: green;
}
a:hover {
color: blue;
}
a .myCls {
color: green;
}
Expected Result
a:hover {
color: blue;
}
a .myCls {
color: green;
}
The first plugin "call" is not written as property: value, but all calls after that.
It would be cool if we could do something like:
api.add({
'.test': {
'.some, .sel': {
'^html.ie8': {
color: "#333"
},
width: "100%"
}
}
});
.test .some, .test .sel {
width: 100%;
}
html.ie8 .test .some, html.ie8 .test .sel {
color: #333;
}
Normally the html.ie8 would be appended to the current selector chain. But it would be great if we could use a Symbol (like ^, shoud be an otherwise invalid css selector symbol) which turns the append in a prepend (globally)
Example Use Case: IE8 fixes with complex nested selectors (you don't have to copy the whole selector for the fix).
If I import a CSS file with something like this:
header, footer, aside {
display: block;
}
and then use the API to add additional styles:
api.add({
'header': {
width: '100px',
height: '100px'
}
});
the resulting output looks like this:
header, footer, aside {
display: block;
width: 100px;
height: 100px;
}
but should look like this:
header, footer, aside {
display: block;
}
header {
width: 100px;
height: 100px;
}
api.plugin("hoverEffect", function(api, color) {
return {
"&:hover": {
color: color,
background: api.lighten(color, 60)
}
};
});
api.add({
a: {
color: "#000",
hoverEffect: "#999"
}
});
Result:
a {
color: #000;
&:hover: [object Object];
}
a:hover {
color: #999;
background: #f5f5f5;
}
which BSD? 2-clause? 3-clause? 4?
I don't know if generators are still a thing, but i use it in my workflow and it might help others.
If u pass in an undefined value, it is not caught by absurd. It would be nice if absurd would tell you where the error happen by throwing its own or notify you in some other way that you probably did something wrong :)
example:
return {
body: { width: undefined, }
}
Error: (no mentioned of where in the file it happened... :( )
Running "absurd:cssmin" (absurd) task
Error: '/Users/mozilla/Dropbox/www/nybl/kiwi/src/absurd/CommentBox.css.js'. [TypeError: Cannot call method 'toString' of undefined] TypeError: Cannot call method 'toString' of undefined
at Object.add (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/api/add.js:168:16)
at Object.add (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/API.js:117:16)
at module.exports (/Users/mozilla/Dropbox/www/nybl/kiwi/src/absurd/CommentBox.css.js:39:7)
at importFile (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/api/import.js:37:26)
at Object.<anonymous> (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/api/import.js:47:4)
at Object.import (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/API.js:117:16)
at /Users/mozilla/Dropbox/www/nybl/kiwi/src/absurd/absurd.js:16:15
at Array.map (native)
at module.exports (/Users/mozilla/Dropbox/www/nybl/kiwi/src/absurd/absurd.js:15:11)
at importFile (/Users/mozilla/Dropbox/www/nybl/kiwi/node_modules/grunt-absurd/node_modules/absurd/lib/api/import.js:37:26)
There are many cases where selectors end up having no rules (either by not having, or by combining selectors, etc)
Example:
css['.system'] = {
'&:before': {
position: 'absolute',
color: 'red',
content: 'SS',
},
'&-shields': {
},
};
results in:
.system {
}
.system:before {
position: absolute;
color: red;
content: SS;
}
.system-shields {
}
Printing the empty .system {}
takes up spaces and has no real effect on the overall result (same for .system-shields
)
if you want to achieve the following, you have to write a rule for 'a': { ... }
and a separate rule for 'a.fancy': {}
which is not ideal given that you should be able to nest these:
a { color: red; }
a:hover { color: blue; }
a.fancy { color: green; }
one solution would be to have it LESS-style using the &
operator:
{
a: {
color: 'red',
':hover': { color: 'blue', }
'&.fancy': { color: 'green', }
}
}
Genaro Pinson: Hello Krasimir, thanks for this tool, I plan to somehow use this in Flex, my only problem is that this one converts camel casing to "dashed" format which is nice with HTML. If we could only toggle and have a flag to either use the "dashed" rule for html and not use it for Flex, I think this one can be very very useful in Flex as well. In my case, my ANT script to implement a LESS like approach to my Flex CSS is somehow very limited. With this tool, removing the camel case conversion I think , will make your awesome tool be very useful for Flex Developers .... doing that , you can help both Flex and HTML5 community.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.