Comments (16)
@TravisSpomer In light of the recent comments on the reserved words issue (#61), I wonder if combination of the prefix idea there and what you've suggested could work:
Let's imagine for a moment we use a special prefix like $
or _
for all properties in our spec that have a special meaning (value, type, description, etc.) across both groups and tokens. Then we could have a "special" property on groups, for example $default
, that can be used when you want a token in that group which shares the same name in some contexts (e.g. when being exported as code).
So, it could look like this (if we assume _
as our universal reserved word prefix):
{
"color": {
"accent": {
"_default": {
"_type": "color",
"_value": "#dd0000"
},
"light": {
"_type": "color",
"_value": "#ff2222"
},
"dark": {
"_type": "color",
"_value": "#aa0000"
}
}
}
}
I've been thinking lately about the tree data model that our token files describe (similar to how HTML files define a DOM) and, in the context of this issue, was wondering if that default color token is logically a child of the accent group or a child of the color group. Personally, I'm leaning towards the latter. In this example it makes more sense to me to think of all 3 as accent colors, as opposed to 1 arbitrary color + 2 accent colors. It's just so happens that one of those accent colors doesn't need a further suffix appended to its name when exported as code.
I therefore like this kind of approach, where that default token is still something within the group. The hybrid approaches lift it up a level in the hierarchy and that doesn't feel right to me.
If we did something like _default
, I think it could referenced as {color.accent._default}
, but perhaps as a convenient shorthand you'd also be allowed to do {color.accent}
. The rule that parsers could follow could be that a reference pointing to a group would resolve to the _default
token in that group if it exists or be invalid otherwise.
But, I am intrigued by @TravisSpomer's desire to be able reference groups some day. I think there is a way that could co-exist with the _default
referencing shorthand I've just proposed. My reading of his example is that button.text
is actually a group referencing another group as a shortcut to create a batch of alias tokens.
So, rather than make the value of button.text
be something that looks like a token (since it has a value
property), why not do this:
{
"neutralcontrol": {
"foreground": {
"_type": "color",
"rest": { "_value": "#..." },
"hover": { "_value": "#..." },
"pressed": { "_value": "#..." },
"disabled": { "_value": "#..." }
},
"background": {
"_type": "color",
"rest": { "_value": "#..." },
"hover": { "_value": "#..." },
"pressed": { "_value": "#..." },
"disabled": { "_value": "#..." }
}
},
"button":
{
"text": {
// The value is no longer an object with a token property and therefore
// not a token. So, when a "bare" reference like this is encountered parsers
// are required to interpret it as a *group* reference.
"color": "{neutralcontrol.foreground}"
},
"base": {
"color": "{neutralcontrol.background}"
}
}
}
Even if {neutralcontrol.foreground}
contained a _default
token, parsers would know not treat the group reference as a shortcut to that default token. Instead, you'd get button.text.color._default
being an alias token for neutralcontrol.foreground._default
.
That could actually be quite nice if you'd prefer to use _default
instead of rest
in your naming:
{
"neutralcontrol": {
"foreground": {
"_type": "color",
"_default": { "_value": "#..." },
"hover": { "_value": "#..." },
"pressed": { "_value": "#..." },
"disabled": { "_value": "#..." }
},
"background": {
"_type": "color",
"_default": { "_value": "#..." },
"hover": { "_value": "#..." },
"pressed": { "_value": "#..." },
"disabled": { "_value": "#..." }
}
},
"button":
{
"text": {
// The value is no longer an object with a token property and therefore
// not a token. So, when a "bare" reference like this is encountered parsers
// are required to interpret it as a *group* reference.
"color": "{neutralcontrol.foreground}"
},
"base": {
"color": "{neutralcontrol.background}"
}
}
}
An export tool outputting SASS might then produce something along the lines of:
$neutralcontrol-foreground: #... ;
$neutralcontrol-foreground-hover: #...;
$neutralcontrol-foreground-pressed: #...;
// etc...
$button-text-color: $neutralcontrol-foreground;
$button-text-color-hover: $neutralcontrol-foreground-hover;
$button-text-color-pressed: $neutralcontrol-foreground-pressed;
// etc...
What do you think?
from community-group.
If all one cares about is the exported token's name, you could still achieve that pretty easily in the export process! Tokens are already necessarily getting renamed when exporting to code, to turn .
into -
, to change case, or so on. So you could just have a rule in your export that anything named "_"
or base
or default
or whatever gets dropped when exporting to SCSS.
color.accent.default
= #dd0000
→ $color-accent: #dd0000;
color.accent.light
= #ff2222
→ $color-accent-light: #ff2222;
color.accent.dark
= #aa0000
→ $color-accent-dark: #aa0000;
One scenario that's somewhat important to me for the future is group aliasing. For example:
{
"neutralcontrol": {
"foreground": {
"type": "color",
"rest": { "value": "{...}" },
"hover": { "value": "{...}" },
"pressed": { "value": "{...}" },
"disabled": { "value": "{...}" }
},
"background": {
"type": "color",
"rest": { "value": "{...}" },
"hover": { "value": "{...}" },
"pressed": { "value": "{...}" },
"disabled": { "value": "{...}" }
}
},
"button":
{
"text": {
"color": { "value": "{neutralcontrol.foreground}" }
},
"base": {
"color": { "value": "{neutralcontrol.background}" }
}
}
}
(In that example, button
has 8 tokens that just reference existing sets of colors that were designed to go together, so no accidentally mixing and matching incompatible sets. button.text.color.rest
= neutralcontrol.foreground.rest
, button.base.color.disabled
= neutralcolor.background.disabled
, and so on.)
It's not possible with today's spec, but I want to try to make sure it's possible someday. If neutralcolor.foreground
could have a value and be a group, then {neutralcolor.foreground}
becomes ambiguous. It's not a total blocker, but that's one reason I'm in favor of tokens and groups not being allowed to share a name.
from community-group.
Suggestion 2: Token and group hybrid
This is so interesting to see this suggestion because that exact idea has been something I’ve been mulling about for a while. I posted a comment in the theme discussion with a similar syntax, but I tried to format it according to previous comments.
Here’s one idea for your “hybrid” suggestion but with a syntax I’d prefer:
{
"color": {
"accent": {
"type": "color",
"value": "#dd0000",
"mode": {
"light": "#ff2222",
"dark": "#aa0000"
}
}
}
}
Note: mode
inherits type
from parent; it must be the same type and each value in the object is essentially another value
By namespacing it under mode
(idea), it hopefully resolves the reserved word issue. And the type
inheritance hopefully alleviates some complexity. But all just suggestions! I’m sure I’m missing something and there are likely tradeoffs to this idea.
from community-group.
If groups and tokens can share a name, my inclination is that the token/group hybrid is the right way to go.
However, I think we ought to hash out if it makes sense to allow groups and tokens to share a name. I feel like we end up making naming tokens a little more flexible at the cost of a lot of complexity in parsing/reading.
In our examples above, what is the value of color-accent
? In one sense, it's a group of two tokens named light
and dark
. In another sense, it's a token with the value of #dd0000
. In both reasoning about the system and using it, we'd run into a lot of challenges working with two distinct things called color-accent
.
I'd suggest that we keep things simple and lean on the requirement of unique keys within JSON to provide some guard rails.
Say you define the group like this
{
"color": {
"type": "group",
"value": {
"accent": {
"type": "group",
"value": {
"light": {
"type": "color",
"value": "#ff2222"
}, {
"dark": {
"type": "color",
"value": "#aa0000"
}
}
}
}
}
}
The color
group can only have one value for the key accent
. Since you've already defined it as a group, you can't re-use it for a color.
You do lose some flexibility in naming tokens, but gain a lot of precision.
from community-group.
@drwpow: I think the mode
thing you're proposing could be a good be a solution to theming, dark/light modes, etc. - essentially anything where a single token may have alternative values in certain contexts. However, what I was trying to describe in this issue is (at least in my mind) a different problem. I'm trying to define 3 distinct design tokens, but one of them happens to have a name that clashes with a group that contains the other 2.
Perhaps I chose the bad names for my example - the "light" and "dark" colors weren't intended as alternative values for light and dark mode, but rather just 2 extra colors. In hindsight, I probably should have used names like "tint" and "shade".
I'm less keen on the mode
approach as a way of doing a group/token hybrid as it's not clear to me how you'd put nested groups into it (after all, groups can contain groups as well as tokens) and/or tokens with their own, different types. I'd prefer something that keeps hybrids as close as possible to group and token's current syntax.
But, we should totally look into it for theming, dark/light modes, etc. - feel free to open an issue for that if you like, btw. It's a topic we'll need to address sooner or later.
from community-group.
My reading of his example is that button.text is actually a group referencing another group as a shortcut to create a batch of alias tokens.
Yes, precisely.
The system I'm using right now already has groups and aliases to groups implemented, and I'd say that it's partly-successful: It definitely does achieve its goal of allowing easier reuse of groups of tokens, but about half of people find the concept confusing, and it's not split down engineer-or-designer lines. Some designers find groups intuitive, but the one currently in charge of our design system finds them hopelessly complicated. Most engineers grasp the idea easily, but some are resistant because they keep thinking that it's something they'll need to support at runtime instead of getting "compiled out."
from community-group.
I'm mostly just toying with two different approaches to the group syntax, which may necessitate a separate issue. So I'm gonna open up a new discussion to continue that thread to keep things on-topic here.
I do want to be direct about the question: should we allow a group and a token to have the same name?
In once sense, it makes it slightly easier to organize your tokens if you like to have things like accent
and accent.light
both refer to tokens.
However, it might make it very difficult to talk about (and parse) the thing called accent
. Are you talking about the accent group, or the accent token? Say you wanted to compile the accent token into one file, but the contents of the accent group into a different file? I think it'd be a bit fuzzy as to the right way to do that.
I'd love to try and motivate the requirement that tokens and groups should be able to share a name before going deep on solving it - but please excuse me if that conversation was had in an editors meeting.
from community-group.
To get the ball rolling, I'll outline a workaround and some potential approaches:
Work around
Authors can side-step the issue by not using a group. The example in the issue description could just put all 3 tokens into the "color" group and not have an "accent" group at all:
{
"color": {
"accent": {
"type": "color",
"value": "#dd0000"
},
"accent-light": {
"type": "color",
"value": "#ff2222"
},
"accent-dark": {
"type": "color",
"value": "#aa0000"
}
}
}
While this works, it's not ideal. Part of the benefit of groups is that avoids having to repeat common prefixes in names, such as "accent" in this example. By using this work-around authors miss out on that benefit.
Also, groups can have their own descriptions (and potentially other properties future spec versions may add), so by using this work-around authors lose the ability to add such descriptive information to all the "accent*" tokens as there is no "accent" group anymore.
Suggestion 1: Empty name token
It turns out that an empty string ""
is a valid name in JSON. Authors could therefore do the following:
{
"color": {
"accent": {
"": {
"type": "color",
"value": "#dd0000"
},
"light": {
"type": "color",
"value": "#ff2222"
},
"dark": {
"type": "color",
"value": "#aa0000"
}
}
}
}
Since this apprach retains the "accent" group, authors can add things like a description to that group and that would be indendent of any description they give the "" token itself. For example:
{
"color": {
"accent": {
"description": "Our brand's accent color and its tints & shades",
"": {
"type": "color",
"value": "#dd0000",
"description": "Our brand's accent color"
},
"light": {
"type": "color",
"value": "#ff2222",
"description": "Tinted version of our brand's accent color"
},
// ...
}
}
}
There is actually nothing in the current spec draft that forbids this. However, if you wanted to alias the "color" / "accent" / "" token, the reference would need to be {color.accent.}
(note the trailing period .
). Without the period at the end, the reference would be pointing to the group, but we don't allow that (reference must always point to tokens).
Such reference might look a bit odd and are perhaps unintuitive. For convenience we may therefore want to modify our spec to have a rule stating that a reference that points to a group should be interpreted a pointing to a token with an empty name (""
) within that group. So, if such a token exists the reference is valid and otherwise it is not. That way {color.accent}
would be a valid reference.
Suggestion 2: Token and group hybrid
In the current spec draft, groups and tokens are two very distinct concepts. Only tokens have values and only groups can contain tokens and other groups.
What if we allowed hybrids that are both token and group at the same time. They'd have a value (like a token), but could also contain other tokens or groups.
Our example might then become something like this:
{
"color": {
"accent": {
"type": "color",
"value": "#dd0000",
"light": {
"type": "color",
"value": "#ff2222"
},
"dark": {
"type": "color",
"value": "#aa0000"
}
}
}
}
While this may seem quite elegant, it does introduce some challenges:
- How do we allow separate descriptions (or other "special" properties) for the group and token that make up the hybrid?
- Currently the
type
property on a group acts as a default type for any tokens within that group - the group itself doesn't actually have a type. Therefore, how do we allow authors to specify a separate group (default) type and token type for the hybrid? - This potentially increases the number of reserved words that cannot be used as group or token names. Every property that is allowed for tokens (
value
,type
,description
,extensions
and whatever else we may add in future) must necessarily also be a reserved word within groups, since every group has the potential to be a hybrid.
You could resolve the first 2 challenges by have group-specific property names that don't clash with their token equivalents (e.g. group-description
, group-type
etc.), but that then means there even more reserved words.
For example, you might end up with something like this:
{
"color": {
// "accent" is a group & token hybrid
"accent": {
// "accent" group special props
"group-description": "Our brand's accent color and its tints & shades",
// "accent" token special props
"type": "color",
"value": "#dd0000",
"description": "Our brand's accent color"
// "light", "dark" etc. are items in the "accent" group as per usual
"light": {
"type": "color",
"value": "#ff2222",
"description": "Tinted version of our brand's accent color"
},
// ...
}
}
}
I'm sure there's other pros/cons and approaches too. So, let's hear 'em! :-)
from community-group.
@ilikescience So, if I've understood your example you're proposing that we alter the syntax of groups to be more token-like? I.e. rather than just a JSON object where any properties are treated as the names of the nested tokens/groups (with the exception of a few reserved ones like description
), the need to have a type
property set to "group" and a value
, which is then an object containing the items in that group. Is that right?
If so, I'm not sure what that provides over the current draft spec. I'd argue we already have a precise way of differentiating between groups and tokens - any object with a value
key must be a token (and all its other properties are then interpreted accordingly) and otherwise it must be a group (and gets interpreted accordingly).
It doesn't appear to solve the issue - i.e. there's no way of have "color.accent" somehow be a color that is distinct from "color.accent.light / dark".
Please do correct me, if I've misunderstood though!
from community-group.
Going slightly (more) off-topic, it occurs to me that it might be nice to for "bare" references to also be usable as a shorthand for creating alias tokens. For example:
{
"some-group": {
"original-token": {
"value": "2rem",
"type": "dimension"
}
},
// What we already know and love...
"long-hand-alias": {
"value": "{some-group.original-token}"
},
// ...could be equivalent to:
"short-hand-alias": "{some-group.original-token}"
}
However, then we'd still need to find a way to reference groups. So maybe there's a slight extension to the reference syntax to allow that:
{
"neutralcontrol": {
"foreground": {
"_type": "color",
"_default": { "_value": "#..." },
"hover": { "_value": "#..." },
"pressed": { "_value": "#..." },
"disabled": { "_value": "#..." }
}
},
"button": {
"text": {
"color": "{neutralcontrol.foreground.*}", // notice the .* at the end!
// and the above is basically a short-hand for doing this:
"color-longhand": {
"_default": { "_value": "{neutralcontrol.foreground}" },
"hover": { "_value": "{neutralcontrol.foreground.hover}" },
"pressed": { "_value": "{neutralcontrol.foreground.pressed}" },
"disabled": { "_value": "{neutralcontrol.foreground.disabled}" }
}
}
}
}
Probably none of this stuff will be in our initial spec, but the more I think about it, the more I'd like something like this to be possible in the future!
from community-group.
I'd love to try and motivate the requirement that tokens and groups should be able to share a name before going deep on solving it - but please excuse me if that conversation was had in an editors meeting.
Good question. It certainly wasn't discussed in any depth and may well be an edge case we don't need to make special accommodations for.
My (vague) recollection is that @dbanksdesign once mentioned folks trying to achieve something similar in Style Dictionary. I've just been through their old issues and found this one where someone wanted to do this (and interestingly used DEFAULT
as the name): amzn/style-dictionary#716
So, if this is something folks want to do, it would be nice if our format's spec had an official answer for how to do it - even it's just some kind of work-around rather than a first class feature of the format.
At our last format editor's meeting I suggested opening an issue for this now as this discussion might help inform the ongoing reserved words discussion (#61). My hunch was this might highlight the need for an additional group-level property and that in turn would potentially be new reserved word we'd need to accommodate somehow.
from community-group.
about half of people find the concept confusing, and it's not split down engineer-or-designer lines.
That's really interesting! Thanks for sharing.
Makes me think there could be a market for DCTG file linters someday. People already use things like ESLint and Stylelint to enforce their organisations coding standards. Perhaps one day an equivalent will exist for our spec's file format. Then, if one organisation or team finds group aliases confusing they could discourage their use by configuring their linter to flag it (and suggest creating several token aliases as an alternative).
from community-group.
@c1rrus thanks for the clarification! I see the use case and I also want to see if we can accommodate it if possible.
The hard part for me is that the thing (say, color.accent
) should be formatted and behave like a token when it's used as a token, and be formatted and behave like a group when it's used as a group.
So, say we were working with color.accent
as a token. The spec currently defines a token as an object with a "value" property, so we should expect color.accent
to have a value
. So far, none of the examples we've explored meet this expectation!
Next, we work with color.accent
as a group - say, put its children into their own css file when translating to css. This is an easier case since there's no real format requirements for a group - but since any object can be a token or a group, the parser will essentially have to ask "are there any items in this object that aren't reserved words?" — iteratively! — before concluding that it's safe to move back up the tree.
Thinking through this now, I see how some of the things we've discussed resolve the bulk of the issue. Especially _default
(or something like that) — _default
should be a regular old token with a value
(as you've shown).
I do think that these cases outline one argument for why groups should have "_type": "group"
— if they didn't, a parser would have to do some extra work to figure out how to work with the object or token. It isn't a world-ending requirement, and it's definitely a tradeoff either way. I'm going to open my group formatting issue so we can explore further.
from community-group.
Ok, returning to this after having some experience with trying to parse larger token files, I think some kind of explicit key is necessary. The main reason is that groups can have properties that are named the same as tokens. For example:
{
"color": {
"$type": "color",
"$description": "lorem ipsum",
"$value": "blue",
"primary": {
"$value": "red"
}
}
}
In this example, it's unclear if the "$type" at the root applies to the root token, "color" (blue) or is intended to cascade down to child tokens like "color.primary". Same with description; is it a description for the group? or a description of the root token?
So, I'd like to recommend the following change to the group format:
"groupName": {
"$type": "..." // optional type that can be inherited by children
"$description": "..." // optional description of the group
"$rootToken": {} // optional root token
"$extensions": {} // optional extensions as usual
"childName": {} // required, can be a group or a token.
}
I'm open to other names, but I chose "rootToken" to be very explicit that this should be a token that is associated with the root of the group. I also considered "root" and "base". I deliberately avoided "default", as this doesn't quite make sense grammatically — a default implies options, which isn't how groups work.
from community-group.
Just wanted to chime in briefly here to say that I'm experimenting with setting up design tokens using the DTCG format, and our current color variables are set up something like this:
:root {
--color-gray: var(--color-gray-50);
--color-gray-10: hsl(214deg, 15%, 10%);
--color-gray-20: hsl(214deg, 15%, 20%);
--color-gray-30: hsl(214deg, 15%, 30%);
--color-gray-40: hsl(214deg, 15%, 40%);
--color-gray-50: hsl(214deg, 15%, 50%);
}
My first intuition was to try to replicate this by using $value
, without worrying about the reference/alias to start with:
{
"color": {
"$type": "color",
"base": {
"gray": {
"$value": "#6c7d93"
"10" : { "$value": "#16191d" },
"15": { "$value": "#21252c" },
"20" : { "$value": "#2b323b" },
"30" : { "$value": "#414b58" },
"40" : { "$value": "#576475" },
"50" : { "$value": "#6c7d93" }
},
}
}
}
This does not work in style-dictionary, so I came here and found this issue. I think it would be great to have some kind of guidance on how to accomplish this. I don't have strong opinions on how it should be done or the various tradeoffs, but what I posted above was the most intuitive for me personally. I'm just getting started with this, so I thought I'd share my "beginner mindset" in case that's useful. :)
from community-group.
@IanVS I don't think parsers like Style Dictionary support a top-level variable and nested variables inside. It's either one or the other.
If I had to guess it's probably an issue with some exports, like the JS object syntax used by CSS in JS platforms. If you had a top-level variable defined, you couldn't also have an array of child elements, one would override the other.
{
colors: {
// It can't be a string and object at same time
gray: "#6c7d93",
gray: {
10: "#16191d",
},
},
}
You'd have to do something like this and make your top level gray something like --color-gray-0
:
{
"color": {
"$type": "color",
"base": {
"gray": {
"0": { "$value": "#6c7d93" },
"10" : { "$value": "#16191d" },
"15": { "$value": "#21252c" },
"20" : { "$value": "#2b323b" },
"30" : { "$value": "#414b58" },
"40" : { "$value": "#576475" },
"50" : { "$value": "#6c7d93" }
},
}
}
}
This kind of pattern happens more often with variants and component/composite tokens. It's easy to want to do a button.background
and then a button.background.disabled
-- but that causes similar collisions. So it's best to name the "default" state as something (usually default, initial, etc): button.background
becomes button.background.default
.
To acknowledge the discussion: I'm not sure how having a group type would resolve the consolidation of the tokens into variables. Unless each variable is unique (like CSS exports, where you get individual --color-gray
names -- or individual JS var export like const colorGray
and const colorGray10
), this system won't work with parsers like Style Dictionary.
For example, I wanted to theme the gray colors, this definitely works with individual variables:
// Dark theme
export const colorGray = "#6c7d93";
export const colorGray10 = "#16191d";
Then I could use these inside my project:
import lightTheme from "./dark"
import darkTheme from "./dark"
const theme = isDarkMode ? darkTheme : lightTheme;
But if I had an object based syntax, this doesn't work.
And ideally the goal of these tokens would be to be used across all -- if not most platforms? So I feel like this would just always conflict with dynamic languages like JS and the common practice of theming (like CSS in JS).
If it were supported, there'd definitely have to be some sort of guidelines for parsers to understand that groups would only be supported in "split variable" contexts. This way they could throw an error to help user understand why the tokens aren't properly reflected in more dynamic contexts (e.g. JS object syntax, SASS maps, etc).
from community-group.
Related Issues (20)
- Define how far design tokens are expected to be interoperable. HOT 1
- Remove REM/EM from specification? HOT 26
- Error in Font Weight example in spec?
- Standardizing the Handoff - Conceptual HOT 10
- Extensible Types HOT 2
- grid type HOT 6
- Specification / recommendation for custom types HOT 4
- Token Operations
- The $ property name prefix should be unnecessary with a well-structured schema HOT 10
- [Discussion]: How to transform composite tokens HOT 5
- Transition token documentation issue HOT 1
- Suggestion: colorList type for DataViz HOT 6
- Most recent edition (07/2023) missing from main page on w3c community group HOT 1
- A comment about history of design tokens HOT 2
- Type: Text alignment HOT 12
- Custom Types / Interpritations HOT 2
- Is there a way to still include boolean and string type functionality? HOT 1
- Be explicit about whether or not empty groups are allowed HOT 5
- Alias $type inheritance? HOT 7
- [Meta] Do functions/transforms happen before tokens.json (i.e. to generate it)? Or within tokens.json? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from community-group.