Skip to content

Commit 941d3c4

Browse files
committed
feat: implement Ghost City mode (JhaSourav07#97)
1 parent 0d21d85 commit 941d3c4

3 files changed

Lines changed: 195 additions & 251 deletions

File tree

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ Most GitHub stat badges are **flat**. Flat bars, flat text, flat colors. They bl
3232

3333
**CommitPulse is different.**
3434

35-
We render your contribution data as a **3D Isometric City** — a grid of glowing towers where each column's height is directly proportional to your commit count that day. The more you grind, the taller your skyline grows. This is not decoration. This is a **live, animated data visualization** that makes your dedication impossible to ignore.
35+
We render your contribution data as a **3D Isometric City** — a grid of glowing towers where each column's height is directly proportional to your commit count that day. The more you grind, the taller your skyline grows.
36+
37+
**Ghost City Architecture:** In this mode, zero-contribution days aren't just empty space. They are rendered as thin, wireframe-style **blueprint foundations** (4px high). This gives your commit landscape a structured, architectural "work-in-progress" look even during rest days, maintaining the premium 3D aesthetic across the entire calendar.
38+
39+
This is not decoration. This is a **live, animated data visualization** that makes your dedication impossible to ignore.
3640

3741
### Why Isometric > Flat
3842

lib/svg/generator.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,51 @@ describe('generateSVG', () => {
202202
expect(svg).toContain('prefers-reduced-motion');
203203
});
204204
});
205+
206+
// Ghost City Placeholder Mode tests
207+
describe('Ghost City Mode', () => {
208+
const emptyCalendar: ContributionCalendar = {
209+
totalContributions: 0,
210+
weeks: [
211+
{
212+
contributionDays: [
213+
{ contributionCount: 0, date: '2024-06-10' },
214+
{ contributionCount: 0, date: '2024-06-11' },
215+
],
216+
},
217+
],
218+
};
219+
220+
const activeCalendar: ContributionCalendar = {
221+
totalContributions: 5,
222+
weeks: [
223+
{
224+
contributionDays: [
225+
{ contributionCount: 0, date: '2024-06-10' },
226+
{ contributionCount: 5, date: '2024-06-11' },
227+
],
228+
},
229+
],
230+
};
231+
232+
it('renders Ghost City blueprint when user has 0 total contributions', () => {
233+
const svg = generateSVG(mockStats, { user: 'avi' } as unknown as BadgeParams, emptyCalendar);
234+
235+
// Should contain wireframe strokes
236+
expect(svg).toContain('stroke-width="0.5"');
237+
expect(svg).toContain('stroke-opacity="0.3"');
238+
// Should use the GHOST_HEIGHT_PX which is 4 (10 + 4 = 14)
239+
expect(svg).toContain('L0 14 L-16 4 L-16 0 Z');
240+
});
241+
242+
it('does not render Ghost City when user has active contributions', () => {
243+
const svg = generateSVG(mockStats, { user: 'avi' } as unknown as BadgeParams, activeCalendar);
244+
245+
// Should NOT contain wireframe strokes
246+
expect(svg).not.toContain('stroke-width="0.5"');
247+
expect(svg).not.toContain('stroke-opacity="0.3"');
248+
// Active mode empty days should have h=0 (10 + 0 = 10)
249+
expect(svg).toContain('L0 10 L-16 0 L-16 0 Z');
250+
});
251+
});
205252
});

0 commit comments

Comments
 (0)