Skip to main content

Projects Data Guide (js/projects-data.js)

This guide explains how to add new content to js/projects-data.js, including every property currently supported by the renderer in js/main.js.


Quick Start

  1. Open js/projects-data.js.
  2. Find the category you want to update inside portfolioData.categories.
  3. Add a new project object to that category's projects array.
  4. Save and refresh the site.

Data Structure Overview

The file exports one top-level object:

const portfolioData = {
socialLinks: [/* social link objects */],
categories: [/* category objects */]
};

Top-level properties

PropertyTypeRequiredWhat it does
socialLinksArray<SocialLink>YesRenders the social pills at the top of the page.
categoriesArray<Category>YesRenders each project section and all project tiles.

Each social link item supports:

PropertyTypeRequiredWhat it does
labelstringYesVisible text shown in the social pill.
urlstringYes (recommended)Link destination. If missing, renderer falls back to #.
iconstringYesFont Awesome class string used in <i class="..."></i>.
colorClassstringNoTile color class (for example tile-tone-01).

Example

{
label: 'GitHub',
url: 'https://github.com/mythicalcuddles',
icon: 'fab fa-github',
colorClass: 'tile-tone-01'
}
  1. Open the socialLinks array in js/projects-data.js.
  2. Add a new object with label, url, and icon.
  3. Optionally add colorClass to control pill tone.
  4. Save and refresh.
socialLinks: [
// existing links...
{
label: 'Mastodon',
url: 'https://mastodon.social/@yourname',
icon: 'fab fa-mastodon',
colorClass: 'tile-tone-02'
}
]

categories Reference

Each category object supports:

PropertyTypeRequiredWhat it does
titlestringYesSection heading shown above that category's tiles.
projectsArray<Project>YesList of tiles rendered in that section.

Example

{
title: 'Personal Projects',
projects: [
/* one or more project objects */
]
}

How to add a new category

  1. Open the categories array in js/projects-data.js.
  2. Add a new object with:
    • title (required)
    • projects (required, can start empty)
  3. Add one or more project objects to that category.
categories: [
// existing categories...
{
title: 'Open Source',
projects: [
{
title: 'Example Tool',
url: 'https://github.com/org/example-tool',
colorClass: 'tile-tone-08',
description: ['CLI helper for day-to-day workflows.']
}
]
}
]

Tip: For intro/notice rows in a category, create a first project tile with fullRow: true and a short description.


Project Reference

A project object supports the following properties:

PropertyTypeRequiredWhat it does
titlestringYesProject/tile title.
urlstring | nullNoIf provided, title area becomes a clickable link opening in a new tab. If missing or null, the tile header is non-clickable.
colorClassstringNoAdds tile color class to the project button/header.
fullRowbooleanNoIf true, tile uses full-row style (fullRow class). Great for notices or section intros.
languagesstring[]NoRendered as a bullet-separated line (HTML • CSS • JavaScript).
datestringNoRendered in a <time> element. Valid date strings are formatted to DD-MM-YYYY; invalid formats are shown as-is.
headerNotestringNoInjected as HTML under header metadata (supports inline links/emojis).
contentArray<ContentBlock>NoRich blocks displayed before description paragraphs. Currently image blocks are supported.
descriptionstring[]NoEach entry renders as its own paragraph (<p>). HTML is allowed.
linksArray<LinkItem>NoRenders action row at the bottom of the tile. If omitted/empty, the link list is hidden.

Minimal project example

{
title: 'My New Project',
url: 'https://example.com',
colorClass: 'tile-tone-06',
description: [
'Short summary of the project.'
]
}
{
title: 'My Rich Project',
url: 'https://example.com',
colorClass: 'tile-tone-11',
fullRow: false,
languages: ['Unity3D', 'UdonSharp'],
date: '2026-02-13',
headerNote: '🚀 Released with community support!',
content: [
{ type: 'image', src: 'images/my-project.png', alt: 'My project preview' }
],
description: [
'Paragraph one.',
'Paragraph two with <strong>inline HTML</strong>.'
],
links: [
{ type: 'link', text: 'Source Code', url: 'https://github.com/org/repo' },
{ type: 'badge', src: 'https://img.shields.io/badge/status-active-brightgreen', alt: 'Status Active' },
{ type: 'text', text: 'Private repo' }
]
}

content Block Types

Currently supported by renderer:

Image block (type: 'image')

PropertyTypeRequiredWhat it does
type'image'YesEnables image rendering logic.
srcstringYesImage path/URL. Local files are typically under images/.
altstringNoAlt text for accessibility.

Rendered behavior:

  • The image is wrapped in a link to itself.
  • Clicking opens the image in a new tab.

Example:

content: [
{ type: 'image', src: 'images/vrchat_world.png', alt: 'VRChat world preview' }
]

The links array supports multiple item types.

PropertyTypeRequiredWhat it does
type'link'YesRenders a clickable button-style anchor.
textstringYesMain label text.
urlstringYes (recommended)Destination URL. Falls back to # if missing.
iconstringNoFont Awesome class for icon. Defaults to fas fa-link.
notestringNoSmall helper note shown inside the button.

Example:

{ type: 'link', text: 'Wiki', url: 'https://example.com/wiki', icon: 'fas fa-book', note: 'Updated weekly' }

2) Badge (type: 'badge')

PropertyTypeRequiredWhat it does
type'badge'YesRenders an image badge.
srcstringYesBadge image URL/path.
altstringNoAlt text for accessibility.
urlstringNoIf present, wraps badge in a clickable link.
textstringNoUsed as fallback for alt text when alt is missing.

Example:

{ type: 'badge', src: 'https://img.shields.io/badge/build-passing-brightgreen', alt: 'Build passing' }

3) Static text chip (type: 'text')

For type: 'text' (or any unknown type), renderer creates a non-clickable chip.

PropertyTypeRequiredWhat it does
type'text'RecommendedSignals static chip intent.
textstringYesChip label.

Example:

{ type: 'text', text: 'Not Maintained' }

How to Add a New Project (Step-by-Step)

  1. Pick a category in portfolioData.categories.
  2. Append a project object to that category's projects array.
  3. Set required fields first:
    • title
    • optional but recommended: url, colorClass, description
  4. Add extra metadata as needed:
    • languages, date, headerNote, fullRow
  5. Add richer content:
    • screenshots via content: [{ type: 'image', ... }]
    • call-to-action entries via links
  6. Save and verify in browser.

All Available Options (Cheat Sheet)

Use this as a quick checklist when editing js/projects-data.js.

Root object

  • socialLinks: SocialLink[]
  • categories: Category[]
  • label: string (display text)
  • url: string (destination; fallback # if missing)
  • icon: string (Font Awesome classes)
  • colorClass?: string (optional tone class)

Category

  • title: string (section heading)
  • projects: Project[] (tiles under this section)

Project

  • title: string
  • url?: string | null
  • colorClass?: string
  • fullRow?: boolean
  • languages?: string[]
  • date?: string
  • headerNote?: string (HTML allowed)
  • content?: ContentBlock[]
  • description?: string[] (HTML allowed)
  • links?: LinkItem[]

ContentBlock (currently only image)

  • type: 'image'
  • src: string
  • alt?: string

LinkItem types

  • type: 'link'
    • text: string
    • url?: string
    • icon?: string
    • note?: string
  • type: 'badge'
    • src: string
    • alt?: string
    • url?: string
    • text?: string (fallback alt)
  • type: 'text' (or any unknown type)
    • text: string

Conventions & Tips

  • Prefer existing tile-tone-* classes for visual consistency.
  • Use fullRow: true for notices/intro tiles, not regular projects.
  • Keep description as an array of short paragraphs for readable cards.
  • Use meaningful alt text for accessibility (avoid empty alt unless image is decorative).
  • Keep date formats consistent (YYYY-MM-DD is safest for automatic formatting).
  • Use type: 'text' link items for status labels like “Archived” or “Not Maintained”.

Common Pitfalls

  • Missing commas between objects/array items (breaks the whole script).
  • Invalid quote usage inside text (escape apostrophes or use double quotes where helpful).
  • Forgetting image files: if using local images/... paths, ensure the file exists in the repository.
  • Assuming unknown content types render: only content items with type: 'image' are currently supported.

Copy/Paste Starter Template

{
title: 'Project Name',
url: 'https://example.com',
colorClass: 'tile-tone-06',
languages: ['HTML', 'CSS', 'JavaScript'],
date: '2026-02-13',
headerNote: 'Optional short note',
content: [
{ type: 'image', src: 'images/example.png', alt: 'Example screenshot' }
],
description: [
'Paragraph one.',
'Paragraph two.'
],
links: [
{ type: 'link', text: 'Live Demo', url: 'https://example.com' },
{ type: 'link', text: 'Source Code', url: 'https://github.com/org/repo' },
{ type: 'text', text: 'Actively Maintained' }
]
}