feat: name animation

Signed-off-by: Ameya Shenoy <shenoy.ameya@gmail.com>
This commit is contained in:
Ameya Shenoy 2025-06-08 19:55:32 +05:30
parent f12356ae66
commit d385af6afe
12 changed files with 320 additions and 8 deletions

View file

@ -12,6 +12,7 @@
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"gsap": "^3.13.0",
"lucide-react": "^0.511.0",
"matter-js": "^0.20.0",
"next": "15.3.3",

View file

@ -13,6 +13,7 @@
"@radix-ui/react-slot": "^1.2.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"gsap": "^3.13.0",
"lucide-react": "^0.511.0",
"matter-js": "^0.20.0",
"next": "15.3.3",

View file

@ -0,0 +1,24 @@
import { GetStaticPaths, GetStaticProps } from "next";
import { getMarkdownContent } from "@/lib/markdown";
export default async function BlogPost() {
const content = await getMarkdownContent(`docker_primer.md`);
return (
<main className="flex items-center justify-center h-screen">
<div className="w-[95vw]" dangerouslySetInnerHTML={{ __html: content }} />
</main>
);
}
// export const getStaticPaths: GetStaticPaths = async () => {
// // Here you would fetch the list of markdown files to create paths
// const paths = [{ params: { slug: "example" } }]; // Example path
// return { paths, fallback: false };
// };
//
// export const getStaticProps: GetStaticProps = async ({ params }) => {
// console.log(params?.slug);
// const content = await getMarkdownContent(`docker_primer.md`);
// return { props: { content } };
// };

View file

@ -0,0 +1,178 @@
---
title: Docker Primer
date: 2018-02-13T13:56:12-05:00
tags: ["docker", "containers"]
type: Docker
summary: Docker basics to get you started
---
When we think of virtualization today, we may think of Virtual Box, which abstracts away the system processes, and lets you run a completely system from another. Think of Docker as Virtual Box, but extremely lightweight (in terms of resource consumption). Obviously I'm over simplifying the explanation a little, and a whole of things are getting lost in simplification. But for now, this will do.
## Installation
- Install docker
```shell
apt remove docker docker-engine docker.io
apt update && apt -y upgrade
apt install -y linux-image-extra-$(uname -r) linux-image-extra-virtual #FOR UBUNTU 18: apt install -y linux-image-$(uname -r) linux-image-extra-virtual
apt update && apt -y upgrade
apt install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #FOR UBUNTU 18: instead of stable use edge (just for now, since they haven't released the stable version on 18.04 yet)
apt update && apt -y upgrade
apt install -y docker-ce
```
- Install docker-compose
```shell
curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose #use the latest docker-compose version, by looking at releases on github pages [https://github.com/docker/compose/releases]https://gist.githubusercontent.com/mamigot/1abdefc684f97d3476f177d85248ff36/raw/5f57b4918b237f8e0127b45984fa51a483218349/docker-compose.yml
chmod +x /usr/local/bin/docker-compose
```
## Post Installation stuff
Allow docker usage without sudo access
The docker daemon binds to a Unix socket instead of a TCP port. By
default that Unix socket is owned by the user root and other users can
only access it using sudo. The docker daemon always runs as the root
user. To prevent using sudo when you use the docker command, create a
Unix group called docker and add users to it. When the docker daemon
starts, it makes the ownership of the Unix socket read/writable by the
docker group
```shell
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
```
## Terminology
- Images
Images are read only We upload images to hub. Think of them as classes in an object oriented programming language terminology.
- Containers
Containers boot up from images. Think of them as instances of a class.
- Tags
You can think of this as versions
- Container ID or Image ID
Unique ID assigned to every container or image respectively
## Usage
- A `Dockerfile` can be used to build docker images
- To list all images available on your system
```shell
docker images
```
- To list all containers
```shell
docker ps -a
```
- To pull images from the docker hub, for example for pulling the
ubuntu image
```shell
docker pull ubuntu
```
By default the `latest` `tag` is pulled. Consider `tag` to be sort of like the version of the image you want.
- To pull a specific tag, lets say the `tag` is `12.04`
```shell
docker pull ubuntu:12.04
```
- To delete an image
```shell
docker rmi ubuntu:latest
```
or
```shell
docker rmi IMAGE_ID
```
- To create a `container` from an `image` and run it
```shell
docker run -it ID /bin/bash
```
- `i` stands for interactive
- `t` stands for pseudo tty. It is for specifying the path to the shell to be run.
- `ID` can be an `IMAGE-ID` or a `CONTAINER-ID` obtained by listing all images, or containers respectively.
Note: Every time you use `docker run` using the IMAGE-ID, a new
container is created based on the `image`
Extra bits: If the argument `--rm` is if passed, causes the container to automatically get deleted after exiting the shell.
- To exit a container
```shell
exit
```
- To start a container
```shell
docker start CONTAINER_ID
```
- To stop a container
```shell
docker stop CONTAINER_ID
```
- To delete a container
```shell
docker rm CONTAINER_ID
```
- To build your own docker image using a `Dockerfile`. Create a `Dockerfile` and put it in a folder, and execute the following command
```shell
docker build -t username/image_name:image_tag .
```
`username` - as on hub.docker.com
`image_name` - the name of the image you want to build
`image_tag` - the tag you want to assign to the image
- To delete dangling images (unused images present on your system)
```shell
docker rmi $(docker images -f dangling=true -q)
```
- Save an existing docker container as an image
```shell
docker commit CONTAINER_ID IMAGE_NAME:IMAGE_TAG
```
- Saving an image as a tar file
```shell
docker save IMAGE_ID -o file_name.tar
```

View file

@ -1,7 +1,8 @@
export default function Blog() {
return (
<main className="flex items-center justify-center h-screen">
This is blog list page
This is blogs index page
</main>
);
}

View file

@ -4,6 +4,7 @@ import { Geist, Geist_Mono, Space_Grotesk, Space_Mono } from "next/font/google";
import "./globals.css";
import { NavigationMenu } from "@/components/Navbar";
import GSAPCursor from "@/components/CustomCircleCursor";
const geistSans = Geist({
variable: "--font-geist-sans",
@ -49,6 +50,7 @@ export default function RootLayout({
disableTransitionOnChange
>
<div className="min-h-screen">
<GSAPCursor />
<NavigationMenu />
{children}
<footer className="flex"></footer>

View file

@ -0,0 +1,45 @@
"use client";
import { useRef, useEffect, FC } from "react";
import gsap from "gsap";
const GSAPCursor: FC = () => {
const cursorRef = useRef<HTMLDivElement>(null);
// For touch devices, return null
if (typeof window !== "undefined" && "ontouchstart" in window) return null;
useEffect(() => {
// Initialize GSAP animation
let xTo = gsap.quickTo(cursorRef.current, "x", {
duration: 2,
ease: "power2.out",
});
let yTo = gsap.quickTo(cursorRef.current, "y", {
duration: 2,
ease: "power2.out",
});
const onMouseMove = (e: MouseEvent) => {
xTo(e.clientX);
yTo(e.clientY);
};
window.addEventListener("mousemove", onMouseMove);
return () => {
window.removeEventListener("mousemove", onMouseMove);
};
}, []);
return (
<div
ref={cursorRef}
className="fixed w-8 h-8 rounded-full border-2 border-dotted border-red-500 bg-transparent pointer-events-none z-50"
style={{
transform: "translate(-50%, -50%)",
}}
/>
);
};
export default GSAPCursor;

View file

@ -4,7 +4,7 @@ export function NameComponent() {
return (
<div className="flex justify-center font-[family-name:var(--font-spacegrotesk-sans)] font-semibold text-fluid tracking-tighter">
<TextScramble
firstName="Ameya"
firstName="Ameya "
lastName="Shenoy"
onlineHandleFirstName="coding"
onlineHandleLastName="coffee"

View file

@ -149,7 +149,7 @@ export function World() {
const pillsToRenderInfo = [
{ text: "ENGINEERING MANAGER" },
{ text: "PRINCIPAL ENGINEER" },
{ text: "NIX", chamferRadius: convertRemToPixels(1.25) },
{ text: "NIX *", chamferRadius: convertRemToPixels(1.25) },
{ text: "AI", chamferRadius: convertRemToPixels(1.25) },
];
@ -254,10 +254,15 @@ export function World() {
}, [resolvedTheme, dimensions]);
return (
// TODO: ask Shubh why does my name spawn at the top and then shift down
<div
ref={containerRef}
className="h-[40vh] mx-auto relative overflow-hidden"
className="h-[40vh] border-red-500 border-2"
style={{ width: `${viewportWidthPercent}vw` }}
/>
>
<div
ref={containerRef}
className="h-full w-full mx-auto relative overflow-hidden"
/>
</div>
);
}

View file

@ -1,6 +1,7 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import { useIsMobile } from "@/hooks/useIsMobile"; // Adjust the path as necessary
interface TextScrambleProps {
firstName: string;
@ -22,7 +23,7 @@ const TextScramble: React.FC<TextScrambleProps> = ({
const chars = "!<>-_\\/[]{}—=+*^?#________";
const scramble = useCallback(
(fromText: string, toText: string, setFunctiono) => {
(fromText: string, toText: string, setFunction: Function) => {
let counter = 0;
const length = Math.max(fromText.length, toText.length);
const queue = [];
@ -56,7 +57,7 @@ const TextScramble: React.FC<TextScrambleProps> = ({
if (counter >= end) complete++;
}
setFunctiono(output);
setFunction(output);
if (complete < length) {
requestAnimationFrame(update);
counter++;
@ -78,6 +79,26 @@ const TextScramble: React.FC<TextScrambleProps> = ({
}
}, [isHovering, scramble, firstName, lastName]);
const autoScramble = () => {
console.log(displayFirstName, firstName);
if (displayFirstName == firstName) {
scramble(firstName, onlineHandleFirstName, setfirstNameText);
scramble(lastName, onlineHandleLastName, setLastNameText);
} else {
scramble(displayFirstName, firstName, setfirstNameText);
scramble(displayLastNameText, lastName, setLastNameText);
}
};
const isMobile = useIsMobile();
useEffect(() => {
if (isMobile) {
const intervalID = setInterval(autoScramble, 2000);
return () => clearInterval(intervalID);
}
}, [isMobile, displayFirstName, displayLastNameText]);
return (
<div
className="group relative font-mono transition-all duration-300"

View file

@ -0,0 +1,18 @@
import { useState, useEffect } from "react";
export const useIsMobile = () => {
const [isMobile, setIsMobile] = useState<boolean>(false);
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 640); // Tailwind's mobile breakpoint
};
handleResize(); // Check on mount
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return isMobile;
};

View file

@ -0,0 +1,16 @@
// utils/markdown.ts
import fs from "fs";
import path from "path";
import { remark } from "remark";
import html from "remark-html";
const markdownDirectory = path.join(process.cwd(), "src/app/blog/content");
console.log(markdownDirectory)
export async function getMarkdownContent(fileName: string) {
const filePath = path.join(markdownDirectory, fileName);
const fileContents = fs.readFileSync(filePath, "utf8");
const processedContent = await remark().use(html).process(fileContents);
return processedContent.toString();
}