Technical Art

A collection of my work in technical art and engine systems. Regardless of its the center piece to a project, or a prop in the far background, these are some of the technical achievements I'm most proud of.Select a discipline below to see the work, its vision, and a comprehensive breakdown for each piece. For other discipline-focused breakdowns, visit VISUAL DEVELOPMENT, and ANIMATION. For a list of the games I've worked on and my role in each project, visit GAMES.


Character Models & Rigs

Jerbederb

Blender, Clip Studio Paint, Substance Painter | 2022

TURNAROUND & POLYCOUNT | CONTROL & DEFORM RIG | TEXTURE BREAKDOWN | EXPRESSION SHEET

This is my primary character rig and has been used throughout much of my personal branding and online content. Originally created in 2022, the rig has been continually revised as my rigging and Technical Art skills have developed. The current version features an animator-focused control rig designed for expressive body language, facial performance, and stylized posing. Over time, the character has also served as a testing ground for improving deformation, secondary controls, and overall animation usability. The expression sheet demonstrates the rig’s performance range across a variety of acting poses, gestures, and emotional states.

hORNET

Blender, Substance Painter | 2025

TURNAROUND & POLYCOUNT | CONTROL & DEFORM RIG | TEXTURE BREAKDOWN | CAPE SYSTEM

This unofficial Hornet fan project began as a sculpting exercise before expanding into a full animation rig inspired by the expressive motion of Hollow Knight and Silksong. While the character’s body is relatively straightforward, her cape presented a more interesting rigging challenge because its silhouette changes substantially between poses. To preserve that flexibility, I created dedicated controls for the cape’s hem, interior, frills, and individual sections, along with a driven system that can shorten the cape when a pose requires a more compact silhouette. The result gives an animator direct control over one of the character’s most recognizable features while preserving the exaggerated readability of the source animation style.

NYX (FINAL FANTASY VII)

Blender, Clip Studio Paint, Substance Painter | 2025

TURNAROUND & POLYCOUNT | CONTROL & DEFORM RIG | TEXTURE BREAKDOWN | TEXTURE BASED EXPRESSIONS

Created as a personal VRChat project, this model reimagines Nyx from Embers Amongst the Pyre in the low-poly visual language of the original Final Fantasy VII. The intentionally minimal geometry presented an unusual facial-animation problem: the character’s features are primarily texture-based rather than modeled directly into the face. To preserve that style while still allowing expressive performance, I built a texture-driven facial system that uses an animator-facing control to drive UV offsets across a facial-expression atlas. This allows Nyx to transition between multiple eye and mouth states without introducing additional facial geometry, retaining the limitations and charm of the original visual style while supporting modern character expression.

JOE COLADA

Blender, Clip Studio Paint, Substance Painter | 2024

TURNAROUND & POLYCOUNT | CONTROL & DEFORM RIG | TEXTURE BREAKDOWN | SHAPE KEYS & CORRECTIVES

Joe Colada was designed to capture the exaggerated energy of a 1990s cartoon and serve as an extremely expressive character in Pineapple Panic. Translating that kind of hand-drawn elasticity into a 3D character required a rig capable of supporting extreme facial and body poses without allowing the underlying forms to collapse. The final setup includes dedicated facial controls, multiple shape keys, blinking controls, and driven corrective shapes for extreme deformation. One corrective, for example, restores volume to the back of Joe’s head as his mouth opens wider. Together, these systems allow the character to reach highly exaggerated poses while maintaining a consistent and intentional silhouette.

PINA THE PINEAPPLE

Blender, Clip Studio Paint, Substance Painter | 2024

TURNAROUND & POLYCOUNT | CONTROL & DEFORM RIG | TEXTURE BREAKDOWN | SHAPE KEYS & DRIVERS

Pina is the playable character of Pineapple Panic, designed around a deliberately simple silhouette with thin, flexible noodle-like limbs and a large crown of independently moving foliage. Her unusual proportions shaped the rigging approach, with lightweight IK-based controls used for the arms and legs while the leaves required a more specialized secondary-motion system. Each leaf has its own IK control, while a master control can influence the entire crown together for broader posing and directional movement. Pina’s facial expressions are driven entirely through shape keys, accessed through a separate animator-facing expression board using driven sliders. The result keeps the rig approachable while providing independent control over the character’s most expressive features.

Props & Assets

Kart

Blender, Clip Studio Paint, Substance Painter | 2026

LODs & POLYCOUNT | CONTROL RIG | TEXTURE ATLAS | SHAPE KEYS & DRIVERS

Created for a branding project for a close friend and inspired by Mario Kart, this go-kart was developed as a fully animatable, game-and-animation-ready prop rather than a static model. The rig includes controls for individual and synchronized wheel rotation, steering, and gas and brake pedal movement. I also created a driver-based material-state system that transitions the kart between clean and mud-covered appearances. The same control drives a shape key that reveals modeled mud buildup within the tire treads, allowing the geometry and material state to change together. Multiple LODs were created to preserve the kart’s silhouette and visual identity while substantially reducing geometry at distance.

Fantasy Chest

Blender, Clip Studio Paint, Substance Painter | 2026

LODs & POLYCOUNT | CONTROL RIG | TEXTURE BREAKDOWN | CHEST CONTROLS

Originally created as a stylized prop for a short-form video thumbnail, this chest was later expanded into a complete game-ready asset. The rig supports lid animation, squash-and-stretch deformation, and dedicated pivot controls that allow the chest to rock or tilt from either side for more exaggerated character-like motion. The asset also includes four LOD levels, custom low-poly collision shaped for both the interior and exterior, and an optimized texture set using packed material channels. Together, these systems allow the chest to function as both a traditional environmental prop and a more expressive animated object.

Atlastooth

Blender, Clip Studio Paint, Substance Painter | 2024

LODs & POLYCOUNT | TEXTURE BREAKDOWN | BLENDER MATERIAL | UNREAL MATERIAL

Atlastooth is a concept for Zafeiri’s primary weapon in Embers Amongst the Pyre and was developed as a test case for refining the project’s game-asset pipeline. In addition to multiple optimized LODs, the weapon features a custom magical material system built around its pommel and emissive blade details. The original Unreal Engine material combines view-dependent rim and interior effects with animated procedural textures to create a shifting, reflective magical surface inspired by the visual language of Materia from Final Fantasy VII. I later recreated the material behavior in Blender for consistent promo shot rendering, translating the underlying shader logic between two different material systems. The blade also supports controllable emissive intensity for powered or magical states in engine.

(() => { 'use strict'; /* ===================================================== CONFIGURATION ===================================================== */ const CATEGORIES = [ 'rigs', 'environments', 'props', 'systems' ]; const COLLAPSED = 'portfolio-collapsed'; /* ===================================================== STATE ===================================================== */ let activeCategory = null; let activeBreakdown = null; /* ===================================================== BASIC UTILITIES ===================================================== */ function get(id) { return document.getElementById(id); } function hide(element) { if (!element) return; element.classList.add(COLLAPSED); element.setAttribute('aria-hidden', 'true'); } function show(element) { if (!element) return; element.classList.remove(COLLAPSED); element.setAttribute('aria-hidden', 'false'); } /* ===================================================== LAYOUT / IMAGE REFRESH Carrd initially calculates the page while our hidden portfolio sections occupy no space. When a large section becomes visible, this gives the browser and Carrd a few nudges to recalculate the page height and check newly visible images. ===================================================== */ function refreshLayout(element) { if (!element) return; requestAnimationFrame(() => { /* * Force a browser layout calculation. */ void document.body.offsetHeight; /* * Encourage images inside the newly revealed * section to begin loading immediately. */ element.querySelectorAll('img').forEach(img => { if (img.loading === 'lazy') { img.loading = 'eager'; } /* * Accessing dimensions also encourages the * browser to account for the image. */ void img.offsetHeight; }); /* * Notify anything listening for viewport/layout * changes. */ window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('scroll')); /* * Second pass after the browser has had time to * react to the first layout change. */ requestAnimationFrame(() => { void document.body.offsetHeight; window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('scroll')); }); /* * Final delayed pass catches images or Carrd * elements that update shortly after becoming * visible. */ window.setTimeout(() => { void document.body.offsetHeight; window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('scroll')); }, 150); }); } /* ===================================================== BREAKDOWNS ===================================================== */ function hideAllBreakdowns() { document .querySelectorAll( '[id^="breakdown-"]:not([id^="breakdown-trigger-"])' ) .forEach(hide); document .querySelectorAll( '[id^="breakdown-trigger-"]' ) .forEach(button => { button.setAttribute( 'aria-expanded', 'false' ); }); activeBreakdown = null; } function toggleBreakdown(targetId, trigger = null) { const target = get(targetId); if (!target) { console.warn( `[PortfolioTechArt] Could not find #${targetId}.` ); return; } /* * Check this BEFORE closing everything. */ const alreadyOpen = activeBreakdown === targetId; /* * Only one breakdown may be open. */ hideAllBreakdowns(); /* * Clicking an already-open button simply closes it. */ if (alreadyOpen) { return; } /* * Open requested breakdown. */ show(target); activeBreakdown = targetId; /* * Accessibility state for its button. */ if (trigger) { trigger.setAttribute( 'aria-expanded', 'true' ); } /* * Tell Carrd/browser that a large new section * has entered the page. */ refreshLayout(target); /* * Gently bring the breakdown into view. */ window.setTimeout(() => { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 100); } /* ===================================================== CATEGORIES ===================================================== */ function hideAllCategories() { CATEGORIES.forEach(category => { hide( get(`title-${category}`) ); hide( get(`category-${category}`) ); }); /* * Changing categories also closes any open * artwork breakdown. */ hideAllBreakdowns(); activeCategory = null; } function openCategory(category) { if (!CATEGORIES.includes(category)) { console.warn( `[PortfolioTechArt] Unknown category: ${category}` ); return; } const title = get(`title-${category}`); const panel = get(`category-${category}`); /* * Concept Art does not exist yet, so this lets it * remain safely preconfigured without throwing an * error. */ if (!title && !panel) { console.warn( `[PortfolioTechArt] Could not find category "${category}".` ); return; } /* * Close the previous category and any breakdown * belonging to it. */ hideAllCategories(); /* * Reveal requested category. */ show(title); show(panel); activeCategory = category; /* * Recalculate Carrd/browser layout after revealing * what can be a very large section. */ refreshLayout(panel); } /* ===================================================== AUTOMATIC BREAKDOWN BUTTON BINDING Example: breakdown-trigger-2dillustration-01 automatically controls: breakdown-2dillustration-01 ===================================================== */ function bindBreakdownButtons() { const buttons = document.querySelectorAll( '[id^="breakdown-trigger-"]' ); buttons.forEach(button => { const targetId = button.id.replace( 'breakdown-trigger-', 'breakdown-' ); const target = get(targetId); if (!target) { console.warn( `[PortfolioTechArt] "${button.id}" has no matching "#${targetId}".` ); return; } button.setAttribute( 'aria-controls', targetId ); button.setAttribute( 'aria-expanded', 'false' ); button.addEventListener( 'click', event => { event.preventDefault(); toggleBreakdown( targetId, button ); } ); }); } /* ===================================================== DIAGNOSTIC TOOL ===================================================== */ function diagnose() { const report = {}; CATEGORIES.forEach(category => { report[category] = { titleFound: !!get(`title-${category}`), categoryFound: !!get(`category-${category}`) }; }); report.breakdownTriggers = document.querySelectorAll( '[id^="breakdown-trigger-"]' ).length; report.breakdowns = document.querySelectorAll( '[id^="breakdown-"]:not([id^="breakdown-trigger-"])' ).length; console.log( '[PortfolioVisDev Diagnostic]' ); console.table(report); return report; } /* ===================================================== INITIALIZATION ===================================================== */ function initialize() { /* * The portfolio-collapsed class should already * make these invisible before JavaScript loads, * but enforce the correct state here as well. */ hideAllCategories(); /* * Automatically connect every existing View * Breakdown button. */ bindBreakdownButtons(); console.log( '[PortfolioTechArt] Initialized' ); } /* ===================================================== PUBLIC FUNCTIONS These are what your Carrd gallery images call. ===================================================== */ window.PortfolioTechArt = Object.freeze({ openCategory, hideAllCategories, hideAllBreakdowns, diagnose }); /* ===================================================== START ===================================================== */ if ( document.readyState === 'loading' ) { document.addEventListener( 'DOMContentLoaded', initialize ); } else { initialize(); } })();

3D Modeled Scenes & Props

Text

Programs used | 202x

BREAKDOWN IMAGE | BREAKDOWN IMAGE | BREAKDOWN IMAGE | BREAKDOWN IMAGE | BREAKDOWN IMAGE |

Breakdown information