[{"data":1,"prerenderedAt":1620},["ShallowReactive",2],{"projects-all":3},[4,761,872,1116,1347,1417,1461,1538],{"id":5,"title":6,"additionalTags":7,"body":8,"description":735,"excerpt":736,"extension":737,"featured":738,"meta":739,"name":6,"navigation":738,"openSource":745,"path":746,"projectDate":747,"seo":748,"sitemap":749,"status":753,"stem":754,"subtitle":755,"tags":756,"thumbnail":759,"__hash__":760},"projects/projects/1.portfolio-refresh.md","Portfolio Refresh",[],{"type":9,"value":10,"toc":728},"minimark",[11,15,19,24,47,51,54,58,61,64,67,71,75,78,81,469,472,609,616,637,644,673,677,724],[12,13],"stats-table",{":stats":14},"[{\"label\": \"release date\", \"value\": \"2025\"}]",[16,17,18],"p",{},"Welcome to my 2025 refreshed portfolio.",[20,21,23],"h2",{"id":22},"goals","Goals",[25,26,27,35,41],"ol",{},[28,29,30,34],"li",{},[31,32,33],"strong",{},"Speed"," - It had to be fast and I wanted to get as close to a perfect Lighthouse score as possible.",[28,36,37,40],{},[31,38,39],{},"Modern"," - I wanted to utilize the latest tech, Nuxt, Tailwind, and GSAP for subtle animations & micro-interactions.",[28,42,43,46],{},[31,44,45],{},"Learn Something New"," - Get out of my comfort zone and try new things.",[20,48,50],{"id":49},"results","Results",[52,53],"app-lighthouse-results",{},[20,55,57],{"id":56},"process","Process",[16,59,60],{},"I knew from the very beginning I wanted to stick with Vue but I wanted to take it a step further and explore the Nuxt ecosystem which up to this point I hadn't really had a chance or reason to use.",[16,62,63],{},"Choosing Nuxt lead me to Nuxt UI which brought with it Tailwind, which was another tech that I had minimal experience with but that I wanted to get more familiar with.",[16,65,66],{},"I also knew I wanted to host on Vercel's Edge network as I felt that would get me closer to that perfect Lighthouse score.",[20,68,70],{"id":69},"animations","Animations",[72,73],"app-sticker",{":replayable":74},"true",[16,76,77],{},"The opening sticker animation was made using an SVG that I designed in Adobe Illustrator and then animated the writing in GSAP.",[16,79,80],{},"The entire writing animation is a mere 6 lines of code.",[82,83,88],"pre",{"className":84,"code":85,"language":86,"meta":87,"style":87},"language-vue shiki shiki-themes material-theme-lighter monokai monokai","\u003Cscript setup>\nonMounted(() => {\n    gsap.set(\"#sig-1\", { drawSVG: '0%' });\n    gsap.set(\"#sig-2\", { drawSVG: '0%' });\n    const tl = gsap.timeline({ \n        defaults: { duration: .6, delay: .3, ease: 'power1.inOut' } });\n    tl.to('#sticker', { y: 0, opacity: 1 });\n    tl.to(\"#sig-1\", { drawSVG: '-100%', delay: 0.4 });\n    tl.to(\"#sig-2\", { drawSVG: '100%', delay: -.01 });\n})\n\u003C/script>\n","vue","",[89,90,91,111,132,187,225,254,305,353,400,450,459],"code",{"__ignoreMap":87},[92,93,96,100,104,108],"span",{"class":94,"line":95},"line",1,[92,97,99],{"class":98},"sqipZ","\u003C",[92,101,103],{"class":102},"sDhRb","script",[92,105,107],{"class":106},"s4WCV"," setup",[92,109,110],{"class":98},">\n",[92,112,114,118,122,125,129],{"class":94,"line":113},2,[92,115,117],{"class":116},"sj8bM","onMounted",[92,119,121],{"class":120},"s--uY","(",[92,123,124],{"class":98},"()",[92,126,128],{"class":127},"sMInQ"," =>",[92,130,131],{"class":98}," {\n",[92,133,135,138,141,144,147,151,155,157,160,163,166,169,172,175,178,181,184],{"class":94,"line":134},3,[92,136,137],{"class":120},"    gsap",[92,139,140],{"class":98},".",[92,142,143],{"class":116},"set",[92,145,121],{"class":146},"sFVGM",[92,148,150],{"class":149},"sl1cq","\"",[92,152,154],{"class":153},"seZNR","#sig-1",[92,156,150],{"class":149},[92,158,159],{"class":98},",",[92,161,162],{"class":98}," {",[92,164,165],{"class":146}," drawSVG",[92,167,168],{"class":98},":",[92,170,171],{"class":149}," '",[92,173,174],{"class":153},"0%",[92,176,177],{"class":149},"'",[92,179,180],{"class":98}," }",[92,182,183],{"class":146},")",[92,185,186],{"class":98},";\n",[92,188,190,192,194,196,198,200,203,205,207,209,211,213,215,217,219,221,223],{"class":94,"line":189},4,[92,191,137],{"class":120},[92,193,140],{"class":98},[92,195,143],{"class":116},[92,197,121],{"class":146},[92,199,150],{"class":149},[92,201,202],{"class":153},"#sig-2",[92,204,150],{"class":149},[92,206,159],{"class":98},[92,208,162],{"class":98},[92,210,165],{"class":146},[92,212,168],{"class":98},[92,214,171],{"class":149},[92,216,174],{"class":153},[92,218,177],{"class":149},[92,220,180],{"class":98},[92,222,183],{"class":146},[92,224,186],{"class":98},[92,226,228,231,234,238,241,243,246,248,251],{"class":94,"line":227},5,[92,229,230],{"class":127},"    const",[92,232,233],{"class":120}," tl",[92,235,237],{"class":236},"s-IWT"," =",[92,239,240],{"class":120}," gsap",[92,242,140],{"class":98},[92,244,245],{"class":116},"timeline",[92,247,121],{"class":146},[92,249,250],{"class":98},"{",[92,252,253],{"class":146}," \n",[92,255,257,260,262,264,267,269,273,275,278,280,283,285,288,290,292,295,297,299,301,303],{"class":94,"line":256},6,[92,258,259],{"class":146},"        defaults",[92,261,168],{"class":98},[92,263,162],{"class":98},[92,265,266],{"class":146}," duration",[92,268,168],{"class":98},[92,270,272],{"class":271},"sfpNJ"," .6",[92,274,159],{"class":98},[92,276,277],{"class":146}," delay",[92,279,168],{"class":98},[92,281,282],{"class":271}," .3",[92,284,159],{"class":98},[92,286,287],{"class":146}," ease",[92,289,168],{"class":98},[92,291,171],{"class":149},[92,293,294],{"class":153},"power1.inOut",[92,296,177],{"class":149},[92,298,180],{"class":98},[92,300,180],{"class":98},[92,302,183],{"class":146},[92,304,186],{"class":98},[92,306,308,311,313,316,318,320,323,325,327,329,332,334,337,339,342,344,347,349,351],{"class":94,"line":307},7,[92,309,310],{"class":120},"    tl",[92,312,140],{"class":98},[92,314,315],{"class":116},"to",[92,317,121],{"class":146},[92,319,177],{"class":149},[92,321,322],{"class":153},"#sticker",[92,324,177],{"class":149},[92,326,159],{"class":98},[92,328,162],{"class":98},[92,330,331],{"class":146}," y",[92,333,168],{"class":98},[92,335,336],{"class":271}," 0",[92,338,159],{"class":98},[92,340,341],{"class":146}," opacity",[92,343,168],{"class":98},[92,345,346],{"class":271}," 1",[92,348,180],{"class":98},[92,350,183],{"class":146},[92,352,186],{"class":98},[92,354,356,358,360,362,364,366,368,370,372,374,376,378,380,383,385,387,389,391,394,396,398],{"class":94,"line":355},8,[92,357,310],{"class":120},[92,359,140],{"class":98},[92,361,315],{"class":116},[92,363,121],{"class":146},[92,365,150],{"class":149},[92,367,154],{"class":153},[92,369,150],{"class":149},[92,371,159],{"class":98},[92,373,162],{"class":98},[92,375,165],{"class":146},[92,377,168],{"class":98},[92,379,171],{"class":149},[92,381,382],{"class":153},"-100%",[92,384,177],{"class":149},[92,386,159],{"class":98},[92,388,277],{"class":146},[92,390,168],{"class":98},[92,392,393],{"class":271}," 0.4",[92,395,180],{"class":98},[92,397,183],{"class":146},[92,399,186],{"class":98},[92,401,403,405,407,409,411,413,415,417,419,421,423,425,427,430,432,434,436,438,441,444,446,448],{"class":94,"line":402},9,[92,404,310],{"class":120},[92,406,140],{"class":98},[92,408,315],{"class":116},[92,410,121],{"class":146},[92,412,150],{"class":149},[92,414,202],{"class":153},[92,416,150],{"class":149},[92,418,159],{"class":98},[92,420,162],{"class":98},[92,422,165],{"class":146},[92,424,168],{"class":98},[92,426,171],{"class":149},[92,428,429],{"class":153},"100%",[92,431,177],{"class":149},[92,433,159],{"class":98},[92,435,277],{"class":146},[92,437,168],{"class":98},[92,439,440],{"class":236}," -",[92,442,443],{"class":271},".01",[92,445,180],{"class":98},[92,447,183],{"class":146},[92,449,186],{"class":98},[92,451,453,456],{"class":94,"line":452},10,[92,454,455],{"class":98},"}",[92,457,458],{"class":120},")\n",[92,460,462,465,467],{"class":94,"line":461},11,[92,463,464],{"class":98},"\u003C/",[92,466,103],{"class":102},[92,468,110],{"class":98},[16,470,471],{},"The sticker's dropshadow was made using an SVG filter:",[82,473,477],{"className":474,"code":475,"language":476,"meta":87,"style":87},"language-html shiki shiki-themes material-theme-lighter monokai monokai","\u003Csvg ...>\n  \u003Cdefs>\n      \u003Cfilter id=\"shadow\">\n          \u003CfeDropShadow dx=\"0\" dy=\"6\" stdDeviation=\"7\" flood-opacity=\"0.3\" />\n      \u003C/filter>\n  \u003C/defs>\n\u003C/svg>\n","html",[89,478,479,491,501,524,583,592,601],{"__ignoreMap":87},[92,480,481,483,486,489],{"class":94,"line":95},[92,482,99],{"class":98},[92,484,485],{"class":102},"svg",[92,487,488],{"class":106}," ...",[92,490,110],{"class":98},[92,492,493,496,499],{"class":94,"line":113},[92,494,495],{"class":98},"  \u003C",[92,497,498],{"class":102},"defs",[92,500,110],{"class":98},[92,502,503,506,509,512,515,517,520,522],{"class":94,"line":134},[92,504,505],{"class":98},"      \u003C",[92,507,508],{"class":102},"filter",[92,510,511],{"class":106}," id",[92,513,514],{"class":98},"=",[92,516,150],{"class":149},[92,518,519],{"class":153},"shadow",[92,521,150],{"class":149},[92,523,110],{"class":98},[92,525,526,529,532,535,537,539,542,544,547,549,551,554,556,559,561,563,566,568,571,573,575,578,580],{"class":94,"line":189},[92,527,528],{"class":98},"          \u003C",[92,530,531],{"class":102},"feDropShadow",[92,533,534],{"class":106}," dx",[92,536,514],{"class":98},[92,538,150],{"class":149},[92,540,541],{"class":153},"0",[92,543,150],{"class":149},[92,545,546],{"class":106}," dy",[92,548,514],{"class":98},[92,550,150],{"class":149},[92,552,553],{"class":153},"6",[92,555,150],{"class":149},[92,557,558],{"class":106}," stdDeviation",[92,560,514],{"class":98},[92,562,150],{"class":149},[92,564,565],{"class":153},"7",[92,567,150],{"class":149},[92,569,570],{"class":106}," flood-opacity",[92,572,514],{"class":98},[92,574,150],{"class":149},[92,576,577],{"class":153},"0.3",[92,579,150],{"class":149},[92,581,582],{"class":98}," />\n",[92,584,585,588,590],{"class":94,"line":227},[92,586,587],{"class":98},"      \u003C/",[92,589,508],{"class":102},[92,591,110],{"class":98},[92,593,594,597,599],{"class":94,"line":256},[92,595,596],{"class":98},"  \u003C/",[92,598,498],{"class":102},[92,600,110],{"class":98},[92,602,603,605,607],{"class":94,"line":307},[92,604,464],{"class":98},[92,606,485],{"class":102},[92,608,110],{"class":98},[16,610,611,612,615],{},"and then applied onto the ",[89,613,614],{},"\u003Csvg/>"," using a regular style attribute:",[82,617,619],{"className":474,"code":618,"language":476,"meta":87,"style":87},"\u003Csvg style=\"filter: url('#shadow'); ...\n",[89,620,621],{"__ignoreMap":87},[92,622,623,625,627,630,632,634],{"class":94,"line":95},[92,624,99],{"class":98},[92,626,485],{"class":102},[92,628,629],{"class":106}," style",[92,631,514],{"class":98},[92,633,150],{"class":149},[92,635,636],{"class":153},"filter: url('#shadow'); ...\n",[16,638,639,640,643],{},"The ",[89,641,642],{},"v-gsap-nuxt"," module makes it even easier to animate DOM elements simply through specialized attributes.\nThis is method I used on the work history page to animate the history entries in as the page scrolls.",[82,645,649],{"className":646,"code":647,"language":648,"meta":87,"style":87},"language-vue-html shiki shiki-themes material-theme-lighter monokai monokai","\u003Celement v-gsap.whenVisible.once.stagger.from=\"{ opacity: 0, x: -10, stagger: 0.2 }\" >\n","vue-html",[89,650,651],{"__ignoreMap":87},[92,652,653,655,658,661,663,665,668,670],{"class":94,"line":95},[92,654,99],{"class":98},[92,656,657],{"class":102},"element",[92,659,660],{"class":106}," v-gsap.whenVisible.once.stagger.from",[92,662,514],{"class":98},[92,664,150],{"class":149},[92,666,667],{"class":153},"{ opacity: 0, x: -10, stagger: 0.2 }",[92,669,150],{"class":149},[92,671,672],{"class":98}," >\n",[20,674,676],{"id":675},"technologies-utilized","Technologies Utilized",[678,679,680,690],"table",{},[681,682,683],"thead",{},[684,685,686],"tr",{},[687,688,689],"th",{},"Frontend",[691,692,693,699,704,709,714,719],"tbody",{},[684,694,695],{},[696,697,698],"td",{},"Nuxt",[684,700,701],{},[696,702,703],{},"Vue 3",[684,705,706],{},[696,707,708],{},"Nuxt UI",[684,710,711],{},[696,712,713],{},"Tailwind",[684,715,716],{},[696,717,718],{},"GSAP",[684,720,721],{},[696,722,723],{},"TypeScript",[725,726,727],"style",{},"html pre.shiki code .sqipZ, html code.shiki .sqipZ{--shiki-light:#39ADB5;--shiki-default:#F8F8F2;--shiki-dark:#F8F8F2}html pre.shiki code .sDhRb, html code.shiki .sDhRb{--shiki-light:#E53935;--shiki-default:#F92672;--shiki-dark:#F92672}html pre.shiki code .s4WCV, html code.shiki .s4WCV{--shiki-light:#9C3EDA;--shiki-default:#A6E22E;--shiki-dark:#A6E22E}html pre.shiki code .sj8bM, html code.shiki .sj8bM{--shiki-light:#6182B8;--shiki-default:#A6E22E;--shiki-dark:#A6E22E}html pre.shiki code .s--uY, html code.shiki .s--uY{--shiki-light:#90A4AE;--shiki-default:#F8F8F2;--shiki-dark:#F8F8F2}html pre.shiki code .sMInQ, html code.shiki .sMInQ{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#66D9EF;--shiki-default-font-style:italic;--shiki-dark:#66D9EF;--shiki-dark-font-style:italic}html pre.shiki code .sFVGM, html code.shiki .sFVGM{--shiki-light:#E53935;--shiki-default:#F8F8F2;--shiki-dark:#F8F8F2}html pre.shiki code .sl1cq, html code.shiki .sl1cq{--shiki-light:#39ADB5;--shiki-default:#E6DB74;--shiki-dark:#E6DB74}html pre.shiki code .seZNR, html code.shiki .seZNR{--shiki-light:#91B859;--shiki-default:#E6DB74;--shiki-dark:#E6DB74}html pre.shiki code .s-IWT, html code.shiki .s-IWT{--shiki-light:#39ADB5;--shiki-default:#F92672;--shiki-dark:#F92672}html pre.shiki code .sfpNJ, html code.shiki .sfpNJ{--shiki-light:#F76D47;--shiki-default:#AE81FF;--shiki-dark:#AE81FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":87,"searchDepth":113,"depth":113,"links":729},[730,731,732,733,734],{"id":22,"depth":113,"text":23},{"id":49,"depth":113,"text":50},{"id":56,"depth":113,"text":57},{"id":69,"depth":113,"text":70},{"id":675,"depth":113,"text":676},"Rebuilding my website with modern tech.",null,"md",true,{"items":740},[741,742,743,744],"/projects/crateos/home-dark.jpg","/projects/crateos/home.jpg","/projects/crateos/recall.jpg","/projects/crateos/recall-dark.jpg",false,"/projects/portfolio-refresh","2025-05-01T00:00:00.000Z",{"description":735},{"loc":746,"lastmod":750,"changefreq":751,"priority":752},"2025-05-18","monthly",0.8,"published","projects/1.portfolio-refresh","Gotta go fast",[757,698,718,713,723,758],"VueJS","Git","/projects/portfolio/thumb.webp","QiGZjUMDeFEax3ll1HamWS6r0UfyztBOjGdzkqk-VkQ",{"id":762,"title":763,"additionalTags":764,"body":765,"description":856,"excerpt":736,"extension":737,"featured":738,"meta":857,"name":775,"navigation":738,"openSource":745,"path":859,"projectDate":860,"seo":861,"sitemap":862,"status":753,"stem":863,"subtitle":864,"tags":865,"thumbnail":870,"__hash__":871},"projects/projects/2.crateos-recalls.md","Crateos Recalls",[],{"type":9,"value":766,"toc":854},[767,781,786,789,795,798,850],[16,768,769,776,777,140],{},[770,771,775],"a",{"href":772,"rel":773},"https://crateos.com",[774],"nofollow","CrateOS Recalls"," is a web application that\nI started to push myself, get out of my comfort zone and learn new technologies along the way.\nTutorials and documentation are great but I feel I learn best by ",[778,779,780],"em",{},"building",[782,783],"problem-solution",{"problem":784,"solution":785},"The recall process is often confusing, time consuming, and parents are too busy to dedicate the time & effort.","Make the recall discovery process easier and enable tailored recall alerts on a per-company basis.",[16,787,788],{},"The result is a Solo-SaaS project and the culmination of my experience in designing and developing web applications.",[790,791],"player",{"posterDesc":792,"posterSrc":793,"src":794},"A brief walkthrough of the CrateOS Recalls app.","https://www.crateos.com/images/demo-poster.gif","https://www.crateos.com/media/crateos-recalls-promo-720.mp4",[796,797,676],"h4",{"id":675},[678,799,800,809],{},[681,801,802],{},[684,803,804,806],{},[687,805,689],{},[687,807,808],{},"Backend",[691,810,811,818,826,834,842],{},[684,812,813,815],{},[696,814,703],{},[696,816,817],{},"ExpressJS",[684,819,820,823],{},[696,821,822],{},"Composition API",[696,824,825],{},"Loopback",[684,827,828,831],{},[696,829,830],{},"Pinia",[696,832,833],{},"PostgreSQL",[684,835,836,839],{},[696,837,838],{},"VueUse",[696,840,841],{},"ElasticSearch",[684,843,844,847],{},[696,845,846],{},"Bulma / Buefy",[696,848,849],{},"NodeJS",[851,852],"image-carousel",{":items":853},"[\"/projects/crateos/home-dark.jpg\",\"/projects/crateos/home.jpg\",\"/projects/crateos/recall.jpg\", \"/projects/crateos/recall-dark.jpg\"]",{"title":87,"searchDepth":113,"depth":113,"links":855},[],"Tailored CPSC product recalls for parents & busy people.",{"url":772,"items":858},[741,742,743,744],"/projects/crateos-recalls","2025-01-01T00:00:00.000Z",{"description":856},{"loc":859,"lastmod":750,"changefreq":751,"priority":752},"projects/2.crateos-recalls","Solo Founder + Full Stack + Design  + Branding",[757,866,867,723,868,689,808,869,758],"Bulma","SCSS","Postgres","PWA","/projects/crateos/thumb.webp","ub7Vj1IlE8DRDd4oU1kvD_1eLt2yddpi80dvH8bCmaY",{"id":873,"title":874,"additionalTags":875,"body":879,"description":1099,"excerpt":736,"extension":737,"featured":745,"meta":1100,"name":1101,"navigation":738,"openSource":745,"path":1102,"projectDate":1103,"seo":1104,"sitemap":1105,"status":87,"stem":1106,"subtitle":1107,"tags":1108,"thumbnail":1114,"__hash__":1115},"projects/projects/4.headlight.md","Headlight",[876,877,878],"typescript","testing","leadership",{"type":9,"value":880,"toc":1093},[881,889,900,905,908,913,917,927,930,934,937,1019,1021,1090],[16,882,883,888],{},[770,884,887],{"href":885,"rel":886},"https://headlight.com",[774],"HeadLight"," is a suite of advanced digital construction management applications.",[16,890,891,892,895,896,899],{},"For over 9 years at HeadLight (previously Pavia Systems) my involvement included ",[31,893,894],{},"UI/UX design"," for the native iOS application\nand leading the ",[31,897,898],{},"front-end development"," for the HeadLight Suite of web applications.",[901,902,904],"h3",{"id":903},"wireframe-to-final-product","Wireframe to Final Product",[16,906,907],{},"I was involved from the very beginning with designing mockups for the native IOS app and through to building & shipping web applications.",[909,910],"app-before-after",{"after":911,"before":912},"/projects/headlight/after.webp","/projects/headlight/before.webp",[901,914,916],{"id":915},"measuring-success","Measuring Success",[16,918,919,920,923,924,140],{},"The FieldBook apps would enable field personnel to capture ",[31,921,922],{},"millions of Observations"," across ",[31,925,926],{},"tens of thousands of construction projects",[16,928,929],{},"While the native iOS app was used primarily used for capturing in the field.\nThe web app which had feature-parity and was specifically geared for accessing project data by office personnel.",[901,931,933],{"id":932},"from-app-to-comprehensive-suite","From App to Comprehensive Suite",[16,935,936],{},"Moving to a shared code architecture, which AngularJS's module system was very well suited for,\nenabled us to quickly build and ship a entire suite specialized applications covering many aspects of e-construction.",[678,938,939,949],{},[681,940,941],{},[684,942,943,946],{},[687,944,945],{},"AngularJS Apps",[687,947,948],{},"VueJS Apps",[691,950,951,959,967,975,983,991,998,1005,1012],{},[684,952,953,956],{},[696,954,955],{},"FieldBook",[696,957,958],{},"Contract Admin",[684,960,961,964],{},[696,962,963],{},"Tracker",[696,965,966],{},"SamplePlan v2",[684,968,969,972],{},[696,970,971],{},"Portal",[696,973,974],{},"Materials v2",[684,976,977,980],{},[696,978,979],{},"Vault",[696,981,982],{},"Dashboards",[684,984,985,988],{},[696,986,987],{},"SamplePlan",[696,989,990],{},"Covid-19 Safety",[684,992,993,996],{},[696,994,995],{},"Profile Mgmt",[696,997],{},[684,999,1000,1003],{},[696,1001,1002],{},"Customer Mgmt",[696,1004],{},[684,1006,1007,1010],{},[696,1008,1009],{},"Project Mgmt",[696,1011],{},[684,1013,1014,1017],{},[696,1015,1016],{},"Materials",[696,1018],{},[901,1020,676],{"id":675},[678,1022,1023,1032],{},[681,1024,1025],{},[684,1026,1027,1029],{},[687,1028,689],{},[687,1030,1031],{},"Testing",[691,1033,1034,1042,1049,1057,1064,1070,1077,1084],{},[684,1035,1036,1039],{},[696,1037,1038],{},"AngularJS",[696,1040,1041],{},"Mocha",[684,1043,1044,1046],{},[696,1045,757],{},[696,1047,1048],{},"Jest",[684,1050,1051,1054],{},[696,1052,1053],{},"Bootstrap",[696,1055,1056],{},"Chai",[684,1058,1059,1061],{},[696,1060,758],{},[696,1062,1063],{},"Karma",[684,1065,1066,1068],{},[696,1067,867],{},[696,1069],{},[684,1071,1072,1075],{},[696,1073,1074],{},"Gulp",[696,1076],{},[684,1078,1079,1082],{},[696,1080,1081],{},"Grunt",[696,1083],{},[684,1085,1086,1088],{},[696,1087,723],{},[696,1089],{},[851,1091],{":items":1092},"[\"/projects/headlight/hl-01.png\",\"/projects/headlight/hl-02.png\",\"/projects/headlight/hl-03.png\"]",{"title":87,"searchDepth":113,"depth":113,"links":1094},[1095,1096,1097,1098],{"id":903,"depth":134,"text":904},{"id":915,"depth":134,"text":916},{"id":932,"depth":134,"text":933},{"id":675,"depth":134,"text":676},"Comprehensive suite of e-construction web applications.",{"url":885},"HeadLight Suite","/projects/headlight","2024-05-01T00:00:00.000Z",{"description":1099},{"loc":1102,"lastmod":750,"changefreq":751,"priority":752},"projects/4.headlight","UI/UX + Front-end development + Leadership",[1038,757,1053,867,723,1041,1063,1048,1109,758,1110,1111,1112,1113],"Parcel","Docker","Quasar","Capacitor","Cordova","/projects/headlight/thumb.webp","eDBDdG4_ei_jseZn1sPaTQwIw2cfdNm6e48QobdW2K8",{"id":1117,"title":1118,"additionalTags":1119,"body":1120,"description":1328,"excerpt":736,"extension":737,"featured":738,"meta":1329,"name":1330,"navigation":738,"openSource":745,"path":1331,"projectDate":1332,"seo":1333,"sitemap":1334,"status":753,"stem":1336,"subtitle":1337,"tags":1338,"thumbnail":1345,"__hash__":1346},"projects/projects/3.shooting-gallery-for-playdate.md","Shooting Gallery For Playdate",[],{"type":9,"value":1121,"toc":1321},[1122,1125,1129,1132,1138,1142,1151,1159,1182,1187,1191,1198,1213,1219,1228,1233,1240,1249,1254,1263,1272,1276,1279,1290,1297,1301,1311],[12,1123],{":stats":1124},"[{\"label\": \"release date\", \"value\": \"2023\"}, {\"label\": \"rating\", \"stars\":5 }, {\"label\": \"downloads\", \"value\": \"390+\"}, {\"label\": \"URL\", \"value\": \"itch.io\", \"url\": \"https://limitlis.itch.io/shooting-gallery\"}]",[901,1126,1128],{"id":1127},"step-right-up","Step right up!",[16,1130,1131],{},"Aim for the middle and test your mettle against a volley of tricky targets, diabolical ducks, and bewitched bombs as they float tauntingly across your playdate. Use PowerUps to your advantage to reach the top of the high score leaderboard.\nSet a high score and then hand the playdate to a friend to see if they can beat it.",[1133,1134,1135],"blockquote",{},[16,1136,1137],{},"\"incredibly high polish on the concept\" - LedBetter Games",[901,1139,1141],{"id":1140},"inspiration","Inspiration",[16,1143,1144,1145,1150],{},"From the day it was first announced I knew I wanted to make a game for the yellow ",[770,1146,1149],{"href":1147,"rel":1148},"https://play.date/",[774],"Playdate"," console and immediately pre-ordered one.",[16,1152,1153,1154,140],{},"Having never written a single line of Lua, I went from designing and building to self-publishing and releasing my first indie game on ",[770,1155,1158],{"href":1156,"rel":1157},"https://limitlis.itch.io/shooting-gallery",[774],"itch.io",[1160,1161,1166],"div",{"className":1162},[1163,1164,1165],"h-auto","w-auto","aspect-3-2",[16,1167,1168],{},[1169,1170],"img",{"alt":1171,"className":1172,"src":1180,"width":1181},"Gameplay",[1173,1174,1175,1176,1177,1178,1165,1179],"not-prose","rounded","h-48","w-full","md:h-full","md:h-48","object-contain","/projects/playdate/gameplay.gif",400,[1133,1183,1184],{},[16,1185,1186],{},"\"I like the duck game\" – My kids",[901,1188,1190],{"id":1189},"gameplay-mechanics","Gameplay Mechanics",[16,1192,1193],{},[770,1194,1197],{"href":87,"className":1195},[1196],"text-lg","PowerUps",[16,1199,1200,1211],{},[1169,1201],{"alt":1202,"className":1203,"src":1208,"width":1209,"style":1210},"Time Bonus",[1204,1205,1206,1207],"inline-flex","p-1","object-cover","pointer-none","/projects/playdate/time-bonus.gif",30,"margin: 0; margin-right: 10px; zoom: 1.5; background-color: #b1aea7; aspect-ratio: 1; width: 40px;",[31,1212,1202],{},[1214,1215,1216],"ul",{},[28,1217,1218],{},"Adds seconds to the clock to extend your current game.",[16,1220,1221,1225],{},[1169,1222],{"alt":1202,"className":1223,"src":1224,"width":1209,"style":1210},[1204,1205,1206,1207],"/projects/playdate/phantom-ammo.gif",[31,1226,1227],{},"Phantom Ammo",[1214,1229,1230],{},[28,1231,1232],{},"Shoot to stop at a random number and that amount of phantom ammo will be added without a reloading or resetting your hit streak.",[1133,1234,1235],{},[16,1236,1237],{},[778,1238,1239],{},"Reloading will be prevented until all phantom rounds are spent.",[16,1241,1242,1246],{},[1169,1243],{"alt":1202,"className":1244,"src":1245,"width":1209,"style":1210},[1204,1205,1206,1207],"/projects/playdate/point-bomb.png",[31,1247,1248],{},"Point Bombs",[1214,1250,1251],{},[28,1252,1253],{},"Shoot one and a bomb card will appear in your hit streak. Clear the card before the reload counter reaches 0 and receive the points.\nOtherwise those points will be removed from your current score.",[16,1255,1256,1261],{},[1169,1257],{"alt":1258,"className":1259,"src":1260,"width":1209,"style":1210},"Shiny Targets",[1204,1205,1206,1207],"/projects/playdate/shiny-target.webp",[31,1262,1258],{},[1214,1264,1265],{},[28,1266,1267,1268,1271],{},"Shiny targets will ",[31,1269,1270],{},"2X"," the score for the first three hits, being worth 2, 4, 6, 8 or 10 depending on your accuracy.",[901,1273,1275],{"id":1274},"development-challenges","Development Challenges",[16,1277,1278],{},"Getting the duck's movement just right was pretty challenging early on while I was still figuring out the SDK. I had a general idea of how I wanted the movement to be\nbut most importantly it had to feel mechanical — as if driven by gears. The SDK has built in support for making arcs but getting the random\nmovement took some math to get just right.",[16,1280,1281,1282,1285,1286,1289],{},"Here's a small diagram I made to help me figure out where to place the next arc based on a random ",[31,1283,1284],{},"radius","\nand the duck's current ",[31,1287,1288],{},"X"," position.",[16,1291,1292],{},[1169,1293],{"alt":1294,"className":1295,"src":1296,"width":1181},"Arc Math",[1176],"/projects/playdate/arcmath.webp",[901,1298,1300],{"id":1299},"nerdy-stats","Nerdy Stats",[16,1302,1303,1304,1310],{},"For source control I set up a local ",[770,1305,1309],{"href":1306,"rel":1307,"target":1308},"https://about.gitea.com/",[774],"_blank","Gittea"," instance on my home Network Attached Storage (NAS).",[1312,1313,1314],"client-only",{},[1315,1316,1320],"iframe",{"frameBorder":541,"src":1317,"width":1318,"height":1319},"https://itch.io/embed/1837225?border_width=2&bg_color=18181c&fg_color=a3a5aa&link_color=1fcd9f&border_color=26262f",554,169,"\u003Ca href=\"https://limitlis.itch.io/shooting-gallery\">SHOOTING GALLERY for Playdate by limitlis\u003C/a>",{"title":87,"searchDepth":113,"depth":113,"links":1322},[1323,1324,1325,1326,1327],{"id":1127,"depth":134,"text":1128},{"id":1140,"depth":134,"text":1141},{"id":1189,"depth":134,"text":1190},{"id":1274,"depth":134,"text":1275},{"id":1299,"depth":134,"text":1300},"A carnival inspired game for the Playdate console.",{"url":1156},"Shooting Gallery","/projects/shooting-gallery-for-playdate","2023-10-01T00:00:00.000Z",{"description":1328},{"loc":1331,"lastmod":1335,"changefreq":751,"priority":752},"2026-02-22","projects/3.shooting-gallery-for-playdate","Game Design & Development",[1339,1340,1341,1342,1343,1344,758],"Lua","Playdate SDK","Graphic Design","SFX","Game design","Game Development","/projects/playdate/thumb.webp","VNfjA2HH2oLPUMOgxzNMTUpy8Ekr-nOl_rU5F6jh6Ug",{"id":1348,"title":1349,"additionalTags":1350,"body":1351,"description":1399,"excerpt":736,"extension":737,"featured":745,"meta":1400,"name":1401,"navigation":738,"openSource":745,"path":1402,"projectDate":1403,"seo":1404,"sitemap":1405,"status":1406,"stem":1407,"subtitle":1408,"tags":1409,"thumbnail":1415,"__hash__":1416},"projects/projects/5.enamel-pin.md","Enamel Pin",[],{"type":9,"value":1352,"toc":1394},[1353,1356,1360,1363,1369,1373,1376,1379,1381,1384,1391],[12,1354],{":stats":1355},"[{\"label\": \"Farthest Backer\", \"value\": \"> 8,000 miles\"}]",[20,1357,1359],{"id":1358},"overview","Overview",[16,1361,1362],{},"\"Don't @ me bro\" is an enamel pin that I designed and was meant as a tongue-in-cheek take on how disruptive notifications can be when\nworking from home became a reality for many during the Covid pandemic.",[16,1364,1365],{},[1169,1366],{"alt":1367,"src":1368},"Enamel pin and packaging","/projects/enamel-pin/pin-01.jpg",[20,1370,1372],{"id":1371},"challenges","Challenges",[16,1374,1375],{},"By far the biggest issue that came up was that my pin manufacturer made a mistake with the color of the phosphorescence.\nUnfortunately this was't made apparent until the pins arrived at my door.",[16,1377,1378],{},"I had to approach my backers with the bad news, apologized for the error and offered refunds but everyone was still excited even with the standard green glow color.",[20,1380,50],{"id":49},[16,1382,1383],{},"From Seattle to backers across the world with the farthest pin going over 8,000 miles away to Singapore.\nOverall the campaign was a success and I learned a lot along the way.",[16,1385,1386],{},[1169,1387],{"alt":1388,"src":1389,"className":1390},"Pins shipped across the world","/projects/enamel-pin/map.webp",[1176],[851,1392],{":items":1393},"[ \"/projects/enamel-pin/pin-02.jpg\", \"/projects/enamel-pin/pin-04.jpg\", \"/projects/enamel-pin/pin-03.gif\", \"/projects/enamel-pin/pin-05.webp\",\"/projects/enamel-pin/pin-07.webp\"]",{"title":87,"searchDepth":113,"depth":113,"links":1395},[1396,1397,1398],{"id":1358,"depth":113,"text":1359},{"id":1371,"depth":113,"text":1372},{"id":49,"depth":113,"text":50},"Glow-in-the-dark enamel pin design",{},"Don't @ Me - Enamel Pin","/projects/enamel-pin","2020-07-01T00:00:00.000Z",{"description":1399},{"loc":746,"lastmod":750,"changefreq":751,"priority":752},"draft","projects/5.enamel-pin","Graphic design + illustration + crowd funding",[1410,1341,1411,1412,1413,1414],"Illustration","Motion Graphics","Crowdfunding","Order fulfillment","Kickstarter","/projects/enamel-pin/thumb.webp","BFM3b-_dmK0NL286fxVndivtPFliUGfXAnObLpcyqfc",{"id":1418,"title":1419,"additionalTags":1420,"body":1421,"description":1448,"excerpt":736,"extension":737,"featured":745,"meta":1449,"name":1419,"navigation":738,"openSource":745,"path":1450,"projectDate":1451,"seo":1452,"sitemap":1453,"status":1406,"stem":1454,"subtitle":1455,"tags":1456,"thumbnail":1459,"__hash__":1460},"projects/projects/3.stohke.md","Stohke",[],{"type":9,"value":1422,"toc":1446},[1423,1426,1433,1436,1439,1443],[16,1424,1425],{},"Stohke was a social network whose aim was to bring the world's best brands, athletes and causes to your fingertips.",[16,1427,1428],{},[1169,1429],{"alt":1430,"className":1431,"src":1432},"'Stohke mobile app redesign'",[1173,1176],"/projects/stohke/app-promo-images.webp",[16,1434,1435],{},"I started contracting on my free time and pitching in on their existing AngularJS application.",[16,1437,1438],{},"I would eventually lead the UI/UX design and front-end development that would transition Stohke from a simple app into a comprehensive social platform with hybrid iOS and Android apps.",[909,1440],{"after":1441,"before":1442},"/projects/stohke/after.webp","/projects/stohke/before.webp",[851,1444],{":items":1445},"[\"/projects/stohke/stohke-01.jpg\",\"/projects/stohke/stohke-02.jpg\",\"/projects/stohke/stohke-03.jpg\",\"/projects/stohke/stohke-04.jpg\"]",{"title":87,"searchDepth":113,"depth":113,"links":1447},[],"An social network for outdoor & action sports enthusiasts.",{"wip":738},"/projects/stohke","2015-12-01T00:00:00.000Z",{"description":1448},{"loc":1450,"lastmod":750,"changefreq":751,"priority":752},"projects/3.stohke","UI/UX + front-end development",[1038,1053,867,1341,1457,1411,1458,758],"UI/UX Design","Wireframes","/projects/stohke/thumb.webp","oy0RbuUQeC7U95yHCD9bmcc1w14vJ9akBZHEysWuto8",{"id":1462,"title":1463,"additionalTags":1464,"body":1465,"description":1528,"excerpt":736,"extension":737,"featured":745,"meta":1529,"name":1473,"navigation":738,"openSource":745,"path":1530,"projectDate":1531,"seo":1532,"sitemap":1533,"status":87,"stem":1534,"subtitle":1455,"tags":1535,"thumbnail":1536,"__hash__":1537},"projects/projects/4.classflow.md","Classflow",[],{"type":9,"value":1466,"toc":1525},[1467,1475,1478],[16,1468,1469,1474],{},[770,1470,1473],{"href":1471,"rel":1472,"target":1308},"https://www.classflow.com",[774],"ClassFlow"," by Promethean (sunset late 2023) was a cloud-based teaching and learning platform that makes lesson planning easier and lesson delivery more dynamic.",[16,1476,1477],{},"Complete with a specialized view for students, the two work in unison to provide a robust solution for lesson planning, delivering as well as student interaction and feedback.",[851,1479,1481,1483],{":items":1480},"[\"/projects/classflow/classflow-01.png\",\"/projects/classflow/classflow-02.png\",\"/projects/classflow/classflow-03.png\",\"/projects/classflow/classflow-04.png\",\"/projects/classflow/classflow-05.png\"]",[901,1482,676],{"id":675},[678,1484,1485,1491],{},[681,1486,1487],{},[684,1488,1489],{},[687,1490,689],{},[691,1492,1493,1498,1503,1507,1512,1517,1521],{},[684,1494,1495],{},[696,1496,1497],{},"KendoUI",[684,1499,1500],{},[696,1501,1502],{},"JS",[684,1504,1505],{},[696,1506,1053],{},[684,1508,1509],{},[696,1510,1511],{},"jQuery",[684,1513,1514],{},[696,1515,1516],{},"LESS",[684,1518,1519],{},[696,1520,1074],{},[684,1522,1523],{},[696,1524,1081],{},{"title":87,"searchDepth":113,"depth":113,"links":1526},[1527],{"id":675,"depth":134,"text":676},"Cloud-based classroom lesson delivery software",{"wip":738},"/projects/classflow","2014-10-01T00:00:00.000Z",{"description":1528},{"loc":1530,"lastmod":750,"changefreq":751,"priority":752},"projects/4.classflow",[1497,1053,1516,1341,1457,758],"/projects/classflow/thumb.webp","AomZ1FtH5MSAkEzxtF6a0gLHoA6EaoYiF59SD1Es5II",{"id":1539,"title":1540,"additionalTags":1541,"body":1542,"description":1608,"excerpt":736,"extension":737,"featured":745,"meta":1609,"name":1540,"navigation":738,"openSource":745,"path":1610,"projectDate":1611,"seo":1612,"sitemap":1613,"status":736,"stem":1614,"subtitle":1615,"tags":1616,"thumbnail":1618,"__hash__":1619},"projects/projects/6.sushi-stacks.md","Sushi Stacks",[],{"type":9,"value":1543,"toc":1605},[1544,1547,1554,1557,1561,1577,1582,1585,1591,1594],[12,1545],{":stats":1546},"[{\"label\": \"release date\", \"value\": \"2013\"}]",[16,1548,1549],{},[1169,1550],{"alt":1551,"src":1552,"className":1553},"Join the Sushi Revolution","/projects/sushi/header.jpg",[1176],[16,1555,1556],{},"I developed Sushi Stacks as fun way to tally up your meal total made specifically for use at conveyor-belt sushi restaurants.",[901,1558,1560],{"id":1559},"a-dish-best-served-cold","A dish best served cold",[16,1562,1563,1564,1566,1567,1566,1570,1572,1573,1576],{},"First of its kind, when released it was the only app that works for practically any conveyor-belt sushi restaurant and retains the experience of stacking your plates and calculates as you go.\nThis hybrid app was made with ",[31,1565,1038],{},", ",[31,1568,1569],{},"jQuery Mobile",[31,1571,1113],{}," and used ",[31,1574,1575],{},"Firebase"," as a realtime datastore. Released on both Apple App Store and Google Play Store.",[851,1578],{":items":1579,"className":1580},"[\"/projects/sushi/ss-add.gif\",\"/projects/sushi/ss-remove.gif\",\"/projects/sushi/ss-summary.png\", \"/projects/sushi/ss-main.png\", \"/projects/sushi/ss-browse.png\"]",[1581],"max-w-md",[16,1583,1584],{},"I would love to someday dust off and revisit this project as it was a lot of fun.\nI even started designing more plate types with only CSS that I could include like drinks and bowls. Though these days with SVG being better supported that's probably a better choice.",[16,1586,1587],{},[1169,1588],{"alt":1589,"src":1590},"More stuff to stack","/projects/sushi/sushi-stacks-new-dish-types.jpg",[16,1592,1593],{},"Check out this martini glass!",[1312,1595,1596],{},[1315,1597,1604],{"height":1598,"style":1599,"scrolling":1600,"title":1601,"src":1602,"frameBorder":1600,"loading":1603,"allowTransparency":74,"allowFullScreen":74},300,"width: 100%;","no","CSS Martini Glass","https://codepen.io/limitlis/embed/OJXNdz?default-tab=html%2Cresult&theme-id=dark","lazy","\n  See the Pen \u003Ca href=\"https://codepen.io/limitlis/pen/OJXNdz\">\n  CSS Martini Glass\u003C/a> by Cesar Vargas (\u003Ca href=\"https://codepen.io/limitlis\">@limitlis\u003C/a>)\n  on \u003Ca href=\"https://codepen.io\">CodePen\u003C/a>.\n",{"title":87,"searchDepth":113,"depth":113,"links":1606},[1607],{"id":1559,"depth":134,"text":1560},"A fun app made for conveyor-belt sushi lovers.",{},"/projects/sushi-stacks","2013-12-01T00:00:00.000Z",{"description":1608},{"loc":1610,"lastmod":750,"changefreq":751,"priority":752},"projects/6.sushi-stacks","Web Development + Hybrid App development",[1038,1341,1575,1617,1113,1511],"Hybrid App","/projects/sushi/thumb.webp","qrGf_9CZvyX7twAXJhQQCtCnu6KT8vyU-W6BNeL3oqo",1778072417573]