October, 18, 2023 by Andrew Farmer in 3D Printing
Several years ago, I undertook the creation of the Swarm Bot as a commissioned project destined for Trade Shows. While it initially served its purpose, the project left room for improvement, particularly in the areas of joint stability and design accuracy. In this blog post, I will outline the pragmatic evolution of the Swarm Bot, detailing challenges faced and the practical steps taken to refine its form.
Version 1 had its flaws, and a very obvious join in the middle.
Returning to the design years later, drawing on skills from my studies, hobbies, and past trials, I aimed to improve the design while staying true to the original specifications. The focus was on making the joints more robust.
The design specifications as given to me.
Designing 3D ball joints that maintain stability over time poses a unique set of challenges. Striking the right balance is crucial, as a joint slot too small risks breakage during the assembly process, while one that is too large results in a loose joint unable to support weight.
In my approach, I crafted a slot slightly undersized compared to the ball, integrating strategic slits for plastic flex. This design allows for a controlled level of flexibility, considering the limitations of printing in PLA rather than more elastic materials like TPU or Silicone. An additional consideration was the expansion of plastic under heat during the printing process, making precise measurements less than ideal.
To enhance the flexibility and adaptability of the ball joints, I made a strategic decision to incorporate slits into the ball itself. Additionally, I opted to hollow out the interior of the ball. While acknowledging that this approach inherently introduces a level of structural compromise, it serves a crucial purpose—allowing the ball to flex and fit snugly into tighter joints.
Version 4 retained this refined design but with added modularity for enhanced printing and assembly. The decision to maintain the hidden cuts, combined with a more modular structure, not only contributed to a cleaner and more visually pleasing appearance but also streamlined the manufacturing and assembly process.
In versions 3 and 4 of the Swarm Bot, the combination of PLA and transparent resin made assembly a breeze – no need for glue. Additionally, both versions feature built-in space for LED lights powered by a D battery pack inside.
The LED sits under the resin lens cap.
Following version 3, I revisited the design one last time to enhance modularity and address issues, particularly focusing on strengthening joints. The design of version 4 reflects the culmination of these efforts. The printed parts, seen here, are all set for seamless assembly.
An exploded design in Fusion360.
All parts for version 4 printed. Note the modular design.
Rendered version 4.
In concluding this journey of iterative design, from version 1 to the refined version 4, the Swarm Bot stands as a testament to the persistent pursuit of improvement. Perhaps in the future I can consider a version 5 that uses arduino motors to move.
October, 18, 2023 by Andrew Farmer in Web Development
A while ago I was tasked by a client to create a client website to advertise for their up and coming video game, Fox and Shadow.
The game's narrative unfolds in a city overrun by AI, where remnants of humanity survive in cryosleep underground, leaving a handful of scavengers to brave the polluted surface. This dystopian setting, with its cyberpunk, electronic vibe, sparked an idea to translate the game's essence into a dynamic user journey on the website.
Intrigued by the creativity of YouTube front-end developers, I envisioned a randomized 'hacking' animation for hyperlinks. This animation, seamlessly integrated into the Fox and Shadow website, needed to meet specific criteria:
Hover Interaction: When users hover over a link, the animation should play without disrupting the page layout.
Continuous Animation: The animation should persist even when the user stops hovering, creating an immersive experience.
Non-Restartable Cycle: If a user hovers over a link again before the previous cycle finishes, the animation shouldn't restart, ensuring a smooth user experience.
Single Playback: The animation should play only once during the hover event, irrespective of whether the user re-enters the event.An additional goal is to make the code easily scalable and reusable in other links.
Since we are using React, we need to set up a few important steps.
Router Configuration
Integrate the <Router> component from 'react-router-dom' to establish the context for <Link> components, enabling seamless navigation within the underlying routing system.
import { BrowserRouter as Router } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>
);
The Router component is important for setting up the context that allows <Link> to create navigation links that work with underlying routing systems. Note that <Link> doesn’t work with external links or href tags, but we will look at adapting that into our code later.
Animated Link Component
Now let’s create an animated link component that only generates the link but also manages the animation independently.
By encapsulating the link and animation logic into a dedicated component, we enhance the maintainability and scalability of our code. This approach allows us to seamlessly incorporate animated links across various sections of our application without duplicating code or sacrificing clarity.
Creating a separate component for the animated link not only adheres to best practices in React development but also aligns with the broader goal of crafting a robust, flexible, and maintainable codebase
So, let's dive into the nitty-gritty of coding this reusable animated link.
// Import necessary dependencies from React and 'react-router-dom'
import { useState } from 'react'; // component to manage state
import { Link } from 'react-router-dom'; //link from react-router-dom
// Import the AnimationHackEffect component from './animationHack.js'
import AnimationHackEffect from './animationHack.js'; // this will be our animation
// Define a functional component named AnimationLink, receiving props as parameters
const AnimationLink = ({ targetId, to, dataValue, icon, onMouseEnter, onMouseLeave, isExternal }) => {
// State variables to track animation and hover states
const [isAnimating, setIsAnimating] = useState(false);
const [isHovered, setIsHovered] = useState(false);
//targetId = css ID that will be changing.
//to = the hyperlink that will be passed to the user
//dataValue = the text to pass to the animation so it knows what to make/return to.
//Icon = if you would like to use an <i> icon before the text animation. Here I am using a Font Awesome icon.
//onMouseEnter = what to do when the mouse enters the area of text/css
//onMouseLeave = what to do when the mouse leaves the area of text/css
//isExternal = true/false Boolean to tell the component to use <Link> or <a>
// Function to handle mouse enter event
const handleMouseEnter = () => {
setIsHovered(true); //set hovered state
setIsAnimating(true); //set animation state
// Call the provided onMouseEnter function if it exists
if (onMouseEnter) {
onMouseEnter();
}
};
// Function to handle mouse leave event
const handleMouseLeave = () => {
setIsHovered(false);
};
// Conditional rendering based on whether the link is external or internal
if (isExternal) {
// External links
return (
<div className=link'
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<a
href={to} // href for external links
>
<i className={icon}></i>
</a>
<a
id={targetId} //css target ID
href={to} // href for external links
className='papercactus__socials-social_icon'
>
{dataValue} //the datavalue previously mentioned that is also passed to the animation component
//below is the AnimationHackEffect Component, this component handles all the animation logic.
<AnimationHackEffect
targetElementId={targetId} //css target ID
dataValue={dataValue}// text value that users see which is passed to the animation component
isAnimating={isAnimating} //animation is true
setIsAnimating={setIsAnimating} //setter for animation is true
/>
</a>
</div>
);
} else {
// Internal links used by React Router
return (
<div className='link'
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<Link
to={to}
>
<i className={icon}></i>
</Link>
<Link
id={targetId}
data-value={dataValue}
className='papercactus__socials-social_icon'
to={to}
>
// the data value previously mentioned that is also passed to the animation component.
{dataValue}
<AnimationHackEffect
targetElementId={targetId} //css target ID
dataValue={dataValue} //text value that is passed to the animation
isAnimating={isAnimating} //animation is true
setIsAnimating={setIsAnimating} //setter for animation is true
/>
</Link>
</div>
);
}
};
// Export the AnimationLink component as the default export
export default AnimationLink;
The AnimationLink component takes charge of generating both <Link> components and <a> tags, effectively acting as a bridge between the structure of our application and the animation logic handled by the AnimationHack component.
To ensure the seamless integration of the animation logic, a crucial decision is made using an if statement. This decision-making process evaluates the value of {isExternal}—a prop provided to the AnimationLink component. If {isExternal} is true, it signals to React that an <a> tag should be rendered.
Hack Animation Component
The animation component is the heartbeat of this project, injecting life into the static world of links. Let's craft a component that orchestrates the mesmerizing logic of our animation. In this pivotal component, we're navigating the realm of text randomization, an intricate dance set to the rhythm of intervals. Here's how we bring this animation logic to life; which updates at intervals of 30 milliseconds for 3 loops for each character that is passed down from the AnimationLinks {dataValue}.
// Import necessary hooks from the 'react' library
import { useEffect, useRef } from 'react';
// Define a functional component named 'AnimationHackEffect' that takes in props
const AnimationHackEffect = ({ targetElementId, dataValue, isAnimating, setIsAnimating }) => {
// Define the alphabet for random letter generation
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Create refs to persist values across renders
const interval = useRef(null);
const iteration = useRef(0);
// targetElementId = css ID that will be changing.
//dataValue = the text to pass to the animation so it knows what to make/return to.
//Icon = if you would like to use an <i> icon before the text animation.
// isAnimating = // true/false Boolean if its animating or not
// setIsAnimating = //setter for isAnimating
// useEffect hook: runs after every render, mimicking component lifecycle methods
useEffect(() => {
// Retrieve the target element using the provided ID
const targetElement = document.getElementById(targetElementId);
// test if the target element exists, if doesn’t exist then end.
if (!targetElement) {
console.error(`Element with ID ${targetElementId} not found`);
return; // Exit the function if the element is not found
}
// Check if animation is active, if true, begin animation sequence, one letter at a time
if (isAnimating) {
// Set up an interval to create the animation effect
interval.current = setInterval(() => {
// Modify the text content of the target element dynamically
targetElement.innerText = targetElement.innerText
.split("")
.map((letter, index) => {
// If the current index is less than the current iteration value
if (index < iteration.current) {
// Return the corresponding letter from the original dataValue
return dataValue[index];
}
// Otherwise, return a random letter from the alphabet
return letters[Math.floor(Math.random() * 26)];
})
.join("");
// Check if the iteration has reached the length of the original dataValue
if (iteration.current >= dataValue.length) {
// If so, clear the interval, reset the iteration, and signal the end of animation
clearInterval(interval.current);
iteration.current = 0;
setIsAnimating(false);
}
// Increment the iteration by 1/3 to control the animation speed
iteration.current += 1 / 3;
}, 30); // Run the interval every 30 milliseconds
}
// Cleanup function. Clear the interval when the component is unmounted or the dependencies change
return () => {
clearInterval(interval.current);
};
}, [targetElementId, dataValue, isAnimating, setIsAnimating]); // Dependency array for useEffect
// The component doesn't render anything (returns null)
return null;
};
// Export the AnimationHackEffect component as the default export
export default AnimationHackEffect;
When both components come together and call an <AnimationLink> on our App component.
<AnimationLink
targetId={'appHackLink'}
to={''}
dataValue={'Click here to connect to the cyberspace'}
/>
You can see the effect in motion.
Remember, the key is to align with your design and theme—mirroring the same nomenclature as your IDs. Using CSS, you can really bring the animation effect into the cyberspace.
As this effect comes to life, it's worth noting that the intensity might be more pronounced with longer text. Yet, with shorter text snippets, and even when adorned with an icon, it takes on a distinct ‘cyber’ vibe.
Feel free to use this code in your own projects, or modify it to your own desires.The github page can be found here.
To witness this dynamic effect firsthand, navigate to the Fox and Shadow homepage. You'll be immersed in the live showcase of these components, turning every link into a cyber-compromised link to the post-apocalyptic landscape of Fox and Shadow.