diff --git a/.gitignore b/.gitignore
index 1bd5e34..0943b27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ pnpm-debug.log*
*.bak
tree.txt
+
+App.tsx
diff --git a/astro.config.mjs b/astro.config.mjs
index 3b8ec31..182085f 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -1,6 +1,8 @@
// @ts-check
import tailwindcss from '@tailwindcss/vite';
+import remarkDirective from 'remark-directive';
+import { remarkAlert } from 'remark-github-beta-blockquote-admonitions';
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
@@ -11,6 +13,12 @@ export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
+ markdown: {
+ remarkPlugins: [
+ remarkDirective,
+ remarkAlert,
+ ],
+ },
integrations: [react()],
});
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index f786470..952fa5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,6 +30,8 @@
"lucide-react": "^0.562.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
+ "remark-directive": "^4.0.0",
+ "remark-github-beta-blockquote-admonitions": "^3.1.2",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18"
},
@@ -268,7 +270,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/generator": "^7.28.6",
@@ -1021,7 +1022,6 @@
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz",
"integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "7.1.0"
},
@@ -3108,7 +3108,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz",
"integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -3118,7 +3117,6 @@
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -3160,7 +3158,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3327,7 +3324,6 @@
"resolved": "https://registry.npmjs.org/astro/-/astro-5.16.9.tgz",
"integrity": "sha512-gJvoZv0v8xCcKBcsxz1ZfXqoJ7sJJcyoKP8bUTjkuD4vDShLe0N26em4LQxitVv/2HLOpldQg67bEHB/qGoxJA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@astrojs/compiler": "^2.13.0",
"@astrojs/internal-helpers": "0.7.5",
@@ -3564,7 +3560,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -4870,7 +4865,6 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"license": "MIT",
- "peer": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -4931,7 +4925,6 @@
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
"integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
"license": "MPL-2.0",
- "peer": true,
"dependencies": {
"detect-libc": "^2.0.3"
},
@@ -5258,6 +5251,27 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/mdast-util-directive": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz",
+ "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "parse-entities": "^4.0.0",
+ "stringify-entities": "^4.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/mdast-util-find-and-replace": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
@@ -5620,6 +5634,25 @@
"micromark-util-types": "^2.0.0"
}
},
+ "node_modules/micromark-extension-directive": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz",
+ "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-factory-whitespace": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "parse-entities": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/micromark-extension-gfm": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
@@ -6609,7 +6642,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -6619,7 +6651,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -6885,6 +6916,22 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/remark-directive": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-4.0.0.tgz",
+ "integrity": "sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-directive": "^3.0.0",
+ "micromark-extension-directive": "^4.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/remark-gfm": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
@@ -6903,6 +6950,15 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/remark-github-beta-blockquote-admonitions": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/remark-github-beta-blockquote-admonitions/-/remark-github-beta-blockquote-admonitions-3.1.2.tgz",
+ "integrity": "sha512-4t5uhMnhXp9/B0RdI+seIO8v9KCsOcoua+7MX5naDq2RTJDr4VsRZ8RgB0URCATvLlayoAl0rAU/SxFpcuna4g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "unist-util-visit": "^5.0.0"
+ }
+ },
"node_modules/remark-mdx": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz",
@@ -7334,8 +7390,7 @@
"version": "4.1.18",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.0",
@@ -7952,6 +8007,7 @@
"os": [
"aix"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -7968,6 +8024,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -7984,6 +8041,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8000,6 +8058,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8016,6 +8075,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8032,6 +8092,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8048,6 +8109,7 @@
"os": [
"freebsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8064,6 +8126,7 @@
"os": [
"freebsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8080,6 +8143,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8096,6 +8160,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8112,6 +8177,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8128,6 +8194,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8144,6 +8211,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8160,6 +8228,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8176,6 +8245,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8192,6 +8262,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8208,6 +8279,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8224,6 +8296,7 @@
"os": [
"netbsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8240,6 +8313,7 @@
"os": [
"netbsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8256,6 +8330,7 @@
"os": [
"openbsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8272,6 +8347,7 @@
"os": [
"openbsd"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8288,6 +8364,7 @@
"os": [
"openharmony"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8304,6 +8381,7 @@
"os": [
"sunos"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8320,6 +8398,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8336,6 +8415,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8352,6 +8432,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -8362,6 +8443,7 @@
"integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
"hasInstallScript": true,
"license": "MIT",
+ "peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -8532,7 +8614,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/package.json b/package.json
index f85cf14..666fdd1 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,8 @@
"lucide-react": "^0.562.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
+ "remark-directive": "^4.0.0",
+ "remark-github-beta-blockquote-admonitions": "^3.1.2",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18"
},
diff --git a/public/images/puppeteer.png b/public/images/puppeteer.png
new file mode 100644
index 0000000..376ddfe
Binary files /dev/null and b/public/images/puppeteer.png differ
diff --git a/src/components/Menu.astro b/src/components/Menu.astro
index cb34828..2c294bf 100644
--- a/src/components/Menu.astro
+++ b/src/components/Menu.astro
@@ -1,9 +1,16 @@
---
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
-import { faHouse, faUser, faBlog, faEnvelope } from '@fortawesome/free-solid-svg-icons'
+import { faHouse, faUser, faBlog, faEnvelope, faCode } from '@fortawesome/free-solid-svg-icons'
---
-
- - Home
- - About Me
- - Contact
+
diff --git a/src/components/ProjectEntryCard.astro b/src/components/ProjectEntryCard.astro
new file mode 100644
index 0000000..fbc10c9
--- /dev/null
+++ b/src/components/ProjectEntryCard.astro
@@ -0,0 +1,44 @@
+---
+// import {
+// Card,
+// CardAction,
+// CardContent,
+// CardDescription,
+// CardFooter,
+// CardHeader,
+// CardTitle,
+// } from "@/components/ui/card";
+import { Card, CardContent, CardHeader, CardDescription, CardTitle, CardFooter } from '@/components/ui/card'
+import { Button } from "@/components/ui/button";
+const { title, pubDate, description, url, thumbnail, technologies } = Astro.props;
+---
+
+
diff --git a/src/pages/SideNav.astro b/src/components/SideNav.astro
similarity index 97%
rename from src/pages/SideNav.astro
rename to src/components/SideNav.astro
index cf47b02..94f876e 100644
--- a/src/pages/SideNav.astro
+++ b/src/components/SideNav.astro
@@ -22,7 +22,7 @@ import { Label } from "@/components/ui/label"
-
+
Support Me
diff --git a/src/content.config.ts b/src/content.config.ts
index abb203c..97b8d88 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -20,7 +20,7 @@ const project = defineCollection({
description: z.string(),
url: z.string(),
thumbnail: z.string(),
- techList: z.string(),
+ technologies: z.string().array(),
}),
});
diff --git a/src/content/project/0.kwin-project-intro/index.md b/src/content/project/0.kwin-project-intro/index.md
index a748ca1..c9e8d60 100644
--- a/src/content/project/0.kwin-project-intro/index.md
+++ b/src/content/project/0.kwin-project-intro/index.md
@@ -3,9 +3,16 @@ title: GSoC 2025 Project Blog Intro - Improving Game Controller Support in KWin
authors:
- yorisoft
date: 2025-05-12
-thumbnail: https://community.kde.org/images.community/thumb/a/af/Mascot_konqi-base-plasma.png/250px-Mascot_konqi-base-plasma.png
-SPDX-License-Identifier: CC-BY-SA-4.0
-SPDX-FileCopyrightText: 2025 Yelsin Sepulveda
+description: project description - foo
+url: https://foo.co
+thumbnail: https://foo.png
+technologies:
+ - cpp
+ - java
+ - go
+ - python
+ - qt
+ - cmake
---
# Hello KDE Community!
diff --git a/src/content/project/1.kwin-project-week-1-2/index.md b/src/content/project/1.kwin-project-week-1-2/index.md
deleted file mode 100644
index 2e2896e..0000000
--- a/src/content/project/1.kwin-project-week-1-2/index.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-title: "GSoC'25 Kwin Project Blog Post: Week 1-2"
-authors:
- - yorisoft
-date: 2025-06-24
-thumbnail: /images/games.svg
-SPDX-License-Identifier: CC-BY-SA-4.0
-SPDX-FileCopyrightText: 2025 Yelsin Sepulveda
----
-
-These past few week’s my focus was on exploring input device detection and event handling mechanisms in Linux, with a particular emphasis on game controllers and their potential integration into KWin.
-I also spent time reading through KWin’s input-related source code to understand how it currently manages devices, and began reviewing documentation for various Linux input subsystems—including `evdev`, HID, and `/dev/input/jsX` in order to evaluate which layer would provide the most reliable and straight forward support for integrating controller recognition.
-The time was mostly spent learning how to use different libraries, tools and creating virtual controller prototype.
-
-
-## Tools, Libraries, and Concepts Used
-
-### libevdev
-
-`libevdev` is a library for handling `evdev` devices.
-It provides a higher-level interface over `/dev/input/event*` and abstracts much of the complexity of input event parsing.
-> `evdev` is the generic input event interface. This is the preferred interface for userspace to consume user input, and all clients are encouraged to use it.
->
-> -The kernel development community.
-
-`libevdev` can be used to:
-- Detect physical game controllers.
-- Read input events (e.g., joystick, buttons).
-- Create virtual input device and write/forward events to it from physical game controller.
-
-### Useful functions:
-- `libevdev_new()`, `libevdev_set_fd(int fd, struct libevdev **dev)`: for opening physical devices.
-- `libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)`: for polling events.
-- `libevdev_get_id_*(const struct libevdev *dev)`: to query device meta data.
-
-### uinput (User Input Subsystem)
-I used the Linux **uinput** subsystem to create a **virtual input device** that mirrors a physical controller input.
-**uinput** is what allows us to make a virtual controller out of any evdev device by:
-- Opening a file discriptor for the input device that will be emulate (i.e. have it input event forwarded).
-- Forwarding the inputs from a `evdev` interface device to `/dev/uinput` (or `/dev/input/uinput`).
-- **uinput** then creates a new node to expose the virtual device as a `evdev` interface device in `/dev/input/event*`
-
-From here the idea is that KWin or any other system component can treat the virtual controller as if it were an ordinary HID device.
-
-> uinput is a kernel module that makes it possible to emulate input devices from userspace.
-> By writing to /dev/uinput (or /dev/input/uinput) device, a process can create a virtual input device with specific capabilities.
-> Once this virtual device is created, the process can send events through it, that will be delivered to userspace and in-kernel consumers.
->
-> -The kernel development community.
-
-### Useful functions:
-- `libevdev_uinput_create_from_device(const struct libevdev *dev, int uinput_fd, struct libevdev_uinput **uinput_dev)`:
- For creating a uinput device based on the given libevdev device.
-- `libevdev_uinput_get_devnode (struct libevdev_uinput *uinput_dev)`:
- Return the device node representing this uinput device.
-- `libevdev_uinput_write_event (const struct libevdev_uinput *uinput_dev, unsigned int type, unsigned int code, int value)`:
- Post an event through the uinput device.
-
-
-Tools used:
-- `libevdev-uinput.h` for management of `uinput` devices via `libevdev`.
-- `/dev/uinput` opened with correct permissions.
- - Ensuring the current user is in the `input` group.
- - Verifying that the `uinput` kernel module is loaded (using `modprobe uinput`). Some distros (Ubuntu/Kubuntu) have it built in, not loaded as module, thus `modprobe uinput` command won't log anything.
- - Opening `/dev/uinput` with `O_WRONLY | O_NONBLOCK` flags using `open()`, and ensuring no `EPERM` or `EACCES` errors were returned.
- - Optional: Run program as sudo user.
-
-### force feedback detection/support
-
-Using `ioctl(fd, EVIOCGBIT(EV_FF, ...))` and tools like `fftest`, I examined:
-
-- How to query a device’s force feedback (FF) capabilities to figure out which effects are supported (e.g., rumble, sine wave).
-- How to upload ff effects to physical game controller and test rumble motors.
- - This was key to understanding haptic capability support on physical devices.
-
-> To enable force feedback, you have to:
->
-> have your kernel configured with evdev and a driver that supports your device.
->
-> make sure evdev module is loaded and /dev/input/event* device files are created.
-
-
-### Testing & Validation
-- Used `evtest` and `fftest`to test evdev devices and understand their capabilities -
- `sudo evtest /dev/input/eventX`.
-- Used those same tools to test virtual devices creating using uinput -
-`sudo fftest dev/input/eventX`. uinput creates a node device in `dev/input/eventX` for the virtual input.
-- Prototype logs validate that a virtual device can be created and events can properly be written to a that virtual device using `libevdev`.
-
----
-
-### **Takeaways**
-
-- Using `libevdev` and `libevdev-uinput` we can access physical controllers, create virtual controller and read/write low-level input events.
-- Understanding of the permission requirements to open `/dev/input/*` and `/dev/uinput` (use `udev` rules or run as root).
-- Tools to test:
- - `evtest` and `fftest` (from `input-utils`)
- - `udevadm info --name=/dev/input/eventX --attribute-walk`
- - Shows the device hierarchy - how the device is connected to PC and any parent device it connects to.
-- Built a minimal proof-of-concept C++ program that routes an evdev devices input 1:1 to a virtual controller (via uinput).
-- Not all controllers support all force feedback types; some failed with `EINVAL` during upload.
-- `libevdev` does not handle FF upload directly — this remains kernel-level and typically involves `ioctl()`.
-
-
-### References and Documentation
-- **[Linux Input Subsystem Documentation](https://www.kernel.org/doc/html/latest/input/index.html) (kernel-level overview of evdev, HID, uinput, etc.)**
-- **[evdev interface documentation](https://www.kernel.org/doc/html/latest/input/event.html) (from the kernel source)**
-- **[uinput](https://www.kernel.org/doc/html/latest/input/uinput.html): User-level input device emulation**
-- **[Force Feedback programming on Linux](https://www.kernel.org/doc/html/latest/input/ff.html) (FF effect types and ioctl usage)**
-- **[libevdev](https://www.freedesktop.org/software/libevdev/doc/latest/) (Userspace abstraction for evdev devices)**
diff --git a/src/content/project/2.kwin-project-week-3-4/index.md b/src/content/project/2.kwin-project-week-3-4/index.md
index 2ce50f0..b05217a 100644
--- a/src/content/project/2.kwin-project-week-3-4/index.md
+++ b/src/content/project/2.kwin-project-week-3-4/index.md
@@ -4,9 +4,16 @@ discourse: yorisoft
authors:
- yorisoft
date: 2025-09-15
+description: project description foo
+url: https://foo.co
thumbnail: /images/kwin_plugin_gamepad_architecture_diagram_3.png
-SPDX-License-Identifier: CC-BY-SA-4.0
-SPDX-FileCopyrightText: 2025 Yelsin Sepulveda
+technologies:
+ - cpp
+ - java
+ - go
+ - python
+ - qt
+ - cmake
---
# KWin::Plugin::GamePadManager
diff --git a/src/content/project/3.kwin-project-week-5-6/index.md b/src/content/project/3.kwin-project-week-5-6/index.md
index 0cb4faa..d058f9d 100644
--- a/src/content/project/3.kwin-project-week-5-6/index.md
+++ b/src/content/project/3.kwin-project-week-5-6/index.md
@@ -4,9 +4,16 @@ discourse: yorisoft
authors:
- yorisoft
date: 2025-10-03
+description: project description foo
+url: https://foo.co
thumbnail: /images/kwin_plugin_gamepad_kcm.png
-SPDX-License-Identifier: CC-BY-SA-4.0
-SPDX-FileCopyrightText: 2025 Yelsin Sepulveda
+technologies:
+ - cpp
+ - java
+ - go
+ - python
+ - qt
+ - cmake
---
It's been another few weeks of progress on the KWin GameController Plugin and I've got a lot to share! After spending the previous weeks setting up the foundation, I've progressed things forward by improving the logic a bit more, creating a few integration tests, integrating it into System Settings, and making sure it runs well on real hardware like the steamdeck.
diff --git a/src/content/project/puppet-purchase/index.md b/src/content/project/puppet-purchase/index.md
new file mode 100644
index 0000000..1b442b5
--- /dev/null
+++ b/src/content/project/puppet-purchase/index.md
@@ -0,0 +1,98 @@
+---
+title: "Puppet-Purchase: Auto Purchase Scripts"
+authors:
+ - yorisoft
+date: 2010-01-10
+description: "puppet-purchase is a bot that automates the process of purchasing an item from a few of the most popular online retailers."
+url: https://github.com/Yorisoft/puppet-purchase
+thumbnail: /images/puppeteer.png
+technologies:
+ - js
+ - docker
+ - jenkins
+ - shell
+ - puppeteer
+---
+
+puppet-purchase is a bot that automates the process of purchasing an item from a few of the major online retailers. In attempt to combat scalping, I've created puppet-purchase bot and am making it publicly available with you all. Not perfect, but has helped me. Please share && contribute.
+
+## How Does it work?
+
+These are scripts that automate the user flow of purchasing an item.
+That flow of purchasing an item varies a bit from website to website, but in general it is as follows:
+- Navigate to site
+- Sign-in to the account
+- Navigate to item listing page
+- If no is stock available:
+ Switches store and refresh page until it finds available stock.
+- Adds item to cart
+- Checks-out cart
+
+
+### Connecting it to your account
+
+To run these scripts, setting up an online account with one of the retailers is required. To ensure the scripts execute with no errors, be sure to plug in your account information. Each bot uses the **.env.userInfo** file located in _**scripts/< bot >/userInfo/.env.userInfo**_ to define user specific information.
+
+> [!CAUTION]
+> _**Do not include your payment information.**_
+> All payment information should be setup by using your web browser, logging into the account, and adding a payment option. Not in the scripts.
+> Avoid checking in personal account information to this project if you decide to contribute by adding _**env.userInfo**_ to _**gitignore**_.
+> Or even better, by creating a new a _**env.**_ file and pointing to it in _**scripts/< bot >/myInfo.js**_
+
+
+## Installation
+
+To run these script use [node.js](https://nodejs.org/en/) in order to install the required node modules. Navigate to the project directory and install npm.
+
+```node
+npm i
+```
+Because of the way that the environment variables are defined, a version of [WSL](https://docs.microsoft.com/en-us/windows/wsl/) will need to be installed on your machine if running on windows machine. Alternatively, and perhaps an easier method for some, installing [Git](https://git-scm.com/downloads) and running the program using _**Git Bash**_
+
+## Usage
+Once npm finishes installing all the required node modules, the scripts are ready to go! Try filling out the necessary account info in _**scripts/< bot >/userInfo/.env.userInfo**_, then running one of the bots to see it in action.
+```node
+npm run target-bot
+```
+A full list of available scripts can be found in _**package.json**_. We recommend running one of the bot-test to ensure everything is working properly.
+
+## Test
+Running one of the bot-tests is the best way of making sure that the program is properly installed and running correctly. The bot-tests _**DO NOT**_ perform the last step - clicking the 'place order' button. Bot-tests are also a great way of making sure that your account has all the required information for a speedy checkout.
+
+When running the bot-tests, test-user information will need to be added as environment variables instead of being added to _**env.userInfo**_ file. This is the list of all test-user variable
+
+```node
+export TEST_USER_EMAIL= \
+ TEST_USER_PASSW= \
+ TEST_USER_INBOX_PASSW= \
+ TEST_USER_PHONE= \
+ TEST_USER_LOC= \
+ TEST_USER_CVV= \
+ TEST_USER_LISTING_URL= \
+```
+Use 'export' if you're on Linux or 'SET' if you're on Windows.
+
+Some environment variables are not required for all of the bot-test, such as TEST_USER_INBOX_PASSW && TEST_USER_LOC. Look inside the _**env.userInfo**_ file that pertains to the specific bot inorder to know what variables the program is expecting.
+
+We find it easier to export all of the variables, and just change the TEST_USER_LISTING_URL variable depending on what bot-tests is we expect to run.
+
+
+## Docker
+Alternatively, you can run the program inside a docker container. Use the _**Dockerfile**_ provided to make a docker image and then run it inside a docker container.
+```node
+docker build -t puppet-purchase .
+docker run -p 5901:5901 -d puppet-purchase
+```
+
+## VNC
+Use [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to look inside the container and view the process. By default it is running on port 5901. Feel free to change the default port by editing the -p flag and the _**Dockerfile**_
+```node
+# Inside Dockerfile, add this
+EXPOSE [new_port_number]
+```
+default password: puppeteer
+
+## Contributing
+Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
+
+Please make sure to update tests as appropriate.
diff --git a/src/layouts/main.astro b/src/layouts/Blog.astro
similarity index 54%
rename from src/layouts/main.astro
rename to src/layouts/Blog.astro
index b03fc15..9cea7f3 100644
--- a/src/layouts/main.astro
+++ b/src/layouts/Blog.astro
@@ -1,6 +1,8 @@
---
import '../styles/global.css';
+import SideNav from '../components/SideNav.astro';
+
const props = Astro.props;
---
@@ -19,8 +21,16 @@ const props = Astro.props;