João Guerreiro Designer & Developer
Current Status:

Web Development

GIT

Tips & Tricks

Undo Unpushed Commits but Keep Changes in Working Directory

git reset --soft HEAD~n

Replace n with the number of commits you want to undo. This command will move the HEAD pointer back to the specified commit and keep your changes staged.

Clean Code

Clean Variables

Descriptive variables, i.e. todaysDate rather than d.

Clean properties: class Cat { name; age; }

rather than

class Cat { catName; catAge; }

Clean Magic Numbers

What is 120? Basically we need to ensure that we make these ‘magic’ numbers, which at the time made sense, easily understood.

function calculatePadding(element) { const headerSpacing = element.height + 120; }

function calculatePadding(element) { const toolbarHeight = 120; const headerSpacing = element.height + toolbarHeight; }

Clean Functions

Limit parameters

Having too many parameters can make functions harder to understand, maintain, and test.

function createUser(name, age, email, isAdmin) {
  ...
}

vs

function createUser(userDetails) {
  // Function logic using userDetails object properties
}

When using an object, you can encapsulate related data into a single parameter, making the function call cleaner and more readable. It also allows for flexibility in adding or modifying parameters without changing the function signature. However, it’s important to strike a balance and consider the specific context of your code. Sometimes using individual parameters may be more appropriate, especially for functions with a small number of parameters or when the parameters are unrelated.

Encapsulating Conditionals

Encapsulating conditionals refers to organizing and structuring your code in a way that isolates conditional logic within functions or modules. This approach promotes code clarity, maintainability, and reusability.

const age = 20;
if (age >= 20) {
  console.log("You are eligible to vote.");
} else {
  console.log("You are not eligible to vote yet.");
}

vs

function isEligibleToVote(age) {
  return age >= 18;
}

const age = 20;
if (isEligibleToVote(age)) {
  console.log("You are eligible to vote.");
} else {
  console.log("You are not eligible to vote yet.");
}

Cloudfare Workers

Cloudflare Workers are a serverless computing platform that runs JavaScript functions at the edge of Cloudflare’s global network. They enable developers to deploy code without managing servers, respond to HTTP requests using JavaScript, and optimize web applications for performance and security. Key benefits include low-latency responses due to edge computing and the ability to implement custom logic for routing, caching, security, and more.

Getting Started

  1. Create a new Worker project

C3 (create-cloudflare-cli) is a command-line tool designed to help you setup and deploy Workers to Cloudflare as fast as possible.

Open a terminal window and run C3 to create your Worker project:

npm create cloudflare@latest
  1. Develop with Wrangler CLI

The Workers command-line interface, Wrangler, allows you to create, test, and deploy your Workers projects. C3 will install Wrangler in projects by default.

After you have created your first Worker, run the wrangler dev command in the project directory to start a local server for developing your Worker. This will allow you to test your Worker locally during development.

npx wrangler dev
  1. Write code

With your new project generated and running, you can begin to write and edit your code.

Find the src/index.js file.

  1. Deploy your project

If you did not deploy your Worker during step 1, deploy your Worker via Wrangler, to a *.workers.dev subdomain, or a Custom Domain, if you have one configured.

npx wrangler deploy

Reference: https://developers.cloudflare.com/workers/get-started/guide/

Connecting a worker to OpenAI

  1. Install OpenAI in your Worker project
npm install openai
  1. Save OpenAI API key to your Worker’s environment
npx wrangler secret put OPENAI_API_KEY

(This can also be done/edited through the Cloudflare website admin area).

Then, also ensure that those secrets are added locally:

When developing your Worker or Pages Function, create a .dev.vars file in the root of your project to define secrets that will be used when >running wrangler dev or wrangler pages dev, as opposed to using environment variables in wrangler.toml. This works both in local and remote >development modes. The .dev.vars file should be formatted like a dotenv file, such as KEY=VALUE:

https://developers.cloudflare.com/workers/configuration/secrets/#secrets-in-development

.dev.vars

OPENAI_API_KEY=value
  1. Sample OpenAI boilerplate worker code (which also handles CORS and preflight requests)

src/index.js

import OpenAI from "openai";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type",
};

export default {
  async fetch(request, env, ctx) {
    // Handle CORS preflight requests
    if (request.method === "OPTIONS") {
      return new Response(null, { headers: corsHeaders });
    }

    const openai = new OpenAI({
      apiKey: env.OPENAI_API_KEY,
    });

    try {
      const requestData = await request.text();
      const messages = requestData ? JSON.parse(requestData) : [];

      const chatCompletion = await openai.chat.completions.create({
        model: "gpt-4",
        messages: messages,
      });
      const response = chatCompletion.choices[0].message;

      return new Response(JSON.stringify(response), { headers: corsHeaders });
    } catch (e) {
      return new Response(e, { headers: corsHeaders });
    }
  },
};

And now, the sample code for our app.

async function fetchData(data) {
  try {
    const url = "https://WORKER-URL.workers.dev";

    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify([{ role: "user", content: "Hello world." }]),
    });
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error.message);
  }
}
  1. Deploy the latest Worker changes
npx wrangler deploy

Vite

Getting Started (Vite + React + Tailwind)

  1. Create your project

Start by creating a new Vite project if you don’t have one set up already. The most common approach is to use Create Vite.

npm create vite@latest my-project -- --template react
cd my-project
  1. Install Tailwind CSS

Install tailwindcss and its peer dependencies, then generate your tailwind.config.js and postcss.config.js files.

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
  1. Configure your template paths Add the paths to all of your template files in your tailwind.config.js file.
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
  1. Add the Tailwind directives to your CSS Add the @tailwind directives for each of Tailwind’s layers to your ./src/index.css file.

index.css

@tailwind base;
@tailwind components;
@tailwind utilities;
  1. Start your build process Run your build process with npm run dev.
npm run dev

ESLint and Prettier

  1. Install ESLint

npm install eslint --save-dev

  1. Init ESLint

npx eslint --init

GSAP

Default Ease and Ease Types

In GSAP, the default ease for ease types is always “Out.” This means that for ease types like bounce, we can simply write bounce instead of bounceOut. If a different variation is needed, such as bounceIn or bounceInOut, we must specify it explicitly. The default “Out” behavior applies to all ease types, making the shorthand more convenient in most cases.

GSAP defaults to “Out” easing because it offers a natural and visually pleasing effect where the motion decelerates toward the end. This type of easing mimics real-world movement, where objects typically start with more momentum and slow down as they reach their destination (like a ball thrown in the air). By starting animations quickly and slowing them down as they complete, “Out” easing helps focus attention on the final position of the element, which is typically the most important part of an animation.

Note: If no ease property is specified, GSAP defaults to Power1.easeOut.

Understanding the each and amount Properties in GSAP’s Stagger Object

Here’s a brief summary for your journal on the each and amount properties of GSAP’s stagger object:

stagger: { each }

The each property defines the delay between the start of each animation in a sequence.

It sets a constant delay between the start of one element’s animation and the next.

gsap.to(".box", { x: 100, duration: 1, stagger: { each: 0.5 } });

This would move each .box element 100px to the right, with a 0.5-second delay between the start of each animation.

Use case: When you want consistent timing between the animations of multiple elements.

stagger: { amount }

The amount property defines the total delay spread across all animations.

Instead of setting a fixed delay like each, GSAP will automatically divide the total delay evenly among the elements.

gsap.to(".box", { x: 100, duration: 1, stagger: { amount: 2 } });

Here, if there are 4 .box elements, the 2-second delay is divided evenly, resulting in a 0.5-second delay between each.

Use case: When you want to control the overall spread of the stagger timing, but let GSAP handle the distribution across elements.

Key Difference

  • each sets a specific delay for each item.
  • amount distributes a total delay across all elements evenly.

Here’s a brief explanation of the from property in the GSAP stagger object for your journal:

The from Property in GSAP’s Stagger Object

The from property in GSAP’s stagger object controls the direction or starting point of the staggered animations. By default, staggered animations are applied sequentially from the first element to the last, but the from property allows you to specify where the stagger begins.

Possible Values:

  • "start" (default): Animations start sequentially from the first element.
  • "end": Animations start from the last element and move backward.
  • "center": Animations start from the middle element(s) and move outward toward both ends.
  • Index Number: You can also specify a numerical index, which makes animations start from that particular element and stagger outward in both directions.

Example:

gsap.to(".box", {
  x: 100,
  duration: 1,
  stagger: { each: 0.5, from: "center" },
});

In this example, the animations begin from the middle of the .box elements and stagger outward.

Use Case:

The from property is useful for adding a more dynamic and engaging visual effect, especially in cases like animating a grid of elements or when creating complex entrance animations where the order matters. It helps you control the flow of animations in different directions, enhancing the overall timing and feel.

Timeline Positioning: Absolute, Relative, and Alignment Options

The position parameter in GSAP timelines provides granular control over when each animation begins within a timeline. You can use absolute times, labels, alignment options, and relative positions to create dynamic and precise sequences. Here’s a full breakdown of each option:

Absolute Position

An absolute position starts an animation at a specific point in time on the timeline, in seconds. For example, specifying 1 as the position parameter will start the animation exactly 1 second into the timeline, regardless of other animations.

Labels

Labels are named markers in a timeline, used as reference points. You can set an animation to start at a label by specifying it as the position parameter (e.g., "labelName"). Labels help organize and control the start time of animations by providing clear, reusable markers.

Alignment Options

These options align an animation’s start relative to the previous animation’s start or end:

  • "<" (Align with Start): Begins the animation at the exact start time of the previous animation, causing an overlap.

  • ">" (Align with End): Positions the animation to start right after the previous animation ends. This is the default setting, meaning animations will naturally play one after the other in sequence if no other position parameter is provided.

  • Offset Alignment ("<+=X" or ">+=X"): Combine "<" or ">" with a specific offset for fine control:

    • "<+=X" delays the animation’s start by X seconds after the previous animation begins.
    • ">+=X" delays the start by X seconds after the prior animation finishes. This is functionally equivalent to "+=X", which also delays the start by X seconds after the previous animation ends.
    • Example: "<+=0.5" starts the animation 0.5 seconds after the previous one begins, while ">+=0.5" delays the start by 0.5 seconds after it finishes.
  • Percentage Alignment: You can also use percentages with the alignment parameter. For example, "<50%" positions the animation to start when the previous animation is 50% complete, allowing for precise synchronization based on the previous animation’s progress.

Relative Position Options

Relative positions allow an animation to start a specified time before or after the previous animation’s endpoint.

  • "+=X": Starts the animation X seconds after the previous one ends. For example, "+=1" delays the start by 1 second after the end of the last animation.
  • "-=X": Begins the animation X seconds before the previous animation ends, creating an overlap. For instance, "-=1" starts the animation 1 second before the end of the last one.

Combining Alignment and Relative Offsets

For ultimate control over timing, you can mix alignment with relative offsets:

  • "<+=X": Starts the animation relative to the beginning of the previous one, with a positive offset.
  • ">-=X": Begins the animation relative to the end of the previous one but with a negative offset, making it start slightly before the previous one finishes.

Using these absolute, label-based, alignment, relative position parameters, and percentage options, you can orchestrate animations to create seamless, dynamic sequences within a GSAP timeline.

Percent-Based Keyframes in GSAP

What Are Percent-Based Keyframes?
In GSAP, percent-based keyframes allow you to define animation states at specific percentages of the animation’s timeline. This feature provides precise control over how and when animations occur within a defined duration.

Benefits of Using Percent-Based Keyframes

  1. Granular Control Over Animations

    • You can define specific points in an animation with exact timing.
    • Example: Set a particular transformation or style change to happen exactly at 25%, 50%, or any custom percentage of the timeline.
  2. Multiple Easing Functions

    • Assign unique easing curves to different segments of the animation.
    • Example: Use ease-in for the first 25%, ease-out for the next 25%, and linear for the rest.
  3. Flexibility in Timeline Adjustments

    • Percent-based keyframes are independent of animation duration. You can easily adjust the total duration without recalculating specific points.
  4. Improved Readability and Maintenance

    • When animating complex sequences, percent-based keyframes simplify defining transitions at logical intervals instead of relying on absolute timing.
  5. Seamless Coordination of Multiple Properties

    • Animate multiple properties (e.g., opacity, transform, background-color) in parallel with synchronized keyframes, making animations more cohesive.

Example Code
Here’s a practical example in GSAP:

gsap.to(".box", {
  keyframes: [
    { x: 100, ease: "power1.in", percent: 25 },
    { y: 50, ease: "power2.out", percent: 50 },
    { rotation: 360, ease: "linear", percent: 100 },
  ],
  duration: 2,
});

Conclusion
Percent-based keyframes in GSAP are a powerful tool for creating intricate, smooth, and highly customizable animations. They allow you to focus on the “when” and “how” of your animations without being constrained by absolute timing, making your workflow more efficient and your animations more professional.