├── .eslintrc.json ├── .gitignore ├── Licence ├── README.md ├── components ├── ReusableStyles.jsx ├── footer.jsx └── landing.jsx ├── next-seo.config.js ├── next.config.js ├── package.json ├── pages ├── _app.jsx ├── _document.js ├── api │ └── hello.ts └── index.jsx ├── public ├── button-dots.svg ├── dots.svg ├── favicon.ico ├── figma-bg.png ├── figma-dark.svg ├── figma.svg ├── figma_icon.svg ├── overlayz.svg ├── plugin.png ├── preview.jpg ├── realvjy.svg ├── stippling-dark.svg ├── stippling.svg ├── twitter.svg └── vercel.svg ├── styles ├── Home.module.scss └── globals.scss ├── tsconfig.json └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /Licence: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022-present realvjy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | I coded this retro-looking, cool header for the landing page of my new stippling Figma plugin. It uses mouse control to create a parallax effect with a stack of images. You can use it on your project freely. 2 | 3 | --- 4 | ### Here [Stippling plugin](https://www.figma.com/community/plugin/1409794712197371392/stippling) 5 | ### original website [stippling.app](https://stippling.app) 6 | -------------------------------------------------------------------------------- /components/ReusableStyles.jsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import styled from "styled-components"; 3 | 4 | export const Container = styled.div` 5 | position: relative; 6 | align-items: center; 7 | justify-content: center; 8 | width: 900px; 9 | padding: 0px; 10 | margin: 0 auto; 11 | @media screen and (max-width: 600px) { 12 | width: 100%; 13 | overflow-x: hidden; 14 | } 15 | `; 16 | -------------------------------------------------------------------------------- /components/footer.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | 3 | import styled from "styled-components"; 4 | import Link from "next/link"; 5 | 6 | export default function Footer() { 7 | return ( 8 |
9 |
10 | 11 | made by 12 | 13 | 14 | 15 | 16 | 17 | at 18 | 19 | 20 | @overlayz 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 | ); 32 | } 33 | 34 | const Wrapper = styled.div` 35 | display: flex; 36 | justify-content: center; 37 | margin-top: 30px; 38 | padding: 40px 0; 39 | font-size: 16px; 40 | letter-spacing: -0.2px; 41 | font-weight: 500; 42 | width: 100%; 43 | color: rgba(255, 255, 255, 0.8); 44 | gap: 4px; 45 | align-items: center; 46 | span { 47 | padding-inline: 5px; 48 | font-weight: 500; 49 | .img-r { 50 | transform: scale(1.2); 51 | } 52 | a { 53 | text-decoration: none; 54 | color: rgba(255, 255, 255, 1); 55 | opacity: 0.9; 56 | &:hover { 57 | opacity: 1; 58 | } 59 | } 60 | &.img { 61 | padding: 0; 62 | } 63 | } 64 | `; 65 | -------------------------------------------------------------------------------- /components/landing.jsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | import styled from "styled-components"; 4 | import React, { useState, useEffect, useRef } from "react"; 5 | import { Container } from "./ReusableStyles"; 6 | import Footer from "./footer"; 7 | 8 | export default function Landing() { 9 | const [position, setPosition] = useState({ x: 1, y: 1 }); 10 | const [isLoaded, setIsLoaded] = useState(false); 11 | const containerRef = useRef(null); 12 | const intensity = 4; 13 | useEffect(() => { 14 | const handleMouseMove = (e) => { 15 | if (!containerRef.current) return; 16 | 17 | const { left, top, width, height } = 18 | containerRef.current.getBoundingClientRect(); 19 | const x = (e.clientX - left) / width - 0.5; 20 | const y = (e.clientY - top) / height - 0.5; 21 | 22 | setPosition({ x, y }); 23 | }; 24 | 25 | window.addEventListener("mousemove", handleMouseMove); 26 | 27 | const timer = setTimeout(() => setIsLoaded(true), 100); 28 | 29 | return () => { 30 | window.removeEventListener("mousemove", handleMouseMove); 31 | clearTimeout(timer); 32 | }; 33 | }, []); 34 | 35 | const getImageStyle = (multiplier) => ({ 36 | transform: `translate(${position.x * multiplier * intensity}px, ${ 37 | position.y * multiplier * intensity 38 | }px)`, 39 | transition: isLoaded ? "transform 0.1s ease-out" : "none", 40 | opacity: isLoaded ? 1 : 0, 41 | }); 42 | 43 | const mainImageStyle = getImageStyle(15); 44 | const shadowImageStyle = getImageStyle(25); 45 | const dotsImageStyle = getImageStyle(5); 46 | return ( 47 | 48 | 49 | 50 | 51 | Main 57 | Main 63 | Main 69 | Shadow 75 | 80 | 81 | 82 | 83 | 84 | Install Now 85 | 86 | 87 |