framework-version #1

Merged
popmopo merged 2 commits from framework-version into main 2026-07-11 21:38:21 +00:00
58 changed files with 7527 additions and 386 deletions

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

5
AGENTS.md Normal file
View File

@ -0,0 +1,5 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

1
CLAUDE.md Normal file
View File

@ -0,0 +1 @@
@AGENTS.md

View File

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

View File

@ -0,0 +1,28 @@
import Image from "next/image";
import shrimp3D from "./shrimp.png";
export default function Banner() {
return (
<section className="w-full flex bg-tangerine-dream-shrimp items-center justify-center md:gap-[30px] gap-[0] text-3xl text-space-shrimp-blue py-3 lg:px-25 px-5">
<Image
loading="eager"
src={shrimp3D}
alt="3D modeled shrimp"
width={774}
height={605}
className="md:w-[150px] w-[75px] h-auto"
/>
<h1 className="w-fit text-nowrap md:text-5xl text-2xl">
SHRIMP SQUAD
</h1>
<Image
loading="eager"
className="transform-[scaleX(-1)] md:w-[150px] w-[75px] h-auto"
src={shrimp3D}
alt="3D modeled shrimp"
width={774}
height={605}
/>
</section>
);
}

View File

Before

Width:  |  Height:  |  Size: 355 KiB

After

Width:  |  Height:  |  Size: 355 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -0,0 +1,17 @@
import Image from "next/image";
import heroShrimp from "./hero-shrimp.png";
export default function HeroShrimp() {
return (
<section className="w-full h-auto flex items-center justify-center w-full bg-apricot-shrimp">
<Image
loading="eager"
src={heroShrimp}
alt="photo of three gold shrimp on rocks underwater"
width={2400}
height={742}
className="w-full h-auto"
/>
</section>
);
}

View File

@ -0,0 +1,41 @@
import { useState } from "react";
import { createPortal } from "react-dom";
import { ShrimpRain } from "./shrimp-rain";
export default function SeafoodButton() {
const [showShrimpOverlay, setShowShrimpOverlay] = useState(false);
// set maxShrimp based on image size so not to overflow
const maxShrimp = 83;
const shrimpRainValues: number[] = [];
for (let i = 0; i < maxShrimp; i++) {
shrimpRainValues.push(Math.floor(Math.random() * 200));
}
function itsRainingShrimp() {
setShowShrimpOverlay(true);
// wait until after the animation plays to make the shrimp disappear 🪄
setTimeout(() => {
setShowShrimpOverlay(false);
}, 2900);
}
return (
<>
<button
className="cursor-[unset] bg-space-shrimp-blue text-tangerine-dream-shrimp p-[20px] mt-[10px] w-full rounded-xl border-transparent border-2 hover:border-ashy-shrimp shadow-lg/40"
type="button"
onClick={() => itsRainingShrimp()}
>
Dive into Seafood Delights
</button>
{showShrimpOverlay &&
createPortal(
<ShrimpRain randomValues={shrimpRainValues} />,
document.body
)}
</>
);
}
//todo nice to have: cooler button hover state - dancing shrimps

View File

@ -0,0 +1,16 @@
import SeafoodButton from "./seafood-button";
export default function SeafoodDelights() {
return (
<section className="shrimp-info w-full bg-cherry-shrimp py-[10px] lg:px-25 px-5">
<div className="text-space-shrimp-blue text-center">
<p className="font-bold">
We are Shrimp Squad and we make things.
</p>
There's no project we can't mantis punch. Shrimply take a look
at what we're known for.
</div>
<SeafoodButton />
</section>
);
}

View File

@ -0,0 +1,32 @@
import Image from "next/image";
import Shrimp from "./shrimp.png";
export function ShrimpRain({ randomValues }: { randomValues: number[] }) {
const maxWidthToShrimp = randomValues.length;
const shrimpImagesArray = Array.from(Array(maxWidthToShrimp).keys());
const shrimpImagesArrayElements = shrimpImagesArray.map((index) => {
const left = "left-[" + (index + 1) + "%]";
const bottom = "bottom-[" + randomValues[index] + "%]";
return (
<Image
key={index}
className="w-[15%] h-auto absolute animate-shrimply-rain"
src={Shrimp}
alt="3D modeled shrimp"
width={774}
height={605}
style={{
left: +index + 1 + "%",
bottom: randomValues[index] + "%",
}}
/>
);
});
return (
<div className="fixed w-full h-full overflow-hidden">
{shrimpImagesArrayElements}
</div>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Discord-Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 126.644 96"><defs><style>.cls-1{fill:#5865f2;}</style></defs><path id="Discord-Symbol-Blurple" class="cls-1" d="M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 14 MiB

After

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

View File

@ -0,0 +1,24 @@
import Image from "next/image";
import danceShrimp from "../assets/dance-shrimp-dance.gif";
export default function DancingShrimps() {
const shrimpArray = Array.from(Array(20).keys());
const shrimpArrayElements = shrimpArray.map((index) => (
<Image
key={index}
className="w-[150px] h-auto"
src={danceShrimp}
alt="dancing 3D modeled shrimp"
width={910}
height={530}
/>
));
return (
<div className="flex flex-wrap justify-between py-5 bg-apricot-shrimp">
{shrimpArrayElements}
</div>
);
}
//todo try out one line of shrimp only that change size

View File

@ -0,0 +1,82 @@
import Image from "next/image";
import shrimp3D from "./assets/shrimp.png";
import discordSymbol from "./assets/Discord-Symbol-Blurple.svg";
import linkedInSymbol from "./assets/LI-In-Bug.png";
import mediawikiSymbol from "./assets/mediawiki.png";
import DancingShrimps from "./dancing-shrimps/dancing-shrimps";
export default function ShrimpFeet() {
const currentYear = new Date().getFullYear();
return (
<section>
<div className="flex md:flex-row flex-col items-center lg:gap-10 gap-5 justify-center py-5 lg:px-25 px-4 bg-ashy-shrimp text-space-shrimp-blue">
<div className="flex items-center">
<Image
src={shrimp3D}
alt="3D modeled shrimp"
width={774}
height={605}
className="w-[150px] h-auto"
/>
<div>
<p className="font-bold text-cherry-shrimp text-xl">
Making games should be fun
</p>
<p>Shrimp Squad Inc.</p>
<a
href="mailto:contact@shrimpsquad.ca"
className="underline cursor-[unset] hover:font-bold"
>
contact@shrimpsquad.ca
</a>
<p>© {currentYear}</p>
</div>
</div>
<div className="flex gap-5 justify-center items-center">
<a
href="https://discord.gg/RVhc27mbAc"
target="_blank"
className="cursor-[unset]"
>
<Image
src={discordSymbol}
alt="discord symbol"
width={150}
height={150}
className="w-[48px] h-auto"
/>
</a>
<a
href="https://dev.shrimpsquad.ca/"
target="_blank"
className="cursor-[unset]"
>
<Image
src={mediawikiSymbol}
alt="discord symbol"
width={135}
height={135}
className="w-[48px] h-auto"
/>
</a>
<a
href="https://www.linkedin.com/company/shrimp-squad-inc/"
target="_blank"
className="cursor-[unset]"
>
<Image
src={linkedInSymbol}
alt="linkedIn symbol"
width={635}
height={540}
className="w-[48px] h-auto"
/>
</a>
</div>
</div>
<DancingShrimps />
</section>
);
}
//todo get centered shrimp image

View File

@ -0,0 +1,6 @@
import ProjectContent from "./project-content";
import { ProjectImageProps, ProjectContentProps } from "../types";
export { ProjectContent };
export type { ProjectImageProps, ProjectContentProps };

View File

@ -0,0 +1,33 @@
import Image from "next/image";
import { ProjectContentProps } from "./";
export default function ProjectContent(projectContent: ProjectContentProps) {
return (
<section className="flex flex-col items-center w-full pt-[10px]">
<div className="flex flex-col xl:flex-row justify-between gap-[10px] *:basis-[32%] [&>div]:bg-tangerine-dream-shrimp">
<Image
src={projectContent.images.left.src}
alt=""
width={2000}
height={2000}
className="w-full xl:w-[30%] h-auto"
/>
<div className="p-[40px]">{projectContent.children}</div>
<Image
src={projectContent.images.right.src}
alt=""
width={2000}
height={2000}
className="w-full xl:w-[30%] h-auto"
/>
</div>
<Image
src={projectContent.images.central.src}
alt=""
width={2000}
height={2000}
className="w-full h-auto xl:mt-[15px] mt-[10px]"
/>
</section>
);
}

View File

@ -0,0 +1,23 @@
export default function BiotamaText() {
return (
<div>
<p className="mb-2">
<span className="font-bold">Biotama</span> is a game where
players attempt to convert wastelands into thriving ecosystems.
</p>
<p className="mb-2">
The player starts with a "Mother Tree" which acts as the core
component of the player's ecosystem. Trees grow roots that can
connect together, allowing them to communicate and send
resources between each other. Mycelial networks function
similarly for fungi.
</p>
<p>
Biotama aims to be educational as well as fun. It will feature
real-world species with tooltips showing fun facts about those
species. We are consulting with experts in biology where
necessary to ensure accuracy to the real world.
</p>
</div>
);
}

View File

@ -0,0 +1,29 @@
export default function HackThePlanetText() {
return (
<div className="h-full grid grid-cols-1 grid-row-2">
<div>
<p className="mb-2">
A game by Shrimp Squad Studios made for the Epic MegaJam!
</p>
<p className="mb-2">
One week to make a game and this is what we made! A game
based on the movie Hackers.
</p>
<p className="mb-2">
Your goal is to hack the Gibson computer and collect the
garbage file. Which will then in turn let you
<span className="font-bold"> HACK THE PLANET!</span>
</p>
</div>
<div className="mt-[16px] mb-[16px] bg-space-shrimp-blue p-[15px] size-fit rounded-md self-end">
<a
className="animate-blink border-solid border-r-[2px] border-ashy-shrimp text-[24px] text-ashy-shrimp cursor-[unset]"
href="https://megsum.itch.io/hack-the-planet"
target="_blank"
>
&gt;&gt; Try it out!
</a>
</div>
</div>
);
}

View File

@ -0,0 +1,31 @@
import { ProjectListProps } from "../types";
export default function ProjectList({
projects,
handleProjectClick,
}: {
projects: ProjectListProps[];
handleProjectClick: any;
}) {
const projectList = projects.map((project) => (
<button
key={project.id}
className={
(project.selected
? "text-shadow-[4px_3px_0_var(--color-cherry-shrimp)]"
: "") +
" hover:[text-decoration-line:underline_overline] hover:decoration-ashy-shrimp cursor-[unset]"
}
onClick={() => handleProjectClick(project.id)}
>
{project.name}
</button>
));
return (
<section className="flex gap-[20px] justify-evenly py-[10px] text-tangerine-dream-shrimp text-2xl">
{projectList}
</section>
);
}
//todo nice to have: border-image on hover would be cool

View File

@ -0,0 +1,35 @@
import { useState } from "react";
import ProjectList from "./project-list/project-list";
import ProjectContent from "./project-content/project-content";
import {
getCurrentProjectContent,
getProjectList,
} from "../../lib/project-content/getShrimps";
export default function ShrimpProjects() {
const [project, setProject] = useState("biotama");
const [projectContent, setProjectContent] = useState(
getCurrentProjectContent(project)
);
const [projectList, setProjectlist] = useState(getProjectList(project));
const handleProjectClick = (newProject: string) => {
setProject(newProject);
setProjectlist(getProjectList(newProject));
setProjectContent(getCurrentProjectContent(newProject));
};
const projectListProps = {
projects: projectList,
handleProjectClick: handleProjectClick,
};
return (
<section className="bg-space-shrimp-blue pb-5 lg:px-25 px-5 wave-border">
<ProjectList {...projectListProps} />
<ProjectContent {...projectContent}>
{projectContent.content}
</ProjectContent>
</section>
);
}

View File

@ -0,0 +1,25 @@
import { StaticImageData } from "next/image";
import { ReactNode } from "react";
export type ProjectImageProps = {
src: StaticImageData;
alt: string;
};
export type ProjectImages = {
left: ProjectImageProps;
right: ProjectImageProps;
central: ProjectImageProps;
};
export type ProjectContentProps = React.PropsWithChildren<{
name: string;
content: ReactNode;
images: ProjectImages;
}>;
export type ProjectListProps = {
id: string;
name: string;
selected: boolean;
};

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

53
app/globals.css Normal file
View File

@ -0,0 +1,53 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-space-shrimp-blue: #2c2c54;
--color-cherry-shrimp: #a40e4c;
--color-ashy-shrimp: #acc3a6;
--color-apricot-shrimp: #f5d6ba;
--color-tangerine-dream-shrimp: #f49d6e;
}
@utility wave-border {
border-image: url("lib/waves-border.png") 27 fill / 35px / 25px 0 0 0 round;
position: relative;
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
cursor: url("lib/cursors/shrimp_cursor.png"), auto;
}
@theme {
--animate-blink: blink-border 0.75s step-end infinite;
@keyframes blink-border {
from,
to {
border-color: transparent;
}
50% {
border-color: var(--ashy-shrimp);
}
}
--animate-shrimply-rain: rain-down 3s linear 1;
@keyframes rain-down {
0% {
transform: translateY(0);
}
100% {
transform: translateY(200vh);
}
}
}

33
app/layout.tsx Normal file
View File

@ -0,0 +1,33 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Dive into Seafood Delights",
description: "It's shrimp",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
</html>
);
}

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 MiB

After

Width:  |  Height:  |  Size: 4.7 MiB

View File

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

Before

Width:  |  Height:  |  Size: 983 KiB

After

Width:  |  Height:  |  Size: 983 KiB

View File

Before

Width:  |  Height:  |  Size: 950 KiB

After

Width:  |  Height:  |  Size: 950 KiB

View File

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 242 KiB

View File

@ -0,0 +1,17 @@
import { projects } from "./shrimpjects";
export function getCurrentProjectContent(project: string) {
return {
name: projects[project].name,
content: projects[project].content,
images: projects[project].images,
};
}
export function getProjectList(currentProject: string) {
return Object.keys(projects).map((key) => ({
id: key.toString(),
name: projects[key].name,
selected: key === currentProject,
}));
}

View File

@ -0,0 +1,74 @@
import { StaticImageData } from "next/image";
import { ReactNode } from "react";
import biotamaCentral from "./assets/biotama1.png";
import biotamaLeft from "./assets/biotama2.png";
import biotamaRight from "./assets/biotama3.png";
import htpCentral from "./assets/htp3.png";
import htpLeft from "./assets/htp1.png";
import htpRight from "./assets/htp2.png";
import BiotamaText from "@/app/components/shrimp-projects/project-descriptions/biotama";
import HackThePlanetText from "@/app/components/shrimp-projects/project-descriptions/htp";
type ProjectImage = {
src: StaticImageData;
alt: string;
};
type ProjectImages = {
left: ProjectImage;
right: ProjectImage;
central: ProjectImage;
};
type ProjectContent = {
name: string;
content: ReactNode;
images: ProjectImages;
};
export type Project = {
[key: string]: ProjectContent;
};
export const projects: Project = {
biotama: {
name: "BIOTAMA",
content: <BiotamaText />,
images: {
left: {
src: biotamaLeft,
alt: "mother tree with a river and cliffs in the background",
},
right: {
src: biotamaRight,
alt: "inside of an old brick house looking out the door onto a path leading to a bridge",
},
central: {
src: biotamaCentral,
alt: "top down view of the mother tree and greenery",
},
},
},
htp: {
name: "HACK THE PLANET",
content: <HackThePlanetText />,
images: {
left: {
src: htpLeft,
alt: "visual puzzle with different colours",
},
right: {
src: htpRight,
alt: "the player character standing surrounded by various text characters",
},
central: {
src: htpCentral,
alt: "top down camera view of a black screen with hex codes randomly placed",
},
},
},
};
//todo add new images for biotama
//todo use image components instead of properties

View File

Before

Width:  |  Height:  |  Size: 888 B

After

Width:  |  Height:  |  Size: 888 B

26
app/page.tsx Normal file
View File

@ -0,0 +1,26 @@
"use client";
import Banner from "./components/banner/banner";
import HeroShrimp from "./components/hero-shrimp/hero-shrimp";
import SeafoodDelights from "./components/seafood-delights/seafood-delights";
import ShrimpFeet from "./components/shrimp-feet/shrimp-feet";
import ShrimpProjects from "./components/shrimp-projects/shrimp-projects";
export default function Home() {
return (
<div>
<Banner />
<SeafoodDelights />
<HeroShrimp />
<ShrimpProjects />
<ShrimpFeet />
</div>
);
}
/* todo list
- more shrimpy font
- shrimp profiles (about us)
- menu i guess, hamburger, but the lines are waves
- animations
- shirmp cursor for hover - colour swap
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

18
eslint.config.mjs Normal file
View File

@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;

View File

@ -1,59 +0,0 @@
<!DOCTYPE html>
<html lang="en-CA">
<head>
<title>Dive into Seafood Delights</title>
<link rel="icon" type="image/x-icon" href="./shrimpmoji.ico">
<link rel="stylesheet" href="shrimpy-styles.css"/>
<script type="module">
import { getProjectData, itsRainingShrimp} from "./shrimply-the-best.js"
window.getProjectData = getProjectData;
window.itsRainingShrimp = itsRainingShrimp;
</script>
</head>
<body>
<div id="shrimply-the-rain"></div>
<section class="we-are-shrimp-squad">
<img src="assets/shrimp.png"/>
<h1>SHRIMP SQUAD</h1>
<img class="flip" src="assets/shrimp.png"/>
</section>
<section>
<div class="shrimp-info">
<div> We are Shrimp Squad and we make things. There's no project we can't mantis punch. Shrimply take a look at what we're known for.</div>
<button id="seafoodDelightsBtn" type="button">Dive into Seafood Delights</button>
</div>
</section>
<section class="shrimp-hero">
<img src="assets/hero-shrimp.png"/>
</section>
<section class="shrimp-projects">
<section class="shrimp-project-list">
<div id='biotama'>BIOTAMA</div>
<div id='htp'>HACK THE PLANET</div>
</section>
<section id="shrimp-project-content">
<div class="upper">
<img id="image-left" class="smol-image"/>
<div id="project-content"></div>
<img id="image-right" class="smol-image"/>
</div>
<img id="image-central"/>
</section>
</section>
<section class="footer">
<div id="shrimp-gif"></div>
</section>
</body>
</html>
<!--
todo list
- more shrimpy font
- shrimp profiles (about us)
- menu i guess, hamburger, but the lines are waves
- animations
- shirmp cursor for hover
- clean up click handling
-->

7
next.config.ts Normal file
View File

@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

6710
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "shrimp-squad-site",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"next": "16.2.4",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.4",
"prettier": "3.8.3",
"tailwindcss": "^4",
"typescript": "^5"
}
}

7
postcss.config.mjs Normal file
View File

@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

10
prettier.config.ts Normal file
View File

@ -0,0 +1,10 @@
// prettier.config.ts, .prettierrc.ts, prettier.config.mts, or .prettierrc.mts
import { type Config } from "prettier";
const config: Config = {
trailingComma: "es5",
tabWidth: 4,
};
export default config;

1
public/file.svg Normal file
View File

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

1
public/globe.svg Normal file
View File

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
public/next.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
public/vercel.svg Normal file
View File

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

1
public/window.svg Normal file
View File

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

View File

@ -1,32 +0,0 @@
export const projects = {
"biotama":{
content:
`<p><span class="bold">Biotama</span> is a game where players attempt to convert wastelands into thriving ecosystems.</p>
<p>The player starts with a "Mother Tree"
which acts as the core component of the player's ecosystem.
Trees grow roots that can connect together,
allowing them to communicate and send resources between each other.
Mycelial networks function similarly for fungi. </p>
<p>Biotama aims to be educational as well as fun.
It will feature real-world species with tooltips showing fun facts about those species.
We are consulting with experts in biology where necessary to ensure accuracy to the real world.</p>
`,
images: {
left: {src:"biotama2.png",alt:"mother tree with a river and cliffs in the background"},
right: {src:"biotama3.png",alt:"inside of an old brick house looking out the door onto a path leading to a bridge"},
central: {src:"biotama1.png",alt:"top down view of the mother tree and greenery"},
},
},
"htp":{
content: `<p>A game by Shrimp Squad Studios made for the Epic MegaJam!</p>
<p>One week to make a game and this is what we made! A game based on the movie Hackers.</p>
<p>Your goal is to hack the Gibson computer and collect the garbage file.
Which will then in turn let you <span class="bold">HACK THE PLANET!</span> </p>
<div class='cta-wrapper'><a class='cta' href='https://megsum.itch.io/hack-the-planet'> >> Try it out!</a></div>`,
images: {
left: {src:"htp1.png",alt:"visual puzzle with different colours"},
right: {src:"htp2.png",alt:"the player character standing surrounded by various text characters"},
central: {src:"htp3.png",alt:"top down camera view of a black screen with hex codes randomly placed"},
},
},
}

View File

@ -1,60 +0,0 @@
import { projects } from "./shrimpjects.js";
export function getProjectData(project){
const leftImage = document.getElementById("image-left");
const rightImage = document.getElementById("image-right");
const centralImage = document.getElementById("image-central");
const projectContent = document.getElementById("project-content");
const projectData = projects[project];
projectContent.innerHTML = projectData.content;
const assetPath = "assets/"
leftImage.src = assetPath + projectData.images.left.src;
leftImage.alt = "altleft";
rightImage.src = assetPath + projectData.images.right.src;
centralImage.src = assetPath + projectData.images.central.src;
return;
}
export function clearSelectedProjectClass() {
document.getElementById("biotama").classList.remove("selected-project");
document.getElementById("htp").classList.remove("selected-project");
}
export function createShrimpFooter() {
const footer = document.getElementById("shrimp-gif");
footer.innerHTML = "<img src='./assets/dance-shrimp-dance.gif' alt='a shrimp dancing'>".repeat(10);
}
export function itsRainingShrimp() {
const shrimpyRain = document.getElementById("shrimply-the-rain");
// push shrimp rain to the front. It's basically an overlay
shrimpyRain.style.zIndex = 2;
var increment = 0;
var drops = "";
// maxWidthToShrimp is set based on image size so not to overflow
const maxWidthToShrimp = 83;
while (increment < maxWidthToShrimp) {
// how much you want shrimp to cover
var randomTwoHundo = (Math.floor(Math.random() * 200));
drops += '<img src="assets/shrimp.png" style="'
+ 'left: ' + increment
+ '%; bottom: ' + (randomTwoHundo) + '%;" />'
increment++;
}
shrimpyRain.innerHTML = drops;
// wait until after the animation plays to make the shrimp disappear 🪄
setTimeout(() => {
shrimpyRain.style.zIndex = -1;
shrimpyRain.innerHTML = "";
}, 2950);
}

View File

@ -1,34 +0,0 @@
import {
getProjectData,
clearSelectedProjectClass,
createShrimpFooter,
itsRainingShrimp
} from "./shrimple-functions.js";
const biotamaBtn = document.getElementById("biotama");
const htpBtn = document.getElementById("htp");
const seafoodBtn = document.getElementById("seafoodDelightsBtn");
document.addEventListener("DOMContentLoaded", function(event) {
biotamaBtn.click();
createShrimpFooter();
});
biotamaBtn.addEventListener("click", function() {
clearSelectedProjectClass();
this.classList.add("selected-project");
getProjectData("biotama");
});
htpBtn.addEventListener("click", function() {
clearSelectedProjectClass();
this.classList.add("selected-project");
getProjectData("htp");
});
seafoodBtn.addEventListener("click", function() {
itsRainingShrimp();
})
export {getProjectData, itsRainingShrimp}

View File

@ -1,201 +0,0 @@
body {
cursor: url("assets/shrimp_cursor.png"), auto;
--space-shrimp-blue: #2C2C54;
--cherry-shrimp: #A40E4C;
--ashy-shrimp: #ACC3A6;
--apricot-shrimp: #F5D6BA;
--tangerine-dream-shrimp: #F49D6E;
color: var(--space-shrimp-blue);
background: repeat url(assets/shrimp-tile.png);
background-size: 50px;
margin: 0 20px;
}
.we-are-shrimp-squad {
width:100%;
height: 50%;
background-color: var(--tangerine-dream-shrimp);
font-size:30px;
display:flex;
align-items: center;
justify-content: center;
gap: 30px;
}
.we-are-shrimp-squad img {
height:10%;
width: 10%;
}
.flip {
transform: scaleX(-1);
}
.shrimp-hero {
max-width:100%;
height:auto;
background-color: var(--apricot-shrimp);
display:flex;
align-items: center;
justify-content: center;
width:100%;
}
.shrimp-hero img {
max-width:100%;
height:auto;
vertical-align: top;
}
.shrimp-hero div.inside-container, .shrimp-info {
background-color: var(--cherry-shrimp);
padding:10px;
}
.shrimp-hero button, .shrimp-info button{
border-radius: 10px;
background-color: var(--space-shrimp-blue);
color: var(--tangerine-dream-shrimp);
padding:10px;
margin-top:10px;
width: 100%;
cursor: unset;
}
.shrimp-project-list {
padding: 10px 0;
display: flex;
gap: 20px;
justify-content: space-evenly;
border-image: url("./assets/waves-border.png") 27 fill / 35px / 25px 0 0 0 round;
position:relative;
color: var(--tangerine-dream-shrimp);
font-size: 24px;
}
.shrimp-project-list div:hover {
text-decoration: underline overline var(--ashy-shrimp);
}
.selected-project{
text-shadow: 4px 3px 0 var(--cherry-shrimp);
}
#shrimp-project-content {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
margin-top: 10px;
}
#shrimp-project-content .upper{
display: flex;
justify-content: space-between;
gap: 10px;
}
#shrimp-project-content .upper > * {
flex-basis: 32%;
}
#shrimp-project-content .upper > div{
background-color:var(--tangerine-dream-shrimp);
padding: 0 10px;
}
#shrimp-project-content .smol-image{
width: 30%;
}
#shrimp-project-content #image-central {
width: inherit;
margin-top: 15px;
}
#shrimp-gif {
display: flex;
flex-flow: row wrap;
}
#shrimp-gif > * {
width:50%;
}
#project-content{
display:flex;
flex-flow:column;
margin-top: 0;
margin-bottom: 0;
justify-content: space-between;
}
@media screen and (orientation: portrait) {
#shrimp-project-content .upper{
flex-direction: column;
gap: 15px;
}
#shrimp-project-content .smol-image{
width: 100%;
}
p {
font-size: 16px;
}
h1{
font-size: 32px;
}
}
.bold {
font-weight: bold;
}
/* buttons */
.cta-wrapper{
margin:16px 0;
background-color: var(--space-shrimp-blue);
border-radius: 5px;
padding:15px;
width:fit-content;
}
.cta-wrapper .cta {
text-decoration: none;
border-right: 2px solid var(--ashy-shrimp);
color: var(--ashy-shrimp);
font-size: 24px;
animation: blink-border .75s step-end infinite;
}
@keyframes blink-border {
from, to { border-color: transparent }
50% { border-color: var(--ashy-shrimp); }
}
/* end buttons */
/* shrimp rain animation */
#shrimply-the-rain {
height:100%;
width:100%;
overflow: hidden;
position:fixed;
z-index: -1;
}
#shrimply-the-rain > img {
animation: RainDown 3s linear 1;
position:absolute;
width:15%;
}
@keyframes RainDown {
0% {
transform: translateY(0);
}
100% {
transform: translateY(200vh);
}
}
/* end shrimp rain animation */

34
tsconfig.json Normal file
View File

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}