CINXE.COM
<!doctype html><html lang="en"><head><title data-rh="true">The My Talking Angela 2 Hair System | by Aleksander Gregorka | Outfit7 | Medium</title><meta data-rh="true" charset="utf-8"/><meta data-rh="true" name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,maximum-scale=1"/><meta data-rh="true" name="theme-color" content="#000000"/><meta data-rh="true" name="twitter:app:name:iphone" content="Medium"/><meta data-rh="true" name="twitter:app:id:iphone" content="828256236"/><meta data-rh="true" property="al:ios:app_name" content="Medium"/><meta data-rh="true" property="al:ios:app_store_id" content="828256236"/><meta data-rh="true" property="al:android:package" content="com.medium.reader"/><meta data-rh="true" property="fb:app_id" content="542599432471018"/><meta data-rh="true" property="og:site_name" content="Medium"/><meta data-rh="true" property="og:type" content="article"/><meta data-rh="true" property="article:published_time" content="2022-11-17T11:20:25.148Z"/><meta data-rh="true" name="title" content="The My Talking Angela 2 Hair System | by Aleksander Gregorka | Outfit7 | Medium"/><meta data-rh="true" property="og:title" content="The My Talking Angela 2 Hair System"/><meta data-rh="true" property="al:android:url" content="medium://p/46cf06181893"/><meta data-rh="true" property="al:ios:url" content="medium://p/46cf06181893"/><meta data-rh="true" property="al:android:app_name" content="Medium"/><meta data-rh="true" name="description" content="TL;DR: The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together. With all the hairy details. I’m Aleksander Gregorka and…"/><meta data-rh="true" property="og:description" content="The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together."/><meta data-rh="true" property="og:url" content="https://medium.com/outfit7/the-my-talking-angela-2-hair-system-46cf06181893"/><meta data-rh="true" property="al:web:url" content="https://medium.com/outfit7/the-my-talking-angela-2-hair-system-46cf06181893"/><meta data-rh="true" property="og:image" content="https://miro.medium.com/v2/da:true/resize:fit:1003/0*QeoWDJ4qQhrCS_Ei"/><meta data-rh="true" property="article:author" content="https://medium.com/@aleksander.gregorka"/><meta data-rh="true" name="author" content="Aleksander Gregorka"/><meta data-rh="true" name="robots" content="index,noarchive,follow,max-image-preview:large"/><meta data-rh="true" name="referrer" content="unsafe-url"/><meta data-rh="true" property="twitter:title" content="The My Talking Angela 2 Hair System"/><meta data-rh="true" name="twitter:site" content="@Medium"/><meta data-rh="true" name="twitter:app:url:iphone" content="medium://p/46cf06181893"/><meta data-rh="true" property="twitter:description" content="The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together."/><meta data-rh="true" name="twitter:image:src" content="https://miro.medium.com/v2/da:true/resize:fit:1003/0*QeoWDJ4qQhrCS_Ei"/><meta data-rh="true" name="twitter:card" content="summary_large_image"/><meta data-rh="true" name="twitter:label1" content="Reading time"/><meta data-rh="true" name="twitter:data1" content="13 min read"/><link data-rh="true" rel="icon" href="https://miro.medium.com/v2/5d8de952517e8160e40ef9841c781cdc14a5db313057fa3c3de41c6f5b494b19"/><link data-rh="true" rel="search" type="application/opensearchdescription+xml" title="Medium" href="/osd.xml"/><link data-rh="true" rel="apple-touch-icon" sizes="152x152" href="https://miro.medium.com/v2/resize:fill:304:304/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="120x120" href="https://miro.medium.com/v2/resize:fill:240:240/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="76x76" href="https://miro.medium.com/v2/resize:fill:152:152/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="60x60" href="https://miro.medium.com/v2/resize:fill:120:120/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="mask-icon" href="https://miro.medium.com/v2/resize:fill:1000:1000/7*GAOKVe--MXbEJmV9230oOQ.png" color="#171717"/><link data-rh="true" rel="preconnect" href="https://glyph.medium.com" crossOrigin=""/><link data-rh="true" id="glyph_preload_link" rel="preload" as="style" type="text/css" href="https://glyph.medium.com/css/unbound.css"/><link data-rh="true" id="glyph_link" rel="stylesheet" type="text/css" href="https://glyph.medium.com/css/unbound.css"/><link data-rh="true" rel="author" href="https://medium.com/@aleksander.gregorka"/><link data-rh="true" rel="canonical" href="https://medium.com/outfit7/the-my-talking-angela-2-hair-system-46cf06181893"/><link data-rh="true" rel="alternate" href="android-app://com.medium.reader/https/medium.com/p/46cf06181893"/><script data-rh="true" type="application/ld+json">{"@context":"http:\u002F\u002Fschema.org","@type":"NewsArticle","image":["https:\u002F\u002Fmiro.medium.com\u002Fv2\u002Fda:true\u002Fresize:fit:1200\u002F0*QeoWDJ4qQhrCS_Ei"],"url":"https:\u002F\u002Fmedium.com\u002Foutfit7\u002Fthe-my-talking-angela-2-hair-system-46cf06181893","dateCreated":"2022-11-16T16:19:34.780Z","datePublished":"2022-11-16T16:19:34.780Z","dateModified":"2022-11-17T12:50:03.145Z","headline":"The My Talking Angela 2 Hair System - Outfit7 - Medium","name":"The My Talking Angela 2 Hair System - Outfit7 - Medium","description":"TL;DR: The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together. With all the hairy details. I’m Aleksander Gregorka and…","identifier":"46cf06181893","author":{"@type":"Person","name":"Aleksander Gregorka","url":"https:\u002F\u002Fmedium.com\u002F@aleksander.gregorka"},"creator":["Aleksander Gregorka"],"publisher":{"@type":"Organization","name":"Outfit7","url":"https:\u002F\u002Fmedium.com\u002Foutfit7","logo":{"@type":"ImageObject","width":60,"height":60,"url":"https:\u002F\u002Fmiro.medium.com\u002Fv2\u002Fresize:fit:120\u002F1*nTxl_7KgWQYo8PfVROUK_A.png"}},"mainEntityOfPage":"https:\u002F\u002Fmedium.com\u002Foutfit7\u002Fthe-my-talking-angela-2-hair-system-46cf06181893"}</script><style type="text/css" data-fela-rehydration="602" data-fela-type="STATIC">html{box-sizing:border-box;-webkit-text-size-adjust:100%}*, *:before, *:after{box-sizing:inherit}body{margin:0;padding:0;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:rgba(0,0,0,0.8);position:relative;min-height:100vh}h1, h2, h3, h4, h5, h6, dl, dd, ol, ul, menu, figure, blockquote, p, pre, form{margin:0}menu, ol, ul{padding:0;list-style:none;list-style-image:none}main{display:block}a{color:inherit;text-decoration:none}a, button, input{-webkit-tap-highlight-color:transparent}img, svg{vertical-align:middle}button{background:transparent;overflow:visible}button, input, optgroup, select, textarea{margin:0}:root{--reach-tabs:1;--reach-menu-button:1}#speechify-root{font-family:Sohne, sans-serif}div[data-popper-reference-hidden="true"]{visibility:hidden;pointer-events:none}.grecaptcha-badge{visibility:hidden} /*XCode style (c) Angel Garcia <angelgarcia.mail@gmail.com>*/.hljs {background: #fff;color: black; }/* Gray DOCTYPE selectors like WebKit */ .xml .hljs-meta {color: #c0c0c0; }.hljs-comment, .hljs-quote {color: #007400; }.hljs-tag, .hljs-attribute, .hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-name {color: #aa0d91; }.hljs-variable, .hljs-template-variable {color: #3F6E74; }.hljs-code, .hljs-string, .hljs-meta .hljs-string {color: #c41a16; }.hljs-regexp, .hljs-link {color: #0E0EFF; }.hljs-title, .hljs-symbol, .hljs-bullet, .hljs-number {color: #1c00cf; }.hljs-section, .hljs-meta {color: #643820; }.hljs-title.class_, .hljs-class .hljs-title, .hljs-type, .hljs-built_in, .hljs-params {color: #5c2699; }.hljs-attr {color: #836C28; }.hljs-subst {color: #000; }.hljs-formula {background-color: #eee;font-style: italic; }.hljs-addition {background-color: #baeeba; }.hljs-deletion {background-color: #ffc8bd; }.hljs-selector-id, .hljs-selector-class {color: #9b703f; }.hljs-doctag, .hljs-strong {font-weight: bold; }.hljs-emphasis {font-style: italic; } </style><style type="text/css" data-fela-rehydration="602" data-fela-type="KEYFRAME">@-webkit-keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}@-moz-keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}@keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE">.a{font-family:medium-content-sans-serif-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif}.b{font-weight:400}.c{background-color:rgba(255, 255, 255, 1)}.l{display:block}.m{position:sticky}.n{top:0}.o{z-index:500}.p{padding:0 24px}.q{align-items:center}.r{border-bottom:solid 1px #F2F2F2}.y{height:41px}.z{line-height:20px}.ab{display:flex}.ac{height:57px}.ae{flex:1 0 auto}.af{color:inherit}.ag{fill:inherit}.ah{font-size:inherit}.ai{border:inherit}.aj{font-family:inherit}.ak{letter-spacing:inherit}.al{font-weight:inherit}.am{padding:0}.an{margin:0}.ao{cursor:pointer}.ap:disabled{cursor:not-allowed}.aq:disabled{color:#6B6B6B}.ar:disabled{fill:#6B6B6B}.au{width:auto}.av path{fill:#242424}.aw{height:25px}.ax{margin-left:16px}.ay{border:none}.az{border-radius:20px}.ba{width:240px}.bb{background:#F9F9F9}.bc path{fill:#6B6B6B}.be{outline:none}.bf{font-family:sohne, "Helvetica Neue", Helvetica, Arial, sans-serif}.bg{font-size:14px}.bh{width:100%}.bi{padding:10px 20px 10px 0}.bj{background-color:transparent}.bk{color:#242424}.bl::placeholder{color:#6B6B6B}.bm{display:inline-block}.bn{margin-left:12px}.bo{margin-right:12px}.bp{border-radius:4px}.bq{margin-left:24px}.br{height:24px}.bx{background-color:#F9F9F9}.by{border-radius:50%}.bz{height:32px}.ca{width:32px}.cb{justify-content:center}.ch{max-width:680px}.ci{min-width:0}.cj{animation:k1 1.2s ease-in-out infinite}.ck{height:100vh}.cl{margin-bottom:16px}.cm{margin-top:48px}.cn{align-items:flex-start}.co{flex-direction:column}.cp{justify-content:space-between}.cq{margin-bottom:24px}.cw{width:80%}.cx{background-color:#F2F2F2}.dd{height:44px}.de{width:44px}.df{margin:auto 0}.dg{margin-bottom:4px}.dh{height:16px}.di{width:120px}.dj{width:80px}.dp{margin-bottom:8px}.dq{width:96%}.dr{width:98%}.ds{width:81%}.dt{margin-left:8px}.du{color:#6B6B6B}.dv{font-size:13px}.dw{height:100%}.ep{color:#FFFFFF}.eq{fill:#FFFFFF}.er{background:rgba(133, 132, 132, 1)}.es{border-color:rgba(133, 132, 132, 1)}.ew:disabled{cursor:inherit !important}.ex:disabled{opacity:0.3}.ey:disabled:hover{background:rgba(133, 132, 132, 1)}.ez:disabled:hover{border-color:rgba(133, 132, 132, 1)}.fa{border-radius:99em}.fb{border-width:1px}.fc{border-style:solid}.fd{box-sizing:border-box}.fe{text-decoration:none}.ff{text-align:center}.fi{margin-right:32px}.fj{position:relative}.fk{fill:#6B6B6B}.fn{background:transparent}.fo svg{margin-left:4px}.fp svg{fill:#6B6B6B}.fr{box-shadow:inset 0 0 0 1px rgba(0, 0, 0, 0.05)}.fs{position:absolute}.fz{margin:0 24px}.gd{background:rgba(255, 255, 255, 1)}.ge{border:1px solid #F2F2F2}.gf{box-shadow:0 1px 4px #F2F2F2}.gg{max-height:100vh}.gh{overflow-y:auto}.gi{left:0}.gj{top:calc(100vh + 100px)}.gk{bottom:calc(100vh + 100px)}.gl{width:10px}.gm{pointer-events:none}.gn{word-break:break-word}.go{word-wrap:break-word}.gp:after{display:block}.gq:after{content:""}.gr:after{clear:both}.gs{line-height:1.23}.gt{letter-spacing:0}.gu{font-style:normal}.gv{font-weight:700}.ia{align-items:baseline}.ib{width:48px}.ic{height:48px}.id{border:2px solid rgba(255, 255, 255, 1)}.ie{z-index:0}.if{box-shadow:none}.ig{border:1px solid rgba(0, 0, 0, 0.05)}.ih{margin-left:-12px}.ii{width:28px}.ij{height:28px}.ik{z-index:1}.il{width:24px}.im{margin-bottom:2px}.in{flex-wrap:nowrap}.io{font-size:16px}.ip{line-height:24px}.ir{margin:0 8px}.is{display:inline}.it{color:rgba(133, 132, 132, 1)}.iu{fill:rgba(133, 132, 132, 1)}.ix{flex:0 0 auto}.ja{flex-wrap:wrap}.jd{white-space:pre-wrap}.je{margin-right:4px}.jf{overflow:hidden}.jg{max-height:20px}.jh{text-overflow:ellipsis}.ji{display:-webkit-box}.jj{-webkit-line-clamp:1}.jk{-webkit-box-orient:vertical}.jl{word-break:break-all}.jn{padding-left:8px}.jo{padding-right:8px}.kp> *{flex-shrink:0}.kq{overflow-x:scroll}.kr::-webkit-scrollbar{display:none}.ks{scrollbar-width:none}.kt{-ms-overflow-style:none}.ku{width:74px}.kv{flex-direction:row}.kw{z-index:2}.kz{-webkit-user-select:none}.la{border:0}.lb{fill:rgba(117, 117, 117, 1)}.le{outline:0}.lf{user-select:none}.lg> svg{pointer-events:none}.lp{cursor:progress}.lq{margin-left:4px}.lr{margin-top:0px}.ls{opacity:1}.lt{padding:4px 0}.lw{width:16px}.ly{display:inline-flex}.me{max-width:100%}.mf{padding:8px 2px}.mg svg{color:#6B6B6B}.mx{line-height:1.58}.my{letter-spacing:-0.004em}.mz{font-family:source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif}.nu{margin-bottom:-0.46em}.nv{font-style:italic}.nw{margin-left:auto}.nx{margin-right:auto}.ny{max-width:1003px}.oe{clear:both}.og{cursor:zoom-in}.oh{z-index:auto}.oj{height:auto}.ok{line-height:1.12}.ol{letter-spacing:-0.022em}.om{font-weight:600}.ph{margin-bottom:-0.28em}.pn{text-decoration:underline}.po{max-width:1600px}.pp{margin-top:10px}.pq{max-width:728px}.pt{max-width:554px}.pu{max-width:973px}.pv{list-style-type:decimal}.pw{margin-left:30px}.px{padding-left:0px}.qd{overflow-x:auto}.qe{font-family:source-code-pro, Menlo, Monaco, "Courier New", Courier, monospace}.qf{padding:32px}.qg{border:1px solid #E5E5E5}.qh{line-height:1.4}.qi{margin-top:-0.2em}.qj{margin-bottom:-0.2em}.qk{white-space:pre}.ql{min-width:fit-content}.qr{width:50.03%}.qs{margin-right:10px}.qt{padding-top:5px}.qu{padding-bottom:5px}.qv:last-of-type{margin-right:0}.qw{width:49.97%}.qx{max-width:536px}.qy{width:50.23%}.qz{width:49.77%}.ra{width:200.99999999999997%}.rb{left:calc(-0.4999999999999858% - 8px)}.rc{transform:translateX(-50%)}.rd{font-style:inherit}.re{width:50.05%}.rf{width:49.95%}.rg{width:200%}.rh{left:calc(0% - 8px)}.ri{max-width:544px}.rj{max-width:874px}.rk{max-width:414px}.rl{max-width:555px}.rm{width:49.92%}.rn{width:50.08%}.ro{width:33.77%}.rp{width:28.68%}.rq{width:37.55%}.rr{max-width:865px}.rs{width:33.43%}.rt{width:33.39%}.ru{width:33.18%}.rv{width:301%}.rw{left:calc(-50.5% - 8px)}.rx{width:50.04%}.ry{width:49.96%}.rz{margin-bottom:26px}.sa{margin-top:6px}.sb{margin-top:8px}.sc{margin-right:8px}.sd{padding:8px 16px}.se{border-radius:100px}.sf{transition:background 300ms ease}.sh{white-space:nowrap}.si{border-top:none}.sj{margin-bottom:14px}.sk{height:52px}.sl{max-height:52px}.sm{box-sizing:content-box}.sn{position:static}.sp{max-width:155px}.sv{margin-right:20px}.tb{height:0px}.tc{margin-bottom:40px}.td{margin-bottom:48px}.tr{border-radius:2px}.tt{height:64px}.tu{width:64px}.tv{align-self:flex-end}.tw{flex:1 1 auto}.ua{padding-right:4px}.ub{font-weight:500}.uo{margin-top:16px}.up{color:rgba(255, 255, 255, 1)}.uq{fill:rgba(255, 255, 255, 1)}.ur{background:rgba(25, 25, 25, 1)}.us{border-color:rgba(25, 25, 25, 1)}.uv:disabled{opacity:0.1}.uw:disabled:hover{background:rgba(25, 25, 25, 1)}.ux:disabled:hover{border-color:rgba(25, 25, 25, 1)}.vg{gap:18px}.vh{fill:rgba(61, 61, 61, 1)}.vj{margin-top:32px}.vk{fill:#242424}.vl{background:0}.vm{border-color:#242424}.vn:disabled:hover{color:#242424}.vo:disabled:hover{fill:#242424}.vp:disabled:hover{border-color:#242424}.wa{border-bottom:solid 1px #E5E5E5}.wb{margin-top:72px}.wc{padding:24px 0}.wd{margin-bottom:0px}.we{margin-right:16px}.as:hover:not(:disabled){color:rgba(25, 25, 25, 1)}.at:hover:not(:disabled){fill:rgba(25, 25, 25, 1)}.et:hover{background:rgba(115, 113, 113, 1)}.eu:hover{border-color:rgba(115, 113, 113, 1)}.ev:hover{cursor:pointer}.fl:hover{color:#242424}.fm:hover{fill:#242424}.fq:hover svg{fill:#242424}.ft:hover{background-color:rgba(0, 0, 0, 0.1)}.iq:hover{text-decoration:underline}.iv:hover:not(:disabled){color:rgba(115, 113, 113, 1)}.iw:hover:not(:disabled){fill:rgba(115, 113, 113, 1)}.ld:hover{fill:rgba(8, 8, 8, 1)}.lu:hover{fill:#000000}.lv:hover p{color:#000000}.lx:hover{color:#000000}.mh:hover svg{color:#000000}.sg:hover{background-color:#F2F2F2}.ts:hover{background-color:none}.ut:hover{background:#000000}.uu:hover{border-color:#242424}.vi:hover{fill:rgba(25, 25, 25, 1)}.bd:focus-within path{fill:#242424}.lc:focus{fill:rgba(8, 8, 8, 1)}.mi:focus svg{color:#000000}.oi:focus{transform:scale(1.01)}.lh:active{border-style:none}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (min-width: 1080px)">.d{display:none}.bw{width:64px}.cg{margin:0 64px}.cv{height:48px}.dc{margin-bottom:52px}.do{margin-bottom:48px}.ef{font-size:14px}.eg{line-height:20px}.em{font-size:13px}.eo{padding:5px 12px}.fh{display:flex}.fy{margin-bottom:68px}.gc{max-width:680px}.hq{font-size:42px}.hr{margin-top:1.19em}.hs{margin-bottom:32px}.ht{line-height:52px}.hu{letter-spacing:-0.011em}.hz{align-items:center}.kb{border-top:solid 1px #F2F2F2}.kc{border-bottom:solid 1px #F2F2F2}.kd{margin:32px 0 0}.ke{padding:3px 8px}.kn> *{margin-right:24px}.ko> :last-child{margin-right:0}.lo{margin-top:0px}.md{margin:0}.nq{font-size:20px}.nr{margin-top:2.14em}.ns{line-height:32px}.nt{letter-spacing:-0.003em}.od{margin-top:56px}.pd{font-size:24px}.pe{margin-top:1.95em}.pf{line-height:30px}.pg{letter-spacing:-0.016em}.pm{margin-top:0.94em}.qc{margin-top:1.14em}.qq{max-width:1192px}.su{display:inline-block}.ta{margin-bottom:104px}.te{flex-direction:row}.th{margin-bottom:0}.ti{margin-right:20px}.tx{max-width:500px}.um{line-height:24px}.un{letter-spacing:0}.vc{margin-bottom:88px}.vf{margin-bottom:72px}.vu{width:min-width}.vz{padding-top:72px}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (max-width: 1079.98px)">.e{display:none}.ln{margin-top:0px}.pr{margin-left:auto}.ps{text-align:center}.st{display:inline-block}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (max-width: 903.98px)">.f{display:none}.lm{margin-top:0px}.ss{display:inline-block}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (max-width: 727.98px)">.g{display:none}.lk{margin-top:0px}.ll{margin-right:0px}.sr{display:inline-block}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (max-width: 551.98px)">.h{display:none}.s{display:flex}.t{justify-content:space-between}.bs{width:24px}.cc{margin:0 24px}.cr{height:40px}.cy{margin-bottom:44px}.dk{margin-bottom:32px}.dx{font-size:13px}.dy{line-height:20px}.eh{padding:0px 8px 1px}.fu{margin-bottom:4px}.gw{font-size:32px}.gx{margin-top:1.01em}.gy{margin-bottom:24px}.gz{line-height:38px}.ha{letter-spacing:-0.014em}.hv{align-items:flex-start}.iy{flex-direction:column}.jb{margin-bottom:2px}.jp{margin:24px -24px 0}.jq{padding:0}.kf> *{margin-right:8px}.kg> :last-child{margin-right:24px}.kx{margin-left:0px}.li{margin-top:0px}.lj{margin-right:0px}.lz{margin:0}.mj{border:1px solid #F2F2F2}.mk{border-radius:99em}.ml{padding:0px 16px 0px 12px}.mm{height:38px}.mn{align-items:center}.mp svg{margin-right:8px}.na{font-size:18px}.nb{margin-top:1.56em}.nc{line-height:28px}.nd{letter-spacing:-0.003em}.nz{margin-top:40px}.on{font-size:20px}.oo{margin-top:1.2em}.op{line-height:24px}.oq{letter-spacing:0}.pi{margin-top:0.67em}.py{margin-top:1.34em}.qm{max-width:100%}.sq{display:inline-block}.sw{margin-bottom:96px}.tp{margin-bottom:20px}.tq{margin-right:0}.uc{font-size:24px}.ud{line-height:30px}.ue{letter-spacing:-0.016em}.uy{margin-bottom:64px}.vq{width:100%}.vv{padding-top:48px}.mo:hover{border-color:#E5E5E5}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (min-width: 904px) and (max-width: 1079.98px)">.i{display:none}.bv{width:64px}.cf{margin:0 64px}.cu{height:48px}.db{margin-bottom:52px}.dn{margin-bottom:48px}.ed{font-size:14px}.ee{line-height:20px}.ek{font-size:13px}.el{padding:5px 12px}.fg{display:flex}.fx{margin-bottom:68px}.gb{max-width:680px}.hl{font-size:42px}.hm{margin-top:1.19em}.hn{margin-bottom:32px}.ho{line-height:52px}.hp{letter-spacing:-0.011em}.hy{align-items:center}.jx{border-top:solid 1px #F2F2F2}.jy{border-bottom:solid 1px #F2F2F2}.jz{margin:32px 0 0}.ka{padding:3px 8px}.kl> *{margin-right:24px}.km> :last-child{margin-right:0}.mc{margin:0}.nm{font-size:20px}.nn{margin-top:2.14em}.no{line-height:32px}.np{letter-spacing:-0.003em}.oc{margin-top:56px}.oz{font-size:24px}.pa{margin-top:1.95em}.pb{line-height:30px}.pc{letter-spacing:-0.016em}.pl{margin-top:0.94em}.qb{margin-top:1.14em}.qp{max-width:1192px}.sz{margin-bottom:104px}.tf{flex-direction:row}.tj{margin-bottom:0}.tk{margin-right:20px}.ty{max-width:500px}.uk{line-height:24px}.ul{letter-spacing:0}.vb{margin-bottom:88px}.ve{margin-bottom:72px}.vt{width:min-width}.vy{padding-top:72px}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (min-width: 728px) and (max-width: 903.98px)">.j{display:none}.w{display:flex}.x{justify-content:space-between}.bu{width:64px}.ce{margin:0 48px}.ct{height:48px}.da{margin-bottom:52px}.dm{margin-bottom:48px}.eb{font-size:13px}.ec{line-height:20px}.ej{padding:0px 8px 1px}.fw{margin-bottom:68px}.ga{max-width:680px}.hg{font-size:42px}.hh{margin-top:1.19em}.hi{margin-bottom:32px}.hj{line-height:52px}.hk{letter-spacing:-0.011em}.hx{align-items:center}.jt{border-top:solid 1px #F2F2F2}.ju{border-bottom:solid 1px #F2F2F2}.jv{margin:32px 0 0}.jw{padding:3px 8px}.kj> *{margin-right:24px}.kk> :last-child{margin-right:0}.mb{margin:0}.ni{font-size:20px}.nj{margin-top:2.14em}.nk{line-height:32px}.nl{letter-spacing:-0.003em}.ob{margin-top:56px}.ov{font-size:24px}.ow{margin-top:1.95em}.ox{line-height:30px}.oy{letter-spacing:-0.016em}.pk{margin-top:0.94em}.qa{margin-top:1.14em}.qo{max-width:100%}.sy{margin-bottom:104px}.tg{flex-direction:row}.tl{margin-bottom:0}.tm{margin-right:20px}.tz{max-width:500px}.ui{line-height:24px}.uj{letter-spacing:0}.va{margin-bottom:88px}.vd{margin-bottom:72px}.vs{width:min-width}.vx{padding-top:72px}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="all and (min-width: 552px) and (max-width: 727.98px)">.k{display:none}.u{display:flex}.v{justify-content:space-between}.bt{width:24px}.cd{margin:0 24px}.cs{height:40px}.cz{margin-bottom:44px}.dl{margin-bottom:32px}.dz{font-size:13px}.ea{line-height:20px}.ei{padding:0px 8px 1px}.fv{margin-bottom:4px}.hb{font-size:32px}.hc{margin-top:1.01em}.hd{margin-bottom:24px}.he{line-height:38px}.hf{letter-spacing:-0.014em}.hw{align-items:flex-start}.iz{flex-direction:column}.jc{margin-bottom:2px}.jr{margin:24px 0 0}.js{padding:0}.kh> *{margin-right:8px}.ki> :last-child{margin-right:8px}.ky{margin-left:0px}.ma{margin:0}.mq{border:1px solid #F2F2F2}.mr{border-radius:99em}.ms{padding:0px 16px 0px 12px}.mt{height:38px}.mu{align-items:center}.mw svg{margin-right:8px}.ne{font-size:18px}.nf{margin-top:1.56em}.ng{line-height:28px}.nh{letter-spacing:-0.003em}.oa{margin-top:40px}.or{font-size:20px}.os{margin-top:1.2em}.ot{line-height:24px}.ou{letter-spacing:0}.pj{margin-top:0.67em}.pz{margin-top:1.34em}.qn{max-width:100%}.sx{margin-bottom:96px}.tn{margin-bottom:20px}.to{margin-right:0}.uf{font-size:24px}.ug{line-height:30px}.uh{letter-spacing:-0.016em}.uz{margin-bottom:64px}.vr{width:100%}.vw{padding-top:48px}.mv:hover{border-color:#E5E5E5}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="print">.so{display:none}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="(orientation: landscape) and (max-width: 903.98px)">.jm{max-height:none}</style><style type="text/css" data-fela-rehydration="602" data-fela-type="RULE" media="(prefers-reduced-motion: no-preference)">.of{transition:transform 300ms cubic-bezier(0.2, 0, 0.2, 1)}</style></head><body><div id="root"><div class="a b c"><div class="d e f g h i j k"></div><script>document.domain = document.domain;</script><div class="l c"><div class="l m n o c"><div class="p q r s t u v w x i d y z"><a class="du ag dv bf ak b am an ao ap aq ar as at s u w i d q dw z" href="https://rsci.app.link/?%24canonical_url=https%3A%2F%2Fmedium.com%2Fp%2F46cf06181893&%7Efeature=LoOpenInAppButton&%7Echannel=ShowPostUnderCollection&source=---top_nav_layout_nav----------------------------------" rel="noopener follow">Open in app<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="none" viewBox="0 0 10 10" class="dt"><path fill="currentColor" d="M.985 8.485a.375.375 0 1 0 .53.53zM8.75 1.25h.375A.375.375 0 0 0 8.75.875zM8.375 6.5a.375.375 0 1 0 .75 0zM3.5.875a.375.375 0 1 0 0 .75zm-1.985 8.14 7.5-7.5-.53-.53-7.5 7.5zm6.86-7.765V6.5h.75V1.25zM3.5 1.625h5.25v-.75H3.5z"></path></svg></a><div class="ab q"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><button class="bf b dx dy eh dz ea ei eb ec ej ek ee el em eg eo ep eq er es et eu ev ew ex ey ez fa fb fc fd bm fe ff" data-testid="headerSignUpButton">Sign up</button></span></p><div class="ax l"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSignInButton" rel="noopener follow" href="/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&source=post_page---top_nav_layout_nav-----------------------global_nav-----------">Sign in</a></span></p></div></div></div><div class="p q r ab ac"><div class="ab q ae"><a class="af ag ah ai aj ak al am an ao ap aq ar as at ab" aria-label="Homepage" data-testid="headerMediumLogo" rel="noopener follow" href="/?source=---top_nav_layout_nav----------------------------------"><svg xmlns="http://www.w3.org/2000/svg" width="719" height="160" fill="none" viewBox="0 0 719 160" class="au av aw"><path fill="#242424" d="m174.104 9.734.215-.047V8.02H130.39L89.6 103.89 48.81 8.021H1.472v1.666l.212.047c8.018 1.81 12.09 4.509 12.09 14.242V137.93c0 9.734-4.087 12.433-12.106 14.243l-.212.047v1.671h32.118v-1.665l-.213-.048c-8.018-1.809-12.089-4.509-12.089-14.242V30.586l52.399 123.305h2.972l53.925-126.743V140.75c-.687 7.688-4.721 10.062-11.982 11.701l-.215.05v1.652h55.948v-1.652l-.215-.05c-7.269-1.639-11.4-4.013-12.087-11.701l-.037-116.774h.037c0-9.733 4.071-12.432 12.087-14.242m25.555 75.488c.915-20.474 8.268-35.252 20.606-35.507 3.806.063 6.998 1.312 9.479 3.714 5.272 5.118 7.751 15.812 7.368 31.793zm-.553 5.77h65.573v-.275c-.186-15.656-4.721-27.834-13.466-36.196-7.559-7.227-18.751-11.203-30.507-11.203h-.263c-6.101 0-13.584 1.48-18.909 4.16-6.061 2.807-11.407 7.003-15.855 12.511-7.161 8.874-11.499 20.866-12.554 34.343q-.05.606-.092 1.212a50 50 0 0 0-.065 1.151 85.807 85.807 0 0 0-.094 5.689c.71 30.524 17.198 54.917 46.483 54.917 25.705 0 40.675-18.791 44.407-44.013l-1.886-.664c-6.557 13.556-18.334 21.771-31.738 20.769-18.297-1.369-32.314-19.922-31.042-42.395m139.722 41.359c-2.151 5.101-6.639 7.908-12.653 7.908s-11.513-4.129-15.418-11.63c-4.197-8.053-6.405-19.436-6.405-32.92 0-28.067 8.729-46.22 22.24-46.22 5.657 0 10.111 2.807 12.236 7.704zm43.499 20.008c-8.019-1.897-12.089-4.722-12.089-14.951V1.309l-48.716 14.353v1.757l.299-.024c6.72-.543 11.278.386 13.925 2.83 2.072 1.915 3.082 4.853 3.082 8.987v18.66c-4.803-3.067-10.516-4.56-17.448-4.56-14.059 0-26.909 5.92-36.176 16.672-9.66 11.205-14.767 26.518-14.767 44.278-.003 31.72 15.612 53.039 38.851 53.039 13.595 0 24.533-7.449 29.54-20.013v16.865h43.711v-1.746zM424.1 19.819c0-9.904-7.468-17.374-17.375-17.374-9.859 0-17.573 7.632-17.573 17.374s7.721 17.374 17.573 17.374c9.907 0 17.375-7.47 17.375-17.374m11.499 132.546c-8.019-1.897-12.089-4.722-12.089-14.951h-.035V43.635l-43.714 12.551v1.705l.263.024c9.458.842 12.047 4.1 12.047 15.152v81.086h43.751v-1.746zm112.013 0c-8.018-1.897-12.089-4.722-12.089-14.951V43.635l-41.621 12.137v1.71l.246.026c7.733.813 9.967 4.257 9.967 15.36v59.279c-2.578 5.102-7.415 8.131-13.274 8.336-9.503 0-14.736-6.419-14.736-18.073V43.638l-43.714 12.55v1.703l.262.024c9.459.84 12.05 4.097 12.05 15.152v50.17a56.3 56.3 0 0 0 .91 10.444l.787 3.423c3.701 13.262 13.398 20.197 28.59 20.197 12.868 0 24.147-7.966 29.115-20.43v17.311h43.714v-1.747zm169.818 1.788v-1.749l-.213-.05c-8.7-2.006-12.089-5.789-12.089-13.49v-63.79c0-19.89-11.171-31.761-29.883-31.761-13.64 0-25.141 7.882-29.569 20.16-3.517-13.01-13.639-20.16-28.606-20.16-13.146 0-23.449 6.938-27.869 18.657V43.643L545.487 55.68v1.715l.263.024c9.345.829 12.047 4.181 12.047 14.95v81.784h40.787v-1.746l-.215-.053c-6.941-1.631-9.181-4.606-9.181-12.239V66.998c1.836-4.289 5.537-9.37 12.853-9.37 9.086 0 13.692 6.296 13.692 18.697v77.828h40.797v-1.746l-.215-.053c-6.94-1.631-9.18-4.606-9.18-12.239V75.066a42 42 0 0 0-.578-7.26c1.947-4.661 5.86-10.177 13.475-10.177 9.214 0 13.691 6.114 13.691 18.696v77.828z"></path></svg></a><div class="ax h"><div class="ab ay az ba bb q bc bd"><div class="bm" aria-hidden="false" aria-describedby="searchResults" aria-labelledby="searchResults"></div><div class="bn bo ab"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M4.092 11.06a6.95 6.95 0 1 1 13.9 0 6.95 6.95 0 0 1-13.9 0m6.95-8.05a8.05 8.05 0 1 0 5.13 14.26l3.75 3.75a.56.56 0 1 0 .79-.79l-3.73-3.73A8.05 8.05 0 0 0 11.042 3z" clip-rule="evenodd"></path></svg></div><input role="combobox" aria-controls="searchResults" aria-expanded="false" aria-label="search" data-testid="headerSearchInput" tabindex="0" class="ay be bf bg z bh bi bj bk bl" placeholder="Search" value=""/></div></div></div><div class="h k w fg fh"><div class="fi ab"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerWriteButton" rel="noopener follow" href="/m/signin?operation=register&redirect=https%3A%2F%2Fmedium.com%2Fnew-story&source=---top_nav_layout_nav-----------------------new_post_topnav-----------"><div class="bf b bg z du fj fk ab q fl fm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" aria-label="Write"><path fill="currentColor" d="M14 4a.5.5 0 0 0 0-1zm7 6a.5.5 0 0 0-1 0zm-7-7H4v1h10zM3 4v16h1V4zm1 17h16v-1H4zm17-1V10h-1v10zm-1 1a1 1 0 0 0 1-1h-1zM3 20a1 1 0 0 0 1 1v-1zM4 3a1 1 0 0 0-1 1h1z"></path><path stroke="currentColor" d="m17.5 4.5-8.458 8.458a.25.25 0 0 0-.06.098l-.824 2.47a.25.25 0 0 0 .316.316l2.47-.823a.25.25 0 0 0 .098-.06L19.5 6.5m-2-2 2.323-2.323a.25.25 0 0 1 .354 0l1.646 1.646a.25.25 0 0 1 0 .354L19.5 6.5m-2-2 2 2"></path></svg><div class="dt l">Write</div></div></a></span></div></div><div class="k j i d"><div class="fi ab"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSearchButton" rel="noopener follow" href="/search?source=---top_nav_layout_nav----------------------------------"><div class="bf b bg z du fj fk ab q fl fm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" aria-label="Search"><path fill="currentColor" fill-rule="evenodd" d="M4.092 11.06a6.95 6.95 0 1 1 13.9 0 6.95 6.95 0 0 1-13.9 0m6.95-8.05a8.05 8.05 0 1 0 5.13 14.26l3.75 3.75a.56.56 0 1 0 .79-.79l-3.73-3.73A8.05 8.05 0 0 0 11.042 3z" clip-rule="evenodd"></path></svg></div></a></div></div><div class="fi h k j"><div class="ab q"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><button class="bf b dx dy eh dz ea ei eb ec ej ek ee el em eg eo ep eq er es et eu ev ew ex ey ez fa fb fc fd bm fe ff" data-testid="headerSignUpButton">Sign up</button></span></p><div class="ax l"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSignInButton" rel="noopener follow" href="/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&source=post_page---top_nav_layout_nav-----------------------global_nav-----------">Sign in</a></span></p></div></div></div><div class="l" aria-hidden="false"><button class="ay fn am ab q ao fo fp fq" aria-label="user options menu" data-testid="headerUserIcon"><div class="l fj"><img alt="" class="l fd by bz ca cx" src="https://miro.medium.com/v2/resize:fill:64:64/1*dmbNkD5D-u45r44go_cf0g.png" width="32" height="32" loading="lazy" role="presentation"/><div class="fr by l bz ca fs n ay ft"></div></div></button></div></div></div><div class="l"><div class="fu fv fw fx fy l"><div class="ab cb"><div class="ci bh fz ga gb gc"></div></div><article><div class="l"><div class="l"><span class="l"></span><section><div><div class="fs gi gj gk gl gm"></div><div class="gn go gp gq gr"><div class="ab cb"><div class="ci bh fz ga gb gc"><div><h1 id="5dd9" class="pw-post-title gs gt gu bf gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht hu bk" data-testid="storyTitle">The My Talking Angela 2 Hair System</h1><div><div class="speechify-ignore ab cp"><div class="speechify-ignore bh l"><div class="hv hw hx hy hz ab"><div><div class="ab ia"><div><div class="bm" aria-hidden="false"><a rel="noopener follow" href="/@aleksander.gregorka?source=post_page---byline--46cf06181893--------------------------------"><div class="l ib ic by id ie"><div class="l fj"><img alt="Aleksander Gregorka" class="l fd by dd de cx" src="https://miro.medium.com/v2/resize:fill:88:88/1*cAYUfjr9zj796olrnlP1eg.png" width="44" height="44" loading="lazy" data-testid="authorPhoto"/><div class="if by l dd de fs n ig ft"></div></div></div></a></div></div><div class="ih ab fj"><div><div class="bm" aria-hidden="false"><a href="https://medium.com/outfit7?source=post_page---byline--46cf06181893--------------------------------" rel="noopener follow"><div class="l ii ij by id ik"><div class="l fj"><img alt="Outfit7" class="l fd by br il cx" src="https://miro.medium.com/v2/resize:fill:48:48/1*dCIQWfMya9g57UUL2ZzrJQ.png" width="24" height="24" loading="lazy" data-testid="publicationPhoto"/><div class="if by l br il fs n ig ft"></div></div></div></a></div></div></div></div></div><div class="bn bh l"><div class="ab"><div style="flex:1"><span class="bf b bg z bk"><div class="im ab q"><div class="ab q in"><div class="ab q"><div><div class="bm" aria-hidden="false"><p class="bf b io ip bk"><a class="af ag ah ai aj ak al am an ao ap aq ar iq" data-testid="authorName" rel="noopener follow" href="/@aleksander.gregorka?source=post_page---byline--46cf06181893--------------------------------">Aleksander Gregorka</a></p></div></div></div><span class="ir is" aria-hidden="true"><span class="bf b bg z du">·</span></span><p class="bf b io ip du"><span><a class="it iu ah ai aj ak al am an ao ap aq ar ex iv iw" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fsubscribe%2Fuser%2F565c34edb417&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&user=Aleksander+Gregorka&userId=565c34edb417&source=post_page-565c34edb417--byline--46cf06181893---------------------post_header-----------">Follow</a></span></p></div></div></span></div></div><div class="l ix"><span class="bf b bg z du"><div class="ab cn iy iz ja"><div class="jb jc ab"><div class="bf b bg z du ab jd"><span class="je l ix">Published in</span><div><div class="l" aria-hidden="false"><a class="af ag ah ai aj ak al am an ao ap aq ar iq ab q" data-testid="publicationName" href="https://medium.com/outfit7?source=post_page---byline--46cf06181893--------------------------------" rel="noopener follow"><p class="bf b bg z jf jg jh ji jj jk jl jm bk">Outfit7</p></a></div></div></div><div class="h k"><span class="ir is" aria-hidden="true"><span class="bf b bg z du">·</span></span></div></div><span class="bf b bg z du"><div class="ab ae"><span data-testid="storyReadTime">13 min read</span><div class="jn jo l" aria-hidden="true"><span class="l" aria-hidden="true"><span class="bf b bg z du">·</span></span></div><span data-testid="storyPublishDate">Nov 16, 2022</span></div></span></div></span></div></div></div><div class="ab cp jp jq jr js jt ju jv jw jx jy jz ka kb kc kd ke"><div class="h k w fg fh q"><div class="ku l"><div class="ab q kv kw"><div class="pw-multi-vote-icon fj je kx ky kz"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Foutfit7%2F46cf06181893&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&user=Aleksander+Gregorka&userId=565c34edb417&source=---header_actions--46cf06181893---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="la ao lb lc ld le am lf lg lh kz"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l li lj lk ll lm ln lo"><p class="bf b dv z du"><span class="lp">--</span></p></div></div></div><div><div class="bm" aria-hidden="false"><button class="ao la ls lt ab q fk lu lv" aria-label="responses"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="lr"><path d="M18.006 16.803c1.533-1.456 2.234-3.325 2.234-5.321C20.24 7.357 16.709 4 12.191 4S4 7.357 4 11.482c0 4.126 3.674 7.482 8.191 7.482.817 0 1.622-.111 2.393-.327.231.2.48.391.744.559 1.06.693 2.203 1.044 3.399 1.044.224-.008.4-.112.486-.287a.49.49 0 0 0-.042-.518c-.495-.67-.845-1.364-1.04-2.057a4 4 0 0 1-.125-.598zm-3.122 1.055-.067-.223-.315.096a8 8 0 0 1-2.311.338c-4.023 0-7.292-2.955-7.292-6.587 0-3.633 3.269-6.588 7.292-6.588 4.014 0 7.112 2.958 7.112 6.593 0 1.794-.608 3.469-2.027 4.72l-.195.168v.255c0 .056 0 .151.016.295.025.231.081.478.154.733.154.558.398 1.117.722 1.659a5.3 5.3 0 0 1-2.165-.845c-.276-.176-.714-.383-.941-.59z"></path></svg><p class="bf b dv z du"><span class="pw-responses-count lq lr">1</span></p></button></div></div></div><div class="ab q kf kg kh ki kj kk kl km kn ko kp kq kr ks kt"><div class="lw k j i d"></div><div class="h k"><div><div class="bm" aria-hidden="false"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerBookmarkButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fbookmark%2Fp%2F46cf06181893&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&source=---header_actions--46cf06181893---------------------bookmark_footer-----------"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="none" viewBox="0 0 25 25" class="du lx" aria-label="Add to list bookmark button"><path fill="currentColor" d="M18 2.5a.5.5 0 0 1 1 0V5h2.5a.5.5 0 0 1 0 1H19v2.5a.5.5 0 1 1-1 0V6h-2.5a.5.5 0 0 1 0-1H18zM7 7a1 1 0 0 1 1-1h3.5a.5.5 0 0 0 0-1H8a2 2 0 0 0-2 2v14a.5.5 0 0 0 .805.396L12.5 17l5.695 4.396A.5.5 0 0 0 19 21v-8.5a.5.5 0 0 0-1 0v7.485l-5.195-4.012a.5.5 0 0 0-.61 0L7 19.985z"></path></svg></a></span></div></div></div><div class="fd ly cn"><div class="l ae"><div class="ab cb"><div class="lz ma mb mc md me ci bh"><div class="ab"><div class="bm bh" aria-hidden="false"><div><div class="bm" aria-hidden="false"><button aria-label="Listen" data-testid="audioPlayButton" class="af fk ah ai aj ak al mf an ao ap ex mg mh lv mi mj mk ml mm s mn mo mp mq mr ms mt u mu mv mw"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M3 12a9 9 0 1 1 18 0 9 9 0 0 1-18 0m9-10C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2m3.376 10.416-4.599 3.066a.5.5 0 0 1-.777-.416V8.934a.5.5 0 0 1 .777-.416l4.599 3.066a.5.5 0 0 1 0 .832" clip-rule="evenodd"></path></svg><div class="j i d"><p class="bf b bg z du">Listen</p></div></button></div></div></div></div></div></div></div></div><div class="bm" aria-hidden="false" aria-describedby="postFooterSocialMenu" aria-labelledby="postFooterSocialMenu"><div><div class="bm" aria-hidden="false"><button aria-controls="postFooterSocialMenu" aria-expanded="false" aria-label="Share Post" data-testid="headerSocialShareButton" class="af fk ah ai aj ak al mf an ao ap ex mg mh lv mi mj mk ml mm s mn mo mp mq mr ms mt u mu mv mw"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M15.218 4.931a.4.4 0 0 1-.118.132l.012.006a.45.45 0 0 1-.292.074.5.5 0 0 1-.3-.13l-2.02-2.02v7.07c0 .28-.23.5-.5.5s-.5-.22-.5-.5v-7.04l-2 2a.45.45 0 0 1-.57.04h-.02a.4.4 0 0 1-.16-.3.4.4 0 0 1 .1-.32l2.8-2.8a.5.5 0 0 1 .7 0l2.8 2.79a.42.42 0 0 1 .068.498m-.106.138.008.004v-.01zM16 7.063h1.5a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-11c-1.1 0-2-.9-2-2v-10a2 2 0 0 1 2-2H8a.5.5 0 0 1 .35.15.5.5 0 0 1 .15.35.5.5 0 0 1-.15.35.5.5 0 0 1-.35.15H6.4c-.5 0-.9.4-.9.9v10.2a.9.9 0 0 0 .9.9h11.2c.5 0 .9-.4.9-.9v-10.2c0-.5-.4-.9-.9-.9H16a.5.5 0 0 1 0-1" clip-rule="evenodd"></path></svg><div class="j i d"><p class="bf b bg z du">Share</p></div></button></div></div></div></div></div></div></div></div></div><p id="4d01" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk"><strong class="mz gv"><em class="nv">TL;DR:</em></strong><em class="nv"> The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together. With all the hairy details.</em></p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx ny"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*QeoWDJ4qQhrCS_Ei 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*QeoWDJ4qQhrCS_Ei 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*QeoWDJ4qQhrCS_Ei 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*QeoWDJ4qQhrCS_Ei 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*QeoWDJ4qQhrCS_Ei 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*QeoWDJ4qQhrCS_Ei 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*QeoWDJ4qQhrCS_Ei 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*QeoWDJ4qQhrCS_Ei 640w, https://miro.medium.com/v2/resize:fit:720/0*QeoWDJ4qQhrCS_Ei 720w, https://miro.medium.com/v2/resize:fit:750/0*QeoWDJ4qQhrCS_Ei 750w, https://miro.medium.com/v2/resize:fit:786/0*QeoWDJ4qQhrCS_Ei 786w, https://miro.medium.com/v2/resize:fit:828/0*QeoWDJ4qQhrCS_Ei 828w, https://miro.medium.com/v2/resize:fit:1100/0*QeoWDJ4qQhrCS_Ei 1100w, https://miro.medium.com/v2/resize:fit:1400/0*QeoWDJ4qQhrCS_Ei 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="443" loading="eager" role="presentation"/></picture></div></div></figure><p id="25a9" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">I’m Aleksander Gregorka and I’m a Senior Software Engineer at Outfit7. I’ve been with the company since 2014, and during that time I’ve implemented tons of things that moved across millions of screens. And what better way to put my skills to the test than by making bouncy hair.</p><p id="51dc" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Today we’ll take a look at the hair system I implemented for our hit mobile game, My Talking Angela 2. At the time of publishing this article, the game had achieved over 300 million downloads in its first year.</p><p id="1e8b" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The game was made using our own proprietary game engine called Starlite. We’ll get into the details of Starlite and its editor in one of our upcoming blog posts, but for now, the only thing you need to know is that we’re using C++ for runtime development, so any code samples in this article will also be in C++.</p><h1 id="90ce" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Goals</h1><p id="f114" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Having a proprietary game engine has some downsides, but also a lot of benefits. An example of this would be that you can’t just take a hair system package from the app store and call it a day. The benefit of implementing it yourself, though, is that you can integrate it into the rest of the app using the same architecture used elsewhere in the game. If something goes wrong, you can fix it yourself, which is extremely important in a project as big as My Talking Angela 2.</p><p id="80b3" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The goal of the system was to support stylized hair, meaning that the simulation wouldn’t have to be completely physically realistic.</p><p id="8817" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">One of the important things was also that we should avoid hair mesh clipping with other items as much as possible, but this is really hard to achieve in real-time dynamic games where characters can interact with other items, such as toys, hats, and furniture. Even their own arms sometimes move dangerously close to the hair.</p><p id="1d94" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">It was also very important for the system to be easily used by artists without much back and forth between 3D and Dev teams. We knew we’d be importing a large number of hair rigs, so we wanted to make it as simple as possible for them. Currently, we have 65 hair configurations in the game, including those with the same style but different lengths.</p><h1 id="499c" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">How to Approach the Task</h1><p id="c4cc" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Facing a challenge like this was very interesting, because there were a lot of unknowns at the start of the project. We only had concept art at the time, so the exact style of the hair wasn’t yet known.</p><p id="9d67" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">When we start projects at Outfit7, we start with the pre-production phase. Typically, we mainly want to solve the difficult technical challenges as soon as possible in order to make the actual production smooth. However, at such an early stage, the art isn’t usually ready yet, so we have to make some assumptions. So for the hair system for My Talking Angela 2, I took a look at the art styles of our previous games, and used some assets from there as a starting point.</p><p id="101a" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Prototyping systems like this early in the production phase is absolutely necessary to avoid project delays in the future — at this stage, we have time to scrap everything and try something else if we need to. It’s also important to plan for things to go wrong. There should be some time dedicated for asset integration.</p><p id="ce2a" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">I tried to predict as many use cases as possible without overengineering for the end of the world — I knew that some things could be fixed later if problems arose during production.</p><h1 id="dc30" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Possible Approaches</h1><h1 id="948a" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Hair Cards</h1><p id="5aa2" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Hair cards are simple polygonal meshes used to shape the hair strands. They are <a class="af pn" href="https://en.wikipedia.org/wiki/UV_mapping" rel="noopener ugc nofollow" target="_blank">UV</a> wrapped in a way that you can texture them to display hair strands with a simple shader. They can be animated by <a class="af pn" href="https://en.wikipedia.org/wiki/Skeletal_animation#Technique" rel="noopener ugc nofollow" target="_blank">rigging</a> them, or even applying a vertex shader so they sway a bit when moving. But for our needs, this approach would be a bit too complicated, and we wanted something simpler in terms of geometry.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx po"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*DUVCAooC130ra4cS 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*DUVCAooC130ra4cS 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*DUVCAooC130ra4cS 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*DUVCAooC130ra4cS 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*DUVCAooC130ra4cS 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*DUVCAooC130ra4cS 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*DUVCAooC130ra4cS 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*DUVCAooC130ra4cS 640w, https://miro.medium.com/v2/resize:fit:720/0*DUVCAooC130ra4cS 720w, https://miro.medium.com/v2/resize:fit:750/0*DUVCAooC130ra4cS 750w, https://miro.medium.com/v2/resize:fit:786/0*DUVCAooC130ra4cS 786w, https://miro.medium.com/v2/resize:fit:828/0*DUVCAooC130ra4cS 828w, https://miro.medium.com/v2/resize:fit:1100/0*DUVCAooC130ra4cS 1100w, https://miro.medium.com/v2/resize:fit:1400/0*DUVCAooC130ra4cS 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="367" loading="lazy" role="presentation"/></picture></div></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du">A developer visualization of how a hair card setup for a sloppy mohawk could look like.</figcaption></figure><h1 id="8f5e" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Animated Hair</h1><p id="907f" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">With this approach we could have hair items rigged and animated traditionally. This would result in a larger application size because we were planning to have up to 30 bones per hair style, with multiple hair types. This would add a lot of animations to the game, just for the hair. Basically each of the character animations would require a matching hair animation. We would need to simplify it with reusing hair rigs, or blending idle poses.</p><p id="c498" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">But why is application size an issue? Well, mainly because we’re working with mobile games, and there are limits to how big of a game you can download over a cellular connection. For Android, this is currently 150MB, and it’s 200MB on iOS. From our experience, the increase in installs from being able to download the game via a cellular connection makes it worth it to stick to these limits.</p><p id="7593" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Fitting such a big game into 150MB? Well, that’s a topic for another blog post, but it involves a lot of clever tricks.</p><h1 id="1a10" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Procedural Animation</h1><p id="c7df" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Ah yes, now we’re talking. When in doubt, you should always use procedural animation.</p><p id="0e22" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">We’d still be able to use a traditional rigging setup with each hair style having up to 20 strands, but they would be animated dynamically based on world inputs. This would greatly simplify our workflows and make our animation team’s life easier. The downside to this approach is that you have less control over the final looks — unexpected things can happen due to the hair being simulated in real time.</p><p id="6241" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">In the end I chose this approach because I believed it would best fit our needs.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div class="nw nx pt"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*rnfHykY-fMXUKqRu 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*rnfHykY-fMXUKqRu 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*rnfHykY-fMXUKqRu 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*rnfHykY-fMXUKqRu 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*rnfHykY-fMXUKqRu 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*rnfHykY-fMXUKqRu 1100w, https://miro.medium.com/v2/resize:fit:1108/format:webp/0*rnfHykY-fMXUKqRu 1108w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 554px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*rnfHykY-fMXUKqRu 640w, https://miro.medium.com/v2/resize:fit:720/0*rnfHykY-fMXUKqRu 720w, https://miro.medium.com/v2/resize:fit:750/0*rnfHykY-fMXUKqRu 750w, https://miro.medium.com/v2/resize:fit:786/0*rnfHykY-fMXUKqRu 786w, https://miro.medium.com/v2/resize:fit:828/0*rnfHykY-fMXUKqRu 828w, https://miro.medium.com/v2/resize:fit:1100/0*rnfHykY-fMXUKqRu 1100w, https://miro.medium.com/v2/resize:fit:1108/0*rnfHykY-fMXUKqRu 1108w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 554px"/><img alt="" class="bh me oj c" width="554" height="554" loading="lazy" role="presentation"/></picture></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du">Individual hair strands.</figcaption></figure><h1 id="ec31" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Architecture</h1><p id="7013" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">I wanted the system to be designed in such a way that items should be independent of the other character systems. Basically, you just equip an item (hair, in this case), and the hair system takes care of the simulation.</p><p id="7583" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The system I designed consists of multiple parts. I tried to create it in such a way that it’s not specific to hair, but could also be used for other purposes. If you had some joints and you wanted them to move, for example, you could use this system with little effort. We’re calling it “Bone Physics”. Many jokes came to mind, but for now let’s focus on the topic at hand (I would prefer keeping my job if I can).</p><h1 id="9ea0" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Physics Joint</h1><p id="cf38" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">This is the smallest unit in the system. It’s a one-on-one wrapper for your world transform. It keeps references to the previous and current simulated positions, so we can make some calculations based on the differences between the two.</p><h1 id="c669" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Physics Chain</h1><p id="2fdb" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">This is a collection of physics joints. In the example of hair, <strong class="mz gv">one hair strand is represented by one chain</strong>. Each chain can have its own physics settings, so hair strands (chains) in the front can behave differently than strands in the back.</p><h1 id="a7a2" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Simulator Data</h1><p id="b761" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">In every frame of the simulation, we gather all the chain data, join it in SimulatorData, and feed it to the simulator.</p><h1 id="9fd8" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Physics Simulator</h1><p id="80b8" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">I will describe what the simulator does in the next section, but let’s call it a black box, one which takes in simulator data, processes it, and moves the physics joints to their new simulation positions.</p><p id="4a19" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">After the simulator finishes its job, we take the new joint positions and apply them to the actual 3D transforms. This completes our frame, and the same process is repeated for the next frame.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx pu"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*QFNJRSBUy2Ks7JIs 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*QFNJRSBUy2Ks7JIs 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*QFNJRSBUy2Ks7JIs 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*QFNJRSBUy2Ks7JIs 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*QFNJRSBUy2Ks7JIs 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*QFNJRSBUy2Ks7JIs 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*QFNJRSBUy2Ks7JIs 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*QFNJRSBUy2Ks7JIs 640w, https://miro.medium.com/v2/resize:fit:720/0*QFNJRSBUy2Ks7JIs 720w, https://miro.medium.com/v2/resize:fit:750/0*QFNJRSBUy2Ks7JIs 750w, https://miro.medium.com/v2/resize:fit:786/0*QFNJRSBUy2Ks7JIs 786w, https://miro.medium.com/v2/resize:fit:828/0*QFNJRSBUy2Ks7JIs 828w, https://miro.medium.com/v2/resize:fit:1100/0*QFNJRSBUy2Ks7JIs 1100w, https://miro.medium.com/v2/resize:fit:1400/0*QFNJRSBUy2Ks7JIs 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="406" loading="lazy" role="presentation"/></picture></div></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du">System architecture.</figcaption></figure><h1 id="3e9c" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Simulation</h1><p id="d827" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">For the simulation itself, the most important thing is that we’re using a fixed time step. This means that our simulation output won’t be affected by the frame rate of the device.</p><p id="9076" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">A simplified example of this can be seen below. A fixed time step means that if we want to do something in 160 milliseconds and one step takes 16 milliseconds, we’re getting 10 steps, no matter the FPS of the device. If we have a variable time step, on the other hand, we’re tied to the rendering speed of the device. Frames can take from 16.66 milliseconds (when targeting 60 FPS — 1s/60) to X milliseconds, where X depends on how badly our game is performing.</p><p id="f3b3" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">In the example below, we want to move the ball from position 0 to position 20. Each step, we increase the position by 2 and, with a fixed time step, we get to position 20 after 10 steps. When the time step is variable (16–32 milliseconds between steps in the example), we only get to execute 7 steps in 160 milliseconds. This only brings us to position 14, which is not what we wanted.</p><p id="6f85" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The end result for our physical simulation would be incorrect, and the behavior would appear different on slower devices.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx po"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*_m7AjZjK_AgqvdJs 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*_m7AjZjK_AgqvdJs 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*_m7AjZjK_AgqvdJs 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*_m7AjZjK_AgqvdJs 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*_m7AjZjK_AgqvdJs 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*_m7AjZjK_AgqvdJs 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*_m7AjZjK_AgqvdJs 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*_m7AjZjK_AgqvdJs 640w, https://miro.medium.com/v2/resize:fit:720/0*_m7AjZjK_AgqvdJs 720w, https://miro.medium.com/v2/resize:fit:750/0*_m7AjZjK_AgqvdJs 750w, https://miro.medium.com/v2/resize:fit:786/0*_m7AjZjK_AgqvdJs 786w, https://miro.medium.com/v2/resize:fit:828/0*_m7AjZjK_AgqvdJs 828w, https://miro.medium.com/v2/resize:fit:1100/0*_m7AjZjK_AgqvdJs 1100w, https://miro.medium.com/v2/resize:fit:1400/0*_m7AjZjK_AgqvdJs 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="508" loading="lazy" role="presentation"/></picture></div></div></figure><p id="b3b8" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">To fix this problem, most game engines will provide you with a fixed time step update loop. If you want to do it yourself, you have to measure the time between two frames, then break it up into equal parts.</p><h1 id="c1ed" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Calculation</h1><p id="e774" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">We use <a class="af pn" href="https://en.wikipedia.org/wiki/Verlet_integration" rel="noopener ugc nofollow" target="_blank">Verlet integration</a> for calculating joint movement, which means that we store the previous and current joint positions and calculate the next position based on those, as opposed to storing and using velocity as you usually do with Euler integration. This approach results in a more stable simulation.</p><p id="462a" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Verlet integration is often used for rope physics in game development. If you think about it, hair strands are kind of like tiny ropes, just a bit more rigid.</p><p id="a108" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The simulation itself is basically split up into two steps:</p><ol class=""><li id="e7ce" class="mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu pv pw px bk">Calculate forces (gravity, other world influences like wind, etc.); and</li><li id="3aee" class="mx my gu mz b na py nc nd ne pz ng nh ni qa nk nl nm qb no np nq qc ns nt nu pv pw px bk">Apply constraints.</li></ol><pre class="nz oa ob oc od qd qe qf bp qg bb bk"><span id="8ec8" class="qh ol gu qe b bg qi qj l qk ql">void BonePhysicsSimulator::Simulate(const SimulatorData& data) {<br/> DebugAssert(data.chain_.Count(), "Empty chain");<br/> SetInitialJointPositions(data);<br/> ApplyForce(data);<br/> ApplyConstraints(data);<br/> ApplySimulationUpdates(data);<br/>}</span></pre><p id="6bac" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Constraints are what limits or enhances the movement of joints to achieve the desired effect. You can apply the constraints multiple times — the more you do it, the more accurate the simulation result will be. But it comes at a cost as you will burn more precious CPU cycles.</p><h1 id="43b5" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Simulation Constraints</h1><h1 id="50f6" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Damping</h1><p id="d704" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">This is used to reduce the effect of position change. The effect is applied from the start to the end of the chain.</p></div></div><div class="oe"><div class="ab cb"><div class="lz qm ma qn mb qo cf qp cg qq ci bh"><div class="nz oa ob oc od ab kv"><figure class="lr oe qr qs qt qu qv paragraph-image"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*Tn_QohjKYD_D4vDu 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*Tn_QohjKYD_D4vDu 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*Tn_QohjKYD_D4vDu 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*Tn_QohjKYD_D4vDu 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*Tn_QohjKYD_D4vDu 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*Tn_QohjKYD_D4vDu 1100w, https://miro.medium.com/v2/resize:fit:784/format:webp/0*Tn_QohjKYD_D4vDu 784w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 392px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*Tn_QohjKYD_D4vDu 640w, https://miro.medium.com/v2/resize:fit:720/0*Tn_QohjKYD_D4vDu 720w, https://miro.medium.com/v2/resize:fit:750/0*Tn_QohjKYD_D4vDu 750w, https://miro.medium.com/v2/resize:fit:786/0*Tn_QohjKYD_D4vDu 786w, https://miro.medium.com/v2/resize:fit:828/0*Tn_QohjKYD_D4vDu 828w, https://miro.medium.com/v2/resize:fit:1100/0*Tn_QohjKYD_D4vDu 1100w, https://miro.medium.com/v2/resize:fit:784/0*Tn_QohjKYD_D4vDu 784w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 392px"/><img alt="" class="bh me oj c" width="392" height="516" loading="eager" role="presentation"/></picture></figure><figure class="lr oe qw qs qt qu qv paragraph-image"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*UXCvfvbh88BGFUH8 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*UXCvfvbh88BGFUH8 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*UXCvfvbh88BGFUH8 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*UXCvfvbh88BGFUH8 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*UXCvfvbh88BGFUH8 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*UXCvfvbh88BGFUH8 1100w, https://miro.medium.com/v2/resize:fit:780/format:webp/0*UXCvfvbh88BGFUH8 780w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 390px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*UXCvfvbh88BGFUH8 640w, https://miro.medium.com/v2/resize:fit:720/0*UXCvfvbh88BGFUH8 720w, https://miro.medium.com/v2/resize:fit:750/0*UXCvfvbh88BGFUH8 750w, https://miro.medium.com/v2/resize:fit:786/0*UXCvfvbh88BGFUH8 786w, https://miro.medium.com/v2/resize:fit:828/0*UXCvfvbh88BGFUH8 828w, https://miro.medium.com/v2/resize:fit:1100/0*UXCvfvbh88BGFUH8 1100w, https://miro.medium.com/v2/resize:fit:780/0*UXCvfvbh88BGFUH8 780w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 390px"/><img alt="" class="bh me oj c" width="390" height="514" loading="eager" role="presentation"/></picture></figure></div></div></div></div><div class="ab cb"><div class="ci bh fz ga gb gc"><pre class="nz oa ob oc od qd qe qf bp qg bb bk"><span id="d9a8" class="qh ol gu qe b bg qi qj l qk ql">Vector3 BonePhysicsSimulator::DampPositionDelta(const Vector3& velocity, const Ref<BonePhysicsConfiguration>& physics_configuration) {<br/> return velocity * (1 - physics_configuration->damping_);<br/>}</span></pre><h1 id="8047" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Bounciness</h1><p id="7265" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">This is used to enhance the effect of joint movement down the chain.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div class="nw nx qx"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*D7q8X4TzN3ttw7XY 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*D7q8X4TzN3ttw7XY 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*D7q8X4TzN3ttw7XY 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*D7q8X4TzN3ttw7XY 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*D7q8X4TzN3ttw7XY 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*D7q8X4TzN3ttw7XY 1100w, https://miro.medium.com/v2/resize:fit:1072/format:webp/0*D7q8X4TzN3ttw7XY 1072w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 536px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*D7q8X4TzN3ttw7XY 640w, https://miro.medium.com/v2/resize:fit:720/0*D7q8X4TzN3ttw7XY 720w, https://miro.medium.com/v2/resize:fit:750/0*D7q8X4TzN3ttw7XY 750w, https://miro.medium.com/v2/resize:fit:786/0*D7q8X4TzN3ttw7XY 786w, https://miro.medium.com/v2/resize:fit:828/0*D7q8X4TzN3ttw7XY 828w, https://miro.medium.com/v2/resize:fit:1100/0*D7q8X4TzN3ttw7XY 1100w, https://miro.medium.com/v2/resize:fit:1072/0*D7q8X4TzN3ttw7XY 1072w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 536px"/><img alt="" class="bh me oj c" width="536" height="536" loading="lazy" role="presentation"/></picture></div></figure><pre class="nz oa ob oc od qd qe qf bp qg bb bk"><span id="bb50" class="qh ol gu qe b bg qi qj l qk ql">Vector3 diff = previous_position - joint->simulation_position_;<br/>joint->simulation_position_ += diff * (1 - bounciness);</span></pre><h1 id="38a2" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Collision</h1><p id="7414" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">I decided to implement my own collision system because it was simple enough to add to the simulation, and it enabled me to fine-tune hair collision without relying on external dependencies.</p><p id="7cad" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">We ended up supporting multiple types of colliders — sphere, plane, capsule.</p></div></div><div class="oe"><div class="ab cb"><div class="lz qm ma qn mb qo cf qp cg qq ci bh"><div class="nz oa ob oc od ab kv"><figure class="lr oe qy qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*IVuUYXDgNNlteiHK 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*IVuUYXDgNNlteiHK 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*IVuUYXDgNNlteiHK 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*IVuUYXDgNNlteiHK 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*IVuUYXDgNNlteiHK 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*IVuUYXDgNNlteiHK 1100w, https://miro.medium.com/v2/resize:fit:1006/format:webp/0*IVuUYXDgNNlteiHK 1006w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 503px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*IVuUYXDgNNlteiHK 640w, https://miro.medium.com/v2/resize:fit:720/0*IVuUYXDgNNlteiHK 720w, https://miro.medium.com/v2/resize:fit:750/0*IVuUYXDgNNlteiHK 750w, https://miro.medium.com/v2/resize:fit:786/0*IVuUYXDgNNlteiHK 786w, https://miro.medium.com/v2/resize:fit:828/0*IVuUYXDgNNlteiHK 828w, https://miro.medium.com/v2/resize:fit:1100/0*IVuUYXDgNNlteiHK 1100w, https://miro.medium.com/v2/resize:fit:1006/0*IVuUYXDgNNlteiHK 1006w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 503px"/><img alt="" class="bh me oj c" width="503" height="531" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe qz qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*5UEwNYVkPLyk16Wg 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*5UEwNYVkPLyk16Wg 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*5UEwNYVkPLyk16Wg 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*5UEwNYVkPLyk16Wg 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*5UEwNYVkPLyk16Wg 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*5UEwNYVkPLyk16Wg 1100w, https://miro.medium.com/v2/resize:fit:996/format:webp/0*5UEwNYVkPLyk16Wg 996w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 498px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*5UEwNYVkPLyk16Wg 640w, https://miro.medium.com/v2/resize:fit:720/0*5UEwNYVkPLyk16Wg 720w, https://miro.medium.com/v2/resize:fit:750/0*5UEwNYVkPLyk16Wg 750w, https://miro.medium.com/v2/resize:fit:786/0*5UEwNYVkPLyk16Wg 786w, https://miro.medium.com/v2/resize:fit:828/0*5UEwNYVkPLyk16Wg 828w, https://miro.medium.com/v2/resize:fit:1100/0*5UEwNYVkPLyk16Wg 1100w, https://miro.medium.com/v2/resize:fit:996/0*5UEwNYVkPLyk16Wg 996w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 498px"/><img alt="" class="bh me oj c" width="498" height="536" loading="eager" role="presentation"/></picture></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du ra fj rb rc"><em class="rd">Sphere-to-sphere collision and sphere-to-plane collision.</em></figcaption></figure></div><div class="ab kv"><figure class="lr oe re qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*5Sj8eifRbgGUjWKB 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*5Sj8eifRbgGUjWKB 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*5Sj8eifRbgGUjWKB 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*5Sj8eifRbgGUjWKB 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*5Sj8eifRbgGUjWKB 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*5Sj8eifRbgGUjWKB 1100w, https://miro.medium.com/v2/resize:fit:1002/format:webp/0*5Sj8eifRbgGUjWKB 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*5Sj8eifRbgGUjWKB 640w, https://miro.medium.com/v2/resize:fit:720/0*5Sj8eifRbgGUjWKB 720w, https://miro.medium.com/v2/resize:fit:750/0*5Sj8eifRbgGUjWKB 750w, https://miro.medium.com/v2/resize:fit:786/0*5Sj8eifRbgGUjWKB 786w, https://miro.medium.com/v2/resize:fit:828/0*5Sj8eifRbgGUjWKB 828w, https://miro.medium.com/v2/resize:fit:1100/0*5Sj8eifRbgGUjWKB 1100w, https://miro.medium.com/v2/resize:fit:1002/0*5Sj8eifRbgGUjWKB 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px"/><img alt="" class="bh me oj c" width="501" height="535" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe rf qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*soHknyHSoE_kly4g 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*soHknyHSoE_kly4g 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*soHknyHSoE_kly4g 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*soHknyHSoE_kly4g 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*soHknyHSoE_kly4g 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*soHknyHSoE_kly4g 1100w, https://miro.medium.com/v2/resize:fit:1000/format:webp/0*soHknyHSoE_kly4g 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*soHknyHSoE_kly4g 640w, https://miro.medium.com/v2/resize:fit:720/0*soHknyHSoE_kly4g 720w, https://miro.medium.com/v2/resize:fit:750/0*soHknyHSoE_kly4g 750w, https://miro.medium.com/v2/resize:fit:786/0*soHknyHSoE_kly4g 786w, https://miro.medium.com/v2/resize:fit:828/0*soHknyHSoE_kly4g 828w, https://miro.medium.com/v2/resize:fit:1100/0*soHknyHSoE_kly4g 1100w, https://miro.medium.com/v2/resize:fit:1000/0*soHknyHSoE_kly4g 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px"/><img alt="" class="bh me oj c" width="500" height="1600" loading="eager" role="presentation"/></picture></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du rg fj rh rc"><em class="rd">Sphere-to-capsule collision and the character collider setup.</em></figcaption></figure></div></div></div></div><div class="ab cb"><div class="ci bh fz ga gb gc"><h1 id="6ccb" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Rotation Lock</h1><p id="1410" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">I implemented rotation lock, which allows you to limit the maximum angle of rotation from parent to child joint. For example, you could say that the maximum bend is 90 degrees, which could be useful in some cases. However, in the end we didn’t use it for the hair system.</p><h1 id="61be" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Pinned Joints</h1><p id="4db9" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">My Talking Angela 2 features a bathroom where you can bathe your Talking Angela by applying some soap to her. This spawns soap bubbles all over the character, and you have to wash them off using a shower head.</p><p id="87c7" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">To animate the shower hose, we used the bone physics system. However, the final joint needed to be moveable as the player was going to drag it around.</p><p id="89c7" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">We could simply override the joint’s position in the simulation, and the rest of the joints would react to that. We called this process “joint pinning”.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div class="nw nx ri"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*QH0VOYNBAwretZx1 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*QH0VOYNBAwretZx1 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*QH0VOYNBAwretZx1 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*QH0VOYNBAwretZx1 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*QH0VOYNBAwretZx1 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*QH0VOYNBAwretZx1 1100w, https://miro.medium.com/v2/resize:fit:1088/format:webp/0*QH0VOYNBAwretZx1 1088w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 544px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*QH0VOYNBAwretZx1 640w, https://miro.medium.com/v2/resize:fit:720/0*QH0VOYNBAwretZx1 720w, https://miro.medium.com/v2/resize:fit:750/0*QH0VOYNBAwretZx1 750w, https://miro.medium.com/v2/resize:fit:786/0*QH0VOYNBAwretZx1 786w, https://miro.medium.com/v2/resize:fit:828/0*QH0VOYNBAwretZx1 828w, https://miro.medium.com/v2/resize:fit:1100/0*QH0VOYNBAwretZx1 1100w, https://miro.medium.com/v2/resize:fit:1088/0*QH0VOYNBAwretZx1 1088w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 544px"/><img alt="" class="bh me oj c" width="544" height="544" loading="lazy" role="presentation"/></picture></div></figure><h1 id="4309" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Joint Rotation</h1><p id="530e" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Just a tip if you’re ever working on something similar yourself — if you want to keep the chain mesh volume consistent, an important step is to always rotate the child joint towards the parent. If you don’t, the mesh will appear stretched.</p><h1 id="a76e" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Simulation Weight</h1><p id="c1c7" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Simulation weight is a variable that tells the simulator how strongly to apply the simulation result to the final joint position. It lerps between the original joint position and the simulated joint position.</p><p id="c652" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">This would allow us to have stylized physics in cases where physically correct simulations would break the desired hairstyle. For example, if we have a braid over the shoulder, we want to keep it on the shoulder at all times, while allowing it to bounce a bit when moving. If we were to use the simulation fully, the braid would simply fall down, being pulled by gravity.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx rj"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*NBj50R9Nwk99hH4R 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*NBj50R9Nwk99hH4R 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*NBj50R9Nwk99hH4R 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*NBj50R9Nwk99hH4R 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*NBj50R9Nwk99hH4R 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*NBj50R9Nwk99hH4R 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*NBj50R9Nwk99hH4R 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*NBj50R9Nwk99hH4R 640w, https://miro.medium.com/v2/resize:fit:720/0*NBj50R9Nwk99hH4R 720w, https://miro.medium.com/v2/resize:fit:750/0*NBj50R9Nwk99hH4R 750w, https://miro.medium.com/v2/resize:fit:786/0*NBj50R9Nwk99hH4R 786w, https://miro.medium.com/v2/resize:fit:828/0*NBj50R9Nwk99hH4R 828w, https://miro.medium.com/v2/resize:fit:1100/0*NBj50R9Nwk99hH4R 1100w, https://miro.medium.com/v2/resize:fit:1400/0*NBj50R9Nwk99hH4R 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="286" loading="lazy" role="presentation"/></picture></div></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du"><em class="rd">Debugging hair texture — the final result is much nicer.</em></figcaption></figure><figure class="nz oa ob oc od oe nw nx paragraph-image"><div class="nw nx rk"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 1100w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*aa9jNd5P7RHuqRAuqiBJGg.gif 828w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 414px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/1*aa9jNd5P7RHuqRAuqiBJGg.gif 640w, https://miro.medium.com/v2/resize:fit:720/1*aa9jNd5P7RHuqRAuqiBJGg.gif 720w, https://miro.medium.com/v2/resize:fit:750/1*aa9jNd5P7RHuqRAuqiBJGg.gif 750w, https://miro.medium.com/v2/resize:fit:786/1*aa9jNd5P7RHuqRAuqiBJGg.gif 786w, https://miro.medium.com/v2/resize:fit:828/1*aa9jNd5P7RHuqRAuqiBJGg.gif 828w, https://miro.medium.com/v2/resize:fit:1100/1*aa9jNd5P7RHuqRAuqiBJGg.gif 1100w, https://miro.medium.com/v2/resize:fit:828/1*aa9jNd5P7RHuqRAuqiBJGg.gif 828w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 414px"/><img alt="" class="bh me oj c" width="414" height="549" loading="lazy" role="presentation"/></picture></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du"><em class="rd">Stylized physics example — the braid over the shoulder.</em></figcaption></figure><p id="6120" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">With this, we could also animate parts of the hair with traditional animation, if needed. This would be useful in complex cases, like when Angela is getting up in the morning.</p><p id="0a5f" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">We are now also able to combine different physics behaviors per hair style, because each chain has its own properties. A ponytail could be fully physically simulated, for example.</p><h1 id="b624" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Applying the System to a Hair Rig</h1><p id="2928" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">We have 1 to 20 chains per hair rig. There is no need to cross-connect the chains like you would do for cloth simulation. As each of the chains is standalone, we can have some mesh clipping for more complex hair. Angela’s arms can pass between the strands in some cases, but we decided that that would be acceptable.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div class="nw nx rl"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*Qm1qjNFtRxFoB7KI 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*Qm1qjNFtRxFoB7KI 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*Qm1qjNFtRxFoB7KI 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*Qm1qjNFtRxFoB7KI 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*Qm1qjNFtRxFoB7KI 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*Qm1qjNFtRxFoB7KI 1100w, https://miro.medium.com/v2/resize:fit:1110/format:webp/0*Qm1qjNFtRxFoB7KI 1110w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 555px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*Qm1qjNFtRxFoB7KI 640w, https://miro.medium.com/v2/resize:fit:720/0*Qm1qjNFtRxFoB7KI 720w, https://miro.medium.com/v2/resize:fit:750/0*Qm1qjNFtRxFoB7KI 750w, https://miro.medium.com/v2/resize:fit:786/0*Qm1qjNFtRxFoB7KI 786w, https://miro.medium.com/v2/resize:fit:828/0*Qm1qjNFtRxFoB7KI 828w, https://miro.medium.com/v2/resize:fit:1100/0*Qm1qjNFtRxFoB7KI 1100w, https://miro.medium.com/v2/resize:fit:1110/0*Qm1qjNFtRxFoB7KI 1110w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 555px"/><img alt="" class="bh me oj c" width="555" height="554" loading="lazy" role="presentation"/></picture></div></figure><p id="5ec4" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Each hair style has from 1 to 3 different lengths, so we reused a lot of rigs to minimize the app size as much as possible.</p><h1 id="459d" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Results</h1></div></div><div class="oe"><div class="ab cb"><div class="lz qm ma qn mb qo cf qp cg qq ci bh"><div class="nz oa ob oc od ab kv"><figure class="lr oe rm qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 1100w, https://miro.medium.com/v2/resize:fit:1000/format:webp/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 640w, https://miro.medium.com/v2/resize:fit:720/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 720w, https://miro.medium.com/v2/resize:fit:750/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 750w, https://miro.medium.com/v2/resize:fit:786/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 786w, https://miro.medium.com/v2/resize:fit:828/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 828w, https://miro.medium.com/v2/resize:fit:1100/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 1100w, https://miro.medium.com/v2/resize:fit:1000/1*v6IBVwy-AvrSgLxJTwiSvQ.gif 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px"/><img alt="" class="bh me oj c" width="500" height="850" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe rn qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*nqfFY-AmQ6C_n63U 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*nqfFY-AmQ6C_n63U 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*nqfFY-AmQ6C_n63U 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*nqfFY-AmQ6C_n63U 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*nqfFY-AmQ6C_n63U 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*nqfFY-AmQ6C_n63U 1100w, https://miro.medium.com/v2/resize:fit:1002/format:webp/0*nqfFY-AmQ6C_n63U 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*nqfFY-AmQ6C_n63U 640w, https://miro.medium.com/v2/resize:fit:720/0*nqfFY-AmQ6C_n63U 720w, https://miro.medium.com/v2/resize:fit:750/0*nqfFY-AmQ6C_n63U 750w, https://miro.medium.com/v2/resize:fit:786/0*nqfFY-AmQ6C_n63U 786w, https://miro.medium.com/v2/resize:fit:828/0*nqfFY-AmQ6C_n63U 828w, https://miro.medium.com/v2/resize:fit:1100/0*nqfFY-AmQ6C_n63U 1100w, https://miro.medium.com/v2/resize:fit:1002/0*nqfFY-AmQ6C_n63U 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px"/><img alt="" class="bh me oj c" width="501" height="850" loading="eager" role="presentation"/></picture></div></figure></div><div class="ab kv"><figure class="lr oe ro qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*WXnE-MITNznbJ_FC 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*WXnE-MITNznbJ_FC 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*WXnE-MITNznbJ_FC 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*WXnE-MITNznbJ_FC 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*WXnE-MITNznbJ_FC 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*WXnE-MITNznbJ_FC 1100w, https://miro.medium.com/v2/resize:fit:676/format:webp/0*WXnE-MITNznbJ_FC 676w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 338px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*WXnE-MITNznbJ_FC 640w, https://miro.medium.com/v2/resize:fit:720/0*WXnE-MITNznbJ_FC 720w, https://miro.medium.com/v2/resize:fit:750/0*WXnE-MITNznbJ_FC 750w, https://miro.medium.com/v2/resize:fit:786/0*WXnE-MITNznbJ_FC 786w, https://miro.medium.com/v2/resize:fit:828/0*WXnE-MITNznbJ_FC 828w, https://miro.medium.com/v2/resize:fit:1100/0*WXnE-MITNznbJ_FC 1100w, https://miro.medium.com/v2/resize:fit:676/0*WXnE-MITNznbJ_FC 676w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 338px"/><img alt="" class="bh me oj c" width="338" height="741" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe rp qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 1100w, https://miro.medium.com/v2/resize:fit:574/format:webp/1*AvuxgnwCY_EgSjXpBMRWZw.gif 574w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 287px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/1*AvuxgnwCY_EgSjXpBMRWZw.gif 640w, https://miro.medium.com/v2/resize:fit:720/1*AvuxgnwCY_EgSjXpBMRWZw.gif 720w, https://miro.medium.com/v2/resize:fit:750/1*AvuxgnwCY_EgSjXpBMRWZw.gif 750w, https://miro.medium.com/v2/resize:fit:786/1*AvuxgnwCY_EgSjXpBMRWZw.gif 786w, https://miro.medium.com/v2/resize:fit:828/1*AvuxgnwCY_EgSjXpBMRWZw.gif 828w, https://miro.medium.com/v2/resize:fit:1100/1*AvuxgnwCY_EgSjXpBMRWZw.gif 1100w, https://miro.medium.com/v2/resize:fit:574/1*AvuxgnwCY_EgSjXpBMRWZw.gif 574w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 287px"/><img alt="" class="bh me oj c" width="287" height="716" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe rq qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*mh90cFJFM4NIjo7U 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*mh90cFJFM4NIjo7U 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*mh90cFJFM4NIjo7U 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*mh90cFJFM4NIjo7U 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*mh90cFJFM4NIjo7U 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*mh90cFJFM4NIjo7U 1100w, https://miro.medium.com/v2/resize:fit:752/format:webp/0*mh90cFJFM4NIjo7U 752w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 376px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*mh90cFJFM4NIjo7U 640w, https://miro.medium.com/v2/resize:fit:720/0*mh90cFJFM4NIjo7U 720w, https://miro.medium.com/v2/resize:fit:750/0*mh90cFJFM4NIjo7U 750w, https://miro.medium.com/v2/resize:fit:786/0*mh90cFJFM4NIjo7U 786w, https://miro.medium.com/v2/resize:fit:828/0*mh90cFJFM4NIjo7U 828w, https://miro.medium.com/v2/resize:fit:1100/0*mh90cFJFM4NIjo7U 1100w, https://miro.medium.com/v2/resize:fit:752/0*mh90cFJFM4NIjo7U 752w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 376px"/><img alt="" class="bh me oj c" width="376" height="391" loading="eager" role="presentation"/></picture></div></figure></div></div></div></div><div class="ab cb"><div class="ci bh fz ga gb gc"><h1 id="1c3d" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Workflow for Artists</h1><p id="e874" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">It’s a two-step process. When a rig is imported from 3D software to our engine, you can right-click it and use a context menu that runs a hair setup script on it. What it does is finds the root joint, then adds a BonePhysicsChain object for each chain that it finds, and automatically links all the child joints. It also automatically creates a physics setup configuration object with some defaults that suit most of the hair dynamics, so in an ideal case you probably don’t even have to tweak the settings that much.</p><p id="0a0c" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The second part is testing the hair, which is done using another context menu. It will spawn the hair for you, to quickly verify if it’s working.</p><figure class="nz oa ob oc od oe nw nx paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><div class="nw nx rr"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*B5TkKY50Vw_nYidG 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*B5TkKY50Vw_nYidG 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*B5TkKY50Vw_nYidG 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*B5TkKY50Vw_nYidG 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*B5TkKY50Vw_nYidG 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*B5TkKY50Vw_nYidG 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*B5TkKY50Vw_nYidG 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*B5TkKY50Vw_nYidG 640w, https://miro.medium.com/v2/resize:fit:720/0*B5TkKY50Vw_nYidG 720w, https://miro.medium.com/v2/resize:fit:750/0*B5TkKY50Vw_nYidG 750w, https://miro.medium.com/v2/resize:fit:786/0*B5TkKY50Vw_nYidG 786w, https://miro.medium.com/v2/resize:fit:828/0*B5TkKY50Vw_nYidG 828w, https://miro.medium.com/v2/resize:fit:1100/0*B5TkKY50Vw_nYidG 1100w, https://miro.medium.com/v2/resize:fit:1400/0*B5TkKY50Vw_nYidG 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh me oj c" width="700" height="700" loading="eager" role="presentation"/></picture></div></div></figure><h1 id="f1cf" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Other Applications</h1><p id="5ba0" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">One of the other use cases is the shower hose, as previously mentioned above. We also used it to animate some headwear, as shown below.</p></div></div><div class="oe"><div class="ab cb"><div class="lz qm ma qn mb qo cf qp cg qq ci bh"><div class="nz oa ob oc od ab kv"><figure class="lr oe rs qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*zvRT44FbgCduymTT 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*zvRT44FbgCduymTT 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*zvRT44FbgCduymTT 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*zvRT44FbgCduymTT 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*zvRT44FbgCduymTT 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*zvRT44FbgCduymTT 1100w, https://miro.medium.com/v2/resize:fit:670/format:webp/0*zvRT44FbgCduymTT 670w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 335px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*zvRT44FbgCduymTT 640w, https://miro.medium.com/v2/resize:fit:720/0*zvRT44FbgCduymTT 720w, https://miro.medium.com/v2/resize:fit:750/0*zvRT44FbgCduymTT 750w, https://miro.medium.com/v2/resize:fit:786/0*zvRT44FbgCduymTT 786w, https://miro.medium.com/v2/resize:fit:828/0*zvRT44FbgCduymTT 828w, https://miro.medium.com/v2/resize:fit:1100/0*zvRT44FbgCduymTT 1100w, https://miro.medium.com/v2/resize:fit:670/0*zvRT44FbgCduymTT 670w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 335px"/><img alt="" class="bh me oj c" width="335" height="513" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe rt qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*Ts8soQ4lWr6MUcni 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*Ts8soQ4lWr6MUcni 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*Ts8soQ4lWr6MUcni 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*Ts8soQ4lWr6MUcni 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*Ts8soQ4lWr6MUcni 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*Ts8soQ4lWr6MUcni 1100w, https://miro.medium.com/v2/resize:fit:668/format:webp/0*Ts8soQ4lWr6MUcni 668w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 334px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*Ts8soQ4lWr6MUcni 640w, https://miro.medium.com/v2/resize:fit:720/0*Ts8soQ4lWr6MUcni 720w, https://miro.medium.com/v2/resize:fit:750/0*Ts8soQ4lWr6MUcni 750w, https://miro.medium.com/v2/resize:fit:786/0*Ts8soQ4lWr6MUcni 786w, https://miro.medium.com/v2/resize:fit:828/0*Ts8soQ4lWr6MUcni 828w, https://miro.medium.com/v2/resize:fit:1100/0*Ts8soQ4lWr6MUcni 1100w, https://miro.medium.com/v2/resize:fit:668/0*Ts8soQ4lWr6MUcni 668w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 334px"/><img alt="" class="bh me oj c" width="334" height="390" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe ru qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*DnqxN_XUG9S0Jom1 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*DnqxN_XUG9S0Jom1 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*DnqxN_XUG9S0Jom1 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*DnqxN_XUG9S0Jom1 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*DnqxN_XUG9S0Jom1 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*DnqxN_XUG9S0Jom1 1100w, https://miro.medium.com/v2/resize:fit:664/format:webp/0*DnqxN_XUG9S0Jom1 664w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 332px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*DnqxN_XUG9S0Jom1 640w, https://miro.medium.com/v2/resize:fit:720/0*DnqxN_XUG9S0Jom1 720w, https://miro.medium.com/v2/resize:fit:750/0*DnqxN_XUG9S0Jom1 750w, https://miro.medium.com/v2/resize:fit:786/0*DnqxN_XUG9S0Jom1 786w, https://miro.medium.com/v2/resize:fit:828/0*DnqxN_XUG9S0Jom1 828w, https://miro.medium.com/v2/resize:fit:1100/0*DnqxN_XUG9S0Jom1 1100w, https://miro.medium.com/v2/resize:fit:664/0*DnqxN_XUG9S0Jom1 664w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 332px"/><img alt="" class="bh me oj c" width="332" height="578" loading="eager" role="presentation"/></picture></div><figcaption class="pp ff pq nw nx pr ps bf b bg z du rv fj rw rc"><em class="rd">Headwear and some bouncy spheres that were used when testing the system in development.</em></figcaption></figure></div></div></div></div><div class="ab cb"><div class="ci bh fz ga gb gc"><h1 id="c243" class="ok ol gu bf om on oo op oq or os ot ou ov ow ox oy oz pa pb pc pd pe pf pg ph bk">Conclusion</h1><p id="4340" class="pw-post-body-paragraph mx my gu mz b na pi nc nd ne pj ng nh ni pk nk nl nm pl no np nq pm ns nt nu gn bk">Working on the hair system for My Talking Angela 2 was a challenging project for me. There were so many unknowns, the biggest and the most important of which was the fact that the style of the game wasn’t yet finalized. (Although artists might say that the style is never final — at least until it’s final, final). I had to guess some things and, in the end, I created some small features that weren’t used. That was a shame because I probably made some cool bugs that will never see the light of day.</p><p id="2514" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Looking at it now, the system is kind of simple. But you know what? If I were to do it again, I would simplify it even further, and get an artist on board as soon as possible to help prototype the custom-made assets.</p><p id="0bbb" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Performance-wise, we haven’t had any issues so far, which is great. But we’re targeting mobile devices, so every bit of extra performance helps — if nothing else, the battery of the device lasts longer. As the Bone Physics system is designed in a self-sufficient way — I called it a “black box” before — all the calculations could also be run on a different thread, and then at the end we could just apply them on the main thread.</p><p id="4ab3" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">In the future, I think we could improve some clipping issues by pairing up the joints in the Physics Chain, and treating them as capsule colliders, which would improve hair behavior when Angela’s arm passes through a hair strand. But overall, I’m very proud of the end result, and I’m looking forward to doing something similar in the future.</p><p id="85f5" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">The best thing about this whole process is that it was pretty hilarious. Some of the bugs I produced were ridiculous and I’m sorry I didn’t record more of them. I’m leaving you with these, as a taste.</p><p id="5149" class="pw-post-body-paragraph mx my gu mz b na nb nc nd ne nf ng nh ni nj nk nl nm nn no np nq nr ns nt nu gn bk">Thank you for reading.</p></div></div><div class="oe"><div class="ab cb"><div class="lz qm ma qn mb qo cf qp cg qq ci bh"><div class="nz oa ob oc od ab kv"><figure class="lr oe rx qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*EFBBW3Pr026N1LVI 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*EFBBW3Pr026N1LVI 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*EFBBW3Pr026N1LVI 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*EFBBW3Pr026N1LVI 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*EFBBW3Pr026N1LVI 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*EFBBW3Pr026N1LVI 1100w, https://miro.medium.com/v2/resize:fit:1002/format:webp/0*EFBBW3Pr026N1LVI 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*EFBBW3Pr026N1LVI 640w, https://miro.medium.com/v2/resize:fit:720/0*EFBBW3Pr026N1LVI 720w, https://miro.medium.com/v2/resize:fit:750/0*EFBBW3Pr026N1LVI 750w, https://miro.medium.com/v2/resize:fit:786/0*EFBBW3Pr026N1LVI 786w, https://miro.medium.com/v2/resize:fit:828/0*EFBBW3Pr026N1LVI 828w, https://miro.medium.com/v2/resize:fit:1100/0*EFBBW3Pr026N1LVI 1100w, https://miro.medium.com/v2/resize:fit:1002/0*EFBBW3Pr026N1LVI 1002w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 501px"/><img alt="" class="bh me oj c" width="501" height="644" loading="eager" role="presentation"/></picture></div></figure><figure class="lr oe ry qs qt qu qv paragraph-image"><div role="button" tabindex="0" class="of og fj oh bh oi"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*hsM9c4wuxvHL1V7w 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*hsM9c4wuxvHL1V7w 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*hsM9c4wuxvHL1V7w 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*hsM9c4wuxvHL1V7w 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*hsM9c4wuxvHL1V7w 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*hsM9c4wuxvHL1V7w 1100w, https://miro.medium.com/v2/resize:fit:1000/format:webp/0*hsM9c4wuxvHL1V7w 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*hsM9c4wuxvHL1V7w 640w, https://miro.medium.com/v2/resize:fit:720/0*hsM9c4wuxvHL1V7w 720w, https://miro.medium.com/v2/resize:fit:750/0*hsM9c4wuxvHL1V7w 750w, https://miro.medium.com/v2/resize:fit:786/0*hsM9c4wuxvHL1V7w 786w, https://miro.medium.com/v2/resize:fit:828/0*hsM9c4wuxvHL1V7w 828w, https://miro.medium.com/v2/resize:fit:1100/0*hsM9c4wuxvHL1V7w 1100w, https://miro.medium.com/v2/resize:fit:1000/0*hsM9c4wuxvHL1V7w 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px"/><img alt="" class="bh me oj c" width="500" height="645" loading="eager" role="presentation"/></picture></div></figure></div></div></div></div></div></div></section></div></div></article></div><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="rz sa ab ja"><div class="sb ab"><a class="sc ay am ao" rel="noopener follow" href="/tag/game-development?source=post_page-----46cf06181893--------------------------------"><div class="sd fj cx se ge sf sg bf b bg z bk sh">Game Development</div></a></div><div class="sb ab"><a class="sc ay am ao" rel="noopener follow" href="/tag/procedural-animation?source=post_page-----46cf06181893--------------------------------"><div class="sd fj cx se ge sf sg bf b bg z bk sh">Procedural Animation</div></a></div><div class="sb ab"><a class="sc ay am ao" rel="noopener follow" href="/tag/simulation?source=post_page-----46cf06181893--------------------------------"><div class="sd fj cx se ge sf sg bf b bg z bk sh">Simulation</div></a></div><div class="sb ab"><a class="sc ay am ao" rel="noopener follow" href="/tag/mobile-games?source=post_page-----46cf06181893--------------------------------"><div class="sd fj cx se ge sf sg bf b bg z bk sh">Mobile Games</div></a></div><div class="sb ab"><a class="sc ay am ao" rel="noopener follow" href="/tag/rendering?source=post_page-----46cf06181893--------------------------------"><div class="sd fj cx se ge sf sg bf b bg z bk sh">Rendering</div></a></div></div></div></div><div class="l"></div><footer class="si sj sk sl sm ab q sn ik c"><div class="l ae"><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="ab cp so"><div class="ab q kv"><div class="sp l"><span class="l sq sr ss e d"><div class="ab q kv kw"><div class="pw-multi-vote-icon fj je kx ky kz"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Foutfit7%2F46cf06181893&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&user=Aleksander+Gregorka&userId=565c34edb417&source=---footer_actions--46cf06181893---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="la ao lb lc ld le am lf lg lh kz"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l li lj lk ll lm ln lo"><p class="bf b dv z du"><span class="lp">--</span></p></div></div></span><span class="l h g f st su"><div class="ab q kv kw"><div class="pw-multi-vote-icon fj je kx ky kz"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Foutfit7%2F46cf06181893&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&user=Aleksander+Gregorka&userId=565c34edb417&source=---footer_actions--46cf06181893---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="la ao lb lc ld le am lf lg lh kz"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l li lj lk ll lm ln lo"><p class="bf b dv z du"><span class="lp">--</span></p></div></div></span></div><div class="bq ab"><div><div class="bm" aria-hidden="false"><button class="ao la ls lt ab q fk lu lv" aria-label="responses"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="lr"><path d="M18.006 16.803c1.533-1.456 2.234-3.325 2.234-5.321C20.24 7.357 16.709 4 12.191 4S4 7.357 4 11.482c0 4.126 3.674 7.482 8.191 7.482.817 0 1.622-.111 2.393-.327.231.2.48.391.744.559 1.06.693 2.203 1.044 3.399 1.044.224-.008.4-.112.486-.287a.49.49 0 0 0-.042-.518c-.495-.67-.845-1.364-1.04-2.057a4 4 0 0 1-.125-.598zm-3.122 1.055-.067-.223-.315.096a8 8 0 0 1-2.311.338c-4.023 0-7.292-2.955-7.292-6.587 0-3.633 3.269-6.588 7.292-6.588 4.014 0 7.112 2.958 7.112 6.593 0 1.794-.608 3.469-2.027 4.72l-.195.168v.255c0 .056 0 .151.016.295.025.231.081.478.154.733.154.558.398 1.117.722 1.659a5.3 5.3 0 0 1-2.165-.845c-.276-.176-.714-.383-.941-.59z"></path></svg><p class="bf b bg z du"><span class="pw-responses-count lq lr">1</span></p></button></div></div></div></div><div class="ab q"><div class="sv l ix"><div><div class="bm" aria-hidden="false"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerBookmarkButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fbookmark%2Fp%2F46cf06181893&operation=register&redirect=https%3A%2F%2Fmedium.com%2Foutfit7%2Fthe-my-talking-angela-2-hair-system-46cf06181893&source=---footer_actions--46cf06181893---------------------bookmark_footer-----------"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="none" viewBox="0 0 25 25" class="du lx" aria-label="Add to list bookmark button"><path fill="currentColor" d="M18 2.5a.5.5 0 0 1 1 0V5h2.5a.5.5 0 0 1 0 1H19v2.5a.5.5 0 1 1-1 0V6h-2.5a.5.5 0 0 1 0-1H18zM7 7a1 1 0 0 1 1-1h3.5a.5.5 0 0 0 0-1H8a2 2 0 0 0-2 2v14a.5.5 0 0 0 .805.396L12.5 17l5.695 4.396A.5.5 0 0 0 19 21v-8.5a.5.5 0 0 0-1 0v7.485l-5.195-4.012a.5.5 0 0 0-.61 0L7 19.985z"></path></svg></a></span></div></div></div><div class="sv l ix"><div class="bm" aria-hidden="false" aria-describedby="postFooterSocialMenu" aria-labelledby="postFooterSocialMenu"><div><div class="bm" aria-hidden="false"><button aria-controls="postFooterSocialMenu" aria-expanded="false" aria-label="Share Post" data-testid="footerSocialShareButton" class="af fk ah ai aj ak al mf an ao ap ex mg mh lv mi"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M15.218 4.931a.4.4 0 0 1-.118.132l.012.006a.45.45 0 0 1-.292.074.5.5 0 0 1-.3-.13l-2.02-2.02v7.07c0 .28-.23.5-.5.5s-.5-.22-.5-.5v-7.04l-2 2a.45.45 0 0 1-.57.04h-.02a.4.4 0 0 1-.16-.3.4.4 0 0 1 .1-.32l2.8-2.8a.5.5 0 0 1 .7 0l2.8 2.79a.42.42 0 0 1 .068.498m-.106.138.008.004v-.01zM16 7.063h1.5a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-11c-1.1 0-2-.9-2-2v-10a2 2 0 0 1 2-2H8a.5.5 0 0 1 .35.15.5.5 0 0 1 .15.35.5.5 0 0 1-.15.35.5.5 0 0 1-.35.15H6.4c-.5 0-.9.4-.9.9v10.2a.9.9 0 0 0 .9.9h11.2c.5 0 .9-.4.9-.9v-10.2c0-.5-.4-.9-.9-.9H16a.5.5 0 0 1 0-1" clip-rule="evenodd"></path></svg></button></div></div></div></div></div></div></div></div></div></footer><div class="sw sx sy sz ta l"><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="tb bh r tc"></div><div class="td l"><div class="ab te tf tg iz iy"><div class="th ti tj tk tl tm tn to tp tq ab cp"><div class="h k"><a href="https://medium.com/outfit7?source=post_page---post_publication_info--46cf06181893--------------------------------" rel="noopener follow"><div class="fj ab"><img alt="Outfit7" class="tr ib ic cx" src="https://miro.medium.com/v2/resize:fill:96:96/1*dCIQWfMya9g57UUL2ZzrJQ.png" width="48" height="48" loading="lazy"/><div class="tr l ic ib fs n fr ts"></div></div></a></div><div class="j i d"><a href="https://medium.com/outfit7?source=post_page---post_publication_info--46cf06181893--------------------------------" rel="noopener follow"><div class="fj ab"><img alt="Outfit7" class="tr tu tt cx" src="https://miro.medium.com/v2/resize:fill:128:128/1*dCIQWfMya9g57UUL2ZzrJQ.png" width="64" height="64" loading="lazy"/><div class="tr l tt tu fs n fr ts"></div></div></a></div><div class="j i d tv ix"><div class="ab"></div></div></div><div class="ab co tw"><div class="tx ty tz qn qm l"><a class="af ag ah aj ak al am an ao ap aq ar as at ab q" href="https://medium.com/outfit7?source=post_page---post_publication_info--46cf06181893--------------------------------" rel="noopener follow"><h2 class="pw-author-name bf ub uc ud ue uf ug uh ni ui uj nm uk ul nq um un bk"><span class="gn ua">Published in <!-- -->Outfit7</span></h2></a><div class="sb ab ia"><div class="l ix"><span class="pw-follower-count bf b bg z du"><a class="af ag ah ai aj ak al am an ao ap aq ar iq" rel="noopener follow" href="/outfit7/followers?source=post_page---post_publication_info--46cf06181893--------------------------------">53 Followers</a></span></div><div class="bf b bg z du ab jd"><span class="ir l" aria-hidden="true"><span class="bf b bg z du">·</span></span><a class="af ag ah ai aj ak al am an ao ap aq ar iq" rel="noopener follow" href="/outfit7/new-home-for-outfit7-tech-articles-b317a75e1447?source=post_page---post_publication_info--46cf06181893--------------------------------">Last published <span>Sep 26, 2024</span></a></div></div><div class="uo l"><p class="bf b bg z bk"><span class="gn">The inside scoop on development, engineering & tech innovation @ Outfit7.</span></p></div></div></div><div class="h k"><div class="ab"></div></div></div></div><div class="ab te tf tg iz iy"><div class="th ti tj tk tl tm tn to tp tq ab cp"><div class="h k"><a tabindex="0" rel="noopener follow" href="/@aleksander.gregorka?source=post_page---post_author_info--46cf06181893--------------------------------"><div class="l fj"><img alt="Aleksander Gregorka" class="l fd by ic ib cx" src="https://miro.medium.com/v2/resize:fill:96:96/1*cAYUfjr9zj796olrnlP1eg.png" width="48" height="48" loading="lazy"/><div class="fr by l ic ib fs n ay ts"></div></div></a></div><div class="j i d"><a tabindex="0" rel="noopener follow" href="/@aleksander.gregorka?source=post_page---post_author_info--46cf06181893--------------------------------"><div class="l fj"><img alt="Aleksander Gregorka" class="l fd by tt tu cx" src="https://miro.medium.com/v2/resize:fill:128:128/1*cAYUfjr9zj796olrnlP1eg.png" width="64" height="64" loading="lazy"/><div class="fr by l tt tu fs n ay ts"></div></div></a></div><div class="j i d tv ix"><div class="ab"><span><button class="bf b bg z up sd uq ur us ut uu ev ew uv uw ux fa fb fc fd bm fe ff">Follow</button></span></div></div></div><div class="ab co tw"><div class="tx ty tz qn qm l"><a class="af ag ah aj ak al am an ao ap aq ar as at ab q" rel="noopener follow" href="/@aleksander.gregorka?source=post_page---post_author_info--46cf06181893--------------------------------"><h2 class="pw-author-name bf ub uc ud ue uf ug uh ni ui uj nm uk ul nq um un bk"><span class="gn ua">Written by <!-- -->Aleksander Gregorka</span></h2></a><div class="sb ab ia"><div class="l ix"><span class="pw-follower-count bf b bg z du"><a class="af ag ah ai aj ak al am an ao ap aq ar iq" rel="noopener follow" href="/@aleksander.gregorka/followers?source=post_page---post_author_info--46cf06181893--------------------------------">7 Followers</a></span></div><div class="bf b bg z du ab jd"><span class="ir l" aria-hidden="true"><span class="bf b bg z du">·</span></span><a class="af ag ah ai aj ak al am an ao ap aq ar iq" rel="noopener follow" href="/@aleksander.gregorka/following?source=post_page---post_author_info--46cf06181893--------------------------------">1 Following</a></div></div><div class="uo l"><p class="bf b bg z bk"><span class="gn">Senior Software Engineer, Game Developer, Maker of Things.</span></p></div></div></div><div class="h k"><div class="ab"><span><button class="bf b bg z up sd uq ur us ut uu ev ew uv uw ux fa fb fc fd bm fe ff">Follow</button></span></div></div></div></div></div></div><div class="uy uz va vb vc l"><div class="tb bh r uy uz vd ve vf"></div><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="ab q cp"><h2 class="bf ub on op oq or ot ou ov ox oy oz pb pc pd pf pg bk">Responses (<!-- -->1<!-- -->)</h2><div class="ab vg"><div><div class="bm" aria-hidden="false"><a class="vh vi" href="https://policy.medium.com/medium-rules-30e5502c4eb4?source=post_page---post_responses--46cf06181893--------------------------------" rel="noopener follow" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25"><path fill-rule="evenodd" d="M11.987 5.036a.754.754 0 0 1 .914-.01c.972.721 1.767 1.218 2.6 1.543.828.322 1.719.485 2.887.505a.755.755 0 0 1 .741.757c-.018 3.623-.43 6.256-1.449 8.21-1.034 1.984-2.662 3.209-4.966 4.083a.75.75 0 0 1-.537-.003c-2.243-.874-3.858-2.095-4.897-4.074-1.024-1.951-1.457-4.583-1.476-8.216a.755.755 0 0 1 .741-.757c1.195-.02 2.1-.182 2.923-.503.827-.322 1.6-.815 2.519-1.535m.468.903c-.897.69-1.717 1.21-2.623 1.564-.898.35-1.856.527-3.026.565.037 3.45.469 5.817 1.36 7.515.884 1.684 2.25 2.762 4.284 3.571 2.092-.81 3.465-1.89 4.344-3.575.886-1.698 1.299-4.065 1.334-7.512-1.149-.039-2.091-.217-2.99-.567-.906-.353-1.745-.873-2.683-1.561m-.009 9.155a2.672 2.672 0 1 0 0-5.344 2.672 2.672 0 0 0 0 5.344m0 1a3.672 3.672 0 1 0 0-7.344 3.672 3.672 0 0 0 0 7.344m-1.813-3.777.525-.526.916.917 1.623-1.625.526.526-2.149 2.152z" clip-rule="evenodd"></path></svg></a></div></div></div></div><div class="vj l"><button class="bf b bg z bk sd vk vl vm lx lu uu ev ew ex vn vo vp fa vq vr vs vt vu fb fc fd bm fe ff">See all responses</button></div></div></div></div><div class="vv vw vx vy vz l bx"><div class="h k j"><div class="tb bh wa wb"></div><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="wc ab kv ja"><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://help.medium.com/hc/en-us?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Help</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://medium.statuspage.io/?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Status</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/about?autoplay=1&source=post_page-----46cf06181893--------------------------------"><p class="bf b dv z du">About</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/jobs-at-medium/work-at-medium-959d1a85284e?source=post_page-----46cf06181893--------------------------------"><p class="bf b dv z du">Careers</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="pressinquiries@medium.com?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Press</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://blog.medium.com/?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Blog</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://policy.medium.com/medium-privacy-policy-f03bf92035c9?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Privacy</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://policy.medium.com/medium-terms-of-service-9db0094a1e0f?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Terms</p></a></div><div class="wd we l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://speechify.com/medium?source=post_page-----46cf06181893--------------------------------" rel="noopener follow"><p class="bf b dv z du">Text to speech</p></a></div><div class="wd l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/business?source=post_page-----46cf06181893--------------------------------"><p class="bf b dv z du">Teams</p></a></div></div></div></div></div></div></div></div></div></div><script>window.__BUILD_ID__="main-20241126-160001-7c01a96524"</script><script>window.__GRAPHQL_URI__ = "https://medium.com/_/graphql"</script><script>window.__PRELOADED_STATE__ = {"algolia":{"queries":{}},"cache":{"experimentGroupSet":true,"reason":"","group":"enabled","tags":["group-edgeCachePosts","post-46cf06181893","user-565c34edb417","collection-6ec626d5ad62"],"serverVariantState":"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","middlewareEnabled":true,"cacheStatus":"DYNAMIC","shouldUseCache":true,"vary":[],"lohpSummerUpsellEnabled":false,"publicationHierarchyEnabledWeb":false,"postBottomResponsesEnabled":false},"client":{"hydrated":false,"isUs":false,"isNativeMedium":false,"isSafariMobile":false,"isSafari":false,"isFirefox":false,"routingEntity":{"type":"DEFAULT","explicit":false},"viewerIsBot":false},"debug":{"requestId":"372619fb-1a24-47cf-b65f-604317e8cf71","hybridDevServices":[],"originalSpanCarrier":{"traceparent":"00-b9b692b9ec0a7c6619f488a7a7a02c59-4c64840bec5c9826-01"}},"multiVote":{"clapsPerPost":{}},"navigation":{"branch":{"show":null,"hasRendered":null,"blockedByCTA":false},"hideGoogleOneTap":false,"hasRenderedAlternateUserBanner":null,"currentLocation":"https:\u002F\u002Fmedium.com\u002Foutfit7\u002Fthe-my-talking-angela-2-hair-system-46cf06181893","host":"medium.com","hostname":"medium.com","referrer":"","hasSetReferrer":false,"susiModal":{"step":null,"operation":"register"},"postRead":false,"partnerProgram":{"selectedCountryCode":null},"queryString":"","currentHash":""},"config":{"nodeEnv":"production","version":"main-20241126-160001-7c01a96524","target":"production","productName":"Medium","publicUrl":"https:\u002F\u002Fcdn-client.medium.com\u002Flite","authDomain":"medium.com","authGoogleClientId":"216296035834-k1k6qe060s2tp2a2jam4ljdcms00sttg.apps.googleusercontent.com","favicon":"production","glyphUrl":"https:\u002F\u002Fglyph.medium.com","branchKey":"key_live_ofxXr2qTrrU9NqURK8ZwEhknBxiI6KBm","algolia":{"appId":"MQ57UUUQZ2","apiKeySearch":"394474ced050e3911ae2249ecc774921","indexPrefix":"medium_","host":"-dsn.algolia.net"},"recaptchaKey":"6Lfc37IUAAAAAKGGtC6rLS13R1Hrw_BqADfS1LRk","recaptcha3Key":"6Lf8R9wUAAAAABMI_85Wb8melS7Zj6ziuf99Yot5","recaptchaEnterpriseKeyId":"6Le-uGgpAAAAAPprRaokM8AKthQ9KNGdoxaGUvVp","datadog":{"applicationId":"6702d87d-a7e0-42fe-bbcb-95b469547ea0","clientToken":"pub853ea8d17ad6821d9f8f11861d23dfed","rumToken":"pubf9cc52896502b9413b68ba36fc0c7162","context":{"deployment":{"target":"production","tag":"main-20241126-160001-7c01a96524","commit":"7c01a965241ad37c2365004cf4b2d6822ee64323"}},"datacenter":"us"},"googleAnalyticsCode":"G-7JY7T788PK","googlePay":{"apiVersion":"2","apiVersionMinor":"0","merchantId":"BCR2DN6TV7EMTGBM","merchantName":"Medium","instanceMerchantId":"13685562959212738550"},"applePay":{"version":3},"signInWallCustomDomainCollectionIds":["3a8144eabfe3","336d898217ee","61061eb0c96b","138adf9c44c","819cc2aaeee0"],"mediumMastodonDomainName":"me.dm","mediumOwnedAndOperatedCollectionIds":["8a9336e5bb4","b7e45b22fec3","193b68bd4fba","8d6b8a439e32","54c98c43354d","3f6ecf56618","d944778ce714","92d2092dc598","ae2a65f35510","1285ba81cada","544c7006046e","fc8964313712","40187e704f1c","88d9857e584e","7b6769f2748b","bcc38c8f6edf","cef6983b292","cb8577c9149e","444d13b52878","713d7dbc99b0","ef8e90590e66","191186aaafa0","55760f21cdc5","9dc80918cc93","bdc4052bbdba","8ccfed20cbb2"],"tierOneDomains":["medium.com","thebolditalic.com","arcdigital.media","towardsdatascience.com","uxdesign.cc","codeburst.io","psiloveyou.xyz","writingcooperative.com","entrepreneurshandbook.co","prototypr.io","betterhumans.coach.me","theascent.pub"],"topicsToFollow":["d61cf867d93f","8a146bc21b28","1eca0103fff3","4d562ee63426","aef1078a3ef5","e15e46793f8d","6158eb913466","55f1c20aba7a","3d18b94f6858","4861fee224fd","63c6f1f93ee","1d98b3a9a871","decb52b64abf","ae5d4995e225","830cded25262"],"topicToTagMappings":{"accessibility":"accessibility","addiction":"addiction","android-development":"android-development","art":"art","artificial-intelligence":"artificial-intelligence","astrology":"astrology","basic-income":"basic-income","beauty":"beauty","biotech":"biotech","blockchain":"blockchain","books":"books","business":"business","cannabis":"cannabis","cities":"cities","climate-change":"climate-change","comics":"comics","coronavirus":"coronavirus","creativity":"creativity","cryptocurrency":"cryptocurrency","culture":"culture","cybersecurity":"cybersecurity","data-science":"data-science","design":"design","digital-life":"digital-life","disability":"disability","economy":"economy","education":"education","equality":"equality","family":"family","feminism":"feminism","fiction":"fiction","film":"film","fitness":"fitness","food":"food","freelancing":"freelancing","future":"future","gadgets":"gadgets","gaming":"gaming","gun-control":"gun-control","health":"health","history":"history","humor":"humor","immigration":"immigration","ios-development":"ios-development","javascript":"javascript","justice":"justice","language":"language","leadership":"leadership","lgbtqia":"lgbtqia","lifestyle":"lifestyle","machine-learning":"machine-learning","makers":"makers","marketing":"marketing","math":"math","media":"media","mental-health":"mental-health","mindfulness":"mindfulness","money":"money","music":"music","neuroscience":"neuroscience","nonfiction":"nonfiction","outdoors":"outdoors","parenting":"parenting","pets":"pets","philosophy":"philosophy","photography":"photography","podcasts":"podcast","poetry":"poetry","politics":"politics","privacy":"privacy","product-management":"product-management","productivity":"productivity","programming":"programming","psychedelics":"psychedelics","psychology":"psychology","race":"race","relationships":"relationships","religion":"religion","remote-work":"remote-work","san-francisco":"san-francisco","science":"science","self":"self","self-driving-cars":"self-driving-cars","sexuality":"sexuality","social-media":"social-media","society":"society","software-engineering":"software-engineering","space":"space","spirituality":"spirituality","sports":"sports","startups":"startup","style":"style","technology":"technology","transportation":"transportation","travel":"travel","true-crime":"true-crime","tv":"tv","ux":"ux","venture-capital":"venture-capital","visual-design":"visual-design","work":"work","world":"world","writing":"writing"},"defaultImages":{"avatar":{"imageId":"1*dmbNkD5D-u45r44go_cf0g.png","height":150,"width":150},"orgLogo":{"imageId":"7*V1_7XP4snlmqrc_0Njontw.png","height":110,"width":500},"postLogo":{"imageId":"bd978bb536350a710e8efb012513429cabdc4c28700604261aeda246d0f980b7","height":810,"width":1440},"postPreviewImage":{"imageId":"1*hn4v1tCaJy7cWMyb0bpNpQ.png","height":386,"width":579}},"collectionStructuredData":{"8d6b8a439e32":{"name":"Elemental","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F980\u002F1*9ygdqoKprhwuTVKUM0DLPA@2x.png","width":980,"height":159}}},"3f6ecf56618":{"name":"Forge","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F596\u002F1*uULpIlImcO5TDuBZ6lm7Lg@2x.png","width":596,"height":183}}},"ae2a65f35510":{"name":"GEN","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F264\u002F1*RdVZMdvfV3YiZTw6mX7yWA.png","width":264,"height":140}}},"88d9857e584e":{"name":"LEVEL","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*JqYMhNX6KNNb2UlqGqO2WQ.png","width":540,"height":108}}},"7b6769f2748b":{"name":"Marker","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F383\u002F1*haCUs0wF6TgOOvfoY-jEoQ@2x.png","width":383,"height":92}}},"444d13b52878":{"name":"OneZero","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*cw32fIqCbRWzwJaoQw6BUg.png","width":540,"height":123}}},"8ccfed20cbb2":{"name":"Zora","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*tZUQqRcCCZDXjjiZ4bDvgQ.png","width":540,"height":106}}}},"embeddedPostIds":{"coronavirus":"cd3010f9d81f"},"sharedCdcMessaging":{"COVID_APPLICABLE_TAG_SLUGS":[],"COVID_APPLICABLE_TOPIC_NAMES":[],"COVID_APPLICABLE_TOPIC_NAMES_FOR_TOPIC_PAGE":[],"COVID_MESSAGES":{"tierA":{"text":"For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":66,"end":73,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"tierB":{"text":"Anyone can publish on Medium per our Policies, but we don’t fact-check every story. For more info about the coronavirus, see cdc.gov.","markups":[{"start":37,"end":45,"href":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Fcategories\u002F201931128-Policies-Safety"},{"start":125,"end":132,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"paywall":{"text":"This article has been made free for everyone, thanks to Medium Members. For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":56,"end":70,"href":"https:\u002F\u002Fmedium.com\u002Fmembership"},{"start":138,"end":145,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"unbound":{"text":"This article is free for everyone, thanks to Medium Members. For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":45,"end":59,"href":"https:\u002F\u002Fmedium.com\u002Fmembership"},{"start":127,"end":134,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]}},"COVID_BANNER_POST_ID_OVERRIDE_WHITELIST":["3b31a67bff4a"]},"sharedVoteMessaging":{"TAGS":["politics","election-2020","government","us-politics","election","2020-presidential-race","trump","donald-trump","democrats","republicans","congress","republican-party","democratic-party","biden","joe-biden","maga"],"TOPICS":["politics","election"],"MESSAGE":{"text":"Find out more about the U.S. election results here.","markups":[{"start":46,"end":50,"href":"https:\u002F\u002Fcookpolitical.com\u002F2020-national-popular-vote-tracker"}]},"EXCLUDE_POSTS":["397ef29e3ca5"]},"embedPostRules":[],"recircOptions":{"v1":{"limit":3},"v2":{"limit":8}},"braintreeClientKey":"production_zjkj96jm_m56f8fqpf7ngnrd4","braintree":{"enabled":true,"merchantId":"m56f8fqpf7ngnrd4","merchantAccountId":{"usd":"AMediumCorporation_instant","eur":"amediumcorporation_EUR","cad":"amediumcorporation_CAD"},"publicKey":"ds2nn34bg2z7j5gd","braintreeEnvironment":"production","dashboardUrl":"https:\u002F\u002Fwww.braintreegateway.com\u002Fmerchants","gracePeriodDurationInDays":14,"mediumMembershipPlanId":{"monthly":"ce105f8c57a3","monthlyV2":"e8a5e126-792b-4ee6-8fba-d574c1b02fc5","monthlyWithTrial":"d5ee3dbe3db8","monthlyPremium":"fa741a9b47a2","yearly":"a40ad4a43185","yearlyV2":"3815d7d6-b8ca-4224-9b8c-182f9047866e","yearlyStaff":"d74fb811198a","yearlyWithTrial":"b3bc7350e5c7","yearlyPremium":"e21bd2c12166","monthlyOneYearFree":"e6c0637a-2bad-4171-ab4f-3c268633d83c","monthly25PercentOffFirstYear":"235ecc62-0cdb-49ae-9378-726cd21c504b","monthly20PercentOffFirstYear":"ba518864-9c13-4a99-91ca-411bf0cac756","monthly15PercentOffFirstYear":"594c029b-9f89-43d5-88f8-8173af4e070e","monthly10PercentOffFirstYear":"c6c7bc9a-40f2-4b51-8126-e28511d5bdb0","monthlyForStudents":"629ebe51-da7d-41fd-8293-34cd2f2030a8","yearlyOneYearFree":"78ba7be9-0d9f-4ece-aa3e-b54b826f2bf1","yearly25PercentOffFirstYear":"2dbb010d-bb8f-4eeb-ad5c-a08509f42d34","yearly20PercentOffFirstYear":"47565488-435b-47f8-bf93-40d5fbe0ebc8","yearly15PercentOffFirstYear":"8259809b-0881-47d9-acf7-6c001c7f720f","yearly10PercentOffFirstYear":"9dd694fb-96e1-472c-8d9e-3c868d5c1506","yearlyForStudents":"e29345ef-ab1c-4234-95c5-70e50fe6bc23","monthlyCad":"p52orjkaceei","yearlyCad":"h4q9g2up9ktt"},"braintreeDiscountId":{"oneMonthFree":"MONTHS_FREE_01","threeMonthsFree":"MONTHS_FREE_03","sixMonthsFree":"MONTHS_FREE_06","fiftyPercentOffOneYear":"FIFTY_PERCENT_OFF_ONE_YEAR"},"3DSecureVersion":"2","defaultCurrency":"usd","providerPlanIdCurrency":{"4ycw":"usd","rz3b":"usd","3kqm":"usd","jzw6":"usd","c2q2":"usd","nnsw":"usd","q8qw":"usd","d9y6":"usd","fx7w":"cad","nwf2":"cad"}},"paypalClientId":"AXj1G4fotC2GE8KzWX9mSxCH1wmPE3nJglf4Z2ig_amnhvlMVX87otaq58niAg9iuLktVNF_1WCMnN7v","paypal":{"host":"https:\u002F\u002Fapi.paypal.com:443","clientMode":"production","serverMode":"live","webhookId":"4G466076A0294510S","monthlyPlan":{"planId":"P-9WR0658853113943TMU5FDQA","name":"Medium Membership (Monthly) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"yearlyPlan":{"planId":"P-7N8963881P8875835MU5JOPQ","name":"Medium Membership (Annual) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"oneYearGift":{"name":"Medium Membership (1 Year, Digital Gift Code)","description":"Unlimited access to the best and brightest stories on Medium. Gift codes can be redeemed at medium.com\u002Fredeem.","price":"50.00","currency":"USD","sku":"membership-gift-1-yr"},"oldMonthlyPlan":{"planId":"P-96U02458LM656772MJZUVH2Y","name":"Medium Membership (Monthly)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"oldYearlyPlan":{"planId":"P-59P80963JF186412JJZU3SMI","name":"Medium Membership (Annual)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"monthlyPlanWithTrial":{"planId":"P-66C21969LR178604GJPVKUKY","name":"Medium Membership (Monthly) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"yearlyPlanWithTrial":{"planId":"P-6XW32684EX226940VKCT2MFA","name":"Medium Membership (Annual) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"oldMonthlyPlanNoSetupFee":{"planId":"P-4N046520HR188054PCJC7LJI","name":"Medium Membership (Monthly)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"oldYearlyPlanNoSetupFee":{"planId":"P-7A4913502Y5181304CJEJMXQ","name":"Medium Membership (Annual)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"sdkUrl":"https:\u002F\u002Fwww.paypal.com\u002Fsdk\u002Fjs"},"stripePublishableKey":"pk_live_7FReX44VnNIInZwrIIx6ghjl","log":{"json":true,"level":"info"},"imageUploadMaxSizeMb":25,"staffPicks":{"title":"Staff Picks","catalogId":"c7bc6e1ee00f"}},"session":{"xsrf":""}}</script><script>window.__APOLLO_STATE__ = {"ROOT_QUERY":{"__typename":"Query","viewer":null,"collectionByDomainOrSlug({\"domainOrSlug\":\"outfit7\"})":{"__ref":"Collection:6ec626d5ad62"},"postResult({\"id\":\"46cf06181893\"})":{"__ref":"Post:46cf06181893"}},"ImageMetadata:":{"__typename":"ImageMetadata","id":""},"Collection:6ec626d5ad62":{"__typename":"Collection","id":"6ec626d5ad62","favicon":{"__ref":"ImageMetadata:"},"customStyleSheet":null,"colorPalette":{"__typename":"ColorPalette","highlightSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FFFFFFFF","colorPoints":[{"__typename":"ColorPoint","color":"#FFF5F2F1","point":0},{"__typename":"ColorPoint","color":"#FFF3F0EF","point":0.1},{"__typename":"ColorPoint","color":"#FFF1EEEE","point":0.2},{"__typename":"ColorPoint","color":"#FFEFECEC","point":0.3},{"__typename":"ColorPoint","color":"#FFEDEAEA","point":0.4},{"__typename":"ColorPoint","color":"#FFEBE8E8","point":0.5},{"__typename":"ColorPoint","color":"#FFE9E7E6","point":0.6},{"__typename":"ColorPoint","color":"#FFE7E5E4","point":0.7},{"__typename":"ColorPoint","color":"#FFE5E3E2","point":0.8},{"__typename":"ColorPoint","color":"#FFE3E1E0","point":0.9},{"__typename":"ColorPoint","color":"#FFE1DFDE","point":1}]},"defaultBackgroundSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FFFFFFFF","colorPoints":[{"__typename":"ColorPoint","color":"#FF858484","point":0},{"__typename":"ColorPoint","color":"#FF7C7B7B","point":0.1},{"__typename":"ColorPoint","color":"#FF737171","point":0.2},{"__typename":"ColorPoint","color":"#FF696868","point":0.3},{"__typename":"ColorPoint","color":"#FF5F5E5E","point":0.4},{"__typename":"ColorPoint","color":"#FF555454","point":0.5},{"__typename":"ColorPoint","color":"#FF4A4949","point":0.6},{"__typename":"ColorPoint","color":"#FF3F3E3E","point":0.7},{"__typename":"ColorPoint","color":"#FF343333","point":0.8},{"__typename":"ColorPoint","color":"#FF272727","point":0.9},{"__typename":"ColorPoint","color":"#FF1A1A1A","point":1}]},"tintBackgroundSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FF111111","colorPoints":[{"__typename":"ColorPoint","color":"#FF111111","point":0},{"__typename":"ColorPoint","color":"#FF313131","point":0.1},{"__typename":"ColorPoint","color":"#FF4D4C4C","point":0.2},{"__typename":"ColorPoint","color":"#FF666565","point":0.3},{"__typename":"ColorPoint","color":"#FF7D7C7C","point":0.4},{"__typename":"ColorPoint","color":"#FF939292","point":0.5},{"__typename":"ColorPoint","color":"#FFA9A7A7","point":0.6},{"__typename":"ColorPoint","color":"#FFBDBBBB","point":0.7},{"__typename":"ColorPoint","color":"#FFD2CFCF","point":0.8},{"__typename":"ColorPoint","color":"#FFE5E2E2","point":0.9},{"__typename":"ColorPoint","color":"#FFF8F5F5","point":1}]}},"domain":null,"slug":"outfit7","googleAnalyticsId":null,"editors":[{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:ebaddf6e1f2a"}}],"name":"Outfit7","avatar":{"__ref":"ImageMetadata:1*dCIQWfMya9g57UUL2ZzrJQ.png"},"description":"The inside scoop on development, engineering & tech innovation @ Outfit7.","subscriberCount":53,"latestPostsConnection({\"paging\":{\"limit\":1}})":{"__typename":"PostConnection","posts":[{"__ref":"Post:b317a75e1447"}]},"viewerEdge":{"__ref":"CollectionViewerEdge:collectionId:6ec626d5ad62-viewerId:lo_39beedb2a269"},"twitterUsername":null,"facebookPageId":null,"logo":{"__ref":"ImageMetadata:1*nTxl_7KgWQYo8PfVROUK_A.png"}},"User:ebaddf6e1f2a":{"__typename":"User","id":"ebaddf6e1f2a"},"ImageMetadata:1*dCIQWfMya9g57UUL2ZzrJQ.png":{"__typename":"ImageMetadata","id":"1*dCIQWfMya9g57UUL2ZzrJQ.png"},"User:3215f0e451af":{"__typename":"User","id":"3215f0e451af","customDomainState":null,"hasSubdomain":false,"username":"jure.gorinsek_80693"},"Post:b317a75e1447":{"__typename":"Post","id":"b317a75e1447","firstPublishedAt":1727352997939,"creator":{"__ref":"User:3215f0e451af"},"collection":{"__ref":"Collection:6ec626d5ad62"},"isSeries":false,"mediumUrl":"https:\u002F\u002Fmedium.com\u002Foutfit7\u002Fnew-home-for-outfit7-tech-articles-b317a75e1447","sequence":null,"uniqueSlug":"new-home-for-outfit7-tech-articles-b317a75e1447"},"LinkedAccounts:565c34edb417":{"__typename":"LinkedAccounts","mastodon":null,"id":"565c34edb417"},"UserViewerEdge:userId:565c34edb417-viewerId:lo_39beedb2a269":{"__typename":"UserViewerEdge","id":"userId:565c34edb417-viewerId:lo_39beedb2a269","isFollowing":false,"isUser":false,"isMuting":false},"User:565c34edb417":{"__typename":"User","id":"565c34edb417","linkedAccounts":{"__ref":"LinkedAccounts:565c34edb417"},"isSuspended":false,"imageId":"1*cAYUfjr9zj796olrnlP1eg.png","mediumMemberAt":0,"verifications":{"__typename":"VerifiedInfo","isBookAuthor":false},"name":"Aleksander Gregorka","socialStats":{"__typename":"SocialStats","followerCount":7,"followingCount":1,"collectionFollowingCount":0},"username":"aleksander.gregorka","customDomainState":null,"hasSubdomain":false,"bio":"Senior Software Engineer, Game Developer, Maker of Things.","isPartnerProgramEnrolled":false,"viewerEdge":{"__ref":"UserViewerEdge:userId:565c34edb417-viewerId:lo_39beedb2a269"},"viewerIsUser":false,"newsletterV3":null,"postSubscribeMembershipUpsellShownAt":0,"membership":null,"allowNotes":true,"twitterScreenName":""},"Topic:decb52b64abf":{"__typename":"Topic","slug":"programming","id":"decb52b64abf","name":"Programming"},"Paragraph:fe52d6145399_0":{"__typename":"Paragraph","id":"fe52d6145399_0","name":"5dd9","type":"H3","href":null,"layout":null,"metadata":null,"text":"The My Talking Angela 2 Hair System","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_1":{"__typename":"Paragraph","id":"fe52d6145399_1","name":"4d01","type":"P","href":null,"layout":null,"metadata":null,"text":"TL;DR: The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together. With all the hairy details.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":6,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"EM","start":0,"end":168,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*QeoWDJ4qQhrCS_Ei":{"__typename":"ImageMetadata","id":"0*QeoWDJ4qQhrCS_Ei","originalHeight":634,"originalWidth":1003,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_2":{"__typename":"Paragraph","id":"fe52d6145399_2","name":"38c1","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*QeoWDJ4qQhrCS_Ei"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_3":{"__typename":"Paragraph","id":"fe52d6145399_3","name":"25a9","type":"P","href":null,"layout":null,"metadata":null,"text":"I’m Aleksander Gregorka and I’m a Senior Software Engineer at Outfit7. I’ve been with the company since 2014, and during that time I’ve implemented tons of things that moved across millions of screens. And what better way to put my skills to the test than by making bouncy hair.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_4":{"__typename":"Paragraph","id":"fe52d6145399_4","name":"51dc","type":"P","href":null,"layout":null,"metadata":null,"text":"Today we’ll take a look at the hair system I implemented for our hit mobile game, My Talking Angela 2. At the time of publishing this article, the game had achieved over 300 million downloads in its first year.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_5":{"__typename":"Paragraph","id":"fe52d6145399_5","name":"1e8b","type":"P","href":null,"layout":null,"metadata":null,"text":"The game was made using our own proprietary game engine called Starlite. We’ll get into the details of Starlite and its editor in one of our upcoming blog posts, but for now, the only thing you need to know is that we’re using C++ for runtime development, so any code samples in this article will also be in C++.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_6":{"__typename":"Paragraph","id":"fe52d6145399_6","name":"90ce","type":"H3","href":null,"layout":null,"metadata":null,"text":"Goals","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_7":{"__typename":"Paragraph","id":"fe52d6145399_7","name":"f114","type":"P","href":null,"layout":null,"metadata":null,"text":"Having a proprietary game engine has some downsides, but also a lot of benefits. An example of this would be that you can’t just take a hair system package from the app store and call it a day. The benefit of implementing it yourself, though, is that you can integrate it into the rest of the app using the same architecture used elsewhere in the game. If something goes wrong, you can fix it yourself, which is extremely important in a project as big as My Talking Angela 2.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_8":{"__typename":"Paragraph","id":"fe52d6145399_8","name":"80b3","type":"P","href":null,"layout":null,"metadata":null,"text":"The goal of the system was to support stylized hair, meaning that the simulation wouldn’t have to be completely physically realistic.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_9":{"__typename":"Paragraph","id":"fe52d6145399_9","name":"8817","type":"P","href":null,"layout":null,"metadata":null,"text":"One of the important things was also that we should avoid hair mesh clipping with other items as much as possible, but this is really hard to achieve in real-time dynamic games where characters can interact with other items, such as toys, hats, and furniture. Even their own arms sometimes move dangerously close to the hair.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_10":{"__typename":"Paragraph","id":"fe52d6145399_10","name":"1d94","type":"P","href":null,"layout":null,"metadata":null,"text":"It was also very important for the system to be easily used by artists without much back and forth between 3D and Dev teams. We knew we’d be importing a large number of hair rigs, so we wanted to make it as simple as possible for them. Currently, we have 65 hair configurations in the game, including those with the same style but different lengths.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_11":{"__typename":"Paragraph","id":"fe52d6145399_11","name":"499c","type":"H3","href":null,"layout":null,"metadata":null,"text":"How to Approach the Task","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_12":{"__typename":"Paragraph","id":"fe52d6145399_12","name":"c4cc","type":"P","href":null,"layout":null,"metadata":null,"text":"Facing a challenge like this was very interesting, because there were a lot of unknowns at the start of the project. We only had concept art at the time, so the exact style of the hair wasn’t yet known.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_13":{"__typename":"Paragraph","id":"fe52d6145399_13","name":"9d67","type":"P","href":null,"layout":null,"metadata":null,"text":"When we start projects at Outfit7, we start with the pre-production phase. Typically, we mainly want to solve the difficult technical challenges as soon as possible in order to make the actual production smooth. However, at such an early stage, the art isn’t usually ready yet, so we have to make some assumptions. So for the hair system for My Talking Angela 2, I took a look at the art styles of our previous games, and used some assets from there as a starting point.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_14":{"__typename":"Paragraph","id":"fe52d6145399_14","name":"101a","type":"P","href":null,"layout":null,"metadata":null,"text":"Prototyping systems like this early in the production phase is absolutely necessary to avoid project delays in the future — at this stage, we have time to scrap everything and try something else if we need to. It’s also important to plan for things to go wrong. There should be some time dedicated for asset integration.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_15":{"__typename":"Paragraph","id":"fe52d6145399_15","name":"ce2a","type":"P","href":null,"layout":null,"metadata":null,"text":"I tried to predict as many use cases as possible without overengineering for the end of the world — I knew that some things could be fixed later if problems arose during production.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_16":{"__typename":"Paragraph","id":"fe52d6145399_16","name":"dc30","type":"H3","href":null,"layout":null,"metadata":null,"text":"Possible Approaches","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_17":{"__typename":"Paragraph","id":"fe52d6145399_17","name":"948a","type":"H3","href":null,"layout":null,"metadata":null,"text":"Hair Cards","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_18":{"__typename":"Paragraph","id":"fe52d6145399_18","name":"5aa2","type":"P","href":null,"layout":null,"metadata":null,"text":"Hair cards are simple polygonal meshes used to shape the hair strands. They are UV wrapped in a way that you can texture them to display hair strands with a simple shader. They can be animated by rigging them, or even applying a vertex shader so they sway a bit when moving. But for our needs, this approach would be a bit too complicated, and we wanted something simpler in terms of geometry.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":80,"end":82,"href":"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FUV_mapping","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":196,"end":203,"href":"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSkeletal_animation#Technique","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*DUVCAooC130ra4cS":{"__typename":"ImageMetadata","id":"0*DUVCAooC130ra4cS","originalHeight":838,"originalWidth":1600,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_19":{"__typename":"Paragraph","id":"fe52d6145399_19","name":"b5eb","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*DUVCAooC130ra4cS"},"text":"A developer visualization of how a hair card setup for a sloppy mohawk could look like.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_20":{"__typename":"Paragraph","id":"fe52d6145399_20","name":"8f5e","type":"H3","href":null,"layout":null,"metadata":null,"text":"Animated Hair","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_21":{"__typename":"Paragraph","id":"fe52d6145399_21","name":"907f","type":"P","href":null,"layout":null,"metadata":null,"text":"With this approach we could have hair items rigged and animated traditionally. This would result in a larger application size because we were planning to have up to 30 bones per hair style, with multiple hair types. This would add a lot of animations to the game, just for the hair. Basically each of the character animations would require a matching hair animation. We would need to simplify it with reusing hair rigs, or blending idle poses.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_22":{"__typename":"Paragraph","id":"fe52d6145399_22","name":"c498","type":"P","href":null,"layout":null,"metadata":null,"text":"But why is application size an issue? Well, mainly because we’re working with mobile games, and there are limits to how big of a game you can download over a cellular connection. For Android, this is currently 150MB, and it’s 200MB on iOS. From our experience, the increase in installs from being able to download the game via a cellular connection makes it worth it to stick to these limits.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_23":{"__typename":"Paragraph","id":"fe52d6145399_23","name":"7593","type":"P","href":null,"layout":null,"metadata":null,"text":"Fitting such a big game into 150MB? Well, that’s a topic for another blog post, but it involves a lot of clever tricks.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_24":{"__typename":"Paragraph","id":"fe52d6145399_24","name":"1a10","type":"H3","href":null,"layout":null,"metadata":null,"text":"Procedural Animation","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_25":{"__typename":"Paragraph","id":"fe52d6145399_25","name":"c7df","type":"P","href":null,"layout":null,"metadata":null,"text":"Ah yes, now we’re talking. When in doubt, you should always use procedural animation.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_26":{"__typename":"Paragraph","id":"fe52d6145399_26","name":"0e22","type":"P","href":null,"layout":null,"metadata":null,"text":"We’d still be able to use a traditional rigging setup with each hair style having up to 20 strands, but they would be animated dynamically based on world inputs. This would greatly simplify our workflows and make our animation team’s life easier. The downside to this approach is that you have less control over the final looks — unexpected things can happen due to the hair being simulated in real time.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_27":{"__typename":"Paragraph","id":"fe52d6145399_27","name":"6241","type":"P","href":null,"layout":null,"metadata":null,"text":"In the end I chose this approach because I believed it would best fit our needs.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*rnfHykY-fMXUKqRu":{"__typename":"ImageMetadata","id":"0*rnfHykY-fMXUKqRu","originalHeight":554,"originalWidth":554,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_28":{"__typename":"Paragraph","id":"fe52d6145399_28","name":"7867","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*rnfHykY-fMXUKqRu"},"text":"Individual hair strands.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_29":{"__typename":"Paragraph","id":"fe52d6145399_29","name":"ec31","type":"H3","href":null,"layout":null,"metadata":null,"text":"Architecture","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_30":{"__typename":"Paragraph","id":"fe52d6145399_30","name":"7013","type":"P","href":null,"layout":null,"metadata":null,"text":"I wanted the system to be designed in such a way that items should be independent of the other character systems. Basically, you just equip an item (hair, in this case), and the hair system takes care of the simulation.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_31":{"__typename":"Paragraph","id":"fe52d6145399_31","name":"7583","type":"P","href":null,"layout":null,"metadata":null,"text":"The system I designed consists of multiple parts. I tried to create it in such a way that it’s not specific to hair, but could also be used for other purposes. If you had some joints and you wanted them to move, for example, you could use this system with little effort. We’re calling it “Bone Physics”. Many jokes came to mind, but for now let’s focus on the topic at hand (I would prefer keeping my job if I can).","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_32":{"__typename":"Paragraph","id":"fe52d6145399_32","name":"9ea0","type":"H3","href":null,"layout":null,"metadata":null,"text":"Physics Joint","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_33":{"__typename":"Paragraph","id":"fe52d6145399_33","name":"cf38","type":"P","href":null,"layout":null,"metadata":null,"text":"This is the smallest unit in the system. It’s a one-on-one wrapper for your world transform. It keeps references to the previous and current simulated positions, so we can make some calculations based on the differences between the two.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_34":{"__typename":"Paragraph","id":"fe52d6145399_34","name":"c669","type":"H3","href":null,"layout":null,"metadata":null,"text":"Physics Chain","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_35":{"__typename":"Paragraph","id":"fe52d6145399_35","name":"2fdb","type":"P","href":null,"layout":null,"metadata":null,"text":"This is a collection of physics joints. In the example of hair, one hair strand is represented by one chain. Each chain can have its own physics settings, so hair strands (chains) in the front can behave differently than strands in the back.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":64,"end":107,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_36":{"__typename":"Paragraph","id":"fe52d6145399_36","name":"a7a2","type":"H3","href":null,"layout":null,"metadata":null,"text":"Simulator Data","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_37":{"__typename":"Paragraph","id":"fe52d6145399_37","name":"b761","type":"P","href":null,"layout":null,"metadata":null,"text":"In every frame of the simulation, we gather all the chain data, join it in SimulatorData, and feed it to the simulator.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_38":{"__typename":"Paragraph","id":"fe52d6145399_38","name":"9fd8","type":"H3","href":null,"layout":null,"metadata":null,"text":"Physics Simulator","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_39":{"__typename":"Paragraph","id":"fe52d6145399_39","name":"80b8","type":"P","href":null,"layout":null,"metadata":null,"text":"I will describe what the simulator does in the next section, but let’s call it a black box, one which takes in simulator data, processes it, and moves the physics joints to their new simulation positions.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_40":{"__typename":"Paragraph","id":"fe52d6145399_40","name":"4a19","type":"P","href":null,"layout":null,"metadata":null,"text":"After the simulator finishes its job, we take the new joint positions and apply them to the actual 3D transforms. This completes our frame, and the same process is repeated for the next frame.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*QFNJRSBUy2Ks7JIs":{"__typename":"ImageMetadata","id":"0*QFNJRSBUy2Ks7JIs","originalHeight":563,"originalWidth":973,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_41":{"__typename":"Paragraph","id":"fe52d6145399_41","name":"4e1d","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*QFNJRSBUy2Ks7JIs"},"text":"System architecture.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_42":{"__typename":"Paragraph","id":"fe52d6145399_42","name":"3e9c","type":"H3","href":null,"layout":null,"metadata":null,"text":"Simulation","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_43":{"__typename":"Paragraph","id":"fe52d6145399_43","name":"d827","type":"P","href":null,"layout":null,"metadata":null,"text":"For the simulation itself, the most important thing is that we’re using a fixed time step. This means that our simulation output won’t be affected by the frame rate of the device.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_44":{"__typename":"Paragraph","id":"fe52d6145399_44","name":"9076","type":"P","href":null,"layout":null,"metadata":null,"text":"A simplified example of this can be seen below. A fixed time step means that if we want to do something in 160 milliseconds and one step takes 16 milliseconds, we’re getting 10 steps, no matter the FPS of the device. If we have a variable time step, on the other hand, we’re tied to the rendering speed of the device. Frames can take from 16.66 milliseconds (when targeting 60 FPS — 1s\u002F60) to X milliseconds, where X depends on how badly our game is performing.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_45":{"__typename":"Paragraph","id":"fe52d6145399_45","name":"f3b3","type":"P","href":null,"layout":null,"metadata":null,"text":"In the example below, we want to move the ball from position 0 to position 20. Each step, we increase the position by 2 and, with a fixed time step, we get to position 20 after 10 steps. When the time step is variable (16–32 milliseconds between steps in the example), we only get to execute 7 steps in 160 milliseconds. This only brings us to position 14, which is not what we wanted.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_46":{"__typename":"Paragraph","id":"fe52d6145399_46","name":"6f85","type":"P","href":null,"layout":null,"metadata":null,"text":"The end result for our physical simulation would be incorrect, and the behavior would appear different on slower devices.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*_m7AjZjK_AgqvdJs":{"__typename":"ImageMetadata","id":"0*_m7AjZjK_AgqvdJs","originalHeight":1161,"originalWidth":1600,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_47":{"__typename":"Paragraph","id":"fe52d6145399_47","name":"02d1","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*_m7AjZjK_AgqvdJs"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_48":{"__typename":"Paragraph","id":"fe52d6145399_48","name":"b3b8","type":"P","href":null,"layout":null,"metadata":null,"text":"To fix this problem, most game engines will provide you with a fixed time step update loop. If you want to do it yourself, you have to measure the time between two frames, then break it up into equal parts.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_49":{"__typename":"Paragraph","id":"fe52d6145399_49","name":"c1ed","type":"H3","href":null,"layout":null,"metadata":null,"text":"Calculation","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_50":{"__typename":"Paragraph","id":"fe52d6145399_50","name":"e774","type":"P","href":null,"layout":null,"metadata":null,"text":"We use Verlet integration for calculating joint movement, which means that we store the previous and current joint positions and calculate the next position based on those, as opposed to storing and using velocity as you usually do with Euler integration. This approach results in a more stable simulation.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":7,"end":25,"href":"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVerlet_integration","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_51":{"__typename":"Paragraph","id":"fe52d6145399_51","name":"462a","type":"P","href":null,"layout":null,"metadata":null,"text":"Verlet integration is often used for rope physics in game development. If you think about it, hair strands are kind of like tiny ropes, just a bit more rigid.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_52":{"__typename":"Paragraph","id":"fe52d6145399_52","name":"a108","type":"P","href":null,"layout":null,"metadata":null,"text":"The simulation itself is basically split up into two steps:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_53":{"__typename":"Paragraph","id":"fe52d6145399_53","name":"e7ce","type":"OLI","href":null,"layout":null,"metadata":null,"text":"Calculate forces (gravity, other world influences like wind, etc.); and","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_54":{"__typename":"Paragraph","id":"fe52d6145399_54","name":"3aee","type":"OLI","href":null,"layout":null,"metadata":null,"text":"Apply constraints.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_55":{"__typename":"Paragraph","id":"fe52d6145399_55","name":"8ec8","type":"PRE","href":null,"layout":null,"metadata":null,"text":"void BonePhysicsSimulator::Simulate(const SimulatorData& data) {\n DebugAssert(data.chain_.Count(), \"Empty chain\");\n SetInitialJointPositions(data);\n ApplyForce(data);\n ApplyConstraints(data);\n ApplySimulationUpdates(data);\n}","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":{"__typename":"CodeBlockMetadata","mode":"EXPLICIT","lang":"cpp"},"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_56":{"__typename":"Paragraph","id":"fe52d6145399_56","name":"6bac","type":"P","href":null,"layout":null,"metadata":null,"text":"Constraints are what limits or enhances the movement of joints to achieve the desired effect. You can apply the constraints multiple times — the more you do it, the more accurate the simulation result will be. But it comes at a cost as you will burn more precious CPU cycles.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_57":{"__typename":"Paragraph","id":"fe52d6145399_57","name":"43b5","type":"H3","href":null,"layout":null,"metadata":null,"text":"Simulation Constraints","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_58":{"__typename":"Paragraph","id":"fe52d6145399_58","name":"50f6","type":"H3","href":null,"layout":null,"metadata":null,"text":"Damping","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_59":{"__typename":"Paragraph","id":"fe52d6145399_59","name":"d704","type":"P","href":null,"layout":null,"metadata":null,"text":"This is used to reduce the effect of position change. The effect is applied from the start to the end of the chain.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*Tn_QohjKYD_D4vDu":{"__typename":"ImageMetadata","id":"0*Tn_QohjKYD_D4vDu","originalHeight":516,"originalWidth":392,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_60":{"__typename":"Paragraph","id":"fe52d6145399_60","name":"fe8a","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*Tn_QohjKYD_D4vDu"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*UXCvfvbh88BGFUH8":{"__typename":"ImageMetadata","id":"0*UXCvfvbh88BGFUH8","originalHeight":514,"originalWidth":390,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_61":{"__typename":"Paragraph","id":"fe52d6145399_61","name":"3bbd","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*UXCvfvbh88BGFUH8"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_62":{"__typename":"Paragraph","id":"fe52d6145399_62","name":"d9a8","type":"PRE","href":null,"layout":null,"metadata":null,"text":"Vector3 BonePhysicsSimulator::DampPositionDelta(const Vector3& velocity, const Ref\u003CBonePhysicsConfiguration\u003E& physics_configuration) {\n return velocity * (1 - physics_configuration-\u003Edamping_);\n}","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":{"__typename":"CodeBlockMetadata","mode":"EXPLICIT","lang":"cpp"},"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_63":{"__typename":"Paragraph","id":"fe52d6145399_63","name":"8047","type":"H3","href":null,"layout":null,"metadata":null,"text":"Bounciness","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_64":{"__typename":"Paragraph","id":"fe52d6145399_64","name":"7265","type":"P","href":null,"layout":null,"metadata":null,"text":"This is used to enhance the effect of joint movement down the chain.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*D7q8X4TzN3ttw7XY":{"__typename":"ImageMetadata","id":"0*D7q8X4TzN3ttw7XY","originalHeight":536,"originalWidth":536,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_65":{"__typename":"Paragraph","id":"fe52d6145399_65","name":"9d45","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*D7q8X4TzN3ttw7XY"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_66":{"__typename":"Paragraph","id":"fe52d6145399_66","name":"bb50","type":"PRE","href":null,"layout":null,"metadata":null,"text":"Vector3 diff = previous_position - joint-\u003Esimulation_position_;\njoint-\u003Esimulation_position_ += diff * (1 - bounciness);","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":{"__typename":"CodeBlockMetadata","mode":"EXPLICIT","lang":"cpp"},"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_67":{"__typename":"Paragraph","id":"fe52d6145399_67","name":"38a2","type":"H3","href":null,"layout":null,"metadata":null,"text":"Collision","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_68":{"__typename":"Paragraph","id":"fe52d6145399_68","name":"7414","type":"P","href":null,"layout":null,"metadata":null,"text":"I decided to implement my own collision system because it was simple enough to add to the simulation, and it enabled me to fine-tune hair collision without relying on external dependencies.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_69":{"__typename":"Paragraph","id":"fe52d6145399_69","name":"7cad","type":"P","href":null,"layout":null,"metadata":null,"text":"We ended up supporting multiple types of colliders — sphere, plane, capsule.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*IVuUYXDgNNlteiHK":{"__typename":"ImageMetadata","id":"0*IVuUYXDgNNlteiHK","originalHeight":531,"originalWidth":536,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_70":{"__typename":"Paragraph","id":"fe52d6145399_70","name":"8949","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*IVuUYXDgNNlteiHK"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*5UEwNYVkPLyk16Wg":{"__typename":"ImageMetadata","id":"0*5UEwNYVkPLyk16Wg","originalHeight":536,"originalWidth":536,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_71":{"__typename":"Paragraph","id":"fe52d6145399_71","name":"df8f","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*5UEwNYVkPLyk16Wg"},"text":"Sphere-to-sphere collision and sphere-to-plane collision.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":57,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*5Sj8eifRbgGUjWKB":{"__typename":"ImageMetadata","id":"0*5Sj8eifRbgGUjWKB","originalHeight":535,"originalWidth":536,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_72":{"__typename":"Paragraph","id":"fe52d6145399_72","name":"9286","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*5Sj8eifRbgGUjWKB"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*soHknyHSoE_kly4g":{"__typename":"ImageMetadata","id":"0*soHknyHSoE_kly4g","originalHeight":1600,"originalWidth":1600,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_73":{"__typename":"Paragraph","id":"fe52d6145399_73","name":"c2af","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*soHknyHSoE_kly4g"},"text":"Sphere-to-capsule collision and the character collider setup.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":61,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_74":{"__typename":"Paragraph","id":"fe52d6145399_74","name":"6ccb","type":"H3","href":null,"layout":null,"metadata":null,"text":"Rotation Lock","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_75":{"__typename":"Paragraph","id":"fe52d6145399_75","name":"1410","type":"P","href":null,"layout":null,"metadata":null,"text":"I implemented rotation lock, which allows you to limit the maximum angle of rotation from parent to child joint. For example, you could say that the maximum bend is 90 degrees, which could be useful in some cases. However, in the end we didn’t use it for the hair system.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_76":{"__typename":"Paragraph","id":"fe52d6145399_76","name":"61be","type":"H3","href":null,"layout":null,"metadata":null,"text":"Pinned Joints","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_77":{"__typename":"Paragraph","id":"fe52d6145399_77","name":"4db9","type":"P","href":null,"layout":null,"metadata":null,"text":"My Talking Angela 2 features a bathroom where you can bathe your Talking Angela by applying some soap to her. This spawns soap bubbles all over the character, and you have to wash them off using a shower head.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_78":{"__typename":"Paragraph","id":"fe52d6145399_78","name":"87c7","type":"P","href":null,"layout":null,"metadata":null,"text":"To animate the shower hose, we used the bone physics system. However, the final joint needed to be moveable as the player was going to drag it around.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_79":{"__typename":"Paragraph","id":"fe52d6145399_79","name":"89c7","type":"P","href":null,"layout":null,"metadata":null,"text":"We could simply override the joint’s position in the simulation, and the rest of the joints would react to that. We called this process “joint pinning”.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*QH0VOYNBAwretZx1":{"__typename":"ImageMetadata","id":"0*QH0VOYNBAwretZx1","originalHeight":544,"originalWidth":544,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_80":{"__typename":"Paragraph","id":"fe52d6145399_80","name":"b875","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*QH0VOYNBAwretZx1"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_81":{"__typename":"Paragraph","id":"fe52d6145399_81","name":"4309","type":"H3","href":null,"layout":null,"metadata":null,"text":"Joint Rotation","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_82":{"__typename":"Paragraph","id":"fe52d6145399_82","name":"530e","type":"P","href":null,"layout":null,"metadata":null,"text":"Just a tip if you’re ever working on something similar yourself — if you want to keep the chain mesh volume consistent, an important step is to always rotate the child joint towards the parent. If you don’t, the mesh will appear stretched.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_83":{"__typename":"Paragraph","id":"fe52d6145399_83","name":"a76e","type":"H3","href":null,"layout":null,"metadata":null,"text":"Simulation Weight","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_84":{"__typename":"Paragraph","id":"fe52d6145399_84","name":"c1c7","type":"P","href":null,"layout":null,"metadata":null,"text":"Simulation weight is a variable that tells the simulator how strongly to apply the simulation result to the final joint position. It lerps between the original joint position and the simulated joint position.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_85":{"__typename":"Paragraph","id":"fe52d6145399_85","name":"c652","type":"P","href":null,"layout":null,"metadata":null,"text":"This would allow us to have stylized physics in cases where physically correct simulations would break the desired hairstyle. For example, if we have a braid over the shoulder, we want to keep it on the shoulder at all times, while allowing it to bounce a bit when moving. If we were to use the simulation fully, the braid would simply fall down, being pulled by gravity.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*NBj50R9Nwk99hH4R":{"__typename":"ImageMetadata","id":"0*NBj50R9Nwk99hH4R","originalHeight":357,"originalWidth":874,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_86":{"__typename":"Paragraph","id":"fe52d6145399_86","name":"5398","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*NBj50R9Nwk99hH4R"},"text":"Debugging hair texture — the final result is much nicer.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":56,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:1*aa9jNd5P7RHuqRAuqiBJGg.gif":{"__typename":"ImageMetadata","id":"1*aa9jNd5P7RHuqRAuqiBJGg.gif","originalHeight":549,"originalWidth":414,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_87":{"__typename":"Paragraph","id":"fe52d6145399_87","name":"c3fd","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:1*aa9jNd5P7RHuqRAuqiBJGg.gif"},"text":"Stylized physics example — the braid over the shoulder.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":55,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_88":{"__typename":"Paragraph","id":"fe52d6145399_88","name":"6120","type":"P","href":null,"layout":null,"metadata":null,"text":"With this, we could also animate parts of the hair with traditional animation, if needed. This would be useful in complex cases, like when Angela is getting up in the morning.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_89":{"__typename":"Paragraph","id":"fe52d6145399_89","name":"0a5f","type":"P","href":null,"layout":null,"metadata":null,"text":"We are now also able to combine different physics behaviors per hair style, because each chain has its own properties. A ponytail could be fully physically simulated, for example.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_90":{"__typename":"Paragraph","id":"fe52d6145399_90","name":"b624","type":"H3","href":null,"layout":null,"metadata":null,"text":"Applying the System to a Hair Rig","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_91":{"__typename":"Paragraph","id":"fe52d6145399_91","name":"2928","type":"P","href":null,"layout":null,"metadata":null,"text":"We have 1 to 20 chains per hair rig. There is no need to cross-connect the chains like you would do for cloth simulation. As each of the chains is standalone, we can have some mesh clipping for more complex hair. Angela’s arms can pass between the strands in some cases, but we decided that that would be acceptable.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*Qm1qjNFtRxFoB7KI":{"__typename":"ImageMetadata","id":"0*Qm1qjNFtRxFoB7KI","originalHeight":554,"originalWidth":555,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_92":{"__typename":"Paragraph","id":"fe52d6145399_92","name":"7206","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*Qm1qjNFtRxFoB7KI"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_93":{"__typename":"Paragraph","id":"fe52d6145399_93","name":"5ec4","type":"P","href":null,"layout":null,"metadata":null,"text":"Each hair style has from 1 to 3 different lengths, so we reused a lot of rigs to minimize the app size as much as possible.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_94":{"__typename":"Paragraph","id":"fe52d6145399_94","name":"459d","type":"H3","href":null,"layout":null,"metadata":null,"text":"Results","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:1*v6IBVwy-AvrSgLxJTwiSvQ.gif":{"__typename":"ImageMetadata","id":"1*v6IBVwy-AvrSgLxJTwiSvQ.gif","originalHeight":850,"originalWidth":641,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_95":{"__typename":"Paragraph","id":"fe52d6145399_95","name":"3fde","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:1*v6IBVwy-AvrSgLxJTwiSvQ.gif"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*nqfFY-AmQ6C_n63U":{"__typename":"ImageMetadata","id":"0*nqfFY-AmQ6C_n63U","originalHeight":850,"originalWidth":643,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_96":{"__typename":"Paragraph","id":"fe52d6145399_96","name":"3e7e","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*nqfFY-AmQ6C_n63U"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*WXnE-MITNznbJ_FC":{"__typename":"ImageMetadata","id":"0*WXnE-MITNznbJ_FC","originalHeight":741,"originalWidth":663,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_97":{"__typename":"Paragraph","id":"fe52d6145399_97","name":"e3e1","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*WXnE-MITNznbJ_FC"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:1*AvuxgnwCY_EgSjXpBMRWZw.gif":{"__typename":"ImageMetadata","id":"1*AvuxgnwCY_EgSjXpBMRWZw.gif","originalHeight":716,"originalWidth":544,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_98":{"__typename":"Paragraph","id":"fe52d6145399_98","name":"a81a","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:1*AvuxgnwCY_EgSjXpBMRWZw.gif"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*mh90cFJFM4NIjo7U":{"__typename":"ImageMetadata","id":"0*mh90cFJFM4NIjo7U","originalHeight":391,"originalWidth":389,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_99":{"__typename":"Paragraph","id":"fe52d6145399_99","name":"9d74","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*mh90cFJFM4NIjo7U"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_100":{"__typename":"Paragraph","id":"fe52d6145399_100","name":"1c3d","type":"H3","href":null,"layout":null,"metadata":null,"text":"Workflow for Artists","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_101":{"__typename":"Paragraph","id":"fe52d6145399_101","name":"e874","type":"P","href":null,"layout":null,"metadata":null,"text":"It’s a two-step process. When a rig is imported from 3D software to our engine, you can right-click it and use a context menu that runs a hair setup script on it. What it does is finds the root joint, then adds a BonePhysicsChain object for each chain that it finds, and automatically links all the child joints. It also automatically creates a physics setup configuration object with some defaults that suit most of the hair dynamics, so in an ideal case you probably don’t even have to tweak the settings that much.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_102":{"__typename":"Paragraph","id":"fe52d6145399_102","name":"0a0c","type":"P","href":null,"layout":null,"metadata":null,"text":"The second part is testing the hair, which is done using another context menu. It will spawn the hair for you, to quickly verify if it’s working.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*B5TkKY50Vw_nYidG":{"__typename":"ImageMetadata","id":"0*B5TkKY50Vw_nYidG","originalHeight":865,"originalWidth":865,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_103":{"__typename":"Paragraph","id":"fe52d6145399_103","name":"9425","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*B5TkKY50Vw_nYidG"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_104":{"__typename":"Paragraph","id":"fe52d6145399_104","name":"f1cf","type":"H3","href":null,"layout":null,"metadata":null,"text":"Other Applications","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_105":{"__typename":"Paragraph","id":"fe52d6145399_105","name":"5ba0","type":"P","href":null,"layout":null,"metadata":null,"text":"One of the other use cases is the shower hose, as previously mentioned above. We also used it to animate some headwear, as shown below.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*zvRT44FbgCduymTT":{"__typename":"ImageMetadata","id":"0*zvRT44FbgCduymTT","originalHeight":513,"originalWidth":515,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_106":{"__typename":"Paragraph","id":"fe52d6145399_106","name":"a482","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*zvRT44FbgCduymTT"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*Ts8soQ4lWr6MUcni":{"__typename":"ImageMetadata","id":"0*Ts8soQ4lWr6MUcni","originalHeight":390,"originalWidth":391,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_107":{"__typename":"Paragraph","id":"fe52d6145399_107","name":"412f","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*Ts8soQ4lWr6MUcni"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*DnqxN_XUG9S0Jom1":{"__typename":"ImageMetadata","id":"0*DnqxN_XUG9S0Jom1","originalHeight":578,"originalWidth":576,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_108":{"__typename":"Paragraph","id":"fe52d6145399_108","name":"3f65","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*DnqxN_XUG9S0Jom1"},"text":"Headwear and some bouncy spheres that were used when testing the system in development.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":87,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_109":{"__typename":"Paragraph","id":"fe52d6145399_109","name":"c243","type":"H3","href":null,"layout":null,"metadata":null,"text":"Conclusion","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_110":{"__typename":"Paragraph","id":"fe52d6145399_110","name":"4340","type":"P","href":null,"layout":null,"metadata":null,"text":"Working on the hair system for My Talking Angela 2 was a challenging project for me. There were so many unknowns, the biggest and the most important of which was the fact that the style of the game wasn’t yet finalized. (Although artists might say that the style is never final — at least until it’s final, final). I had to guess some things and, in the end, I created some small features that weren’t used. That was a shame because I probably made some cool bugs that will never see the light of day.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_111":{"__typename":"Paragraph","id":"fe52d6145399_111","name":"2514","type":"P","href":null,"layout":null,"metadata":null,"text":"Looking at it now, the system is kind of simple. But you know what? If I were to do it again, I would simplify it even further, and get an artist on board as soon as possible to help prototype the custom-made assets.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_112":{"__typename":"Paragraph","id":"fe52d6145399_112","name":"0bbb","type":"P","href":null,"layout":null,"metadata":null,"text":"Performance-wise, we haven’t had any issues so far, which is great. But we’re targeting mobile devices, so every bit of extra performance helps — if nothing else, the battery of the device lasts longer. As the Bone Physics system is designed in a self-sufficient way — I called it a “black box” before — all the calculations could also be run on a different thread, and then at the end we could just apply them on the main thread.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_113":{"__typename":"Paragraph","id":"fe52d6145399_113","name":"4ab3","type":"P","href":null,"layout":null,"metadata":null,"text":"In the future, I think we could improve some clipping issues by pairing up the joints in the Physics Chain, and treating them as capsule colliders, which would improve hair behavior when Angela’s arm passes through a hair strand. But overall, I’m very proud of the end result, and I’m looking forward to doing something similar in the future.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_114":{"__typename":"Paragraph","id":"fe52d6145399_114","name":"85f5","type":"P","href":null,"layout":null,"metadata":null,"text":"The best thing about this whole process is that it was pretty hilarious. Some of the bugs I produced were ridiculous and I’m sorry I didn’t record more of them. I’m leaving you with these, as a taste.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:fe52d6145399_115":{"__typename":"Paragraph","id":"fe52d6145399_115","name":"5149","type":"P","href":null,"layout":null,"metadata":null,"text":"Thank you for reading.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*EFBBW3Pr026N1LVI":{"__typename":"ImageMetadata","id":"0*EFBBW3Pr026N1LVI","originalHeight":644,"originalWidth":650,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_116":{"__typename":"Paragraph","id":"fe52d6145399_116","name":"ae08","type":"IMG","href":null,"layout":"OUTSET_ROW","metadata":{"__ref":"ImageMetadata:0*EFBBW3Pr026N1LVI"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*hsM9c4wuxvHL1V7w":{"__typename":"ImageMetadata","id":"0*hsM9c4wuxvHL1V7w","originalHeight":645,"originalWidth":650,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:fe52d6145399_117":{"__typename":"Paragraph","id":"fe52d6145399_117","name":"7f34","type":"IMG","href":null,"layout":"OUTSET_ROW_CONTINUE","metadata":{"__ref":"ImageMetadata:0*hsM9c4wuxvHL1V7w"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"CollectionViewerEdge:collectionId:6ec626d5ad62-viewerId:lo_39beedb2a269":{"__typename":"CollectionViewerEdge","id":"collectionId:6ec626d5ad62-viewerId:lo_39beedb2a269","isEditor":false,"isMuting":false},"ImageMetadata:1*nTxl_7KgWQYo8PfVROUK_A.png":{"__typename":"ImageMetadata","id":"1*nTxl_7KgWQYo8PfVROUK_A.png","originalWidth":4566,"originalHeight":4566},"PostViewerEdge:postId:46cf06181893-viewerId:lo_39beedb2a269":{"__typename":"PostViewerEdge","shouldIndexPostForExternalSearch":true,"id":"postId:46cf06181893-viewerId:lo_39beedb2a269"},"Tag:game-development":{"__typename":"Tag","id":"game-development","displayTitle":"Game Development","normalizedTagSlug":"game-development"},"Tag:procedural-animation":{"__typename":"Tag","id":"procedural-animation","displayTitle":"Procedural Animation","normalizedTagSlug":"procedural-animation"},"Tag:simulation":{"__typename":"Tag","id":"simulation","displayTitle":"Simulation","normalizedTagSlug":"simulation"},"Tag:mobile-games":{"__typename":"Tag","id":"mobile-games","displayTitle":"Mobile Games","normalizedTagSlug":"mobile-games"},"Tag:rendering":{"__typename":"Tag","id":"rendering","displayTitle":"Rendering","normalizedTagSlug":"rendering"},"Post:46cf06181893":{"__typename":"Post","id":"46cf06181893","collection":{"__ref":"Collection:6ec626d5ad62"},"content({\"postMeteringOptions\":{}})":{"__typename":"PostContent","isLockedPreviewOnly":false,"bodyModel":{"__typename":"RichText","sections":[{"__typename":"Section","name":"b04d","startIndex":0,"textLayout":null,"imageLayout":null,"backgroundImage":null,"videoLayout":null,"backgroundVideo":null}],"paragraphs":[{"__ref":"Paragraph:fe52d6145399_0"},{"__ref":"Paragraph:fe52d6145399_1"},{"__ref":"Paragraph:fe52d6145399_2"},{"__ref":"Paragraph:fe52d6145399_3"},{"__ref":"Paragraph:fe52d6145399_4"},{"__ref":"Paragraph:fe52d6145399_5"},{"__ref":"Paragraph:fe52d6145399_6"},{"__ref":"Paragraph:fe52d6145399_7"},{"__ref":"Paragraph:fe52d6145399_8"},{"__ref":"Paragraph:fe52d6145399_9"},{"__ref":"Paragraph:fe52d6145399_10"},{"__ref":"Paragraph:fe52d6145399_11"},{"__ref":"Paragraph:fe52d6145399_12"},{"__ref":"Paragraph:fe52d6145399_13"},{"__ref":"Paragraph:fe52d6145399_14"},{"__ref":"Paragraph:fe52d6145399_15"},{"__ref":"Paragraph:fe52d6145399_16"},{"__ref":"Paragraph:fe52d6145399_17"},{"__ref":"Paragraph:fe52d6145399_18"},{"__ref":"Paragraph:fe52d6145399_19"},{"__ref":"Paragraph:fe52d6145399_20"},{"__ref":"Paragraph:fe52d6145399_21"},{"__ref":"Paragraph:fe52d6145399_22"},{"__ref":"Paragraph:fe52d6145399_23"},{"__ref":"Paragraph:fe52d6145399_24"},{"__ref":"Paragraph:fe52d6145399_25"},{"__ref":"Paragraph:fe52d6145399_26"},{"__ref":"Paragraph:fe52d6145399_27"},{"__ref":"Paragraph:fe52d6145399_28"},{"__ref":"Paragraph:fe52d6145399_29"},{"__ref":"Paragraph:fe52d6145399_30"},{"__ref":"Paragraph:fe52d6145399_31"},{"__ref":"Paragraph:fe52d6145399_32"},{"__ref":"Paragraph:fe52d6145399_33"},{"__ref":"Paragraph:fe52d6145399_34"},{"__ref":"Paragraph:fe52d6145399_35"},{"__ref":"Paragraph:fe52d6145399_36"},{"__ref":"Paragraph:fe52d6145399_37"},{"__ref":"Paragraph:fe52d6145399_38"},{"__ref":"Paragraph:fe52d6145399_39"},{"__ref":"Paragraph:fe52d6145399_40"},{"__ref":"Paragraph:fe52d6145399_41"},{"__ref":"Paragraph:fe52d6145399_42"},{"__ref":"Paragraph:fe52d6145399_43"},{"__ref":"Paragraph:fe52d6145399_44"},{"__ref":"Paragraph:fe52d6145399_45"},{"__ref":"Paragraph:fe52d6145399_46"},{"__ref":"Paragraph:fe52d6145399_47"},{"__ref":"Paragraph:fe52d6145399_48"},{"__ref":"Paragraph:fe52d6145399_49"},{"__ref":"Paragraph:fe52d6145399_50"},{"__ref":"Paragraph:fe52d6145399_51"},{"__ref":"Paragraph:fe52d6145399_52"},{"__ref":"Paragraph:fe52d6145399_53"},{"__ref":"Paragraph:fe52d6145399_54"},{"__ref":"Paragraph:fe52d6145399_55"},{"__ref":"Paragraph:fe52d6145399_56"},{"__ref":"Paragraph:fe52d6145399_57"},{"__ref":"Paragraph:fe52d6145399_58"},{"__ref":"Paragraph:fe52d6145399_59"},{"__ref":"Paragraph:fe52d6145399_60"},{"__ref":"Paragraph:fe52d6145399_61"},{"__ref":"Paragraph:fe52d6145399_62"},{"__ref":"Paragraph:fe52d6145399_63"},{"__ref":"Paragraph:fe52d6145399_64"},{"__ref":"Paragraph:fe52d6145399_65"},{"__ref":"Paragraph:fe52d6145399_66"},{"__ref":"Paragraph:fe52d6145399_67"},{"__ref":"Paragraph:fe52d6145399_68"},{"__ref":"Paragraph:fe52d6145399_69"},{"__ref":"Paragraph:fe52d6145399_70"},{"__ref":"Paragraph:fe52d6145399_71"},{"__ref":"Paragraph:fe52d6145399_72"},{"__ref":"Paragraph:fe52d6145399_73"},{"__ref":"Paragraph:fe52d6145399_74"},{"__ref":"Paragraph:fe52d6145399_75"},{"__ref":"Paragraph:fe52d6145399_76"},{"__ref":"Paragraph:fe52d6145399_77"},{"__ref":"Paragraph:fe52d6145399_78"},{"__ref":"Paragraph:fe52d6145399_79"},{"__ref":"Paragraph:fe52d6145399_80"},{"__ref":"Paragraph:fe52d6145399_81"},{"__ref":"Paragraph:fe52d6145399_82"},{"__ref":"Paragraph:fe52d6145399_83"},{"__ref":"Paragraph:fe52d6145399_84"},{"__ref":"Paragraph:fe52d6145399_85"},{"__ref":"Paragraph:fe52d6145399_86"},{"__ref":"Paragraph:fe52d6145399_87"},{"__ref":"Paragraph:fe52d6145399_88"},{"__ref":"Paragraph:fe52d6145399_89"},{"__ref":"Paragraph:fe52d6145399_90"},{"__ref":"Paragraph:fe52d6145399_91"},{"__ref":"Paragraph:fe52d6145399_92"},{"__ref":"Paragraph:fe52d6145399_93"},{"__ref":"Paragraph:fe52d6145399_94"},{"__ref":"Paragraph:fe52d6145399_95"},{"__ref":"Paragraph:fe52d6145399_96"},{"__ref":"Paragraph:fe52d6145399_97"},{"__ref":"Paragraph:fe52d6145399_98"},{"__ref":"Paragraph:fe52d6145399_99"},{"__ref":"Paragraph:fe52d6145399_100"},{"__ref":"Paragraph:fe52d6145399_101"},{"__ref":"Paragraph:fe52d6145399_102"},{"__ref":"Paragraph:fe52d6145399_103"},{"__ref":"Paragraph:fe52d6145399_104"},{"__ref":"Paragraph:fe52d6145399_105"},{"__ref":"Paragraph:fe52d6145399_106"},{"__ref":"Paragraph:fe52d6145399_107"},{"__ref":"Paragraph:fe52d6145399_108"},{"__ref":"Paragraph:fe52d6145399_109"},{"__ref":"Paragraph:fe52d6145399_110"},{"__ref":"Paragraph:fe52d6145399_111"},{"__ref":"Paragraph:fe52d6145399_112"},{"__ref":"Paragraph:fe52d6145399_113"},{"__ref":"Paragraph:fe52d6145399_114"},{"__ref":"Paragraph:fe52d6145399_115"},{"__ref":"Paragraph:fe52d6145399_116"},{"__ref":"Paragraph:fe52d6145399_117"}]},"validatedShareKey":"","shareKeyCreator":null},"creator":{"__ref":"User:565c34edb417"},"inResponseToEntityType":null,"isLocked":false,"isMarkedPaywallOnly":false,"lockedSource":"LOCKED_POST_SOURCE_NONE","mediumUrl":"https:\u002F\u002Fmedium.com\u002Foutfit7\u002Fthe-my-talking-angela-2-hair-system-46cf06181893","primaryTopic":{"__ref":"Topic:decb52b64abf"},"topics":[{"__typename":"Topic","slug":"programming"}],"isPublished":true,"latestPublishedVersion":"fe52d6145399","visibility":"PUBLIC","postResponses":{"__typename":"PostResponses","count":1},"clapCount":86,"allowResponses":true,"isLimitedState":false,"title":"The My Talking Angela 2 Hair System","isSeries":false,"sequence":null,"uniqueSlug":"the-my-talking-angela-2-hair-system-46cf06181893","socialTitle":"","socialDek":"","canonicalUrl":"","metaDescription":"","latestPublishedAt":1668684025148,"readingTime":12.462264150943396,"previewContent":{"__typename":"PreviewContent","subtitle":"The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together."},"previewImage":{"__ref":"ImageMetadata:0*QeoWDJ4qQhrCS_Ei"},"isShortform":false,"seoTitle":"","firstPublishedAt":1668615574780,"updatedAt":1668689403145,"shortformType":"SHORTFORM_TYPE_LINK","seoDescription":"","viewerEdge":{"__ref":"PostViewerEdge:postId:46cf06181893-viewerId:lo_39beedb2a269"},"isSuspended":false,"license":"ALL_RIGHTS_RESERVED","tags":[{"__ref":"Tag:game-development"},{"__ref":"Tag:procedural-animation"},{"__ref":"Tag:simulation"},{"__ref":"Tag:mobile-games"},{"__ref":"Tag:rendering"}],"isNewsletter":false,"statusForCollection":"APPROVED","pendingCollection":null,"detectedLanguage":"en","wordCount":2746,"layerCake":3,"responsesLocked":false}}</script><script>window.__MIDDLEWARE_STATE__={"session":{"xsrf":""},"cache":{"cacheStatus":"HIT"}}</script><script src="https://cdn-client.medium.com/lite/static/js/manifest.6ad5b715.js"></script><script src="https://cdn-client.medium.com/lite/static/js/9865.1496d74a.js"></script><script src="https://cdn-client.medium.com/lite/static/js/main.e556b4ac.js"></script><script src="https://cdn-client.medium.com/lite/static/js/instrumentation.d9108df7.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/reporting.ff22a7a5.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/9120.5df29668.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5049.d1ead72d.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/4810.6318add7.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6618.db187378.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2707.b0942613.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/9977.5b3eb23a.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8599.1ab63137.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5250.9f9e01d2.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5787.e66a3a4d.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2648.26563adf.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8393.826a25fb.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/3104.0364d65e.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/3735.afb7e926.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5642.8ad8a900.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6546.cd03f950.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6834.08de95de.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7346.72622eb9.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2420.2a5e2d95.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/839.ca7937c2.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7975.d195c6f1.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2106.21ff89d3.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7394.094844de.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2961.00a48598.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8204.c4082863.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/4391.59acaed3.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/PostPage.MainContent.1387c5dc.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8414.6565ad5f.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/3974.8d3e0217.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2527.a0afad8a.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/PostResponsesContent.36c2ecf4.chunk.js"></script><script>window.main();</script><script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'8e92d8c22bf1ce2e',t:'MTczMjcxODE0Ny4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body></html>