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
- Open
js/projects-data.js. - Find the category you want to update inside
portfolioData.categories. - Add a new project object to that category's
projectsarray. - 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
| Property | Type | Required | What it does |
|---|---|---|---|
socialLinks | Array<SocialLink> | Yes | Renders the social pills at the top of the page. |
categories | Array<Category> | Yes | Renders each project section and all project tiles. |
socialLinks Reference
Each social link item supports:
| Property | Type | Required | What it does |
|---|---|---|---|
label | string | Yes | Visible text shown in the social pill. |
url | string | Yes (recommended) | Link destination. If missing, renderer falls back to #. |
icon | string | Yes | Font Awesome class string used in <i class="..."></i>. |
colorClass | string | No | Tile color class (for example tile-tone-01). |
Example
{
label: 'GitHub',
url: 'https://github.com/mythicalcuddles',
icon: 'fab fa-github',
colorClass: 'tile-tone-01'
}
How to add a new social link
- Open the
socialLinksarray injs/projects-data.js. - Add a new object with
label,url, andicon. - Optionally add
colorClassto control pill tone. - 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:
| Property | Type | Required | What it does |
|---|---|---|---|
title | string | Yes | Section heading shown above that category's tiles. |
projects | Array<Project> | Yes | List of tiles rendered in that section. |
Example
{
title: 'Personal Projects',
projects: [
/* one or more project objects */
]
}
How to add a new category
- Open the
categoriesarray injs/projects-data.js. - Add a new object with:
title(required)projects(required, can start empty)
- 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: trueand a shortdescription.
Project Reference
A project object supports the following properties:
| Property | Type | Required | What it does |
|---|---|---|---|
title | string | Yes | Project/tile title. |
url | string | null | No | If provided, title area becomes a clickable link opening in a new tab. If missing or null, the tile header is non-clickable. |
colorClass | string | No | Adds tile color class to the project button/header. |
fullRow | boolean | No | If true, tile uses full-row style (fullRow class). Great for notices or section intros. |
languages | string[] | No | Rendered as a bullet-separated line (HTML • CSS • JavaScript). |
date | string | No | Rendered in a <time> element. Valid date strings are formatted to DD-MM-YYYY; invalid formats are shown as-is. |
headerNote | string | No | Injected as HTML under header metadata (supports inline links/emojis). |
content | Array<ContentBlock> | No | Rich blocks displayed before description paragraphs. Currently image blocks are supported. |
description | string[] | No | Each entry renders as its own paragraph (<p>). HTML is allowed. |
links | Array<LinkItem> | No | Renders 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.'
]
}
Full-featured project example
{
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')
| Property | Type | Required | What it does |
|---|---|---|---|
type | 'image' | Yes | Enables image rendering logic. |
src | string | Yes | Image path/URL. Local files are typically under images/. |
alt | string | No | Alt 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' }
]
links Item Types
The links array supports multiple item types.
1) Standard link (type: 'link')
| Property | Type | Required | What it does |
|---|---|---|---|
type | 'link' | Yes | Renders a clickable button-style anchor. |
text | string | Yes | Main label text. |
url | string | Yes (recommended) | Destination URL. Falls back to # if missing. |
icon | string | No | Font Awesome class for icon. Defaults to fas fa-link. |
note | string | No | Small 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')
| Property | Type | Required | What it does |
|---|---|---|---|
type | 'badge' | Yes | Renders an image badge. |
src | string | Yes | Badge image URL/path. |
alt | string | No | Alt text for accessibility. |
url | string | No | If present, wraps badge in a clickable link. |
text | string | No | Used 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.
| Property | Type | Required | What it does |
|---|---|---|---|
type | 'text' | Recommended | Signals static chip intent. |
text | string | Yes | Chip label. |
Example:
{ type: 'text', text: 'Not Maintained' }
How to Add a New Project (Step-by-Step)
- Pick a category in
portfolioData.categories. - Append a project object to that category's
projectsarray. - Set required fields first:
title- optional but recommended:
url,colorClass,description
- Add extra metadata as needed:
languages,date,headerNote,fullRow
- Add richer content:
- screenshots via
content: [{ type: 'image', ... }] - call-to-action entries via
links
- screenshots via
- 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[]
SocialLink
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: stringurl?: string | nullcolorClass?: stringfullRow?: booleanlanguages?: string[]date?: stringheaderNote?: string(HTML allowed)content?: ContentBlock[]description?: string[](HTML allowed)links?: LinkItem[]
ContentBlock (currently only image)
type: 'image'src: stringalt?: string
LinkItem types
type: 'link'text: stringurl?: stringicon?: stringnote?: string
type: 'badge'src: stringalt?: stringurl?: stringtext?: string(fallback alt)
type: 'text'(or any unknown type)text: string
Conventions & Tips
- Prefer existing
tile-tone-*classes for visual consistency. - Use
fullRow: truefor notices/intro tiles, not regular projects. - Keep
descriptionas an array of short paragraphs for readable cards. - Use meaningful
alttext for accessibility (avoid empty alt unless image is decorative). - Keep date formats consistent (
YYYY-MM-DDis 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
contentitems withtype: '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' }
]
}