Giter Club home page Giter Club logo

Comments (19)

johanstromqvist avatar johanstromqvist commented on September 12, 2024 4

Regarding easing:

  1. I haven't seen Excite, Overshoot and Anticipate being applied anywhere. Would it be possible to remove them? We want to avoid bezier curves with values <0 or >1 for now as they don't convey the measured and restrained style we're going for. We might want to add either of these in the future, but in that case with specific intention and documentation.

  2. I think the top three should either be called in-out, in and out to be more consistent, or default, disappear and appear to imply usage. I'm leaning to the latter. You should always be able to default to default and feel good about it.

  3. In POS Next and any other animation work I've done, I've been using these following timing functions. They have good buy-in and are likely to stick around. Reference.

Default (ease-in-out): cubic-bezier(0.4, 0.22, 0.28, 1)
Appear (ease-out): cubic-bezier(0, 0, 0.13, 1)
Disappear (ease-in): cubic-bezier(0.5, 0.1, 1, 1)

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024 3

We use base in our other tokens to indicate default. I think I prefer default, but I prefer consistency in naming more. How do we feel about base instead of default?

from polaris-tokens.

alex-page avatar alex-page commented on September 12, 2024 2

base feels like it grows or shrinks from this value. Which isn't always logically correct. I would prefer calling it default when it is default.

from polaris-tokens.

johanstromqvist avatar johanstromqvist commented on September 12, 2024 2

Is it meaningful to call all base/default values either base or default?

I think default is great as long as it's actually a default choice, i.e. when you don't know what token to choose, or if you don't have a specific reason to chose a specific one, you should be able to trust that default is a safe choice.

If that's not the case, then I don't think it should be called default.

A base font size from which all fonts scale doesn't make sense to call default imo. Base is a great name for that.

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024 2

Final

Review here: #76

BorderWidths

props:
  - name: borderWidth-1
    value: 1px
  - name: borderWidth-2
    value: 2px
  - name: borderWidth-3
    value: 3px
global:
  type: number
  category: sizing

Easings

props:
  - name: easing-default
    value: 'cubic-bezier(0.4, 0.22, 0.28, 1)'
  - name: easing-appear
    value: 'cubic-bezier(0, 0, 0.13, 1)'
  - name: easing-disappear
    value: 'cubic-bezier(0.5, 0.1, 1, 1)'
global:
  type: string
  category: easing

Radii

props:
  - name: radius-3
    value: 3px
  - name: radius-6
    value: 6px
global:
  type: number
  category: radius

Shadows

props:
  - name: shadow-faint
    value: '( 0 1px 0 0 rgba(22, 29, 37, 0.05), )'
  - name: shadow-default
    value: '( 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 3px 0 rgba(63, 63, 68, 0.15), )'
  - name: shadow-deep
    value: '( 0 0 0 1px rgba(6, 44, 82, 0.1), 0 2px 16px rgba(33, 43, 54, 0.08), )'
  - name: shadow-layer
    value: '( 0 31px 41px 0 rgba(32, 42, 53, 0.2), 0 2px 16px 0 rgba(32, 42, 54, 0.08), )'
  - name: shadow-transparent
    value: '0 0 0 0 transparent'
global:
  type: string
  category: drop-shadow

Sizes

props:
  - name: size-navigationWidth
    value: 240px
  - name: size-layoutWidth-oneHalf
    value: 450px
  - name: size-layoutWidth-oneThird
    value: 240px
  - name: size-layoutMinWidth-primary
    value: 480px
  - name: size-layoutMaxWidth-primary
    value: 662px
  - name: size-layoutMinWidth-secondary
    value: 240px
  - name: size-layoutMaxWidth-secondary
    value: 320px
  - name: size-pageIsPartiallyCondensed
    value: 450px
  - name: size-pageIsNotCondensed
    value: 680px
  - name: size-typographyIsCondensed
    value: 640px
  - name: size-navigationIsVisible
    value: 769px
global:
  type: number
  category: sizing

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024 1

Audit: Global data

Border radius

  • base: 3px
  • large: 6px

Border width

  • base: rem(1px)
  • thick: rem(2px)
  • thicker: rem(3px)

Border

  • base: border-width() solid color('sky')
  • dark: border-width() solid color('sky', 'dark')
  • transparent: border-width() solid transparent

Easing

  • base: cubic-bezier(0.64, 0, 0.35, 1)
  • in: cubic-bezier(0.36, 0, 1, 1)
  • out: cubic-bezier(0, 0, 0.42, 1)
  • excite: cubic-bezier(0.18, 0.67, 0.6, 1.22)
  • overshoot: cubic-bezier(0.07, 0.28, 0.32, 1.22)
  • anticipate: cubic-bezier(0.38, -0.4, 0.88, 0.65)

Shadows

  • faint: ( 0 1px 0 0 rgba(22, 29, 37, 0.05), )
  • base: ( 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 3px 0 rgba(63, 63, 68, 0.15), )
  • deep: ( 0 0 0 1px rgba(6, 44, 82, 0.1), 0 2px 16px rgba(33, 43, 54, 0.08), )
  • layer: ( 0 31px 41px 0 rgba(32, 42, 53, 0.2), 0 2px 16px 0 rgba(32, 42, 54, 0.08), )
  • transparent: 0 0 0 0 transparent

Line-height

  • caption-base: rem(20px)
  • caption-large-screen: rem(16px)
  • heading-base: rem(24px)
  • subheading-base: rem(16px)
  • input-base: rem(24px)
  • body-base: rem(20px)
  • button-base: rem(16px)
  • button-large-base: rem(20px)
  • display-x-large-base: rem(36px)
  • display-x-large-large-screen: rem(44px)
  • display-large-base: rem(28px)
  • display-large-large-screen: rem(32px)
  • display-medium-base: rem(28px)
  • display-medium-large-screen: rem(32px)
  • display-small-base: rem(24px)
  • display-small-large-screen: rem(28px)

Font-size

  • caption-base: rem(13px)
  • caption-large-screen: rem(12px)
  • heading-base: rem(17px)
  • heading-large-screen: rem(16px)
  • subheading-base: rem(13px)
  • subheading-large-screen: rem(12px)
  • input-base: rem(16px)
  • input-large-screen: rem(14px)
  • body-base: rem(15px)
  • body-large-screen: rem(14px)
  • button-base: rem(15px)
  • button-large-screen: rem(14px)
  • button-large-base: rem(17px)
  • button-large-large-screen: rem(16px)
  • display-x-large-base: rem(27px)
  • display-x-large-large-screen: rem(42px)
  • display-large-base: rem(24px)
  • display-large-large-screen: rem(28px)
  • display-medium-base: rem(21px)
  • display-medium-large-screen: rem(26px)
  • display-small-base: rem(16px)
  • display-small-large-screen: rem(20px)

Z-index

  • global-ribbon: 510
  • loading-bar: 511
  • top-bar: 512
  • context-bar: 513
  • small-screen-loading-bar: 514
  • nav-backdrop: 515
  • nav: 516
  • skip-to-content: 517
  • backdrop: 518
  • modal: 519
  • toast: 520
  • dev-ui: 521

from polaris-tokens.

kaelig avatar kaelig commented on September 12, 2024 1

About tokens that are component-specific (button, caption, input…): the question you'll want to ask is "do I really want to have to update an external dependency to be able to update that value in the Polaris React library?".

Without going too deep in the nuance of what Theo/Design Tokens can bring, in a nutshell: if you'd rather have control over it easily in Polaris React, or if nobody ever asked to this value to be available outside of Polaris React, then it should probably live in Polaris React.

from polaris-tokens.

alex-page avatar alex-page commented on September 12, 2024 1

My assumption is that the tokens are sensible defaults that can be overridden in polaris-react. polaris-tokens creates the structure and naming conventions, the values can be changed if necessary.

I am not sure if I assosiciate base with default. Maybe there could be something else?

Font sizes and z-index should just be done in a numeric way. Associating them with semantic values adds little value here.

I am also wondering about base, large, thick, thicker. These don't scale and I am unsure about what the future values could be added. It might be smart to move these to numeric values as well. I would look at other implementations of these values at scale. Theme specification is tried and tested. Some of the key values might be worth considering changing as well ( border-radius => radii makes it more useful in other situations ).

@johanstromqvist had some thoughts on the easing key name as well, last time I worked with him.

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

Audit: Global data already covered by tokens

  • Color
  • Duration
    • add $skeleton-shimmer-duration: duration(slower) * 2 ?
  • Filters
  • Spacing
  • Font-family

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

Audit: Utility

  • Color-multiply()
  • Ms-high-contrast-color()
  • Rem()
  • Px()
  • Em()
  • Available-names()

Audit: Shared

Accessibility

  • Visually-hidden

Button

  • high-contrast-button-outline
  • button-base
  • base-button-disabled
  • button-filled
  • button-filled-disabled
  • button-outline
  • button-outline-disabled
  • button-full-width
  • plain-button-background()
    • removed after color system
  • plain-button-backdrop
  • unstyled-button

Breakpoints

  • breakpoint()
  • page-content-breakpoint-before
  • page-content-breakpoint-after
  • breakpoint-after
  • breakpoint-before
  • frame-with-nav-when-not-max-width
  • page-when-not-max-width
  • page-content-when-layout-stacked
  • page-content-when-layout-not-stacked
  • page-content-when-partially-condensed
  • page-content-when-not-partially-condensed
  • page-content-when-fully-condensed
  • page-content-when-not-fully-condensed
  • frame-when-nav-displayed
  • frame-when-nav-hidden

Controls

  • control-backdrop

Forms

  • unstyled-input
  • range-track-selectors
  • range-thumb-selectors

Icons

  • recolor-icon
  • color-icon

Interaction State

  • state
    • removed after color system

Layout

  • layout-flex-fix
  • safe-area-for
  • after-topbar-sheet

Links

  • unstyled-link

Lists

  • unstyled-list

Page

  • page-padding-not-fully-condensed
  • page-padding-not-partially-condensed
  • page-layout
  • page-content-layout
  • page-title-layout
  • page-header-layout
  • page-header-has-navigation
  • page-header-without-navigation
  • page-header-has-secondary-actions
  • page-actions-layout

Printing

  • when-printing
  • when-not-printing
  • hidden-when-printing

Skeleton

  • skeleton-shimmer
  • skeleton-content
  • skeleton-page-secondary-actions-layout
  • skeleton-page-header-has-secondary-actions
  • skeleton-page-header-layout

Typography

  • when-typography-not-condensed (media query)
  • when-typography-condensed (media query)
  • text-style-caption
  • text-style-heading
  • text-style-subheading
  • text-style-input
  • text-style-body
  • text-style-button
  • text-style-button-large
  • text-style-display-x-large
  • text-style-display-large
  • text-style-display-medium
  • text-style-display-small
  • text-emphasis-placeholder
  • text-emphasis-subdued
  • text-emphasis-strong
  • text-emphasis-normal
  • text-breakword
  • truncate
  • print-hidden

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

Audit: Data used in component-specific mixins and functions

Layout

  • primary-min: rem(480px)
  • primary-max: rem(662px)
  • secondary-min: rem(240px)
  • secondary-max: rem(320px)
  • one-half-width-base: rem(450px)
  • one-third-width-base: rem(240px)
  • nav-base: rem(240px)
  • page-with-nav-base: rem(769px)
  • page-content-not-condensed: rem(680px)
  • page-content-partially-condensed: rem(450px)
  • inner-spacing-base: spacing()
    • alias, not very useful
  • outer-spacing-min: spacing(loose)
    • alias, not very useful
  • outer-spacing-max: spacing(extra-loose)
    • alias, not very useful

Breakpoints

(Each of these either represent math done on layout values, or em conversions of layout values, so they don't really need to be tokens)

  • page-max-width: layout-width(primary, max) + layout-width(secondary, max) + layout-width(inner-spacing)
  • frame-with-nav-max-width: layout-width(nav) + $page-max-width
  • stacked-content: em(layout-width(primary, min) + layout-width(secondary, min) + layout-width(inner-spacing))
  • not-condensed-content: em(layout-width(page-content, not-condensed))
  • partially-condensed-content: em(layout-width(page-content, partially-condensed))
  • not-condensed-outer-spacing: em(2 * layout-width(outer-spacing, max))
  • partially-condensed-outer-spacing: em(2 * layout-width(outer-spacing, min))
  • not-condensed-min-page: $not-condensed-content + $not-condensed-outer-spacing
  • partially-condensed-min-page: $partially-condensed-content + $partially-condensed-outer-spacing
  • nav-size: em(layout-width(nav))
  • nav-min-window: em(layout-width(page-with-nav))

Controls

  • control-height: rem(36px)
  • control-slim-height: rem(28px)
  • control-vertical-padding: (control-height() - line-height(input) - rem(2px)) / 2
    • math done on control height and line height
  • control-icon-transition: transform duration(fast) easing(in) easing(out)
    • alias for token values

Icons

  • icon-size: rem(20px)

Page

  • actions-vertical-spacing: spacing(tight)

Skeleton (actually thumbnail)

  • small-thumbnail-size: rem(40px)
  • medium-thumbnail-size: rem(60px)
  • large-thumbnail-size: rem(80px)

Typography

  • typography-condensed: em(640px) (used in breakpoints)

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

Audit: Component-specific

Badge

  • pip-color

Banner

  • banner-attributes
  • banner-variants

Navigation

  • nav()
  • nav-animation()
  • nav-item-attributes
  • nav-item-icon-attributes
  • nav-listitem-attributes
  • nav-item-text-attributes
  • usermenu-section-attributes

ResouceItem

  • action-hide
  • action-unhide

ResourceList

  • disabled-pointer-events
  • resource-list-overlay

SkeletonDisplayText

  • skeleton-display-text-height

SkeletonThumbnail

  • skeleton-thumbnail-size

Spinner

  • spinnerSize

Stack

  • stack-spacing

TextContainer

  • text-container-spacing

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

Questions

how do we handle returning rems without a rem function?

  • I think each component that returns rem or em modified units should return px and allow the modification to happen on the consumer side

how should we handle tokens that depend on other tokens?

  • unless the above applies, this feels like a smell that they should not be tokens, and are just aliases for combined token values that live in a project

should utility functions and shared mixins be deprecated and then undeprecated after sass API removal?

I really don't know how to handle this one

The plan is to duplicate all of our common mixins and functions (our internal Sass API) into a common directory, and use the _common file as the place to import all internal Sass from. We'll deprecate everything in the shared and foundation directories, but not the duplicates in common. That will stop us from seeing a mess of deprecation warnings in our internal work, but will warn consumers that these sass functions/mixins that they depend on will go away. The advice for them will be to use tokens where they can, and copy those functions/mixins into their project where they can't.

from polaris-tokens.

BPScott avatar BPScott commented on September 12, 2024

should utility functions and shared mixins be deprecated and then undeprecated after sass API removal?

I think we should eat our own dogfood and update our components to use the new tokens instead of the utility functions. At which point we're not using them internally and are free to delete the functions making them unavailable for external use when it comes to v5

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

I think we should eat our own dogfood and update our components to use the new tokens instead of the utility functions. At which point we're not using them internally and are free to delete the functions making them unavailable for external use when it comes to v5

I agree for things that tokens do well, like conveying constants (color, spacing, easing, duration, etc.) but for everything listed in this comment and this comment, we're not going to get anywhere close to tokens serving these functions (rem, em, px, etc., and all the component-specific and shared mixins). We can't get away from a lot of that Sass. So the question is geared towards what we do with those.

I agree that we should burn down everything tokens can do, and just use the tokens. But things like mixins and utility functions can't be done in tokens.

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

I had a 1:1 conversation with @BPScott to address this question:

should utility functions and shared mixins be deprecated and then undeprecated after sass API removal?

The plan is to duplicate all of our common mixins and functions (our internal Sass API) into a common directory, and use the _common file as the place to import all internal Sass from. We'll deprecate everything in the shared and foundation directories, but not the duplicates in common. That will stop us from seeing a mess of deprecation warnings in our internal work, but will warn consumers that these sass functions/mixins that they depend on will go away. The advice for them will be to use tokens where they can, and copy those functions/mixins into their project where they can't.

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

First pass at which values should be included in tokens, with proposed names

{
  "border-radius": {
    "base": "3px",
    "large": "6px"
  },
  "border-width": {
    "base": "1px",
    "thick": "2px",
    "thicker": "3px"
  },
  "easing": {
    "base": "cubic-bezier(0.64, 0, 0.35, 1)",
    "in": "cubic-bezier(0.36, 0, 1, 1)",
    "out": "cubic-bezier(0, 0, 0.42, 1)",
    "excite": "cubic-bezier(0.18, 0.67, 0.6, 1.22)",
    "overshoot": "cubic-bezier(0.07, 0.28, 0.32, 1.22)",
    "anticipate": "cubic-bezier(0.38, -0.4, 0.88, 0.65)"
  },
  "shadows": {
    "faint": "( 0 1px 0 0 rgba(22, 29, 37, 0.05), )",
    "base": "( 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 3px 0 rgba(63, 63, 68, 0.15), )",
    "deep": "( 0 0 0 1px rgba(6, 44, 82, 0.1), 0 2px 16px rgba(33, 43, 54, 0.08), )",
    "layer": "( 0 31px 41px 0 rgba(32, 42, 53, 0.2), 0 2px 16px 0 rgba(32, 42, 54, 0.08), )",
    "transparent": "0 0 0 0 transparent"
  },
  "line-height": {
    "body": "20px",
    "button": "16px",
    "buttonLarge": "20px",
    "caption": "20px",
    "caption-desktop": "16px",
    "displaySmall": "24px",
    "displaySmall-desktop": "28px",
    "displayMedium": "28px",
    "displayMedium-desktop": "32px",
    "displayLarge": "28px",
    "displayLarge-desktop": "32px",
    "displayExtraLarge": "36p",
    "displayExtraLarge-desktop": "44px",
    "heading": "24px",
    "input": "24px",
    "subheading": "16px"
  },
  "font-size": {
    "body": "15px",
    "body-desktop": "14px",
    "button": "15px",
    "button-desktop": "14px",
    "buttonLarge": "17px",
    "buttonLarge-desktop": "16px",
    "caption": "13px",
    "caption-desktop": "12px",
    "displaySmall": "16px",
    "displaySmall-desktop": "20px",
    "displayMedium": "21px",
    "displayMedium-desktop": "26px",
    "displayLarge": "24px",
    "displayLarge-desktop": "28px",
    "displayExtraLarge": "27px",
    "displayExtraLarge-desktop": "42px",
    "heading": "17px",
    "heading-desktop": "16px",
    "input": "16px",
    "input-desktop": "14px",
    "subheading": "13px",
    "subheading-desktop": "12px"
  },
  "z-index": {
    "backdrop": 518,
    "contextBar": 513,
    "devUi": 521,
    "globalRibbon": 510,
    "loadingBar": 514,
    "loadingBar-desktop": 511,
    "modal": 519,
    "nav": 516,
    "navBackdrop": 515,
    "skipToContent": 517,
    "toast": 520,
    "topBar": 512
  },
  "dimensions": {
    "navigationWidth": "240px",
    "layoutWidth-oneHalf": "450px",
    "layoutWidth-oneThird": "240px",
    "layoutMinWidth-primary": "480px",
    "layoutMaxWidth-primary": "662px",
    "layoutMinWidth-secondary": "240px",
    "layoutMaxWidth-secondary": "320px",
    "controlHeight": "36px",
    "controlHeight-slim": "28px"
  },
  "breakpoints": {
    "pageContent-isPartiallyCondensed": "450px",
    "pageContent-isNotCondensed": "680px",
    "typographyIsNotCondensed": "640px",
    "navigationIsVisible": "769px"
  }
}

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

@kaelig and @alex-page based on this feedback, I think our first round should include a smaller set of tokens. We'll omit values for font-size, and line-height for sure, since changing those in an external repo would be painful, and no one has necessarily asked for them to be shared. This will also allow us to make future decisions around themable/generative font sizes and line heights.

I've updated the key names to be more in line with Theme Specification, and have used numerical keys for radii and borderWidths. My concern with radii is that we only ever have two radius values, and that in the master brand, they change to 4 and 8. So a numeric system here may be setting us up for failure as it will imminently get new values.

I'm somewhat hesitant about even including zIndeces, since they are values that could change. My only rationale for including them is that web also uses them in building UIs that respect our stacking context. But I am leaning towards not including them in tokens. If we do include them, numeric names don't seem super useful, as they are literally tied to specific components in their application. I'm going to omit them for now, unless anyone has a strong rationale for including them.

Anything we don't include now, but add later, could be done in a minor release of tokens, so I feel safe starting with a limited set of tokens and reserving the right to expand at a future date.

Regarding the name base, it doesn't bother me much, and I don't think it should be associated with default. root would be my proposed alternative.

Proposed tokens and names round 2

{
  "radii": {
    3: "3px",
    6: "6px"
  },
  "borderWidths": {
    1: "1px",
    2: "2px",
    3: "3px"
  },
  "easing": {
    "base": "cubic-bezier(0.64, 0, 0.35, 1)",
    "in": "cubic-bezier(0.36, 0, 1, 1)",
    "out": "cubic-bezier(0, 0, 0.42, 1)",
    "excite": "cubic-bezier(0.18, 0.67, 0.6, 1.22)",
    "overshoot": "cubic-bezier(0.07, 0.28, 0.32, 1.22)",
    "anticipate": "cubic-bezier(0.38, -0.4, 0.88, 0.65)"
  },
  "shadows": {
    "faint": "( 0 1px 0 0 rgba(22, 29, 37, 0.05), )",
    "base": "( 0 0 0 1px rgba(63, 63, 68, 0.05), 0 1px 3px 0 rgba(63, 63, 68, 0.15), )",
    "deep": "( 0 0 0 1px rgba(6, 44, 82, 0.1), 0 2px 16px rgba(33, 43, 54, 0.08), )",
    "layer": "( 0 31px 41px 0 rgba(32, 42, 53, 0.2), 0 2px 16px 0 rgba(32, 42, 54, 0.08), )",
    "transparent": "0 0 0 0 transparent"
  },
  "sizes": {
    "navigationWidth": "240px",
    "layoutWidth-oneHalf": "450px",
    "layoutWidth-oneThird": "240px",
    "layoutMinWidth-primary": "480px",
    "layoutMaxWidth-primary": "662px",
    "layoutMinWidth-secondary": "240px",
    "layoutMaxWidth-secondary": "320px",
    "pageIsPartiallyCondensed": "450px",
    "pageIsNotCondensed": "680px",
    "typographyIsCondensed": "640px",
    "navigationIsVisible": "769px"
  }
}

from polaris-tokens.

danrosenthal avatar danrosenthal commented on September 12, 2024

base feels like it grows or shrinks from this value.

That makes perfect sense!

from polaris-tokens.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.