[{"data":1,"prerenderedAt":325},["ShallowReactive",2],{"project-site":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"name":8,"year":10,"topics":11,"heroImage":14,"archived":6,"languages":17,"homepage":24,"githubUrl":25,"tools":26,"body":32,"_type":319,"_id":320,"_source":321,"_file":322,"_stem":323,"_extension":324},"/projects/site","projects",false,"","site","Statically generated portfolio and blog 🚀",2022,[12,13],"shaders","static site generation",{"remote":15,"local":16},"https://raw.githubusercontent.com/ryanachten/site/main/docs/site-landing.gif","hero-images/site.webp",[18,19,20,21,22,23],"Vue","TypeScript","JavaScript","GLSL","HCL","SCSS","https://ryanachten.com/","https://github.com/ryanachten/site",[27,28,29,30,31],"amplify","nodejs","nuxtjs","terraform","three-js",{"type":33,"children":34,"toc":307},"root",[35,42,54,61,69,74,79,86,117,123,164,170,196,202,212,230,238,244,254,260,265,277,282],{"type":36,"tag":37,"props":38,"children":39},"element","h1",{"id":8},[40],{"type":41,"value":8},"text",{"type":36,"tag":43,"props":44,"children":45},"p",{},[46,52],{"type":36,"tag":47,"props":48,"children":51},"img",{"alt":49,"src":50},"landing page","https://github.com/ryanachten/site/raw/main/docs/site-landing.gif",[],{"type":41,"value":53},"\nStatically generated site using a Node.js data ingestion pipeline for consuming markdown and images stored in GitHub. Site also features some sweet, sweet shaders using GLSL and Three.js.",{"type":36,"tag":55,"props":56,"children":58},"h2",{"id":57},"data-ingestion",[59],{"type":41,"value":60},"Data Ingestion",{"type":36,"tag":43,"props":62,"children":63},{},[64],{"type":36,"tag":47,"props":65,"children":68},{"alt":66,"src":67},"data ingestion pipeline","https://github.com/ryanachten/site/raw/main/docs/data-sync.png",[],{"type":36,"tag":43,"props":70,"children":71},{},[72],{"type":41,"value":73},"One of the key problems with my old website was that it was cumbersome to maintain. It required a lot of content duplicated from what I was already writing in GitHub, as well as manual image processing steps.",{"type":36,"tag":43,"props":75,"children":76},{},[77],{"type":41,"value":78},"To solve all of this, I wanted to make the new website as automated as possible. Hence the need for a data ingestion pipeline. The pipeline does the following:",{"type":36,"tag":80,"props":81,"children":83},"h3",{"id":82},"metadata",[84],{"type":41,"value":85},"Metadata",{"type":36,"tag":87,"props":88,"children":89},"ul",{},[90,105],{"type":36,"tag":91,"props":92,"children":93},"li",{},[94,96,103],{"type":41,"value":95},"Given a list of projects (via ",{"type":36,"tag":97,"props":98,"children":100},"code",{"className":99},[],[101],{"type":41,"value":102},"index.yml",{"type":41,"value":104},"), the pipeline will retrieve repository metadata from GitHub such as project languages, topics and archive status",{"type":36,"tag":91,"props":106,"children":107},{},[108,110,115],{"type":41,"value":109},"This metadata is written back to the ",{"type":36,"tag":97,"props":111,"children":113},{"className":112},[],[114],{"type":41,"value":102},{"type":41,"value":116}," file and in each project markdown file for Nuxt functionality",{"type":36,"tag":80,"props":118,"children":120},{"id":119},"images",[121],{"type":41,"value":122},"Images",{"type":36,"tag":87,"props":124,"children":125},{},[126,138],{"type":36,"tag":91,"props":127,"children":128},{},[129,131,136],{"type":41,"value":130},"Hero images defined in ",{"type":36,"tag":97,"props":132,"children":134},{"className":133},[],[135],{"type":41,"value":102},{"type":41,"value":137}," are downloaded locally",{"type":36,"tag":91,"props":139,"children":140},{},[141,143],{"type":41,"value":142},"Image transformations are applied\n",{"type":36,"tag":87,"props":144,"children":145},{},[146,151],{"type":36,"tag":91,"props":147,"children":148},{},[149],{"type":41,"value":150},"Crop image to specified aspect ratio for easier consistency in WebGL",{"type":36,"tag":91,"props":152,"children":153},{},[154,156,162],{"type":41,"value":155},"Convert to ",{"type":36,"tag":97,"props":157,"children":159},{"className":158},[],[160],{"type":41,"value":161},".webp",{"type":41,"value":163}," format for SEO purposes",{"type":36,"tag":80,"props":165,"children":167},{"id":166},"readme",[168],{"type":41,"value":169},"ReadMe",{"type":36,"tag":87,"props":171,"children":172},{},[173,178],{"type":36,"tag":91,"props":174,"children":175},{},[176],{"type":41,"value":177},"Retrieve the main ReadMe file for each project",{"type":36,"tag":91,"props":179,"children":180},{},[181,183],{"type":41,"value":182},"It will then perform a number of post-processing tasks\n",{"type":36,"tag":87,"props":184,"children":185},{},[186,191],{"type":36,"tag":91,"props":187,"children":188},{},[189],{"type":41,"value":190},"replacing local repository references and",{"type":36,"tag":91,"props":192,"children":193},{},[194],{"type":41,"value":195},"adding the metadata retrieved earlier for Nuxt page functionality",{"type":36,"tag":55,"props":197,"children":199},{"id":198},"shader-pipeline",[200],{"type":41,"value":201},"Shader Pipeline",{"type":36,"tag":43,"props":203,"children":204},{},[205,210],{"type":36,"tag":47,"props":206,"children":209},{"alt":207,"src":208},"Shader pipeline","https://github.com/ryanachten/site/raw/main/docs/shader-pipeline.png",[],{"type":41,"value":211},"\nThe pipeline used by shaders in this site are fairly simple",{"type":36,"tag":87,"props":213,"children":214},{},[215,220,225],{"type":36,"tag":91,"props":216,"children":217},{},[218],{"type":41,"value":219},"Images are loaded from Nuxt static content and used to generated Three.js textures.",{"type":36,"tag":91,"props":221,"children":222},{},[223],{"type":41,"value":224},"vertex and fragment shader files are loaded using Webpack",{"type":36,"tag":91,"props":226,"children":227},{},[228],{"type":41,"value":229},"textures and shader files are combined to create a Three.js shader material which is applied to a plane to be rendered",{"type":36,"tag":43,"props":231,"children":232},{},[233],{"type":36,"tag":47,"props":234,"children":237},{"alt":235,"src":236},"projects page","https://github.com/ryanachten/site/raw/main/docs/site-projects.gif",[],{"type":36,"tag":55,"props":239,"children":241},{"id":240},"infrastructure",[242],{"type":41,"value":243},"Infrastructure",{"type":36,"tag":43,"props":245,"children":246},{},[247,252],{"type":36,"tag":47,"props":248,"children":251},{"alt":249,"src":250},"Infrastructure pipeline","https://github.com/ryanachten/site/raw/main/docs/infrastructure.png",[],{"type":41,"value":253},"\nWebsite is deployed using AWS Amplify, with infrastructure managed using Terraform. Because the site is statically generated, we only need to use an frontend Amplify build for this project.",{"type":36,"tag":55,"props":255,"children":257},{"id":256},"development",[258],{"type":41,"value":259},"Development",{"type":36,"tag":43,"props":261,"children":262},{},[263],{"type":41,"value":264},"General site development uses common Nuxt commands (requires Node v16).",{"type":36,"tag":266,"props":267,"children":272},"pre",{"className":268,"code":270,"language":271,"meta":7},[269],"language-bash","# install dependencies\n$ yarn install\n\n# serve with hot reload at localhost:8000\n$ yarn dev\n\n# build for production and launch server\n$ yarn build\n$ yarn start\n\n# generate static project\n$ yarn generate\n","bash",[273],{"type":36,"tag":97,"props":274,"children":275},{"__ignoreMap":7},[276],{"type":41,"value":270},{"type":36,"tag":43,"props":278,"children":279},{},[280],{"type":41,"value":281},"Guides for specific aspects of site development can be found below:",{"type":36,"tag":87,"props":283,"children":284},{},[285,297],{"type":36,"tag":91,"props":286,"children":287},{},[288],{"type":36,"tag":289,"props":290,"children":294},"a",{"href":291,"rel":292},"https://github.com/ryanachten/site/raw/main/infra/README.md",[293],"nofollow",[295],{"type":41,"value":296},"Infrastructure development",{"type":36,"tag":91,"props":298,"children":299},{},[300],{"type":36,"tag":289,"props":301,"children":304},{"href":302,"rel":303},"https://github.com/ryanachten/site/raw/main/sync/README.md",[293],[305],{"type":41,"value":306},"Sync pipeline development",{"title":7,"searchDepth":308,"depth":308,"links":309},2,[310,316,317,318],{"id":57,"depth":308,"text":60,"children":311},[312,314,315],{"id":82,"depth":313,"text":85},3,{"id":119,"depth":313,"text":122},{"id":166,"depth":313,"text":169},{"id":198,"depth":308,"text":201},{"id":240,"depth":308,"text":243},{"id":256,"depth":308,"text":259},"markdown","content:projects:site.md","content","projects/site.md","projects/site","md",1776573205289]