pacman-contribution-graph 1.0.14 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +59 -9
  2. package/dist/pacman-contribution-graph.min.js +1 -1
  3. package/package.json +44 -26
  4. package/.prettierrc +0 -8
  5. package/.vscode/extensions.json +0 -5
  6. package/.vscode/settings.json +0 -6
  7. package/assets/packman-demo.png +0 -0
  8. package/dist/pacman-contribution-graph.js +0 -1776
  9. package/dist/pacman-contribution-graph.js.map +0 -1
  10. package/embeded/canvas.html +0 -41
  11. package/github-action/action.yml +0 -16
  12. package/github-action/dist/index.js +0 -26901
  13. package/github-action/package.json +0 -14
  14. package/github-action/pnpm-lock.yaml +0 -77
  15. package/github-action/src/index.js +0 -47
  16. package/index.html +0 -528
  17. package/pacman.abozanona.me/index.js +0 -47
  18. package/pacman.abozanona.me/package.json +0 -8
  19. package/server/api/contributions/route.ts.z +0 -31
  20. package/server/page.zts.z +0 -13
  21. package/src/assets/images/ghosts/blinky.png +0 -0
  22. package/src/assets/images/ghosts/clyde.png +0 -0
  23. package/src/assets/images/ghosts/inky.png +0 -0
  24. package/src/assets/images/ghosts/pinky.png +0 -0
  25. package/src/assets/images/ghosts/scared.png +0 -0
  26. package/src/assets/sounds/pacman_beginning.wav +0 -0
  27. package/src/assets/sounds/pacman_chomp.wav +0 -0
  28. package/src/assets/sounds/pacman_death.wav +0 -0
  29. package/src/assets/sounds/pacman_eatghost.wav +0 -0
  30. package/src/canvas.ts +0 -244
  31. package/src/constants.ts +0 -102
  32. package/src/game.ts +0 -231
  33. package/src/grid.ts +0 -127
  34. package/src/index.ts +0 -48
  35. package/src/movement/ghosts-movement.ts +0 -183
  36. package/src/movement/movement-utils.ts +0 -40
  37. package/src/movement/pacman-movement.ts +0 -230
  38. package/src/music-player.ts +0 -119
  39. package/src/store.ts +0 -23
  40. package/src/svg.ts +0 -254
  41. package/src/types.ts +0 -78
  42. package/src/utils.ts +0 -81
  43. package/tsconfig.json +0 -11
  44. package/webpack.common.js +0 -19
  45. package/webpack.dev.js +0 -23
  46. package/webpack.prod.js +0 -18
@@ -1,47 +0,0 @@
1
- import http from 'http';
2
- import { PacmanRenderer } from 'pacman-contribution-graph';
3
- import querystring from 'querystring';
4
- import url from 'url';
5
-
6
- const githubToken = process.env.GITHUB_ACCESS_TOKEN;
7
-
8
- const generateSvg = async (userName) => {
9
- return new Promise((resolve) => {
10
- const conf = {
11
- platform: "github",
12
- username: userName,
13
- outputFormat: "svg",
14
- gameSpeed: 1,
15
- gameTheme: "github-dark",
16
- githubSettings: {
17
- accessToken: githubToken
18
- },
19
- svgCallback: (animatedSVG) => resolve(animatedSVG)
20
- };
21
-
22
- const pr = new PacmanRenderer(conf);
23
- pr.start();
24
- });
25
- };
26
-
27
- const server = http.createServer(async (req, res) => {
28
- const parsedUrl = url.parse(req.url);
29
- const queryParams = querystring.parse(parsedUrl.query);
30
- const username = queryParams.username || 'abozanona';
31
-
32
- try {
33
- const svg = await generateSvg(username);
34
- res.writeHead(200, {
35
- 'Content-Type': 'image/svg+xml',
36
- 'Cache-Control': 'no-store, no-cache, must-revalidate',
37
- 'Pragma': 'no-cache',
38
- 'Expires': '0'
39
- });
40
- res.end(svg.replace("Generated with ", "Generated with " + username + " "));
41
- } catch (error) {
42
- res.end('Error generating SVG');
43
- throw error;
44
- }
45
- });
46
-
47
- server.listen();
@@ -1,8 +0,0 @@
1
- {
2
- "name": "pacman-abozanona-node",
3
- "type": "module",
4
- "version": "1.0.0",
5
- "dependencies": {
6
- "pacman-contribution-graph": "^1.0.13"
7
- }
8
- }
@@ -1,31 +0,0 @@
1
- import { NextResponse } from 'next/server';
2
-
3
- export async function GET(request: Request) {
4
- const { searchParams } = new URL(request.url);
5
- const username = searchParams.get('username');
6
-
7
- if (!username) {
8
- return NextResponse.json({ error: 'Username is required' }, { status: 400 });
9
- }
10
-
11
- try {
12
- const response = await fetch(`https://gitlab.com/users/${username}/calendar.json`);
13
-
14
- if (!response.ok) {
15
- throw new Error('Failed to fetch contributions from GitLab');
16
- }
17
-
18
- const contributionsList = await response.json();
19
-
20
- // Create a new response with CORS headers
21
- const corsResponse = NextResponse.json(contributionsList);
22
- corsResponse.headers.set('Access-Control-Allow-Origin', '*');
23
- corsResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
24
- corsResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
25
-
26
- return corsResponse;
27
- } catch (error) {
28
- console.error('Error fetching contributions:', error);
29
- return NextResponse.json({ error: 'Failed to fetch contributions' }, { status: 500 });
30
- }
31
- }
package/server/page.zts.z DELETED
@@ -1,13 +0,0 @@
1
- //
2
- export default function Home() {
3
- return (
4
- <div className="p-8">
5
- <h1 className="text-3xl font-bold mb-4">GitHub and GitLab API Routes</h1>
6
- <p className="mb-4">Use the following API routes:</p>
7
- <ul className="list-disc pl-8">
8
- <li>/api/contributions?username=USERNAME</li>
9
- </ul>
10
- <p className="mt-4">Replace 'USERNAME' with an actual GitLab username.</p>
11
- </div>
12
- );
13
- }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/src/canvas.ts DELETED
@@ -1,244 +0,0 @@
1
- import {
2
- CELL_SIZE,
3
- GAP_SIZE,
4
- GHOSTS,
5
- GRID_HEIGHT,
6
- GRID_WIDTH,
7
- PACMAN_COLOR,
8
- PACMAN_COLOR_DEAD,
9
- PACMAN_COLOR_POWERUP,
10
- WALLS
11
- } from './constants';
12
- import { MusicPlayer } from './music-player';
13
- import { StoreType } from './types';
14
- import { Utils } from './utils';
15
-
16
- const resizeCanvas = (store: StoreType) => {
17
- const canvasWidth = GRID_WIDTH * (CELL_SIZE + GAP_SIZE);
18
- const canvasHeight = GRID_HEIGHT * (CELL_SIZE + GAP_SIZE) + 20; // Adding some space for months on top
19
-
20
- store.config.canvas.width = canvasWidth;
21
- store.config.canvas.height = canvasHeight;
22
- };
23
-
24
- const drawGrid = (store: StoreType) => {
25
- const ctx = store.config.canvas.getContext('2d')!;
26
- ctx.fillStyle = Utils.getCurrentTheme(store).gridBackground;
27
- ctx.fillRect(0, 0, store.config.canvas.width, store.config.canvas.height);
28
-
29
- for (let x = 0; x < GRID_WIDTH; x++) {
30
- for (let y = 0; y < GRID_HEIGHT; y++) {
31
- const intensity = store.grid[x][y].intensity;
32
- if (intensity > 0) {
33
- const adjustedIntensity = intensity < 0.2 ? 0.3 : intensity;
34
- const color = Utils.hexToRGBA(Utils.getCurrentTheme(store).contributionBoxColor, adjustedIntensity);
35
- ctx.fillStyle = color;
36
- } else {
37
- ctx.fillStyle = Utils.getCurrentTheme(store).emptyContributionBoxColor;
38
- }
39
- ctx.beginPath();
40
- store.config.canvas
41
- .getContext('2d')!
42
- .roundRect(x * (CELL_SIZE + GAP_SIZE), y * (CELL_SIZE + GAP_SIZE) + 15, CELL_SIZE, CELL_SIZE, 5);
43
- ctx.fill();
44
- }
45
- }
46
-
47
- ctx.fillStyle = Utils.getCurrentTheme(store).wallColor;
48
- for (let x = 0; x <= GRID_WIDTH; x++) {
49
- for (let y = 0; y <= GRID_HEIGHT; y++) {
50
- // Draw horizontal walls
51
- if (WALLS.horizontal[x][y].active) {
52
- ctx.fillRect(
53
- x * (CELL_SIZE + GAP_SIZE) - GAP_SIZE,
54
- y * (CELL_SIZE + GAP_SIZE) - GAP_SIZE + 15,
55
- CELL_SIZE + GAP_SIZE,
56
- GAP_SIZE
57
- );
58
- // // TODO: For debug only
59
- // ctx.fillStyle = '#000';
60
- // ctx.fillText(WALLS.horizontal[x][y].id, x * (GAP_SIZE + CELL_SIZE), y * (GAP_SIZE + CELL_SIZE));
61
- }
62
-
63
- // Draw vertical walls
64
- if (WALLS.vertical[x][y].active) {
65
- ctx.fillRect(
66
- x * (CELL_SIZE + GAP_SIZE) - GAP_SIZE,
67
- y * (CELL_SIZE + GAP_SIZE) - GAP_SIZE + 15,
68
- GAP_SIZE,
69
- CELL_SIZE + GAP_SIZE
70
- );
71
- // // TODO: For debug only
72
- // ctx.fillStyle = '#000';
73
- // ctx.fillText(WALLS.vertical[x][y].id, x * (GAP_SIZE + CELL_SIZE), (y + 1) * (GAP_SIZE + CELL_SIZE));
74
- }
75
- }
76
- }
77
-
78
- ctx.fillStyle = Utils.getCurrentTheme(store).textColor;
79
- ctx.font = '10px Arial';
80
- ctx.textAlign = 'center';
81
-
82
- let lastMonth = '';
83
-
84
- for (let x = 0; x < GRID_WIDTH; x++) {
85
- if (store.monthLabels[x] !== lastMonth) {
86
- const xPos = x * (CELL_SIZE + GAP_SIZE) + CELL_SIZE / 2;
87
- ctx.fillText(store.monthLabels[x], xPos, 10);
88
- lastMonth = store.monthLabels[x];
89
- }
90
- }
91
- };
92
-
93
- const drawPacman = (store: StoreType) => {
94
- const ctx = store.config.canvas.getContext('2d')!;
95
- const x = store.pacman.x * (CELL_SIZE + GAP_SIZE) + CELL_SIZE / 2;
96
- const y = store.pacman.y * (CELL_SIZE + GAP_SIZE) + CELL_SIZE / 2 + 15;
97
- const radius = CELL_SIZE / 2;
98
-
99
- // Change Pac-Man's color to red if he's on power-up, dead, else yellow
100
- if (store.pacman.deadRemainingDuration) {
101
- ctx.fillStyle = PACMAN_COLOR_DEAD;
102
- } else if (store.pacman.powerupRemainingDuration) {
103
- ctx.fillStyle = PACMAN_COLOR_POWERUP;
104
- } else {
105
- ctx.fillStyle = PACMAN_COLOR;
106
- }
107
-
108
- const mouthAngle = store.pacmanMouthOpen ? 0.35 * Math.PI : 0.1 * Math.PI;
109
-
110
- let startAngle, endAngle;
111
- switch (store.pacman.direction) {
112
- case 'up':
113
- startAngle = 1.5 * Math.PI + mouthAngle;
114
- endAngle = 1.5 * Math.PI - mouthAngle;
115
- break;
116
- case 'down':
117
- startAngle = 0.5 * Math.PI + mouthAngle;
118
- endAngle = 0.5 * Math.PI - mouthAngle;
119
- break;
120
- case 'left':
121
- startAngle = Math.PI + mouthAngle;
122
- endAngle = Math.PI - mouthAngle;
123
- break;
124
- case 'right':
125
- default:
126
- startAngle = 0 + mouthAngle;
127
- endAngle = 2 * Math.PI - mouthAngle;
128
- break;
129
- }
130
-
131
- ctx.beginPath();
132
- ctx.arc(x, y, radius, startAngle, endAngle);
133
- ctx.lineTo(x, y);
134
- ctx.fill();
135
- };
136
-
137
- const preloadedImages: { [key: string]: HTMLImageElement } = {};
138
- const getLoadedImage = (key: string, imgDate: string): HTMLImageElement => {
139
- if (!preloadedImages[key]) {
140
- const image = new Image();
141
- image.src = imgDate;
142
- preloadedImages[key] = image;
143
- }
144
- return preloadedImages[key];
145
- };
146
-
147
- const drawGhosts = (store: StoreType) => {
148
- store.ghosts.forEach((ghost) => {
149
- const x = ghost.x * (CELL_SIZE + GAP_SIZE);
150
- const y = ghost.y * (CELL_SIZE + GAP_SIZE) + 15;
151
- const size = CELL_SIZE;
152
-
153
- const ctx = store.config.canvas.getContext('2d')!;
154
- if (ghost.scared) {
155
- ctx.drawImage(getLoadedImage('scared', GHOSTS['scared'].imgDate), x, y, size, size);
156
- } else {
157
- ctx.drawImage(getLoadedImage(ghost.name, GHOSTS[ghost.name].imgDate), x, y, size, size);
158
- }
159
- });
160
- };
161
-
162
- const renderGameOver = (store: StoreType) => {
163
- const ctx = store.config.canvas.getContext('2d')!;
164
- ctx.fillStyle = Utils.getCurrentTheme(store).textColor;
165
- ctx.font = '20px Arial';
166
- ctx.textAlign = 'center';
167
- ctx.fillText('Game Over', store.config.canvas.width / 2, store.config.canvas.height / 2);
168
- };
169
-
170
- const drawSoundController = (store: StoreType) => {
171
- if (!store.config.enableSounds) {
172
- return;
173
- }
174
- const ctx = store.config.canvas.getContext('2d')!;
175
-
176
- const width = 30,
177
- height = 30,
178
- left = store.config.canvas.width - width - 10,
179
- top = 10;
180
- ctx.fillStyle = `rgba(0, 0, 0, ${MusicPlayer.getInstance().isMuted ? 0.3 : 0.5})`;
181
- ctx.beginPath();
182
- ctx.moveTo(left + 10, top + 10);
183
- ctx.lineTo(left + 20, top + 5);
184
- ctx.lineTo(left + 20, top + 25);
185
- ctx.lineTo(left + 10, top + 20);
186
- ctx.closePath();
187
- ctx.fill();
188
-
189
- if (!MusicPlayer.getInstance().isMuted) {
190
- ctx.strokeStyle = `rgba(0, 0, 0, 0.4)`;
191
- ctx.lineWidth = 2;
192
-
193
- // First wave
194
- ctx.beginPath();
195
- ctx.arc(left + 25, top + 15, 5, 0, Math.PI * 2);
196
- ctx.stroke();
197
-
198
- // Second wave
199
- ctx.beginPath();
200
- ctx.arc(left + 25, top + 15, 8, 0, Math.PI * 2);
201
- ctx.stroke();
202
- } else {
203
- // Mute line
204
- ctx.strokeStyle = 'rgba(255, 0, 0, 0.6)';
205
- ctx.lineWidth = 3;
206
- ctx.beginPath();
207
- ctx.moveTo(left + 25, top + 5);
208
- ctx.lineTo(left + 5, top + 25);
209
- ctx.stroke();
210
- }
211
- };
212
-
213
- const listenToSoundController = (store: StoreType) => {
214
- if (!store.config.enableSounds) {
215
- return;
216
- }
217
- store.config.canvas.addEventListener('click', function (event) {
218
- const rect = store.config.canvas.getBoundingClientRect();
219
- const x = event.clientX - rect.left,
220
- y = event.clientY - rect.top;
221
- const width = 30,
222
- height = 30,
223
- left = store.config.canvas.width - width - 10,
224
- top = 10;
225
-
226
- if (x >= left && x <= left + this.width && y >= top && y <= top + this.height) {
227
- if (MusicPlayer.getInstance().isMuted) {
228
- MusicPlayer.getInstance().unmute();
229
- } else {
230
- MusicPlayer.getInstance().mute();
231
- }
232
- }
233
- });
234
- };
235
-
236
- export const Canvas = {
237
- resizeCanvas,
238
- drawGrid,
239
- drawPacman,
240
- drawGhosts,
241
- renderGameOver,
242
- drawSoundController,
243
- listenToSoundController
244
- };
package/src/constants.ts DELETED
@@ -1,102 +0,0 @@
1
- import { GameTheme, GhostName, ThemeKeys } from './types';
2
-
3
- export const CELL_SIZE = 20;
4
- export const GAP_SIZE = 2;
5
- export const GRID_WIDTH = 52;
6
- export const GRID_HEIGHT = 7;
7
- export const PACMAN_COLOR = 'yellow';
8
- export const PACMAN_COLOR_POWERUP = 'red';
9
- export const PACMAN_COLOR_DEAD = '#80808064';
10
- export const GHOST_NAMES: GhostName[] = ['blinky', 'clyde', 'inky', 'pinky'];
11
- export const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
12
- export const DELTA_TIME = 200;
13
- export const PACMAN_DEATH_DURATION = 10;
14
- export const PACMAN_POWERUP_DURATION = 15;
15
- export const GAME_THEMES: { [key in ThemeKeys]: GameTheme } = {
16
- github: {
17
- textColor: '#586069',
18
- gridBackground: '#ffffff',
19
- contributionBoxColor: '#9be9a8',
20
- emptyContributionBoxColor: '#ebedf0',
21
- wallColor: '#000000'
22
- },
23
- 'github-dark': {
24
- textColor: '#8b949e',
25
- gridBackground: '#0d1117',
26
- contributionBoxColor: '#26a641',
27
- emptyContributionBoxColor: '#161b22',
28
- wallColor: '#FFFFFF'
29
- },
30
- gitlab: {
31
- textColor: '#626167',
32
- gridBackground: '#ffffff',
33
- contributionBoxColor: '#7992f5',
34
- emptyContributionBoxColor: '#ececef',
35
- wallColor: '#000000'
36
- },
37
- 'gitlab-dark': {
38
- textColor: '#999999',
39
- gridBackground: '#1f1f1f',
40
- contributionBoxColor: '#2e7db1',
41
- emptyContributionBoxColor: '#2d2d2d',
42
- wallColor: '#FFFFFF'
43
- }
44
- };
45
- export const GHOSTS: { [key in GhostName | 'scared']: { imgDate: string } } = {
46
- blinky: {
47
- imgDate:
48
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAfUlEQVQ4T+2TUQ7AIAhDy/0PzQIRAqxmLtnn/DJPWypBAVkKKOMCyOQN7IRElLrcnIrDLNK4wVtxNbkb6Hq+jOcSbim6QVzKEstkw92gxVeFrMpqokix4wA+NvCOnvfArvcEbHoe2G9QmmhDMUc65p3xYC6q3zQPxtdl3NgF5QpL/b/rs3IAAAAASUVORK5CYIIA'
49
- },
50
- clyde: {
51
- imgDate:
52
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgUlEQVQ4T+2T0Q6AIAhFLx9sH1MfTIPCAeLKrcd8PHqP4JBQLN7BFacNlHkAs+AQcqIueBs2mVWjgtWwl4yCdrd/pHYLLlVEgR2yK0wy4SoI5TcGXU4wM+AEJQfwsUCuXngDOR4rqKbngf0C94gyFHmkbd4rbkxD/pv2jfR1Ky7sBNrzXbHpnBX+AAAAAElFTkSuQmCC'
53
- },
54
- inky: {
55
- imgDate:
56
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAg0lEQVQ4T+WTWxKAIAhFuQvK/a+jFoT5QAVxypn+6vMEx6sDIO/jk12OAMs1WDVOXV3UBW+bRVbTFMFu8yCZBExH/g26VHCXI0AJpKgdUCUrTlkwxE+FECdzS7HiJemXgvyeO29gE7jD8wDVFX4vSLNtR1q2z+OVlaZxTaXYrq7HbxYBS8VgMVrqzkEAAAAASUVORK5CYIIA'
57
- },
58
- pinky: {
59
- imgDate:
60
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhklEQVQ4T+2T0Q2AIAwF281wC50Qt9DNagoptqVESfyUz4N3vJCCECxaD4o47gt6bsAo2IWUqAnehkUmbYpgNqwlvSCnur+dtnnAuYUVyCGJimTAi8DUzwmwOoGI7hYjDgAfC/jqiTfg47ZBND0P7BeoR+Sh8CMt8x5xYSWkv2nbcF834swuA/9u49Yy5bgAAAAASUVORK5CYIIA'
61
- },
62
- scared: {
63
- imgDate:
64
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAeUlEQVQ4T82TUQ6AMAhD7UX0/sdyF0GREVmDmTN+bH9r6Bs0A0t2VpFULwDrrfBkZFcA3YC3ZodViAFGzQHyP0B2w2NrB0/1AoDbHwLoQ5/nrw1OBuD5e/crbM9Aiz35njHWzpSB/m3+0r40mV41M8U19WJe3Uw/tQOKt08pUUbBEQAAAABJRU5ErkJgggAA'
65
- }
66
- };
67
- export const WALLS: {
68
- horizontal: { active: boolean; id: string }[][];
69
- vertical: { active: boolean; id: string }[][];
70
- } = {
71
- horizontal: Array(GRID_WIDTH + 1)
72
- .fill(null)
73
- .map(() => Array(GRID_HEIGHT + 1).fill({ active: false, id: '' })),
74
- vertical: Array(GRID_WIDTH + 1)
75
- .fill(null)
76
- .map(() => Array(GRID_HEIGHT + 1).fill({ active: false, id: '' }))
77
- };
78
-
79
- export const setWall = (x: number, y: number, direction: 'horizontal' | 'vertical', lineId: string) => {
80
- if (direction === 'horizontal') {
81
- if (x >= 0 && x < WALLS.horizontal.length && y >= 0 && y < WALLS.horizontal[0].length) {
82
- WALLS.horizontal[x][y] = { active: true, id: lineId };
83
- }
84
- } else {
85
- if (x >= 0 && x < WALLS.vertical.length && y >= 0 && y < WALLS.vertical[0].length) {
86
- WALLS.vertical[x][y] = { active: true, id: lineId };
87
- }
88
- }
89
- };
90
-
91
- export const hasWall = (x: number, y: number, direction: 'up' | 'down' | 'left' | 'right'): boolean => {
92
- switch (direction) {
93
- case 'up':
94
- return WALLS.horizontal[x][y].active;
95
- case 'down':
96
- return WALLS.horizontal[x + 1][y].active;
97
- case 'left':
98
- return WALLS.vertical[x][y].active;
99
- case 'right':
100
- return WALLS.vertical[x][y + 1].active;
101
- }
102
- };