gitbreathing
gitlabgitBreathing: A deterministic procedural contribution-art generator that transforms GitHub and GitLab activity into animated Demon Slayer-inspired breathing effects, with customizable SVG and GIF output.
clone
https://gitlab.com/bitzzdev/gitbreathing.gitstages:- renderrender-gitbreathing:stage: renderimage: node:22-bookwormrules:- if: '$CI_PIPELINE_SOURCE == "schedule"'- if: '$CI_PIPELINE_SOURCE == "web"'- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_MESSAGE !~ /^chore: update GitBreathing artwork$/'before_script:- apt-get update -qq && apt-get install -y -qq git- npm install --no-audit --no-fundscript: |set -euif [ -z "${GITLAB_TOKEN:-}" ]; thenecho "Set a masked GITLAB_TOKEN with API read and repository write access." >&2exit 1fiif [ -z "${CONTRIBUTIONS:-}" ]; thenUSERNAME=$(node -p "JSON.parse(require('fs').readFileSync('gitbreathing.json','utf8')).username")USER_ID=$(curl --fail-with-body -fsS --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --get --data-urlencode "username=${USERNAME}" "${CI_API_V4_URL}/users" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const a=JSON.parse(s);if(!a.length)process.exit(2);console.log(a[0].id)})")PAGE=1TOTAL=0AFTER=$(date -u -d '1 year ago' +%F)while :; doEVENTS=$(curl --fail-with-body -fsS --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --get --data-urlencode "after=${AFTER}" --data-urlencode "per_page=100" --data-urlencode "page=${PAGE}" "${CI_API_V4_URL}/users/${USER_ID}/events")COUNT=$(printf '%s' "$EVENTS" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>console.log(JSON.parse(s).length))")TOTAL=$((TOTAL + COUNT))[ "$COUNT" -lt 100 ] && breakPAGE=$((PAGE + 1))doneexport CONTRIBUTIONS="$TOTAL"echo "GitLab Events API returned ${TOTAL} activity events in the one-year window. This is an event-count approximation, not a canonical contribution-calendar total."fiif [ -n "${GH_TOKEN:-}" ]; thenUSERNAME=$(node -p "JSON.parse(require('fs').readFileSync('gitbreathing.json','utf8')).username")QUERY='query($login:String!){user(login:$login){login name bio location company websiteUrl avatarUrl twitterUsername email createdAt followers(first:1){totalCount} following(first:1){totalCount} repositories(first:100,privacy:PUBLIC,ownerAffiliations:OWNER,orderBy:{field:STARGAZERS,direction:DESC}){totalCount nodes{name url description stargazerCount forkCount primaryLanguage{name color}}} starredRepositories(first:1){totalCount} gists(first:1){totalCount} organizations(first:20){totalCount nodes{login name url}} socialAccounts(first:20){nodes{provider url}} pinnedItems(first:6,types:[REPOSITORY]){nodes{... on Repository{name url description stargazerCount forkCount primaryLanguage{name color}}}} contributionsCollection{totalCommitContributions totalIssueContributions totalPullRequestContributions totalPullRequestReviewContributions contributionCalendar{totalContributions weeks{contributionDays{date contributionCount color}}}}}}'BODY=$(jq -n --arg q "$QUERY" --arg u "$USERNAME" '{query:$q,variables:{login:$u}}')RESPONSE=$(curl --fail-with-body -fsS --header "Authorization: bearer $GH_TOKEN" --header 'Content-Type: application/json' --data "$BODY" https://api.github.com/graphql)printf '%s' "$RESPONSE" | jq -e '.data.user' >/dev/nullmkdir -p distprintf '%s' "$RESPONSE" | jq '{data:.data}' > dist/profile-data.jsonfinpm run rendernpm run render:profilegit config user.name 'GitBreathing CI'git config user.email 'gitbreathing-bot@users.noreply.gitlab.com'git add dist/slash.svg dist/slash.gif dist/slash.png dist/metadata.json dist/profile.svg dist/profile-data.jsonif ! git diff --cached --quiet; thengit commit -m "chore: update GitBreathing artwork"git push "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "HEAD:${CI_DEFAULT_BRANCH}"elseecho "No artwork changes."fi