3D Ascii Logo on your websites
Tags: react, webdev, beginners, tutorial
Published: 2024-04-02 07:03:01

Hi, I'm writing this as tutorial to turn your logo into a cool ascii 3d mesh you can use on your own website.
Here's what we're trying to do [Ascii](https://ascii-logo.vercel.app/).
To achieve this I'll be using React, react three/fiber and typescript on the coding portion and Blender for the 3d editing portion.
You can check everything at my [Git](https://github.com/Arteiro07/ascii-logo) where you can see the finished code and download the 3D should you wish to use mine.

## Getting Started

Start by creating a clean react project, in this case I'm using next.js but that isn't really relevant use whatever you usually use.
After that install both react three fiber and react three fiber drei to be able to use 3d elemnts on your website, on this tutorial I won't go into details on react three fiber and three js there are other materials out there that explain them better, that being said you can use this tutorial without much knowledge of what's happening behind the scenes and decide after if 3d in the web is something you want to pursue further.

```
npm install three @types/three @react-three/fiber
npm install @react-three/drei
```

Next we create our Canvas

``` tsx
"use client";
import Scene from "@/components/Scene";
import { Canvas } from "@react-three/fiber";

export default function Home() {
	return (
		<Canvas>
			<Scene />
		</Canvas>
	);
}

```
Inside Canvas I call Scene a component where I create we instantiate our 3d meshes. By default Canvas has width and height of 100%. So to make it span across the screen and add a background I use this CSS.

```css
body {
	background: rgb(13, 10, 11);
	background: linear-gradient(
		300deg,
		rgba(13, 10, 11, 1) 0%,
		rgba(0, 159, 194, 1) 100%
	);
	width: 100vw;
	height: 100vh;
	margin: 0;
	padding: 0;
	position: relative;
}

```
Once our Canvas is setup and covering the screen time to create our Scene component, to start let's create a red cube.
I also add OrbitControls to our scene so you can play around with the cube and enjoy the "3d" effect on your website. 

```tsx
import { OrbitControls } from "@react-three/drei";

export default function Scene() {
	return (
		<>
			<OrbitControls />
			<mesh scale={2}>
				<boxGeometry />
				<meshBasicMaterial color={"blue"} />
			</mesh>
		</>
	);
}

```

## Create your 3D Logo

There are several ways to convert your logo or whatever you're trying to display into 3D,

- The easiest way might be to use a tool like https://banger.show/tools/image-to-3d.
- You can just download a 3d file online if it's something common that other people might've made already.
- You can use cad a software, especially easy for orthogonal shapes.
- Or some other 3D sculpting software like blender.

Assuming you didn't use the first tool it's important you export your 3d object as a .GLtf or .GLB file.

##Display you new 3D Logo on your website


There are other ways to import 3D objects into your code, but I found that using GLTFJSX takes care of everything automatically.
So import your object into your public folder and then run
`npx gltfjsx "public/Model.glb" -o "components/Model.tsx" -t --transform`
you can also use their tool online at https://gltf.pmnd.rs/ where you can better understand how the system works.

Replace "public/model.glb" with the path to your 3D object the same the "components/Model.tsx" to wherever you want your component to end up, --tranform is used to prepare your file for display online but it's not necessary and -t is used for typescript ignore in case you prefer vanilla js.

This should output a component like this:

```tsx
import { useGLTF } from "@react-three/drei";
import React from "react";
import * as THREE from "three";
import { GLTF } from "three-stdlib";

type GLTFResult = GLTF & {
	nodes: {
		["65e0f86b14b5e75ad0ee8b07"]: THREE.Mesh;
		["65e0f86b14b5e75ad0ee8b07001"]: THREE.Mesh;
		["65e0f86b14b5e75ad0ee8b07002"]: THREE.Mesh;
	};
	materials: {
		ID9: THREE.MeshStandardMaterial;
		ID16: THREE.MeshStandardMaterial;
		ID23: THREE.MeshStandardMaterial;
	};
};

type ContextType = Record<
	string,
	React.ForwardRefExoticComponent<JSX.IntrinsicElements["mesh"]>
>;

export function Ascii(props: JSX.IntrinsicElements["group"]) {
	const { nodes, materials } = useGLTF("/ascii-transformed.glb") as GLTFResult;
	return (
		<group {...props} dispose={null}>
			<mesh
				geometry={nodes["65e0f86b14b5e75ad0ee8b07"].geometry}
				material={materials.ID9}
			/>
			<mesh
				geometry={nodes["65e0f86b14b5e75ad0ee8b07001"].geometry}
				material={materials.ID16}
			/>
			<mesh
				geometry={nodes["65e0f86b14b5e75ad0ee8b07002"].geometry}
				material={materials.ID23}
			/>
		</group>
	);
}

useGLTF.preload("/ascii-transformed.glb");
```
You'll find your goup nodes and materials will difer as your object might not be the same as mine nontheless shoud be similar, You might want to check the paths used, change the names of the component and delete the animations.
Then just replace your mesh in Scene.tsx for your model.

```tsx
export default function Scene() {
	return (
		<>
			<OrbitControls />
			<Ascii />
		</>
	);
}
```
## Blender convert your 3D logo to ascii

Depending on your experience with Blender this step might be more complicated.
First select your objects and use "S" and scale the objects close to a meter in size then use "ctrl+A" to apply the new scale.
Secondly eleminate all elements already present and importe you're own then apply a modifier, wrench bottom right, and add a new geometry nodes. You should get a split screen like this

![Split screen top 3d objcts, bottom 2 nodes group input to group output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffvacq0kzfzjmwuuux2d.png)

This is what geometry nodes is all about group input, our mesh, to group output our mesh transformed. Inbetween we add the necessary functions to achieve our desired effect, bellow I'm going to add the completed diagram you can simply copy and edit to your liking, that said I will explain each block if you want to understand and maybe change a few things.
To add a block simply use shift+a and type the name of the block and drag the lines.

![Our effect applied on blender](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ghgtgk9laz2i5ukrezty.png)


![Geometry nodes blocks of a converter to ascii](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5s6vzlq5hr166mhn6rc.png)

- Subdivide the mesh, it adds resolution to the mesh by divide faces or edges into smaller units.
- Mesh to points, convert your mesh into points.
- Instance on points, create an instance in each of the points we created previously.
- String, where we decide which characters to use on our ascii effect.
- String to curves, gives mass to the characters created previously.Choose the size you want for each character here.
- Fill curve fill the curves.
- Random value, choose integer and make it's possible values between 0 and lenth of your sting-1, allows you to randomly select a character from the "string".
- Random value, choose boolean add randomness vary probability to skip some points.
- Rotate instances, choose a rotation you think looks best.

Change and choose your variables to best fit your desired effect careful when subdividing the mesh a bigger value might be too hard on your pc and shutdown blender.

Select your objects and export them as gltf/glb, doesn't really matter which, make sure you click "apply transforms" before exporting.


## Repeat step 3
Basically repeat step 3 and test configurations

Add this to your component if you want to add a simple rotation effect

```tsx
	const groupRef = useRef<THREE.Group>(null);

	useFrame(() => {
		// Rotate the group (or any other object) continuously
		if (groupRef.current) {
			groupRef.current.rotation.z += 0.005;
		}
	});
	return (
		<group {...props} ref={groupRef} dispose={null}>
...
```

you can also change camera position by adding a prop to canvas
`		<Canvas camera={{ position: [0, 0, 8], fov: 35 }}>`


Should you like to know more feel free to comment or contact me at [The Analogue Code Company](analoguecode.com)