PricingDeep DiveLevel 1 - Process Deep Dives

FDM - Filament Extrusion

How to price FDM/FFF parts by splitting geometry into shell, infill, and supports to estimate print time, which is the dominant cost driver.

Why this process is unique

FDM pricing is dominated by print time, not material cost. A structurally solid part uses similar material volume to the same part printed hollow, but they take very different amounts of machine time.

The key insight is to split the part into three regions that print at different speeds:

  • Shell (outer walls): slow, many direction changes
  • Infill: fast, long sweeping lines
  • Supports: medium speed, low density

Cost = material consumed + machine time × rate


Core methodology

Shell volume: Math.min(volume, area × nozzle × walls) - bounded so thin parts don't produce negative infill

Infill volume: (volume - shellVolume) × infillDensity

Support volume: estimated from the convex hull gap, exposed via variable() for override

Print time: each region's volume ÷ volumetric flow rate, summed and multiplied by overhead

Shell penalty: parts heavy in shell features print slower than their volume suggests


Numerical example

Part: 40 × 40 × 80mm post, 20% infill, volume = 30,000 mm³, area = 14,400 mm²

ParameterValue
Nozzle diameter0.4 mm
Layer height (precision)0.2 mm
Wall count3
Base speed60 mm/s
Wall speed factor0.5
Infill speed factor1.0
printerCostPerHour€8
materialCostPerKg€28, materialDensity = 1.24 g/cm³

Shell volume: min(30,000, 14,400 × 0.4 × 3) = min(30,000, 17,280) = 17,280 mm³

Infill volume: (30,000 − 17,280) × 0.20 = 2,544 mm³

Wall time: 17,280 / (0.4 × 0.2 × 60 × 0.5) = 17,280 / 2.4 = 7,200 s

Infill time: 2,544 / (0.4 × 0.2 × 60 × 1.0) = 2,544 / 4.8 = 530 s

Shell penalty: 1 + 0.5 × (17,280 / (17,280 + 2,544))² = 1.41

Print time: (7,200 + 530) × 1.3 × 1.41 / 3600 = 3.7 hours

Material cost: (17,280 + 2,544 + 0 support) / 1,000 × 1.24 / 1,000 × 28 = €0.55

Machine cost: 3.7 × 8 = €29.60

Unit price (1 part, no discount): ~€30.15


Complete algorithm

const { material, width, height, length, volume, area, convexHullVolume, infill, precision } = specification
const { quantity } = requisition

// --- Machine definitions ---
const MACHINES = [
  { name: 'Small desktop FFF',      bed: { l: 256, w: 256, h: 256 }, costPerHour: 6  },
  { name: 'Medium desktop FFF', bed: { l: 300, w: 300, h: 300 }, costPerHour: 7  },
  { name: 'Big desktop FFF',      bed: { l: 320, w: 320, h: 325 }, costPerHour: 9  },
]

function selectMachine() {
  return MACHINES.find(m =>
    length <= m.bed.l && width <= m.bed.w && height <= m.bed.h
  ) ?? MACHINES[MACHINES.length - 1]
}

// --- Constants ---
const NOZZLE_DIAMETER_MM  = 0.4
const NUMBER_OF_WALLS     = 3
const SUPPORT_INFILL      = 0.2
const PRINT_TIME_OVERHEAD = 1.3

// --- Geometry ---
const layerHeight = precision?.value ?? 0.20
const partInfill  = infill?.value ?? 0.20

const shellVolume   = Math.min(volume, area * NOZZLE_DIAMETER_MM * NUMBER_OF_WALLS)
const infillVolume  = (volume - shellVolume) * partInfill
const hullGap       = convexHullVolume - volume
const supportVolume = variable('supportVolume', round(hullGap * 0.10, 0))

// --- Material cost ---
const materialDensity   = material.variables['materialDensity']
const materialCostPerKg = material.variables['materialCostPerKg']
const mainWeight    = ((shellVolume + infillVolume) / 1000) * materialDensity / 1000
const supportWeight = ((supportVolume * SUPPORT_INFILL) / 1000) * materialDensity / 1000
const materialCost  = round((mainWeight + supportWeight) * materialCostPerKg, 2)

// --- Print time ---
const baseSpeed          = material.variables['baseSpeedNozzle']
const wallSpeedFactor    = material.variables['wallSpeedFactor']
const infillSpeedFactor  = material.variables['infillSpeedFactor']
const supportSpeedFactor = material.variables['supportSpeedFactor']

const wallTime    = shellVolume  / (NOZZLE_DIAMETER_MM * layerHeight * baseSpeed * wallSpeedFactor)
const infillTime  = infillVolume / (NOZZLE_DIAMETER_MM * layerHeight * baseSpeed * infillSpeedFactor)
const supportTime = (supportVolume * SUPPORT_INFILL) / (NOZZLE_DIAMETER_MM * layerHeight * baseSpeed * supportSpeedFactor)
const shellPenalty = 1 + 0.5 * Math.pow(shellVolume / (shellVolume + infillVolume + 1), 2)
const printTimeHours = variable('printTime', round(
  (wallTime + infillTime + supportTime) * PRINT_TIME_OVERHEAD * shellPenalty / 3600, 2
))

// --- Machine cost ---
const machine        = selectMachine()
const machineName    = variable('Machine', machine.name)
const machineCost    = round(printTimeHours * machine.costPerHour, 2)

// --- Pricing ---
const hardwareCost = variable('Hardware cost', 0)
const getDiscount  = createBands({ 10: 0.95, 50: 0.90, 100: 0.85, 250: 0.80 }, 1.0)
const baseCost     = (materialCost + machineCost + hardwareCost) * getDiscount(quantity)
const MIN_PRICE    = material.variables['minUnitPrice']
const unitPrice    = variable('unitPrice', Math.max(MIN_PRICE, round(baseCost, 2)))

// --- Review gate ---
const largest = MACHINES[MACHINES.length - 1].bed
const oversized = length > largest.l || width > largest.w || height > largest.h
done(unitPrice, printTimeHours, oversized)

Material variables: materialDensity, materialCostPerKg, baseSpeedNozzle, wallSpeedFactor, infillSpeedFactor, supportSpeedFactor, minUnitPrice


When to use this

All desktop and industrial FFF/FDM printers. Any extrusion process where print time is the main cost driver.

For very large parts (>500mm), use the Large Format FDM page instead.

Last updated on

On this page