Notes on refs, frame loops, scene control, and how R3F changes frontend thinking.
In this portfolio project, I used React Three Fiber to introduce 3D expression into the website. Before I started working with it, I had the impression that React Three Fiber was something like “a convenient library that lets you use Three.js with React syntax.” And in some ways, that first impression made sense. Being able to write 3D objects directly in JSX, such as <mesh>, <ambientLight>, or <sphereGeometry>, feels very intuitive. You can place objects in 3D space while writing something that feels like React. You can split things into components. You can pass props. At least on the surface, it looks like an extension of ordinary React development. However, once I started building animations, particle effects, 3D models, and scene transitions, that impression changed quite a lot. React Three Fiber is not simply React with 3D rendering added on top. I came to see it more as a technology that brings the real-time rendering world of Three.js into React, and forces you to think carefully about how to handle the boundary between the two. In ordinary React development, we usually split the UI into components, manage state with state and props, and build interfaces declaratively. For buttons, forms, cards, modals, lists, and page layouts, this approach is extremely powerful. When the state changes, the UI changes. When the data changes, the display changes. By separating responsibilities into components, we can create a structure that is easier to maintain. This is one of React’s greatest strengths. However, in React Three Fiber, bringing that mindset in too directly can sometimes make things harder. In 3D space, values such as an object’s position, rotation, scale, opacity, camera, lights, materials, and vertex data can change every frame. This is especially true for animations and particle effects, where values may be updated dozens of times per second. If every frame-by-frame change is managed through React state, it can cause too many re-renders. Also, trying too hard to force everything into React-style state management can make the flow of the code more difficult to understand. This is where useFrame and ref become important. In React Three Fiber, it is common to run logic on every frame inside useFrame and directly control Three.js objects through refs. For example, you might gradually rotate an object. Interpolate the camera position. Update particle coordinates. Keep track of animation progress internally. Switch movement behavior depending on the current mode. For these kinds of operations, it often feels more natural to control values imperatively through refs or buffers, rather than updating React state in small increments. This was one of the biggest differences from ordinary React development. When learning React, you naturally absorb ideas such as “manage state with React,” “split components into small pieces,” and “separate logic clearly.” These ideas are very important in web application development. However, inside a React Three Fiber Canvas, pushing those ideas too far can actually make the implementation more fragile. You may think you have separated things cleanly, but the animation flow becomes harder to follow. You move state outside the component, but then the update timing becomes less clear. You split components too finely, and the relationship between refs and frame updates becomes complicated. You organize the code in a React-like way, but the 3D expression itself becomes harder to control. This was something I could not fully understand until I actually built something that moved in React Three Fiber.
One of the biggest lessons I learned from this project was that the way I design things should change depending on whether I am working outside or inside the Canvas. Outside the Canvas, I can think in terms of normal React architecture. Page structure, text, buttons, cards, navigation, layout, scroll control, and conditional rendering all work very well with React’s component-based design. Passing data through props, managing UI state with state, and separating components by responsibility are all things that can be organized in the same way as ordinary React development. Inside the Canvas, however, things are different. Inside the Canvas, I am not dealing with the DOM. I am dealing with 3D space. This means working with concepts such as scene, camera, light, mesh, geometry, material, animation loops, buffers, and frame updates. In this area, the mindset required is closer to Three.js or game engine programming than ordinary React UI design. In particular, logic that runs inside useFrame behaves very differently from a normal React component. Instead of updating the UI through React re-rendering, it directly changes the state of objects on every frame. Because of that, trying too hard to force Canvas logic into normal React design patterns can actually feel unnatural. One rule became especially important for me during this project: Organize the outside of the Canvas as React. Understand the inside of the Canvas as Three.js control. Once I started thinking with this separation in mind, the way I looked at React Three Fiber code changed. Not everything needs to be split into small components. Not everything needs to be managed with state. There needs to be a distinction between the parts where React-like structure should be preserved and the parts where Three.js-style control should be accepted. This was a feeling I gained after struggling with the implementation quite a lot. This way of thinking was especially important for animation control. Simply displaying particles is not that difficult. However, once I tried to gather particles into a specific shape, transform them into another shape, make them flow along an orbit, scatter them like an explosion, or switch between multiple animation modes, the difficulty increased significantly. At that point, the challenge is not only about creating the visual appearance. It becomes about managing the flow of time. Which mode is active now? How many seconds have passed since the mode changed? Where is each particle moving from and to? How far has the interpolation progressed? What condition triggers the next state? Is the rendering cost still acceptable? All of this information needs to be handled inside the frame-by-frame update flow. In this situation, constants, types, and pure calculation functions are usually better placed outside the main animation logic. For example, particle counts, angles, radii, interpolation functions, and coordinate calculations can be extracted without much problem. However, logic running inside useFrame, objects stored in ref, buffer updates, mode transitions, and animation progress management can become harder to read if they are separated too aggressively. From a React perspective, I naturally want to separate the logic. I want to divide responsibilities. I want to improve readability. I want to make parts reusable. But in React Three Fiber, there are situations where the moving flow itself is the most important part. If the logic is broken down too much, it becomes harder to understand things like: “What is happening at this exact moment?” “Where is this ref being updated?” “In which mode is this buffer being rewritten?” “Where is this animation state coming from?” In other words, with React Three Fiber, clean code structure is important, but visibility over the timeline is just as important. This felt different from ordinary UI development. With UI components, the code often becomes easier to understand by organizing the relationship between state and what is displayed. But in React Three Fiber, the central question is how things change over time. Because of that, there are moments where preserving the flow of animation is more important than splitting the logic into smaller pieces.
Through this project, I realized that React Three Fiber cannot be fully mastered with React knowledge alone. Of course, understanding React is essential. Knowledge of component structure, props, hooks, rendering, and state management remains the foundation. With React Three Fiber, you also need to understand how to think in 3D space. Coordinates, rotation, scale, cameras, lights, materials, geometry, rendering cost, frame updates, and animation interpolation all need to be considered simultaneously. And when 3D expression is integrated into a website, you cannot focus only on the 3D part. The overall user experience. Loading speed. Performance on smartphones. Heat generation on laptops. When the Canvas should be displayed. How it works together with other UI animations. The role separation between Framer Motion and React Three Fiber. The balance between 3D expression, blog content, and readable UI. All of these things need to be considered as well. 3D expression is visually impressive. However, the more visually intense it becomes, the more it turns into a battle against performance and maintainability. Increasing the number of particles creates more impact. /n Using more complex models increases expressiveness. Adding more animations makes the site feel more dynamic. But at the same time, the site becomes heavier. The code becomes more complex. Bugs become harder to trace. The experience can change depending on the user’s device. Finding the right balance is one of the hardest parts of React Three Fiber, but I also think it is one of the most interesting parts. One thing that especially stood out to me while struggling with React Three Fiber was that the “right” architecture is harder to see than in ordinary React development. In React UI development, there are relatively common design principles. Split components. Lift state up when needed. Organize side effects. Separate presentational components from logic. Define types clearly. Of course, React itself can still be difficult, but the direction of thinking is relatively easy to understand. With React Three Fiber, however, simply splitting things apart is not always the right answer. It is better to separate things by Scene. It is better to organize the outside of the Canvas as React. It is better to move constants, types, and pure calculation logic outside. But useFrame, ref, buffers, animation state, and mode transitions should not always be separated too aggressively. This balance is difficult. At first, I tried to organize everything cleanly according to React design principles. But as the motion became more complex, I realized that this approach alone was not enough. In React Three Fiber, it is not enough to look at the code only as a static structure. You also need to understand what is changing while the code is running. Which values change every frame? Which values should not trigger React re-renders? Which logic should be held in refs? Which logic can safely be moved into external functions? Which logic is easier to understand if it stays inside the Scene? Making these decisions felt much harder than in ordinary React development. React Three Fiber is not just “a library that makes it easy to write 3D in React.” It is a technology that makes you think about how React’s component-based architecture and Three.js’s real-time rendering model can coexist. In ordinary React development, UI is built mainly around state, props, components, and rendering. But with React Three Fiber, you also need to handle concepts such as scenes, cameras, lights, meshes, geometry, materials, animation loops, refs, buffers, and frame updates. The truly difficult part is not simply displaying 3D objects. It is what happens behind the scenes. How should things move? How should they be controlled? How should the code be divided? How can the experience stay lightweight? How should the React world and the Three.js world be connected? That is where I feel the essence of React Three Fiber exists. Through this portfolio project, React Three Fiber became a major learning experience for me. It was not just a way to add 3D visuals. It also changed the way I think about React architecture itself.Through this portfolio project, React Three Fiber became a major learning experience for me. It was not just a way to add 3D visuals. It also changed the way I think about React architecture itself. React Three Fiber is difficult. But within that difficulty, there is a kind of excitement that ordinary Web UI development cannot offer. It is not just about building UI with React. It is about designing a moving 3D space inside the browser. Learning that feeling was the biggest takeaway from this project.