├── site
├── .nvmrc
├── gatsby-ssr.js
├── gatsby-browser.js
├── static
│ ├── _redirects
│ ├── card.png
│ ├── etsy.jpg
│ └── topoink.png
├── netlify.toml
├── postcss.config.js
├── raw
│ ├── 1x
│ │ ├── twitter.png
│ │ └── twitter-100.jpg
│ └── SVG
│ │ ├── circlewhitecircle.svg
│ │ ├── mask.svg
│ │ ├── serious mouth.svg
│ │ ├── capback.svg
│ │ ├── bgcircle.svg
│ │ ├── sad mouth.svg
│ │ ├── longhair.svg
│ │ ├── longhairback.svg
│ │ ├── beanieback.svg
│ │ ├── sadmouth.svg
│ │ ├── vue.svg
│ │ ├── gatsby.svg
│ │ ├── longhairfront.svg
│ │ ├── seriouseyebrows.svg
│ │ ├── happy.svg
│ │ ├── content.svg
│ │ ├── lashes.svg
│ │ ├── grin.svg
│ │ ├── knockedout.svg
│ │ ├── hairshort.svg
│ │ ├── simpleyes.svg
│ │ ├── angry eyebrows.svg
│ │ ├── oooooo.svg
│ │ ├── normal eyebrows.svg
│ │ ├── leftloweredeyebrow.svg
│ │ ├── bobback.svg
│ │ ├── dressfront.svg
│ │ ├── lefteyebrowlowered.svg
│ │ ├── opensmile.svg
│ │ ├── concernedeyebrows.svg
│ │ ├── sad.svg
│ │ ├── graphql.svg
│ │ ├── tongue.svg
│ │ ├── longhairfront_1.svg
│ │ ├── wink.svg
│ │ ├── stubble.svg
│ │ ├── dressback.svg
│ │ ├── tinyglasses.svg
│ │ ├── afro_front.svg
│ │ ├── roundglasses.svg
│ │ ├── normal eyes.svg
│ │ ├── redwood.svg
│ │ ├── lips.svg
│ │ ├── tanktop.svg
│ │ ├── breastsfront.svg
│ │ ├── shorthair.svg
│ │ ├── buzzcut.svg
│ │ ├── hearteyes.svg
│ │ ├── afro_back.svg
│ │ ├── react.svg
│ │ ├── shades.svg
│ │ ├── vneck.svg
│ │ ├── capfront.svg
│ │ ├── lefttwitcheye.svg
│ │ ├── twitch.svg
│ │ ├── squinteyes.svg
│ │ ├── baldinghair.svg
│ │ ├── breasts.svg
│ │ ├── eyeswithlashes.svg
│ │ └── shirt.svg
├── src
│ ├── images
│ │ └── favicon.png
│ ├── index.css
│ ├── components
│ │ ├── SlotMachine.tsx
│ │ ├── SEO.tsx
│ │ └── Hero.tsx
│ ├── pages
│ │ ├── 404.tsx
│ │ └── index.tsx
│ └── utils
│ │ └── getRandomOptions.ts
├── tailwind.config.js
├── tsconfig.json
├── gatsby-config.js
├── package.json
├── .gitignore
└── functions
│ └── svg
│ └── svg.js
├── tsconfig.json
├── demo
└── demo.gif
├── core
├── .gitignore
├── src
│ ├── components
│ │ ├── hats
│ │ │ └── types.ts
│ │ ├── eyes
│ │ │ ├── types.ts
│ │ │ ├── HappyEyes.tsx
│ │ │ ├── SimpleEyes.tsx
│ │ │ ├── ContentEyes.tsx
│ │ │ ├── Lashes.tsx
│ │ │ ├── DizzyEyes.tsx
│ │ │ ├── Wink.tsx
│ │ │ ├── NormalEyes.tsx
│ │ │ ├── HeartEyes.tsx
│ │ │ ├── LeftTwitchEyes.tsx
│ │ │ └── SquintEyes.tsx
│ │ ├── facialHair
│ │ │ ├── types.ts
│ │ │ └── Stubble.tsx
│ │ ├── mouths
│ │ │ ├── types.ts
│ │ │ ├── SeriousMouth.tsx
│ │ │ ├── Grin.tsx
│ │ │ ├── OpenMouth.tsx
│ │ │ ├── SmileOpen.tsx
│ │ │ ├── Sad.tsx
│ │ │ ├── Tongue.tsx
│ │ │ └── Lips.tsx
│ │ ├── hair
│ │ │ ├── types.ts
│ │ │ ├── LongHair.tsx
│ │ │ ├── ShortHair.tsx
│ │ │ └── BuzzCut.tsx
│ │ ├── bodies
│ │ │ ├── types.ts
│ │ │ └── Chest.tsx
│ │ ├── clothing
│ │ │ ├── types.ts
│ │ │ ├── TankTop.tsx
│ │ │ ├── Dress.tsx
│ │ │ └── VNeck.tsx
│ │ ├── Mask.tsx
│ │ ├── BgCircle.tsx
│ │ ├── clothingGraphic
│ │ │ ├── Vue.tsx
│ │ │ ├── Gatsby.tsx
│ │ │ ├── GraphQL.tsx
│ │ │ └── Redwood.tsx
│ │ ├── eyebrows
│ │ │ ├── SeriousEyebrows.tsx
│ │ │ ├── AngryEyebrows.tsx
│ │ │ ├── ConcernedEyebrows.tsx
│ │ │ ├── Normal.tsx
│ │ │ └── LeftLoweredEyebrows.tsx
│ │ ├── accessories
│ │ │ ├── TinyGlasses.tsx
│ │ │ ├── RoundGlasses.tsx
│ │ │ └── Shades.tsx
│ │ └── FaceMask.tsx
│ ├── utils
│ │ └── Noop.tsx
│ ├── index.tsx
│ ├── themeContext.tsx
│ └── theme.ts
├── tsconfig.json
├── package.json
├── .github
│ └── workflows
│ │ └── main.yml
├── LICENSE
└── exportParts.js
├── prettier.config.js
├── LICENSE
└── .gitignore
/site/.nvmrc:
--------------------------------------------------------------------------------
1 | v16
--------------------------------------------------------------------------------
/site/gatsby-ssr.js:
--------------------------------------------------------------------------------
1 | import './src/index.css'
2 |
--------------------------------------------------------------------------------
/site/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | import './src/index.css'
2 |
--------------------------------------------------------------------------------
/site/static/_redirects:
--------------------------------------------------------------------------------
1 | /svg /example.svg 200
2 | /* /index.html 200
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "."
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/demo/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/demo/demo.gif
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | *.zip
3 | .DS_Store
4 | node_modules
5 | .cache
6 | dist
7 | parts
--------------------------------------------------------------------------------
/core/src/components/hats/types.ts:
--------------------------------------------------------------------------------
1 | export interface HatProps {
2 | scale?: number
3 | }
4 |
--------------------------------------------------------------------------------
/core/src/components/eyes/types.ts:
--------------------------------------------------------------------------------
1 | export interface EyeProps {
2 | withLashes?: boolean
3 | }
4 |
--------------------------------------------------------------------------------
/core/src/utils/Noop.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Noop = () => <>>
4 |
--------------------------------------------------------------------------------
/site/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | functions = "functions"
3 |
4 | [dev]
5 | command = "yarn dev"
--------------------------------------------------------------------------------
/site/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = () => ({
2 | plugins: [require('tailwindcss')],
3 | })
4 |
--------------------------------------------------------------------------------
/site/static/card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/static/card.png
--------------------------------------------------------------------------------
/site/static/etsy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/static/etsy.jpg
--------------------------------------------------------------------------------
/site/raw/1x/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/raw/1x/twitter.png
--------------------------------------------------------------------------------
/site/static/topoink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/static/topoink.png
--------------------------------------------------------------------------------
/site/raw/1x/twitter-100.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/raw/1x/twitter-100.jpg
--------------------------------------------------------------------------------
/site/src/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RobertBroersma/beanheads/HEAD/site/src/images/favicon.png
--------------------------------------------------------------------------------
/core/src/components/facialHair/types.ts:
--------------------------------------------------------------------------------
1 | import { colors } from '../../theme'
2 |
3 | export interface FacialHairProps {
4 | color: keyof typeof colors.hair
5 | }
6 |
--------------------------------------------------------------------------------
/core/src/components/mouths/types.ts:
--------------------------------------------------------------------------------
1 | import { colors } from '../../theme'
2 |
3 | export interface MouthProps {
4 | lipColor?: keyof typeof colors.lipColors
5 | }
6 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 2,
3 | singleQuote: true,
4 | trailingComma: 'all',
5 | semi: false,
6 | arrowParens: 'avoid',
7 | }
8 |
--------------------------------------------------------------------------------
/core/src/components/hair/types.ts:
--------------------------------------------------------------------------------
1 | import { colors } from '../../theme'
2 |
3 | export interface HairProps {
4 | hairColor: keyof typeof colors.hair
5 | hasHat?: boolean
6 | }
7 |
--------------------------------------------------------------------------------
/core/src/components/bodies/types.ts:
--------------------------------------------------------------------------------
1 | import { colors } from '../../theme'
2 |
3 | export interface BodyProps {
4 | clothingColor: keyof typeof colors.clothing
5 | braStraps: boolean
6 | }
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/circlewhitecircle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/src/components/clothing/types.ts:
--------------------------------------------------------------------------------
1 | import { colors } from '../../theme'
2 |
3 | export interface ClothingProps {
4 | color: keyof typeof colors.clothing
5 | graphic?: React.ComponentType
6 | }
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/mask.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/site/raw/SVG/serious mouth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as theme from './theme'
2 |
3 | export { theme }
4 | export * from './components/Avatar'
5 | export { Avatar as BeanHead } from './components/Avatar'
6 |
7 | export { ThemeContext } from './themeContext'
8 |
9 | export { Noop } from './utils/Noop'
10 |
--------------------------------------------------------------------------------
/core/src/themeContext.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 | import { colors } from './theme'
3 |
4 | export const ThemeContext = React.createContext({
5 | colors,
6 | skin: colors.skin.light,
7 | })
8 |
9 | export const useTheme = () => useContext(ThemeContext)
10 |
--------------------------------------------------------------------------------
/site/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: ['./src/**/*.js', './src/**/*.jsx', './src/**/*.ts', './src/**/*.tsx'],
3 | theme: {
4 | extend: {},
5 | fontFamily: {
6 | sans: ['Jost', 'sans-serif'],
7 | },
8 | },
9 | variants: {},
10 | plugins: [],
11 | }
12 |
--------------------------------------------------------------------------------
/site/raw/SVG/capback.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/raw/SVG/bgcircle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/src/components/Mask.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Mask = ({ id }: { id: string }) => {
4 | return (
5 |
6 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/site/raw/SVG/sad mouth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/raw/SVG/longhair.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/site/raw/SVG/longhairback.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/src/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Jost:wght@400;600&display=swap');
2 |
3 | @tailwind base;
4 |
5 | @tailwind components;
6 |
7 | @tailwind utilities;
8 |
9 | body {
10 | @apply font-sans;
11 | }
12 |
13 | .underline-blue {
14 | text-decoration-color: #63b3ed;
15 | }
16 |
17 | .underline-blue:hover {
18 | color: #4299e1;
19 | text-decoration-color: #4299e1;
20 | }
21 |
--------------------------------------------------------------------------------
/site/raw/SVG/beanieback.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/raw/SVG/sadmouth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/site/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "esnext",
5 | "jsx": "preserve",
6 | "lib": ["dom", "esnext"],
7 | "strict": true,
8 | "noEmit": true,
9 | "isolatedModules": true,
10 | "esModuleInterop": true,
11 | "noUnusedLocals": false,
12 | "strictNullChecks": true,
13 | "allowJs": true
14 | },
15 | "exclude": ["node_modules", "public", ".cache"]
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/components/BgCircle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../themeContext'
3 | import { colors } from '../theme'
4 |
5 | export interface BgCircleProps {
6 | circleColor: keyof typeof colors.bgColors
7 | }
8 |
9 | export const BgCircle = ({ circleColor }: BgCircleProps) => {
10 | const { colors } = useTheme()
11 |
12 | const color = colors.bgColors[circleColor]
13 |
14 | return
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/components/mouths/SeriousMouth.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const SeriousMouth = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/site/raw/SVG/vue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/site/raw/SVG/gatsby.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/site/raw/SVG/longhairfront.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/site/raw/SVG/seriouseyebrows.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/happy.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/components/clothingGraphic/Vue.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const Vue = () => {
4 | return (
5 | <>
6 |
12 |
16 |
20 | >
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/site/raw/SVG/content.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/lashes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src", "types"],
3 | "compilerOptions": {
4 | "module": "esnext",
5 | "lib": ["dom", "esnext"],
6 | "importHelpers": true,
7 | "declaration": true,
8 | "sourceMap": true,
9 | "rootDir": "./src",
10 | "strict": true,
11 | "noUnusedLocals": true,
12 | "noUnusedParameters": true,
13 | "noImplicitReturns": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "moduleResolution": "node",
16 | "baseUrl": "./",
17 | "paths": {
18 | "*": ["src/*", "node_modules/*"]
19 | },
20 | "jsx": "react",
21 | "esModuleInterop": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/site/src/components/SlotMachine.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useCallback, useEffect } from 'react'
2 | import { BeanHead } from 'beanheads'
3 |
4 | export function SlotMachine({
5 | interval = 300,
6 | pause = false,
7 | }: {
8 | interval?: number
9 | pause?: boolean
10 | }) {
11 | const [rerender, set] = useState(0)
12 |
13 | const forceRerender = useCallback(() => {
14 | set(a => a + 1)
15 | }, [])
16 |
17 | useEffect(() => {
18 | const timeout = setTimeout(
19 | forceRerender,
20 | rerender % 15 === 0 && pause ? 2000 : interval,
21 | )
22 |
23 | return () => clearTimeout(timeout)
24 | }, [rerender, interval])
25 |
26 | return
27 | }
28 |
--------------------------------------------------------------------------------
/site/raw/SVG/grin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/site/raw/SVG/knockedout.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/hairshort.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/simpleyes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/angry eyebrows.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/components/eyebrows/SeriousEyebrows.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const SeriousEyebrows = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/site/raw/SVG/oooooo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/src/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'gatsby'
3 | import { BeanHead } from 'beanheads'
4 | import { SEO } from '../components/SEO'
5 |
6 | function NotFound() {
7 | return (
8 | <>
9 |
10 |
11 |
12 |
18 |
19 |
Page Not Found
20 |
21 | Go Home
22 |
23 |
24 | >
25 | )
26 | }
27 |
28 | export default NotFound
29 |
--------------------------------------------------------------------------------
/site/raw/SVG/normal eyebrows.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/components/eyes/HappyEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const HappyEyes = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
17 |
25 | >
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/components/eyes/SimpleEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const SimpleEyes = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
10 |
14 |
15 |
19 | >
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/site/raw/SVG/leftloweredeyebrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/components/eyes/ContentEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const ContentEyes = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
17 |
25 | >
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/site/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | title: 'Bean Heads',
4 | titleTemplate: '%s · Easily generate avatars for your projects',
5 | description:
6 | 'Combine expressions, clothing, hair styles and colors into billions of different unique characters.',
7 | url: 'https://beanheads.robertbroersma.com',
8 | // TODO:
9 | image: '/card.png', // Path to your image you placed in the 'static' folder
10 | twitterUsername: '@robertbrosma',
11 | },
12 | plugins: [
13 | 'gatsby-plugin-typescript',
14 | 'gatsby-plugin-postcss',
15 | // {
16 | // resolve: 'gatsby-plugin-manifest',
17 | // options: {
18 | // icon: 'src/images/favicon.png',
19 | // },
20 | // },
21 | 'gatsby-plugin-react-helmet',
22 | {
23 | resolve: 'gatsby-plugin-google-analytics',
24 | options: {
25 | trackingId: 'UA-176816069-1',
26 | },
27 | },
28 | ],
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/components/eyes/Lashes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const RightLash = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 |
13 | )
14 | }
15 |
16 | export const LeftLash = () => {
17 | const { colors } = useTheme()
18 |
19 | return (
20 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/components/eyebrows/AngryEyebrows.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const AngryEyebrows = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.3.3",
3 | "license": "MIT",
4 | "main": "dist/index.js",
5 | "typings": "dist/index.d.ts",
6 | "files": [
7 | "dist",
8 | "src"
9 | ],
10 | "engines": {
11 | "node": ">=10"
12 | },
13 | "scripts": {
14 | "start": "tsdx watch",
15 | "build": "tsdx build",
16 | "test": "tsdx test --passWithNoTests",
17 | "lint": "tsdx lint",
18 | "prepare": "tsdx build"
19 | },
20 | "peerDependencies": {
21 | "react": ">=16"
22 | },
23 | "husky": {
24 | "hooks": {
25 | "pre-commit": "tsdx lint"
26 | }
27 | },
28 | "name": "beanheads",
29 | "author": "Robert Broersma",
30 | "module": "dist/core.esm.js",
31 | "devDependencies": {
32 | "@types/react": "^16.9.41",
33 | "@types/react-dom": "^16.9.8",
34 | "husky": "^4.2.5",
35 | "react": "^16.13.1",
36 | "react-dom": "^16.13.1",
37 | "tsdx": "^0.13.2",
38 | "tslib": "^2.0.0",
39 | "typescript": "^3.9.6"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/site/raw/SVG/bobback.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/dressfront.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/lefteyebrowlowered.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/opensmile.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/concernedeyebrows.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/site/raw/SVG/sad.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [push]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 |
7 | steps:
8 | - name: Begin CI...
9 | uses: actions/checkout@v2
10 |
11 | - name: Use Node 12
12 | uses: actions/setup-node@v1
13 | with:
14 | node-version: 12.x
15 |
16 | - name: Use cached node_modules
17 | uses: actions/cache@v1
18 | with:
19 | path: node_modules
20 | key: nodeModules-${{ hashFiles('**/yarn.lock') }}
21 | restore-keys: |
22 | nodeModules-
23 |
24 | - name: Install dependencies
25 | run: yarn install --frozen-lockfile
26 | env:
27 | CI: true
28 |
29 | - name: Lint
30 | run: yarn lint
31 | env:
32 | CI: true
33 |
34 | - name: Test
35 | run: yarn test --ci --coverage --maxWorkers=2
36 | env:
37 | CI: true
38 |
39 | - name: Build
40 | run: yarn build
41 | env:
42 | CI: true
43 |
--------------------------------------------------------------------------------
/site/raw/SVG/graphql.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/components/eyebrows/ConcernedEyebrows.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const ConcernedEyebrows = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/components/clothingGraphic/Gatsby.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export const GatsbyGraphic = () => {
4 | return (
5 | <>
6 |
12 |
16 | >
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/core/src/components/eyebrows/Normal.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const NormalEyebrows = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/components/mouths/Grin.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const Grin = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
16 |
26 |
36 | >
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/site/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "characters",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "beanheads": "^0.3.3",
8 | "gatsby": "^2.23.7",
9 | "gatsby-plugin-google-analytics": "^2.3.13",
10 | "gatsby-plugin-postcss": "^2.3.9",
11 | "gatsby-plugin-react-helmet": "^3.3.9",
12 | "gatsby-plugin-typescript": "^2.4.6",
13 | "prism-react-renderer": "^1.1.1",
14 | "query-string": "^6.13.1",
15 | "react": "^16.13.1",
16 | "react-dom": "^16.13.1",
17 | "react-feather": "^2.0.8",
18 | "react-helmet": "^6.1.0",
19 | "react-intersection-observer": "^8.26.2",
20 | "react-syntax-highlighter": "^12.2.1",
21 | "seedrandom": "^3.0.5"
22 | },
23 | "scripts": {
24 | "dev": "gatsby develop",
25 | "build": "gatsby build",
26 | "serve": "gatsby serve",
27 | "clean": "gatsby clean"
28 | },
29 | "devDependencies": {
30 | "@types/react-helmet": "^6.0.0",
31 | "@types/react-syntax-highlighter": "^11.0.4",
32 | "tailwindcss": "^1.4.6",
33 | "typescript": "^3.9.5"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/core/src/components/eyebrows/LeftLoweredEyebrows.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const LeftLoweredEyebrows = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 | >
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Robert Broersma
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/core/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Robert Broersma
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/site/raw/SVG/tongue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/core/src/components/mouths/OpenMouth.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const OpenMouth = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
10 |
14 |
18 |
27 | >
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/site/raw/SVG/longhairfront_1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/core/src/components/mouths/SmileOpen.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const SmileOpen = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
17 |
24 |
28 | >
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/components/mouths/Sad.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const SadMouth = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
16 |
20 |
24 | >
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/components/eyes/DizzyEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const DizzyEyes = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
20 |
31 |
42 |
53 | >
54 | )
55 | }
56 |
--------------------------------------------------------------------------------
/site/raw/SVG/wink.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/site/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 | junit.xml
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
28 | node_modules
29 | examples/biz-website/public/
30 | examples/blog/public/
31 | integration-tests/gatsby-cli/execution-folder/*
32 | *.un~
33 | dist
34 | bin/published.js
35 |
36 | # Build Path of Test Fixtures
37 | test/**/public
38 | .gatsby-context.js
39 | .DS_Store
40 | public/
41 | node_modules/
42 | e2e-tests/gatsby-pnp/
43 | .cache/
44 | .netlify
45 |
46 | # IDE specific
47 | .idea/
48 | .vscode/
49 | *.sw*
50 |
51 | # misc
52 | .serverless/
53 | .eslintcache
54 |
55 | # lock files
56 | yarn.lock
57 | package-lock.json
58 | # ignore any lock file other than main lock file
59 | !/yarn.lock
60 |
61 | # starters are special; we want to persist the lock files
62 | !starters/*/package-lock.json
63 | !themes/gatsby-starter-blog-theme/package-lock.json
64 | !themes/gatsby-starter-notes-theme/package-lock.json
65 | !themes/gatsby-starter-theme/package-lock.json
66 | !themes/gatsby-starter-theme-workspace/package-lock.json
--------------------------------------------------------------------------------
/site/raw/SVG/stubble.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/core/src/components/mouths/Tongue.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const Tongue = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
20 |
24 |
31 |
35 | >
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 | junit.xml
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
28 | node_modules
29 | examples/biz-website/public/
30 | examples/blog/public/
31 | integration-tests/gatsby-cli/execution-folder/*
32 | *.un~
33 | dist
34 | bin/published.js
35 |
36 | # Build Path of Test Fixtures
37 | test/**/public
38 | .gatsby-context.js
39 | .DS_Store
40 | public/
41 | node_modules/
42 | e2e-tests/gatsby-pnp/
43 | .cache/
44 | .netlify
45 |
46 | # IDE specific
47 | .idea/
48 | .vscode/
49 | *.sw*
50 |
51 | # misc
52 | .serverless/
53 | .eslintcache
54 |
55 | # lock files
56 | yarn.lock
57 | package-lock.json
58 | # ignore any lock file other than main lock file
59 | !/yarn.lock
60 |
61 | # starters are special; we want to persist the lock files
62 | !starters/*/package-lock.json
63 | !themes/gatsby-starter-blog-theme/package-lock.json
64 | !themes/gatsby-starter-notes-theme/package-lock.json
65 | !themes/gatsby-starter-theme/package-lock.json
66 | !themes/gatsby-starter-theme-workspace/package-lock.json
67 |
68 | *.log
69 | .DS_Store
70 | node_modules
71 | .cache
72 | dist
73 |
--------------------------------------------------------------------------------
/core/src/components/facialHair/Stubble.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const StubbleBeard = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | >
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/site/raw/SVG/dressback.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/site/raw/SVG/tinyglasses.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/site/src/utils/getRandomOptions.ts:
--------------------------------------------------------------------------------
1 | import {
2 | theme,
3 | eyesMap,
4 | eyebrowsMap,
5 | mouthsMap,
6 | hairMap,
7 | facialHairMap,
8 | clothingMap,
9 | accessoryMap,
10 | graphicsMap,
11 | hatMap,
12 | bodyMap,
13 | } from 'beanheads'
14 |
15 | function selectRandomKey(object: T) {
16 | return (Object.keys(object) as Array)[
17 | Math.floor(Math.random() * Object.keys(object).length)
18 | ]
19 | }
20 |
21 | export function getRandomOptions() {
22 | const skinTone = selectRandomKey(theme.colors.skin)
23 | const eyes = selectRandomKey(eyesMap)
24 | const eyebrows = selectRandomKey(eyebrowsMap)
25 | const mouth = selectRandomKey(mouthsMap)
26 | const hair = selectRandomKey(hairMap)
27 | const facialHair = selectRandomKey(facialHairMap)
28 | const clothing = selectRandomKey(clothingMap)
29 | const accessory = selectRandomKey(accessoryMap)
30 | const graphic = selectRandomKey(graphicsMap)
31 | const hat = selectRandomKey(hatMap)
32 | const body = selectRandomKey(bodyMap)
33 |
34 | const hairColor = selectRandomKey(theme.colors.hair)
35 | const clothingColor = selectRandomKey(theme.colors.clothing)
36 | const circleColor = selectRandomKey(theme.colors.bgColors)
37 | const lipColor = selectRandomKey(theme.colors.lipColors)
38 | const hatColor = selectRandomKey(theme.colors.clothing)
39 | const faceMaskColor = selectRandomKey(theme.colors.clothing)
40 |
41 | const mask = true
42 | const faceMask = false
43 | const lashes = Math.random() > 0.5
44 |
45 | return {
46 | skinTone,
47 | eyes,
48 | eyebrows,
49 | mouth,
50 | hair,
51 | facialHair,
52 | clothing,
53 | accessory,
54 | graphic,
55 | hat,
56 | body,
57 | hairColor,
58 | clothingColor,
59 | circleColor,
60 | lipColor,
61 | hatColor,
62 | faceMaskColor,
63 | mask,
64 | faceMask,
65 | lashes,
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/site/raw/SVG/afro_front.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/site/raw/SVG/roundglasses.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/site/raw/SVG/normal eyes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/components/eyes/Wink.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { EyeProps } from './types'
4 | import { LeftLash } from './Lashes'
5 |
6 | export const WinkEyes = ({ withLashes }: EyeProps) => {
7 | const { colors, skin } = useTheme()
8 |
9 | return (
10 | <>
11 |
15 |
22 |
23 |
34 |
38 |
39 | {withLashes && }
40 | >
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/core/src/components/clothingGraphic/GraphQL.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const GraphQLGraphic = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
14 |
18 | >
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/site/src/components/SEO.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Helmet } from 'react-helmet'
3 | import { useLocation } from '@reach/router'
4 | import { useStaticQuery, graphql } from 'gatsby'
5 |
6 | interface SEOProps {
7 | title?: string
8 | description?: string
9 | image?: string
10 | }
11 |
12 | export const SEO = ({ title, description, image }: SEOProps) => {
13 | const { pathname } = useLocation()
14 | const { site } = useStaticQuery(query)
15 | const {
16 | defaultTitle,
17 | titleTemplate,
18 | defaultDescription,
19 | siteUrl,
20 | defaultImage,
21 | twitterUsername,
22 | } = site.siteMetadata
23 |
24 | const seo = {
25 | title: title || defaultTitle,
26 | description: description || defaultDescription,
27 | image: `${siteUrl}${image || defaultImage}`,
28 | url: `${siteUrl}${pathname}`,
29 | }
30 |
31 | return (
32 |
71 | )
72 | }
73 |
74 | const query = graphql`
75 | query SEO {
76 | site {
77 | siteMetadata {
78 | defaultTitle: title
79 | titleTemplate
80 | defaultDescription: description
81 | siteUrl: url
82 | defaultImage: image
83 | twitterUsername
84 | }
85 | }
86 | }
87 | `
88 |
--------------------------------------------------------------------------------
/core/src/components/hair/LongHair.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { HairProps } from './types'
4 |
5 | export const Back = ({ hairColor }: HairProps) => {
6 | const { colors } = useTheme()
7 |
8 | const { base } = colors.hair[hairColor]
9 |
10 | return (
11 | <>
12 |
19 | >
20 | )
21 | }
22 |
23 | export const Front = ({ hairColor }: HairProps) => {
24 | const { colors, skin } = useTheme()
25 |
26 | const { base } = colors.hair[hairColor]
27 |
28 | return (
29 | <>
30 |
34 |
38 |
42 |
46 |
53 | >
54 | )
55 | }
56 |
57 | export const hatScale = 1.12
58 |
--------------------------------------------------------------------------------
/site/raw/SVG/redwood.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/lips.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/src/theme.ts:
--------------------------------------------------------------------------------
1 | export const colors = {
2 | skin: {
3 | light: {
4 | base: '#fdd2b2',
5 | shadow: '#f3ab98',
6 | },
7 | yellow: {
8 | base: '#FBE8B3',
9 | shadow: '#EDD494',
10 | },
11 | brown: {
12 | base: '#D8985D',
13 | shadow: '#C6854E',
14 | },
15 | dark: {
16 | base: '#A56941',
17 | shadow: '#8D5638',
18 | },
19 | red: {
20 | base: '#CC734C',
21 | shadow: '#B56241',
22 | },
23 | black: {
24 | base: '#754437',
25 | shadow: '#6B3D34',
26 | },
27 | },
28 | hair: {
29 | blonde: {
30 | base: '#FEDC58',
31 | shadow: '#EDBF2E',
32 | },
33 | orange: {
34 | base: '#D96E27',
35 | shadow: '#C65C22',
36 | },
37 | black: {
38 | base: '#592d3d',
39 | shadow: '#592d3d',
40 | },
41 | white: {
42 | base: '#ffffff',
43 | shadow: '#E2E2E2',
44 | },
45 | brown: {
46 | base: '#A56941',
47 | shadow: '#8D5638',
48 | },
49 | blue: {
50 | base: '#85c5e5',
51 | shadow: '#67B7D6',
52 | },
53 | pink: {
54 | base: '#D69AC7',
55 | shadow: '#C683B4',
56 | },
57 | },
58 | lipColors: {
59 | red: {
60 | base: '#DD3E3E',
61 | shadow: '#C43333',
62 | },
63 | purple: {
64 | base: '#B256A1',
65 | shadow: '#9C4490',
66 | },
67 | pink: {
68 | base: '#D69AC7',
69 | shadow: '#C683B4',
70 | },
71 | turqoise: {
72 | base: '#5CCBF1',
73 | shadow: '#49B5CD',
74 | },
75 | green: {
76 | base: '#4AB749',
77 | shadow: '#3CA047',
78 | },
79 | },
80 | clothing: {
81 | white: {
82 | base: '#FFFFFF',
83 | shadow: '#E2E2E2',
84 | },
85 | blue: {
86 | base: '#85c5e5',
87 | shadow: '#67B7D6',
88 | },
89 | black: {
90 | base: '#633749',
91 | shadow: '#5E3244',
92 | },
93 | green: {
94 | base: '#89D86F',
95 | shadow: '#7DC462',
96 | },
97 | red: {
98 | base: '#D67070',
99 | shadow: '#C46565',
100 | },
101 | },
102 | bgColors: {
103 | blue: '#85c5e5',
104 | // green: '#89D86F',
105 | // red: '#ED9191',
106 | },
107 | outline: '#592d3d',
108 | white: '#ffffff',
109 | tongue: '#f28195',
110 | }
111 |
--------------------------------------------------------------------------------
/core/src/components/clothingGraphic/Redwood.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { colors } from '../../theme'
3 |
4 | export const RedwoodGraphic = () => {
5 | return (
6 | <>
7 |
8 |
9 |
14 |
19 | >
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/core/exportParts.js:
--------------------------------------------------------------------------------
1 | const React = require('react')
2 | const RDS = require('react-dom/server')
3 | const fs = require('fs')
4 | const path = require('path')
5 |
6 | const {
7 | theme,
8 | eyesMap,
9 | eyebrowsMap,
10 | mouthsMap,
11 | hairMap,
12 | facialHairMap,
13 | clothingMap,
14 | accessoryMap,
15 | graphicsMap,
16 | hatMap,
17 | bodyMap,
18 | ThemeContext,
19 | Noop,
20 | } = require('./dist')
21 |
22 | const allMaps = {
23 | eyesMap,
24 | eyebrowsMap,
25 | mouthsMap,
26 | hairMap,
27 | facialHairMap,
28 | clothingMap,
29 | accessoryMap,
30 | graphicsMap,
31 | hatMap,
32 | bodyMap,
33 | }
34 |
35 | const skinTone = theme.colors.skin.light
36 | const hairColor = 'blonde'
37 | const clothingColor = 'blue'
38 | const circleColor = 'blue'
39 | const lipColor = 'red'
40 | const hatColor = 'blue'
41 |
42 | // const mask = true
43 | // const lashes = rng() > 0.5
44 |
45 | async function renderPart(Part, mapKey, key) {
46 | if (Part === Noop) return
47 |
48 | try {
49 | const partString = RDS.renderToString(
50 | React.createElement(
51 | ThemeContext.Provider,
52 | { value: { colors: theme.colors, skin: skinTone } },
53 | React.createElement(
54 | 'svg',
55 | {
56 | xmlns: 'http://www.w3.org/2000/svg',
57 | viewBox: '0 0 1000 990',
58 | },
59 | React.createElement(Part, {
60 | skinTone,
61 | hairColor,
62 | clothingColor,
63 | circleColor,
64 | lipColor,
65 | hatColor,
66 | }),
67 | ),
68 | ),
69 | )
70 |
71 | await fs.promises.mkdir(path.join(__dirname, 'parts', mapKey), {
72 | recursive: true,
73 | })
74 |
75 | await fs.promises.writeFile(
76 | path.join(__dirname, 'parts', mapKey, `${key}.svg`),
77 | partString,
78 | )
79 | } catch (e) {
80 | console.error(e)
81 | }
82 |
83 | console.log(`${key} written`)
84 | }
85 |
86 | async function exportParts() {
87 | for (let [mapKey, map] of Object.entries(allMaps)) {
88 | for (let [key, Part] of Object.entries(map)) {
89 | if (Part.Front) {
90 | renderPart(Part.Front, mapKey, `${key}-front`)
91 | renderPart(Part.Back, mapKey, `${key}-back`)
92 | } else {
93 | renderPart(Part, mapKey, key)
94 | }
95 | }
96 | }
97 | }
98 |
99 | exportParts()
100 |
--------------------------------------------------------------------------------
/site/raw/SVG/tanktop.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/site/raw/SVG/breastsfront.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/site/raw/SVG/shorthair.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/core/src/components/accessories/TinyGlasses.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const TinyGlasses = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
16 |
21 |
30 |
34 |
38 |
45 |
50 |
59 |
63 |
67 |
74 |
78 | >
79 | )
80 | }
81 |
--------------------------------------------------------------------------------
/core/src/components/eyes/NormalEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { EyeProps } from './types'
4 | import { LeftLash, RightLash } from './Lashes'
5 |
6 | export const NormalEyes = ({ withLashes }: EyeProps) => {
7 | const { skin, colors } = useTheme()
8 |
9 | return (
10 | <>
11 |
15 |
22 |
23 |
27 |
34 |
35 |
36 | {withLashes && (
37 |
38 |
39 |
40 |
41 | )}
42 | >
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/site/raw/SVG/buzzcut.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/site/raw/SVG/hearteyes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/site/raw/SVG/afro_back.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/components/accessories/RoundGlasses.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const RoundGlasses = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
10 |
14 |
19 |
28 |
37 |
44 |
48 |
52 |
53 |
58 |
67 |
71 |
75 | >
76 | )
77 | }
78 |
--------------------------------------------------------------------------------
/core/src/components/bodies/Chest.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { Noop } from '../../utils/Noop'
4 |
5 | export const Front = Noop
6 |
7 | export const Back = () => {
8 | const { skin, colors } = useTheme()
9 | return (
10 | <>
11 |
15 |
19 |
23 |
27 |
31 |
35 | >
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/components/mouths/Lips.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { MouthProps } from './types'
4 |
5 | export const Lips = ({ lipColor }: MouthProps) => {
6 | const { colors } = useTheme()
7 |
8 | const { base, shadow } = colors.lipColors[lipColor || 'red']
9 |
10 | return (
11 | <>
12 | {/* */}
16 |
20 |
24 |
28 |
32 |
39 |
43 |
47 | >
48 | )
49 | }
50 |
--------------------------------------------------------------------------------
/site/src/components/Hero.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { GitHub, Twitter, Coffee } from 'react-feather'
3 |
4 | export function Hero() {
5 | return (
6 |
7 |
8 |
9 |
14 |
15 |
16 |
17 | Randomly Generated Characters for Your Apps & Games
18 |
19 |
20 | Combine expressions, clothing, hair styles and colors into billions
21 | of different unique characters. Embed them on your website, use them
22 | in your favourite design software, or import them from the React
23 | library!
24 |
25 |
26 | Free for personal and commercial use. Consider buying me a coffee
27 | and follow me on Twitter!
28 |
29 |
57 |
58 |
59 |
60 | )
61 | }
62 |
--------------------------------------------------------------------------------
/site/raw/SVG/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/components/clothing/TankTop.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { ClothingProps } from './types'
4 | import { Noop } from '../../utils/Noop'
5 |
6 | export const TankTop = ({ color, graphic: Graphic = Noop }: ClothingProps) => {
7 | const { colors } = useTheme()
8 |
9 | const { base, shadow } = colors.clothing[color]
10 |
11 | return (
12 | <>
13 |
17 |
21 |
25 |
29 |
36 |
40 |
47 |
54 |
55 |
56 |
57 | >
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/site/functions/svg/svg.js:
--------------------------------------------------------------------------------
1 | const React = require('react')
2 | const RDS = require('react-dom/server')
3 | const seedrandom = require('seedrandom')
4 |
5 | const {
6 | BeanHead,
7 | theme,
8 | eyesMap,
9 | eyebrowsMap,
10 | mouthsMap,
11 | hairMap,
12 | facialHairMap,
13 | clothingMap,
14 | accessoryMap,
15 | graphicsMap,
16 | hatMap,
17 | bodyMap,
18 | } = require('beanheads')
19 |
20 | function getRandomOptions(rng) {
21 | function selectRandomKey(object) {
22 | return Object.keys(object)[Math.floor(rng() * Object.keys(object).length)]
23 | }
24 |
25 | const skinTone = selectRandomKey(theme.colors.skin)
26 | const eyes = selectRandomKey(eyesMap)
27 | const eyebrows = selectRandomKey(eyebrowsMap)
28 | const mouth = selectRandomKey(mouthsMap)
29 | const hair = selectRandomKey(hairMap)
30 | const facialHair = selectRandomKey(facialHairMap)
31 | const clothing = selectRandomKey(clothingMap)
32 | const accessory = selectRandomKey(accessoryMap)
33 | const graphic = selectRandomKey(graphicsMap)
34 | const hat = selectRandomKey(hatMap)
35 | const body = selectRandomKey(bodyMap)
36 |
37 | const hairColor = selectRandomKey(theme.colors.hair)
38 | const clothingColor = selectRandomKey(theme.colors.clothing)
39 | const circleColor = selectRandomKey(theme.colors.bgColors)
40 | const lipColor = selectRandomKey(theme.colors.lipColors)
41 | const hatColor = selectRandomKey(theme.colors.clothing)
42 | const faceMaskColor = selectRandomKey(theme.colors.clothing)
43 |
44 | const mask = true
45 | const faceMask = false
46 | const lashes = rng() > 0.5
47 |
48 | return {
49 | skinTone,
50 | eyes,
51 | eyebrows,
52 | mouth,
53 | hair,
54 | facialHair,
55 | clothing,
56 | accessory,
57 | graphic,
58 | hat,
59 | body,
60 | hairColor,
61 | clothingColor,
62 | circleColor,
63 | lipColor,
64 | hatColor,
65 | faceMaskColor,
66 | mask,
67 | faceMask,
68 | lashes,
69 | }
70 | }
71 |
72 | // Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method
73 | exports.handler = async event => {
74 | try {
75 | let { seed, ...props } = event.queryStringParameters
76 |
77 | for (let [key, value] of Object.entries(props)) {
78 | if (value === 'false') {
79 | props[key] = false
80 | }
81 |
82 | if (value === 'true') {
83 | props[key] = true
84 | }
85 | }
86 |
87 | const rng = seed ? seedrandom(seed) : Math.random
88 |
89 | const mergedProps = {
90 | ...getRandomOptions(rng),
91 | ...props,
92 | }
93 |
94 | const avatarString = RDS.renderToString(
95 | React.createElement(BeanHead, mergedProps),
96 | )
97 |
98 | return {
99 | statusCode: 200,
100 | body: avatarString,
101 | headers: {
102 | 'Content-Type': 'image/svg+xml',
103 | },
104 | }
105 | } catch (err) {
106 | return { statusCode: 500, body: err.toString() }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/site/raw/SVG/shades.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/core/src/components/hair/ShortHair.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { HairProps } from './types'
4 |
5 | export const Back = () => <>>
6 |
7 | export const Front = ({ hairColor }: HairProps) => {
8 | const { colors, skin } = useTheme()
9 |
10 | const { base, shadow } = colors.hair[hairColor]
11 |
12 | return (
13 | <>
14 |
18 |
22 |
26 |
30 |
34 |
41 |
45 | >
46 | )
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/components/hair/BuzzCut.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { HairProps } from './types'
4 | import { Noop } from '../../utils/Noop'
5 |
6 | export const Back = Noop
7 |
8 | export const Front = ({ hairColor }: HairProps) => {
9 | const { colors } = useTheme()
10 |
11 | const { base, shadow } = colors.hair[hairColor]
12 |
13 | return (
14 | <>
15 |
19 |
23 |
30 |
34 | >
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/components/eyes/HeartEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { EyeProps } from './types'
4 | import { LeftLash, RightLash } from './Lashes'
5 |
6 | export const HeartEyes = ({ withLashes }: EyeProps) => {
7 | const { colors, skin } = useTheme()
8 |
9 | return (
10 | <>
11 |
15 |
22 |
26 |
30 |
37 |
41 |
42 | {withLashes && (
43 | <>
44 |
45 |
46 | >
47 | )}
48 | >
49 | )
50 | }
51 |
--------------------------------------------------------------------------------
/site/raw/SVG/vneck.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/site/raw/SVG/capfront.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/core/src/components/accessories/Shades.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 |
4 | export const Shades = () => {
5 | const { colors } = useTheme()
6 |
7 | return (
8 | <>
9 |
13 |
18 |
23 |
28 |
35 |
39 |
43 |
48 |
52 |
56 |
63 |
70 |
80 | >
81 | )
82 | }
83 |
--------------------------------------------------------------------------------
/site/raw/SVG/lefttwitcheye.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/site/raw/SVG/twitch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/core/src/components/clothing/Dress.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { ClothingProps } from './types'
4 |
5 | export const Front = ({ color }: ClothingProps) => {
6 | const { colors, skin } = useTheme()
7 |
8 | const { base } = colors.clothing[color]
9 |
10 | return (
11 | <>
12 |
19 |
23 |
30 |
34 | >
35 | )
36 | }
37 |
38 | export const Back = ({ color }: ClothingProps) => {
39 | const { colors } = useTheme()
40 |
41 | const { base, shadow } = colors.clothing[color]
42 |
43 | return (
44 | <>
45 |
49 |
53 |
57 |
61 |
68 |
72 |
76 | >
77 | )
78 | }
79 |
80 | export const braStraps = false
81 |
--------------------------------------------------------------------------------
/site/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, useCallback, useMemo } from 'react'
2 | import qs from 'query-string'
3 | import { Link } from 'gatsby'
4 | import { BeanHead } from 'beanheads'
5 | import { useInView } from 'react-intersection-observer'
6 |
7 | import { Hero } from '../components/Hero'
8 | import { SEO } from '../components/SEO'
9 | import { getRandomOptions } from '../utils/getRandomOptions'
10 |
11 | const RandomAvatar = () => {
12 | const options = getRandomOptions()
13 |
14 | const queryString = qs.stringify(options)
15 |
16 | return (
17 |
18 |
19 |
20 | )
21 | }
22 |
23 | const RandomAvatars = React.memo(
24 | ({ onReachEnd, page }: { onReachEnd(page: number): void; page: number }) => {
25 | const [ref, inView] = useInView()
26 |
27 | useEffect(() => {
28 | if (inView) {
29 | onReachEnd(page)
30 | }
31 | }, [inView])
32 |
33 | return useMemo(
34 | () => (
35 | <>
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | >
73 | ),
74 | [],
75 | )
76 | },
77 | )
78 |
79 | const Home = () => {
80 | const onReachEnd = useCallback(page => {
81 | setPages(current => {
82 | if (page === current.length) {
83 | return [
84 | ...current,
85 | ,
90 | ]
91 | }
92 |
93 | return current
94 | })
95 | }, [])
96 |
97 | const [pages, setPages] = useState([
98 | ,
99 | ])
100 |
101 | if (typeof window === 'undefined') {
102 | return
103 | }
104 |
105 | return (
106 | <>
107 |
108 |
109 |
110 |
111 |
112 | More Bean Heads
113 |
114 |
115 | Click on any character to edit, save or embed!
116 |
117 |
118 | {pages}
119 |
120 |
121 |
122 | >
123 | )
124 | }
125 |
126 | export default Home
127 |
--------------------------------------------------------------------------------
/site/raw/SVG/squinteyes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/site/raw/SVG/baldinghair.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/site/raw/SVG/breasts.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/site/raw/SVG/eyeswithlashes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/site/raw/SVG/shirt.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/core/src/components/FaceMask.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../themeContext'
3 | import { colors as themeColors } from '../theme'
4 |
5 | interface FaceMaskProps {
6 | color: keyof typeof themeColors.clothing
7 | }
8 |
9 | export const FaceMask = ({ color }: FaceMaskProps) => {
10 | const { colors, skin } = useTheme()
11 | const { base, shadow } = colors.clothing[color]
12 |
13 | return (
14 | <>
15 |
19 |
26 |
30 |
34 |
38 |
42 |
49 |
56 |
63 | >
64 | )
65 | }
66 |
--------------------------------------------------------------------------------
/core/src/components/eyes/LeftTwitchEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { EyeProps } from './types'
4 | import { LeftLash, RightLash } from './Lashes'
5 |
6 | export const LeftTwitchEyes = ({ withLashes }: EyeProps) => {
7 | const { skin, colors } = useTheme()
8 |
9 | return (
10 | <>
11 |
15 |
19 |
20 |
27 |
34 |
38 |
45 |
46 |
50 |
54 |
55 | {withLashes && (
56 |
57 |
58 |
59 |
60 | )}
61 | >
62 | )
63 | }
64 |
--------------------------------------------------------------------------------
/core/src/components/clothing/VNeck.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { ClothingProps } from './types'
4 | import { Noop } from '../../utils/Noop'
5 |
6 | export const VNeck = ({ color, graphic: Graphic = Noop }: ClothingProps) => {
7 | const { colors, skin } = useTheme()
8 |
9 | const { base, shadow } = colors.clothing[color]
10 |
11 | return (
12 | <>
13 |
17 |
25 |
29 |
33 |
37 |
41 |
45 |
49 |
57 |
65 |
69 |
73 |
80 |
84 |
91 |
99 |
103 |
110 |
111 |
112 |
113 | >
114 | )
115 | }
116 |
--------------------------------------------------------------------------------
/core/src/components/eyes/SquintEyes.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useTheme } from '../../themeContext'
3 | import { EyeProps } from './types'
4 | import { LeftLash, RightLash } from './Lashes'
5 |
6 | export const SquintEyes = ({ withLashes }: EyeProps) => {
7 | const { colors, skin } = useTheme()
8 |
9 | return (
10 | <>
11 |
15 |
19 |
20 |
27 |
34 |
41 |
45 |
49 |
50 |
57 |
64 |
71 |
72 | {withLashes && (
73 | <>
74 |
75 |
76 | >
77 | )}
78 | >
79 | )
80 | }
81 |
--------------------------------------------------------------------------------