{"id":1757,"date":"2024-04-22T10:09:35","date_gmt":"2024-04-22T16:09:35","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=1757"},"modified":"2024-04-22T10:09:37","modified_gmt":"2024-04-22T16:09:37","slug":"faces-js-and-playing-with-densely-packed-grids","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/faces-js-and-playing-with-densely-packed-grids\/","title":{"rendered":"Faces.js and Playing with Densely Packed Grids"},"content":{"rendered":"\n<p>I only just recently saw <a href=\"https:\/\/github.com\/zengm-games\/facesjs\">Faces.js<\/a>, a library for producing controllable cartoony avatars. It was launched in 2012, so I&#8217;m a little late to the party. It produces faces (busts, really) randomly, or with certain parameters locked to what you want. <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"># Generate a random face that always has blue skin\n<span class=\"hljs-keyword\">const<\/span> face = generate({ <span class=\"hljs-attr\">body<\/span>: { <span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">\"blue\"<\/span> } });\ndisplay(<span class=\"hljs-string\">\"my-div-id\"<\/span>, face);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I think that&#8217;s a really cool idea, and if you needed this kind of thing on a project, you can install it yourself which is safer than using a hosted service for random avatars. Like, <a href=\"https:\/\/pravatar.cc\/\">Pravatar<\/a> is neat, but these services have a super high churn rate. Do not count on it sticking around. <\/p>\n\n\n\n<p>I wanted to have a quick play and have it output a bunch of random faces on a grid. First I made 100 <code>&lt;div&gt;<\/code>s. You could do this any number of ways, including JavaScript, but I did it with Pug just for fun:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">.faces\n  - <span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">1<\/span>;\n  - <span class=\"hljs-keyword\">while<\/span> (i &lt; <span class=\"hljs-number\">100<\/span>)\n    div(id=<span class=\"hljs-string\">`face-<span class=\"hljs-subst\">${i}<\/span>`<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span><\/span>=<span class=\"hljs-string\">\"face\"<\/span>)\n    - i++;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then I made that into a grid:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.faces<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: grid;\n  <span class=\"hljs-attribute\">grid-template-columns<\/span>: <span class=\"hljs-built_in\">repeat<\/span>(auto-fit, minmax(<span class=\"hljs-number\">100px<\/span>, <span class=\"hljs-number\">1<\/span>fr));\n}\n<span class=\"hljs-selector-class\">.face<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>\n  aspect-ratio: <span class=\"hljs-number\">1<\/span> \/ <span class=\"hljs-number\">1<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Fun:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_wvZReva\" src=\"\/\/codepen.io\/anon\/embed\/wvZReva?height=450&amp;theme-id=47434&amp;slug-hash=wvZReva&amp;default-tab=js,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed wvZReva\" title=\"CodePen Embed wvZReva\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Hm. That makes me want to make the grid more interesting to look at, perhaps with some of the avatars spanning two columns (and thus two rows accommodate the height). <\/p>\n\n\n\n<p>To do that I put a random number 1-10 on each face when creating the <code>&lt;div&gt;<\/code>s, as a data-* attribute:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">.faces\n  - <span class=\"hljs-keyword\">let<\/span> i = <span class=\"hljs-number\">1<\/span>;\n  - <span class=\"hljs-keyword\">while<\/span> (i &lt; <span class=\"hljs-number\">100<\/span>)\n    - <span class=\"hljs-keyword\">var<\/span> n = <span class=\"hljs-built_in\">Math<\/span>.floor(<span class=\"hljs-built_in\">Math<\/span>.random() * <span class=\"hljs-number\">10<\/span> + <span class=\"hljs-number\">1<\/span>);\n    div(id=<span class=\"hljs-string\">`face-<span class=\"hljs-subst\">${i}<\/span>`<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span><\/span>=<span class=\"hljs-string\">\"face\"<\/span> data-size=n)\n    - i++;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then I can select <em>some<\/em> of them and make them bigger:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.face<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>\n  aspect-ratio: <span class=\"hljs-number\">1<\/span> \/ <span class=\"hljs-number\">1<\/span>;\n  \n  &amp;&#91;data-size=\"5\"] {\n    <span class=\"hljs-attribute\">grid-column<\/span>: span <span class=\"hljs-number\">2<\/span>;\n    <span class=\"hljs-attribute\">grid-row<\/span>: span <span class=\"hljs-number\">2<\/span>;\n    <span class=\"hljs-attribute\">scale<\/span>: <span class=\"hljs-number\">1.2<\/span>;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I used <code>scale<\/code> there to juice the size even more and make them overlap:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_vYMvZKw\" src=\"\/\/codepen.io\/anon\/embed\/vYMvZKw?height=450&amp;theme-id=47434&amp;slug-hash=vYMvZKw&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed vYMvZKw\" title=\"CodePen Embed vYMvZKw\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>I wanted to do a <em>few<\/em> more thing though. One, this left some gaps in the grid, as in, literal blank grid positions. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"436\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?resize=1024%2C436&#038;ssl=1\" alt=\"\" class=\"wp-image-1760\" style=\"width:717px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?resize=1024%2C436&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?resize=300%2C128&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?resize=768%2C327&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?resize=1536%2C654&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/CleanShot-2024-04-22-at-08.57.00%402x.png?w=1630&amp;ssl=1 1630w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>It&#8217;s incredibly satisfying to fill those in with just one extra grid declaration:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">grid-auto-flow<\/span>: <span class=\"hljs-selector-tag\">dense<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then I wanted the edges of the screen to allow for overlap, so the edges don&#8217;t seem perfectly lined up. I wanted it to look more like randomly cut wrapping paper. To do that, all I did was <code>scale<\/code> up the <code>body<\/code> (much like we did with the enlarged avatars) and then <code>clip<\/code> off the horizontal overlow.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">body<\/span> {\n  <span class=\"hljs-attribute\">scale<\/span>: <span class=\"hljs-number\">1.2<\/span>;\n  <span class=\"hljs-attribute\">overflow-x<\/span>: clip;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I added a few more random sizes and scalings and, I dunno, it just ended up a satisfying little thing to play with.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_poBVWBm\" src=\"\/\/codepen.io\/anon\/embed\/poBVWBm?height=450&amp;theme-id=47434&amp;slug-hash=poBVWBm&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed poBVWBm\" title=\"CodePen Embed poBVWBm\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Have you actually used a random avatar generator in a production app? On CodePen we just use a consistent generic one, which I hope kinda encourages people to replace it. I imagine random avatars are more useful in mockups and during development. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I only just recently saw Faces.js, a library for producing controllable cartoony avatars. It was launched in 2012, so I&#8217;m a little late to the party. It produces faces (busts, really) randomly, or with certain parameters locked to what you want. I think that&#8217;s a really cool idea, and if you needed this kind of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1762,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[159,3,91],"class_list":["post-1757","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-avatars","tag-javascript","tag-svg"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/04\/faces-thumbs.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1757","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=1757"}],"version-history":[{"count":3,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1757\/revisions"}],"predecessor-version":[{"id":1763,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1757\/revisions\/1763"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/1762"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=1757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=1757"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=1757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}